#include <sys_defs.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdarg.h>
#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_ops.h>
#include <match_list.h>
struct MATCH_LIST {
int flags;
ARGV *patterns;
int match_count;
MATCH_LIST_FN *match_func;
const char **match_args;
};
#define MATCH_DICTIONARY(pattern) \
((pattern)[0] != '[' && strchr((pattern), ':') != 0)
static ARGV *match_list_parse(ARGV *list, char *string, int init_match)
{
const char *myname = "match_list_parse";
VSTRING *buf = vstring_alloc(10);
VSTREAM *fp;
const char *delim = " ,\t\r\n";
char *bp = string;
char *start;
char *item;
char *map_type_name_flags;
int match;
while ((start = mystrtok(&bp, delim)) != 0) {
for (match = init_match, item = start; *item == '!'; item++)
match = !match;
if (*item == 0)
msg_fatal("%s: no pattern after '!'", myname);
if (*item == '/') {
if ((fp = vstream_fopen(item, O_RDONLY, 0)) == 0)
msg_fatal("%s: open file %s: %m", myname, item);
while (vstring_fgets(buf, fp))
if (vstring_str(buf)[0] != '#')
list = match_list_parse(list, vstring_str(buf), match);
if (vstream_fclose(fp))
msg_fatal("%s: read file %s: %m", myname, item);
} else if (MATCH_DICTIONARY(item)) {
#define OPEN_FLAGS O_RDONLY
#define DICT_FLAGS (DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX)
#define STR(x) vstring_str(x)
vstring_sprintf(buf, "%s%s(%o,%s)", match ? "" : "!",
item, OPEN_FLAGS, dict_flags_str(DICT_FLAGS));
map_type_name_flags = STR(buf) + (match == 0);
if (dict_handle(map_type_name_flags) == 0)
dict_register(map_type_name_flags,
dict_open(item, OPEN_FLAGS, DICT_FLAGS));
argv_add(list, STR(buf), (char *) 0);
} else {
argv_add(list, match ? item :
STR(vstring_sprintf(buf, "!%s", item)), (char *) 0);
}
}
vstring_free(buf);
return (list);
}
MATCH_LIST *match_list_init(int flags, const char *patterns, int match_count,...)
{
MATCH_LIST *list;
char *saved_patterns;
va_list ap;
int i;
if (flags & ~MATCH_FLAG_ALL)
msg_panic("match_list_init: bad flags 0x%x", flags);
list = (MATCH_LIST *) mymalloc(sizeof(*list));
list->flags = flags;
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);
#define DO_MATCH 1
saved_patterns = mystrdup(patterns);
list->patterns = match_list_parse(argv_alloc(1), saved_patterns, DO_MATCH);
argv_terminate(list->patterns);
myfree(saved_patterns);
return (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;
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->flags, list->match_args[i], pat))
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);
}
void match_list_free(MATCH_LIST * list)
{
argv_free(list->patterns);
myfree((char *) list->match_func);
myfree((char *) list->match_args);
myfree((char *) list);
}