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