mirror of
https://gitee.com/acl-dev/acl.git
synced 2024-12-05 05:18:53 +08:00
256 lines
6.9 KiB
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
|
|
|