xref: /dflybsd-src/contrib/cvs-1.12/src/ignore.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
186d7f5d3SJohn Marino /* This program is free software; you can redistribute it and/or modify
286d7f5d3SJohn Marino    it under the terms of the GNU General Public License as published by
386d7f5d3SJohn Marino    the Free Software Foundation; either version 2, or (at your option)
486d7f5d3SJohn Marino    any later version.
586d7f5d3SJohn Marino 
686d7f5d3SJohn Marino    This program is distributed in the hope that it will be useful,
786d7f5d3SJohn Marino    but WITHOUT ANY WARRANTY; without even the implied warranty of
886d7f5d3SJohn Marino    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
986d7f5d3SJohn Marino    GNU General Public License for more details.  */
1086d7f5d3SJohn Marino 
1186d7f5d3SJohn Marino /*
1286d7f5d3SJohn Marino  * .cvsignore file support contributed by David G. Grubbs <dgg@odi.com>
1386d7f5d3SJohn Marino  */
1486d7f5d3SJohn Marino 
1586d7f5d3SJohn Marino #include "cvs.h"
1686d7f5d3SJohn Marino #include "getline.h"
1786d7f5d3SJohn Marino #include "lstat.h"
1886d7f5d3SJohn Marino 
1986d7f5d3SJohn Marino /*
2086d7f5d3SJohn Marino  * Ignore file section.
2186d7f5d3SJohn Marino  *
2286d7f5d3SJohn Marino  *	"!" may be included any time to reset the list (i.e. ignore nothing);
2386d7f5d3SJohn Marino  *	"*" may be specified to ignore everything.  It stays as the first
2486d7f5d3SJohn Marino  *	    element forever, unless a "!" clears it out.
2586d7f5d3SJohn Marino  */
2686d7f5d3SJohn Marino 
2786d7f5d3SJohn Marino static char **ign_list;			/* List of files to ignore in update
2886d7f5d3SJohn Marino 					 * and import */
2986d7f5d3SJohn Marino static char **s_ign_list = NULL;
3086d7f5d3SJohn Marino static int ign_count;			/* Number of active entries */
3186d7f5d3SJohn Marino static int s_ign_count = 0;
3286d7f5d3SJohn Marino static int ign_size;			/* This many slots available (plus
3386d7f5d3SJohn Marino 					 * one for a NULL) */
3486d7f5d3SJohn Marino static int ign_hold = -1;		/* Index where first "temporary" item
3586d7f5d3SJohn Marino 					 * is held */
3686d7f5d3SJohn Marino 
3786d7f5d3SJohn Marino const char *ign_default = ". .. core RCSLOG tags TAGS RCS SCCS .make.state\
3886d7f5d3SJohn Marino  .nse_depinfo #* .#* cvslog.* ,* CVS CVS.adm .del-* *.a *.olb *.o *.obj\
3986d7f5d3SJohn Marino  *.so *.Z *~ *.old *.elc *.ln *.bak *.BAK *.orig *.rej *.exe _$* *$";
4086d7f5d3SJohn Marino 
4186d7f5d3SJohn Marino #define IGN_GROW 16			/* grow the list by 16 elements at a
4286d7f5d3SJohn Marino 					 * time */
4386d7f5d3SJohn Marino 
4486d7f5d3SJohn Marino /* Nonzero if we have encountered an -I ! directive, which means one should
4586d7f5d3SJohn Marino    no longer ask the server about what is in CVSROOTADM_IGNORE.  */
4686d7f5d3SJohn Marino int ign_inhibit_server;
4786d7f5d3SJohn Marino 
4886d7f5d3SJohn Marino 
4986d7f5d3SJohn Marino 
5086d7f5d3SJohn Marino /*
5186d7f5d3SJohn Marino  * To the "ignore list", add the hard-coded default ignored wildcards above,
5286d7f5d3SJohn Marino  * the wildcards found in $CVSROOT/CVSROOT/cvsignore, the wildcards found in
5386d7f5d3SJohn Marino  * ~/.cvsignore and the wildcards found in the CVSIGNORE environment
5486d7f5d3SJohn Marino  * variable.
5586d7f5d3SJohn Marino  */
5686d7f5d3SJohn Marino void
ign_setup(void)5786d7f5d3SJohn Marino ign_setup (void)
5886d7f5d3SJohn Marino {
5986d7f5d3SJohn Marino     char *home_dir;
6086d7f5d3SJohn Marino     char *tmp;
6186d7f5d3SJohn Marino 
6286d7f5d3SJohn Marino     ign_inhibit_server = 0;
6386d7f5d3SJohn Marino 
6486d7f5d3SJohn Marino     /* Start with default list and special case */
6586d7f5d3SJohn Marino     tmp = xstrdup (ign_default);
6686d7f5d3SJohn Marino     ign_add (tmp, 0);
6786d7f5d3SJohn Marino     free (tmp);
6886d7f5d3SJohn Marino 
6986d7f5d3SJohn Marino     /* The client handles another way, by (after it does its own ignore file
7086d7f5d3SJohn Marino        processing, and only if !ign_inhibit_server), letting the server
7186d7f5d3SJohn Marino        know about the files and letting it decide whether to ignore
7286d7f5d3SJohn Marino        them based on CVSROOOTADM_IGNORE.  */
7386d7f5d3SJohn Marino     if (!current_parsed_root->isremote)
7486d7f5d3SJohn Marino     {
7586d7f5d3SJohn Marino 	char *file = Xasprintf ("%s/%s/%s", current_parsed_root->directory,
7686d7f5d3SJohn Marino 				CVSROOTADM, CVSROOTADM_IGNORE);
7786d7f5d3SJohn Marino 	/* Then add entries found in repository, if it exists */
7886d7f5d3SJohn Marino 	ign_add_file (file, 0);
7986d7f5d3SJohn Marino 	free (file);
8086d7f5d3SJohn Marino     }
8186d7f5d3SJohn Marino 
8286d7f5d3SJohn Marino     /* Then add entries found in home dir, (if user has one) and file exists */
8386d7f5d3SJohn Marino     home_dir = get_homedir ();
8486d7f5d3SJohn Marino     /* If we can't find a home directory, ignore ~/.cvsignore.  This may
8586d7f5d3SJohn Marino        make tracking down problems a bit of a pain, but on the other
8686d7f5d3SJohn Marino        hand it might be obnoxious to complain when CVS will function
8786d7f5d3SJohn Marino        just fine without .cvsignore (and many users won't even know what
8886d7f5d3SJohn Marino        .cvsignore is).  */
8986d7f5d3SJohn Marino     if (home_dir)
9086d7f5d3SJohn Marino     {
9186d7f5d3SJohn Marino 	char *file = strcat_filename_onto_homedir (home_dir, CVSDOTIGNORE);
9286d7f5d3SJohn Marino 	ign_add_file (file, 0);
9386d7f5d3SJohn Marino 	free (file);
9486d7f5d3SJohn Marino     }
9586d7f5d3SJohn Marino 
9686d7f5d3SJohn Marino     /* Then add entries found in CVSIGNORE environment variable. */
9786d7f5d3SJohn Marino     ign_add (getenv (IGNORE_ENV), 0);
9886d7f5d3SJohn Marino 
9986d7f5d3SJohn Marino     /* Later, add ignore entries found in -I arguments */
10086d7f5d3SJohn Marino }
10186d7f5d3SJohn Marino 
10286d7f5d3SJohn Marino 
10386d7f5d3SJohn Marino 
10486d7f5d3SJohn Marino /*
10586d7f5d3SJohn Marino  * Open a file and read lines, feeding each line to a line parser. Arrange
10686d7f5d3SJohn Marino  * for keeping a temporary list of wildcards at the end, if the "hold"
10786d7f5d3SJohn Marino  * argument is set.
10886d7f5d3SJohn Marino  */
10986d7f5d3SJohn Marino void
ign_add_file(char * file,int hold)11086d7f5d3SJohn Marino ign_add_file (char *file, int hold)
11186d7f5d3SJohn Marino {
11286d7f5d3SJohn Marino     FILE *fp;
11386d7f5d3SJohn Marino     char *line = NULL;
11486d7f5d3SJohn Marino     size_t line_allocated = 0;
11586d7f5d3SJohn Marino 
11686d7f5d3SJohn Marino     /* restore the saved list (if any) */
11786d7f5d3SJohn Marino     if (s_ign_list != NULL)
11886d7f5d3SJohn Marino     {
11986d7f5d3SJohn Marino 	int i;
12086d7f5d3SJohn Marino 
12186d7f5d3SJohn Marino 	for (i = 0; i < s_ign_count; i++)
12286d7f5d3SJohn Marino 	    ign_list[i] = s_ign_list[i];
12386d7f5d3SJohn Marino 	ign_count = s_ign_count;
12486d7f5d3SJohn Marino 	ign_list[ign_count] = NULL;
12586d7f5d3SJohn Marino 
12686d7f5d3SJohn Marino 	s_ign_count = 0;
12786d7f5d3SJohn Marino 	free (s_ign_list);
12886d7f5d3SJohn Marino 	s_ign_list = NULL;
12986d7f5d3SJohn Marino     }
13086d7f5d3SJohn Marino 
13186d7f5d3SJohn Marino     /* is this a temporary ignore file? */
13286d7f5d3SJohn Marino     if (hold)
13386d7f5d3SJohn Marino     {
13486d7f5d3SJohn Marino 	/* re-set if we had already done a temporary file */
13586d7f5d3SJohn Marino 	if (ign_hold >= 0)
13686d7f5d3SJohn Marino 	{
13786d7f5d3SJohn Marino 	    int i;
13886d7f5d3SJohn Marino 
13986d7f5d3SJohn Marino 	    for (i = ign_hold; i < ign_count; i++)
14086d7f5d3SJohn Marino 		free (ign_list[i]);
14186d7f5d3SJohn Marino 	    ign_count = ign_hold;
14286d7f5d3SJohn Marino 	    ign_list[ign_count] = NULL;
14386d7f5d3SJohn Marino 	}
14486d7f5d3SJohn Marino 	else
14586d7f5d3SJohn Marino 	{
14686d7f5d3SJohn Marino 	    ign_hold = ign_count;
14786d7f5d3SJohn Marino 	}
14886d7f5d3SJohn Marino     }
14986d7f5d3SJohn Marino 
15086d7f5d3SJohn Marino     /* load the file */
15186d7f5d3SJohn Marino     fp = CVS_FOPEN (file, "r");
15286d7f5d3SJohn Marino     if (fp == NULL)
15386d7f5d3SJohn Marino     {
15486d7f5d3SJohn Marino 	if (! existence_error (errno))
15586d7f5d3SJohn Marino 	    error (0, errno, "cannot open %s", file);
15686d7f5d3SJohn Marino 	return;
15786d7f5d3SJohn Marino     }
15886d7f5d3SJohn Marino     while (getline (&line, &line_allocated, fp) >= 0)
15986d7f5d3SJohn Marino 	ign_add (line, hold);
16086d7f5d3SJohn Marino     if (ferror (fp))
16186d7f5d3SJohn Marino 	error (0, errno, "cannot read %s", file);
16286d7f5d3SJohn Marino     if (fclose (fp) < 0)
16386d7f5d3SJohn Marino 	error (0, errno, "cannot close %s", file);
16486d7f5d3SJohn Marino     free (line);
16586d7f5d3SJohn Marino }
16686d7f5d3SJohn Marino 
16786d7f5d3SJohn Marino 
16886d7f5d3SJohn Marino 
16986d7f5d3SJohn Marino /* Parse a line of space-separated wildcards and add them to the list. */
17086d7f5d3SJohn Marino void
ign_add(char * ign,int hold)17186d7f5d3SJohn Marino ign_add (char *ign, int hold)
17286d7f5d3SJohn Marino {
17386d7f5d3SJohn Marino     if (!ign || !*ign)
17486d7f5d3SJohn Marino 	return;
17586d7f5d3SJohn Marino 
17686d7f5d3SJohn Marino     for (; *ign; ign++)
17786d7f5d3SJohn Marino     {
17886d7f5d3SJohn Marino 	char *mark;
17986d7f5d3SJohn Marino 	char save;
18086d7f5d3SJohn Marino 
18186d7f5d3SJohn Marino 	/* ignore whitespace before the token */
18286d7f5d3SJohn Marino 	if (isspace ((unsigned char) *ign))
18386d7f5d3SJohn Marino 	    continue;
18486d7f5d3SJohn Marino 
18586d7f5d3SJohn Marino 	/* If we have used up all the space, add some more.  Do this before
18686d7f5d3SJohn Marino 	   processing `!', since an "empty" list still contains the `CVS'
18786d7f5d3SJohn Marino 	   entry.  */
18886d7f5d3SJohn Marino 	if (ign_count >= ign_size)
18986d7f5d3SJohn Marino 	{
19086d7f5d3SJohn Marino 	    ign_size += IGN_GROW;
19186d7f5d3SJohn Marino 	    ign_list = xnrealloc (ign_list, ign_size + 1, sizeof (char *));
19286d7f5d3SJohn Marino 	}
19386d7f5d3SJohn Marino 
19486d7f5d3SJohn Marino 	/*
19586d7f5d3SJohn Marino 	 * if we find a single character !, we must re-set the ignore list
19686d7f5d3SJohn Marino 	 * (saving it if necessary).  We also catch * as a special case in a
19786d7f5d3SJohn Marino 	 * global ignore file as an optimization
19886d7f5d3SJohn Marino 	 */
19986d7f5d3SJohn Marino 	if ((!*(ign+1) || isspace ((unsigned char) *(ign+1)))
20086d7f5d3SJohn Marino 	    && (*ign == '!' || *ign == '*'))
20186d7f5d3SJohn Marino 	{
20286d7f5d3SJohn Marino 	    if (!hold)
20386d7f5d3SJohn Marino 	    {
20486d7f5d3SJohn Marino 		/* permanently reset the ignore list */
20586d7f5d3SJohn Marino 		int i;
20686d7f5d3SJohn Marino 
20786d7f5d3SJohn Marino 		for (i = 0; i < ign_count; i++)
20886d7f5d3SJohn Marino 		    free (ign_list[i]);
20986d7f5d3SJohn Marino 		ign_count = 1;
21086d7f5d3SJohn Marino 		/* Always ignore the "CVS" directory.  */
21186d7f5d3SJohn Marino 		ign_list[0] = xstrdup ("CVS");
21286d7f5d3SJohn Marino 		ign_list[1] = NULL;
21386d7f5d3SJohn Marino 
21486d7f5d3SJohn Marino 		/* if we are doing a '!', continue; otherwise add the '*' */
21586d7f5d3SJohn Marino 		if (*ign == '!')
21686d7f5d3SJohn Marino 		{
21786d7f5d3SJohn Marino 		    ign_inhibit_server = 1;
21886d7f5d3SJohn Marino 		    continue;
21986d7f5d3SJohn Marino 		}
22086d7f5d3SJohn Marino 	    }
22186d7f5d3SJohn Marino 	    else if (*ign == '!')
22286d7f5d3SJohn Marino 	    {
22386d7f5d3SJohn Marino 		/* temporarily reset the ignore list */
22486d7f5d3SJohn Marino 		int i;
22586d7f5d3SJohn Marino 
22686d7f5d3SJohn Marino 		if (ign_hold >= 0)
22786d7f5d3SJohn Marino 		{
22886d7f5d3SJohn Marino 		    for (i = ign_hold; i < ign_count; i++)
22986d7f5d3SJohn Marino 			free (ign_list[i]);
23086d7f5d3SJohn Marino 		    ign_hold = -1;
23186d7f5d3SJohn Marino 		}
23286d7f5d3SJohn Marino 		if (s_ign_list)
23386d7f5d3SJohn Marino 		{
23486d7f5d3SJohn Marino 		    /* Don't save the ignore list twice - if there are two
23586d7f5d3SJohn Marino 		     * bangs in a local .cvsignore file then we don't want to
23686d7f5d3SJohn Marino 		     * save the new list the first bang created.
23786d7f5d3SJohn Marino 		     *
23886d7f5d3SJohn Marino 		     * We still need to free the "new" ignore list.
23986d7f5d3SJohn Marino 		     */
24086d7f5d3SJohn Marino 		    for (i = 0; i < ign_count; i++)
24186d7f5d3SJohn Marino 			free (ign_list[i]);
24286d7f5d3SJohn Marino 		}
24386d7f5d3SJohn Marino 		else
24486d7f5d3SJohn Marino 		{
24586d7f5d3SJohn Marino 		    /* Save the ignore list for later.  */
24686d7f5d3SJohn Marino 		    s_ign_list = xnmalloc (ign_count, sizeof (char *));
24786d7f5d3SJohn Marino 		    for (i = 0; i < ign_count; i++)
24886d7f5d3SJohn Marino 			s_ign_list[i] = ign_list[i];
24986d7f5d3SJohn Marino 		    s_ign_count = ign_count;
25086d7f5d3SJohn Marino 		}
25186d7f5d3SJohn Marino 		ign_count = 1;
25286d7f5d3SJohn Marino 		    /* Always ignore the "CVS" directory.  */
25386d7f5d3SJohn Marino 		ign_list[0] = xstrdup ("CVS");
25486d7f5d3SJohn Marino 		ign_list[1] = NULL;
25586d7f5d3SJohn Marino 		continue;
25686d7f5d3SJohn Marino 	    }
25786d7f5d3SJohn Marino 	}
25886d7f5d3SJohn Marino 
25986d7f5d3SJohn Marino 	/* find the end of this token */
26086d7f5d3SJohn Marino 	for (mark = ign; *mark && !isspace ((unsigned char) *mark); mark++)
26186d7f5d3SJohn Marino 	     /* do nothing */ ;
26286d7f5d3SJohn Marino 
26386d7f5d3SJohn Marino 	save = *mark;
26486d7f5d3SJohn Marino 	*mark = '\0';
26586d7f5d3SJohn Marino 
26686d7f5d3SJohn Marino 	ign_list[ign_count++] = xstrdup (ign);
26786d7f5d3SJohn Marino 	ign_list[ign_count] = NULL;
26886d7f5d3SJohn Marino 
26986d7f5d3SJohn Marino 	*mark = save;
27086d7f5d3SJohn Marino 	if (save)
27186d7f5d3SJohn Marino 	    ign = mark;
27286d7f5d3SJohn Marino 	else
27386d7f5d3SJohn Marino 	    ign = mark - 1;
27486d7f5d3SJohn Marino     }
27586d7f5d3SJohn Marino }
27686d7f5d3SJohn Marino 
27786d7f5d3SJohn Marino 
27886d7f5d3SJohn Marino 
27986d7f5d3SJohn Marino /* Return true if the given filename should be ignored by update or import,
28086d7f5d3SJohn Marino  * else return false.
28186d7f5d3SJohn Marino  */
28286d7f5d3SJohn Marino int
ign_name(char * name)28386d7f5d3SJohn Marino ign_name (char *name)
28486d7f5d3SJohn Marino {
28586d7f5d3SJohn Marino     char **cpp = ign_list;
28686d7f5d3SJohn Marino 
28786d7f5d3SJohn Marino     if (cpp == NULL)
28886d7f5d3SJohn Marino 	return 0;
28986d7f5d3SJohn Marino 
29086d7f5d3SJohn Marino     while (*cpp)
29186d7f5d3SJohn Marino 	if (CVS_FNMATCH (*cpp++, name, 0) == 0)
29286d7f5d3SJohn Marino 	    return 1;
29386d7f5d3SJohn Marino 
29486d7f5d3SJohn Marino     return 0;
29586d7f5d3SJohn Marino }
29686d7f5d3SJohn Marino 
29786d7f5d3SJohn Marino 
29886d7f5d3SJohn Marino 
29986d7f5d3SJohn Marino /* FIXME: This list of dirs to ignore stuff seems not to be used.
30086d7f5d3SJohn Marino    Really?  send_dirent_proc and update_dirent_proc both call
30186d7f5d3SJohn Marino    ignore_directory and do_module calls ign_dir_add.  No doubt could
30286d7f5d3SJohn Marino    use some documentation/testsuite work.  */
30386d7f5d3SJohn Marino 
30486d7f5d3SJohn Marino static char **dir_ign_list = NULL;
30586d7f5d3SJohn Marino static int dir_ign_max = 0;
30686d7f5d3SJohn Marino static int dir_ign_current = 0;
30786d7f5d3SJohn Marino 
30886d7f5d3SJohn Marino /* Add a directory to list of dirs to ignore.  */
30986d7f5d3SJohn Marino void
ign_dir_add(char * name)31086d7f5d3SJohn Marino ign_dir_add (char *name)
31186d7f5d3SJohn Marino {
31286d7f5d3SJohn Marino     /* Make sure we've got the space for the entry.  */
31386d7f5d3SJohn Marino     if (dir_ign_current <= dir_ign_max)
31486d7f5d3SJohn Marino     {
31586d7f5d3SJohn Marino 	dir_ign_max += IGN_GROW;
31686d7f5d3SJohn Marino 	dir_ign_list = xnrealloc (dir_ign_list,
31786d7f5d3SJohn Marino 				  dir_ign_max + 1, sizeof (char *));
31886d7f5d3SJohn Marino     }
31986d7f5d3SJohn Marino 
32086d7f5d3SJohn Marino     dir_ign_list[dir_ign_current++] = xstrdup (name);
32186d7f5d3SJohn Marino }
32286d7f5d3SJohn Marino 
32386d7f5d3SJohn Marino 
32486d7f5d3SJohn Marino /* Return nonzero if NAME is part of the list of directories to ignore.  */
32586d7f5d3SJohn Marino 
32686d7f5d3SJohn Marino int
ignore_directory(const char * name)32786d7f5d3SJohn Marino ignore_directory (const char *name)
32886d7f5d3SJohn Marino {
32986d7f5d3SJohn Marino     int i;
33086d7f5d3SJohn Marino 
33186d7f5d3SJohn Marino     if (!dir_ign_list)
33286d7f5d3SJohn Marino 	return 0;
33386d7f5d3SJohn Marino 
33486d7f5d3SJohn Marino     i = dir_ign_current;
33586d7f5d3SJohn Marino     while (i--)
33686d7f5d3SJohn Marino     {
33786d7f5d3SJohn Marino 	if (strncmp (name, dir_ign_list[i], strlen (dir_ign_list[i])+1) == 0)
33886d7f5d3SJohn Marino 	    return 1;
33986d7f5d3SJohn Marino     }
34086d7f5d3SJohn Marino 
34186d7f5d3SJohn Marino     return 0;
34286d7f5d3SJohn Marino }
34386d7f5d3SJohn Marino 
34486d7f5d3SJohn Marino 
34586d7f5d3SJohn Marino 
34686d7f5d3SJohn Marino /*
34786d7f5d3SJohn Marino  * Process the current directory, looking for files not in ILIST and
34886d7f5d3SJohn Marino  * not on the global ignore list for this directory.  If we find one,
34986d7f5d3SJohn Marino  * call PROC passing it the name of the file and the update dir.
35086d7f5d3SJohn Marino  * ENTRIES is the entries list, which is used to identify known
35186d7f5d3SJohn Marino  * directories.  ENTRIES may be NULL, in which case we assume that any
35286d7f5d3SJohn Marino  * directory with a CVS administration directory is known.
35386d7f5d3SJohn Marino  */
35486d7f5d3SJohn Marino void
ignore_files(List * ilist,List * entries,const char * update_dir,Ignore_proc proc)35586d7f5d3SJohn Marino ignore_files (List *ilist, List *entries, const char *update_dir,
35686d7f5d3SJohn Marino               Ignore_proc proc)
35786d7f5d3SJohn Marino {
35886d7f5d3SJohn Marino     int subdirs;
35986d7f5d3SJohn Marino     DIR *dirp;
36086d7f5d3SJohn Marino     struct dirent *dp;
36186d7f5d3SJohn Marino     struct stat sb;
36286d7f5d3SJohn Marino     char *file;
36386d7f5d3SJohn Marino     const char *xdir;
36486d7f5d3SJohn Marino     List *files;
36586d7f5d3SJohn Marino     Node *p;
36686d7f5d3SJohn Marino 
36786d7f5d3SJohn Marino     /* Set SUBDIRS if we have subdirectory information in ENTRIES.  */
36886d7f5d3SJohn Marino     if (entries == NULL)
36986d7f5d3SJohn Marino 	subdirs = 0;
37086d7f5d3SJohn Marino     else
37186d7f5d3SJohn Marino     {
37286d7f5d3SJohn Marino 	struct stickydirtag *sdtp = entries->list->data;
37386d7f5d3SJohn Marino 
37486d7f5d3SJohn Marino 	subdirs = sdtp == NULL || sdtp->subdirs;
37586d7f5d3SJohn Marino     }
37686d7f5d3SJohn Marino 
37786d7f5d3SJohn Marino     /* we get called with update_dir set to "." sometimes... strip it */
37886d7f5d3SJohn Marino     if (strcmp (update_dir, ".") == 0)
37986d7f5d3SJohn Marino 	xdir = "";
38086d7f5d3SJohn Marino     else
38186d7f5d3SJohn Marino 	xdir = update_dir;
38286d7f5d3SJohn Marino 
38386d7f5d3SJohn Marino     dirp = CVS_OPENDIR (".");
38486d7f5d3SJohn Marino     if (dirp == NULL)
38586d7f5d3SJohn Marino     {
38686d7f5d3SJohn Marino 	error (0, errno, "cannot open current directory");
38786d7f5d3SJohn Marino 	return;
38886d7f5d3SJohn Marino     }
38986d7f5d3SJohn Marino 
39086d7f5d3SJohn Marino     ign_add_file (CVSDOTIGNORE, 1);
39186d7f5d3SJohn Marino     wrap_add_file (CVSDOTWRAPPER, 1);
39286d7f5d3SJohn Marino 
39386d7f5d3SJohn Marino     /* Make a list for the files.  */
39486d7f5d3SJohn Marino     files = getlist ();
39586d7f5d3SJohn Marino 
39686d7f5d3SJohn Marino     while (errno = 0, (dp = CVS_READDIR (dirp)) != NULL)
39786d7f5d3SJohn Marino     {
39886d7f5d3SJohn Marino 	file = dp->d_name;
39986d7f5d3SJohn Marino 	if (strcmp (file, ".") == 0 || strcmp (file, "..") == 0)
40086d7f5d3SJohn Marino 	    continue;
40186d7f5d3SJohn Marino 	if (findnode_fn (ilist, file) != NULL)
40286d7f5d3SJohn Marino 	    continue;
40386d7f5d3SJohn Marino 	if (subdirs)
40486d7f5d3SJohn Marino 	{
40586d7f5d3SJohn Marino 	    Node *node;
40686d7f5d3SJohn Marino 
40786d7f5d3SJohn Marino 	    node = findnode_fn (entries, file);
40886d7f5d3SJohn Marino 	    if (node != NULL
40986d7f5d3SJohn Marino 		&& ((Entnode *) node->data)->type == ENT_SUBDIR)
41086d7f5d3SJohn Marino 	    {
41186d7f5d3SJohn Marino 		char *p;
41286d7f5d3SJohn Marino 		int dir;
41386d7f5d3SJohn Marino 
41486d7f5d3SJohn Marino 		/* For consistency with past behaviour, we only ignore
41586d7f5d3SJohn Marino 		   this directory if there is a CVS subdirectory.
41686d7f5d3SJohn Marino 		   This will normally be the case, but the user may
41786d7f5d3SJohn Marino 		   have messed up the working directory somehow.  */
41886d7f5d3SJohn Marino 		p = Xasprintf ("%s/%s", file, CVSADM);
41986d7f5d3SJohn Marino 		dir = isdir (p);
42086d7f5d3SJohn Marino 		free (p);
42186d7f5d3SJohn Marino 		if (dir)
42286d7f5d3SJohn Marino 		    continue;
42386d7f5d3SJohn Marino 	    }
42486d7f5d3SJohn Marino 	}
42586d7f5d3SJohn Marino 
42686d7f5d3SJohn Marino 	/* We could be ignoring FIFOs and other files which are neither
42786d7f5d3SJohn Marino 	   regular files nor directories here.  */
42886d7f5d3SJohn Marino 	if (ign_name (file))
42986d7f5d3SJohn Marino 	    continue;
43086d7f5d3SJohn Marino 
43186d7f5d3SJohn Marino 	if (
43286d7f5d3SJohn Marino #ifdef DT_DIR
43386d7f5d3SJohn Marino 	    dp->d_type != DT_UNKNOWN ||
43486d7f5d3SJohn Marino #endif
43586d7f5d3SJohn Marino 	    lstat (file, &sb) != -1)
43686d7f5d3SJohn Marino 	{
43786d7f5d3SJohn Marino 
43886d7f5d3SJohn Marino 	    if (
43986d7f5d3SJohn Marino #ifdef DT_DIR
44086d7f5d3SJohn Marino 		dp->d_type == DT_DIR
44186d7f5d3SJohn Marino 		|| (dp->d_type == DT_UNKNOWN && S_ISDIR (sb.st_mode))
44286d7f5d3SJohn Marino #else
44386d7f5d3SJohn Marino 		S_ISDIR (sb.st_mode)
44486d7f5d3SJohn Marino #endif
44586d7f5d3SJohn Marino 		)
44686d7f5d3SJohn Marino 	    {
44786d7f5d3SJohn Marino 		if (!subdirs)
44886d7f5d3SJohn Marino 		{
44986d7f5d3SJohn Marino 		    char *temp = Xasprintf ("%s/%s", file, CVSADM);
45086d7f5d3SJohn Marino 		    if (isdir (temp))
45186d7f5d3SJohn Marino 		    {
45286d7f5d3SJohn Marino 			free (temp);
45386d7f5d3SJohn Marino 			continue;
45486d7f5d3SJohn Marino 		    }
45586d7f5d3SJohn Marino 		    free (temp);
45686d7f5d3SJohn Marino 		}
45786d7f5d3SJohn Marino 	    }
45886d7f5d3SJohn Marino #ifdef S_ISLNK
45986d7f5d3SJohn Marino 	    else if (
46086d7f5d3SJohn Marino #ifdef DT_DIR
46186d7f5d3SJohn Marino 		     dp->d_type == DT_LNK
46286d7f5d3SJohn Marino 		     || (dp->d_type == DT_UNKNOWN && S_ISLNK (sb.st_mode))
46386d7f5d3SJohn Marino #else
46486d7f5d3SJohn Marino 		     S_ISLNK (sb.st_mode)
46586d7f5d3SJohn Marino #endif
46686d7f5d3SJohn Marino 		     )
46786d7f5d3SJohn Marino 	    {
46886d7f5d3SJohn Marino 		continue;
46986d7f5d3SJohn Marino 	    }
47086d7f5d3SJohn Marino #endif
47186d7f5d3SJohn Marino 	}
47286d7f5d3SJohn Marino 
47386d7f5d3SJohn Marino 	p = getnode ();
47486d7f5d3SJohn Marino 	p->type = FILES;
47586d7f5d3SJohn Marino 	p->key = xstrdup (file);
47686d7f5d3SJohn Marino 	(void) addnode (files, p);
47786d7f5d3SJohn Marino     }
47886d7f5d3SJohn Marino     if (errno != 0)
47986d7f5d3SJohn Marino 	error (0, errno, "error reading current directory");
48086d7f5d3SJohn Marino     (void) CVS_CLOSEDIR (dirp);
48186d7f5d3SJohn Marino 
48286d7f5d3SJohn Marino     sortlist (files, fsortcmp);
48386d7f5d3SJohn Marino     for (p = files->list->next; p != files->list; p = p->next)
48486d7f5d3SJohn Marino 	(*proc) (p->key, xdir);
48586d7f5d3SJohn Marino     dellist (&files);
48686d7f5d3SJohn Marino }
487