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>
20 * Ignore file section.
22 * "!" may be included any time to reset the list (i.e. ignore nothing);
23 * "*" may be specified to ignore everything. It stays as the first
24 * element forever, unless a "!" clears it out.
27 static char **ign_list; /* List of files to ignore in update
29 static char **s_ign_list = NULL;
30 static int ign_count; /* Number of active entries */
31 static int s_ign_count = 0;
32 static int ign_size; /* This many slots available (plus
34 static int ign_hold = -1; /* Index where first "temporary" item
37 const char *ign_default = ". .. core RCSLOG tags TAGS RCS SCCS .make.state\
38 .nse_depinfo #* .#* cvslog.* ,* CVS CVS.adm .del-* *.a *.olb *.o *.obj\
39 *.so *.Z *~ *.old *.elc *.ln *.bak *.BAK *.orig *.rej *.exe _$* *$";
41 #define IGN_GROW 16 /* grow the list by 16 elements at a
44 /* Nonzero if we have encountered an -I ! directive, which means one should
45 no longer ask the server about what is in CVSROOTADM_IGNORE. */
46 int ign_inhibit_server;
51 * To the "ignore list", add the hard-coded default ignored wildcards above,
52 * the wildcards found in $CVSROOT/CVSROOT/cvsignore, the wildcards found in
53 * ~/.cvsignore and the wildcards found in the CVSIGNORE environment
62 ign_inhibit_server = 0;
64 /* Start with default list and special case */
65 tmp = xstrdup (ign_default);
69 /* The client handles another way, by (after it does its own ignore file
70 processing, and only if !ign_inhibit_server), letting the server
71 know about the files and letting it decide whether to ignore
72 them based on CVSROOOTADM_IGNORE. */
73 if (!current_parsed_root->isremote)
75 char *file = Xasprintf ("%s/%s/%s", current_parsed_root->directory,
76 CVSROOTADM, CVSROOTADM_IGNORE);
77 /* Then add entries found in repository, if it exists */
78 ign_add_file (file, 0);
82 /* Then add entries found in home dir, (if user has one) and file exists */
83 home_dir = get_homedir ();
84 /* If we can't find a home directory, ignore ~/.cvsignore. This may
85 make tracking down problems a bit of a pain, but on the other
86 hand it might be obnoxious to complain when CVS will function
87 just fine without .cvsignore (and many users won't even know what
91 char *file = strcat_filename_onto_homedir (home_dir, CVSDOTIGNORE);
92 ign_add_file (file, 0);
96 /* Then add entries found in CVSIGNORE environment variable. */
97 ign_add (getenv (IGNORE_ENV), 0);
99 /* 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 (char *file, int hold)
114 size_t line_allocated = 0;
116 /* restore the saved list (if any) */
117 if (s_ign_list != NULL)
121 for (i = 0; i < s_ign_count; i++)
122 ign_list[i] = s_ign_list[i];
123 ign_count = s_ign_count;
124 ign_list[ign_count] = NULL;
131 /* is this a temporary ignore file? */
134 /* re-set if we had already done a temporary file */
139 for (i = ign_hold; i < ign_count; i++)
141 ign_count = ign_hold;
142 ign_list[ign_count] = NULL;
146 ign_hold = ign_count;
151 fp = CVS_FOPEN (file, "r");
154 if (! existence_error (errno))
155 error (0, errno, "cannot open %s", file);
158 while (getline (&line, &line_allocated, fp) >= 0)
159 ign_add (line, hold);
161 error (0, errno, "cannot read %s", file);
163 error (0, errno, "cannot close %s", file);
169 /* Parse a line of space-separated wildcards and add them to the list. */
171 ign_add (char *ign, int hold)
181 /* ignore whitespace before the token */
182 if (isspace ((unsigned char) *ign))
185 /* If we have used up all the space, add some more. Do this before
186 processing `!', since an "empty" list still contains the `CVS'
188 if (ign_count >= ign_size)
190 ign_size += IGN_GROW;
191 ign_list = xnrealloc (ign_list, ign_size + 1, sizeof (char *));
195 * if we find a single character !, we must re-set the ignore list
196 * (saving it if necessary). We also catch * as a special case in a
197 * global ignore file as an optimization
199 if ((!*(ign+1) || isspace ((unsigned char) *(ign+1)))
200 && (*ign == '!' || *ign == '*'))
204 /* permanently reset the ignore list */
207 for (i = 0; i < ign_count; i++)
210 /* Always ignore the "CVS" directory. */
211 ign_list[0] = xstrdup ("CVS");
214 /* if we are doing a '!', continue; otherwise add the '*' */
217 ign_inhibit_server = 1;
221 else if (*ign == '!')
223 /* temporarily reset the ignore list */
228 for (i = ign_hold; i < ign_count; i++)
234 /* Don't save the ignore list twice - if there are two
235 * bangs in a local .cvsignore file then we don't want to
236 * save the new list the first bang created.
238 * We still need to free the "new" ignore list.
240 for (i = 0; i < ign_count; i++)
245 /* Save the ignore list for later. */
246 s_ign_list = xnmalloc (ign_count, sizeof (char *));
247 for (i = 0; i < ign_count; i++)
248 s_ign_list[i] = ign_list[i];
249 s_ign_count = ign_count;
252 /* Always ignore the "CVS" directory. */
253 ign_list[0] = xstrdup ("CVS");
259 /* find the end of this token */
260 for (mark = ign; *mark && !isspace ((unsigned char) *mark); mark++)
266 ign_list[ign_count++] = xstrdup (ign);
267 ign_list[ign_count] = NULL;
279 /* Return true if the given filename should be ignored by update or import,
283 ign_name (char *name)
285 char **cpp = ign_list;
291 if (CVS_FNMATCH (*cpp++, name, 0) == 0)
299 /* FIXME: This list of dirs to ignore stuff seems not to be used.
300 Really? send_dirent_proc and update_dirent_proc both call
301 ignore_directory and do_module calls ign_dir_add. No doubt could
302 use some documentation/testsuite work. */
304 static char **dir_ign_list = NULL;
305 static int dir_ign_max = 0;
306 static int dir_ign_current = 0;
308 /* Add a directory to list of dirs to ignore. */
310 ign_dir_add (char *name)
312 /* Make sure we've got the space for the entry. */
313 if (dir_ign_current <= dir_ign_max)
315 dir_ign_max += IGN_GROW;
316 dir_ign_list = xnrealloc (dir_ign_list,
317 dir_ign_max + 1, sizeof (char *));
320 dir_ign_list[dir_ign_current++] = xstrdup (name);
324 /* Return nonzero if NAME is part of the list of directories to ignore. */
327 ignore_directory (const char *name)
337 if (strncmp (name, dir_ign_list[i], strlen (dir_ign_list[i])+1) == 0)
347 * Process the current directory, looking for files not in ILIST and
348 * not on the global ignore list for this directory. If we find one,
349 * call PROC passing it the name of the file and the update dir.
350 * ENTRIES is the entries list, which is used to identify known
351 * directories. ENTRIES may be NULL, in which case we assume that any
352 * directory with a CVS administration directory is known.
355 ignore_files (List *ilist, List *entries, const char *update_dir,
367 /* Set SUBDIRS if we have subdirectory information in ENTRIES. */
372 struct stickydirtag *sdtp = entries->list->data;
374 subdirs = sdtp == NULL || sdtp->subdirs;
377 /* we get called with update_dir set to "." sometimes... strip it */
378 if (strcmp (update_dir, ".") == 0)
383 dirp = CVS_OPENDIR (".");
386 error (0, errno, "cannot open current directory");
390 ign_add_file (CVSDOTIGNORE, 1);
391 wrap_add_file (CVSDOTWRAPPER, 1);
393 /* Make a list for the files. */
396 while (errno = 0, (dp = CVS_READDIR (dirp)) != NULL)
399 if (strcmp (file, ".") == 0 || strcmp (file, "..") == 0)
401 if (findnode_fn (ilist, file) != NULL)
407 node = findnode_fn (entries, file);
409 && ((Entnode *) node->data)->type == ENT_SUBDIR)
414 /* For consistency with past behaviour, we only ignore
415 this directory if there is a CVS subdirectory.
416 This will normally be the case, but the user may
417 have messed up the working directory somehow. */
418 p = Xasprintf ("%s/%s", file, CVSADM);
426 /* We could be ignoring FIFOs and other files which are neither
427 regular files nor directories here. */
433 dp->d_type != DT_UNKNOWN ||
435 lstat (file, &sb) != -1)
441 || (dp->d_type == DT_UNKNOWN && S_ISDIR (sb.st_mode))
449 char *temp = Xasprintf ("%s/%s", file, CVSADM);
462 || (dp->d_type == DT_UNKNOWN && S_ISLNK (sb.st_mode))
475 p->key = xstrdup (file);
476 (void) addnode (files, p);
479 error (0, errno, "error reading current directory");
480 (void) CVS_CLOSEDIR (dirp);
482 sortlist (files, fsortcmp);
483 for (p = files->list->next; p != files->list; p = p->next)
484 (*proc) (p->key, xdir);