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