Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / util / name_mask.c
blobb2443b5b503e51334591b8bceca6b4dbeee7afe9
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* name_mask 3
6 /* SUMMARY
7 /* map names to bit mask
8 /* SYNOPSIS
9 /* #include <name_mask.h>
11 /* int name_mask(context, table, names)
12 /* const char *context;
13 /* const NAME_MASK *table;
14 /* const char *names;
16 /* const char *str_name_mask(context, table, mask)
17 /* const char *context;
18 /* const NAME_MASK *table;
19 /* int mask;
21 /* int name_mask_opt(context, table, names, flags)
22 /* const char *context;
23 /* const NAME_MASK *table;
24 /* const char *names;
25 /* int flags;
27 /* int name_mask_delim_opt(context, table, names, delim, flags)
28 /* const char *context;
29 /* const NAME_MASK *table;
30 /* const char *names;
31 /* const char *delim;
32 /* int flags;
34 /* const char *str_name_mask_opt(buf, context, table, mask, flags)
35 /* VSTRING *buf;
36 /* const char *context;
37 /* const NAME_MASK *table;
38 /* int mask;
39 /* int flags;
40 /* DESCRIPTION
41 /* name_mask() takes a null-terminated \fItable\fR with (name, mask)
42 /* values and computes the bit-wise OR of the masks that correspond
43 /* to the names listed in the \fInames\fR argument, separated by
44 /* comma and/or whitespace characters.
46 /* str_name_mask() translates a mask into its equivalent names.
47 /* The result is written to a static buffer that is overwritten
48 /* upon each call.
50 /* name_mask_opt() and str_name_mask_opt() are extended versions
51 /* with additional fine control. name_mask_delim_opt() supports
52 /* non-default delimiter characters.
54 /* Arguments:
55 /* .IP buf
56 /* Null pointer or pointer to buffer storage.
57 /* .IP context
58 /* What kind of names and
59 /* masks are being manipulated, in order to make error messages
60 /* more understandable. Typically, this would be the name of a
61 /* user-configurable parameter.
62 /* .IP table
63 /* Table with (name, bit mask) pairs.
64 /* .IP names
65 /* A list of names that is to be converted into a bit mask.
66 /* .IP mask
67 /* A bit mask.
68 /* .IP flags
69 /* Bit-wise OR of zero or more of the following:
70 /* .IP delim
71 /* Delimiter characters to use instead of whitespace and commas.
72 /* .RS
73 /* .IP NAME_MASK_FATAL
74 /* Require that all names listed in \fIname\fR exist in \fItable\fR,
75 /* and that all bits listed in \fImask\fR exist in \fItable\fR.
76 /* Terminate with a fatal run-time error if this condition is not met.
77 /* This feature is enabled by default when calling name_mask()
78 /* or str_name_mask().
79 /* .IP NAME_MASK_RETURN
80 /* Require that all names listed in \fIname\fR exist in \fItable\fR,
81 /* and that all bits listed in \fImask\fR exist in \fItable\fR.
82 /* Log a warning, and return 0 (name_mask()) or a null pointer
83 /* (str_name_mask()) if this condition is not met.
84 /* .IP NAME_MASK_NUMBER
85 /* Require that all bits listed in \fImask\fR exist in \fItable\fR.
86 /* For unrecognized bits, print the numerical hexadecimal form.
87 /* .IP NAME_MASK_ANY_CASE
88 /* Enable case-insensitive matching.
89 /* This feature is not enabled by default when calling name_mask();
90 /* it has no effect with str_name_mask().
91 /* .IP NAME_MASK_COMMA
92 /* Use comma instead of space when converting a mask to string.
93 /* .IP NAME_MASK_PIPE
94 /* Use "|" instead of space when converting a mask to string.
95 /* .RE
96 /* The value NAME_MASK_NONE explicitly requests no features,
97 /* and NAME_MASK_DEFAULT enables the default options.
98 /* DIAGNOSTICS
99 /* Fatal: the \fInames\fR argument specifies a name not found in
100 /* \fItable\fR, or the \fImask\fR specifies a bit not found in
101 /* \fItable\fR.
102 /* LICENSE
103 /* .ad
104 /* .fi
105 /* The Secure Mailer license must be distributed with this software.
106 /* AUTHOR(S)
107 /* Wietse Venema
108 /* IBM T.J. Watson Research
109 /* P.O. Box 704
110 /* Yorktown Heights, NY 10598, USA
111 /*--*/
113 /* System library. */
115 #include <sys_defs.h>
116 #include <string.h>
118 #ifdef STRCASECMP_IN_STRINGS_H
119 #include <strings.h>
120 #endif
122 /* Utility library. */
124 #include <msg.h>
125 #include <mymalloc.h>
126 #include <stringops.h>
127 #include <name_mask.h>
128 #include <vstring.h>
130 #define STR(x) vstring_str(x)
132 /* name_mask_delim_opt - compute mask corresponding to list of names */
134 int name_mask_delim_opt(const char *context, const NAME_MASK *table,
135 const char *names, const char *delim, int flags)
137 const char *myname = "name_mask";
138 char *saved_names = mystrdup(names);
139 char *bp = saved_names;
140 int result = 0;
141 const NAME_MASK *np;
142 char *name;
143 int (*lookup) (const char *, const char *);
145 if (flags & NAME_MASK_ANY_CASE)
146 lookup = strcasecmp;
147 else
148 lookup = strcmp;
151 * Break up the names string, and look up each component in the table. If
152 * the name is found, merge its mask with the result.
154 while ((name = mystrtok(&bp, delim)) != 0) {
155 for (np = table; /* void */ ; np++) {
156 if (np->name == 0) {
157 if (flags & NAME_MASK_FATAL)
158 msg_fatal("unknown %s value \"%s\" in \"%s\"",
159 context, name, names);
160 if (flags & NAME_MASK_RETURN) {
161 msg_warn("unknown %s value \"%s\" in \"%s\"",
162 context, name, names);
163 return (0);
165 break;
167 if (lookup(name, np->name) == 0) {
168 if (msg_verbose)
169 msg_info("%s: %s", myname, name);
170 result |= np->mask;
171 break;
175 myfree(saved_names);
176 return (result);
179 /* str_name_mask_opt - mask to string */
181 const char *str_name_mask_opt(VSTRING *buf, const char *context,
182 const NAME_MASK *table,
183 int mask, int flags)
185 const char *myname = "name_mask";
186 const NAME_MASK *np;
187 int len;
188 static VSTRING *my_buf = 0;
189 int delim = (flags & NAME_MASK_COMMA ? ',' :
190 (flags & NAME_MASK_PIPE ? '|' : ' '));
192 if (buf == 0) {
193 if (my_buf == 0)
194 my_buf = vstring_alloc(1);
195 buf = my_buf;
197 VSTRING_RESET(buf);
199 for (np = table; mask != 0; np++) {
200 if (np->name == 0) {
201 if (flags & NAME_MASK_FATAL) {
202 msg_fatal("%s: unknown %s bit in mask: 0x%x",
203 myname, context, mask);
204 } else if (flags & NAME_MASK_RETURN) {
205 msg_warn("%s: unknown %s bit in mask: 0x%x",
206 myname, context, mask);
207 return (0);
208 } else if (flags & NAME_MASK_NUMBER) {
209 vstring_sprintf_append(buf, "0x%x%c", mask, delim);
211 break;
213 if (mask & np->mask) {
214 mask &= ~np->mask;
215 vstring_sprintf_append(buf, "%s%c", np->name, delim);
218 if ((len = VSTRING_LEN(buf)) > 0)
219 vstring_truncate(buf, len - 1);
220 VSTRING_TERMINATE(buf);
222 return (STR(buf));
225 #ifdef TEST
228 * Stand-alone test program.
230 #include <stdlib.h>
231 #include <vstream.h>
233 int main(int argc, char **argv)
235 static const NAME_MASK table[] = {
236 "zero", 1 << 0,
237 "one", 1 << 1,
238 "two", 1 << 2,
239 "three", 1 << 3,
240 0, 0,
242 int mask;
243 VSTRING *buf = vstring_alloc(1);
245 while (--argc && *++argv) {
246 mask = name_mask("test", table, *argv);
247 vstream_printf("%s -> 0x%x -> %s\n",
248 *argv, mask, str_name_mask("mask_test", table, mask));
249 vstream_fflush(VSTREAM_OUT);
251 vstring_free(buf);
252 exit(0);
255 #endif