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