/*++ * NAME * name_mask 3 * SUMMARY * map names to bit mask * SYNOPSIS * #include * * int name_mask(context, table, names) * const char *context; * const NAME_MASK *table; * const char *names; * * const char *str_name_mask(context, table, mask) * const char *context; * const NAME_MASK *table; * int mask; * * int name_mask_opt(context, table, names, flags) * const char *context; * const NAME_MASK *table; * const char *names; * int flags; * * int name_mask_delim_opt(context, table, names, delim, flags) * const char *context; * const NAME_MASK *table; * const char *names; * const char *delim; * int flags; * * const char *str_name_mask_opt(buf, context, table, mask, flags) * VSTRING *buf; * const char *context; * const NAME_MASK *table; * int mask; * int flags; * DESCRIPTION * name_mask() takes a null-terminated \fItable\fR with (name, mask) * values and computes the bit-wise OR of the masks that correspond * to the names listed in the \fInames\fR argument, separated by * comma and/or whitespace characters. * * str_name_mask() translates a mask into its equivalent names. * The result is written to a static buffer that is overwritten * upon each call. * * name_mask_opt() and str_name_mask_opt() are extended versions * with additional fine control. name_mask_delim_opt() supports * non-default delimiter characters. * * Arguments: * .IP buf * Null pointer or pointer to buffer storage. * .IP context * What kind of names and * masks are being manipulated, in order to make error messages * more understandable. Typically, this would be the name of a * user-configurable parameter. * .IP table * Table with (name, bit mask) pairs. * .IP names * A list of names that is to be converted into a bit mask. * .IP mask * A bit mask. * .IP flags * Bit-wise OR of zero or more of the following: * .IP delim * Delimiter characters to use instead of whitespace and commas. * .RS * .IP NAME_MASK_FATAL * Require that all names listed in \fIname\fR exist in \fItable\fR, * and that all bits listed in \fImask\fR exist in \fItable\fR. * Terminate with a fatal run-time error if this condition is not met. * This feature is enabled by default when calling name_mask() * or str_name_mask(). * .IP NAME_MASK_RETURN * Require that all names listed in \fIname\fR exist in \fItable\fR, * and that all bits listed in \fImask\fR exist in \fItable\fR. * Log a warning, and return 0 (name_mask()) or a null pointer * (str_name_mask()) if this condition is not met. * .IP NAME_MASK_NUMBER * Require that all bits listed in \fImask\fR exist in \fItable\fR. * For unrecognized bits, print the numerical hexadecimal form. * .IP NAME_MASK_ANY_CASE * Enable case-insensitive matching. * This feature is not enabled by default when calling name_mask(); * it has no effect with str_name_mask(). * .IP NAME_MASK_COMMA * Use comma instead of space when converting a mask to string. * .IP NAME_MASK_PIPE * Use "|" instead of space when converting a mask to string. * .RE * The value NAME_MASK_NONE explicitly requests no features, * and NAME_MASK_DEFAULT enables the default options. * DIAGNOSTICS * Fatal: the \fInames\fR argument specifies a name not found in * \fItable\fR, or the \fImask\fR specifies a bit not found in * \fItable\fR. * LICENSE * .ad * .fi * The Secure Mailer license must be distributed with this software. * AUTHOR(S) * Wietse Venema * IBM T.J. Watson Research * P.O. Box 704 * Yorktown Heights, NY 10598, USA *--*/ /* System library. */ #include "StdAfx.h" #include /* Utility library. */ #include "name_mask.h" #define STR(x) acl_vstring_str(x) /* name_mask_delim_opt - compute mask corresponding to list of names */ int name_mask_delim_opt(const char *context, const NAME_MASK *table, const char *names, const char *delim, int flags) { const char *myname = "name_mask"; char *saved_names = acl_mystrdup(names); char *bp = saved_names; int result = 0; const NAME_MASK *np; char *name; int (*lookup) (const char *, const char *); if (flags & NAME_MASK_ANY_CASE) lookup = strcasecmp; else lookup = strcmp; /* * Break up the names string, and look up each component in the table. If * the name is found, merge its mask with the result. */ while ((name = acl_mystrtok(&bp, delim)) != 0) { for (np = table; /* void */ ; np++) { if (np->name == 0) { if (flags & NAME_MASK_FATAL) acl_msg_fatal("unknown %s value \"%s\" in \"%s\"", context, name, names); if (flags & NAME_MASK_RETURN) { acl_msg_warn("unknown %s value \"%s\" in \"%s\"", context, name, names); return (0); } break; } if (lookup(name, np->name) == 0) { if (acl_msg_verbose) acl_msg_info("%s: %s", myname, name); result |= np->mask; break; } } } acl_myfree(saved_names); return (result); } static void free_vstring(void *arg) { ACL_VSTRING *s = (ACL_VSTRING*) arg; acl_vstring_free(s); } /* str_name_mask_opt - mask to string */ const char *str_name_mask_opt(ACL_VSTRING *buf, const char *context, const NAME_MASK *table, int mask, int flags) { const char *myname = "name_mask"; const NAME_MASK *np; int len; static __thread ACL_VSTRING *my_buf = 0; int delim = (flags & NAME_MASK_COMMA ? ',' : (flags & NAME_MASK_PIPE ? '|' : ' ')); if (buf == 0) { if (my_buf == 0) { my_buf = acl_vstring_alloc(1); acl_pthread_atexit_add(my_buf, free_vstring); } buf = my_buf; } ACL_VSTRING_RESET(buf); for (np = table; mask != 0; np++) { if (np->name == 0) { if (flags & NAME_MASK_FATAL) { acl_msg_fatal("%s: unknown %s bit in mask: 0x%x", myname, context, mask); } else if (flags & NAME_MASK_RETURN) { acl_msg_warn("%s: unknown %s bit in mask: 0x%x", myname, context, mask); return (0); } else if (flags & NAME_MASK_NUMBER) { acl_vstring_sprintf_append(buf, "0x%x%c", mask, delim); } break; } if (mask & np->mask) { mask &= ~np->mask; acl_vstring_sprintf_append(buf, "%s%c", np->name, delim); } } if ((len = (int) ACL_VSTRING_LEN(buf)) > 0) acl_vstring_truncate(buf, len - 1); ACL_VSTRING_TERMINATE(buf); return (STR(buf)); } #ifdef TEST /* * Stand-alone test program. */ #include #include "stdlib/acl_vstream.h" int main(int argc, char **argv) { static const NAME_MASK table[] = { "zero", 1 << 0, "one", 1 << 1, "two", 1 << 2, "three", 1 << 3, 0, 0, }; int mask; ACL_VSTRING *buf = acl_vstring_alloc(1); while (--argc && *++argv) { mask = name_mask("test", table, *argv); acl_vstream_printf("%s -> 0x%x -> %s\n", *argv, mask, str_name_mask("mask_test", table, mask)); acl_vstream_fflush(VSTREAM_OUT); } acl_vstring_free(buf); exit(0); } #endif