acl/lib_tls/util/name_mask.c

256 lines
6.9 KiB
C

/*++
* NAME
* name_mask 3
* SUMMARY
* map names to bit mask
* SYNOPSIS
* #include <name_mask.h>
*
* 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 <string.h>
/* 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 <stdlib.h>
#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