1 /* $NetBSD: name_mask.c,v 1.1.1.1 2009/06/23 10:09:00 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* name_mask 3 6 /* SUMMARY 7 /* map names to bit mask 8 /* SYNOPSIS 9 /* #include <name_mask.h> 10 /* 11 /* int name_mask(context, table, names) 12 /* const char *context; 13 /* const NAME_MASK *table; 14 /* const char *names; 15 /* 16 /* const char *str_name_mask(context, table, mask) 17 /* const char *context; 18 /* const NAME_MASK *table; 19 /* int mask; 20 /* 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; 26 /* 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; 33 /* 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. 45 /* 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. 49 /* 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. 53 /* 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 /*--*/ 112 113 /* System library. */ 114 115 #include <sys_defs.h> 116 #include <string.h> 117 118 #ifdef STRCASECMP_IN_STRINGS_H 119 #include <strings.h> 120 #endif 121 122 /* Utility library. */ 123 124 #include <msg.h> 125 #include <mymalloc.h> 126 #include <stringops.h> 127 #include <name_mask.h> 128 #include <vstring.h> 129 130 #define STR(x) vstring_str(x) 131 132 /* name_mask_delim_opt - compute mask corresponding to list of names */ 133 134 int name_mask_delim_opt(const char *context, const NAME_MASK *table, 135 const char *names, const char *delim, int flags) 136 { 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 *); 144 145 if (flags & NAME_MASK_ANY_CASE) 146 lookup = strcasecmp; 147 else 148 lookup = strcmp; 149 150 /* 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. 153 */ 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); 164 } 165 break; 166 } 167 if (lookup(name, np->name) == 0) { 168 if (msg_verbose) 169 msg_info("%s: %s", myname, name); 170 result |= np->mask; 171 break; 172 } 173 } 174 } 175 myfree(saved_names); 176 return (result); 177 } 178 179 /* str_name_mask_opt - mask to string */ 180 181 const char *str_name_mask_opt(VSTRING *buf, const char *context, 182 const NAME_MASK *table, 183 int mask, int flags) 184 { 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 ? '|' : ' ')); 191 192 if (buf == 0) { 193 if (my_buf == 0) 194 my_buf = vstring_alloc(1); 195 buf = my_buf; 196 } 197 VSTRING_RESET(buf); 198 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); 210 } 211 break; 212 } 213 if (mask & np->mask) { 214 mask &= ~np->mask; 215 vstring_sprintf_append(buf, "%s%c", np->name, delim); 216 } 217 } 218 if ((len = VSTRING_LEN(buf)) > 0) 219 vstring_truncate(buf, len - 1); 220 VSTRING_TERMINATE(buf); 221 222 return (STR(buf)); 223 } 224 225 #ifdef TEST 226 227 /* 228 * Stand-alone test program. 229 */ 230 #include <stdlib.h> 231 #include <vstream.h> 232 233 int main(int argc, char **argv) 234 { 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, 241 }; 242 int mask; 243 VSTRING *buf = vstring_alloc(1); 244 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); 250 } 251 vstring_free(buf); 252 exit(0); 253 } 254 255 #endif 256