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