7 /* generic list-based pattern matching
9 /* #include <match_list.h>
11 /* MATCH_LIST *match_list_init(flags, pattern_list, count, func,...)
13 /* const char *pattern_list;
15 /* int (*func)(int flags, const char *string, const char *pattern);
17 /* int match_list_match(list, string,...)
19 /* const char *string;
21 /* void match_list_free(list)
24 /* This module implements a framework for tests for list membership.
25 /* The actual tests are done by user-supplied functions.
27 /* Patterns are separated by whitespace and/or commas. A pattern
28 /* is either a string, a file name (in which case the contents
29 /* of the file are substituted for the file name) or a type:name
30 /* lookup table specification. In order to reverse the result of
31 /* a pattern match, precede a pattern with an exclamation point (!).
33 /* match_list_init() performs initializations. The flags argument
34 /* specifies the bit-wise OR of zero or more of the following:
36 /* .IP MATCH_FLAG_PARENT
37 /* The hostname pattern foo.com matches any name within the domain
38 /* foo.com. If this flag is cleared, foo.com matches itself
39 /* only, and .foo.com matches any name below the domain foo.com.
41 /* Specify MATCH_FLAG_NONE to request none of the above.
42 /* The pattern_list argument specifies a list of patterns. The third
43 /* argument specifies how many match functions follow.
45 /* match_list_match() matches strings against the specified pattern
46 /* list, passing the first string to the first function given to
47 /* match_list_init(), the second string to the second function, and
50 /* match_list_free() releases storage allocated by match_list_init().
52 /* Fatal error: unable to open or read a match_list file; invalid
53 /* match_list pattern.
55 /* host_match(3) match hosts by name or by address
59 /* The Secure Mailer license must be distributed with this software.
62 /* IBM T.J. Watson Research
64 /* Yorktown Heights, NY 10598, USA
76 /* Utility library. */
82 #include <vstring_vstream.h>
83 #include <stringops.h>
86 #include <match_ops.h>
87 #include <match_list.h>
89 /* Application-specific */
92 int flags
; /* processing options */
93 ARGV
*patterns
; /* one pattern each */
94 int match_count
; /* match function/argument count */
95 MATCH_LIST_FN
*match_func
; /* match functions */
96 const char **match_args
; /* match arguments */
99 #define MATCH_DICTIONARY(pattern) \
100 ((pattern)[0] != '[' && strchr((pattern), ':') != 0)
102 /* match_list_parse - parse buffer, destroy buffer */
104 static ARGV
*match_list_parse(ARGV
*list
, char *string
, int init_match
)
106 const char *myname
= "match_list_parse";
107 VSTRING
*buf
= vstring_alloc(10);
109 const char *delim
= " ,\t\r\n";
113 char *map_type_name_flags
;
117 * /filename contents are expanded in-line. To support !/filename we
118 * prepend the negation operator to each item from the file.
120 while ((start
= mystrtok(&bp
, delim
)) != 0) {
121 for (match
= init_match
, item
= start
; *item
== '!'; item
++)
124 msg_fatal("%s: no pattern after '!'", myname
);
125 if (*item
== '/') { /* /file/name */
126 if ((fp
= vstream_fopen(item
, O_RDONLY
, 0)) == 0)
127 msg_fatal("%s: open file %s: %m", myname
, item
);
128 while (vstring_fgets(buf
, fp
))
129 if (vstring_str(buf
)[0] != '#')
130 list
= match_list_parse(list
, vstring_str(buf
), match
);
131 if (vstream_fclose(fp
))
132 msg_fatal("%s: read file %s: %m", myname
, item
);
133 } else if (MATCH_DICTIONARY(item
)) { /* type:table */
134 #define OPEN_FLAGS O_RDONLY
135 #define DICT_FLAGS (DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX)
136 #define STR(x) vstring_str(x)
137 vstring_sprintf(buf
, "%s%s(%o,%s)", match
? "" : "!",
138 item
, OPEN_FLAGS
, dict_flags_str(DICT_FLAGS
));
139 map_type_name_flags
= STR(buf
) + (match
== 0);
140 if (dict_handle(map_type_name_flags
) == 0)
141 dict_register(map_type_name_flags
,
142 dict_open(item
, OPEN_FLAGS
, DICT_FLAGS
));
143 argv_add(list
, STR(buf
), (char *) 0);
144 } else { /* other pattern */
145 argv_add(list
, match
? item
:
146 STR(vstring_sprintf(buf
, "!%s", item
)), (char *) 0);
153 /* match_list_init - initialize pattern list */
155 MATCH_LIST
*match_list_init(int flags
, const char *patterns
, int match_count
,...)
158 char *saved_patterns
;
162 if (flags
& ~MATCH_FLAG_ALL
)
163 msg_panic("match_list_init: bad flags 0x%x", flags
);
165 list
= (MATCH_LIST
*) mymalloc(sizeof(*list
));
167 list
->match_count
= match_count
;
169 (MATCH_LIST_FN
*) mymalloc(match_count
* sizeof(MATCH_LIST_FN
));
171 (const char **) mymalloc(match_count
* sizeof(const char *));
172 va_start(ap
, match_count
);
173 for (i
= 0; i
< match_count
; i
++)
174 list
->match_func
[i
] = va_arg(ap
, MATCH_LIST_FN
);
179 saved_patterns
= mystrdup(patterns
);
180 list
->patterns
= match_list_parse(argv_alloc(1), saved_patterns
, DO_MATCH
);
181 argv_terminate(list
->patterns
);
182 myfree(saved_patterns
);
186 /* match_list_match - match strings against pattern list */
188 int match_list_match(MATCH_LIST
* list
,...)
190 const char *myname
= "match_list_match";
198 * Iterate over all patterns in the list, stop at the first match.
201 for (i
= 0; i
< list
->match_count
; i
++)
202 list
->match_args
[i
] = va_arg(ap
, const char *);
205 for (cpp
= list
->patterns
->argv
; (pat
= *cpp
) != 0; cpp
++) {
206 for (match
= 1; *pat
== '!'; pat
++)
208 for (i
= 0; i
< list
->match_count
; i
++)
209 if (list
->match_func
[i
] (list
->flags
, list
->match_args
[i
], pat
))
213 for (i
= 0; i
< list
->match_count
; i
++)
214 msg_info("%s: %s: no match", myname
, list
->match_args
[i
]);
218 /* match_list_free - release storage */
220 void match_list_free(MATCH_LIST
* list
)
222 argv_free(list
->patterns
);
223 myfree((char *) list
->match_func
);
224 myfree((char *) list
->match_args
);
225 myfree((char *) list
);