dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.bin / ftp / glob.c
blob82d048d79196148b27938f4e7bb863341035b4f7
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
33 * All Rights Reserved
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
37 * contributors.
40 #pragma ident "%Z%%M% %I% %E% SMI"
43 * C-shell glob for random programs.
46 #include "ftp_var.h"
48 #ifndef NCARGS
49 #define NCARGS 5120
50 #endif
52 #define QUOTE 0200
53 #define TRIM 0177
54 #define eq(a, b) (strcmp(a, b) == 0)
57 * According to the person who wrote the C shell "glob" code, a reasonable
58 * limit on number of arguments would seem to be the maximum number of
59 * characters in an arg list / 6.
61 * XXX: With the new VM system, NCARGS has become enormous, making
62 * it impractical to allocate arrays with NCARGS / 6 entries on
63 * the stack. The proper fix is to revamp code elsewhere (in
64 * sh.dol.c and sh.glob.c) to use a different technique for handling
65 * command line arguments. In the meantime, we simply fall back
66 * on using the old value of NCARGS.
68 #ifdef notyet
69 #define GAVSIZ (NCARGS / 6)
70 #else /* notyet */
71 #define GAVSIZ (10240 / 6)
72 #endif /* notyet */
74 static char **gargv; /* Pointer to the (stack) arglist */
75 static char **agargv;
76 static int agargv_size;
77 static long gargc; /* Number args in gargv */
78 static short gflag;
79 static char *strspl();
80 static char *strend(char *cp);
81 static char *strspl(char *cp, char *dp);
82 static int tglob(char c);
83 static char **copyblk(char **v);
84 static void ginit(char **agargv);
85 static void addpath(char c);
86 static int any(int c, char *s);
87 static void Gcat(char *s1, char *s2);
88 static void collect(char *as);
89 static void acollect(char *as);
90 static void sort(void);
91 static void expand(char *as);
92 static void matchdir(char *pattern);
93 static int execbrc(char *p, char *s);
94 static int ftp_fnmatch(wchar_t t_ch, wchar_t t_fch, wchar_t t_lch);
95 static int gethdir(char *home);
96 static void xfree(char *cp);
97 static void rscan(char **t, int (*f)(char));
98 static int letter(char c);
99 static int digit(char c);
100 static int match(char *s, char *p);
101 static int amatch(char *s, char *p);
102 static int blklen(char **av);
103 static char **blkcpy(char **oav, char **bv);
105 static int globcnt;
107 static char *globchars = "`{[*?";
109 static char *gpath, *gpathp, *lastgpathp;
110 static int globbed;
111 static char *entp;
112 static char **sortbas;
114 char **
115 glob(char *v)
117 char agpath[FTPBUFSIZ];
118 char *vv[2];
120 if (agargv == NULL) {
121 agargv = (char **)malloc(GAVSIZ * sizeof (char *));
122 agargv_size = GAVSIZ;
123 if (agargv == NULL) {
124 globerr = "Arguments too long.";
125 return (0);
128 vv[0] = v;
129 vv[1] = 0;
130 globerr = 0;
131 gflag = 0;
132 rscan(vv, tglob);
133 if (gflag == 0)
134 return (copyblk(vv));
136 gpath = agpath;
137 gpathp = gpath;
138 *gpathp = 0;
139 lastgpathp = &gpath[sizeof (agpath) - 2];
140 ginit(agargv);
141 globcnt = 0;
142 collect(v);
143 if (globcnt == 0 && (gflag&1)) {
144 blkfree(gargv);
145 if (gargv == agargv)
146 agargv = 0;
147 gargv = 0;
148 return (0);
149 } else
150 return (gargv = copyblk(gargv));
153 static void
154 ginit(char **agargv)
157 agargv[0] = 0;
158 gargv = agargv;
159 sortbas = agargv;
160 gargc = 0;
163 static void
164 collect(char *as)
166 if (eq(as, "{") || eq(as, "{}")) {
167 Gcat(as, "");
168 sort();
169 } else
170 acollect(as);
173 static void
174 acollect(char *as)
176 register long ogargc = gargc;
178 gpathp = gpath; *gpathp = 0; globbed = 0;
179 expand(as);
180 if (gargc != ogargc)
181 sort();
184 static void
185 sort(void)
187 register char **p1, **p2, *c;
188 char **Gvp = &gargv[gargc];
190 p1 = sortbas;
191 while (p1 < Gvp-1) {
192 p2 = p1;
193 while (++p2 < Gvp)
194 if (strcmp(*p1, *p2) > 0)
195 c = *p1, *p1 = *p2, *p2 = c;
196 p1++;
198 sortbas = Gvp;
201 static void
202 expand(char *as)
204 register char *cs;
205 register char *sgpathp, *oldcs;
206 struct stat stb;
208 sgpathp = gpathp;
209 cs = as;
210 if (*cs == '~' && gpathp == gpath) {
211 addpath('~');
212 cs++;
213 while (letter(*cs) || digit(*cs) || *cs == '-')
214 addpath(*cs++);
215 if (!*cs || *cs == '/') {
216 if (gpathp != gpath + 1) {
217 *gpathp = 0;
218 if (gethdir(gpath + 1))
219 globerr = "Unknown user name after ~";
220 (void) strcpy(gpath, gpath + 1);
221 } else
222 (void) strcpy(gpath, home);
223 gpathp = strend(gpath);
226 while (!any(*cs, globchars)) {
227 if (*cs == 0) {
228 if (!globbed)
229 Gcat(gpath, "");
230 else if (stat(gpath, &stb) >= 0) {
231 Gcat(gpath, "");
232 globcnt++;
234 goto endit;
236 addpath(*cs++);
238 oldcs = cs;
239 while (cs > as && *cs != '/')
240 cs--, gpathp--;
241 if (*cs == '/')
242 cs++, gpathp++;
243 *gpathp = 0;
244 if (*oldcs == '{') {
245 (void) execbrc(cs, ((char *)0));
246 return;
248 matchdir(cs);
249 endit:
250 gpathp = sgpathp;
251 *gpathp = 0;
254 static void
255 matchdir(char *pattern)
257 struct stat stb;
258 register struct dirent *dp;
259 DIR *dirp;
262 * BSD/SunOS open() system call maps a null pathname into
263 * "." while System V does not.
265 if (*gpath == '\0') {
266 dirp = opendir(".");
267 } else
268 dirp = opendir(gpath);
269 if (dirp == NULL) {
270 if (globbed)
271 return;
272 goto patherr2;
274 if (fstat(dirp->dd_fd, &stb) < 0)
275 goto patherr1;
276 if (!S_ISDIR(stb.st_mode)) {
277 errno = ENOTDIR;
278 goto patherr1;
280 while ((dp = readdir(dirp)) != NULL) {
281 if (dp->d_ino == 0)
282 continue;
283 if (match(dp->d_name, pattern)) {
284 Gcat(gpath, dp->d_name);
285 globcnt++;
288 closedir(dirp);
289 return;
291 patherr1:
292 closedir(dirp);
293 patherr2:
294 globerr = "Bad directory components";
297 static int
298 execbrc(char *p, char *s)
300 char restbuf[FTPBUFSIZ + 2];
301 register char *pe, *pm, *pl;
302 int brclev = 0;
303 char *lm, savec, *sgpathp;
304 int len;
306 for (lm = restbuf; *p != '{'; *lm += len, p += len) {
307 if ((len = mblen(p, MB_CUR_MAX)) <= 0)
308 len = 1;
309 memcpy(lm, p, len);
312 for (pe = ++p; *pe; pe += len) {
313 if ((len = mblen(pe, MB_CUR_MAX)) <= 0)
314 len = 1;
316 switch (*pe) {
318 case '{':
319 brclev++;
320 continue;
322 case '}':
323 if (brclev == 0)
324 goto pend;
325 brclev--;
326 continue;
328 case '[':
329 for (pe++; *pe && *pe != ']'; pe += len) {
330 if ((len = mblen(pe, MB_CUR_MAX)) <= 0)
331 len = 1;
333 len = 1;
334 continue;
337 pend:
338 brclev = 0;
339 for (pl = pm = p; pm <= pe; pm += len) {
340 if ((len = mblen(pm, MB_CUR_MAX)) <= 0)
341 len = 1;
343 switch (*pm & (QUOTE|TRIM)) {
345 case '{':
346 brclev++;
347 continue;
349 case '}':
350 if (brclev) {
351 brclev--;
352 continue;
354 goto doit;
356 case ','|QUOTE:
357 case ',':
358 if (brclev)
359 continue;
360 doit:
361 savec = *pm;
362 *pm = 0;
363 (void) strcpy(lm, pl);
364 (void) strcat(restbuf, pe + 1);
365 *pm = savec;
366 if (s == 0) {
367 sgpathp = gpathp;
368 expand(restbuf);
369 gpathp = sgpathp;
370 *gpathp = 0;
371 } else if (amatch(s, restbuf))
372 return (1);
373 sort();
374 pl = pm + 1;
375 if (brclev)
376 return (0);
377 continue;
379 case '[':
380 for (pm++; *pm && *pm != ']'; pm += len) {
381 if ((len = mblen(pm, MB_CUR_MAX)) <= 0)
382 len = 1;
384 len = 1;
385 if (!*pm)
386 pm--;
387 continue;
390 if (brclev)
391 goto doit;
392 return (0);
395 static int
396 match(char *s, char *p)
398 register int c;
399 register char *sentp;
400 char sglobbed = globbed;
402 if (*s == '.' && *p != '.')
403 return (0);
404 sentp = entp;
405 entp = s;
406 c = amatch(s, p);
407 entp = sentp;
408 globbed = sglobbed;
409 return (c);
412 static int
413 amatch(char *s, char *p)
415 wchar_t scc;
416 int ok;
417 wchar_t lc1, lc2;
418 char *sgpathp;
419 struct stat stb;
420 wchar_t c, cc;
421 int len_s, len_p;
423 globbed = 1;
424 for (;;) {
425 if ((len_s = mbtowc(&scc, s, MB_CUR_MAX)) <= 0) {
426 scc = (unsigned char)*s;
427 len_s = 1;
429 /* scc = *s++ & TRIM; */
430 s += len_s;
432 if ((len_p = mbtowc(&c, p, MB_CUR_MAX)) <= 0) {
433 c = (unsigned char)*p;
434 len_p = 1;
436 p += len_p;
437 switch (c) {
439 case '{':
440 return (execbrc(p - len_p, s - len_s));
442 case '[':
443 ok = 0;
444 lc1 = 0;
445 while ((cc = *p) != '\0') {
446 if ((len_p = mbtowc(&cc, p, MB_CUR_MAX)) <= 0) {
447 cc = (unsigned char)*p;
448 len_p = 1;
450 p += len_p;
451 if (cc == ']') {
452 if (ok)
453 break;
454 return (0);
456 if (cc == '-') {
457 if ((len_p = mbtowc(&lc2, p,
458 MB_CUR_MAX)) <= 0) {
459 lc2 = (unsigned char)*p;
460 len_p = 1;
462 p += len_p;
463 if (ftp_fnmatch(scc, lc1, lc2))
464 ok++;
465 } else
466 if (scc == (lc1 = cc))
467 ok++;
469 if (cc == 0)
470 if (!ok)
471 return (0);
472 continue;
474 case '*':
475 if (!*p)
476 return (1);
477 if (*p == '/') {
478 p++;
479 goto slash;
481 s -= len_s;
482 do {
483 if (amatch(s, p))
484 return (1);
485 } while (*s++);
486 return (0);
488 case 0:
489 return (scc == 0);
491 default:
492 if (c != scc)
493 return (0);
494 continue;
496 case '?':
497 if (scc == 0)
498 return (0);
499 continue;
501 case '/':
502 if (scc)
503 return (0);
504 slash:
505 s = entp;
506 sgpathp = gpathp;
507 while (*s)
508 addpath(*s++);
509 addpath('/');
510 if (stat(gpath, &stb) == 0 && S_ISDIR(stb.st_mode))
511 if (*p == 0) {
512 Gcat(gpath, "");
513 globcnt++;
514 } else
515 expand(p);
516 gpathp = sgpathp;
517 *gpathp = 0;
518 return (0);
523 #ifdef notdef
524 static
525 Gmatch(s, p)
526 register char *s, *p;
528 register int scc;
529 int ok, lc;
530 int c, cc;
532 for (;;) {
533 scc = *s++ & TRIM;
534 switch (c = *p++) {
536 case '[':
537 ok = 0;
538 lc = 077777;
539 while (cc = *p++) {
540 if (cc == ']') {
541 if (ok)
542 break;
543 return (0);
545 if (cc == '-') {
546 if (lc <= scc && scc <= *p++)
547 ok++;
548 } else
549 if (scc == (lc = cc))
550 ok++;
552 if (cc == 0)
553 if (ok)
554 p--;
555 else
556 return (0);
557 continue;
559 case '*':
560 if (!*p)
561 return (1);
562 for (s--; *s; s++)
563 if (Gmatch(s, p))
564 return (1);
565 return (0);
567 case 0:
568 return (scc == 0);
570 default:
571 if ((c & TRIM) != scc)
572 return (0);
573 continue;
575 case '?':
576 if (scc == 0)
577 return (0);
578 continue;
583 #endif
585 static void
586 Gcat(char *s1, char *s2)
588 if (gargc >= agargv_size - 1) {
589 char **tmp;
591 if (globerr) {
592 return;
594 tmp = reallocarray(agargv, agargv_size + GAVSIZ,
595 sizeof (char *));
596 if (tmp == NULL) {
597 globerr = "Arguments too long";
598 return;
599 } else {
600 agargv = tmp;
601 agargv_size += GAVSIZ;
603 gargv = agargv;
604 sortbas = agargv;
606 gargc++;
607 gargv[gargc] = 0;
608 gargv[gargc - 1] = strspl(s1, s2);
611 static void
612 addpath(char c)
615 if (gpathp >= lastgpathp)
616 globerr = "Pathname too long";
617 else {
618 *gpathp++ = c;
619 *gpathp = 0;
623 static void
624 rscan(char **t, int (*f)(char))
626 register char *p, c;
627 int len;
629 while (p = *t++) {
630 if (f == tglob)
631 if (*p == '~')
632 gflag |= 2;
633 else if (eq(p, "{") || eq(p, "{}"))
634 continue;
635 while ((c = *p) != '\0') {
636 (void) (*f)(c);
637 if ((len = mblen(p, MB_CUR_MAX)) <= 0)
638 len = 1;
639 p += len;
644 static int
645 tglob(char c)
647 if (any(c, globchars))
648 gflag |= c == '{' ? 2 : 1;
649 return (c);
652 static int
653 letter(char c)
655 return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_');
658 static int
659 digit(char c)
661 return (c >= '0' && c <= '9');
664 static int
665 any(int c, char *s)
667 int len;
669 while (*s) {
670 if (*s == c)
671 return (1);
672 if ((len = mblen(s, MB_CUR_MAX)) <= 0)
673 len = 1;
674 s += len;
676 return (0);
679 static int
680 blklen(char **av)
682 register int i = 0;
684 while (*av++)
685 i++;
686 return (i);
689 static char **
690 blkcpy(char **oav, char **bv)
692 register char **av = oav;
694 while (*av++ = *bv++)
695 continue;
696 return (oav);
699 void
700 blkfree(char **av0)
702 register char **av = av0;
704 while (*av)
705 xfree(*av++);
706 free(av0);
709 static void
710 xfree(char *cp)
712 extern char end[];
714 if (cp >= end && cp < (char *)&cp)
715 free(cp);
718 static char *
719 strspl(char *cp, char *dp)
721 register char *ep = malloc((unsigned)(strlen(cp) + strlen(dp) + 1));
723 if (ep == NULL)
724 fatal("Out of memory");
725 (void) strcpy(ep, cp);
726 (void) strcat(ep, dp);
727 return (ep);
730 static char **
731 copyblk(char **v)
733 register char **nv = (char **)malloc((unsigned)((blklen(v) + 1) *
734 sizeof (char **)));
736 if (nv == (char **)0)
737 fatal("Out of memory");
739 return (blkcpy(nv, v));
742 static char *
743 strend(char *cp)
746 while (*cp)
747 cp++;
748 return (cp);
751 * Extract a home directory from the password file
752 * The argument points to a buffer where the name of the
753 * user whose home directory is sought is currently.
754 * We write the home directory of the user back there.
756 static int
757 gethdir(char *home)
759 register struct passwd *pp = getpwnam(home);
761 if (!pp || home + strlen(pp->pw_dir) >= lastgpathp)
762 return (1);
763 (void) strcpy(home, pp->pw_dir);
764 return (0);
767 static int
768 ftp_fnmatch(wchar_t t_ch, wchar_t t_fch, wchar_t t_lch)
770 char t_char[MB_LEN_MAX + 1];
771 char t_patan[MB_LEN_MAX * 2 + 8];
772 char *p;
773 int i;
775 if ((t_ch == t_fch) || (t_ch == t_lch))
776 return (1);
778 p = t_patan;
779 if ((i = wctomb(t_char, (wchar_t)t_ch)) <= 0)
780 return (0);
781 t_char[i] = 0;
783 *p++ = '[';
784 if ((i = wctomb(p, (wchar_t)t_fch)) <= 0)
785 return (0);
786 p += i;
787 *p++ = '-';
788 if ((i = wctomb(p, (wchar_t)t_lch)) <= 0)
789 return (0);
790 p += i;
791 *p++ = ']';
792 *p = 0;
794 if (fnmatch(t_patan, t_char, FNM_NOESCAPE))
795 return (0);
796 return (1);