fix english
[unix-history] / usr / src / bin / csh / glob.c
CommitLineData
b79f4fa9
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
094e80ed 3 * All rights reserved. The Berkeley Software License Agreement
b79f4fa9
DF
4 * specifies the terms and conditions for redistribution.
5 */
6
35371dec 7#ifndef lint
291a8333 8static char *sccsid = "@(#)glob.c 5.4 (Berkeley) %G%";
094e80ed 9#endif
9363f20d 10
b6e604fd 11#include "sh.h"
3ced312f 12#include <sys/dir.h>
b6e604fd
BJ
13
14/*
15 * C Shell
16 */
17
18int globcnt;
19
b6e604fd
BJ
20char *gpath, *gpathp, *lastgpathp;
21int globbed;
22bool noglob;
23bool nonomatch;
24char *entp;
25char **sortbas;
291a8333 26int sortscmp();
6a422336
JL
27
28#define sort() qsort((char *)sortbas, &gargv[gargc] - sortbas, \
291a8333 29 sizeof(*sortbas), sortscmp), sortbas = &gargv[gargc]
6a422336 30
b6e604fd
BJ
31
32char **
33glob(v)
34 register char **v;
35{
36 char agpath[BUFSIZ];
37 char *agargv[GAVSIZ];
38
39 gpath = agpath; gpathp = gpath; *gpathp = 0;
40 lastgpathp = &gpath[sizeof agpath - 2];
41 ginit(agargv); globcnt = 0;
42#ifdef GDEBUG
43 printf("glob entered: "); blkpr(v); printf("\n");
44#endif
45 noglob = adrof("noglob") != 0;
46 nonomatch = adrof("nonomatch") != 0;
47 globcnt = noglob | nonomatch;
48 while (*v)
49 collect(*v++);
50#ifdef GDEBUG
51 printf("glob done, globcnt=%d, gflag=%d: ", globcnt, gflag); blkpr(gargv); printf("\n");
52#endif
53 if (globcnt == 0 && (gflag&1)) {
54 blkfree(gargv), gargv = 0;
55 return (0);
56 } else
57 return (gargv = copyblk(gargv));
58}
59
60ginit(agargv)
61 char **agargv;
62{
63
64 agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
65 gnleft = NCARGS - 4;
66}
67
68collect(as)
69 register char *as;
70{
71 register int i;
72
73 if (any('`', as)) {
74#ifdef GDEBUG
75 printf("doing backp of %s\n", as);
76#endif
35371dec 77 (void) dobackp(as, 0);
b6e604fd
BJ
78#ifdef GDEBUG
79 printf("backp done, acollect'ing\n");
80#endif
81 for (i = 0; i < pargc; i++)
3ced312f 82 if (noglob) {
b6e604fd 83 Gcat(pargv[i], "");
3ced312f
SL
84 sortbas = &gargv[gargc];
85 } else
b6e604fd
BJ
86 acollect(pargv[i]);
87 if (pargv)
88 blkfree(pargv), pargv = 0;
89#ifdef GDEBUG
90 printf("acollect done\n");
91#endif
401149be 92 } else if (noglob || eq(as, "{") || eq(as, "{}")) {
b6e604fd 93 Gcat(as, "");
401149be
BJ
94 sort();
95 } else
b6e604fd
BJ
96 acollect(as);
97}
98
99acollect(as)
100 register char *as;
101{
102 register int ogargc = gargc;
103
104 gpathp = gpath; *gpathp = 0; globbed = 0;
105 expand(as);
106 if (gargc == ogargc) {
107 if (nonomatch) {
108 Gcat(as, "");
109 sort();
110 }
111 } else
112 sort();
113}
114
291a8333
JL
115/*
116 * String compare for qsort. Also used by filec code in sh.file.c.
117 */
118sortscmp(a1, a2)
6a422336 119 char **a1, **a2;
b6e604fd 120{
6a422336
JL
121
122 return (strcmp(*a1, *a2));
b6e604fd
BJ
123}
124
125expand(as)
126 char *as;
127{
128 register char *cs;
129 register char *sgpathp, *oldcs;
130 struct stat stb;
131
132 sgpathp = gpathp;
133 cs = as;
134 if (*cs == '~' && gpathp == gpath) {
135 addpath('~');
136 for (cs++; letter(*cs) || digit(*cs) || *cs == '-';)
137 addpath(*cs++);
138 if (!*cs || *cs == '/') {
139 if (gpathp != gpath + 1) {
140 *gpathp = 0;
141 if (gethdir(gpath + 1))
142 error("Unknown user: %s", gpath + 1);
35371dec 143 (void) strcpy(gpath, gpath + 1);
b6e604fd 144 } else
35371dec 145 (void) strcpy(gpath, value("home"));
b6e604fd
BJ
146 gpathp = strend(gpath);
147 }
148 }
6a422336 149 while (!isglob(*cs)) {
b6e604fd
BJ
150 if (*cs == 0) {
151 if (!globbed)
152 Gcat(gpath, "");
153 else if (stat(gpath, &stb) >= 0) {
154 Gcat(gpath, "");
155 globcnt++;
156 }
157 goto endit;
158 }
159 addpath(*cs++);
160 }
161 oldcs = cs;
162 while (cs > as && *cs != '/')
163 cs--, gpathp--;
164 if (*cs == '/')
165 cs++, gpathp++;
166 *gpathp = 0;
167 if (*oldcs == '{') {
35371dec 168 (void) execbrc(cs, NOSTR);
b6e604fd
BJ
169 return;
170 }
171 matchdir(cs);
172endit:
173 gpathp = sgpathp;
174 *gpathp = 0;
175}
176
177matchdir(pattern)
178 char *pattern;
179{
180 struct stat stb;
9363f20d 181 register struct direct *dp;
35371dec 182 register DIR *dirp;
b6e604fd 183
9363f20d
KM
184 dirp = opendir(gpath);
185 if (dirp == NULL) {
b6e604fd
BJ
186 if (globbed)
187 return;
9363f20d 188 goto patherr2;
b6e604fd 189 }
9363f20d
KM
190 if (fstat(dirp->dd_fd, &stb) < 0)
191 goto patherr1;
b6e604fd
BJ
192 if (!isdir(stb)) {
193 errno = ENOTDIR;
9363f20d 194 goto patherr1;
b6e604fd 195 }
9363f20d
KM
196 while ((dp = readdir(dirp)) != NULL) {
197 if (dp->d_ino == 0)
198 continue;
199 if (match(dp->d_name, pattern)) {
200 Gcat(gpath, dp->d_name);
201 globcnt++;
b6e604fd
BJ
202 }
203 }
9363f20d 204 closedir(dirp);
b6e604fd
BJ
205 return;
206
9363f20d
KM
207patherr1:
208 closedir(dirp);
209patherr2:
b6e604fd
BJ
210 Perror(gpath);
211}
212
b6e604fd
BJ
213execbrc(p, s)
214 char *p, *s;
215{
216 char restbuf[BUFSIZ + 2];
217 register char *pe, *pm, *pl;
218 int brclev = 0;
219 char *lm, savec, *sgpathp;
220
221 for (lm = restbuf; *p != '{'; *lm++ = *p++)
222 continue;
223 for (pe = ++p; *pe; pe++)
224 switch (*pe) {
225
226 case '{':
227 brclev++;
228 continue;
229
230 case '}':
231 if (brclev == 0)
232 goto pend;
233 brclev--;
234 continue;
235
236 case '[':
237 for (pe++; *pe && *pe != ']'; pe++)
238 continue;
239 if (!*pe)
240 error("Missing ]");
241 continue;
242 }
243pend:
244 if (brclev || !*pe)
245 error("Missing }");
246 for (pl = pm = p; pm <= pe; pm++)
247 switch (*pm & (QUOTE|TRIM)) {
248
249 case '{':
250 brclev++;
251 continue;
252
253 case '}':
254 if (brclev) {
255 brclev--;
256 continue;
257 }
258 goto doit;
259
260 case ','|QUOTE:
261 case ',':
262 if (brclev)
263 continue;
264doit:
265 savec = *pm;
266 *pm = 0;
35371dec
EW
267 (void) strcpy(lm, pl);
268 (void) strcat(restbuf, pe + 1);
b6e604fd
BJ
269 *pm = savec;
270 if (s == 0) {
271 sgpathp = gpathp;
272 expand(restbuf);
273 gpathp = sgpathp;
274 *gpathp = 0;
275 } else if (amatch(s, restbuf))
276 return (1);
277 sort();
278 pl = pm + 1;
279 continue;
280
281 case '[':
282 for (pm++; *pm && *pm != ']'; pm++)
283 continue;
284 if (!*pm)
285 error("Missing ]");
286 continue;
287 }
288 return (0);
289}
290
291match(s, p)
292 char *s, *p;
293{
294 register int c;
295 register char *sentp;
296 char sglobbed = globbed;
297
298 if (*s == '.' && *p != '.')
299 return (0);
300 sentp = entp;
301 entp = s;
302 c = amatch(s, p);
303 entp = sentp;
304 globbed = sglobbed;
305 return (c);
306}
307
308amatch(s, p)
309 register char *s, *p;
310{
311 register int scc;
312 int ok, lc;
313 char *sgpathp;
314 struct stat stb;
315 int c, cc;
316
317 globbed = 1;
318 for (;;) {
319 scc = *s++ & TRIM;
320 switch (c = *p++) {
321
322 case '{':
323 return (execbrc(p - 1, s - 1));
324
325 case '[':
326 ok = 0;
327 lc = 077777;
328 while (cc = *p++) {
329 if (cc == ']') {
330 if (ok)
331 break;
332 return (0);
333 }
334 if (cc == '-') {
335 if (lc <= scc && scc <= *p++)
336 ok++;
337 } else
338 if (scc == (lc = cc))
339 ok++;
340 }
341 if (cc == 0)
342 error("Missing ]");
343 continue;
344
345 case '*':
346 if (!*p)
347 return (1);
348 if (*p == '/') {
349 p++;
350 goto slash;
351 }
352 for (s--; *s; s++)
353 if (amatch(s, p))
354 return (1);
355 return (0);
356
357 case 0:
358 return (scc == 0);
359
360 default:
d33af40e 361 if ((c & TRIM) != scc)
b6e604fd
BJ
362 return (0);
363 continue;
364
365 case '?':
366 if (scc == 0)
367 return (0);
368 continue;
369
370 case '/':
371 if (scc)
372 return (0);
373slash:
374 s = entp;
375 sgpathp = gpathp;
376 while (*s)
377 addpath(*s++);
378 addpath('/');
379 if (stat(gpath, &stb) == 0 && isdir(stb))
380 if (*p == 0) {
381 Gcat(gpath, "");
382 globcnt++;
383 } else
384 expand(p);
385 gpathp = sgpathp;
386 *gpathp = 0;
387 return (0);
388 }
389 }
390}
391
392Gmatch(s, p)
393 register char *s, *p;
394{
395 register int scc;
396 int ok, lc;
397 int c, cc;
398
399 for (;;) {
400 scc = *s++ & TRIM;
401 switch (c = *p++) {
402
403 case '[':
404 ok = 0;
405 lc = 077777;
406 while (cc = *p++) {
407 if (cc == ']') {
408 if (ok)
409 break;
410 return (0);
411 }
412 if (cc == '-') {
413 if (lc <= scc && scc <= *p++)
414 ok++;
415 } else
416 if (scc == (lc = cc))
417 ok++;
418 }
419 if (cc == 0)
420 bferr("Missing ]");
421 continue;
422
423 case '*':
424 if (!*p)
425 return (1);
426 for (s--; *s; s++)
427 if (Gmatch(s, p))
428 return (1);
429 return (0);
430
431 case 0:
432 return (scc == 0);
433
434 default:
435 if ((c & TRIM) != scc)
436 return (0);
437 continue;
438
439 case '?':
440 if (scc == 0)
441 return (0);
442 continue;
443
444 }
445 }
446}
447
448Gcat(s1, s2)
35371dec 449 char *s1, *s2;
b6e604fd 450{
35371dec
EW
451 register char *p, *q;
452 int n;
453
454 for (p = s1; *p++;)
455 ;
456 for (q = s2; *q++;)
457 ;
458 gnleft -= (n = (p - s1) + (q - s2) - 1);
b6e604fd
BJ
459 if (gnleft <= 0 || ++gargc >= GAVSIZ)
460 error("Arguments too long");
461 gargv[gargc] = 0;
35371dec
EW
462 p = gargv[gargc - 1] = xalloc((unsigned)n);
463 for (q = s1; *p++ = *q++;)
464 ;
465 for (p--, q = s2; *p++ = *q++;)
466 ;
b6e604fd
BJ
467}
468
469addpath(c)
470 char c;
471{
472
473 if (gpathp >= lastgpathp)
474 error("Pathname too long");
6795aa44 475 *gpathp++ = c & TRIM;
b6e604fd
BJ
476 *gpathp = 0;
477}
478
479rscan(t, f)
480 register char **t;
481 int (*f)();
482{
35371dec 483 register char *p;
b6e604fd 484
35371dec
EW
485 while (p = *t++)
486 while (*p)
487 (*f)(*p++);
b6e604fd
BJ
488}
489
35371dec 490trim(t)
b6e604fd 491 register char **t;
b6e604fd 492{
35371dec 493 register char *p;
b6e604fd
BJ
494
495 while (p = *t++)
700d2436
JB
496 while (*p)
497 *p++ &= TRIM;
b6e604fd
BJ
498}
499
35371dec
EW
500tglob(t)
501 register char **t;
b6e604fd 502{
35371dec 503 register char *p, c;
b6e604fd 504
35371dec
EW
505 while (p = *t++) {
506 if (*p == '~')
507 gflag |= 2;
508 else if (*p == '{' && (p[1] == '\0' || p[1] == '}' && p[2] == '\0'))
509 continue;
510 while (c = *p++)
6a422336 511 if (isglob(c))
35371dec
EW
512 gflag |= c == '{' ? 2 : 1;
513 }
b6e604fd
BJ
514}
515
516char *
517globone(str)
518 register char *str;
519{
520 char *gv[2];
521 register char **gvp;
522 register char *cp;
523
524 gv[0] = str;
525 gv[1] = 0;
526 gflag = 0;
35371dec 527 tglob(gv);
b6e604fd
BJ
528 if (gflag) {
529 gvp = glob(gv);
530 if (gvp == 0) {
531 setname(str);
532 bferr("No match");
533 }
534 cp = *gvp++;
535 if (cp == 0)
536 cp = "";
537 else if (*gvp) {
538 setname(str);
539 bferr("Ambiguous");
540 } else
541 cp = strip(cp);
542/*
543 if (cp == 0 || *gvp) {
544 setname(str);
545 bferr(cp ? "Ambiguous" : "No output");
546 }
547*/
548 xfree((char *)gargv); gargv = 0;
549 } else {
35371dec 550 trim(gv);
b6e604fd
BJ
551 cp = savestr(gv[0]);
552 }
553 return (cp);
554}
555
556/*
557 * Command substitute cp. If literal, then this is
558 * a substitution from a << redirection, and so we should
559 * not crunch blanks and tabs, separating words only at newlines.
560 */
561char **
562dobackp(cp, literal)
563 char *cp;
564 bool literal;
565{
566 register char *lp, *rp;
567 char *ep;
568 char word[BUFSIZ];
569 char *apargv[GAVSIZ + 2];
570
571 if (pargv) {
572 abort();
573 blkfree(pargv);
574 }
575 pargv = apargv;
576 pargv[0] = NOSTR;
577 pargcp = pargs = word;
578 pargc = 0;
579 pnleft = BUFSIZ - 4;
580 for (;;) {
581 for (lp = cp; *lp != '`'; lp++) {
582 if (*lp == 0) {
583 if (pargcp != pargs)
584 pword();
585#ifdef GDEBUG
586 printf("leaving dobackp\n");
587#endif
588 return (pargv = copyblk(pargv));
589 }
590 psave(*lp);
591 }
592 lp++;
593 for (rp = lp; *rp && *rp != '`'; rp++)
594 if (*rp == '\\') {
595 rp++;
596 if (!*rp)
597 goto oops;
598 }
599 if (!*rp)
600oops:
601 error("Unmatched `");
602 ep = savestr(lp);
603 ep[rp - lp] = 0;
604 backeval(ep, literal);
605#ifdef GDEBUG
606 printf("back from backeval\n");
607#endif
608 cp = rp + 1;
609 }
610}
611
612backeval(cp, literal)
613 char *cp;
614 bool literal;
615{
616 int pvec[2];
617 int quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
618 char ibuf[BUFSIZ];
619 register int icnt = 0, c;
620 register char *ip;
621 bool hadnl = 0;
622 char *fakecom[2];
623 struct command faket;
624
625 faket.t_dtyp = TCOM;
626 faket.t_dflg = 0;
627 faket.t_dlef = 0;
628 faket.t_drit = 0;
629 faket.t_dspr = 0;
630 faket.t_dcom = fakecom;
631 fakecom[0] = "` ... `";
632 fakecom[1] = 0;
633 /*
634 * We do the psave job to temporarily change the current job
635 * so that the following fork is considered a separate job.
636 * This is so that when backquotes are used in a
637 * builtin function that calls glob the "current job" is not corrupted.
638 * We only need one level of pushed jobs as long as we are sure to
639 * fork here.
640 */
641 psavejob();
642 /*
643 * It would be nicer if we could integrate this redirection more
644 * with the routines in sh.sem.c by doing a fake execute on a builtin
645 * function that was piped out.
646 */
647 mypipe(pvec);
648 if (pfork(&faket, -1) == 0) {
649 struct wordent paraml;
650 struct command *t;
651
35371dec
EW
652 (void) close(pvec[0]);
653 (void) dmove(pvec[1], 1);
654 (void) dmove(SHDIAG, 2);
b6e604fd
BJ
655 initdesc();
656 arginp = cp;
657 while (*cp)
658 *cp++ &= TRIM;
35371dec 659 (void) lex(&paraml);
b6e604fd
BJ
660 if (err)
661 error(err);
662 alias(&paraml);
663 t = syntax(paraml.next, &paraml, 0);
664 if (err)
665 error(err);
666 if (t)
667 t->t_dflg |= FPAR;
35371dec
EW
668 (void) signal(SIGTSTP, SIG_IGN);
669 (void) signal(SIGTTIN, SIG_IGN);
670 (void) signal(SIGTTOU, SIG_IGN);
b6e604fd
BJ
671 execute(t, -1);
672 exitstat();
673 }
674 xfree(cp);
35371dec 675 (void) close(pvec[1]);
b6e604fd
BJ
676 do {
677 int cnt = 0;
678 for (;;) {
679 if (icnt == 0) {
680 ip = ibuf;
681 icnt = read(pvec[0], ip, BUFSIZ);
682 if (icnt <= 0) {
683 c = -1;
684 break;
685 }
686 }
687 if (hadnl)
688 break;
689 --icnt;
690 c = (*ip++ & TRIM);
691 if (c == 0)
692 break;
693 if (c == '\n') {
694 /*
695 * Continue around the loop one
696 * more time, so that we can eat
697 * the last newline without terminating
698 * this word.
699 */
700 hadnl = 1;
701 continue;
702 }
703 if (!quoted && (c == ' ' || c == '\t'))
704 break;
705 cnt++;
706 psave(c | quoted);
707 }
708 /*
709 * Unless at end-of-file, we will form a new word
710 * here if there were characters in the word, or in
711 * any case when we take text literally. If
712 * we didn't make empty words here when literal was
713 * set then we would lose blank lines.
714 */
715 if (c != -1 && (cnt || literal))
716 pword();
717 hadnl = 0;
718 } while (c >= 0);
719#ifdef GDEBUG
720 printf("done in backeval, pvec: %d %d\n", pvec[0], pvec[1]);
721 printf("also c = %c <%o>\n", c, c);
722#endif
35371dec 723 (void) close(pvec[0]);
b6e604fd
BJ
724 pwait();
725 prestjob();
726}
727
728psave(c)
729 char c;
730{
731
732 if (--pnleft <= 0)
733 error("Word too long");
734 *pargcp++ = c;
735}
736
737pword()
738{
739
740 psave(0);
741 if (pargc == GAVSIZ)
742 error("Too many words from ``");
743 pargv[pargc++] = savestr(pargs);
744 pargv[pargc] = NOSTR;
745#ifdef GDEBUG
746 printf("got word %s\n", pargv[pargc-1]);
747#endif
748 pargcp = pargs;
749 pnleft = BUFSIZ - 4;
750}