]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - gnu/usr.bin/cvs/cvs/recurse.c
This is the Linux generic soundcard driver, version 1.0c. Supports
[FreeBSD/FreeBSD.git] / gnu / usr.bin / cvs / cvs / recurse.c
1 /*
2  * Copyright (c) 1992, Brian Berliner and Jeff Polk
3  * 
4  * You may distribute under the terms of the GNU General Public License as
5  * specified in the README file that comes with the CVS 1.3 kit.
6  * 
7  * General recursion handler
8  * 
9  */
10
11 #include "cvs.h"
12
13 #ifndef lint
14 static char rcsid[] = "@(#)recurse.c 1.22 92/04/10";
15 #endif
16
17 #if __STDC__
18 static int do_dir_proc (Node * p);
19 static int do_file_proc (Node * p);
20 static void addlist (List ** listp, char *key);
21 #else
22 static int do_file_proc ();
23 static int do_dir_proc ();
24 static void addlist ();
25 #endif                          /* __STDC__ */
26
27
28 /*
29  * Local static versions eliminates the need for globals
30  */
31 static int (*fileproc) ();
32 static int (*filesdoneproc) ();
33 static Dtype (*direntproc) ();
34 static int (*dirleaveproc) ();
35 static int which;
36 static Dtype flags;
37 static int aflag;
38 static int readlock;
39 static int dosrcs;
40 static char update_dir[PATH_MAX];
41 static char *repository = NULL;
42 static List *entries = NULL;
43 static List *srcfiles = NULL;
44 static List *filelist = NULL;
45 static List *dirlist = NULL;
46
47 /*
48  * Called to start a recursive command Command line arguments are processed
49  * if present, otherwise the local directory is processed.
50  */
51 int
52 start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc,
53                  argc, argv, local, which, aflag, readlock,
54                  update_preload, dosrcs)
55     int (*fileproc) ();
56     int (*filesdoneproc) ();
57     Dtype (*direntproc) ();
58     int (*dirleaveproc) ();
59     int argc;
60     char *argv[];
61     int local;
62     int which;
63     int aflag;
64     int readlock;
65     char *update_preload;
66     int dosrcs;
67 {
68     int i, err = 0;
69     Dtype flags;
70
71     if (update_preload == NULL)
72         update_dir[0] = '\0';
73     else
74         (void) strcpy (update_dir, update_preload);
75
76     if (local)
77         flags = R_SKIP_DIRS;
78     else
79         flags = R_PROCESS;
80
81     /* clean up from any previous calls to start_recursion */
82     if (repository)
83     {
84         free (repository);
85         repository = (char *) NULL;
86     }
87     if (entries)
88         dellist (&entries);
89     if (srcfiles)
90         dellist (&srcfiles);
91     if (filelist)
92         dellist (&filelist);
93     if (dirlist)
94         dellist (&dirlist);
95
96     if (argc == 0)
97     {
98
99         /*
100          * There were no arguments, so we'll probably just recurse. The
101          * exception to the rule is when we are called from a directory
102          * without any CVS administration files.  That has always meant to
103          * process each of the sub-directories, so we pretend like we were
104          * called with the list of sub-dirs of the current dir as args
105          */
106         if ((which & W_LOCAL) && !isdir (CVSADM) && !isdir (OCVSADM))
107             dirlist = Find_Dirs ((char *) NULL, W_LOCAL);
108         else
109             addlist (&dirlist, ".");
110
111         err += do_recursion (fileproc, filesdoneproc, direntproc,
112                             dirleaveproc, flags, which, aflag,
113                             readlock, dosrcs);
114     }
115     else
116     {
117
118         /*
119          * There were arguments, so we have to handle them by hand. To do
120          * that, we set up the filelist and dirlist with the arguments and
121          * call do_recursion.  do_recursion recognizes the fact that the
122          * lists are non-null when it starts and doesn't update them
123          */
124
125         /* look for args with /-s in them */
126         for (i = 0; i < argc; i++)
127             if (index (argv[i], '/') != NULL)
128                 break;
129
130         /* if we didn't find any hard one's, do it the easy way */
131         if (i == argc)
132         {
133             /* set up the lists */
134             for (i = 0; i < argc; i++)
135             {
136                 if (isdir (argv[i]))
137                     addlist (&dirlist, argv[i]);
138                 else
139                 {
140                     if (isdir (CVSADM) || isdir (OCVSADM))
141                     {
142                         char *repos;
143                         char tmp[PATH_MAX];
144
145                         repos = Name_Repository ((char *) NULL, update_dir);
146                         (void) sprintf (tmp, "%s/%s", repos, argv[i]);
147                         if (isdir (tmp))
148                             addlist (&dirlist, argv[i]);
149                         else
150                             addlist (&filelist, argv[i]);
151                         free (repos);
152                     }
153                     else
154                         addlist (&filelist, argv[i]);
155                 }
156             }
157
158             /* we aren't recursive if no directories were specified */
159             if (dirlist == NULL)
160                 local = 1;
161
162             /* process the lists */
163             err += do_recursion (fileproc, filesdoneproc, direntproc,
164                                 dirleaveproc, flags, which, aflag,
165                                 readlock, dosrcs);
166         }
167         /* otherwise - do it the hard way */
168         else
169         {
170             char *cp;
171             char *dir = (char *) NULL;
172             char *comp = (char *) NULL;
173             char *oldupdate = (char *) NULL;
174             char savewd[PATH_MAX];
175
176             if (getwd (savewd) == NULL)
177                 error (1, 0, "could not get working directory: %s", savewd);
178
179             for (i = 0; i < argc; i++)
180             {
181                 /* split the arg into the dir and component parts */
182                 dir = xstrdup (argv[i]);
183                 if ((cp = rindex (dir, '/')) != NULL)
184                 {
185                     *cp = '\0';
186                     comp = xstrdup (cp + 1);
187                     oldupdate = xstrdup (update_dir);
188                     if (update_dir[0] != '\0')
189                         (void) strcat (update_dir, "/");
190                     (void) strcat (update_dir, dir);
191                 }
192                 else
193                 {
194                     comp = xstrdup (dir);
195                     if (dir)
196                         free (dir);
197                     dir = (char *) NULL;
198                 }
199
200                 /* chdir to the appropriate place if necessary */
201                 if (dir && chdir (dir) < 0)
202                     error (1, errno, "could not chdir to %s", dir);
203
204                 /* set up the list */
205                 if (isdir (comp))
206                     addlist (&dirlist, comp);
207                 else
208                 {
209                     if (isdir (CVSADM) || isdir (OCVSADM))
210                     {
211                         char *repos;
212                         char tmp[PATH_MAX];
213
214                         repos = Name_Repository ((char *) NULL, update_dir);
215                         (void) sprintf (tmp, "%s/%s", repos, comp);
216                         if (isdir (tmp))
217                             addlist (&dirlist, comp);
218                         else
219                             addlist (&filelist, comp);
220                         free (repos);
221                     }
222                     else
223                         addlist (&filelist, comp);
224                 }
225
226                 /* do the recursion */
227                 err += do_recursion (fileproc, filesdoneproc, direntproc,
228                                     dirleaveproc, flags, which,
229                                     aflag, readlock, dosrcs);
230
231                 /* chdir back and fix update_dir if necessary */
232                 if (dir && chdir (savewd) < 0)
233                     error (1, errno, "could not chdir to %s", dir);
234                 if (oldupdate)
235                 {
236                     (void) strcpy (update_dir, oldupdate);
237                     free (oldupdate);
238                 }
239
240             }
241             if (dir)
242                 free (dir);
243             if (comp)
244                 free (comp);
245         }
246     }
247     return (err);
248 }
249
250 /*
251  * Implement the recursive policies on the local directory.  This may be
252  * called directly, or may be called by start_recursion
253  */
254 int
255 do_recursion (xfileproc, xfilesdoneproc, xdirentproc, xdirleaveproc,
256               xflags, xwhich, xaflag, xreadlock, xdosrcs)
257     int (*xfileproc) ();
258     int (*xfilesdoneproc) ();
259     Dtype (*xdirentproc) ();
260     int (*xdirleaveproc) ();
261     Dtype xflags;
262     int xwhich;
263     int xaflag;
264     int xreadlock;
265     int xdosrcs;
266 {
267     int err = 0;
268     int dodoneproc = 1;
269     char *srepository;
270
271     /* do nothing if told */
272     if (xflags == R_SKIP_ALL)
273         return (0);
274
275     /* set up the static vars */
276     fileproc = xfileproc;
277     filesdoneproc = xfilesdoneproc;
278     direntproc = xdirentproc;
279     dirleaveproc = xdirleaveproc;
280     flags = xflags;
281     which = xwhich;
282     aflag = xaflag;
283     readlock = noexec ? 0 : xreadlock;
284     dosrcs = xdosrcs;
285
286     /*
287      * Fill in repository with the current repository
288      */
289     if (which & W_LOCAL)
290     {
291         if (isdir (CVSADM) || isdir (OCVSADM))
292             repository = Name_Repository ((char *) NULL, update_dir);
293         else
294             repository = NULL;
295     }
296     else
297     {
298         repository = xmalloc (PATH_MAX);
299         (void) getwd (repository);
300     }
301     srepository = repository;           /* remember what to free */
302
303     /*
304      * The filesdoneproc needs to be called for each directory where files
305      * processed, or each directory that is processed by a call where no
306      * directories were passed in.  In fact, the only time we don't want to
307      * call back the filesdoneproc is when we are processing directories that
308      * were passed in on the command line (or in the special case of `.' when
309      * we were called with no args
310      */
311     if (dirlist != NULL && filelist == NULL)
312         dodoneproc = 0;
313
314     /*
315      * If filelist or dirlist is already set, we don't look again. Otherwise,
316      * find the files and directories
317      */
318     if (filelist == NULL && dirlist == NULL)
319     {
320         /* both lists were NULL, so start from scratch */
321         if (fileproc != NULL && flags != R_SKIP_FILES)
322         {
323             int lwhich = which;
324
325             /* be sure to look in the attic if we have sticky tags/date */
326             if ((lwhich & W_ATTIC) == 0)
327                 if (isreadable (CVSADM_TAG))
328                     lwhich |= W_ATTIC;
329
330             /* find the files and fill in entries if appropriate */
331             filelist = Find_Names (repository, lwhich, aflag, &entries);
332         }
333
334         /* find sub-directories if we will recurse */
335         if (flags != R_SKIP_DIRS)
336             dirlist = Find_Dirs (repository, which);
337     }
338     else
339     {
340         /* something was passed on the command line */
341         if (filelist != NULL && fileproc != NULL)
342         {
343             /* we will process files, so pre-parse entries */
344             if (which & W_LOCAL)
345                 entries = ParseEntries (aflag);
346         }
347     }
348
349     /* process the files (if any) */
350     if (filelist != NULL)
351     {
352         /* read lock it if necessary */
353         if (readlock && repository && Reader_Lock (repository) != 0)
354             error (1, 0, "read lock failed - giving up");
355
356         /* pre-parse the source files */
357         if (dosrcs && repository)
358             srcfiles = RCS_parsefiles (filelist, repository);
359         else
360             srcfiles = (List *) NULL;
361
362         /* process the files */
363         err += walklist (filelist, do_file_proc);
364
365         /* unlock it */
366         if (readlock)
367             Lock_Cleanup ();
368
369         /* clean up */
370         dellist (&filelist);
371         dellist (&srcfiles);
372         dellist (&entries);
373     }
374
375     /* call-back files done proc (if any) */
376     if (dodoneproc && filesdoneproc != NULL)
377         err = filesdoneproc (err, repository, update_dir[0] ? update_dir : ".");
378
379     /* process the directories (if necessary) */
380     if (dirlist != NULL)
381         err += walklist (dirlist, do_dir_proc);
382 #ifdef notdef
383     else if (dirleaveproc != NULL)
384         err += dirleaveproc(".", err, ".");
385 #endif
386     dellist (&dirlist);
387
388     /* free the saved copy of the pointer if necessary */
389     if (srepository)
390     {
391         (void) free (srepository);
392         repository = (char *) NULL;
393     }
394
395     return (err);
396 }
397
398 /*
399  * Process each of the files in the list with the callback proc
400  */
401 static int
402 do_file_proc (p)
403     Node *p;
404 {
405     if (fileproc != NULL)
406         return (fileproc (p->key, update_dir, repository, entries, srcfiles));
407     else
408         return (0);
409 }
410
411 /*
412  * Process each of the directories in the list (recursing as we go)
413  */
414 static int
415 do_dir_proc (p)
416     Node *p;
417 {
418     char *dir = p->key;
419     char savewd[PATH_MAX];
420     char newrepos[PATH_MAX];
421     List *sdirlist;
422     char *srepository;
423     char *cp;
424     Dtype dir_return = R_PROCESS;
425     int stripped_dot = 0;
426     int err = 0;
427
428     /* set up update_dir - skip dots if not at start */
429     if (strcmp (dir, ".") != 0)
430     {
431         if (update_dir[0] != '\0')
432         {
433             (void) strcat (update_dir, "/");
434             (void) strcat (update_dir, dir);
435         }
436         else
437             (void) strcpy (update_dir, dir);
438
439         /*
440          * Here we need a plausible repository name for the sub-directory. We
441          * create one by concatenating the new directory name onto the
442          * previous repository name.  The only case where the name should be
443          * used is in the case where we are creating a new sub-directory for
444          * update -d and in that case the generated name will be correct.
445          */
446         if (repository == NULL)
447             newrepos[0] = '\0';
448         else
449             (void) sprintf (newrepos, "%s/%s", repository, dir);
450     }
451     else
452     {
453         if (update_dir[0] == '\0')
454             (void) strcpy (update_dir, dir);
455
456         if (repository == NULL)
457             newrepos[0] = '\0';
458         else
459             (void) strcpy (newrepos, repository);
460     }
461
462     /* call-back dir entry proc (if any) */
463     if (direntproc != NULL)
464         dir_return = direntproc (dir, newrepos, update_dir);
465
466     /* only process the dir if the return code was 0 */
467     if (dir_return != R_SKIP_ALL)
468     {
469         /* save our current directory and static vars */
470         if (getwd (savewd) == NULL)
471             error (1, 0, "could not get working directory: %s", savewd);
472         sdirlist = dirlist;
473         srepository = repository;
474         dirlist = NULL;
475
476         /* cd to the sub-directory */
477         if (chdir (dir) < 0)
478             error (1, errno, "could not chdir to %s", dir);
479
480         /* honor the global SKIP_DIRS (a.k.a. local) */
481         if (flags == R_SKIP_DIRS)
482             dir_return = R_SKIP_DIRS;
483
484         /* remember if the `.' will be stripped for subsequent dirs */
485         if (strcmp (update_dir, ".") == 0)
486         {
487             update_dir[0] = '\0';
488             stripped_dot = 1;
489         }
490
491         /* make the recursive call */
492         err += do_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc,
493                             dir_return, which, aflag, readlock, dosrcs);
494
495         /* put the `.' back if necessary */
496         if (stripped_dot)
497             (void) strcpy (update_dir, ".");
498
499         /* call-back dir leave proc (if any) */
500         if (dirleaveproc != NULL)
501             err = dirleaveproc (dir, err, update_dir);
502
503         /* get back to where we started and restore state vars */
504         if (chdir (savewd) < 0)
505             error (1, errno, "could not chdir to %s", savewd);
506         dirlist = sdirlist;
507         repository = srepository;
508     }
509
510     /* put back update_dir */
511     if ((cp = rindex (update_dir, '/')) != NULL)
512         *cp = '\0';
513     else
514         update_dir[0] = '\0';
515
516     return (err);
517 }
518
519 /*
520  * Add a node to a list allocating the list if necessary
521  */
522 static void
523 addlist (listp, key)
524     List **listp;
525     char *key;
526 {
527     Node *p;
528
529     if (*listp == NULL)
530         *listp = getlist ();
531     p = getnode ();
532     p->type = FILES;
533     p->key = xstrdup (key);
534     (void) addnode (*listp, p);
535 }