NetBSD/gnu/dist/postfix/util/match_list.c

194 lines
5.3 KiB
C

/*++
/* NAME
/* match_list 3
/* SUMMARY
/* generic list-based pattern matching
/* SYNOPSIS
/* #include <match_list.h>
/*
/* MATCH_LIST *match_list_init(pattern_list, count, func,...)
/* const char *pattern_list;
/* int count;
/* int (*func)(const char *string, const char *pattern);
/*
/* int match_list_match(list, string,...)
/* MATCH_LIST *list;
/* const char *string;
/*
/* void match_list_free(list)
/* MATCH_LIST *list;
/* DESCRIPTION
/* This module implements a framework for tests for list membership.
/* The actual tests are done by user-supplied functions.
/*
/* Patterns are separated by whitespace and/or commas. A pattern
/* is either a string, a file name (in which case the contents
/* of the file are substituted for the file name) or a type:name
/* lookup table specification. In order to reverse the result of
/* a pattern match, precede a non-file name pattern with an
/* exclamation point (!).
/*
/* match_list_init() performs initializations. The first argument is
/* a list of patterns. The second argument specifies how many match
/* functions follow.
/*
/* match_list_match() matches strings against the specified pattern
/* list, passing the first string to the first function given to
/* match_list_init(), the second string to the second function, and
/* so on.
/*
/* match_list_free() releases storage allocated by match_list_init().
/* DIAGNOSTICS
/* Fatal error: unable to open or read a match_list file; invalid
/* match_list pattern.
/* SEE ALSO
/* host_match(3) match hosts by name or by address
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/
/* System library. */
#include <sys_defs.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdarg.h>
/* Utility library. */
#include <msg.h>
#include <mymalloc.h>
#include <vstring.h>
#include <vstream.h>
#include <vstring_vstream.h>
#include <stringops.h>
#include <argv.h>
#include <dict.h>
#include <match_list.h>
/* Application-specific */
struct MATCH_LIST {
ARGV *patterns; /* one pattern each */
int match_count; /* match function/argument count */
MATCH_LIST_FN *match_func; /* match functions */
const char **match_args; /* match arguments */
};
/* match_list_parse - parse buffer, destroy buffer */
static ARGV *match_list_parse(ARGV *list, char *string)
{
const char *myname = "match_list_parse";
VSTRING *buf = 0;
VSTREAM *fp;
const char *delim = " ,\t\r\n";
char *bp = string;
char *pattern;
char *cp;
while ((pattern = mystrtok(&bp, delim)) != 0) {
if (*pattern == '/') { /* /file/name */
if (buf == 0)
buf = vstring_alloc(10);
if ((fp = vstream_fopen(pattern, O_RDONLY, 0)) == 0)
msg_fatal("%s: open file %s: %m", myname, pattern);
while (vstring_fgets(buf, fp))
if (vstring_str(buf)[0] != '#')
list = match_list_parse(list, vstring_str(buf));
if (vstream_fclose(fp))
msg_fatal("%s: read file %s: %m", myname, pattern);
} else if (strchr(pattern, ':') != 0) { /* type:table */
for (cp = pattern; *cp == '!'; cp++)
/* void */ ;
if (dict_handle(pattern) == 0)
dict_register(pattern,
dict_open(pattern, O_RDONLY, DICT_FLAG_LOCK));
argv_add(list, pattern, (char *) 0);
} else { /* other pattern */
argv_add(list, pattern, (char *) 0);
}
}
if (buf)
vstring_free(buf);
return (list);
}
/* match_list_init - initialize pattern list */
MATCH_LIST *match_list_init(const char *patterns, int match_count,...)
{
MATCH_LIST *list;
char *saved_patterns;
va_list ap;
int i;
list = (MATCH_LIST *) mymalloc(sizeof(*list));
list->match_count = match_count;
list->match_func =
(MATCH_LIST_FN *) mymalloc(match_count * sizeof(MATCH_LIST_FN));
list->match_args =
(const char **) mymalloc(match_count * sizeof(const char *));
va_start(ap, match_count);
for (i = 0; i < match_count; i++)
list->match_func[i] = va_arg(ap, MATCH_LIST_FN);
va_end(ap);
saved_patterns = mystrdup(patterns);
list->patterns = match_list_parse(argv_alloc(1), saved_patterns);
argv_terminate(list->patterns);
myfree(saved_patterns);
return (list);
}
/* match_list_match - match strings against pattern list */
int match_list_match(MATCH_LIST * list,...)
{
const char *myname = "match_list_match";
char **cpp;
char *pat;
int match;
int i;
va_list ap;
/*
* Iterate over all patterns in the list, stop at the first match.
*/
va_start(ap, list);
for (i = 0; i < list->match_count; i++)
list->match_args[i] = va_arg(ap, const char *);
va_end(ap);
for (cpp = list->patterns->argv; (pat = *cpp) != 0; cpp++) {
for (match = 1; *pat == '!'; pat++)
match = !match;
for (i = 0; i < list->match_count; i++)
if (list->match_func[i] (list->match_args[i], pat) != 0)
return (match);
}
if (msg_verbose)
for (i = 0; i < list->match_count; i++)
msg_info("%s: %s: no match", myname, list->match_args[i]);
return (0);
}
/* match_list_free - release storage */
void match_list_free(MATCH_LIST * list)
{
argv_free(list->patterns);
myfree((char *) list->match_func);
myfree((char *) list->match_args);
myfree((char *) list);
}