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.adm .del-* *.a *.olb *.o *.obj\
39 *.so *.Z *~ *.old *.elc *.ln *.bak *.BAK *.orig *.rej *.exe _$* *$";
40 extern const char *cvsDir
;
42 #define IGN_GROW 16 /* grow the list by 16 elements at a
45 /* Nonzero if we have encountered an -I ! directive, which means one should
46 no longer ask the server about what is in CVSROOTADM_IGNORE. */
47 int ign_inhibit_server
;
52 * To the "ignore list", add the hard-coded default ignored wildcards above,
53 * the wildcards found in $CVSROOT/CVSROOT/cvsignore, the wildcards found in
54 * ~/.cvsignore and the wildcards found in the CVSIGNORE environment
63 ign_inhibit_server
= 0;
65 /* Start with default list and special case */
66 tmp
= xstrdup (ign_default
);
69 tmp
= xstrdup (cvsDir
);
73 /* The client handles another way, by (after it does its own ignore file
74 processing, and only if !ign_inhibit_server), letting the server
75 know about the files and letting it decide whether to ignore
76 them based on CVSROOOTADM_IGNORE. */
77 if (!current_parsed_root
->isremote
)
79 char *file
= Xasprintf ("%s/%s/%s", current_parsed_root
->directory
,
80 CVSROOTADM
, CVSROOTADM_IGNORE
);
81 /* Then add entries found in repository, if it exists */
82 ign_add_file (file
, 0);
86 /* Then add entries found in home dir, (if user has one) and file exists */
87 home_dir
= get_homedir ();
88 /* If we can't find a home directory, ignore ~/.cvsignore. This may
89 make tracking down problems a bit of a pain, but on the other
90 hand it might be obnoxious to complain when CVS will function
91 just fine without .cvsignore (and many users won't even know what
95 char *file
= strcat_filename_onto_homedir (home_dir
, CVSDOTIGNORE
);
96 ign_add_file (file
, 0);
100 /* Then add entries found in CVSIGNORE environment variable. */
101 ign_add (getenv (IGNORE_ENV
), 0);
103 /* Later, add ignore entries found in -I arguments */
109 * Open a file and read lines, feeding each line to a line parser. Arrange
110 * for keeping a temporary list of wildcards at the end, if the "hold"
114 ign_add_file (char *file
, int hold
)
118 size_t line_allocated
= 0;
120 /* restore the saved list (if any) */
121 if (s_ign_list
!= NULL
)
125 for (i
= 0; i
< s_ign_count
; i
++)
126 ign_list
[i
] = s_ign_list
[i
];
127 ign_count
= s_ign_count
;
128 ign_list
[ign_count
] = NULL
;
135 /* is this a temporary ignore file? */
138 /* re-set if we had already done a temporary file */
143 for (i
= ign_hold
; i
< ign_count
; i
++)
145 ign_count
= ign_hold
;
146 ign_list
[ign_count
] = NULL
;
150 ign_hold
= ign_count
;
155 fp
= CVS_FOPEN (file
, "r");
158 if (! existence_error (errno
))
159 error (0, errno
, "cannot open %s", file
);
162 while (getline (&line
, &line_allocated
, fp
) >= 0)
163 ign_add (line
, hold
);
165 error (0, errno
, "cannot read %s", file
);
167 error (0, errno
, "cannot close %s", file
);
173 /* Parse a line of space-separated wildcards and add them to the list. */
175 ign_add (char *ign
, int hold
)
185 /* ignore whitespace before the token */
186 if (isspace ((unsigned char) *ign
))
189 /* If we have used up all the space, add some more. Do this before
190 processing `!', since an "empty" list still contains the `CVS'
192 if (ign_count
>= ign_size
)
194 ign_size
+= IGN_GROW
;
195 ign_list
= xnrealloc (ign_list
, ign_size
+ 1, sizeof (char *));
199 * if we find a single character !, we must re-set the ignore list
200 * (saving it if necessary). We also catch * as a special case in a
201 * global ignore file as an optimization
203 if ((!*(ign
+1) || isspace ((unsigned char) *(ign
+1)))
204 && (*ign
== '!' || *ign
== '*'))
208 /* permanently reset the ignore list */
211 for (i
= 0; i
< ign_count
; i
++)
214 /* Always ignore the "CVS" directory. */
215 ign_list
[0] = xstrdup ("CVS");
218 /* if we are doing a '!', continue; otherwise add the '*' */
221 ign_inhibit_server
= 1;
225 else if (*ign
== '!')
227 /* temporarily reset the ignore list */
232 for (i
= ign_hold
; i
< ign_count
; i
++)
238 /* Don't save the ignore list twice - if there are two
239 * bangs in a local .cvsignore file then we don't want to
240 * save the new list the first bang created.
242 * We still need to free the "new" ignore list.
244 for (i
= 0; i
< ign_count
; i
++)
249 /* Save the ignore list for later. */
250 s_ign_list
= xnmalloc (ign_count
, sizeof (char *));
251 for (i
= 0; i
< ign_count
; i
++)
252 s_ign_list
[i
] = ign_list
[i
];
253 s_ign_count
= ign_count
;
256 /* Always ignore the "CVS" directory. */
257 ign_list
[0] = xstrdup ("CVS");
263 /* find the end of this token */
264 for (mark
= ign
; *mark
&& !isspace ((unsigned char) *mark
); mark
++)
270 ign_list
[ign_count
++] = xstrdup (ign
);
271 ign_list
[ign_count
] = NULL
;
283 /* Return true if the given filename should be ignored by update or import,
287 ign_name (char *name
)
289 char **cpp
= ign_list
;
295 if (CVS_FNMATCH (*cpp
++, name
, 0) == 0)
303 /* FIXME: This list of dirs to ignore stuff seems not to be used.
304 Really? send_dirent_proc and update_dirent_proc both call
305 ignore_directory and do_module calls ign_dir_add. No doubt could
306 use some documentation/testsuite work. */
308 static char **dir_ign_list
= NULL
;
309 static int dir_ign_max
= 0;
310 static int dir_ign_current
= 0;
312 /* Add a directory to list of dirs to ignore. */
314 ign_dir_add (char *name
)
316 /* Make sure we've got the space for the entry. */
317 if (dir_ign_current
<= dir_ign_max
)
319 dir_ign_max
+= IGN_GROW
;
320 dir_ign_list
= xnrealloc (dir_ign_list
,
321 dir_ign_max
+ 1, sizeof (char *));
324 dir_ign_list
[dir_ign_current
++] = xstrdup (name
);
328 /* Return nonzero if NAME is part of the list of directories to ignore. */
331 ignore_directory (const char *name
)
341 if (strncmp (name
, dir_ign_list
[i
], strlen (dir_ign_list
[i
])+1) == 0)
351 * Process the current directory, looking for files not in ILIST and
352 * not on the global ignore list for this directory. If we find one,
353 * call PROC passing it the name of the file and the update dir.
354 * ENTRIES is the entries list, which is used to identify known
355 * directories. ENTRIES may be NULL, in which case we assume that any
356 * directory with a CVS administration directory is known.
359 ignore_files (List
*ilist
, List
*entries
, const char *update_dir
,
371 /* Set SUBDIRS if we have subdirectory information in ENTRIES. */
376 struct stickydirtag
*sdtp
= entries
->list
->data
;
378 subdirs
= sdtp
== NULL
|| sdtp
->subdirs
;
381 /* we get called with update_dir set to "." sometimes... strip it */
382 if (strcmp (update_dir
, ".") == 0)
387 dirp
= CVS_OPENDIR (".");
390 error (0, errno
, "cannot open current directory");
394 ign_add_file (CVSDOTIGNORE
, 1);
395 wrap_add_file (CVSDOTWRAPPER
, 1);
397 /* Make a list for the files. */
400 while (errno
= 0, (dp
= CVS_READDIR (dirp
)) != NULL
)
403 if (strcmp (file
, ".") == 0 || strcmp (file
, "..") == 0)
405 if (findnode_fn (ilist
, file
) != NULL
)
411 node
= findnode_fn (entries
, file
);
413 && ((Entnode
*) node
->data
)->type
== ENT_SUBDIR
)
418 /* For consistency with past behaviour, we only ignore
419 this directory if there is a CVS subdirectory.
420 This will normally be the case, but the user may
421 have messed up the working directory somehow. */
422 p
= Xasprintf ("%s/%s", file
, CVSADM
);
430 /* We could be ignoring FIFOs and other files which are neither
431 regular files nor directories here. */
437 dp
->d_type
!= DT_UNKNOWN
||
439 lstat (file
, &sb
) != -1)
445 || (dp
->d_type
== DT_UNKNOWN
&& S_ISDIR (sb
.st_mode
))
453 char *temp
= Xasprintf ("%s/%s", file
, CVSADM
);
466 || (dp
->d_type
== DT_UNKNOWN
&& S_ISLNK (sb
.st_mode
))
479 p
->key
= xstrdup (file
);
480 (void) addnode (files
, p
);
483 error (0, errno
, "error reading current directory");
484 (void) CVS_CLOSEDIR (dirp
);
486 sortlist (files
, fsortcmp
);
487 for (p
= files
->list
->next
; p
!= files
->list
; p
= p
->next
)
488 (*proc
) (p
->key
, xdir
);