This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / bin / csh / glob.c
CommitLineData
15637ed4
RG
1/*-
2 * Copyright (c) 1980, 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static char sccsid[] = "@(#)glob.c 5.21 (Berkeley) 6/25/91";
36#endif /* not lint */
37
38#include <sys/param.h>
39#include <glob.h>
40#include <errno.h>
41#include <stdlib.h>
42#include <string.h>
43#include <unistd.h>
44#if __STDC__
45# include <stdarg.h>
46#else
47# include <varargs.h>
48#endif
49
50#include "csh.h"
51#include "extern.h"
52
53static int noglob, nonomatch;
54static int pargsiz, gargsiz;
55
56/*
57 * Values for gflag
58 */
59#define G_NONE 0 /* No globbing needed */
60#define G_GLOB 1 /* string contains *?[] characters */
61#define G_CSH 2 /* string contains ~`{ characters */
62
63#define GLOBSPACE 100 /* Alloc increment */
64
65#define LBRC '{'
66#define RBRC '}'
67#define LBRK '['
68#define RBRK ']'
69#define EOS '\0'
70
71Char **gargv = NULL;
72long gargc = 0;
73Char **pargv = NULL;
74long pargc = 0;
75
76/*
77 * globbing is now done in two stages. In the first pass we expand
78 * csh globbing idioms ~`{ and then we proceed doing the normal
79 * globbing if needed ?*[
80 *
81 * Csh type globbing is handled in globexpand() and the rest is
82 * handled in glob() which is part of the 4.4BSD libc.
83 *
84 */
85static Char *globtilde __P((Char **, Char *));
86static Char **libglob __P((Char **));
87static Char **globexpand __P((Char **));
88static int globbrace __P((Char *, Char *, Char ***));
89static void pword __P((void));
90static void psave __P((int));
91static void backeval __P((Char *, bool));
92
93
94static Char *
95globtilde(nv, s)
96 Char **nv, *s;
97{
98 Char gbuf[MAXPATHLEN], *gstart, *b, *u, *e;
99
100 gstart = gbuf;
101 *gstart++ = *s++;
102 u = s;
103 for (b = gstart, e = &gbuf[MAXPATHLEN - 1]; *s && *s != '/' && b < e;
104 *b++ = *s++);
105 *b = EOS;
106 if (gethdir(gstart)) {
107 blkfree(nv);
108 if (*gstart)
109 stderror(ERR_UNKUSER, short2str(gstart));
110 else
111 stderror(ERR_NOHOME);
112 }
113 b = &gstart[Strlen(gstart)];
114 while (*s)
115 *b++ = *s++;
116 *b = EOS;
117 --u;
118 xfree((ptr_t) u);
119 return (Strsave(gstart));
120}
121
122static int
123globbrace(s, p, bl)
124 Char *s, *p, ***bl;
125{
126 int i, len;
127 Char *pm, *pe, *lm, *pl;
128 Char **nv, **vl;
129 Char gbuf[MAXPATHLEN];
130 int size = GLOBSPACE;
131
132 nv = vl = (Char **) xmalloc((size_t) sizeof(Char *) * size);
133 *vl = NULL;
134
135 len = 0;
136 /* copy part up to the brace */
137 for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++)
138 continue;
139
140 /* check for balanced braces */
141 for (i = 0, pe = ++p; *pe; pe++)
142 if (*pe == LBRK) {
143 /* Ignore everything between [] */
144 for (++pe; *pe != RBRK && *pe != EOS; pe++)
145 continue;
146 if (*pe == EOS) {
147 blkfree(nv);
148 return (-LBRK);
149 }
150 }
151 else if (*pe == LBRC)
152 i++;
153 else if (*pe == RBRC) {
154 if (i == 0)
155 break;
156 i--;
157 }
158
159 if (i != 0) {
160 blkfree(nv);
161 return (-LBRC);
162 }
163
164 for (i = 0, pl = pm = p; pm <= pe; pm++)
165 switch (*pm) {
166 case LBRK:
167 for (++pm; *pm != RBRK && *pm != EOS; pm++)
168 continue;
169 if (*pm == EOS) {
170 *vl = NULL;
171 blkfree(nv);
172 return (-RBRK);
173 }
174 break;
175 case LBRC:
176 i++;
177 break;
178 case RBRC:
179 if (i) {
180 i--;
181 break;
182 }
183 /* FALLTHROUGH */
184 case ',':
185 if (i && *pm == ',')
186 break;
187 else {
188 Char savec = *pm;
189
190 *pm = EOS;
191 (void) Strcpy(lm, pl);
192 (void) Strcat(gbuf, pe + 1);
193 *pm = savec;
194 *vl++ = Strsave(gbuf);
195 len++;
196 pl = pm + 1;
197 if (vl == &nv[size]) {
198 size += GLOBSPACE;
199 nv = (Char **) xrealloc((ptr_t) nv, (size_t)
200 size * sizeof(Char *));
201 vl = &nv[size - GLOBSPACE];
202 }
203 }
204 break;
205 }
206 *vl = NULL;
207 *bl = nv;
208 return (len);
209}
210
211static Char **
212globexpand(v)
213 Char **v;
214{
215 Char *s;
216 Char **nv, **vl, **el;
217 int size = GLOBSPACE;
218
219
220 nv = vl = (Char **) xmalloc((size_t) sizeof(Char *) * size);
221 *vl = NULL;
222
223 /*
224 * Step 1: expand backquotes.
225 */
226 while (s = *v++) {
227 if (Strchr(s, '`')) {
228 int i;
229
230 (void) dobackp(s, 0);
231 for (i = 0; i < pargc; i++) {
232 *vl++ = pargv[i];
233 if (vl == &nv[size]) {
234 size += GLOBSPACE;
235 nv = (Char **) xrealloc((ptr_t) nv,
236 (size_t) size * sizeof(Char *));
237 vl = &nv[size - GLOBSPACE];
238 }
239 }
240 xfree((ptr_t) pargv);
241 pargv = NULL;
242 }
243 else {
244 *vl++ = Strsave(s);
245 if (vl == &nv[size]) {
246 size += GLOBSPACE;
247 nv = (Char **) xrealloc((ptr_t) nv, (size_t)
248 size * sizeof(Char *));
249 vl = &nv[size - GLOBSPACE];
250 }
251 }
252 }
253 *vl = NULL;
254
255 if (noglob)
256 return (nv);
257
258 /*
259 * Step 2: expand braces
260 */
261 el = vl;
262 vl = nv;
263 for (s = *vl; s; s = *++vl) {
264 Char *b;
265 Char **vp, **bp;
266
267 if (b = Strchr(s, LBRC)) {
268 Char **bl;
269 int len;
270
271 if ((len = globbrace(s, b, &bl)) < 0) {
272 blkfree(nv);
273 stderror(ERR_MISSING, -len);
274 }
275 xfree((ptr_t) s);
276 if (len == 1) {
277 *vl-- = *bl;
278 xfree((ptr_t) bl);
279 continue;
280 }
281 len = blklen(bl);
282 if (&el[len] >= &nv[size]) {
283 int l, e;
284
285 l = &el[len] - &nv[size];
286 size += GLOBSPACE > l ? GLOBSPACE : l;
287 l = vl - nv;
288 e = el - nv;
289 nv = (Char **) xrealloc((ptr_t) nv, (size_t)
290 size * sizeof(Char *));
291 vl = nv + l;
292 el = nv + e;
293 }
294 vp = vl--;
295 *vp = *bl;
296 len--;
297 for (bp = el; bp != vp; bp--)
298 bp[len] = *bp;
299 el += len;
300 vp++;
301 for (bp = bl + 1; *bp; *vp++ = *bp++)
302 continue;
303 xfree((ptr_t) bl);
304 }
305
306 }
307
308 /*
309 * Step 3: expand ~
310 */
311 vl = nv;
312 for (s = *vl; s; s = *++vl)
313 if (*s == '~')
314 *vl = globtilde(nv, s);
315 vl = nv;
316 return (vl);
317}
318
319static Char *
320handleone(str, vl, action)
321 Char *str, **vl;
322 int action;
323{
324
325 Char *cp, **vlp = vl;
326
327 switch (action) {
328 case G_ERROR:
329 setname(short2str(str));
330 blkfree(vl);
331 stderror(ERR_NAME | ERR_AMBIG);
332 break;
333 case G_APPEND:
334 trim(vlp);
335 str = Strsave(*vlp++);
336 do {
337 cp = Strspl(str, STRspace);
338 xfree((ptr_t) str);
339 str = Strspl(cp, *vlp);
340 xfree((ptr_t) cp);
341 }
342 while (*++vlp);
343 blkfree(vl);
344 break;
345 case G_IGNORE:
346 str = Strsave(strip(*vlp));
347 blkfree(vl);
348 break;
349 }
350 return (str);
351}
352
353static Char **
354libglob(vl)
355 Char **vl;
356{
ce0ab80e 357 int gflgs = GLOB_QUOTE | GLOB_NOCHECK, badmagic = 0, goodmagic = 0;
15637ed4
RG
358 glob_t globv;
359 char *ptr;
360
361 globv.gl_offs = 0;
362 globv.gl_pathv = 0;
363 globv.gl_pathc = 0;
364 nonomatch = adrof(STRnonomatch) != 0;
365 do {
366 ptr = short2qstr(*vl);
367 switch (glob(ptr, gflgs, 0, &globv)) {
368 case GLOB_ABEND:
369 setname(ptr);
370 stderror(ERR_NAME | ERR_GLOB);
371 /* NOTREACHED */
372 case GLOB_NOSPACE:
373 stderror(ERR_NOMEM);
374 /* NOTREACHED */
375 default:
376 break;
377 }
378 if (!nonomatch && (globv.gl_matchc == 0) &&
379 (globv.gl_flags & GLOB_MAGCHAR)) {
ce0ab80e
AS
380 badmagic = 1;
381 globv.gl_pathc--;
382 free(globv.gl_pathv[globv.gl_pathc]);
383 globv.gl_pathv[globv.gl_pathc] = (char *)0;
384 } else
385 if (!nonomatch && (globv.gl_matchc > 0) &&
386 (globv.gl_flags & GLOB_MAGCHAR))
387 goodmagic = 1;
15637ed4
RG
388 gflgs |= GLOB_APPEND;
389 }
390 while (*++vl);
ce0ab80e
AS
391 if (badmagic && !goodmagic) {
392 globfree(&globv);
393 return (NULL);
394 }
15637ed4
RG
395 vl = blk2short(globv.gl_pathv);
396 globfree(&globv);
397 return (vl);
398}
399
400Char *
401globone(str, action)
402 Char *str;
403 int action;
404{
405
406 Char *v[2], **vl, **vo;
407
408 noglob = adrof(STRnoglob) != 0;
409 gflag = 0;
410 v[0] = str;
411 v[1] = 0;
412 tglob(v);
413 if (gflag == G_NONE)
414 return (strip(Strsave(str)));
415
416 if (gflag & G_CSH) {
417 /*
418 * Expand back-quote, tilde and brace
419 */
420 vo = globexpand(v);
421 if (noglob || (gflag & G_GLOB) == 0) {
422 if (vo[0] == NULL) {
423 xfree((ptr_t) vo);
424 return (Strsave(STRNULL));
425 }
426 if (vo[1] != NULL)
427 return (handleone(str, vo, action));
428 else {
429 str = strip(vo[0]);
430 xfree((ptr_t) vo);
431 return (str);
432 }
433 }
434 }
435 else if (noglob || (gflag & G_GLOB) == 0)
436 return (strip(Strsave(str)));
437 else
438 vo = v;
439
440 vl = libglob(vo);
441 if (gflag & G_CSH)
442 blkfree(vo);
443 if (vl == NULL) {
444 setname(short2str(str));
445 stderror(ERR_NAME | ERR_NOMATCH);
446 }
447 if (vl[0] == NULL) {
448 xfree((ptr_t) vl);
449 return (Strsave(STRNULL));
450 }
451 if (vl[1] != NULL)
452 return (handleone(str, vl, action));
453 else {
454 str = strip(*vl);
455 xfree((ptr_t) vl);
456 return (str);
457 }
458}
459
460Char **
461globall(v)
462 Char **v;
463{
464 Char **vl, **vo;
465
466 if (!v || !v[0]) {
467 gargv = saveblk(v);
468 gargc = blklen(gargv);
469 return (gargv);
470 }
471
472 noglob = adrof(STRnoglob) != 0;
473
474 if (gflag & G_CSH)
475 /*
476 * Expand back-quote, tilde and brace
477 */
478 vl = vo = globexpand(v);
479 else
480 vl = vo = saveblk(v);
481
482 if (!noglob && (gflag & G_GLOB)) {
483 vl = libglob(vo);
484 if (gflag & G_CSH)
485 blkfree(vo);
486 }
487
488 gargc = vl ? blklen(vl) : 0;
489 return (gargv = vl);
490}
491
492void
493ginit()
494{
495 gargsiz = GLOBSPACE;
496 gargv = (Char **) xmalloc((size_t) sizeof(Char *) * gargsiz);
497 gargv[0] = 0;
498 gargc = 0;
499}
500
501void
502rscan(t, f)
503 register Char **t;
504 void (*f) ();
505{
506 register Char *p;
507
508 while (p = *t++)
509 while (*p)
510 (*f) (*p++);
511}
512
513void
514trim(t)
515 register Char **t;
516{
517 register Char *p;
518
519 while (p = *t++)
520 while (*p)
521 *p++ &= TRIM;
522}
523
524void
525tglob(t)
526 register Char **t;
527{
528 register Char *p, c;
529
530 while (p = *t++) {
531 if (*p == '~' || *p == '=')
532 gflag |= G_CSH;
533 else if (*p == '{' &&
534 (p[1] == '\0' || p[1] == '}' && p[2] == '\0'))
535 continue;
536 while (c = *p++)
537 if (isglob(c))
538 gflag |= (c == '{' || c == '`') ? G_CSH : G_GLOB;
539 }
540}
541
542/*
543 * Command substitute cp. If literal, then this is a substitution from a
544 * << redirection, and so we should not crunch blanks and tabs, separating
545 * words only at newlines.
546 */
547Char **
548dobackp(cp, literal)
549 Char *cp;
550 bool literal;
551{
552 register Char *lp, *rp;
553 Char *ep, word[MAXPATHLEN];
554
555 if (pargv) {
556 abort();
557 blkfree(pargv);
558 }
559 pargsiz = GLOBSPACE;
560 pargv = (Char **) xmalloc((size_t) sizeof(Char *) * pargsiz);
561 pargv[0] = NULL;
562 pargcp = pargs = word;
563 pargc = 0;
564 pnleft = MAXPATHLEN - 4;
565 for (;;) {
566 for (lp = cp; *lp != '`'; lp++) {
567 if (*lp == 0) {
568 if (pargcp != pargs)
569 pword();
570 return (pargv);
571 }
572 psave(*lp);
573 }
574 lp++;
575 for (rp = lp; *rp && *rp != '`'; rp++)
576 if (*rp == '\\') {
577 rp++;
578 if (!*rp)
579 goto oops;
580 }
581 if (!*rp)
582 oops: stderror(ERR_UNMATCHED, '`');
583 ep = Strsave(lp);
584 ep[rp - lp] = 0;
585 backeval(ep, literal);
586 cp = rp + 1;
587 }
588}
589
590static void
591backeval(cp, literal)
592 Char *cp;
593 bool literal;
594{
595 register int icnt, c;
596 register Char *ip;
597 struct command faket;
598 bool hadnl;
599 int pvec[2], quoted;
600 Char *fakecom[2], ibuf[BUFSIZ];
601 char tibuf[BUFSIZ];
602
603 hadnl = 0;
604 icnt = 0;
605 quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
606 faket.t_dtyp = NODE_COMMAND;
607 faket.t_dflg = 0;
608 faket.t_dlef = 0;
609 faket.t_drit = 0;
610 faket.t_dspr = 0;
611 faket.t_dcom = fakecom;
612 fakecom[0] = STRfakecom1;
613 fakecom[1] = 0;
614
615 /*
616 * We do the psave job to temporarily change the current job so that the
617 * following fork is considered a separate job. This is so that when
618 * backquotes are used in a builtin function that calls glob the "current
619 * job" is not corrupted. We only need one level of pushed jobs as long as
620 * we are sure to fork here.
621 */
622 psavejob();
623
624 /*
625 * It would be nicer if we could integrate this redirection more with the
626 * routines in sh.sem.c by doing a fake execute on a builtin function that
627 * was piped out.
628 */
629 mypipe(pvec);
630 if (pfork(&faket, -1) == 0) {
631 struct wordent paraml;
632 struct command *t;
633
634 (void) close(pvec[0]);
635 (void) dmove(pvec[1], 1);
636 (void) dmove(SHDIAG, 2);
637 initdesc();
638 /*
639 * Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>,
640 * posted to comp.bugs.4bsd 12 Sep. 1989.
641 */
642 if (pargv) /* mg, 21.dec.88 */
643 blkfree(pargv), pargv = 0, pargsiz = 0;
644 /* mg, 21.dec.88 */
645 arginp = cp;
646 while (*cp)
647 *cp++ &= TRIM;
648 (void) lex(&paraml);
649 if (seterr)
650 stderror(ERR_OLD);
651 alias(&paraml);
652 t = syntax(paraml.next, &paraml, 0);
653 if (seterr)
654 stderror(ERR_OLD);
655 if (t)
656 t->t_dflg |= F_NOFORK;
657 (void) signal(SIGTSTP, SIG_IGN);
658 (void) signal(SIGTTIN, SIG_IGN);
659 (void) signal(SIGTTOU, SIG_IGN);
660 execute(t, -1, NULL, NULL);
661 exitstat();
662 }
663 xfree((ptr_t) cp);
664 (void) close(pvec[1]);
665 c = 0;
666 ip = NULL;
667 do {
668 int cnt = 0;
669
670 for (;;) {
671 if (icnt == 0) {
672 int i;
673
674 ip = ibuf;
675 do
676 icnt = read(pvec[0], tibuf, BUFSIZ);
677 while (icnt == -1 && errno == EINTR);
678 if (icnt <= 0) {
679 c = -1;
680 break;
681 }
682 for (i = 0; i < icnt; i++)
683 ip[i] = (unsigned char) tibuf[i];
684 }
685 if (hadnl)
686 break;
687 --icnt;
688 c = (*ip++ & TRIM);
689 if (c == 0)
690 break;
691 if (c == '\n') {
692 /*
693 * Continue around the loop one more time, so that we can eat
694 * the last newline without terminating this word.
695 */
696 hadnl = 1;
697 continue;
698 }
699 if (!quoted && (c == ' ' || c == '\t'))
700 break;
701 cnt++;
702 psave(c | quoted);
703 }
704 /*
705 * Unless at end-of-file, we will form a new word here if there were
706 * characters in the word, or in any case when we take text literally.
707 * If we didn't make empty words here when literal was set then we
708 * would lose blank lines.
709 */
710 if (c != -1 && (cnt || literal))
711 pword();
712 hadnl = 0;
713 } while (c >= 0);
714 (void) close(pvec[0]);
715 pwait();
716 prestjob();
717}
718
719static void
720psave(c)
721 int c;
722{
723 if (--pnleft <= 0)
724 stderror(ERR_WTOOLONG);
725 *pargcp++ = c;
726}
727
728static void
729pword()
730{
731 psave(0);
732 if (pargc == pargsiz - 1) {
733 pargsiz += GLOBSPACE;
734 pargv = (Char **) xrealloc((ptr_t) pargv,
735 (size_t) pargsiz * sizeof(Char *));
736 }
737 pargv[pargc++] = Strsave(pargs);
738 pargv[pargc] = NULL;
739 pargcp = pargs;
740 pnleft = MAXPATHLEN - 4;
741}
742
743int
744Gmatch(string, pattern)
745 register Char *string, *pattern;
746{
747 register Char stringc, patternc;
748 int match;
749 Char rangec;
750
751 for (;; ++string) {
752 stringc = *string & TRIM;
753 patternc = *pattern++;
754 switch (patternc) {
755 case 0:
756 return (stringc == 0);
757 case '?':
758 if (stringc == 0)
759 return (0);
760 break;
761 case '*':
762 if (!*pattern)
763 return (1);
764 while (*string)
765 if (Gmatch(string++, pattern))
766 return (1);
767 return (0);
768 case '[':
769 match = 0;
770 while (rangec = *pattern++) {
771 if (rangec == ']')
772 if (match)
773 break;
774 else
775 return (0);
776 if (match)
777 continue;
778 if (rangec == '-' && *(pattern - 2) != '[' && *pattern != ']') {
779 match = (stringc <= (*pattern & TRIM) &&
780 (*(pattern - 2) & TRIM) <= stringc);
781 pattern++;
782 }
783 else
784 match = (stringc == rangec);
785 }
786 if (rangec == 0)
787 stderror(ERR_NAME | ERR_MISSING, ']');
788 break;
789 default:
790 if ((patternc & TRIM) != stringc)
791 return (0);
792 break;
793
794 }
795 }
796}
797
798void
799Gcat(s1, s2)
800 Char *s1, *s2;
801{
802 register Char *p, *q;
803 int n;
804
805 for (p = s1; *p++;);
806 for (q = s2; *q++;);
807 n = (p - s1) + (q - s2) - 1;
808 if (++gargc >= gargsiz) {
809 gargsiz += GLOBSPACE;
810 gargv = (Char **) xrealloc((ptr_t) gargv,
811 (size_t) gargsiz * sizeof(Char *));
812 }
813 gargv[gargc] = 0;
814 p = gargv[gargc - 1] = (Char *) xmalloc((size_t) n * sizeof(Char));
815 for (q = s1; *p++ = *q++;);
816 for (p--, q = s2; *p++ = *q++;);
817}
818
819#ifdef FILEC
820int
821sortscmp(a, b)
822 register Char **a, **b;
823{
824#if defined(NLS) && !defined(NOSTRCOLL)
825 char buf[2048];
826
827#endif
828
829 if (!a) /* check for NULL */
830 return (b ? 1 : 0);
831 if (!b)
832 return (-1);
833
834 if (!*a) /* check for NULL */
835 return (*b ? 1 : 0);
836 if (!*b)
837 return (-1);
838
839#if defined(NLS) && !defined(NOSTRCOLL)
840 (void) strcpy(buf, short2str(*a));
841 return ((int) strcoll(buf, short2str(*b)));
842#else
843 return ((int) Strcmp(*a, *b));
844#endif
845}
846#endif /* FILEC */