1 /* $OpenBSD: misc.c,v 1.55 2016/03/20 00:01:21 krw Exp $ */ 2 3 /* 4 * Miscellaneous functions 5 */ 6 7 #include <ctype.h> 8 #include <errno.h> 9 #include <fcntl.h> 10 #include <limits.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include <unistd.h> 14 15 #include "sh.h" 16 #include "charclass.h" 17 18 short ctypes [UCHAR_MAX+1]; /* type bits for unsigned char */ 19 20 static int do_gmatch(const unsigned char *, const unsigned char *, 21 const unsigned char *, const unsigned char *); 22 static const unsigned char *cclass(const unsigned char *, int); 23 24 /* 25 * Fast character classes 26 */ 27 void 28 setctypes(const char *s, int t) 29 { 30 int i; 31 32 if (t & C_IFS) { 33 for (i = 0; i < UCHAR_MAX+1; i++) 34 ctypes[i] &= ~C_IFS; 35 ctypes[0] |= C_IFS; /* include \0 in C_IFS */ 36 } 37 while (*s != 0) 38 ctypes[(unsigned char) *s++] |= t; 39 } 40 41 void 42 initctypes(void) 43 { 44 int c; 45 46 for (c = 'a'; c <= 'z'; c++) 47 ctypes[c] |= C_ALPHA; 48 for (c = 'A'; c <= 'Z'; c++) 49 ctypes[c] |= C_ALPHA; 50 ctypes['_'] |= C_ALPHA; 51 setctypes(" \t\n|&;<>()", C_LEX1); /* \0 added automatically */ 52 setctypes("*@#!$-?", C_VAR1); 53 setctypes(" \t\n", C_IFSWS); 54 setctypes("=-+?", C_SUBOP1); 55 setctypes("#%", C_SUBOP2); 56 setctypes(" \n\t\"#$&'()*;<>?[\\`|", C_QUOTE); 57 } 58 59 /* convert unsigned long to base N string */ 60 61 char * 62 ulton(long unsigned int n, int base) 63 { 64 char *p; 65 static char buf [20]; 66 67 p = &buf[sizeof(buf)]; 68 *--p = '\0'; 69 do { 70 *--p = "0123456789ABCDEF"[n%base]; 71 n /= base; 72 } while (n != 0); 73 return p; 74 } 75 76 char * 77 str_save(const char *s, Area *ap) 78 { 79 size_t len; 80 char *p; 81 82 if (!s) 83 return NULL; 84 len = strlen(s)+1; 85 p = alloc(len, ap); 86 strlcpy(p, s, len); 87 return (p); 88 } 89 90 /* Allocate a string of size n+1 and copy upto n characters from the possibly 91 * null terminated string s into it. Always returns a null terminated string 92 * (unless n < 0). 93 */ 94 char * 95 str_nsave(const char *s, int n, Area *ap) 96 { 97 char *ns; 98 99 if (n < 0) 100 return 0; 101 ns = alloc(n + 1, ap); 102 ns[0] = '\0'; 103 return strncat(ns, s, n); 104 } 105 106 /* called from expand.h:XcheckN() to grow buffer */ 107 char * 108 Xcheck_grow_(XString *xsp, char *xp, int more) 109 { 110 char *old_beg = xsp->beg; 111 112 xsp->len += more > xsp->len ? more : xsp->len; 113 xsp->beg = aresize(xsp->beg, xsp->len + 8, xsp->areap); 114 xsp->end = xsp->beg + xsp->len; 115 return xsp->beg + (xp - old_beg); 116 } 117 118 const struct option options[] = { 119 /* Special cases (see parse_args()): -A, -o, -s. 120 * Options are sorted by their longnames - the order of these 121 * entries MUST match the order of sh_flag F* enumerations in sh.h. 122 */ 123 { "allexport", 'a', OF_ANY }, 124 #ifdef BRACE_EXPAND 125 { "braceexpand", 0, OF_ANY }, /* non-standard */ 126 #endif 127 { "bgnice", 0, OF_ANY }, 128 { NULL, 'c', OF_CMDLINE }, 129 { "csh-history", 0, OF_ANY }, /* non-standard */ 130 #ifdef EMACS 131 { "emacs", 0, OF_ANY }, 132 { "emacs-usemeta", 0, OF_ANY }, /* non-standard */ 133 #endif 134 { "errexit", 'e', OF_ANY }, 135 #ifdef EMACS 136 { "gmacs", 0, OF_ANY }, 137 #endif 138 { "ignoreeof", 0, OF_ANY }, 139 { "interactive",'i', OF_CMDLINE }, 140 { "keyword", 'k', OF_ANY }, 141 { "login", 'l', OF_CMDLINE }, 142 { "markdirs", 'X', OF_ANY }, 143 #ifdef JOBS 144 { "monitor", 'm', OF_ANY }, 145 #else /* JOBS */ 146 { NULL, 'm', 0 }, /* so FMONITOR not ifdef'd */ 147 #endif /* JOBS */ 148 { "noclobber", 'C', OF_ANY }, 149 { "noexec", 'n', OF_ANY }, 150 { "noglob", 'f', OF_ANY }, 151 { "nohup", 0, OF_ANY }, 152 { "nolog", 0, OF_ANY }, /* no effect */ 153 #ifdef JOBS 154 { "notify", 'b', OF_ANY }, 155 #endif /* JOBS */ 156 { "nounset", 'u', OF_ANY }, 157 { "physical", 0, OF_ANY }, /* non-standard */ 158 { "posix", 0, OF_ANY }, /* non-standard */ 159 { "privileged", 'p', OF_ANY }, 160 { "restricted", 'r', OF_CMDLINE }, 161 { "sh", 0, OF_ANY }, /* non-standard */ 162 { "stdin", 's', OF_CMDLINE }, /* pseudo non-standard */ 163 { "trackall", 'h', OF_ANY }, 164 { "verbose", 'v', OF_ANY }, 165 #ifdef VI 166 { "vi", 0, OF_ANY }, 167 { "viraw", 0, OF_ANY }, /* no effect */ 168 { "vi-show8", 0, OF_ANY }, /* non-standard */ 169 { "vi-tabcomplete", 0, OF_ANY }, /* non-standard */ 170 { "vi-esccomplete", 0, OF_ANY }, /* non-standard */ 171 #endif 172 { "xtrace", 'x', OF_ANY }, 173 /* Anonymous flags: used internally by shell only 174 * (not visible to user) 175 */ 176 { NULL, 0, OF_INTERNAL }, /* FTALKING_I */ 177 }; 178 179 /* 180 * translate -o option into F* constant (also used for test -o option) 181 */ 182 int 183 option(const char *n) 184 { 185 int i; 186 187 for (i = 0; i < NELEM(options); i++) 188 if (options[i].name && strcmp(options[i].name, n) == 0) 189 return i; 190 191 return -1; 192 } 193 194 struct options_info { 195 int opt_width; 196 struct { 197 const char *name; 198 int flag; 199 } opts[NELEM(options)]; 200 }; 201 202 static char *options_fmt_entry(void *arg, int i, char *buf, int buflen); 203 static void printoptions(int verbose); 204 205 /* format a single select menu item */ 206 static char * 207 options_fmt_entry(void *arg, int i, char *buf, int buflen) 208 { 209 struct options_info *oi = (struct options_info *) arg; 210 211 shf_snprintf(buf, buflen, "%-*s %s", 212 oi->opt_width, oi->opts[i].name, 213 Flag(oi->opts[i].flag) ? "on" : "off"); 214 return buf; 215 } 216 217 static void 218 printoptions(int verbose) 219 { 220 int i; 221 222 if (verbose) { 223 struct options_info oi; 224 int n, len; 225 226 /* verbose version */ 227 shprintf("Current option settings\n"); 228 229 for (i = n = oi.opt_width = 0; i < NELEM(options); i++) 230 if (options[i].name) { 231 len = strlen(options[i].name); 232 oi.opts[n].name = options[i].name; 233 oi.opts[n++].flag = i; 234 if (len > oi.opt_width) 235 oi.opt_width = len; 236 } 237 print_columns(shl_stdout, n, options_fmt_entry, &oi, 238 oi.opt_width + 5, 1); 239 } else { 240 /* short version ala ksh93 */ 241 shprintf("set"); 242 for (i = 0; i < NELEM(options); i++) 243 if (options[i].name) 244 shprintf(" %co %s", 245 Flag(i) ? '-' : '+', 246 options[i].name); 247 shprintf("\n"); 248 } 249 } 250 251 char * 252 getoptions(void) 253 { 254 int i; 255 char m[(int) FNFLAGS + 1]; 256 char *cp = m; 257 258 for (i = 0; i < NELEM(options); i++) 259 if (options[i].c && Flag(i)) 260 *cp++ = options[i].c; 261 *cp = 0; 262 return str_save(m, ATEMP); 263 } 264 265 /* change a Flag(*) value; takes care of special actions */ 266 void 267 change_flag(enum sh_flag f, 268 int what, /* flag to change */ 269 int newval) /* what is changing the flag (command line vs set) */ 270 { 271 int oldval; 272 273 oldval = Flag(f); 274 Flag(f) = newval; 275 #ifdef JOBS 276 if (f == FMONITOR) { 277 if (what != OF_CMDLINE && newval != oldval) 278 j_change(); 279 } else 280 #endif /* JOBS */ 281 #ifdef EDIT 282 if (0 283 # ifdef VI 284 || f == FVI 285 # endif /* VI */ 286 # ifdef EMACS 287 || f == FEMACS || f == FGMACS 288 # endif /* EMACS */ 289 ) 290 { 291 if (newval) { 292 # ifdef VI 293 Flag(FVI) = 0; 294 # endif /* VI */ 295 # ifdef EMACS 296 Flag(FEMACS) = Flag(FGMACS) = 0; 297 # endif /* EMACS */ 298 Flag(f) = newval; 299 } 300 } else 301 #endif /* EDIT */ 302 /* Turning off -p? */ 303 if (f == FPRIVILEGED && oldval && !newval) { 304 gid_t gid = getgid(); 305 306 setresgid(gid, gid, gid); 307 setgroups(1, &gid); 308 setresuid(ksheuid, ksheuid, ksheuid); 309 } else if (f == FPOSIX && newval) { 310 #ifdef BRACE_EXPAND 311 Flag(FBRACEEXPAND) = 0 312 #endif /* BRACE_EXPAND */ 313 ; 314 } 315 /* Changing interactive flag? */ 316 if (f == FTALKING) { 317 if ((what == OF_CMDLINE || what == OF_SET) && procpid == kshpid) 318 Flag(FTALKING_I) = newval; 319 } 320 } 321 322 /* parse command line & set command arguments. returns the index of 323 * non-option arguments, -1 if there is an error. 324 */ 325 int 326 parse_args(char **argv, 327 int what, /* OF_CMDLINE or OF_SET */ 328 int *setargsp) 329 { 330 static char cmd_opts[NELEM(options) + 3]; /* o:\0 */ 331 static char set_opts[NELEM(options) + 5]; /* Ao;s\0 */ 332 char *opts; 333 char *array = NULL; 334 Getopt go; 335 int i, optc, set, sortargs = 0, arrayset = 0; 336 337 /* First call? Build option strings... */ 338 if (cmd_opts[0] == '\0') { 339 char *p, *q; 340 341 /* see cmd_opts[] declaration */ 342 strlcpy(cmd_opts, "o:", sizeof cmd_opts); 343 p = cmd_opts + strlen(cmd_opts); 344 /* see set_opts[] declaration */ 345 strlcpy(set_opts, "A:o;s", sizeof set_opts); 346 q = set_opts + strlen(set_opts); 347 for (i = 0; i < NELEM(options); i++) { 348 if (options[i].c) { 349 if (options[i].flags & OF_CMDLINE) 350 *p++ = options[i].c; 351 if (options[i].flags & OF_SET) 352 *q++ = options[i].c; 353 } 354 } 355 *p = '\0'; 356 *q = '\0'; 357 } 358 359 if (what == OF_CMDLINE) { 360 char *p; 361 /* Set FLOGIN before parsing options so user can clear 362 * flag using +l. 363 */ 364 Flag(FLOGIN) = (argv[0][0] == '-' || 365 ((p = strrchr(argv[0], '/')) && *++p == '-')); 366 opts = cmd_opts; 367 } else 368 opts = set_opts; 369 ksh_getopt_reset(&go, GF_ERROR|GF_PLUSOPT); 370 while ((optc = ksh_getopt(argv, &go, opts)) != -1) { 371 set = (go.info & GI_PLUS) ? 0 : 1; 372 switch (optc) { 373 case 'A': 374 arrayset = set ? 1 : -1; 375 array = go.optarg; 376 break; 377 378 case 'o': 379 if (go.optarg == NULL) { 380 /* lone -o: print options 381 * 382 * Note that on the command line, -o requires 383 * an option (ie, can't get here if what is 384 * OF_CMDLINE). 385 */ 386 printoptions(set); 387 break; 388 } 389 i = option(go.optarg); 390 if (i >= 0 && set == Flag(i)) 391 /* Don't check the context if the flag 392 * isn't changing - makes "set -o interactive" 393 * work if you're already interactive. Needed 394 * if the output of "set +o" is to be used. 395 */ 396 ; 397 else if (i >= 0 && (options[i].flags & what)) 398 change_flag((enum sh_flag) i, what, set); 399 else { 400 bi_errorf("%s: bad option", go.optarg); 401 return -1; 402 } 403 break; 404 405 case '?': 406 return -1; 407 408 default: 409 /* -s: sort positional params (at&t ksh stupidity) */ 410 if (what == OF_SET && optc == 's') { 411 sortargs = 1; 412 break; 413 } 414 for (i = 0; i < NELEM(options); i++) 415 if (optc == options[i].c && 416 (what & options[i].flags)) { 417 change_flag((enum sh_flag) i, what, 418 set); 419 break; 420 } 421 if (i == NELEM(options)) { 422 internal_errorf(1, "parse_args: `%c'", optc); 423 return -1; /* not reached */ 424 } 425 } 426 } 427 if (!(go.info & GI_MINUSMINUS) && argv[go.optind] && 428 (argv[go.optind][0] == '-' || argv[go.optind][0] == '+') && 429 argv[go.optind][1] == '\0') { 430 /* lone - clears -v and -x flags */ 431 if (argv[go.optind][0] == '-' && !Flag(FPOSIX)) 432 Flag(FVERBOSE) = Flag(FXTRACE) = 0; 433 /* set skips lone - or + option */ 434 go.optind++; 435 } 436 if (setargsp) 437 /* -- means set $#/$* even if there are no arguments */ 438 *setargsp = !arrayset && ((go.info & GI_MINUSMINUS) || 439 argv[go.optind]); 440 441 if (arrayset && (!*array || *skip_varname(array, false))) { 442 bi_errorf("%s: is not an identifier", array); 443 return -1; 444 } 445 if (sortargs) { 446 for (i = go.optind; argv[i]; i++) 447 ; 448 qsortp((void **) &argv[go.optind], (size_t) (i - go.optind), 449 xstrcmp); 450 } 451 if (arrayset) { 452 set_array(array, arrayset, argv + go.optind); 453 for (; argv[go.optind]; go.optind++) 454 ; 455 } 456 457 return go.optind; 458 } 459 460 /* parse a decimal number: returns 0 if string isn't a number, 1 otherwise */ 461 int 462 getn(const char *as, int *ai) 463 { 464 char *p; 465 long n; 466 467 n = strtol(as, &p, 10); 468 469 if (!*as || *p || INT_MIN >= n || n >= INT_MAX) 470 return 0; 471 472 *ai = (int)n; 473 return 1; 474 } 475 476 /* getn() that prints error */ 477 int 478 bi_getn(const char *as, int *ai) 479 { 480 int rv = getn(as, ai); 481 482 if (!rv) 483 bi_errorf("%s: bad number", as); 484 return rv; 485 } 486 487 /* -------- gmatch.c -------- */ 488 489 /* 490 * int gmatch(string, pattern) 491 * char *string, *pattern; 492 * 493 * Match a pattern as in sh(1). 494 * pattern character are prefixed with MAGIC by expand. 495 */ 496 497 int 498 gmatch(const char *s, const char *p, int isfile) 499 { 500 const char *se, *pe; 501 502 if (s == NULL || p == NULL) 503 return 0; 504 se = s + strlen(s); 505 pe = p + strlen(p); 506 /* isfile is false iff no syntax check has been done on 507 * the pattern. If check fails, just to a strcmp(). 508 */ 509 if (!isfile && !has_globbing(p, pe)) { 510 int len = pe - p + 1; 511 char tbuf[64]; 512 char *t = len <= sizeof(tbuf) ? tbuf : 513 alloc(len, ATEMP); 514 debunk(t, p, len); 515 return !strcmp(t, s); 516 } 517 return do_gmatch((const unsigned char *) s, (const unsigned char *) se, 518 (const unsigned char *) p, (const unsigned char *) pe); 519 } 520 521 /* Returns if p is a syntacticly correct globbing pattern, false 522 * if it contains no pattern characters or if there is a syntax error. 523 * Syntax errors are: 524 * - [ with no closing ] 525 * - imbalanced $(...) expression 526 * - [...] and *(...) not nested (eg, [a$(b|]c), *(a[b|c]d)) 527 */ 528 /*XXX 529 - if no magic, 530 if dest given, copy to dst 531 return ? 532 - if magic && (no globbing || syntax error) 533 debunk to dst 534 return ? 535 - return ? 536 */ 537 int 538 has_globbing(const char *xp, const char *xpe) 539 { 540 const unsigned char *p = (const unsigned char *) xp; 541 const unsigned char *pe = (const unsigned char *) xpe; 542 int c; 543 int nest = 0, bnest = 0; 544 int saw_glob = 0; 545 int in_bracket = 0; /* inside [...] */ 546 547 for (; p < pe; p++) { 548 if (!ISMAGIC(*p)) 549 continue; 550 if ((c = *++p) == '*' || c == '?') 551 saw_glob = 1; 552 else if (c == '[') { 553 if (!in_bracket) { 554 saw_glob = 1; 555 in_bracket = 1; 556 if (ISMAGIC(p[1]) && p[2] == '!') 557 p += 2; 558 if (ISMAGIC(p[1]) && p[2] == ']') 559 p += 2; 560 } 561 /* XXX Do we need to check ranges here? POSIX Q */ 562 } else if (c == ']') { 563 if (in_bracket) { 564 if (bnest) /* [a*(b]) */ 565 return 0; 566 in_bracket = 0; 567 } 568 } else if ((c & 0x80) && strchr("*+?@! ", c & 0x7f)) { 569 saw_glob = 1; 570 if (in_bracket) 571 bnest++; 572 else 573 nest++; 574 } else if (c == '|') { 575 if (in_bracket && !bnest) /* *(a[foo|bar]) */ 576 return 0; 577 } else if (c == /*(*/ ')') { 578 if (in_bracket) { 579 if (!bnest--) /* *(a[b)c] */ 580 return 0; 581 } else if (nest) 582 nest--; 583 } 584 /* else must be a MAGIC-MAGIC, or MAGIC-!, MAGIC--, MAGIC-] 585 MAGIC-{, MAGIC-,, MAGIC-} */ 586 } 587 return saw_glob && !in_bracket && !nest; 588 } 589 590 /* Function must return either 0 or 1 (assumed by code for 0x80|'!') */ 591 static int 592 do_gmatch(const unsigned char *s, const unsigned char *se, 593 const unsigned char *p, const unsigned char *pe) 594 { 595 int sc, pc; 596 const unsigned char *prest, *psub, *pnext; 597 const unsigned char *srest; 598 599 if (s == NULL || p == NULL) 600 return 0; 601 while (p < pe) { 602 pc = *p++; 603 sc = s < se ? *s : '\0'; 604 s++; 605 if (!ISMAGIC(pc)) { 606 if (sc != pc) 607 return 0; 608 continue; 609 } 610 switch (*p++) { 611 case '[': 612 if (sc == 0 || (p = cclass(p, sc)) == NULL) 613 return 0; 614 break; 615 616 case '?': 617 if (sc == 0) 618 return 0; 619 break; 620 621 case '*': 622 if (p == pe) 623 return 1; 624 s--; 625 do { 626 if (do_gmatch(s, se, p, pe)) 627 return 1; 628 } while (s++ < se); 629 return 0; 630 631 /* 632 * [*+?@!](pattern|pattern|..) 633 * 634 * Not ifdef'd KSH as this is needed for ${..%..}, etc. 635 */ 636 case 0x80|'+': /* matches one or more times */ 637 case 0x80|'*': /* matches zero or more times */ 638 if (!(prest = pat_scan(p, pe, 0))) 639 return 0; 640 s--; 641 /* take care of zero matches */ 642 if (p[-1] == (0x80 | '*') && 643 do_gmatch(s, se, prest, pe)) 644 return 1; 645 for (psub = p; ; psub = pnext) { 646 pnext = pat_scan(psub, pe, 1); 647 for (srest = s; srest <= se; srest++) { 648 if (do_gmatch(s, srest, psub, pnext - 2) && 649 (do_gmatch(srest, se, prest, pe) || 650 (s != srest && do_gmatch(srest, 651 se, p - 2, pe)))) 652 return 1; 653 } 654 if (pnext == prest) 655 break; 656 } 657 return 0; 658 659 case 0x80|'?': /* matches zero or once */ 660 case 0x80|'@': /* matches one of the patterns */ 661 case 0x80|' ': /* simile for @ */ 662 if (!(prest = pat_scan(p, pe, 0))) 663 return 0; 664 s--; 665 /* Take care of zero matches */ 666 if (p[-1] == (0x80 | '?') && 667 do_gmatch(s, se, prest, pe)) 668 return 1; 669 for (psub = p; ; psub = pnext) { 670 pnext = pat_scan(psub, pe, 1); 671 srest = prest == pe ? se : s; 672 for (; srest <= se; srest++) { 673 if (do_gmatch(s, srest, psub, pnext - 2) && 674 do_gmatch(srest, se, prest, pe)) 675 return 1; 676 } 677 if (pnext == prest) 678 break; 679 } 680 return 0; 681 682 case 0x80|'!': /* matches none of the patterns */ 683 if (!(prest = pat_scan(p, pe, 0))) 684 return 0; 685 s--; 686 for (srest = s; srest <= se; srest++) { 687 int matched = 0; 688 689 for (psub = p; ; psub = pnext) { 690 pnext = pat_scan(psub, pe, 1); 691 if (do_gmatch(s, srest, psub, 692 pnext - 2)) { 693 matched = 1; 694 break; 695 } 696 if (pnext == prest) 697 break; 698 } 699 if (!matched && 700 do_gmatch(srest, se, prest, pe)) 701 return 1; 702 } 703 return 0; 704 705 default: 706 if (sc != p[-1]) 707 return 0; 708 break; 709 } 710 } 711 return s == se; 712 } 713 714 static int 715 posix_cclass(const unsigned char *pattern, int test, const unsigned char **ep) 716 { 717 struct cclass *cc; 718 const unsigned char *colon; 719 size_t len; 720 int rval = 0; 721 722 if ((colon = strchr(pattern, ':')) == NULL || colon[1] != MAGIC) { 723 *ep = pattern - 2; 724 return -1; 725 } 726 *ep = colon + 3; /* skip MAGIC */ 727 len = (size_t)(colon - pattern); 728 729 for (cc = cclasses; cc->name != NULL; cc++) { 730 if (!strncmp(pattern, cc->name, len) && cc->name[len] == '\0') { 731 if (cc->isctype(test)) 732 rval = 1; 733 break; 734 } 735 } 736 if (cc->name == NULL) { 737 rval = -2; /* invalid character class */ 738 } 739 return rval; 740 } 741 742 static const unsigned char * 743 cclass(const unsigned char *p, int sub) 744 { 745 int c, d, rv, not, found = 0; 746 const unsigned char *orig_p = p; 747 748 if ((not = (ISMAGIC(*p) && *++p == '!'))) 749 p++; 750 do { 751 /* check for POSIX character class (e.g. [[:alpha:]]) */ 752 if ((p[0] == MAGIC && p[1] == '[' && p[2] == ':') || 753 (p[0] == '[' && p[1] == ':')) { 754 do { 755 const char *pp = p + (*p == MAGIC) + 2; 756 rv = posix_cclass(pp, sub, &p); 757 switch (rv) { 758 case 1: 759 found = 1; 760 break; 761 case -2: 762 return NULL; 763 } 764 } while (rv != -1 && p[0] == MAGIC && p[1] == '[' && p[2] == ':'); 765 if (p[0] == MAGIC && p[1] == ']') 766 break; 767 } 768 769 c = *p++; 770 if (ISMAGIC(c)) { 771 c = *p++; 772 if ((c & 0x80) && !ISMAGIC(c)) { 773 c &= 0x7f;/* extended pattern matching: *+?@! */ 774 /* XXX the ( char isn't handled as part of [] */ 775 if (c == ' ') /* simile for @: plain (..) */ 776 c = '(' /*)*/; 777 } 778 } 779 if (c == '\0') 780 /* No closing ] - act as if the opening [ was quoted */ 781 return sub == '[' ? orig_p : NULL; 782 if (ISMAGIC(p[0]) && p[1] == '-' && 783 (!ISMAGIC(p[2]) || p[3] != ']')) { 784 p += 2; /* MAGIC- */ 785 d = *p++; 786 if (ISMAGIC(d)) { 787 d = *p++; 788 if ((d & 0x80) && !ISMAGIC(d)) 789 d &= 0x7f; 790 } 791 /* POSIX says this is an invalid expression */ 792 if (c > d) 793 return NULL; 794 } else 795 d = c; 796 if (c == sub || (c <= sub && sub <= d)) 797 found = 1; 798 } while (!(ISMAGIC(p[0]) && p[1] == ']')); 799 800 return (found != not) ? p+2 : NULL; 801 } 802 803 /* Look for next ) or | (if match_sep) in *(foo|bar) pattern */ 804 const unsigned char * 805 pat_scan(const unsigned char *p, const unsigned char *pe, int match_sep) 806 { 807 int nest = 0; 808 809 for (; p < pe; p++) { 810 if (!ISMAGIC(*p)) 811 continue; 812 if ((*++p == /*(*/ ')' && nest-- == 0) || 813 (*p == '|' && match_sep && nest == 0)) 814 return ++p; 815 if ((*p & 0x80) && strchr("*+?@! ", *p & 0x7f)) 816 nest++; 817 } 818 return NULL; 819 } 820 821 /* 822 * quick sort of array of generic pointers to objects. 823 */ 824 void 825 qsortp(void **base, /* base address */ 826 size_t n, /* elements */ 827 int (*f) (const void *, const void *)) /* compare function */ 828 { 829 qsort(base, n, sizeof(char *), f); 830 } 831 832 int 833 xstrcmp(const void *p1, const void *p2) 834 { 835 return (strcmp(*(char **)p1, *(char **)p2)); 836 } 837 838 /* Initialize a Getopt structure */ 839 void 840 ksh_getopt_reset(Getopt *go, int flags) 841 { 842 go->optind = 1; 843 go->optarg = NULL; 844 go->p = 0; 845 go->flags = flags; 846 go->info = 0; 847 go->buf[1] = '\0'; 848 } 849 850 851 /* getopt() used for shell built-in commands, the getopts command, and 852 * command line options. 853 * A leading ':' in options means don't print errors, instead return '?' 854 * or ':' and set go->optarg to the offending option character. 855 * If GF_ERROR is set (and option doesn't start with :), errors result in 856 * a call to bi_errorf(). 857 * 858 * Non-standard features: 859 * - ';' is like ':' in options, except the argument is optional 860 * (if it isn't present, optarg is set to 0). 861 * Used for 'set -o'. 862 * - ',' is like ':' in options, except the argument always immediately 863 * follows the option character (optarg is set to the null string if 864 * the option is missing). 865 * Used for 'read -u2', 'print -u2' and fc -40. 866 * - '#' is like ':' in options, expect that the argument is optional 867 * and must start with a digit or be the string "unlimited". If the 868 * argument doesn't match, it is assumed to be missing and normal option 869 * processing continues (optarg is set to 0 if the option is missing). 870 * Used for 'typeset -LZ4' and 'ulimit -adunlimited'. 871 * - accepts +c as well as -c IF the GF_PLUSOPT flag is present. If an 872 * option starting with + is accepted, the GI_PLUS flag will be set 873 * in go->info. 874 */ 875 int 876 ksh_getopt(char **argv, Getopt *go, const char *options) 877 { 878 char c; 879 char *o; 880 881 if (go->p == 0 || (c = argv[go->optind - 1][go->p]) == '\0') { 882 char *arg = argv[go->optind], flag = arg ? *arg : '\0'; 883 884 go->p = 1; 885 if (flag == '-' && arg[1] == '-' && arg[2] == '\0') { 886 go->optind++; 887 go->p = 0; 888 go->info |= GI_MINUSMINUS; 889 return -1; 890 } 891 if (arg == NULL || 892 ((flag != '-' ) && /* neither a - nor a + (if + allowed) */ 893 (!(go->flags & GF_PLUSOPT) || flag != '+')) || 894 (c = arg[1]) == '\0') { 895 go->p = 0; 896 return -1; 897 } 898 go->optind++; 899 go->info &= ~(GI_MINUS|GI_PLUS); 900 go->info |= flag == '-' ? GI_MINUS : GI_PLUS; 901 } 902 go->p++; 903 if (c == '?' || c == ':' || c == ';' || c == ',' || c == '#' || 904 !(o = strchr(options, c))) { 905 if (options[0] == ':') { 906 go->buf[0] = c; 907 go->optarg = go->buf; 908 } else { 909 warningf(true, "%s%s-%c: unknown option", 910 (go->flags & GF_NONAME) ? "" : argv[0], 911 (go->flags & GF_NONAME) ? "" : ": ", c); 912 if (go->flags & GF_ERROR) 913 bi_errorf(NULL); 914 } 915 return '?'; 916 } 917 /* : means argument must be present, may be part of option argument 918 * or the next argument 919 * ; same as : but argument may be missing 920 * , means argument is part of option argument, and may be null. 921 */ 922 if (*++o == ':' || *o == ';') { 923 if (argv[go->optind - 1][go->p]) 924 go->optarg = argv[go->optind - 1] + go->p; 925 else if (argv[go->optind]) 926 go->optarg = argv[go->optind++]; 927 else if (*o == ';') 928 go->optarg = NULL; 929 else { 930 if (options[0] == ':') { 931 go->buf[0] = c; 932 go->optarg = go->buf; 933 return ':'; 934 } 935 warningf(true, "%s%s-`%c' requires argument", 936 (go->flags & GF_NONAME) ? "" : argv[0], 937 (go->flags & GF_NONAME) ? "" : ": ", c); 938 if (go->flags & GF_ERROR) 939 bi_errorf(NULL); 940 return '?'; 941 } 942 go->p = 0; 943 } else if (*o == ',') { 944 /* argument is attached to option character, even if null */ 945 go->optarg = argv[go->optind - 1] + go->p; 946 go->p = 0; 947 } else if (*o == '#') { 948 /* argument is optional and may be attached or unattached 949 * but must start with a digit. optarg is set to 0 if the 950 * argument is missing. 951 */ 952 if (argv[go->optind - 1][go->p]) { 953 if (digit(argv[go->optind - 1][go->p]) || 954 !strcmp(&argv[go->optind - 1][go->p], "unlimited")) { 955 go->optarg = argv[go->optind - 1] + go->p; 956 go->p = 0; 957 } else 958 go->optarg = NULL; 959 } else { 960 if (argv[go->optind] && (digit(argv[go->optind][0]) || 961 !strcmp(argv[go->optind], "unlimited"))) { 962 go->optarg = argv[go->optind++]; 963 go->p = 0; 964 } else 965 go->optarg = NULL; 966 } 967 } 968 return c; 969 } 970 971 /* print variable/alias value using necessary quotes 972 * (POSIX says they should be suitable for re-entry...) 973 * No trailing newline is printed. 974 */ 975 void 976 print_value_quoted(const char *s) 977 { 978 const char *p; 979 int inquote = 0; 980 981 /* Test if any quotes are needed */ 982 for (p = s; *p; p++) 983 if (ctype(*p, C_QUOTE)) 984 break; 985 if (!*p) { 986 shprintf("%s", s); 987 return; 988 } 989 for (p = s; *p; p++) { 990 if (*p == '\'') { 991 shprintf(inquote ? "'\\'" : "\\'"); 992 inquote = 0; 993 } else { 994 if (!inquote) { 995 shprintf("'"); 996 inquote = 1; 997 } 998 shf_putc(*p, shl_stdout); 999 } 1000 } 1001 if (inquote) 1002 shprintf("'"); 1003 } 1004 1005 /* Print things in columns and rows - func() is called to format the ith 1006 * element 1007 */ 1008 void 1009 print_columns(struct shf *shf, int n, char *(*func) (void *, int, char *, int), 1010 void *arg, int max_width, int prefcol) 1011 { 1012 char *str = alloc(max_width + 1, ATEMP); 1013 int i; 1014 int r, c; 1015 int rows, cols; 1016 int nspace; 1017 int col_width; 1018 1019 /* max_width + 1 for the space. Note that no space 1020 * is printed after the last column to avoid problems 1021 * with terminals that have auto-wrap. 1022 */ 1023 cols = x_cols / (max_width + 1); 1024 if (!cols) 1025 cols = 1; 1026 rows = (n + cols - 1) / cols; 1027 if (prefcol && n && cols > rows) { 1028 int tmp = rows; 1029 1030 rows = cols; 1031 cols = tmp; 1032 if (rows > n) 1033 rows = n; 1034 } 1035 1036 col_width = max_width; 1037 if (cols == 1) 1038 col_width = 0; /* Don't pad entries in single column output. */ 1039 nspace = (x_cols - max_width * cols) / cols; 1040 if (nspace <= 0) 1041 nspace = 1; 1042 for (r = 0; r < rows; r++) { 1043 for (c = 0; c < cols; c++) { 1044 i = c * rows + r; 1045 if (i < n) { 1046 shf_fprintf(shf, "%-*s", 1047 col_width, 1048 (*func)(arg, i, str, max_width + 1)); 1049 if (c + 1 < cols) 1050 shf_fprintf(shf, "%*s", nspace, ""); 1051 } 1052 } 1053 shf_putchar('\n', shf); 1054 } 1055 afree(str, ATEMP); 1056 } 1057 1058 /* Strip any nul bytes from buf - returns new length (nbytes - # of nuls) */ 1059 int 1060 strip_nuls(char *buf, int nbytes) 1061 { 1062 char *dst; 1063 1064 if ((dst = memchr(buf, '\0', nbytes))) { 1065 char *end = buf + nbytes; 1066 char *p, *q; 1067 1068 for (p = dst; p < end; p = q) { 1069 /* skip a block of nulls */ 1070 while (++p < end && *p == '\0') 1071 ; 1072 /* find end of non-null block */ 1073 if (!(q = memchr(p, '\0', end - p))) 1074 q = end; 1075 memmove(dst, p, q - p); 1076 dst += q - p; 1077 } 1078 *dst = '\0'; 1079 return dst - buf; 1080 } 1081 return nbytes; 1082 } 1083 1084 /* Like read(2), but if read fails due to non-blocking flag, resets flag 1085 * and restarts read. 1086 */ 1087 int 1088 blocking_read(int fd, char *buf, int nbytes) 1089 { 1090 int ret; 1091 int tried_reset = 0; 1092 1093 while ((ret = read(fd, buf, nbytes)) < 0) { 1094 if (!tried_reset && errno == EAGAIN) { 1095 int oerrno = errno; 1096 if (reset_nonblock(fd) > 0) { 1097 tried_reset = 1; 1098 continue; 1099 } 1100 errno = oerrno; 1101 } 1102 break; 1103 } 1104 return ret; 1105 } 1106 1107 /* Reset the non-blocking flag on the specified file descriptor. 1108 * Returns -1 if there was an error, 0 if non-blocking wasn't set, 1109 * 1 if it was. 1110 */ 1111 int 1112 reset_nonblock(int fd) 1113 { 1114 int flags; 1115 1116 if ((flags = fcntl(fd, F_GETFL)) < 0) 1117 return -1; 1118 if (!(flags & O_NONBLOCK)) 1119 return 0; 1120 flags &= ~O_NONBLOCK; 1121 if (fcntl(fd, F_SETFL, flags) < 0) 1122 return -1; 1123 return 1; 1124 } 1125 1126 1127 /* Like getcwd(), except bsize is ignored if buf is 0 (PATH_MAX is used) */ 1128 char * 1129 ksh_get_wd(char *buf, int bsize) 1130 { 1131 char *b; 1132 char *ret; 1133 1134 /* Note: we could just use plain getcwd(), but then we'd had to 1135 * inject possibly allocated space into the ATEMP area. */ 1136 /* Assume getcwd() available */ 1137 if (!buf) { 1138 bsize = PATH_MAX; 1139 b = alloc(PATH_MAX + 1, ATEMP); 1140 } else 1141 b = buf; 1142 1143 ret = getcwd(b, bsize); 1144 1145 if (!buf) { 1146 if (ret) 1147 ret = aresize(b, strlen(b) + 1, ATEMP); 1148 else 1149 afree(b, ATEMP); 1150 } 1151 1152 return ret; 1153 } 1154