No empty .Rs/.Re
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / util / match_list.c
blob4786735d71b739ba9d41b5c6003f9c27486f5089
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* match_list 3
6 /* SUMMARY
7 /* generic list-based pattern matching
8 /* SYNOPSIS
9 /* #include <match_list.h>
11 /* MATCH_LIST *match_list_init(flags, pattern_list, count, func,...)
12 /* int flags;
13 /* const char *pattern_list;
14 /* int count;
15 /* int (*func)(int flags, const char *string, const char *pattern);
17 /* int match_list_match(list, string,...)
18 /* MATCH_LIST *list;
19 /* const char *string;
21 /* void match_list_free(list)
22 /* MATCH_LIST *list;
23 /* DESCRIPTION
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:
35 /* .RS
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.
40 /* .RE
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
48 /* so on.
50 /* match_list_free() releases storage allocated by match_list_init().
51 /* DIAGNOSTICS
52 /* Fatal error: unable to open or read a match_list file; invalid
53 /* match_list pattern.
54 /* SEE ALSO
55 /* host_match(3) match hosts by name or by address
56 /* LICENSE
57 /* .ad
58 /* .fi
59 /* The Secure Mailer license must be distributed with this software.
60 /* AUTHOR(S)
61 /* Wietse Venema
62 /* IBM T.J. Watson Research
63 /* P.O. Box 704
64 /* Yorktown Heights, NY 10598, USA
65 /*--*/
67 /* System library. */
69 #include <sys_defs.h>
70 #include <unistd.h>
71 #include <string.h>
72 #include <fcntl.h>
73 #include <stdlib.h>
74 #include <stdarg.h>
76 /* Utility library. */
78 #include <msg.h>
79 #include <mymalloc.h>
80 #include <vstring.h>
81 #include <vstream.h>
82 #include <vstring_vstream.h>
83 #include <stringops.h>
84 #include <argv.h>
85 #include <dict.h>
86 #include <match_ops.h>
87 #include <match_list.h>
89 /* Application-specific */
91 struct MATCH_LIST {
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);
108 VSTREAM *fp;
109 const char *delim = " ,\t\r\n";
110 char *bp = string;
111 char *start;
112 char *item;
113 char *map_type_name_flags;
114 int match;
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++)
122 match = !match;
123 if (*item == 0)
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);
149 vstring_free(buf);
150 return (list);
153 /* match_list_init - initialize pattern list */
155 MATCH_LIST *match_list_init(int flags, const char *patterns, int match_count,...)
157 MATCH_LIST *list;
158 char *saved_patterns;
159 va_list ap;
160 int i;
162 if (flags & ~MATCH_FLAG_ALL)
163 msg_panic("match_list_init: bad flags 0x%x", flags);
165 list = (MATCH_LIST *) mymalloc(sizeof(*list));
166 list->flags = flags;
167 list->match_count = match_count;
168 list->match_func =
169 (MATCH_LIST_FN *) mymalloc(match_count * sizeof(MATCH_LIST_FN));
170 list->match_args =
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);
175 va_end(ap);
177 #define DO_MATCH 1
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);
183 return (list);
186 /* match_list_match - match strings against pattern list */
188 int match_list_match(MATCH_LIST * list,...)
190 const char *myname = "match_list_match";
191 char **cpp;
192 char *pat;
193 int match;
194 int i;
195 va_list ap;
198 * Iterate over all patterns in the list, stop at the first match.
200 va_start(ap, list);
201 for (i = 0; i < list->match_count; i++)
202 list->match_args[i] = va_arg(ap, const char *);
203 va_end(ap);
205 for (cpp = list->patterns->argv; (pat = *cpp) != 0; cpp++) {
206 for (match = 1; *pat == '!'; pat++)
207 match = !match;
208 for (i = 0; i < list->match_count; i++)
209 if (list->match_func[i] (list->flags, list->match_args[i], pat))
210 return (match);
212 if (msg_verbose)
213 for (i = 0; i < list->match_count; i++)
214 msg_info("%s: %s: no match", myname, list->match_args[i]);
215 return (0);
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);