2 * .cvsignore file support contributed by David G. Grubbs <dgg@odi.com>
10 * "!" may be included any time to reset the list (i.e. ignore nothing);
11 * "*" may be specified to ignore everything. It stays as the first
12 * element forever, unless a "!" clears it out.
15 static char **ign_list; /* List of files to ignore in update
17 static char **s_ign_list = NULL;
18 static int ign_count; /* Number of active entries */
19 static int s_ign_count = 0;
20 static int ign_size; /* This many slots available (plus
22 static int ign_hold; /* Index where first "temporary" item
25 const char *ign_default = ". .. core RCSLOG tags TAGS RCS SCCS .make.state\
26 .nse_depinfo #* .#* cvslog.* ,* CVS CVS.adm .del-* *.a *.olb *.o *.obj\
27 *.so *.Z *~ *.old *.elc *.ln *.bak *.BAK *.orig *.rej *.exe _$* *$";
29 #define IGN_GROW 16 /* grow the list by 16 elements at a
32 /* Nonzero if we have encountered an -I ! directive, which means one should
33 no longer ask the server about what is in CVSROOTADM_IGNORE. */
34 int ign_inhibit_server;
37 * To the "ignore list", add the hard-coded default ignored wildcards above,
38 * the wildcards found in $CVSROOT/CVSROOT/cvsignore, the wildcards found in
39 * ~/.cvsignore and the wildcards found in the CVSIGNORE environment
49 ign_inhibit_server = 0;
51 /* Start with default list and special case */
52 tmp = xstrdup (ign_default);
57 /* The client handles another way, by (after it does its own ignore file
58 processing, and only if !ign_inhibit_server), letting the server
59 know about the files and letting it decide whether to ignore
60 them based on CVSROOOTADM_IGNORE. */
64 /* Then add entries found in repository, if it exists */
65 (void) sprintf (file, "%s/%s/%s", CVSroot, CVSROOTADM,
67 ign_add_file (file, 0);
70 /* Then add entries found in home dir, (if user has one) and file exists */
71 if ((pw = (struct passwd *) getpwuid (getuid ())) && pw->pw_dir)
73 (void) sprintf (file, "%s/%s", pw->pw_dir, CVSDOTIGNORE);
74 ign_add_file (file, 0);
77 /* Then add entries found in CVSIGNORE environment variable. */
78 ign_add (getenv (IGNORE_ENV), 0);
80 /* Later, add ignore entries found in -I arguments */
84 * Open a file and read lines, feeding each line to a line parser. Arrange
85 * for keeping a temporary list of wildcards at the end, if the "hold"
89 ign_add_file (file, hold)
96 /* restore the saved list (if any) */
97 if (s_ign_list != NULL)
101 for (i = 0; i < s_ign_count; i++)
102 ign_list[i] = s_ign_list[i];
103 ign_count = s_ign_count;
104 ign_list[ign_count] = NULL;
111 /* is this a temporary ignore file? */
114 /* re-set if we had already done a temporary file */
119 for (i = ign_hold; i < ign_count; i++)
121 ign_count = ign_hold;
122 ign_list[ign_count] = NULL;
126 ign_hold = ign_count;
131 fp = fopen (file, "r");
134 if (! existence_error (errno))
135 error (0, errno, "cannot open %s", file);
138 while (fgets (line, sizeof (line), fp))
139 ign_add (line, hold);
141 error (0, errno, "cannot close %s", file);
144 /* Parse a line of space-separated wildcards and add them to the list. */
158 /* ignore whitespace before the token */
163 * if we find a single character !, we must re-set the ignore list
164 * (saving it if necessary). We also catch * as a special case in a
165 * global ignore file as an optimization
167 if ((!*(ign+1) || isspace (*(ign+1))) && (*ign == '!' || *ign == '*'))
171 /* permanently reset the ignore list */
174 for (i = 0; i < ign_count; i++)
179 /* if we are doing a '!', continue; otherwise add the '*' */
182 ign_inhibit_server = 1;
186 else if (*ign == '!')
188 /* temporarily reset the ignore list */
193 for (i = ign_hold; i < ign_count; i++)
197 s_ign_list = (char **) xmalloc (ign_count * sizeof (char *));
198 for (i = 0; i < ign_count; i++)
199 s_ign_list[i] = ign_list[i];
200 s_ign_count = ign_count;
207 /* If we have used up all the space, add some more */
208 if (ign_count >= ign_size)
210 ign_size += IGN_GROW;
211 ign_list = (char **) xrealloc ((char *) ign_list,
212 (ign_size + 1) * sizeof (char *));
215 /* find the end of this token */
216 for (mark = ign; *mark && !isspace (*mark); mark++)
222 ign_list[ign_count++] = xstrdup (ign);
223 ign_list[ign_count] = NULL;
233 /* Set to 1 if ignore file patterns should be matched in a case-insensitive
237 /* Return 1 if the given filename should be ignored by update or import. */
242 char **cpp = ign_list;
249 /* We do a case-insensitive match by calling fnmatch on copies of
250 the pattern and the name which have been converted to
256 name_lower = xstrdup (name);
257 for (p = name_lower; *p != '\0'; ++p)
261 pat_lower = xstrdup (*cpp++);
262 for (p = pat_lower; *p != '\0'; ++p)
264 if (fnmatch (pat_lower, name_lower, 0) == 0)
278 if (fnmatch (*cpp++, name, 0) == 0)
284 /* FIXME: This list of dirs to ignore stuff seems not to be used. */
286 static char **dir_ign_list = NULL;
287 static int dir_ign_max = 0;
288 static int dir_ign_current = 0;
290 /* add a directory to list of dirs to ignore */
291 void ign_dir_add (name)
294 /* make sure we've got the space for the entry */
295 if (dir_ign_current <= dir_ign_max)
297 dir_ign_max += IGN_GROW;
298 dir_ign_list = (char **) xrealloc ((char *) dir_ign_list, (dir_ign_max+1) * sizeof(char*));
301 dir_ign_list[dir_ign_current] = name;
303 dir_ign_current += 1 ;
307 /* this function returns 1 (true) if the given directory name is part of
308 * the list of directories to ignore
311 int ignore_directory (name)
322 if (strncmp(name, dir_ign_list[i], strlen(dir_ign_list[i])) == 0)
330 * Process the current directory, looking for files not in ILIST and not on
331 * the global ignore list for this directory. If we find one, call PROC
332 * passing it the name of the file and the update dir.
335 ignore_files (ilist, update_dir, proc)
346 /* we get called with update_dir set to "." sometimes... strip it */
347 if (strcmp (update_dir, ".") == 0)
352 dirp = opendir (".");
356 ign_add_file (CVSDOTIGNORE, 1);
357 wrap_add_file (CVSDOTWRAPPER, 1);
359 while ((dp = readdir (dirp)) != NULL)
362 if (strcmp (file, ".") == 0 || strcmp (file, "..") == 0)
364 if (findnode_fn (ilist, file) != NULL)
369 dp->d_type != DT_UNKNOWN ||
371 lstat(file, &sb) != -1)
376 dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN &&
382 (void) sprintf (temp, "%s/%s", file, CVSADM);
389 dp->d_type == DT_LNK || dp->d_type == DT_UNKNOWN &&
398 /* We could be ignoring FIFOs and other files which are neither
399 regular files nor directories here. */
402 (*proc) (file, xdir);
404 (void) closedir (dirp);