xref: /plan9/sys/src/ape/cmd/pax/namelist.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1*9a747e4fSDavid du Colombier /* $Source: /u/mark/src/pax/RCS/namelist.c,v $
2*9a747e4fSDavid du Colombier  *
3*9a747e4fSDavid du Colombier  * $Revision: 1.6 $
4*9a747e4fSDavid du Colombier  *
5*9a747e4fSDavid du Colombier  * namelist.c - track filenames given as arguments to tar/cpio/pax
6*9a747e4fSDavid du Colombier  *
7*9a747e4fSDavid du Colombier  * DESCRIPTION
8*9a747e4fSDavid du Colombier  *
9*9a747e4fSDavid du Colombier  *	Arguments may be regular expressions, therefore all agurments will
10*9a747e4fSDavid du Colombier  *	be treated as if they were regular expressions, even if they are
11*9a747e4fSDavid du Colombier  *	not.
12*9a747e4fSDavid du Colombier  *
13*9a747e4fSDavid du Colombier  * AUTHOR
14*9a747e4fSDavid du Colombier  *
15*9a747e4fSDavid du Colombier  *	Mark H. Colburn, NAPS International (mark@jhereg.mn.org)
16*9a747e4fSDavid du Colombier  *
17*9a747e4fSDavid du Colombier  * Sponsored by The USENIX Association for public distribution.
18*9a747e4fSDavid du Colombier  *
19*9a747e4fSDavid du Colombier  * Copyright (c) 1989 Mark H. Colburn.
20*9a747e4fSDavid du Colombier  * All rights reserved.
21*9a747e4fSDavid du Colombier  *
22*9a747e4fSDavid du Colombier  * Redistribution and use in source and binary forms are permitted
23*9a747e4fSDavid du Colombier  * provided that the above copyright notice is duplicated in all such
24*9a747e4fSDavid du Colombier  * forms and that any documentation, advertising materials, and other
25*9a747e4fSDavid du Colombier  * materials related to such distribution and use acknowledge that the
26*9a747e4fSDavid du Colombier  * software was developed by Mark H. Colburn and sponsored by The
27*9a747e4fSDavid du Colombier  * USENIX Association.
28*9a747e4fSDavid du Colombier  *
29*9a747e4fSDavid du Colombier  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
30*9a747e4fSDavid du Colombier  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
31*9a747e4fSDavid du Colombier  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32*9a747e4fSDavid du Colombier  *
33*9a747e4fSDavid du Colombier  * $Log:	namelist.c,v $
34*9a747e4fSDavid du Colombier  * Revision 1.6  89/02/13  09:14:48  mark
35*9a747e4fSDavid du Colombier  * Fixed problem with directory errors
36*9a747e4fSDavid du Colombier  *
37*9a747e4fSDavid du Colombier  * Revision 1.5  89/02/12  12:14:00  mark
38*9a747e4fSDavid du Colombier  * Fixed misspellings
39*9a747e4fSDavid du Colombier  *
40*9a747e4fSDavid du Colombier  * Revision 1.4  89/02/12  11:25:19  mark
41*9a747e4fSDavid du Colombier  * Modifications to compile and link cleanly under USG
42*9a747e4fSDavid du Colombier  *
43*9a747e4fSDavid du Colombier  * Revision 1.3  89/02/12  10:40:23  mark
44*9a747e4fSDavid du Colombier  * Fixed casting problems
45*9a747e4fSDavid du Colombier  *
46*9a747e4fSDavid du Colombier  * Revision 1.2  89/02/12  10:04:57  mark
47*9a747e4fSDavid du Colombier  * 1.2 release fixes
48*9a747e4fSDavid du Colombier  *
49*9a747e4fSDavid du Colombier  * Revision 1.1  88/12/23  18:02:17  mark
50*9a747e4fSDavid du Colombier  * Initial revision
51*9a747e4fSDavid du Colombier  *
52*9a747e4fSDavid du Colombier  */
53*9a747e4fSDavid du Colombier 
54*9a747e4fSDavid du Colombier #ifndef lint
55*9a747e4fSDavid du Colombier static char *ident = "$Id: namelist.c,v 1.6 89/02/13 09:14:48 mark Exp $";
56*9a747e4fSDavid du Colombier static char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
57*9a747e4fSDavid du Colombier #endif /* ! lint */
58*9a747e4fSDavid du Colombier 
59*9a747e4fSDavid du Colombier 
60*9a747e4fSDavid du Colombier /* Headers */
61*9a747e4fSDavid du Colombier 
62*9a747e4fSDavid du Colombier #include "pax.h"
63*9a747e4fSDavid du Colombier 
64*9a747e4fSDavid du Colombier 
65*9a747e4fSDavid du Colombier /* Type Definitions */
66*9a747e4fSDavid du Colombier 
67*9a747e4fSDavid du Colombier /*
68*9a747e4fSDavid du Colombier  * Structure for keeping track of filenames and lists thereof.
69*9a747e4fSDavid du Colombier  */
70*9a747e4fSDavid du Colombier struct nm_list {
71*9a747e4fSDavid du Colombier     struct nm_list *next;
72*9a747e4fSDavid du Colombier     short           length;	/* cached strlen(name) */
73*9a747e4fSDavid du Colombier     char            found;	/* A matching file has been found */
74*9a747e4fSDavid du Colombier     char            firstch;	/* First char is literally matched */
75*9a747e4fSDavid du Colombier     char            re;		/* regexp pattern for item */
76*9a747e4fSDavid du Colombier     char            name[1];	/* name of file or rexexp */
77*9a747e4fSDavid du Colombier };
78*9a747e4fSDavid du Colombier 
79*9a747e4fSDavid du Colombier struct dirinfo {
80*9a747e4fSDavid du Colombier     char            dirname[PATH_MAX + 1];	/* name of directory */
81*9a747e4fSDavid du Colombier     OFFSET	    where;	/* current location in directory */
82*9a747e4fSDavid du Colombier     struct dirinfo *next;
83*9a747e4fSDavid du Colombier };
84*9a747e4fSDavid du Colombier 
85*9a747e4fSDavid du Colombier 
86*9a747e4fSDavid du Colombier /* Static Variables */
87*9a747e4fSDavid du Colombier 
88*9a747e4fSDavid du Colombier static struct dirinfo *stack_head = (struct dirinfo *)NULL;
89*9a747e4fSDavid du Colombier 
90*9a747e4fSDavid du Colombier 
91*9a747e4fSDavid du Colombier /* Function Prototypes */
92*9a747e4fSDavid du Colombier 
93*9a747e4fSDavid du Colombier #ifndef __STDC__
94*9a747e4fSDavid du Colombier 
95*9a747e4fSDavid du Colombier static void pushdir();
96*9a747e4fSDavid du Colombier static struct dirinfo *popdir();
97*9a747e4fSDavid du Colombier 
98*9a747e4fSDavid du Colombier #else
99*9a747e4fSDavid du Colombier 
100*9a747e4fSDavid du Colombier static void pushdir(struct dirinfo *info);
101*9a747e4fSDavid du Colombier static struct dirinfo *popdir(void);
102*9a747e4fSDavid du Colombier 
103*9a747e4fSDavid du Colombier #endif
104*9a747e4fSDavid du Colombier 
105*9a747e4fSDavid du Colombier 
106*9a747e4fSDavid du Colombier /* Internal Identifiers */
107*9a747e4fSDavid du Colombier 
108*9a747e4fSDavid du Colombier static struct nm_list *namelast;	/* Points to last name in list */
109*9a747e4fSDavid du Colombier static struct nm_list *namelist;	/* Points to first name in list */
110*9a747e4fSDavid du Colombier 
111*9a747e4fSDavid du Colombier 
112*9a747e4fSDavid du Colombier /* addname -  add a name to the namelist.
113*9a747e4fSDavid du Colombier  *
114*9a747e4fSDavid du Colombier  * DESCRIPTION
115*9a747e4fSDavid du Colombier  *
116*9a747e4fSDavid du Colombier  *	Addname adds the name given to the name list.  Memory for the
117*9a747e4fSDavid du Colombier  *	namelist structure is dynamically allocated.  If the space for
118*9a747e4fSDavid du Colombier  *	the structure cannot be allocated, then the program will exit
119*9a747e4fSDavid du Colombier  *	the an out of memory error message and a non-zero return code
120*9a747e4fSDavid du Colombier  *	will be returned to the caller.
121*9a747e4fSDavid du Colombier  *
122*9a747e4fSDavid du Colombier  * PARAMETERS
123*9a747e4fSDavid du Colombier  *
124*9a747e4fSDavid du Colombier  *	char *name	- A pointer to the name to add to the list
125*9a747e4fSDavid du Colombier  */
126*9a747e4fSDavid du Colombier 
127*9a747e4fSDavid du Colombier #ifdef __STDC__
128*9a747e4fSDavid du Colombier 
add_name(char * name)129*9a747e4fSDavid du Colombier void add_name(char *name)
130*9a747e4fSDavid du Colombier 
131*9a747e4fSDavid du Colombier #else
132*9a747e4fSDavid du Colombier 
133*9a747e4fSDavid du Colombier void add_name(name)
134*9a747e4fSDavid du Colombier char           *name;		/* pointer to name */
135*9a747e4fSDavid du Colombier 
136*9a747e4fSDavid du Colombier #endif
137*9a747e4fSDavid du Colombier {
138*9a747e4fSDavid du Colombier     int             i;		/* Length of string */
139*9a747e4fSDavid du Colombier     struct nm_list *p;		/* Current struct pointer */
140*9a747e4fSDavid du Colombier 
141*9a747e4fSDavid du Colombier     i = strlen(name);
142*9a747e4fSDavid du Colombier     p = (struct nm_list *) malloc((unsigned) (i + sizeof(struct nm_list)));
143*9a747e4fSDavid du Colombier     if (!p) {
144*9a747e4fSDavid du Colombier 	fatal("cannot allocate memory for namelist entry\n");
145*9a747e4fSDavid du Colombier     }
146*9a747e4fSDavid du Colombier     p->next = (struct nm_list *)NULL;
147*9a747e4fSDavid du Colombier     p->length = i;
148*9a747e4fSDavid du Colombier     strncpy(p->name, name, i);
149*9a747e4fSDavid du Colombier     p->name[i] = '\0';		/* Null term */
150*9a747e4fSDavid du Colombier     p->found = 0;
151*9a747e4fSDavid du Colombier     p->firstch = isalpha(name[0]);
152*9a747e4fSDavid du Colombier     if (strchr(name, '*') || strchr(name, '[') || strchr(name, '?')) {
153*9a747e4fSDavid du Colombier         p->re = 1;
154*9a747e4fSDavid du Colombier     }
155*9a747e4fSDavid du Colombier     if (namelast) {
156*9a747e4fSDavid du Colombier 	namelast->next = p;
157*9a747e4fSDavid du Colombier     }
158*9a747e4fSDavid du Colombier     namelast = p;
159*9a747e4fSDavid du Colombier     if (!namelist) {
160*9a747e4fSDavid du Colombier 	namelist = p;
161*9a747e4fSDavid du Colombier     }
162*9a747e4fSDavid du Colombier }
163*9a747e4fSDavid du Colombier 
164*9a747e4fSDavid du Colombier 
165*9a747e4fSDavid du Colombier /* name_match - match a name from an archive with a name from the namelist
166*9a747e4fSDavid du Colombier  *
167*9a747e4fSDavid du Colombier  * DESCRIPTION
168*9a747e4fSDavid du Colombier  *
169*9a747e4fSDavid du Colombier  *	Name_match attempts to find a name pointed at by p in the namelist.
170*9a747e4fSDavid du Colombier  *	If no namelist is available, then all filenames passed in are
171*9a747e4fSDavid du Colombier  *	assumed to match the filename criteria.  Name_match knows how to
172*9a747e4fSDavid du Colombier  *	match names with regular expressions, etc.
173*9a747e4fSDavid du Colombier  *
174*9a747e4fSDavid du Colombier  * PARAMETERS
175*9a747e4fSDavid du Colombier  *
176*9a747e4fSDavid du Colombier  *	char	*p	- the name to match
177*9a747e4fSDavid du Colombier  *
178*9a747e4fSDavid du Colombier  * RETURNS
179*9a747e4fSDavid du Colombier  *
180*9a747e4fSDavid du Colombier  *	Returns 1 if the name is in the namelist, or no name list is
181*9a747e4fSDavid du Colombier  *	available, otherwise returns 0
182*9a747e4fSDavid du Colombier  *
183*9a747e4fSDavid du Colombier  */
184*9a747e4fSDavid du Colombier 
185*9a747e4fSDavid du Colombier #ifdef __STDC__
186*9a747e4fSDavid du Colombier 
name_match(char * p)187*9a747e4fSDavid du Colombier int name_match(char *p)
188*9a747e4fSDavid du Colombier 
189*9a747e4fSDavid du Colombier #else
190*9a747e4fSDavid du Colombier 
191*9a747e4fSDavid du Colombier int name_match(p)
192*9a747e4fSDavid du Colombier char           *p;
193*9a747e4fSDavid du Colombier 
194*9a747e4fSDavid du Colombier #endif
195*9a747e4fSDavid du Colombier {
196*9a747e4fSDavid du Colombier     struct nm_list *nlp;
197*9a747e4fSDavid du Colombier     int             len;
198*9a747e4fSDavid du Colombier 
199*9a747e4fSDavid du Colombier     if ((nlp = namelist) == 0) {/* Empty namelist is easy */
200*9a747e4fSDavid du Colombier 	return (1);
201*9a747e4fSDavid du Colombier     }
202*9a747e4fSDavid du Colombier     len = strlen(p);
203*9a747e4fSDavid du Colombier     for (; nlp != 0; nlp = nlp->next) {
204*9a747e4fSDavid du Colombier 	/* If first chars don't match, quick skip */
205*9a747e4fSDavid du Colombier 	if (nlp->firstch && nlp->name[0] != p[0]) {
206*9a747e4fSDavid du Colombier 	    continue;
207*9a747e4fSDavid du Colombier 	}
208*9a747e4fSDavid du Colombier 	/* Regular expressions */
209*9a747e4fSDavid du Colombier 	if (nlp->re) {
210*9a747e4fSDavid du Colombier 	    if (wildmat(nlp->name, p)) {
211*9a747e4fSDavid du Colombier 		nlp->found = 1;	/* Remember it matched */
212*9a747e4fSDavid du Colombier 		return (1);	/* We got a match */
213*9a747e4fSDavid du Colombier 	    }
214*9a747e4fSDavid du Colombier 	    continue;
215*9a747e4fSDavid du Colombier 	}
216*9a747e4fSDavid du Colombier 	/* Plain Old Strings */
217*9a747e4fSDavid du Colombier 	if (nlp->length <= len	/* Archive len >= specified */
218*9a747e4fSDavid du Colombier 	    && (p[nlp->length] == '\0' || p[nlp->length] == '/')
219*9a747e4fSDavid du Colombier 	    && strncmp(p, nlp->name, nlp->length) == 0) {
220*9a747e4fSDavid du Colombier 	    /* Name compare */
221*9a747e4fSDavid du Colombier 	    nlp->found = 1;	/* Remember it matched */
222*9a747e4fSDavid du Colombier 	    return (1);		/* We got a match */
223*9a747e4fSDavid du Colombier 	}
224*9a747e4fSDavid du Colombier     }
225*9a747e4fSDavid du Colombier     return (0);
226*9a747e4fSDavid du Colombier }
227*9a747e4fSDavid du Colombier 
228*9a747e4fSDavid du Colombier 
229*9a747e4fSDavid du Colombier /* names_notfound - print names of files in namelist that were not found
230*9a747e4fSDavid du Colombier  *
231*9a747e4fSDavid du Colombier  * DESCRIPTION
232*9a747e4fSDavid du Colombier  *
233*9a747e4fSDavid du Colombier  *	Names_notfound scans through the namelist for any files which were
234*9a747e4fSDavid du Colombier  *	named, but for which a matching file was not processed by the
235*9a747e4fSDavid du Colombier  *	archive.  Each of the files is listed on the standard error.
236*9a747e4fSDavid du Colombier  *
237*9a747e4fSDavid du Colombier  */
238*9a747e4fSDavid du Colombier 
239*9a747e4fSDavid du Colombier #ifdef __STDC__
240*9a747e4fSDavid du Colombier 
names_notfound(void)241*9a747e4fSDavid du Colombier void names_notfound(void)
242*9a747e4fSDavid du Colombier 
243*9a747e4fSDavid du Colombier #else
244*9a747e4fSDavid du Colombier 
245*9a747e4fSDavid du Colombier void names_notfound()
246*9a747e4fSDavid du Colombier 
247*9a747e4fSDavid du Colombier #endif
248*9a747e4fSDavid du Colombier {
249*9a747e4fSDavid du Colombier     struct nm_list *nlp;
250*9a747e4fSDavid du Colombier 
251*9a747e4fSDavid du Colombier     for (nlp = namelist; nlp != 0; nlp = nlp->next) {
252*9a747e4fSDavid du Colombier 	if (!nlp->found) {
253*9a747e4fSDavid du Colombier 	    fprintf(stderr, "%s: %s not found in archive\n",
254*9a747e4fSDavid du Colombier 	            myname, nlp->name);
255*9a747e4fSDavid du Colombier 	}
256*9a747e4fSDavid du Colombier 	free(nlp);
257*9a747e4fSDavid du Colombier     }
258*9a747e4fSDavid du Colombier     namelist = (struct nm_list *)NULL;
259*9a747e4fSDavid du Colombier     namelast = (struct nm_list *)NULL;
260*9a747e4fSDavid du Colombier }
261*9a747e4fSDavid du Colombier 
262*9a747e4fSDavid du Colombier 
263*9a747e4fSDavid du Colombier /* name_init - set up to gather file names
264*9a747e4fSDavid du Colombier  *
265*9a747e4fSDavid du Colombier  * DESCRIPTION
266*9a747e4fSDavid du Colombier  *
267*9a747e4fSDavid du Colombier  *	Name_init sets up the namelist pointers so that we may access the
268*9a747e4fSDavid du Colombier  *	command line arguments.  At least the first item of the command
269*9a747e4fSDavid du Colombier  *	line (argv[0]) is assumed to be stripped off, prior to the
270*9a747e4fSDavid du Colombier  *	name_init call.
271*9a747e4fSDavid du Colombier  *
272*9a747e4fSDavid du Colombier  * PARAMETERS
273*9a747e4fSDavid du Colombier  *
274*9a747e4fSDavid du Colombier  *	int	argc	- number of items in argc
275*9a747e4fSDavid du Colombier  *	char	**argv	- pointer to the command line arguments
276*9a747e4fSDavid du Colombier  */
277*9a747e4fSDavid du Colombier 
278*9a747e4fSDavid du Colombier #ifdef __STDC__
279*9a747e4fSDavid du Colombier 
name_init(int argc,char ** argv)280*9a747e4fSDavid du Colombier void name_init(int argc, char **argv)
281*9a747e4fSDavid du Colombier 
282*9a747e4fSDavid du Colombier #else
283*9a747e4fSDavid du Colombier 
284*9a747e4fSDavid du Colombier void name_init(argc, argv)
285*9a747e4fSDavid du Colombier int             argc;
286*9a747e4fSDavid du Colombier char          **argv;
287*9a747e4fSDavid du Colombier 
288*9a747e4fSDavid du Colombier #endif
289*9a747e4fSDavid du Colombier {
290*9a747e4fSDavid du Colombier     /* Get file names from argv, after options. */
291*9a747e4fSDavid du Colombier     n_argc = argc;
292*9a747e4fSDavid du Colombier     n_argv = argv;
293*9a747e4fSDavid du Colombier }
294*9a747e4fSDavid du Colombier 
295*9a747e4fSDavid du Colombier 
296*9a747e4fSDavid du Colombier /* name_next - get the next name from argv or the name file.
297*9a747e4fSDavid du Colombier  *
298*9a747e4fSDavid du Colombier  * DESCRIPTION
299*9a747e4fSDavid du Colombier  *
300*9a747e4fSDavid du Colombier  *	Name next finds the next name which is to be processed in the
301*9a747e4fSDavid du Colombier  *	archive.  If the named file is a directory, then the directory
302*9a747e4fSDavid du Colombier  *	is recursively traversed for additional file names.  Directory
303*9a747e4fSDavid du Colombier  *	names and locations within the directory are kept track of by
304*9a747e4fSDavid du Colombier  *	using a directory stack.  See the pushdir/popdir function for
305*9a747e4fSDavid du Colombier  *	more details.
306*9a747e4fSDavid du Colombier  *
307*9a747e4fSDavid du Colombier  * 	The names come from argv, after options or from the standard input.
308*9a747e4fSDavid du Colombier  *
309*9a747e4fSDavid du Colombier  * PARAMETERS
310*9a747e4fSDavid du Colombier  *
311*9a747e4fSDavid du Colombier  *	name - a pointer to a buffer of at least MAX_PATH + 1 bytes long;
312*9a747e4fSDavid du Colombier  *	statbuf - a pointer to a stat structure
313*9a747e4fSDavid du Colombier  *
314*9a747e4fSDavid du Colombier  * RETURNS
315*9a747e4fSDavid du Colombier  *
316*9a747e4fSDavid du Colombier  *	Returns -1 if there are no names left, (e.g. EOF), otherwise returns
317*9a747e4fSDavid du Colombier  *	0
318*9a747e4fSDavid du Colombier  */
319*9a747e4fSDavid du Colombier 
320*9a747e4fSDavid du Colombier #ifdef __STDC__
321*9a747e4fSDavid du Colombier 
name_next(char * name,Stat * statbuf)322*9a747e4fSDavid du Colombier int name_next(char *name, Stat *statbuf)
323*9a747e4fSDavid du Colombier 
324*9a747e4fSDavid du Colombier #else
325*9a747e4fSDavid du Colombier 
326*9a747e4fSDavid du Colombier int name_next(name, statbuf)
327*9a747e4fSDavid du Colombier char           *name;
328*9a747e4fSDavid du Colombier Stat           *statbuf;
329*9a747e4fSDavid du Colombier 
330*9a747e4fSDavid du Colombier #endif
331*9a747e4fSDavid du Colombier {
332*9a747e4fSDavid du Colombier     int             err = -1;
333*9a747e4fSDavid du Colombier     static int      in_subdir = 0;
334*9a747e4fSDavid du Colombier     static DIR     *dirp;
335*9a747e4fSDavid du Colombier     struct dirent  *d;
336*9a747e4fSDavid du Colombier     static struct dirinfo *curr_dir;
337*9a747e4fSDavid du Colombier     int			len;
338*9a747e4fSDavid du Colombier 
339*9a747e4fSDavid du Colombier     do {
340*9a747e4fSDavid du Colombier 	if (names_from_stdin) {
341*9a747e4fSDavid du Colombier 	    if (lineget(stdin, name) < 0) {
342*9a747e4fSDavid du Colombier 		return (-1);
343*9a747e4fSDavid du Colombier 	    }
344*9a747e4fSDavid du Colombier 	    if (nameopt(name) < 0) {
345*9a747e4fSDavid du Colombier 		continue;
346*9a747e4fSDavid du Colombier 	    }
347*9a747e4fSDavid du Colombier 	} else {
348*9a747e4fSDavid du Colombier 	    if (in_subdir) {
349*9a747e4fSDavid du Colombier 		if ((d = readdir(dirp)) != (struct dirent *)NULL) {
350*9a747e4fSDavid du Colombier 		    /* Skip . and .. */
351*9a747e4fSDavid du Colombier 		    if (strcmp(d->d_name, ".") == 0 ||
352*9a747e4fSDavid du Colombier 		        strcmp(d->d_name, "..") == 0) {
353*9a747e4fSDavid du Colombier 			    continue;
354*9a747e4fSDavid du Colombier 		    }
355*9a747e4fSDavid du Colombier 		    if (strlen(d->d_name) +
356*9a747e4fSDavid du Colombier 			strlen(curr_dir->dirname) >= PATH_MAX) {
357*9a747e4fSDavid du Colombier 			warn("name too long", d->d_name);
358*9a747e4fSDavid du Colombier 			continue;
359*9a747e4fSDavid du Colombier 		    }
360*9a747e4fSDavid du Colombier 		    strcpy(name, curr_dir->dirname);
361*9a747e4fSDavid du Colombier 		    strcat(name, d->d_name);
362*9a747e4fSDavid du Colombier 		} else {
363*9a747e4fSDavid du Colombier 		    closedir(dirp);
364*9a747e4fSDavid du Colombier 		    in_subdir--;
365*9a747e4fSDavid du Colombier 		    curr_dir = popdir();
366*9a747e4fSDavid du Colombier 		    if (in_subdir) {
367*9a747e4fSDavid du Colombier 			errno = 0;
368*9a747e4fSDavid du Colombier 			if ((dirp=opendir(curr_dir->dirname)) == (DIR *)NULL) {
369*9a747e4fSDavid du Colombier 			    warn(curr_dir->dirname, "error opening directory (1)");
370*9a747e4fSDavid du Colombier 			    in_subdir--;
371*9a747e4fSDavid du Colombier 			}
372*9a747e4fSDavid du Colombier 			seekdir(dirp, curr_dir->where);
373*9a747e4fSDavid du Colombier 		    }
374*9a747e4fSDavid du Colombier 		    continue;
375*9a747e4fSDavid du Colombier 		}
376*9a747e4fSDavid du Colombier 	    } else if (optind >= n_argc) {
377*9a747e4fSDavid du Colombier 		return (-1);
378*9a747e4fSDavid du Colombier 	    } else {
379*9a747e4fSDavid du Colombier 		strcpy(name, n_argv[optind++]);
380*9a747e4fSDavid du Colombier 	    }
381*9a747e4fSDavid du Colombier 	}
382*9a747e4fSDavid du Colombier 	if ((err = LSTAT(name, statbuf)) < 0) {
383*9a747e4fSDavid du Colombier 	    warn(name, strerror());
384*9a747e4fSDavid du Colombier 	    continue;
385*9a747e4fSDavid du Colombier 	}
386*9a747e4fSDavid du Colombier 	if (!names_from_stdin && (statbuf->sb_mode & S_IFMT) == S_IFDIR) {
387*9a747e4fSDavid du Colombier 	    if (in_subdir) {
388*9a747e4fSDavid du Colombier 		curr_dir->where = telldir(dirp);
389*9a747e4fSDavid du Colombier 		pushdir(curr_dir);
390*9a747e4fSDavid du Colombier 		closedir(dirp);
391*9a747e4fSDavid du Colombier 	    }
392*9a747e4fSDavid du Colombier 	    in_subdir++;
393*9a747e4fSDavid du Colombier 
394*9a747e4fSDavid du Colombier 	    /* Build new prototype name */
395*9a747e4fSDavid du Colombier 	    if ((curr_dir = (struct dirinfo *) mem_get(sizeof(struct dirinfo)))
396*9a747e4fSDavid du Colombier 			  == (struct dirinfo *)NULL) {
397*9a747e4fSDavid du Colombier 		exit(2);
398*9a747e4fSDavid du Colombier 	    }
399*9a747e4fSDavid du Colombier 	    strcpy(curr_dir->dirname, name);
400*9a747e4fSDavid du Colombier 	    len = strlen(curr_dir->dirname);
401*9a747e4fSDavid du Colombier 	    while (len >= 1 && curr_dir->dirname[len - 1] == '/') {
402*9a747e4fSDavid du Colombier 		len--;		/* Delete trailing slashes */
403*9a747e4fSDavid du Colombier 	    }
404*9a747e4fSDavid du Colombier 	    curr_dir->dirname[len++] = '/';	/* Now add exactly one back */
405*9a747e4fSDavid du Colombier 	    curr_dir->dirname[len] = '\0';/* Make sure null-terminated */
406*9a747e4fSDavid du Colombier             curr_dir->where = 0;
407*9a747e4fSDavid du Colombier 
408*9a747e4fSDavid du Colombier             errno = 0;
409*9a747e4fSDavid du Colombier             do {
410*9a747e4fSDavid du Colombier                 if ((dirp = opendir(curr_dir->dirname)) == (DIR *)NULL) {
411*9a747e4fSDavid du Colombier                      warn(curr_dir->dirname, "error opening directory (2)");
412*9a747e4fSDavid du Colombier                      if (in_subdir > 1) {
413*9a747e4fSDavid du Colombier                           curr_dir = popdir();
414*9a747e4fSDavid du Colombier                      }
415*9a747e4fSDavid du Colombier                      in_subdir--;
416*9a747e4fSDavid du Colombier                      err = -1;
417*9a747e4fSDavid du Colombier                      continue;
418*9a747e4fSDavid du Colombier                 } else {
419*9a747e4fSDavid du Colombier                      seekdir(dirp, curr_dir->where);
420*9a747e4fSDavid du Colombier 		}
421*9a747e4fSDavid du Colombier 	    } while (in_subdir && (! dirp));
422*9a747e4fSDavid du Colombier 	}
423*9a747e4fSDavid du Colombier     } while (err < 0);
424*9a747e4fSDavid du Colombier     return (0);
425*9a747e4fSDavid du Colombier }
426*9a747e4fSDavid du Colombier 
427*9a747e4fSDavid du Colombier 
428*9a747e4fSDavid du Colombier /* name_gather - gather names in a list for scanning.
429*9a747e4fSDavid du Colombier  *
430*9a747e4fSDavid du Colombier  * DESCRIPTION
431*9a747e4fSDavid du Colombier  *
432*9a747e4fSDavid du Colombier  *	Name_gather takes names from the command line and adds them to
433*9a747e4fSDavid du Colombier  *	the name list.
434*9a747e4fSDavid du Colombier  *
435*9a747e4fSDavid du Colombier  * FIXME
436*9a747e4fSDavid du Colombier  *
437*9a747e4fSDavid du Colombier  * 	We could hash the names if we really care about speed here.
438*9a747e4fSDavid du Colombier  */
439*9a747e4fSDavid du Colombier 
440*9a747e4fSDavid du Colombier #ifdef __STDC__
441*9a747e4fSDavid du Colombier 
name_gather(void)442*9a747e4fSDavid du Colombier void name_gather(void)
443*9a747e4fSDavid du Colombier 
444*9a747e4fSDavid du Colombier #else
445*9a747e4fSDavid du Colombier 
446*9a747e4fSDavid du Colombier void name_gather()
447*9a747e4fSDavid du Colombier 
448*9a747e4fSDavid du Colombier #endif
449*9a747e4fSDavid du Colombier {
450*9a747e4fSDavid du Colombier      while (optind < n_argc) {
451*9a747e4fSDavid du Colombier 	 add_name(n_argv[optind++]);
452*9a747e4fSDavid du Colombier      }
453*9a747e4fSDavid du Colombier }
454*9a747e4fSDavid du Colombier 
455*9a747e4fSDavid du Colombier 
456*9a747e4fSDavid du Colombier /* pushdir - pushes a directory name on the directory stack
457*9a747e4fSDavid du Colombier  *
458*9a747e4fSDavid du Colombier  * DESCRIPTION
459*9a747e4fSDavid du Colombier  *
460*9a747e4fSDavid du Colombier  *	The pushdir function puses the directory structure which is pointed
461*9a747e4fSDavid du Colombier  *	to by "info" onto a stack for later processing.  The information
462*9a747e4fSDavid du Colombier  *	may be retrieved later with a call to popdir().
463*9a747e4fSDavid du Colombier  *
464*9a747e4fSDavid du Colombier  * PARAMETERS
465*9a747e4fSDavid du Colombier  *
466*9a747e4fSDavid du Colombier  *	dirinfo	*info	- pointer to directory structure to save
467*9a747e4fSDavid du Colombier  */
468*9a747e4fSDavid du Colombier 
469*9a747e4fSDavid du Colombier #ifdef __STDC__
470*9a747e4fSDavid du Colombier 
pushdir(struct dirinfo * info)471*9a747e4fSDavid du Colombier static void pushdir(struct dirinfo *info)
472*9a747e4fSDavid du Colombier 
473*9a747e4fSDavid du Colombier #else
474*9a747e4fSDavid du Colombier 
475*9a747e4fSDavid du Colombier static void pushdir(info)
476*9a747e4fSDavid du Colombier struct dirinfo	*info;
477*9a747e4fSDavid du Colombier 
478*9a747e4fSDavid du Colombier #endif
479*9a747e4fSDavid du Colombier {
480*9a747e4fSDavid du Colombier     if  (stack_head == (struct dirinfo *)NULL) {
481*9a747e4fSDavid du Colombier 	stack_head = info;
482*9a747e4fSDavid du Colombier 	stack_head->next = (struct dirinfo *)NULL;
483*9a747e4fSDavid du Colombier     } else {
484*9a747e4fSDavid du Colombier 	info->next = stack_head;
485*9a747e4fSDavid du Colombier 	stack_head = info;
486*9a747e4fSDavid du Colombier     }
487*9a747e4fSDavid du Colombier }
488*9a747e4fSDavid du Colombier 
489*9a747e4fSDavid du Colombier 
490*9a747e4fSDavid du Colombier /* popdir - pop a directory structure off the directory stack.
491*9a747e4fSDavid du Colombier  *
492*9a747e4fSDavid du Colombier  * DESCRIPTION
493*9a747e4fSDavid du Colombier  *
494*9a747e4fSDavid du Colombier  *	The popdir function pops the most recently pushed directory
495*9a747e4fSDavid du Colombier  *	structure off of the directory stack and returns it to the calling
496*9a747e4fSDavid du Colombier  *	function.
497*9a747e4fSDavid du Colombier  *
498*9a747e4fSDavid du Colombier  * RETURNS
499*9a747e4fSDavid du Colombier  *
500*9a747e4fSDavid du Colombier  *	Returns a pointer to the most recently pushed directory structure
501*9a747e4fSDavid du Colombier  *	or NULL if the stack is empty.
502*9a747e4fSDavid du Colombier  */
503*9a747e4fSDavid du Colombier 
504*9a747e4fSDavid du Colombier #ifdef __STDC__
505*9a747e4fSDavid du Colombier 
popdir(void)506*9a747e4fSDavid du Colombier static struct dirinfo *popdir(void)
507*9a747e4fSDavid du Colombier 
508*9a747e4fSDavid du Colombier #else
509*9a747e4fSDavid du Colombier 
510*9a747e4fSDavid du Colombier static struct dirinfo *popdir()
511*9a747e4fSDavid du Colombier 
512*9a747e4fSDavid du Colombier #endif
513*9a747e4fSDavid du Colombier {
514*9a747e4fSDavid du Colombier     struct dirinfo	*tmp;
515*9a747e4fSDavid du Colombier 
516*9a747e4fSDavid du Colombier     if (stack_head == (struct dirinfo *)NULL) {
517*9a747e4fSDavid du Colombier 	return((struct dirinfo *)NULL);
518*9a747e4fSDavid du Colombier     } else {
519*9a747e4fSDavid du Colombier 	tmp = stack_head;
520*9a747e4fSDavid du Colombier 	stack_head = stack_head->next;
521*9a747e4fSDavid du Colombier     }
522*9a747e4fSDavid du Colombier     return(tmp);
523*9a747e4fSDavid du Colombier }
524