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