1 /* glob.c: The csh et al glob pattern matching routines.
4 This software is Copyright 1996-2001 by Craig Metz, All Rights Reserved.
5 The Inner Net License Version 3 applies to this software.
6 You should have received a copy of the license with this software. If
7 you didn't get a copy, you may request one from <license@inner.net>.
9 Portions of this software are Copyright 1995 by Randall Atkinson and Dan
10 McDonald, All Rights Reserved. All Rights under this copyright are assigned
11 to the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and
12 License Agreement applies to this software.
16 Modified by cmetz for OPIE 2.32. Remove include of dirent.h here; it's
17 done already (and conditionally) in opie_cfg.h.
18 Modified by cmetz for OPIE 2.2. Use FUNCTION declaration et al.
19 Remove useless strings. Prototype right.
20 Modified at NRL for OPIE 2.0.
24 * Copyright (c) 1980 Regents of the University of California.
25 * All rights reserved.
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * This product includes software developed by the University of
38 * California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * C-shell glob for random programs.
63 #include <sys/param.h>
64 #endif /* HAVE_SYS_PARAM_H */
69 #endif /* HAVE_PWD_H */
75 #endif /* HAVE_LIMITS_H */
84 #define eq(a,b) (strcmp((a),(b)) == (0))
85 #define GAVSIZ (NCARGS/6)
86 #define isdir(d) (((d.st_mode) & S_IFMT) == S_IFDIR)
88 static char **gargv
; /* Pointer to the (stack) arglist */
89 static int gargc
; /* Number args in gargv */
93 static int letter
__P((register char));
94 static int digit
__P((register char));
95 static int any
__P((int, char *));
96 static int blklen
__P((register char **));
97 VOIDRET blkfree
__P((char **));
98 static char *strspl
__P((register char *, register char *));
100 static int tglob
__P((register char c
));
103 static char *strend
__P((char *));
107 static char *globchars
= "`{[*?";
108 char *globerr
= NULL
;
111 static char *gpath
, *gpathp
, *lastgpathp
;
114 static char **sortbas
;
116 static int amatch
__P((char *p
, char *s
));
117 static int execbrc
__P((register char *p
, register char *s
));
118 VOIDRET opiefatal
__P((char *));
119 char **copyblk
__P((char **));
121 static int match
FUNCTION((s
, p
), char *s AND
char *p
)
124 register char *sentp
;
125 char sglobbed
= globbed
;
127 if (*s
== '.' && *p
!= '.')
138 static int Gmatch
FUNCTION((s
, p
), register char *s AND
register char *p
)
158 if (lc
<= scc
&& scc
<= *p
++)
161 if (scc
== (lc
= cc
))
183 if ((c
& TRIM
) != scc
)
196 static VOIDRET Gcat
FUNCTION((s1
, s2
), register char *s1 AND
register char *s2
)
198 register int len
= strlen(s1
) + strlen(s2
) + 1;
200 if (len
>= gnleft
|| gargc
>= GAVSIZ
- 1)
201 globerr
= "Arguments too long";
206 gargv
[gargc
- 1] = strspl(s1
, s2
);
210 static VOIDRET addpath
FUNCTION((c
), char c
)
213 if (gpathp
>= lastgpathp
)
214 globerr
= "Pathname too long";
221 static VOIDRET rscan
FUNCTION((t
, f
), register char **t AND
int (*f
)__P((char)))
230 if (eq(p
, "{") || eq(p
, "{}"))
237 static int tglob
FUNCTION((c
), register char c
)
239 if (any(c
, globchars
))
240 gflag
|= c
== '{' ? 2 : 1;
244 static int letter
FUNCTION((c
), register char c
)
246 return (c
>= 'a' && c
<= 'z' || c
>= 'A' && c
<= 'Z' || c
== '_');
249 static int digit
FUNCTION((c
), register char c
)
251 return (c
>= '0' && c
<= '9');
254 static int any
FUNCTION((c
, s
), int c AND
char *s
)
262 static int blklen
FUNCTION((av
), register char **av
)
271 static char **blkcpy
FUNCTION((oav
, bv
), char **oav AND
register char **bv
)
273 register char **av
= oav
;
275 while (*av
++ = *bv
++)
280 VOIDRET blkfree
FUNCTION((av0
), char **av0
)
282 register char **av
= av0
;
288 static char *strspl
FUNCTION((cp
, dp
), register char *cp AND
register char *dp
)
290 register char *ep
= (char *) malloc((unsigned) (strlen(cp
) +
293 if (ep
== (char *) 0)
294 opiefatal("Out of memory");
300 char **copyblk
FUNCTION((v
), char **v
)
302 register char **nv
= (char **) malloc((unsigned) ((blklen(v
) + 1) *
305 if (nv
== (char **) 0)
306 opiefatal("Out of memory");
308 return (blkcpy(nv
, v
));
311 static char *strend
FUNCTION((cp
), register char *cp
)
320 * Extract a home directory from the password file
321 * The argument points to a buffer where the name of the
322 * user whose home directory is sought is currently.
323 * We write the home directory of the user back there.
325 static int gethdir
FUNCTION((home
), char *home
)
327 register struct passwd
*pp
= getpwnam(home
);
329 if (!pp
|| home
+ strlen(pp
->pw_dir
) >= lastgpathp
)
331 strcpy(home
, pp
->pw_dir
);
335 static VOIDRET ginit
FUNCTION((agargv
), char **agargv
)
344 static VOIDRET sort FUNCTION_NOARGS
346 register char **p1
, **p2
, *c
;
347 char **Gvp
= &gargv
[gargc
];
350 while (p1
< Gvp
- 1) {
353 if (strcmp(*p1
, *p2
) > 0)
354 c
= *p1
, *p1
= *p2
, *p2
= c
;
360 static VOIDRET matchdir
FUNCTION((pattern
), char *pattern
)
364 register struct dirent
*dp
;
368 dirp
= opendir(*gpath
== '\0' ? "." : gpath
);
375 if (fstat(dirp
->dd_fd
, &stb
) < 0)
381 #endif /* !defined(linux) */
382 while ((dp
= readdir(dirp
)) != NULL
) {
385 if (match(dp
->d_name
, pattern
)) {
386 Gcat(gpath
, dp
->d_name
);
396 globerr
= "Bad directory components";
399 static VOIDRET expand
FUNCTION((as
), char *as
)
402 register char *sgpathp
, *oldcs
;
407 if (*cs
== '~' && gpathp
== gpath
) {
409 for (cs
++; letter(*cs
) || digit(*cs
) || *cs
== '-';)
411 if (!*cs
|| *cs
== '/') {
412 if (gpathp
!= gpath
+ 1) {
414 if (gethdir(gpath
+ 1))
415 globerr
= "Unknown user name after ~";
416 strcpy(gpath
, gpath
+ 1);
419 gpathp
= strend(gpath
);
422 while (!any(*cs
, globchars
)) {
427 if (stat(gpath
, &stb
) >= 0) {
436 while (cs
> as
&& *cs
!= '/')
442 execbrc(cs
, ((char *) 0));
451 static int execbrc
FUNCTION((p
, s
), char *p AND
char *s
)
453 char restbuf
[BUFSIZ
+ 2];
454 register char *pe
, *pm
, *pl
;
456 char *lm
, savec
, *sgpathp
;
458 for (lm
= restbuf
; *p
!= '{'; *lm
++ = *p
++)
460 for (pe
= ++p
; *pe
; pe
++)
474 for (pe
++; *pe
&& *pe
!= ']'; pe
++)
480 for (pl
= pm
= p
; pm
<= pe
; pm
++)
481 switch (*pm
& (QUOTE
| TRIM
)) {
502 strcat(restbuf
, pe
+ 1);
510 if (amatch(s
, restbuf
))
519 for (pm
++; *pm
&& *pm
!= ']'; pm
++)
530 static VOIDRET acollect
FUNCTION((as
), register char *as
)
532 register int ogargc
= gargc
;
542 static VOIDRET collect
FUNCTION((as
), register char *as
)
544 if (eq(as
, "{") || eq(as
, "{}")) {
551 static int amatch
FUNCTION((s
, p
), register char *s AND
register char *p
)
565 return (execbrc(p
- 1, s
- 1));
577 if (lc
<= scc
&& scc
<= *p
++)
580 if (scc
== (lc
= cc
))
627 if (stat(gpath
, &stb
) == 0 && isdir(stb
))
641 char **ftpglob
FUNCTION((v
), register char *v
)
644 char *agargv
[GAVSIZ
];
652 vv
[0] = strspl(v
, "");
653 return (copyblk(vv
));
659 lastgpathp
= &gpath
[sizeof agpath
- 2];
663 if (globcnt
== 0 && (gflag
& 1)) {
664 blkfree(gargv
), gargv
= 0;
667 return (gargv
= copyblk(gargv
));