/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 1995 Sun Microsystems, Inc. All Rights Reserved
*
* module:
* ignore.c
*
* purpose:
* routines to manage the ignore lists and test names against them,
*
* contents:
* ignore_check ... is a particular file covered by an ignore rule
* ignore_file .... add a specific file name to be ignored
* ignore_expr .... add a regular expression for files to be ignored
* ignore_pgm ..... add a rule to run a program to generate a list
* ignore_reset ... flush the internal optimization data structures
*
* static
* ign_hash ... maintain a hash table of ignored names
* cheap_check. build up a table of safe suffixes
*
* notes:
* a much simpler implementation could have been provided, but
* this test (every file tested against every rule) has the
* potential to be EXTREMELY expensive. This module implements
* an engine that attempts to optimize the process of determining
* that a file has not been ignored.
*
* the usage scenario is
* per base
* call ignore_{file,expr,pgm} for each ignore rule
* call ignore_check for every file under the base
* call ignore_reset when you are done
*/
#ident "%W% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include "filesync.h"
#include "messages.h"
/*
* routines:
*/
static void cheap_check(const char *);
/*
* globals
*/
struct list {
};
/*
* routine:
* ignore_check
*
* purpose:
* determine whether or not a particular name matches an ignore pattern.
*
* parameters:
* file name
*
* returns:
*
* note:
* becuse this routine is called on every single file in
* every single sub-directory, it is critical that we make
* it fail quickly for most files. The purpose of the cheap_last
* and cheap_penu arrays is to quickly determine there is no chance
* that a name will match any expression. Most expressions have
* wildcards near the front and constant suffixes, so our cheap
* test is to look at the last two bytes.
*/
const char *s;
/*
* start with the cheap test
*/
for (s = name; *s; s++);
if (cheap_last[ (unsigned char) s[-1] ] == 0 ||
cheap_penu[ (unsigned char) s[-2] ] == 0)
return (FALSE);
/* check the literal names in the hash table */
if (opt_debug & DBG_IGNORE)
return (TRUE);
}
/* check all the regular expressions */
continue;
if (opt_debug & DBG_IGNORE)
return (TRUE);
}
return (FALSE);
}
/*
* routine:
* ignore_file
*
* purpose:
* to add a specific file to an ignore list
*
* parameters:
* command to run
*/
void
{
if (opt_debug & DBG_IGNORE)
}
/*
* routine:
* ignore_expr
*
* purpose:
* to add a regular expression to an ignore list
*
* parameters:
* command to run
*/
void
/* allocate a new node and stick it on the front of the list */
if (lp == 0)
nomem("ignore list");
if (opt_debug & DBG_IGNORE)
}
/*
* routine:
* ignore_pgm
*
* purpose:
* to run a program and gather up the ignore list it produces
*
* parameters:
* command to run
*/
void
{ char *s;
if (opt_debug & DBG_IGNORE)
/* run the command and collect its ouput */
return;
}
/*
* read each line, strip off the newline and add it to the list
*/
/* strip off any trailing newline */
for (s = inbuf; *s && *s != '\n'; s++);
*s = 0;
/* skip any leading white space */
/* add this file to the list */
if (*s) {
cheap_check(s);
(void) ign_hash(s, 1);
if (opt_debug & DBG_IGNORE)
}
}
}
/*
* routine:
* ign_hash
*
* purpose:
* to find an entry in the hash list
*
* parameters:
* name
* allocate flag
*
* returns:
* pointer to new list entry or 0
*/
static struct list *
{ const unsigned char *s;
int i;
/* perform the hash and find the chain */
for (s = (const unsigned char *) name, i = 0; *s; s++)
i += *s;
/* search for the specified entry */
return (lp);
}
/* if caller said alloc, buy a new node and chain it in */
if (alloc) {
if (lp == 0)
nomem("ignore list");
}
return (lp);
}
/*
* routine:
* cheap_check
*
* purpose:
* to update the cheap-check arrays for an ignore expression
*
* parameters:
*/
static void
{ const char *s;
unsigned char c;
int i;
for (s = name; *s; s++);
s--;
/* if expr ends in a wild card, we are undone */
c = *s;
if (c == '*' || c == '?' || c == ']' || c == '}') {
for (i = 0; i < 256; i++) {
cheap_last[i] = 1;
cheap_penu[i] = 1;
}
return;
} else
cheap_last[c] = 1;
if (s <= name)
return;
/* check the next to last character too */
c = s[-1];
if (c == '*' || c == '?' || c == ']' || c == '}') {
for (i = 0; i < 256; i++)
cheap_penu[i] = 1;
} else
cheap_penu[c] = 1;
}
/*
* routine:
* ignore_reset
*
* purpose:
* to free up all the ignore entries so we can start anew
*/
void
ignore_reset(void)
{ int i;
/* clear the cheap check arrays */
for (i = 0; i < 255; i++) {
cheap_last[i] = 0;
cheap_penu[i] = 0;
}
/* free all of the literal hash chains */
for (i = 0; i < HASH_SIZE; i++) {
}
file_list[i] = 0;
}
/* free all of the expressions on the chain */
}
expr_list = 0;
}