expr.y revision 106065
1280905Sganbold%{ 2280905Sganbold/* Written by Pace Willisson (pace@blitz.com) 3280905Sganbold * and placed in the public domain. 4280905Sganbold * 5280905Sganbold * Largely rewritten by J.T. Conklin (jtc@wimsey.com) 6280905Sganbold * 7280905Sganbold * $FreeBSD: head/bin/expr/expr.y 106065 2002-10-28 00:15:43Z wollman $ 8280905Sganbold */ 9280905Sganbold 10280905Sganbold#include <sys/types.h> 11280905Sganbold 12280905Sganbold#include <ctype.h> 13280905Sganbold#include <err.h> 14280905Sganbold#include <errno.h> 15280905Sganbold#include <inttypes.h> 16280905Sganbold#include <limits.h> 17280905Sganbold#include <locale.h> 18280905Sganbold#include <stdio.h> 19280905Sganbold#include <stdlib.h> 20280905Sganbold#include <string.h> 21280905Sganbold#include <regex.h> 22280905Sganbold#include <unistd.h> 23280905Sganbold 24280905Sganbold/* 25280905Sganbold * POSIX specifies a specific error code for syntax errors. We exit 26280905Sganbold * with this code for all errors. 27280905Sganbold */ 28280905Sganbold#define ERR_EXIT 2 29280905Sganbold 30280905Sganboldenum valtype { 31280905Sganbold integer, numeric_string, string 32280905Sganbold} ; 33280905Sganbold 34280905Sganboldstruct val { 35280905Sganbold enum valtype type; 36280905Sganbold union { 37280905Sganbold char *s; 38280905Sganbold intmax_t i; 39280905Sganbold } u; 40280905Sganbold} ; 41280905Sganbold 42280905Sganboldstruct val *result; 43280905Sganbold 44280905Sganboldint chk_div(intmax_t, intmax_t); 45280905Sganboldint chk_minus(intmax_t, intmax_t, intmax_t); 46280905Sganboldint chk_plus(intmax_t, intmax_t, intmax_t); 47280905Sganboldint chk_times(intmax_t, intmax_t, intmax_t); 48280905Sganboldvoid free_value(struct val *); 49280905Sganboldint is_zero_or_null(struct val *); 50280905Sganboldint isstring(struct val *); 51280905Sganboldstruct val *make_integer(intmax_t); 52280905Sganboldstruct val *make_str(const char *); 53281092Sandrewstruct val *op_and(struct val *, struct val *); 54281092Sandrewstruct val *op_colon(struct val *, struct val *); 55281092Sandrewstruct val *op_div(struct val *, struct val *); 56280905Sganboldstruct val *op_eq(struct val *, struct val *); 57280905Sganboldstruct val *op_ge(struct val *, struct val *); 58280905Sganboldstruct val *op_gt(struct val *, struct val *); 59280905Sganboldstruct val *op_le(struct val *, struct val *); 60280905Sganboldstruct val *op_lt(struct val *, struct val *); 61280905Sganboldstruct val *op_minus(struct val *, struct val *); 62280905Sganboldstruct val *op_ne(struct val *, struct val *); 63280905Sganboldstruct val *op_or(struct val *, struct val *); 64280905Sganboldstruct val *op_plus(struct val *, struct val *); 65280905Sganboldstruct val *op_rem(struct val *, struct val *); 66280905Sganboldstruct val *op_times(struct val *, struct val *); 67280905Sganboldintmax_t to_integer(struct val *); 68280905Sganboldvoid to_string(struct val *); 69280905Sganboldint yyerror(const char *); 70280905Sganboldint yylex(void); 71280905Sganboldint yyparse(void); 72280905Sganbold 73280905Sganboldstatic int eflag; 74280905Sganboldchar **av; 75280905Sganbold%} 76280905Sganbold 77280905Sganbold%union 78280905Sganbold{ 79280905Sganbold struct val *val; 80280905Sganbold} 81280905Sganbold 82280905Sganbold%left <val> '|' 83280905Sganbold%left <val> '&' 84280905Sganbold%left <val> '=' '>' '<' GE LE NE 85280905Sganbold%left <val> '+' '-' 86280905Sganbold%left <val> '*' '/' '%' 87280905Sganbold%left <val> ':' 88280905Sganbold 89280905Sganbold%token <val> TOKEN 90280905Sganbold%type <val> start expr 91280905Sganbold 92280905Sganbold%% 93280905Sganbold 94280905Sganboldstart: expr { result = $$; } 95280905Sganbold 96280905Sganboldexpr: TOKEN 97280905Sganbold | '(' expr ')' { $$ = $2; } 98280905Sganbold | expr '|' expr { $$ = op_or ($1, $3); } 99280905Sganbold | expr '&' expr { $$ = op_and ($1, $3); } 100280905Sganbold | expr '=' expr { $$ = op_eq ($1, $3); } 101280905Sganbold | expr '>' expr { $$ = op_gt ($1, $3); } 102280905Sganbold | expr '<' expr { $$ = op_lt ($1, $3); } 103280905Sganbold | expr GE expr { $$ = op_ge ($1, $3); } 104280905Sganbold | expr LE expr { $$ = op_le ($1, $3); } 105280905Sganbold | expr NE expr { $$ = op_ne ($1, $3); } 106280905Sganbold | expr '+' expr { $$ = op_plus ($1, $3); } 107280905Sganbold | expr '-' expr { $$ = op_minus ($1, $3); } 108280905Sganbold | expr '*' expr { $$ = op_times ($1, $3); } 109280905Sganbold | expr '/' expr { $$ = op_div ($1, $3); } 110280905Sganbold | expr '%' expr { $$ = op_rem ($1, $3); } 111280905Sganbold | expr ':' expr { $$ = op_colon ($1, $3); } 112280905Sganbold ; 113280905Sganbold 114280905Sganbold 115280905Sganbold%% 116280905Sganbold 117280905Sganboldstruct val * 118280905Sganboldmake_integer(intmax_t i) 119280905Sganbold{ 120280905Sganbold struct val *vp; 121280905Sganbold 122280905Sganbold vp = (struct val *) malloc (sizeof (*vp)); 123280905Sganbold if (vp == NULL) { 124280905Sganbold errx(ERR_EXIT, "malloc() failed"); 125280905Sganbold } 126280905Sganbold 127280905Sganbold vp->type = integer; 128280905Sganbold vp->u.i = i; 129280905Sganbold return vp; 130280905Sganbold} 131280905Sganbold 132280905Sganboldstruct val * 133280905Sganboldmake_str(const char *s) 134280905Sganbold{ 135280905Sganbold struct val *vp; 136280905Sganbold char *ep; 137280905Sganbold 138280905Sganbold vp = (struct val *) malloc (sizeof (*vp)); 139280905Sganbold if (vp == NULL || ((vp->u.s = strdup (s)) == NULL)) { 140280905Sganbold errx(ERR_EXIT, "malloc() failed"); 141280905Sganbold } 142280905Sganbold 143280905Sganbold /* 144280905Sganbold * Previously we tried to scan the string to see if it ``looked like'' 145280905Sganbold * an integer (erroneously, as it happened). Let strtoimax() do the 146280905Sganbold * dirty work. We could cache the value, except that we are using 147280905Sganbold * a union and need to preserve the original string form until we 148280905Sganbold * are certain that it is not needed. 149280905Sganbold * 150280905Sganbold * IEEE Std.1003.1-2001 says: 151280905Sganbold * /integer/ An argument consisting only of an (optional) unary minus 152280905Sganbold * followed by digits. 153280905Sganbold * 154280905Sganbold * This means that arguments which consist of digits followed by 155280905Sganbold * non-digits MUST NOT be considered integers. strtoimax() will 156280905Sganbold * figure this out for us. 157280905Sganbold */ 158280905Sganbold if (eflag) 159280905Sganbold (void)strtoimax(s, &ep, 10); 160280905Sganbold else 161280905Sganbold (void)strtol(s, &ep, 10); 162280905Sganbold 163280905Sganbold if (*ep != '\0') 164280905Sganbold vp->type = string; 165280905Sganbold else 166280905Sganbold vp->type = numeric_string; 167280905Sganbold 168280905Sganbold return vp; 169280905Sganbold} 170280905Sganbold 171280905Sganbold 172280905Sganboldvoid 173280905Sganboldfree_value(struct val *vp) 174280905Sganbold{ 175280905Sganbold if (vp->type == string || vp->type == numeric_string) 176280905Sganbold free (vp->u.s); 177280905Sganbold} 178280905Sganbold 179280905Sganbold 180280905Sganboldintmax_t 181280905Sganboldto_integer(struct val *vp) 182280905Sganbold{ 183280905Sganbold intmax_t i; 184280905Sganbold 185280905Sganbold if (vp->type == integer) 186280905Sganbold return 1; 187280905Sganbold 188280905Sganbold if (vp->type == string) 189280905Sganbold return 0; 190280905Sganbold 191280905Sganbold /* vp->type == numeric_string, make it numeric */ 192280905Sganbold errno = 0; 193280905Sganbold if (eflag) { 194280905Sganbold i = strtoimax(vp->u.s, (char **)NULL, 10); 195280905Sganbold if (errno == ERANGE) 196280905Sganbold err(ERR_EXIT, NULL); 197280905Sganbold } else { 198280905Sganbold i = strtol(vp->u.s, (char **)NULL, 10); 199280905Sganbold } 200280905Sganbold 201280905Sganbold free (vp->u.s); 202280905Sganbold vp->u.i = i; 203280905Sganbold vp->type = integer; 204280905Sganbold return 1; 205280905Sganbold} 206280905Sganbold 207280905Sganboldvoid 208280905Sganboldto_string(struct val *vp) 209280905Sganbold{ 210280905Sganbold char *tmp; 211280905Sganbold 212280905Sganbold if (vp->type == string || vp->type == numeric_string) 213280905Sganbold return; 214280905Sganbold 215280905Sganbold /* 216280905Sganbold * log_10(x) ~= 0.3 * log_2(x). Rounding up gives the number 217280905Sganbold * of digits; add one each for the sign and terminating null 218280905Sganbold * character, respectively. 219280905Sganbold */ 220280905Sganbold#define NDIGITS(x) (3 * (sizeof(x) * CHAR_BIT) / 10 + 1 + 1 + 1) 221280905Sganbold tmp = malloc(NDIGITS(vp->u.i)); 222280905Sganbold if (tmp == NULL) 223280905Sganbold errx(ERR_EXIT, "malloc() failed"); 224280905Sganbold 225280905Sganbold sprintf(tmp, "%jd", vp->u.i); 226280905Sganbold vp->type = string; 227280905Sganbold vp->u.s = tmp; 228280905Sganbold} 229280905Sganbold 230280905Sganbold 231280905Sganboldint 232280905Sganboldisstring(struct val *vp) 233280905Sganbold{ 234280905Sganbold /* only TRUE if this string is not a valid integer */ 235280905Sganbold return (vp->type == string); 236280905Sganbold} 237280905Sganbold 238280905Sganbold 239280905Sganboldint 240280905Sganboldyylex(void) 241280905Sganbold{ 242280905Sganbold char *p; 243280905Sganbold 244280905Sganbold if (*av == NULL) 245280905Sganbold return (0); 246280905Sganbold 247280905Sganbold p = *av++; 248280905Sganbold 249280905Sganbold if (strlen (p) == 1) { 250280905Sganbold if (strchr ("|&=<>+-*/%:()", *p)) 251280905Sganbold return (*p); 252280905Sganbold } else if (strlen (p) == 2 && p[1] == '=') { 253280905Sganbold switch (*p) { 254280905Sganbold case '>': return (GE); 255280905Sganbold case '<': return (LE); 256280905Sganbold case '!': return (NE); 257280905Sganbold } 258280905Sganbold } 259280905Sganbold 260280905Sganbold yylval.val = make_str (p); 261280905Sganbold return (TOKEN); 262280905Sganbold} 263280905Sganbold 264280905Sganboldint 265280905Sganboldis_zero_or_null(struct val *vp) 266280905Sganbold{ 267280905Sganbold if (vp->type == integer) { 268280905Sganbold return (vp->u.i == 0); 269280905Sganbold } else { 270280905Sganbold return (*vp->u.s == 0 || (to_integer (vp) && vp->u.i == 0)); 271280905Sganbold } 272280905Sganbold /* NOTREACHED */ 273280905Sganbold} 274280905Sganbold 275280905Sganboldint 276280905Sganboldmain(int argc, char *argv[]) 277280905Sganbold{ 278280905Sganbold int c; 279280905Sganbold 280280905Sganbold setlocale (LC_ALL, ""); 281280905Sganbold if (getenv("EXPR_COMPAT") != NULL 282280905Sganbold || check_utility_compat("expr")) { 283280905Sganbold av = argv + 1; 284280905Sganbold eflag = 1; 285280905Sganbold } else { 286280905Sganbold while ((c = getopt(argc, argv, "e")) != -1) 287280905Sganbold switch (c) { 288280905Sganbold case 'e': 289280905Sganbold eflag = 1; 290280905Sganbold break; 291280905Sganbold 292280905Sganbold default: 293280905Sganbold fprintf(stderr, 294280905Sganbold "usage: expr [-e] expression\n"); 295280905Sganbold exit(ERR_EXIT); 296280905Sganbold } 297280905Sganbold av = argv + optind; 298280905Sganbold } 299280905Sganbold 300280905Sganbold yyparse(); 301280905Sganbold 302280905Sganbold if (result->type == integer) 303280905Sganbold printf("%jd\n", result->u.i); 304280905Sganbold else 305280905Sganbold printf("%s\n", result->u.s); 306280905Sganbold 307280905Sganbold return (is_zero_or_null(result)); 308280905Sganbold} 309280905Sganbold 310280905Sganboldint 311280905Sganboldyyerror(const char *s __unused) 312280905Sganbold{ 313280905Sganbold errx(ERR_EXIT, "syntax error"); 314280905Sganbold} 315280905Sganbold 316280905Sganbold 317280905Sganboldstruct val * 318280905Sganboldop_or(struct val *a, struct val *b) 319280905Sganbold{ 320280905Sganbold if (is_zero_or_null (a)) { 321280905Sganbold free_value (a); 322280905Sganbold return (b); 323280905Sganbold } else { 324280905Sganbold free_value (b); 325280905Sganbold return (a); 326280905Sganbold } 327280905Sganbold} 328280905Sganbold 329280905Sganboldstruct val * 330280905Sganboldop_and(struct val *a, struct val *b) 331280905Sganbold{ 332280905Sganbold if (is_zero_or_null (a) || is_zero_or_null (b)) { 333280905Sganbold free_value (a); 334280905Sganbold free_value (b); 335280905Sganbold return (make_integer ((intmax_t)0)); 336280905Sganbold } else { 337280905Sganbold free_value (b); 338280905Sganbold return (a); 339280905Sganbold } 340280905Sganbold} 341280905Sganbold 342280905Sganboldstruct val * 343280905Sganboldop_eq(struct val *a, struct val *b) 344280905Sganbold{ 345280905Sganbold struct val *r; 346280905Sganbold 347280905Sganbold if (isstring (a) || isstring (b)) { 348280905Sganbold to_string (a); 349280905Sganbold to_string (b); 350280905Sganbold r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) == 0)); 351280905Sganbold } else { 352280905Sganbold (void)to_integer(a); 353280905Sganbold (void)to_integer(b); 354280905Sganbold r = make_integer ((intmax_t)(a->u.i == b->u.i)); 355280905Sganbold } 356280905Sganbold 357280905Sganbold free_value (a); 358280905Sganbold free_value (b); 359280905Sganbold return r; 360280905Sganbold} 361280905Sganbold 362280905Sganboldstruct val * 363280905Sganboldop_gt(struct val *a, struct val *b) 364280905Sganbold{ 365280905Sganbold struct val *r; 366280905Sganbold 367280905Sganbold if (isstring (a) || isstring (b)) { 368280905Sganbold to_string (a); 369280905Sganbold to_string (b); 370280905Sganbold r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) > 0)); 371280905Sganbold } else { 372280905Sganbold (void)to_integer(a); 373280905Sganbold (void)to_integer(b); 374280905Sganbold r = make_integer ((intmax_t)(a->u.i > b->u.i)); 375280905Sganbold } 376280905Sganbold 377280905Sganbold free_value (a); 378280905Sganbold free_value (b); 379280905Sganbold return r; 380280905Sganbold} 381280905Sganbold 382280905Sganboldstruct val * 383280905Sganboldop_lt(struct val *a, struct val *b) 384280905Sganbold{ 385280905Sganbold struct val *r; 386280905Sganbold 387280905Sganbold if (isstring (a) || isstring (b)) { 388280905Sganbold to_string (a); 389280905Sganbold to_string (b); 390280905Sganbold r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) < 0)); 391280905Sganbold } else { 392280905Sganbold (void)to_integer(a); 393280905Sganbold (void)to_integer(b); 394280905Sganbold r = make_integer ((intmax_t)(a->u.i < b->u.i)); 395280905Sganbold } 396280905Sganbold 397280905Sganbold free_value (a); 398280905Sganbold free_value (b); 399280905Sganbold return r; 400280905Sganbold} 401280905Sganbold 402280905Sganboldstruct val * 403280905Sganboldop_ge(struct val *a, struct val *b) 404280905Sganbold{ 405280905Sganbold struct val *r; 406280905Sganbold 407280905Sganbold if (isstring (a) || isstring (b)) { 408280905Sganbold to_string (a); 409280905Sganbold to_string (b); 410280905Sganbold r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) >= 0)); 411280905Sganbold } else { 412280905Sganbold (void)to_integer(a); 413280905Sganbold (void)to_integer(b); 414280905Sganbold r = make_integer ((intmax_t)(a->u.i >= b->u.i)); 415280905Sganbold } 416280905Sganbold 417280905Sganbold free_value (a); 418280905Sganbold free_value (b); 419280905Sganbold return r; 420280905Sganbold} 421280905Sganbold 422280905Sganboldstruct val * 423280905Sganboldop_le(struct val *a, struct val *b) 424280905Sganbold{ 425280905Sganbold struct val *r; 426280905Sganbold 427280905Sganbold if (isstring (a) || isstring (b)) { 428280905Sganbold to_string (a); 429280905Sganbold to_string (b); 430280905Sganbold r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) <= 0)); 431280905Sganbold } else { 432280905Sganbold (void)to_integer(a); 433280905Sganbold (void)to_integer(b); 434280905Sganbold r = make_integer ((intmax_t)(a->u.i <= b->u.i)); 435280905Sganbold } 436280905Sganbold 437280905Sganbold free_value (a); 438280905Sganbold free_value (b); 439280905Sganbold return r; 440280905Sganbold} 441280905Sganbold 442280905Sganboldstruct val * 443280905Sganboldop_ne(struct val *a, struct val *b) 444280905Sganbold{ 445280905Sganbold struct val *r; 446280905Sganbold 447280905Sganbold if (isstring (a) || isstring (b)) { 448280905Sganbold to_string (a); 449280905Sganbold to_string (b); 450280905Sganbold r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) != 0)); 451280905Sganbold } else { 452280905Sganbold (void)to_integer(a); 453280905Sganbold (void)to_integer(b); 454280905Sganbold r = make_integer ((intmax_t)(a->u.i != b->u.i)); 455280905Sganbold } 456280905Sganbold 457280905Sganbold free_value (a); 458280905Sganbold free_value (b); 459280905Sganbold return r; 460280905Sganbold} 461280905Sganbold 462280905Sganboldint 463280905Sganboldchk_plus(intmax_t a, intmax_t b, intmax_t r) 464280905Sganbold{ 465280905Sganbold 466280905Sganbold /* sum of two positive numbers must be positive */ 467280905Sganbold if (a > 0 && b > 0 && r <= 0) 468280905Sganbold return 1; 469280905Sganbold /* sum of two negative numbers must be negative */ 470280905Sganbold if (a < 0 && b < 0 && r >= 0) 471280905Sganbold return 1; 472280905Sganbold /* all other cases are OK */ 473280905Sganbold return 0; 474280905Sganbold} 475280905Sganbold 476280905Sganboldstruct val * 477280905Sganboldop_plus(struct val *a, struct val *b) 478280905Sganbold{ 479280905Sganbold struct val *r; 480280905Sganbold 481280905Sganbold if (!to_integer(a) || !to_integer(b)) { 482280905Sganbold errx(ERR_EXIT, "non-numeric argument"); 483280905Sganbold } 484280905Sganbold 485280905Sganbold if (eflag) { 486280905Sganbold r = make_integer(a->u.i + b->u.i); 487280905Sganbold if (chk_plus(a->u.i, b->u.i, r->u.i)) { 488280905Sganbold errx(ERR_EXIT, "overflow"); 489280905Sganbold } 490280905Sganbold } else 491280905Sganbold r = make_integer((long)a->u.i + (long)b->u.i); 492280905Sganbold 493280905Sganbold free_value (a); 494280905Sganbold free_value (b); 495280905Sganbold return r; 496280905Sganbold} 497280905Sganbold 498280905Sganboldint 499280905Sganboldchk_minus(intmax_t a, intmax_t b, intmax_t r) 500280905Sganbold{ 501280905Sganbold 502280905Sganbold /* special case subtraction of INTMAX_MIN */ 503280905Sganbold if (b == INTMAX_MIN) { 504280905Sganbold if (a >= 0) 505280905Sganbold return 1; 506280905Sganbold else 507280905Sganbold return 0; 508280905Sganbold } 509280905Sganbold /* this is allowed for b != INTMAX_MIN */ 510280905Sganbold return chk_plus (a, -b, r); 511280905Sganbold} 512280905Sganbold 513280905Sganboldstruct val * 514280905Sganboldop_minus(struct val *a, struct val *b) 515280905Sganbold{ 516280905Sganbold struct val *r; 517280905Sganbold 518280905Sganbold if (!to_integer(a) || !to_integer(b)) { 519280905Sganbold errx(ERR_EXIT, "non-numeric argument"); 520280905Sganbold } 521280905Sganbold 522280905Sganbold if (eflag) { 523280905Sganbold r = make_integer(a->u.i - b->u.i); 524280905Sganbold if (chk_minus(a->u.i, b->u.i, r->u.i)) { 525280905Sganbold errx(ERR_EXIT, "overflow"); 526280905Sganbold } 527280905Sganbold } else 528280905Sganbold r = make_integer((long)a->u.i - (long)b->u.i); 529280905Sganbold 530280905Sganbold free_value (a); 531280905Sganbold free_value (b); 532280905Sganbold return r; 533280905Sganbold} 534280905Sganbold 535280905Sganboldint 536280905Sganboldchk_times(intmax_t a, intmax_t b, intmax_t r) 537280905Sganbold{ 538280905Sganbold /* special case: first operand is 0, no overflow possible */ 539280905Sganbold if (a == 0) 540280905Sganbold return 0; 541280905Sganbold /* cerify that result of division matches second operand */ 542280905Sganbold if (r / a != b) 543280905Sganbold return 1; 544280905Sganbold return 0; 545280905Sganbold} 546280905Sganbold 547280905Sganboldstruct val * 548280905Sganboldop_times(struct val *a, struct val *b) 549280905Sganbold{ 550280905Sganbold struct val *r; 551280905Sganbold 552280905Sganbold if (!to_integer(a) || !to_integer(b)) { 553280905Sganbold errx(ERR_EXIT, "non-numeric argument"); 554280905Sganbold } 555280905Sganbold 556280905Sganbold if (eflag) { 557280905Sganbold r = make_integer(a->u.i * b->u.i); 558280905Sganbold if (chk_times(a->u.i, b->u.i, r->u.i)) { 559280905Sganbold errx(ERR_EXIT, "overflow"); 560280905Sganbold } 561280905Sganbold } else 562280905Sganbold r = make_integer((long)a->u.i * (long)b->u.i); 563280905Sganbold 564280905Sganbold free_value (a); 565280905Sganbold free_value (b); 566280905Sganbold return (r); 567280905Sganbold} 568280905Sganbold 569280905Sganboldint 570280905Sganboldchk_div(intmax_t a, intmax_t b) 571280905Sganbold{ 572280905Sganbold /* div by zero has been taken care of before */ 573280905Sganbold /* only INTMAX_MIN / -1 causes overflow */ 574280905Sganbold if (a == INTMAX_MIN && b == -1) 575280905Sganbold return 1; 576280905Sganbold /* everything else is OK */ 577280905Sganbold return 0; 578280905Sganbold} 579280905Sganbold 580280905Sganboldstruct val * 581280905Sganboldop_div(struct val *a, struct val *b) 582280905Sganbold{ 583280905Sganbold struct val *r; 584280905Sganbold 585280905Sganbold if (!to_integer(a) || !to_integer(b)) { 586280905Sganbold errx(ERR_EXIT, "non-numeric argument"); 587280905Sganbold } 588280905Sganbold 589280905Sganbold if (b->u.i == 0) { 590280905Sganbold errx(ERR_EXIT, "division by zero"); 591280905Sganbold } 592280905Sganbold 593280905Sganbold if (eflag) { 594280905Sganbold r = make_integer(a->u.i / b->u.i); 595280905Sganbold if (chk_div(a->u.i, b->u.i)) { 596280905Sganbold errx(ERR_EXIT, "overflow"); 597280905Sganbold } 598280905Sganbold } else 599280905Sganbold r = make_integer((long)a->u.i / (long)b->u.i); 600280905Sganbold 601280905Sganbold free_value (a); 602280905Sganbold free_value (b); 603280905Sganbold return r; 604280905Sganbold} 605280905Sganbold 606280905Sganboldstruct val * 607280905Sganboldop_rem(struct val *a, struct val *b) 608280905Sganbold{ 609280905Sganbold struct val *r; 610280905Sganbold 611280905Sganbold if (!to_integer(a) || !to_integer(b)) { 612280905Sganbold errx(ERR_EXIT, "non-numeric argument"); 613280905Sganbold } 614280905Sganbold 615280905Sganbold if (b->u.i == 0) { 616280905Sganbold errx(ERR_EXIT, "division by zero"); 617280905Sganbold } 618280905Sganbold 619280905Sganbold if (eflag) 620280905Sganbold r = make_integer(a->u.i % b->u.i); 621280905Sganbold /* chk_rem necessary ??? */ 622280905Sganbold else 623280905Sganbold r = make_integer((long)a->u.i % (long)b->u.i); 624280905Sganbold 625280905Sganbold free_value (a); 626280905Sganbold free_value (b); 627280905Sganbold return r; 628280905Sganbold} 629280905Sganbold 630280905Sganboldstruct val * 631280905Sganboldop_colon(struct val *a, struct val *b) 632280905Sganbold{ 633280905Sganbold regex_t rp; 634280905Sganbold regmatch_t rm[2]; 635280905Sganbold char errbuf[256]; 636280905Sganbold int eval; 637280905Sganbold struct val *v; 638280905Sganbold 639280905Sganbold /* coerce to both arguments to strings */ 640280905Sganbold to_string(a); 641280905Sganbold to_string(b); 642280905Sganbold 643280905Sganbold /* compile regular expression */ 644280905Sganbold if ((eval = regcomp (&rp, b->u.s, 0)) != 0) { 645280905Sganbold regerror (eval, &rp, errbuf, sizeof(errbuf)); 646280905Sganbold errx(ERR_EXIT, "%s", errbuf); 647280905Sganbold } 648280905Sganbold 649280905Sganbold /* compare string against pattern */ 650280905Sganbold /* remember that patterns are anchored to the beginning of the line */ 651280905Sganbold if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 && rm[0].rm_so == 0) { 652280905Sganbold if (rm[1].rm_so >= 0) { 653280905Sganbold *(a->u.s + rm[1].rm_eo) = '\0'; 654280905Sganbold v = make_str (a->u.s + rm[1].rm_so); 655280905Sganbold 656280905Sganbold } else { 657280905Sganbold v = make_integer ((intmax_t)(rm[0].rm_eo - rm[0].rm_so)); 658280905Sganbold } 659280905Sganbold } else { 660280905Sganbold if (rp.re_nsub == 0) { 661 v = make_integer ((intmax_t)0); 662 } else { 663 v = make_str (""); 664 } 665 } 666 667 /* free arguments and pattern buffer */ 668 free_value (a); 669 free_value (b); 670 regfree (&rp); 671 672 return v; 673} 674