15b81b6b3SRodney W. Grimes %{ 29ddb49cbSWarner Losh /*- 39ddb49cbSWarner Losh * Written by Pace Willisson (pace@blitz.com) 455c497bfSJ.T. Conklin * and placed in the public domain. 55b81b6b3SRodney W. Grimes * 655c497bfSJ.T. Conklin * Largely rewritten by J.T. Conklin (jtc@wimsey.com) 755c497bfSJ.T. Conklin * 82a456239SPeter Wemm * $FreeBSD$ 95b81b6b3SRodney W. Grimes */ 104cf61abaSJ.T. Conklin 1164867286SStefan Eßer #include <sys/types.h> 12f07e4247SGarrett Wollman 135b81b6b3SRodney W. Grimes #include <ctype.h> 1455c497bfSJ.T. Conklin #include <err.h> 15915198b4SStefan Eßer #include <errno.h> 16f07e4247SGarrett Wollman #include <inttypes.h> 17915198b4SStefan Eßer #include <limits.h> 18f07e4247SGarrett Wollman #include <locale.h> 19f07e4247SGarrett Wollman #include <stdio.h> 20f07e4247SGarrett Wollman #include <stdlib.h> 21f07e4247SGarrett Wollman #include <string.h> 22f07e4247SGarrett Wollman #include <regex.h> 23f07e4247SGarrett Wollman #include <unistd.h> 24f07e4247SGarrett Wollman 25f07e4247SGarrett Wollman /* 26f07e4247SGarrett Wollman * POSIX specifies a specific error code for syntax errors. We exit 27f07e4247SGarrett Wollman * with this code for all errors. 28f07e4247SGarrett Wollman */ 29f07e4247SGarrett Wollman #define ERR_EXIT 2 305b81b6b3SRodney W. Grimes 315b81b6b3SRodney W. Grimes enum valtype { 32717252eaSJoerg Wunsch integer, numeric_string, string 335b81b6b3SRodney W. Grimes } ; 345b81b6b3SRodney W. Grimes 355b81b6b3SRodney W. Grimes struct val { 365b81b6b3SRodney W. Grimes enum valtype type; 375b81b6b3SRodney W. Grimes union { 385b81b6b3SRodney W. Grimes char *s; 39f07e4247SGarrett Wollman intmax_t i; 405b81b6b3SRodney W. Grimes } u; 415b81b6b3SRodney W. Grimes } ; 425b81b6b3SRodney W. Grimes 436fbe7bf4SStefan Eßer char **av; 446fbe7bf4SStefan Eßer int nonposix; 455b81b6b3SRodney W. Grimes struct val *result; 463d06e95dSKris Kennaway 47fa717604SStefan Eßer void assert_to_integer(struct val *); 486fbe7bf4SStefan Eßer void assert_div(intmax_t, intmax_t); 496fbe7bf4SStefan Eßer void assert_minus(intmax_t, intmax_t, intmax_t); 506fbe7bf4SStefan Eßer void assert_plus(intmax_t, intmax_t, intmax_t); 516fbe7bf4SStefan Eßer void assert_times(intmax_t, intmax_t, intmax_t); 526fbe7bf4SStefan Eßer int compare_vals(struct val *, struct val *); 537669d0fcSWarner Losh void free_value(struct val *); 54fa717604SStefan Eßer int is_integer(const char *); 5569759f08SStefan Eßer int is_string(struct val *); 56fa717604SStefan Eßer int is_zero_or_null(struct val *); 57f07e4247SGarrett Wollman struct val *make_integer(intmax_t); 587669d0fcSWarner Losh struct val *make_str(const char *); 597669d0fcSWarner Losh struct val *op_and(struct val *, struct val *); 607669d0fcSWarner Losh struct val *op_colon(struct val *, struct val *); 617669d0fcSWarner Losh struct val *op_div(struct val *, struct val *); 627669d0fcSWarner Losh struct val *op_eq(struct val *, struct val *); 637669d0fcSWarner Losh struct val *op_ge(struct val *, struct val *); 647669d0fcSWarner Losh struct val *op_gt(struct val *, struct val *); 657669d0fcSWarner Losh struct val *op_le(struct val *, struct val *); 667669d0fcSWarner Losh struct val *op_lt(struct val *, struct val *); 677669d0fcSWarner Losh struct val *op_minus(struct val *, struct val *); 687669d0fcSWarner Losh struct val *op_ne(struct val *, struct val *); 697669d0fcSWarner Losh struct val *op_or(struct val *, struct val *); 707669d0fcSWarner Losh struct val *op_plus(struct val *, struct val *); 717669d0fcSWarner Losh struct val *op_rem(struct val *, struct val *); 727669d0fcSWarner Losh struct val *op_times(struct val *, struct val *); 73fa717604SStefan Eßer int to_integer(struct val *); 747669d0fcSWarner Losh void to_string(struct val *); 757669d0fcSWarner Losh int yyerror(const char *); 767669d0fcSWarner Losh int yylex(void); 777669d0fcSWarner Losh int yyparse(void); 785b81b6b3SRodney W. Grimes 795b81b6b3SRodney W. Grimes %} 805b81b6b3SRodney W. Grimes 815b81b6b3SRodney W. Grimes %union 825b81b6b3SRodney W. Grimes { 835b81b6b3SRodney W. Grimes struct val *val; 845b81b6b3SRodney W. Grimes } 855b81b6b3SRodney W. Grimes 865b81b6b3SRodney W. Grimes %left <val> '|' 875b81b6b3SRodney W. Grimes %left <val> '&' 885b81b6b3SRodney W. Grimes %left <val> '=' '>' '<' GE LE NE 895b81b6b3SRodney W. Grimes %left <val> '+' '-' 905b81b6b3SRodney W. Grimes %left <val> '*' '/' '%' 915b81b6b3SRodney W. Grimes %left <val> ':' 925b81b6b3SRodney W. Grimes 935b81b6b3SRodney W. Grimes %token <val> TOKEN 945b81b6b3SRodney W. Grimes %type <val> start expr 955b81b6b3SRodney W. Grimes 965b81b6b3SRodney W. Grimes %% 975b81b6b3SRodney W. Grimes 985b81b6b3SRodney W. Grimes start: expr { result = $$; } 995b81b6b3SRodney W. Grimes 1005b81b6b3SRodney W. Grimes expr: TOKEN 1015b81b6b3SRodney W. Grimes | '(' expr ')' { $$ = $2; } 1025b81b6b3SRodney W. Grimes | expr '|' expr { $$ = op_or($1, $3); } 1035b81b6b3SRodney W. Grimes | expr '&' expr { $$ = op_and($1, $3); } 1045b81b6b3SRodney W. Grimes | expr '=' expr { $$ = op_eq($1, $3); } 1055b81b6b3SRodney W. Grimes | expr '>' expr { $$ = op_gt($1, $3); } 1065b81b6b3SRodney W. Grimes | expr '<' expr { $$ = op_lt($1, $3); } 1075b81b6b3SRodney W. Grimes | expr GE expr { $$ = op_ge($1, $3); } 1085b81b6b3SRodney W. Grimes | expr LE expr { $$ = op_le($1, $3); } 1095b81b6b3SRodney W. Grimes | expr NE expr { $$ = op_ne($1, $3); } 1105b81b6b3SRodney W. Grimes | expr '+' expr { $$ = op_plus($1, $3); } 1115b81b6b3SRodney W. Grimes | expr '-' expr { $$ = op_minus($1, $3); } 1125b81b6b3SRodney W. Grimes | expr '*' expr { $$ = op_times($1, $3); } 1135b81b6b3SRodney W. Grimes | expr '/' expr { $$ = op_div($1, $3); } 1145b81b6b3SRodney W. Grimes | expr '%' expr { $$ = op_rem($1, $3); } 1155b81b6b3SRodney W. Grimes | expr ':' expr { $$ = op_colon($1, $3); } 1165b81b6b3SRodney W. Grimes ; 1175b81b6b3SRodney W. Grimes 1185b81b6b3SRodney W. Grimes %% 1195b81b6b3SRodney W. Grimes 1205b81b6b3SRodney W. Grimes struct val * 121f07e4247SGarrett Wollman make_integer(intmax_t i) 1225b81b6b3SRodney W. Grimes { 1235b81b6b3SRodney W. Grimes struct val *vp; 1245b81b6b3SRodney W. Grimes 1255b81b6b3SRodney W. Grimes vp = (struct val *)malloc(sizeof(*vp)); 12669759f08SStefan Eßer if (vp == NULL) 127f07e4247SGarrett Wollman errx(ERR_EXIT, "malloc() failed"); 1285b81b6b3SRodney W. Grimes 1295b81b6b3SRodney W. Grimes vp->type = integer; 1305b81b6b3SRodney W. Grimes vp->u.i = i; 13169759f08SStefan Eßer return (vp); 1325b81b6b3SRodney W. Grimes } 1335b81b6b3SRodney W. Grimes 1345b81b6b3SRodney W. Grimes struct val * 1357669d0fcSWarner Losh make_str(const char *s) 1365b81b6b3SRodney W. Grimes { 1375b81b6b3SRodney W. Grimes struct val *vp; 1385b81b6b3SRodney W. Grimes 1395b81b6b3SRodney W. Grimes vp = (struct val *)malloc(sizeof(*vp)); 14069759f08SStefan Eßer if (vp == NULL || ((vp->u.s = strdup(s)) == NULL)) 141f07e4247SGarrett Wollman errx(ERR_EXIT, "malloc() failed"); 1425b81b6b3SRodney W. Grimes 143fa717604SStefan Eßer if (is_integer(s)) 144f07e4247SGarrett Wollman vp->type = numeric_string; 145fa717604SStefan Eßer else 146fa717604SStefan Eßer vp->type = string; 1472a353a9fSJoerg Wunsch 14869759f08SStefan Eßer return (vp); 1495b81b6b3SRodney W. Grimes } 1505b81b6b3SRodney W. Grimes 1515b81b6b3SRodney W. Grimes void 1527669d0fcSWarner Losh free_value(struct val *vp) 1535b81b6b3SRodney W. Grimes { 154717252eaSJoerg Wunsch if (vp->type == string || vp->type == numeric_string) 1555b81b6b3SRodney W. Grimes free(vp->u.s); 1565b81b6b3SRodney W. Grimes } 1575b81b6b3SRodney W. Grimes 158fa717604SStefan Eßer int 1597669d0fcSWarner Losh to_integer(struct val *vp) 1605b81b6b3SRodney W. Grimes { 161f07e4247SGarrett Wollman intmax_t i; 1625b81b6b3SRodney W. Grimes 163fa717604SStefan Eßer /* we can only convert numeric_string to integer, here */ 164fa717604SStefan Eßer if (vp->type == numeric_string) { 165915198b4SStefan Eßer errno = 0; 166f07e4247SGarrett Wollman i = strtoimax(vp->u.s, (char **)NULL, 10); 167fa717604SStefan Eßer /* just keep as numeric_string, if the conversion fails */ 168fa717604SStefan Eßer if (errno != ERANGE) { 1695b81b6b3SRodney W. Grimes free(vp->u.s); 1705b81b6b3SRodney W. Grimes vp->u.i = i; 171717252eaSJoerg Wunsch vp->type = integer; 172fa717604SStefan Eßer } 173fa717604SStefan Eßer } 174fa717604SStefan Eßer return (vp->type == integer); 175fa717604SStefan Eßer } 176fa717604SStefan Eßer 177fa717604SStefan Eßer void 178fa717604SStefan Eßer assert_to_integer(struct val *vp) 179fa717604SStefan Eßer { 180fa717604SStefan Eßer if (vp->type == string) 181fa717604SStefan Eßer errx(ERR_EXIT, "not a decimal number: '%s'", vp->u.s); 182fa717604SStefan Eßer if (!to_integer(vp)) 183fa717604SStefan Eßer errx(ERR_EXIT, "operand too large: '%s'", vp->u.s); 1845b81b6b3SRodney W. Grimes } 1855b81b6b3SRodney W. Grimes 1865b81b6b3SRodney W. Grimes void 1877669d0fcSWarner Losh to_string(struct val *vp) 1885b81b6b3SRodney W. Grimes { 1895b81b6b3SRodney W. Grimes char *tmp; 1905b81b6b3SRodney W. Grimes 191717252eaSJoerg Wunsch if (vp->type == string || vp->type == numeric_string) 1925b81b6b3SRodney W. Grimes return; 1935b81b6b3SRodney W. Grimes 194f07e4247SGarrett Wollman /* 195f07e4247SGarrett Wollman * log_10(x) ~= 0.3 * log_2(x). Rounding up gives the number 196f07e4247SGarrett Wollman * of digits; add one each for the sign and terminating null 197f07e4247SGarrett Wollman * character, respectively. 198f07e4247SGarrett Wollman */ 199f07e4247SGarrett Wollman #define NDIGITS(x) (3 * (sizeof(x) * CHAR_BIT) / 10 + 1 + 1 + 1) 200f07e4247SGarrett Wollman tmp = malloc(NDIGITS(vp->u.i)); 201f07e4247SGarrett Wollman if (tmp == NULL) 202f07e4247SGarrett Wollman errx(ERR_EXIT, "malloc() failed"); 2035b81b6b3SRodney W. Grimes 204f07e4247SGarrett Wollman sprintf(tmp, "%jd", vp->u.i); 2055b81b6b3SRodney W. Grimes vp->type = string; 2065b81b6b3SRodney W. Grimes vp->u.s = tmp; 2075b81b6b3SRodney W. Grimes } 2085b81b6b3SRodney W. Grimes 2095b81b6b3SRodney W. Grimes int 210fa717604SStefan Eßer is_integer(const char *s) 211fa717604SStefan Eßer { 212fa717604SStefan Eßer if (nonposix) { 213fa717604SStefan Eßer if (*s == '\0') 214fa717604SStefan Eßer return (1); 215fa717604SStefan Eßer while (isspace((unsigned char)*s)) 216fa717604SStefan Eßer s++; 217fa717604SStefan Eßer } 218fa717604SStefan Eßer if (*s == '-' || (nonposix && *s == '+')) 219fa717604SStefan Eßer s++; 220fa717604SStefan Eßer if (*s == '\0') 221fa717604SStefan Eßer return (0); 222fa717604SStefan Eßer while (isdigit((unsigned char)*s)) 223fa717604SStefan Eßer s++; 224fa717604SStefan Eßer return (*s == '\0'); 225fa717604SStefan Eßer } 226fa717604SStefan Eßer 227fa717604SStefan Eßer int 22869759f08SStefan Eßer is_string(struct val *vp) 2295b81b6b3SRodney W. Grimes { 230717252eaSJoerg Wunsch /* only TRUE if this string is not a valid integer */ 2315b81b6b3SRodney W. Grimes return (vp->type == string); 2325b81b6b3SRodney W. Grimes } 2335b81b6b3SRodney W. Grimes 2345b81b6b3SRodney W. Grimes int 2357669d0fcSWarner Losh yylex(void) 2365b81b6b3SRodney W. Grimes { 2375b81b6b3SRodney W. Grimes char *p; 2385b81b6b3SRodney W. Grimes 2395b81b6b3SRodney W. Grimes if (*av == NULL) 2405b81b6b3SRodney W. Grimes return (0); 2415b81b6b3SRodney W. Grimes 2425b81b6b3SRodney W. Grimes p = *av++; 2435b81b6b3SRodney W. Grimes 2445b81b6b3SRodney W. Grimes if (strlen(p) == 1) { 2455b81b6b3SRodney W. Grimes if (strchr("|&=<>+-*/%:()", *p)) 2465b81b6b3SRodney W. Grimes return (*p); 2475b81b6b3SRodney W. Grimes } else if (strlen(p) == 2 && p[1] == '=') { 2485b81b6b3SRodney W. Grimes switch (*p) { 2495b81b6b3SRodney W. Grimes case '>': return (GE); 2505b81b6b3SRodney W. Grimes case '<': return (LE); 2515b81b6b3SRodney W. Grimes case '!': return (NE); 2525b81b6b3SRodney W. Grimes } 2535b81b6b3SRodney W. Grimes } 2545b81b6b3SRodney W. Grimes 2555b81b6b3SRodney W. Grimes yylval.val = make_str(p); 2565b81b6b3SRodney W. Grimes return (TOKEN); 2575b81b6b3SRodney W. Grimes } 2585b81b6b3SRodney W. Grimes 2595b81b6b3SRodney W. Grimes int 2607669d0fcSWarner Losh is_zero_or_null(struct val *vp) 2615b81b6b3SRodney W. Grimes { 26269759f08SStefan Eßer if (vp->type == integer) 2635b81b6b3SRodney W. Grimes return (vp->u.i == 0); 26469759f08SStefan Eßer 265c9fe00dcSJ.T. Conklin return (*vp->u.s == 0 || (to_integer(vp) && vp->u.i == 0)); 2665b81b6b3SRodney W. Grimes } 2675b81b6b3SRodney W. Grimes 268717252eaSJoerg Wunsch int 269f07e4247SGarrett Wollman main(int argc, char *argv[]) 2705b81b6b3SRodney W. Grimes { 271f07e4247SGarrett Wollman int c; 2724cf61abaSJ.T. Conklin 273f07e4247SGarrett Wollman setlocale(LC_ALL, ""); 274c9885518SGarrett Wollman if (getenv("EXPR_COMPAT") != NULL 275c9885518SGarrett Wollman || check_utility_compat("expr")) { 27696ab7da3SGarrett Wollman av = argv + 1; 277fa717604SStefan Eßer nonposix = 1; 27896ab7da3SGarrett Wollman } else { 27969759f08SStefan Eßer while ((c = getopt(argc, argv, "e")) != -1) { 280f07e4247SGarrett Wollman switch (c) { 2811393277eSGarrett Wollman case 'e': 282fa717604SStefan Eßer nonposix = 1; 2831393277eSGarrett Wollman break; 284f07e4247SGarrett Wollman default: 28569759f08SStefan Eßer errx(ERR_EXIT, 2861393277eSGarrett Wollman "usage: expr [-e] expression\n"); 28769759f08SStefan Eßer } 288f07e4247SGarrett Wollman } 289f07e4247SGarrett Wollman av = argv + optind; 29096ab7da3SGarrett Wollman } 2915b81b6b3SRodney W. Grimes 2925b81b6b3SRodney W. Grimes yyparse(); 2935b81b6b3SRodney W. Grimes 2945b81b6b3SRodney W. Grimes if (result->type == integer) 295f07e4247SGarrett Wollman printf("%jd\n", result->u.i); 2965b81b6b3SRodney W. Grimes else 2975b81b6b3SRodney W. Grimes printf("%s\n", result->u.s); 2985b81b6b3SRodney W. Grimes 299717252eaSJoerg Wunsch return (is_zero_or_null(result)); 3005b81b6b3SRodney W. Grimes } 3015b81b6b3SRodney W. Grimes 3025b81b6b3SRodney W. Grimes int 3037669d0fcSWarner Losh yyerror(const char *s __unused) 3045b81b6b3SRodney W. Grimes { 305f07e4247SGarrett Wollman errx(ERR_EXIT, "syntax error"); 3065b81b6b3SRodney W. Grimes } 3075b81b6b3SRodney W. Grimes 3085b81b6b3SRodney W. Grimes struct val * 3097669d0fcSWarner Losh op_or(struct val *a, struct val *b) 3105b81b6b3SRodney W. Grimes { 311fa717604SStefan Eßer if (!is_zero_or_null(a)) { 3125b81b6b3SRodney W. Grimes free_value(b); 3135b81b6b3SRodney W. Grimes return (a); 3145b81b6b3SRodney W. Grimes } 315fa717604SStefan Eßer free_value(a); 316fa717604SStefan Eßer if (!is_zero_or_null(b)) 317fa717604SStefan Eßer return (b); 318fa717604SStefan Eßer free_value(b); 319fa717604SStefan Eßer return (make_integer((intmax_t)0)); 3205b81b6b3SRodney W. Grimes } 3215b81b6b3SRodney W. Grimes 3225b81b6b3SRodney W. Grimes struct val * 3237669d0fcSWarner Losh op_and(struct val *a, struct val *b) 3245b81b6b3SRodney W. Grimes { 3255b81b6b3SRodney W. Grimes if (is_zero_or_null(a) || is_zero_or_null(b)) { 3265b81b6b3SRodney W. Grimes free_value(a); 3275b81b6b3SRodney W. Grimes free_value(b); 328f07e4247SGarrett Wollman return (make_integer((intmax_t)0)); 3295b81b6b3SRodney W. Grimes } else { 3305b81b6b3SRodney W. Grimes free_value(b); 3315b81b6b3SRodney W. Grimes return (a); 3325b81b6b3SRodney W. Grimes } 3335b81b6b3SRodney W. Grimes } 3345b81b6b3SRodney W. Grimes 3356fbe7bf4SStefan Eßer int 3366fbe7bf4SStefan Eßer compare_vals(struct val *a, struct val *b) 3375b81b6b3SRodney W. Grimes { 3386fbe7bf4SStefan Eßer int r; 3395b81b6b3SRodney W. Grimes 34069759f08SStefan Eßer if (is_string(a) || is_string(b)) { 3415b81b6b3SRodney W. Grimes to_string(a); 3425b81b6b3SRodney W. Grimes to_string(b); 3436fbe7bf4SStefan Eßer r = strcoll(a->u.s, b->u.s); 3445b81b6b3SRodney W. Grimes } else { 345fa717604SStefan Eßer assert_to_integer(a); 346fa717604SStefan Eßer assert_to_integer(b); 3476fbe7bf4SStefan Eßer if (a->u.i > b->u.i) 3486fbe7bf4SStefan Eßer r = 1; 3496fbe7bf4SStefan Eßer else if (a->u.i < b->u.i) 3506fbe7bf4SStefan Eßer r = -1; 3516fbe7bf4SStefan Eßer else 3526fbe7bf4SStefan Eßer r = 0; 3535b81b6b3SRodney W. Grimes } 3545b81b6b3SRodney W. Grimes 3555b81b6b3SRodney W. Grimes free_value(a); 3565b81b6b3SRodney W. Grimes free_value(b); 3576fbe7bf4SStefan Eßer return (r); 3586fbe7bf4SStefan Eßer } 3596fbe7bf4SStefan Eßer 3606fbe7bf4SStefan Eßer struct val * 3616fbe7bf4SStefan Eßer op_eq(struct val *a, struct val *b) 3626fbe7bf4SStefan Eßer { 3636fbe7bf4SStefan Eßer return (make_integer((intmax_t)(compare_vals(a, b) == 0))); 3645b81b6b3SRodney W. Grimes } 3655b81b6b3SRodney W. Grimes 3665b81b6b3SRodney W. Grimes struct val * 3677669d0fcSWarner Losh op_gt(struct val *a, struct val *b) 3685b81b6b3SRodney W. Grimes { 3696fbe7bf4SStefan Eßer return (make_integer((intmax_t)(compare_vals(a, b) > 0))); 3705b81b6b3SRodney W. Grimes } 3715b81b6b3SRodney W. Grimes 3725b81b6b3SRodney W. Grimes struct val * 3737669d0fcSWarner Losh op_lt(struct val *a, struct val *b) 3745b81b6b3SRodney W. Grimes { 3756fbe7bf4SStefan Eßer return (make_integer((intmax_t)(compare_vals(a, b) < 0))); 3765b81b6b3SRodney W. Grimes } 3775b81b6b3SRodney W. Grimes 3785b81b6b3SRodney W. Grimes struct val * 3797669d0fcSWarner Losh op_ge(struct val *a, struct val *b) 3805b81b6b3SRodney W. Grimes { 3816fbe7bf4SStefan Eßer return (make_integer((intmax_t)(compare_vals(a, b) >= 0))); 3825b81b6b3SRodney W. Grimes } 3835b81b6b3SRodney W. Grimes 3845b81b6b3SRodney W. Grimes struct val * 3857669d0fcSWarner Losh op_le(struct val *a, struct val *b) 3865b81b6b3SRodney W. Grimes { 3876fbe7bf4SStefan Eßer return (make_integer((intmax_t)(compare_vals(a, b) <= 0))); 3885b81b6b3SRodney W. Grimes } 3895b81b6b3SRodney W. Grimes 3905b81b6b3SRodney W. Grimes struct val * 3917669d0fcSWarner Losh op_ne(struct val *a, struct val *b) 3925b81b6b3SRodney W. Grimes { 3936fbe7bf4SStefan Eßer return (make_integer((intmax_t)(compare_vals(a, b) != 0))); 3945b81b6b3SRodney W. Grimes } 3955b81b6b3SRodney W. Grimes 3966fbe7bf4SStefan Eßer void 3976fbe7bf4SStefan Eßer assert_plus(intmax_t a, intmax_t b, intmax_t r) 398915198b4SStefan Eßer { 3996fbe7bf4SStefan Eßer /* 4006fbe7bf4SStefan Eßer * sum of two positive numbers must be positive, 4016fbe7bf4SStefan Eßer * sum of two negative numbers must be negative 4026fbe7bf4SStefan Eßer */ 4036fbe7bf4SStefan Eßer if ((a > 0 && b > 0 && r <= 0) || 4046fbe7bf4SStefan Eßer (a < 0 && b < 0 && r >= 0)) 4056fbe7bf4SStefan Eßer errx(ERR_EXIT, "overflow"); 406915198b4SStefan Eßer } 407915198b4SStefan Eßer 4085b81b6b3SRodney W. Grimes struct val * 4097669d0fcSWarner Losh op_plus(struct val *a, struct val *b) 4105b81b6b3SRodney W. Grimes { 4115b81b6b3SRodney W. Grimes struct val *r; 4125b81b6b3SRodney W. Grimes 413fa717604SStefan Eßer assert_to_integer(a); 414fa717604SStefan Eßer assert_to_integer(b); 4151393277eSGarrett Wollman r = make_integer(a->u.i + b->u.i); 4166fbe7bf4SStefan Eßer assert_plus(a->u.i, b->u.i, r->u.i); 4171393277eSGarrett Wollman 4185b81b6b3SRodney W. Grimes free_value(a); 4195b81b6b3SRodney W. Grimes free_value(b); 42069759f08SStefan Eßer return (r); 4215b81b6b3SRodney W. Grimes } 4225b81b6b3SRodney W. Grimes 4236fbe7bf4SStefan Eßer void 4246fbe7bf4SStefan Eßer assert_minus(intmax_t a, intmax_t b, intmax_t r) 425915198b4SStefan Eßer { 426f07e4247SGarrett Wollman /* special case subtraction of INTMAX_MIN */ 4276fbe7bf4SStefan Eßer if (b == INTMAX_MIN && a < 0) 4286fbe7bf4SStefan Eßer errx(ERR_EXIT, "overflow"); 4296fbe7bf4SStefan Eßer /* check addition of negative subtrahend */ 4306fbe7bf4SStefan Eßer assert_plus(a, -b, r); 431915198b4SStefan Eßer } 432915198b4SStefan Eßer 4335b81b6b3SRodney W. Grimes struct val * 4347669d0fcSWarner Losh op_minus(struct val *a, struct val *b) 4355b81b6b3SRodney W. Grimes { 4365b81b6b3SRodney W. Grimes struct val *r; 4375b81b6b3SRodney W. Grimes 438fa717604SStefan Eßer assert_to_integer(a); 439fa717604SStefan Eßer assert_to_integer(b); 4401393277eSGarrett Wollman r = make_integer(a->u.i - b->u.i); 4416fbe7bf4SStefan Eßer assert_minus(a->u.i, b->u.i, r->u.i); 4421393277eSGarrett Wollman 4435b81b6b3SRodney W. Grimes free_value(a); 4445b81b6b3SRodney W. Grimes free_value(b); 44569759f08SStefan Eßer return (r); 4465b81b6b3SRodney W. Grimes } 4475b81b6b3SRodney W. Grimes 4486fbe7bf4SStefan Eßer void 4496fbe7bf4SStefan Eßer assert_times(intmax_t a, intmax_t b, intmax_t r) 450915198b4SStefan Eßer { 4516fbe7bf4SStefan Eßer /* 4526fbe7bf4SStefan Eßer * if first operand is 0, no overflow is possible, 4536fbe7bf4SStefan Eßer * else result of division test must match second operand 4546fbe7bf4SStefan Eßer */ 4556fbe7bf4SStefan Eßer if (a != 0 && r / a != b) 4566fbe7bf4SStefan Eßer errx(ERR_EXIT, "overflow"); 457915198b4SStefan Eßer } 458915198b4SStefan Eßer 4595b81b6b3SRodney W. Grimes struct val * 4607669d0fcSWarner Losh op_times(struct val *a, struct val *b) 4615b81b6b3SRodney W. Grimes { 4625b81b6b3SRodney W. Grimes struct val *r; 4635b81b6b3SRodney W. Grimes 464fa717604SStefan Eßer assert_to_integer(a); 465fa717604SStefan Eßer assert_to_integer(b); 4661393277eSGarrett Wollman r = make_integer(a->u.i * b->u.i); 4676fbe7bf4SStefan Eßer assert_times(a->u.i, b->u.i, r->u.i); 4681393277eSGarrett Wollman 4695b81b6b3SRodney W. Grimes free_value(a); 4705b81b6b3SRodney W. Grimes free_value(b); 4715b81b6b3SRodney W. Grimes return (r); 4725b81b6b3SRodney W. Grimes } 4735b81b6b3SRodney W. Grimes 4746fbe7bf4SStefan Eßer void 4756fbe7bf4SStefan Eßer assert_div(intmax_t a, intmax_t b) 476915198b4SStefan Eßer { 4776fbe7bf4SStefan Eßer if (b == 0) 4786fbe7bf4SStefan Eßer errx(ERR_EXIT, "division by zero"); 479f07e4247SGarrett Wollman /* only INTMAX_MIN / -1 causes overflow */ 480f07e4247SGarrett Wollman if (a == INTMAX_MIN && b == -1) 4816fbe7bf4SStefan Eßer errx(ERR_EXIT, "overflow"); 482915198b4SStefan Eßer } 483915198b4SStefan Eßer 4845b81b6b3SRodney W. Grimes struct val * 4857669d0fcSWarner Losh op_div(struct val *a, struct val *b) 4865b81b6b3SRodney W. Grimes { 4875b81b6b3SRodney W. Grimes struct val *r; 4885b81b6b3SRodney W. Grimes 489fa717604SStefan Eßer assert_to_integer(a); 490fa717604SStefan Eßer assert_to_integer(b); 4916fbe7bf4SStefan Eßer /* assert based on operands only, not on result */ 4926fbe7bf4SStefan Eßer assert_div(a->u.i, b->u.i); 493fa717604SStefan Eßer r = make_integer(a->u.i / b->u.i); 4941393277eSGarrett Wollman 4955b81b6b3SRodney W. Grimes free_value(a); 4965b81b6b3SRodney W. Grimes free_value(b); 49769759f08SStefan Eßer return (r); 4985b81b6b3SRodney W. Grimes } 4995b81b6b3SRodney W. Grimes 5005b81b6b3SRodney W. Grimes struct val * 5017669d0fcSWarner Losh op_rem(struct val *a, struct val *b) 5025b81b6b3SRodney W. Grimes { 5035b81b6b3SRodney W. Grimes struct val *r; 5045b81b6b3SRodney W. Grimes 505fa717604SStefan Eßer assert_to_integer(a); 506fa717604SStefan Eßer assert_to_integer(b); 5076fbe7bf4SStefan Eßer /* pass a=1 to only check for div by zero */ 5086fbe7bf4SStefan Eßer assert_div(1, b->u.i); 5091393277eSGarrett Wollman r = make_integer(a->u.i % b->u.i); 5101393277eSGarrett Wollman 5115b81b6b3SRodney W. Grimes free_value(a); 5125b81b6b3SRodney W. Grimes free_value(b); 51369759f08SStefan Eßer return (r); 5145b81b6b3SRodney W. Grimes } 5155b81b6b3SRodney W. Grimes 5165b81b6b3SRodney W. Grimes struct val * 5177669d0fcSWarner Losh op_colon(struct val *a, struct val *b) 5185b81b6b3SRodney W. Grimes { 5194ba5f298SAndrew Moore regex_t rp; 5204cf61abaSJ.T. Conklin regmatch_t rm[2]; 5214ba5f298SAndrew Moore char errbuf[256]; 5224ba5f298SAndrew Moore int eval; 5234ba5f298SAndrew Moore struct val *v; 524c9fe00dcSJ.T. Conklin 525e1854a84SCeri Davies /* coerce both arguments to strings */ 526c9fe00dcSJ.T. Conklin to_string(a); 527c9fe00dcSJ.T. Conklin to_string(b); 5285b81b6b3SRodney W. Grimes 5294ba5f298SAndrew Moore /* compile regular expression */ 5304a13ab7cSJ.T. Conklin if ((eval = regcomp(&rp, b->u.s, 0)) != 0) { 5314ba5f298SAndrew Moore regerror(eval, &rp, errbuf, sizeof(errbuf)); 532f07e4247SGarrett Wollman errx(ERR_EXIT, "%s", errbuf); 5335b81b6b3SRodney W. Grimes } 5344ba5f298SAndrew Moore 5354ba5f298SAndrew Moore /* compare string against pattern */ 5364a13ab7cSJ.T. Conklin /* remember that patterns are anchored to the beginning of the line */ 53769759f08SStefan Eßer if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 && rm[0].rm_so == 0) 5384ba5f298SAndrew Moore if (rm[1].rm_so >= 0) { 53955c497bfSJ.T. Conklin *(a->u.s + rm[1].rm_eo) = '\0'; 5404ba5f298SAndrew Moore v = make_str(a->u.s + rm[1].rm_so); 5414ba5f298SAndrew Moore 54269759f08SStefan Eßer } else 543*8c3bbba8SEitan Adler v = make_integer((intmax_t)(rm[0].rm_eo)); 54469759f08SStefan Eßer else 54569759f08SStefan Eßer if (rp.re_nsub == 0) 546f07e4247SGarrett Wollman v = make_integer((intmax_t)0); 54769759f08SStefan Eßer else 54855c497bfSJ.T. Conklin v = make_str(""); 5494ba5f298SAndrew Moore 5504ba5f298SAndrew Moore /* free arguments and pattern buffer */ 5514ba5f298SAndrew Moore free_value(a); 5524ba5f298SAndrew Moore free_value(b); 5534ba5f298SAndrew Moore regfree(&rp); 5544ba5f298SAndrew Moore 55569759f08SStefan Eßer return (v); 5564ba5f298SAndrew Moore } 557