* Copyright (c) 1992, Brian Berliner and Jeff Polk
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
* General recursion handler
static char rcsid
[] = "@(#)recurse.c 1.22 92/04/10";
static int do_dir_proc (Node
* p
);
static int do_file_proc (Node
* p
);
static void addlist (List
** listp
, char *key
);
static int do_file_proc ();
static int do_dir_proc ();
* Local static versions eliminates the need for globals
static int (*fileproc
) ();
static int (*filesdoneproc
) ();
static Dtype (*direntproc
) ();
static int (*dirleaveproc
) ();
static char update_dir
[PATH_MAX
];
static char *repository
= NULL
;
static List
*entries
= NULL
;
static List
*srcfiles
= NULL
;
static List
*filelist
= NULL
;
static List
*dirlist
= NULL
;
* Called to start a recursive command Command line arguments are processed
* if present, otherwise the local directory is processed.
start_recursion (fileproc
, filesdoneproc
, direntproc
, dirleaveproc
,
argc
, argv
, local
, which
, aflag
, readlock
,
if (update_preload
== NULL
)
(void) strcpy (update_dir
, update_preload
);
/* clean up from any previous calls to start_recursion */
repository
= (char *) NULL
;
* There were no arguments, so we'll probably just recurse. The
* exception to the rule is when we are called from a directory
* without any CVS administration files. That has always meant to
* process each of the sub-directories, so we pretend like we were
* called with the list of sub-dirs of the current dir as args
if ((which
& W_LOCAL
) && !isdir (CVSADM
) && !isdir (OCVSADM
))
dirlist
= Find_Dirs ((char *) NULL
, W_LOCAL
);
err
+= do_recursion (fileproc
, filesdoneproc
, direntproc
,
dirleaveproc
, flags
, which
, aflag
,
* There were arguments, so we have to handle them by hand. To do
* that, we set up the filelist and dirlist with the arguments and
* call do_recursion. do_recursion recognizes the fact that the
* lists are non-null when it starts and doesn't update them
/* look for args with /-s in them */
for (i
= 0; i
< argc
; i
++)
if (index (argv
[i
], '/') != NULL
)
/* if we didn't find any hard one's, do it the easy way */
for (i
= 0; i
< argc
; i
++)
addlist (&dirlist
, argv
[i
]);
if (isdir (CVSADM
) || isdir (OCVSADM
))
repos
= Name_Repository ((char *) NULL
, update_dir
);
(void) sprintf (tmp
, "%s/%s", repos
, argv
[i
]);
addlist (&dirlist
, argv
[i
]);
addlist (&filelist
, argv
[i
]);
addlist (&filelist
, argv
[i
]);
/* we aren't recursive if no directories were specified */
err
+= do_recursion (fileproc
, filesdoneproc
, direntproc
,
dirleaveproc
, flags
, which
, aflag
,
/* otherwise - do it the hard way */
char *dir
= (char *) NULL
;
char *comp
= (char *) NULL
;
char *oldupdate
= (char *) NULL
;
if (getwd (savewd
) == NULL
)
error (1, 0, "could not get working directory: %s", savewd
);
for (i
= 0; i
< argc
; i
++)
/* split the arg into the dir and component parts */
if ((cp
= rindex (dir
, '/')) != NULL
)
oldupdate
= xstrdup (update_dir
);
if (update_dir
[0] != '\0')
(void) strcat (update_dir
, "/");
(void) strcat (update_dir
, dir
);
/* chdir to the appropriate place if necessary */
if (dir
&& chdir (dir
) < 0)
error (1, errno
, "could not chdir to %s", dir
);
addlist (&dirlist
, comp
);
if (isdir (CVSADM
) || isdir (OCVSADM
))
repos
= Name_Repository ((char *) NULL
, update_dir
);
(void) sprintf (tmp
, "%s/%s", repos
, comp
);
addlist (&dirlist
, comp
);
addlist (&filelist
, comp
);
addlist (&filelist
, comp
);
err
+= do_recursion (fileproc
, filesdoneproc
, direntproc
,
dirleaveproc
, flags
, which
,
aflag
, readlock
, dosrcs
);
/* chdir back and fix update_dir if necessary */
if (dir
&& chdir (savewd
) < 0)
error (1, errno
, "could not chdir to %s", dir
);
(void) strcpy (update_dir
, oldupdate
);
* Implement the recursive policies on the local directory. This may be
* called directly, or may be called by start_recursion
do_recursion (xfileproc
, xfilesdoneproc
, xdirentproc
, xdirleaveproc
,
xflags
, xwhich
, xaflag
, xreadlock
, xdosrcs
)
int (*xfilesdoneproc
) ();
if (xflags
== R_SKIP_ALL
)
/* set up the static vars */
filesdoneproc
= xfilesdoneproc
;
direntproc
= xdirentproc
;
dirleaveproc
= xdirleaveproc
;
readlock
= noexec
? 0 : xreadlock
;
* Fill in repository with the current repository
if (isdir (CVSADM
) || isdir (OCVSADM
))
repository
= Name_Repository ((char *) NULL
, update_dir
);
repository
= xmalloc (PATH_MAX
);
(void) getwd (repository
);
srepository
= repository
; /* remember what to free */
* The filesdoneproc needs to be called for each directory where files
* processed, or each directory that is processed by a call where no
* directories were passed in. In fact, the only time we don't want to
* call back the filesdoneproc is when we are processing directories that
* were passed in on the command line (or in the special case of `.' when
* we were called with no args
if (dirlist
!= NULL
&& filelist
== NULL
)
* If filelist or dirlist is already set, we don't look again. Otherwise,
* find the files and directories
if (filelist
== NULL
&& dirlist
== NULL
)
/* both lists were NULL, so start from scratch */
if (fileproc
!= NULL
&& flags
!= R_SKIP_FILES
)
/* be sure to look in the attic if we have sticky tags/date */
if ((lwhich
& W_ATTIC
) == 0)
if (isreadable (CVSADM_TAG
))
/* find the files and fill in entries if appropriate */
filelist
= Find_Names (repository
, lwhich
, aflag
, &entries
);
/* find sub-directories if we will recurse */
if (flags
!= R_SKIP_DIRS
)
dirlist
= Find_Dirs (repository
, which
);
/* something was passed on the command line */
if (filelist
!= NULL
&& fileproc
!= NULL
)
/* we will process files, so pre-parse entries */
entries
= ParseEntries (aflag
);
/* process the files (if any) */
/* read lock it if necessary */
if (readlock
&& repository
&& Reader_Lock (repository
) != 0)
error (1, 0, "read lock failed - giving up");
/* pre-parse the source files */
if (dosrcs
&& repository
)
srcfiles
= RCS_parsefiles (filelist
, repository
);
srcfiles
= (List
*) NULL
;
err
+= walklist (filelist
, do_file_proc
);
/* call-back files done proc (if any) */
if (dodoneproc
&& filesdoneproc
!= NULL
)
err
= filesdoneproc (err
, repository
, update_dir
[0] ? update_dir
: ".");
/* process the directories (if necessary) */
err
+= walklist (dirlist
, do_dir_proc
);
else if (dirleaveproc
!= NULL
)
err
+= dirleaveproc(".", err
, ".");
/* free the saved copy of the pointer if necessary */
(void) free (srepository
);
repository
= (char *) NULL
;
* Process each of the files in the list with the callback proc
return (fileproc (p
->key
, update_dir
, repository
, entries
, srcfiles
));
* Process each of the directories in the list (recursing as we go)
Dtype dir_return
= R_PROCESS
;
/* set up update_dir - skip dots if not at start */
if (strcmp (dir
, ".") != 0)
if (update_dir
[0] != '\0')
(void) strcat (update_dir
, "/");
(void) strcat (update_dir
, dir
);
(void) strcpy (update_dir
, dir
);
* Here we need a plausible repository name for the sub-directory. We
* create one by concatenating the new directory name onto the
* previous repository name. The only case where the name should be
* used is in the case where we are creating a new sub-directory for
* update -d and in that case the generated name will be correct.
(void) sprintf (newrepos
, "%s/%s", repository
, dir
);
if (update_dir
[0] == '\0')
(void) strcpy (update_dir
, dir
);
(void) strcpy (newrepos
, repository
);
/* call-back dir entry proc (if any) */
dir_return
= direntproc (dir
, newrepos
, update_dir
);
/* only process the dir if the return code was 0 */
if (dir_return
!= R_SKIP_ALL
)
/* save our current directory and static vars */
if (getwd (savewd
) == NULL
)
error (1, 0, "could not get working directory: %s", savewd
);
srepository
= repository
;
/* cd to the sub-directory */
error (1, errno
, "could not chdir to %s", dir
);
/* honor the global SKIP_DIRS (a.k.a. local) */
if (flags
== R_SKIP_DIRS
)
dir_return
= R_SKIP_DIRS
;
/* remember if the `.' will be stripped for subsequent dirs */
if (strcmp (update_dir
, ".") == 0)
/* make the recursive call */
err
+= do_recursion (fileproc
, filesdoneproc
, direntproc
, dirleaveproc
,
dir_return
, which
, aflag
, readlock
, dosrcs
);
/* put the `.' back if necessary */
(void) strcpy (update_dir
, ".");
/* call-back dir leave proc (if any) */
if (dirleaveproc
!= NULL
)
err
= dirleaveproc (dir
, err
, update_dir
);
/* get back to where we started and restore state vars */
error (1, errno
, "could not chdir to %s", savewd
);
repository
= srepository
;
/* put back update_dir */
if ((cp
= rindex (update_dir
, '/')) != NULL
)
* Add a node to a list allocating the list if necessary
(void) addnode (*listp
, p
);