source: trunk/athena/etc/ftpd/glob.c @ 7261

Revision 7261, 10.1 KB checked in by root, 31 years ago (diff)
use dir structure differently for SYSV
Line 
1/*
2 * Copyright (c) 1980 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley.  The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 */
17
18#ifndef lint
19static char sccsid[] = "@(#)glob.c      5.6 (Berkeley) 11/30/88";
20#endif /* not lint */
21
22/*
23 * C-shell glob for random programs.
24 */
25
26#include <sys/param.h>
27#include <sys/stat.h>
28#ifdef SYSV
29#include <dirent.h>
30#else
31#include <sys/dir.h>
32#endif
33
34#include <stdio.h>
35#include <errno.h>
36#include <pwd.h>
37
38#define QUOTE 0200
39#define TRIM 0177
40#define eq(a,b)         (strcmp(a, b)==0)
41#define GAVSIZ          (NCARGS/6)
42#define isdir(d)        ((d.st_mode & S_IFMT) == S_IFDIR)
43
44static  char **gargv;           /* Pointer to the (stack) arglist */
45static  int gargc;              /* Number args in gargv */
46static  int gnleft;
47static  short gflag;
48static  int tglob();
49char    **glob();
50char    *globerr;
51char    *home;
52struct  passwd *getpwnam();
53extern  int errno;
54static  char *strspl(), *strend();
55char    *malloc(), *strcpy(), *strcat();
56char    **copyblk();
57
58static  int globcnt;
59
60char    *globchars = "`{[*?";
61
62static  char *gpath, *gpathp, *lastgpathp;
63static  int globbed;
64static  char *entp;
65static  char **sortbas;
66
67char **
68glob(v)
69        register char *v;
70{
71        char agpath[BUFSIZ];
72        char *agargv[GAVSIZ];
73        char *vv[2];
74        vv[0] = v;
75        vv[1] = 0;
76        gflag = 0;
77        rscan(vv, tglob);
78        if (gflag == 0)
79                return (copyblk(vv));
80
81        globerr = 0;
82        gpath = agpath; gpathp = gpath; *gpathp = 0;
83        lastgpathp = &gpath[sizeof agpath - 2];
84        ginit(agargv); globcnt = 0;
85        collect(v);
86        if (globcnt == 0 && (gflag&1)) {
87                blkfree(gargv), gargv = 0;
88                return (0);
89        } else
90                return (gargv = copyblk(gargv));
91}
92
93static
94ginit(agargv)
95        char **agargv;
96{
97
98        agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
99        gnleft = NCARGS - 4;
100}
101
102static
103collect(as)
104        register char *as;
105{
106        if (eq(as, "{") || eq(as, "{}")) {
107                Gcat(as, "");
108                sort();
109        } else
110                acollect(as);
111}
112
113static
114acollect(as)
115        register char *as;
116{
117        register int ogargc = gargc;
118
119        gpathp = gpath; *gpathp = 0; globbed = 0;
120        expand(as);
121        if (gargc != ogargc)
122                sort();
123}
124
125static
126sort()
127{
128        register char **p1, **p2, *c;
129        char **Gvp = &gargv[gargc];
130
131        p1 = sortbas;
132        while (p1 < Gvp-1) {
133                p2 = p1;
134                while (++p2 < Gvp)
135                        if (strcmp(*p1, *p2) > 0)
136                                c = *p1, *p1 = *p2, *p2 = c;
137                p1++;
138        }
139        sortbas = Gvp;
140}
141
142static
143expand(as)
144        char *as;
145{
146        register char *cs;
147        register char *sgpathp, *oldcs;
148        struct stat stb;
149
150        sgpathp = gpathp;
151        cs = as;
152        if (*cs == '~' && gpathp == gpath) {
153                addpath('~');
154                for (cs++; letter(*cs) || digit(*cs) || *cs == '-';)
155                        addpath(*cs++);
156                if (!*cs || *cs == '/') {
157                        if (gpathp != gpath + 1) {
158                                *gpathp = 0;
159                                if (gethdir(gpath + 1))
160                                        globerr = "Unknown user name after ~";
161                                (void) strcpy(gpath, gpath + 1);
162                        } else
163                                (void) strcpy(gpath, home);
164                        gpathp = strend(gpath);
165                }
166        }
167        while (!any(*cs, globchars)) {
168                if (*cs == 0) {
169                        if (!globbed)
170                                Gcat(gpath, "");
171                        else if (stat(gpath, &stb) >= 0) {
172                                Gcat(gpath, "");
173                                globcnt++;
174                        }
175                        goto endit;
176                }
177                addpath(*cs++);
178        }
179        oldcs = cs;
180        while (cs > as && *cs != '/')
181                cs--, gpathp--;
182        if (*cs == '/')
183                cs++, gpathp++;
184        *gpathp = 0;
185        if (*oldcs == '{') {
186                (void) execbrc(cs, ((char *)0));
187                return;
188        }
189        matchdir(cs);
190endit:
191        gpathp = sgpathp;
192        *gpathp = 0;
193}
194
195static
196matchdir(pattern)
197        char *pattern;
198{
199        struct stat stb;
200#ifdef SYSV
201        register struct dirent *dp;
202#else
203        register struct direct *dp;
204#endif
205        DIR *dirp;
206
207        dirp = opendir(gpath);
208        if (dirp == NULL) {
209                if (globbed)
210                        return;
211                goto patherr2;
212        }
213        if (fstat(dirp->dd_fd, &stb) < 0)
214                goto patherr1;
215        if (!isdir(stb)) {
216                errno = ENOTDIR;
217                goto patherr1;
218        }
219        while ((dp = readdir(dirp)) != NULL) {
220                if (dp->d_ino == 0)
221                        continue;
222                if (match(dp->d_name, pattern)) {
223                        Gcat(gpath, dp->d_name);
224                        globcnt++;
225                }
226        }
227        closedir(dirp);
228        return;
229
230patherr1:
231        closedir(dirp);
232patherr2:
233        globerr = "Bad directory components";
234}
235
236static
237execbrc(p, s)
238        char *p, *s;
239{
240        char restbuf[BUFSIZ + 2];
241        register char *pe, *pm, *pl;
242        int brclev = 0;
243        char *lm, savec, *sgpathp;
244
245        for (lm = restbuf; *p != '{'; *lm++ = *p++)
246                continue;
247        for (pe = ++p; *pe; pe++)
248        switch (*pe) {
249
250        case '{':
251                brclev++;
252                continue;
253
254        case '}':
255                if (brclev == 0)
256                        goto pend;
257                brclev--;
258                continue;
259
260        case '[':
261                for (pe++; *pe && *pe != ']'; pe++)
262                        continue;
263                continue;
264        }
265pend:
266        brclev = 0;
267        for (pl = pm = p; pm <= pe; pm++)
268        switch (*pm & (QUOTE|TRIM)) {
269
270        case '{':
271                brclev++;
272                continue;
273
274        case '}':
275                if (brclev) {
276                        brclev--;
277                        continue;
278                }
279                goto doit;
280
281        case ','|QUOTE:
282        case ',':
283                if (brclev)
284                        continue;
285doit:
286                savec = *pm;
287                *pm = 0;
288                (void) strcpy(lm, pl);
289                (void) strcat(restbuf, pe + 1);
290                *pm = savec;
291                if (s == 0) {
292                        sgpathp = gpathp;
293                        expand(restbuf);
294                        gpathp = sgpathp;
295                        *gpathp = 0;
296                } else if (amatch(s, restbuf))
297                        return (1);
298                sort();
299                pl = pm + 1;
300                if (brclev)
301                        return (0);
302                continue;
303
304        case '[':
305                for (pm++; *pm && *pm != ']'; pm++)
306                        continue;
307                if (!*pm)
308                        pm--;
309                continue;
310        }
311        if (brclev)
312                goto doit;
313        return (0);
314}
315
316static
317match(s, p)
318        char *s, *p;
319{
320        register int c;
321        register char *sentp;
322        char sglobbed = globbed;
323
324        if (*s == '.' && *p != '.')
325                return (0);
326        sentp = entp;
327        entp = s;
328        c = amatch(s, p);
329        entp = sentp;
330        globbed = sglobbed;
331        return (c);
332}
333
334static
335amatch(s, p)
336        register char *s, *p;
337{
338        register int scc;
339        int ok, lc;
340        char *sgpathp;
341        struct stat stb;
342        int c, cc;
343
344        globbed = 1;
345        for (;;) {
346                scc = *s++ & TRIM;
347                switch (c = *p++) {
348
349                case '{':
350                        return (execbrc(p - 1, s - 1));
351
352                case '[':
353                        ok = 0;
354                        lc = 077777;
355                        while (cc = *p++) {
356                                if (cc == ']') {
357                                        if (ok)
358                                                break;
359                                        return (0);
360                                }
361                                if (cc == '-') {
362                                        if (lc <= scc && scc <= *p++)
363                                                ok++;
364                                } else
365                                        if (scc == (lc = cc))
366                                                ok++;
367                        }
368                        if (cc == 0)
369                                if (ok)
370                                        p--;
371                                else
372                                        return 0;
373                        continue;
374
375                case '*':
376                        if (!*p)
377                                return (1);
378                        if (*p == '/') {
379                                p++;
380                                goto slash;
381                        }
382                        s--;
383                        do {
384                                if (amatch(s, p))
385                                        return (1);
386                        } while (*s++);
387                        return (0);
388
389                case 0:
390                        return (scc == 0);
391
392                default:
393                        if (c != scc)
394                                return (0);
395                        continue;
396
397                case '?':
398                        if (scc == 0)
399                                return (0);
400                        continue;
401
402                case '/':
403                        if (scc)
404                                return (0);
405slash:
406                        s = entp;
407                        sgpathp = gpathp;
408                        while (*s)
409                                addpath(*s++);
410                        addpath('/');
411                        if (stat(gpath, &stb) == 0 && isdir(stb))
412                                if (*p == 0) {
413                                        Gcat(gpath, "");
414                                        globcnt++;
415                                } else
416                                        expand(p);
417                        gpathp = sgpathp;
418                        *gpathp = 0;
419                        return (0);
420                }
421        }
422}
423
424static
425Gmatch(s, p)
426        register char *s, *p;
427{
428        register int scc;
429        int ok, lc;
430        int c, cc;
431
432        for (;;) {
433                scc = *s++ & TRIM;
434                switch (c = *p++) {
435
436                case '[':
437                        ok = 0;
438                        lc = 077777;
439                        while (cc = *p++) {
440                                if (cc == ']') {
441                                        if (ok)
442                                                break;
443                                        return (0);
444                                }
445                                if (cc == '-') {
446                                        if (lc <= scc && scc <= *p++)
447                                                ok++;
448                                } else
449                                        if (scc == (lc = cc))
450                                                ok++;
451                        }
452                        if (cc == 0)
453                                if (ok)
454                                        p--;
455                                else
456                                        return 0;
457                        continue;
458
459                case '*':
460                        if (!*p)
461                                return (1);
462                        for (s--; *s; s++)
463                                if (Gmatch(s, p))
464                                        return (1);
465                        return (0);
466
467                case 0:
468                        return (scc == 0);
469
470                default:
471                        if ((c & TRIM) != scc)
472                                return (0);
473                        continue;
474
475                case '?':
476                        if (scc == 0)
477                                return (0);
478                        continue;
479
480                }
481        }
482}
483
484static
485Gcat(s1, s2)
486        register char *s1, *s2;
487{
488        register int len = strlen(s1) + strlen(s2) + 1;
489
490        if (len >= gnleft || gargc >= GAVSIZ - 1)
491                globerr = "Arguments too long";
492        else {
493                gargc++;
494                gnleft -= len;
495                gargv[gargc] = 0;
496                gargv[gargc - 1] = strspl(s1, s2);
497        }
498}
499
500static
501addpath(c)
502        char c;
503{
504
505        if (gpathp >= lastgpathp)
506                globerr = "Pathname too long";
507        else {
508                *gpathp++ = c;
509                *gpathp = 0;
510        }
511}
512
513static
514rscan(t, f)
515        register char **t;
516        int (*f)();
517{
518        register char *p, c;
519
520        while (p = *t++) {
521                if (f == tglob)
522                        if (*p == '~')
523                                gflag |= 2;
524                        else if (eq(p, "{") || eq(p, "{}"))
525                                continue;
526                while (c = *p++)
527                        (*f)(c);
528        }
529}
530/*
531static
532scan(t, f)
533        register char **t;
534        int (*f)();
535{
536        register char *p, c;
537
538        while (p = *t++)
539                while (c = *p)
540                        *p++ = (*f)(c);
541} */
542
543static
544tglob(c)
545        register char c;
546{
547
548        if (any(c, globchars))
549                gflag |= c == '{' ? 2 : 1;
550        return (c);
551}
552/*
553static
554trim(c)
555        char c;
556{
557
558        return (c & TRIM);
559} */
560
561
562letter(c)
563        register char c;
564{
565
566        return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_');
567}
568
569digit(c)
570        register char c;
571{
572
573        return (c >= '0' && c <= '9');
574}
575
576any(c, s)
577        register int c;
578        register char *s;
579{
580
581        while (*s)
582                if (*s++ == c)
583                        return(1);
584        return(0);
585}
586blklen(av)
587        register char **av;
588{
589        register int i = 0;
590
591        while (*av++)
592                i++;
593        return (i);
594}
595
596char **
597blkcpy(oav, bv)
598        char **oav;
599        register char **bv;
600{
601        register char **av = oav;
602
603        while (*av++ = *bv++)
604                continue;
605        return (oav);
606}
607
608blkfree(av0)
609        char **av0;
610{
611        register char **av = av0;
612
613        while (*av)
614                free(*av++);
615        free((char *)av0);
616}
617
618static
619char *
620strspl(cp, dp)
621        register char *cp, *dp;
622{
623        register char *ep = malloc((unsigned)(strlen(cp) + strlen(dp) + 1));
624
625        if (ep == (char *)0)
626                fatal("Out of memory");
627        (void) strcpy(ep, cp);
628        (void) strcat(ep, dp);
629        return (ep);
630}
631
632char **
633copyblk(v)
634        register char **v;
635{
636        register char **nv = (char **)malloc((unsigned)((blklen(v) + 1) *
637                                                sizeof(char **)));
638        if (nv == (char **)0)
639                fatal("Out of memory");
640
641        return (blkcpy(nv, v));
642}
643
644static
645char *
646strend(cp)
647        register char *cp;
648{
649
650        while (*cp)
651                cp++;
652        return (cp);
653}
654/*
655 * Extract a home directory from the password file
656 * The argument points to a buffer where the name of the
657 * user whose home directory is sought is currently.
658 * We write the home directory of the user back there.
659 */
660gethdir(home)
661        char *home;
662{
663        register struct passwd *pp = getpwnam(home);
664
665        if (!pp || home + strlen(pp->pw_dir) >= lastgpathp)
666                return (1);
667        (void) strcpy(home, pp->pw_dir);
668        return (0);
669}
Note: See TracBrowser for help on using the repository browser.