4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1995 Sun Microsystems, Inc. All Rights Reserved
29 * routines to manage the ignore lists and test names against them,
32 * ignore_check ... is a particular file covered by an ignore rule
33 * ignore_file .... add a specific file name to be ignored
34 * ignore_expr .... add a regular expression for files to be ignored
35 * ignore_pgm ..... add a rule to run a program to generate a list
36 * ignore_reset ... flush the internal optimization data structures
39 * ign_hash ... maintain a hash table of ignored names
40 * cheap_check. build up a table of safe suffixes
43 * a much simpler implementation could have been provided, but
44 * this test (every file tested against every rule) has the
45 * potential to be EXTREMELY expensive. This module implements
46 * an engine that attempts to optimize the process of determining
47 * that a file has not been ignored.
49 * the usage scenario is
51 * call ignore_{file,expr,pgm} for each ignore rule
52 * call ignore_check for every file under the base
53 * call ignore_reset when you are done
68 static struct list
*ign_hash(const char *, int);
69 static void cheap_check(const char *);
75 char *l_value
; /* the actual string */
76 struct list
*l_next
; /* pointer to next element */
79 static struct list
*expr_list
; /* list of regular expressions */
80 static struct list
*file_list
[ HASH_SIZE
]; /* hash table of literal names */
82 static char cheap_last
[256]; /* cheap test: last char */
83 static char cheap_penu
[256]; /* cheap test: penultimate char */
90 * determine whether or not a particular name matches an ignore pattern.
99 * becuse this routine is called on every single file in
100 * every single sub-directory, it is critical that we make
101 * it fail quickly for most files. The purpose of the cheap_last
102 * and cheap_penu arrays is to quickly determine there is no chance
103 * that a name will match any expression. Most expressions have
104 * wildcards near the front and constant suffixes, so our cheap
105 * test is to look at the last two bytes.
108 ignore_check(const char *name
)
113 * start with the cheap test
115 for (s
= name
; *s
; s
++);
116 if (cheap_last
[ (unsigned char) s
[-1] ] == 0 ||
117 cheap_penu
[ (unsigned char) s
[-2] ] == 0)
120 /* check the literal names in the hash table */
121 if (ign_hash(name
, 0)) {
122 if (opt_debug
& DBG_IGNORE
)
123 fprintf(stderr
, "IGNO: match %s\n", name
);
127 /* check all the regular expressions */
128 for (lp
= expr_list
; lp
; lp
= lp
->l_next
) {
129 if (gmatch(name
, lp
->l_value
) == 0)
132 if (opt_debug
& DBG_IGNORE
)
133 fprintf(stderr
, "IGNO: regex %s : %s\n",
146 * to add a specific file to an ignore list
152 ignore_file(const char *name
)
156 (void) ign_hash(name
, 1);
158 if (opt_debug
& DBG_IGNORE
)
159 fprintf(stderr
, "IGNO: add file %s\n", name
);
167 * to add a regular expression to an ignore list
173 ignore_expr(const char *expr
)
178 /* allocate a new node and stick it on the front of the list */
179 lp
= malloc(sizeof (*lp
));
181 nomem("ignore list");
182 lp
->l_value
= strdup(expr
);
183 lp
->l_next
= expr_list
;
186 if (opt_debug
& DBG_IGNORE
)
187 fprintf(stderr
, "IGNO: add expr %s\n", expr
);
195 * to run a program and gather up the ignore list it produces
201 ignore_pgm(const char *cmd
)
204 char inbuf
[ MAX_LINE
];
206 if (opt_debug
& DBG_IGNORE
)
207 fprintf(stderr
, "IGNO: add pgm %s\n", cmd
);
209 /* run the command and collect its ouput */
210 fp
= popen(cmd
, "r");
212 fprintf(stderr
, gettext(ERR_badrun
), cmd
);
217 * read each line, strip off the newline and add it to the list
219 while (fgets(inbuf
, sizeof (inbuf
), fp
) != 0) {
220 /* strip off any trailing newline */
221 for (s
= inbuf
; *s
&& *s
!= '\n'; s
++);
224 /* skip any leading white space */
225 for (s
= inbuf
; *s
== ' ' || *s
== '\t'; s
++);
227 /* add this file to the list */
230 (void) ign_hash(s
, 1);
232 if (opt_debug
& DBG_IGNORE
)
233 fprintf(stderr
, "IGNO: ... %s\n", s
);
245 * to find an entry in the hash list
252 * pointer to new list entry or 0
255 ign_hash(const char *name
, int alloc
)
256 { const unsigned char *s
;
261 /* perform the hash and find the chain */
262 for (s
= (const unsigned char *) name
, i
= 0; *s
; s
++)
264 pp
= &file_list
[i
% HASH_SIZE
];
266 /* search for the specified entry */
267 for (lp
= *pp
; lp
; lp
= *pp
) {
268 if (strcmp(name
, lp
->l_value
) == 0)
273 /* if caller said alloc, buy a new node and chain it in */
275 lp
= malloc(sizeof (*lp
));
277 nomem("ignore list");
278 lp
->l_value
= strdup(name
);
291 * to update the cheap-check arrays for an ignore expression
297 cheap_check(const char *name
)
302 for (s
= name
; *s
; s
++);
305 /* if expr ends in a wild card, we are undone */
307 if (c
== '*' || c
== '?' || c
== ']' || c
== '}') {
308 for (i
= 0; i
< 256; i
++) {
319 /* check the next to last character too */
321 if (c
== '*' || c
== '?' || c
== ']' || c
== '}') {
322 for (i
= 0; i
< 256; i
++)
333 * to free up all the ignore entries so we can start anew
338 struct list
*np
= 0; /* for LINT */
341 /* clear the cheap check arrays */
342 for (i
= 0; i
< 255; i
++) {
347 /* free all of the literal hash chains */
348 for (i
= 0; i
< HASH_SIZE
; i
++) {
349 for (lp
= file_list
[i
]; lp
; lp
= np
) {
357 /* free all of the expressions on the chain */
358 for (lp
= expr_list
; lp
; lp
= np
) {