1 /* This program is free software; you can redistribute it and/or modify
2 it under the terms of the GNU General Public License as published by
3 the Free Software Foundation; either version 2, or (at your option)
6 This program is distributed in the hope that it will be useful,
7 but WITHOUT ANY WARRANTY; without even the implied warranty of
8 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 GNU General Public License for more details. */
12 * .cvsignore file support contributed by David G. Grubbs <dgg@odi.com>
19 * Ignore file section.
21 * "!" may be included any time to reset the list (i.e. ignore nothing);
22 * "*" may be specified to ignore everything. It stays as the first
23 * element forever, unless a "!" clears it out.
26 static char **ign_list; /* List of files to ignore in update
28 static char **s_ign_list = NULL;
29 static int ign_count; /* Number of active entries */
30 static int s_ign_count = 0;
31 static int ign_size; /* This many slots available (plus
33 static int ign_hold = -1; /* Index where first "temporary" item
36 const char *ign_default = ". .. core RCSLOG tags TAGS RCS SCCS .make.state\
37 .nse_depinfo #* .#* cvslog.* ,* CVS CVS.adm .del-* *.a *.olb *.o *.obj\
38 *.so *.Z *~ *.old *.elc *.ln *.bak *.BAK *.orig *.rej *.exe _$* *$";
40 #define IGN_GROW 16 /* grow the list by 16 elements at a
43 /* Nonzero if we have encountered an -I ! directive, which means one should
44 no longer ask the server about what is in CVSROOTADM_IGNORE. */
45 int ign_inhibit_server;
48 * To the "ignore list", add the hard-coded default ignored wildcards above,
49 * the wildcards found in $CVSROOT/CVSROOT/cvsignore, the wildcards found in
50 * ~/.cvsignore and the wildcards found in the CVSIGNORE environment
59 ign_inhibit_server = 0;
61 /* Start with default list and special case */
62 tmp = xstrdup (ign_default);
67 /* The client handles another way, by (after it does its own ignore file
68 processing, and only if !ign_inhibit_server), letting the server
69 know about the files and letting it decide whether to ignore
70 them based on CVSROOOTADM_IGNORE. */
74 char *file = xmalloc (strlen (CVSroot_directory) + sizeof (CVSROOTADM)
75 + sizeof (CVSROOTADM_IGNORE) + 10);
76 /* Then add entries found in repository, if it exists */
77 (void) sprintf (file, "%s/%s/%s", CVSroot_directory,
78 CVSROOTADM, CVSROOTADM_IGNORE);
79 ign_add_file (file, 0);
83 /* Then add entries found in home dir, (if user has one) and file exists */
84 home_dir = get_homedir ();
85 /* If we can't find a home directory, ignore ~/.cvsignore. This may
86 make tracking down problems a bit of a pain, but on the other
87 hand it might be obnoxious to complain when CVS will function
88 just fine without .cvsignore (and many users won't even know what
92 char *file = xmalloc (strlen (home_dir) + sizeof (CVSDOTIGNORE) + 10);
93 (void) sprintf (file, "%s/%s", home_dir, CVSDOTIGNORE);
94 ign_add_file (file, 0);
98 /* Then add entries found in CVSIGNORE environment variable. */
99 ign_add (getenv (IGNORE_ENV), 0);
101 /* Later, add ignore entries found in -I arguments */
105 * Open a file and read lines, feeding each line to a line parser. Arrange
106 * for keeping a temporary list of wildcards at the end, if the "hold"
110 ign_add_file (file, hold)
116 size_t line_allocated = 0;
118 /* restore the saved list (if any) */
119 if (s_ign_list != NULL)
123 for (i = 0; i < s_ign_count; i++)
124 ign_list[i] = s_ign_list[i];
125 ign_count = s_ign_count;
126 ign_list[ign_count] = NULL;
133 /* is this a temporary ignore file? */
136 /* re-set if we had already done a temporary file */
141 for (i = ign_hold; i < ign_count; i++)
143 ign_count = ign_hold;
144 ign_list[ign_count] = NULL;
148 ign_hold = ign_count;
153 fp = CVS_FOPEN (file, "r");
156 if (! existence_error (errno))
157 error (0, errno, "cannot open %s", file);
160 while (getline (&line, &line_allocated, fp) >= 0)
161 ign_add (line, hold);
163 error (0, errno, "cannot read %s", file);
165 error (0, errno, "cannot close %s", file);
169 /* Parse a line of space-separated wildcards and add them to the list. */
183 /* ignore whitespace before the token */
184 if (isspace ((unsigned char) *ign))
188 * if we find a single character !, we must re-set the ignore list
189 * (saving it if necessary). We also catch * as a special case in a
190 * global ignore file as an optimization
192 if ((!*(ign+1) || isspace ((unsigned char) *(ign+1)))
193 && (*ign == '!' || *ign == '*'))
197 /* permanently reset the ignore list */
200 for (i = 0; i < ign_count; i++)
205 /* if we are doing a '!', continue; otherwise add the '*' */
208 ign_inhibit_server = 1;
212 else if (*ign == '!')
214 /* temporarily reset the ignore list */
219 for (i = ign_hold; i < ign_count; i++)
223 s_ign_list = (char **) xmalloc (ign_count * sizeof (char *));
224 for (i = 0; i < ign_count; i++)
225 s_ign_list[i] = ign_list[i];
226 s_ign_count = ign_count;
233 /* If we have used up all the space, add some more */
234 if (ign_count >= ign_size)
236 ign_size += IGN_GROW;
237 ign_list = (char **) xrealloc ((char *) ign_list,
238 (ign_size + 1) * sizeof (char *));
241 /* find the end of this token */
242 for (mark = ign; *mark && !isspace ((unsigned char) *mark); mark++)
248 ign_list[ign_count++] = xstrdup (ign);
249 ign_list[ign_count] = NULL;
259 /* Set to 1 if filenames should be matched in a case-insensitive
260 fashion. Note that, contrary to the name and placement in ignore.c,
261 this is no longer just for ignore patterns. */
264 /* Return 1 if the given filename should be ignored by update or import. */
269 char **cpp = ign_list;
276 /* We do a case-insensitive match by calling fnmatch on copies of
277 the pattern and the name which have been converted to
278 lowercase. FIXME: would be much cleaner to just unify this
279 with the other case-insensitive fnmatch stuff (FOLD_FN_CHAR
280 in lib/fnmatch.c; os2_fnmatch in emx/system.c). */
285 name_lower = xstrdup (name);
286 for (p = name_lower; *p != '\0'; ++p)
290 pat_lower = xstrdup (*cpp++);
291 for (p = pat_lower; *p != '\0'; ++p)
293 if (CVS_FNMATCH (pat_lower, name_lower, 0) == 0)
307 if (CVS_FNMATCH (*cpp++, name, 0) == 0)
313 /* FIXME: This list of dirs to ignore stuff seems not to be used.
314 Really? send_dirent_proc and update_dirent_proc both call
315 ignore_directory and do_module calls ign_dir_add. No doubt could
316 use some documentation/testsuite work. */
318 static char **dir_ign_list = NULL;
319 static int dir_ign_max = 0;
320 static int dir_ign_current = 0;
322 /* Add a directory to list of dirs to ignore. */
327 /* Make sure we've got the space for the entry. */
328 if (dir_ign_current <= dir_ign_max)
330 dir_ign_max += IGN_GROW;
332 (char **) xrealloc (dir_ign_list,
333 (dir_ign_max + 1) * sizeof (char *));
336 dir_ign_list[dir_ign_current] = name;
338 dir_ign_current += 1 ;
342 /* Return nonzero if NAME is part of the list of directories to ignore. */
345 ignore_directory (name)
356 if (strncmp (name, dir_ign_list[i], strlen (dir_ign_list[i])) == 0)
364 * Process the current directory, looking for files not in ILIST and
365 * not on the global ignore list for this directory. If we find one,
366 * call PROC passing it the name of the file and the update dir.
367 * ENTRIES is the entries list, which is used to identify known
368 * directories. ENTRIES may be NULL, in which case we assume that any
369 * directory with a CVS administration directory is known.
372 ignore_files (ilist, entries, update_dir, proc)
385 /* Set SUBDIRS if we have subdirectory information in ENTRIES. */
390 struct stickydirtag *sdtp;
392 sdtp = (struct stickydirtag *) entries->list->data;
393 subdirs = sdtp == NULL || sdtp->subdirs;
396 /* we get called with update_dir set to "." sometimes... strip it */
397 if (strcmp (update_dir, ".") == 0)
402 dirp = CVS_OPENDIR (".");
405 error (0, errno, "cannot open current directory");
409 ign_add_file (CVSDOTIGNORE, 1);
410 wrap_add_file (CVSDOTWRAPPER, 1);
413 while ((dp = readdir (dirp)) != NULL)
416 if (strcmp (file, ".") == 0 || strcmp (file, "..") == 0)
418 if (findnode_fn (ilist, file) != NULL)
424 node = findnode_fn (entries, file);
426 && ((Entnode *) node->data)->type == ENT_SUBDIR)
431 /* For consistency with past behaviour, we only ignore
432 this directory if there is a CVS subdirectory.
433 This will normally be the case, but the user may
434 have messed up the working directory somehow. */
435 p = xmalloc (strlen (file) + sizeof CVSADM + 10);
436 sprintf (p, "%s/%s", file, CVSADM);
444 /* We could be ignoring FIFOs and other files which are neither
445 regular files nor directories here. */
451 dp->d_type != DT_UNKNOWN ||
453 lstat(file, &sb) != -1)
458 dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN &&
466 temp = xmalloc (strlen (file) + sizeof (CVSADM) + 10);
467 (void) sprintf (temp, "%s/%s", file, CVSADM);
479 dp->d_type == DT_LNK || dp->d_type == DT_UNKNOWN &&
488 (*proc) (file, xdir);
492 error (0, errno, "error reading current directory");
493 (void) closedir (dirp);