Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Postfix/src/util/   (Postfix Mailserver Version 3.11©)  Datei vom 18.7.2025 mit Größe 15 kB image not shown  

Quelle  name_mask.c

  Sprache: 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;
/*
/* long long_name_mask(context, table, names)
/* const char *context;
/* const LONG_NAME_MASK *table;
/* const char *names;
/*
/* const char *str_name_mask(context, table, mask)
/* const char *context;
/* const NAME_MASK *table;
/* int mask;
/*
/* const char *str_long_name_mask(context, table, mask)
/* const char *context;
/* const LONG_NAME_MASK *table;
/* long mask;
/*
/* int name_mask_opt(context, table, names, flags)
/* const char *context;
/* const NAME_MASK *table;
/* const char *names;
/* int flags;
/*
/* long long_name_mask_opt(context, table, names, flags)
/* const char *context;
/* const LONG_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;
/*
/* long long_name_mask_delim_opt(context, table, names, delim, flags)
/* const char *context;
/* const LONG_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;
/*
/* const char *str_name_mask_delim_opt(
/* VSTRING *buf,
/* const char *context,
/* const NAME_MASK *table,
/* int mask,
/* const char *delim,
/* int flags)
/*
/* const char *str_long_name_mask_opt(buf, context, table, mask, flags)
/* VSTRING *buf;
/* const char *context;
/* const LONG_NAME_MASK *table;
/* long 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. The "long_" version returns
/* a "long int" bitmask, rather than an "int" bitmask.
/*
/* str_name_mask() translates a mask into its equivalent names.
/* The result is written to a static buffer that is overwritten
/* upon each call. The "long_" version converts a "long int"
/* bitmask, rather than an "int" bitmask.
/*
/* 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 delim
/* When converting from string to mask, the set of delimiter
/* characters to use instead of whitespace and commas. When
/* converting from mask to string, the delimiter string to use
/* instead what may be specified with flags.
/* .IP flags
/* Bit-wise OR of one or more of the following.  Where features
/* would have conflicting results (e.g., FATAL versus IGNORE),
/* the feature that takes precedence is described first.
/*
/* When converting from string to mask, at least one of the
/* following must be specified: NAME_MASK_FATAL, NAME_MASK_RETURN,
/* NAME_MASK_WARN or NAME_MASK_IGNORE.
/*
/* When converting from mask to string, at least one of the
/* following must be specified: NAME_MASK_NUMBER, NAME_MASK_FATAL,
/* NAME_MASK_RETURN, NAME_MASK_WARN or NAME_MASK_IGNORE.
/* .RS
/* .IP NAME_MASK_NUMBER
/* When converting from string to mask, accept hexadecimal
/* inputs starting with "0x" followed by hexadecimal digits.
/* Each hexadecimal input may specify multiple bits.  This
/* feature is ignored for hexadecimal inputs that cannot be
/* converted (malformed, out of range, etc.).
/*
/* When converting from mask to string, represent bits not
/* defined in \fItable\fR as "0x" followed by hexadecimal
/* digits. This conversion always succeeds.
/* .IP NAME_MASK_FATAL
/* Require that all names listed in \fIname\fR exist in
/* \fItable\fR or that they can be parsed as a hexadecimal
/* string, and require that all bits listed in \fImask\fR exist
/* in \fItable\fR or that they can be converted to hexadecimal
/* string.  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 or that they can be parsed as a hexadecimal
/* string, and require that all bits listed in \fImask\fR exist
/* in \fItable\fR or that they can be converted to hexadecimal
/* string.  Log a warning, and return 0 (name_mask()) or a
/* null pointer (str_name_mask()) if this condition is not
/* met.  This feature is not enabled by default when calling
/* name_mask() or str_name_mask().
/* .IP NAME_MASK_WARN
/* Require that all names listed in \fIname\fR exist in
/* \fItable\fR or that they can be parsed as a hexadecimal
/* string, and require that all bits listed in \fImask\fR exist
/* in \fItable\fR or that they can be converted to hexadecimal
/* string.  Log a warning if this condition is not met, continue
/* processing, and return all valid bits or names.  This feature
/* is not enabled by default when calling name_mask() or
/* str_name_mask().
/* .IP NAME_MASK_IGNORE
/* Silently ignore names listed in \fIname\fR that don't exist
/* in \fItable\fR and that can't be parsed as a hexadecimal
/* string, and silently ignore bits listed in \fImask\fR that
/* don't exist in \fItable\fR and that can't be converted to
/* hexadecimal string.
/* .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 <sys_defs.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>

#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
#endif

/* Utility library. */

#include <msg.h>
#include <mymalloc.h>
#include <stringops.h>
#include <name_mask.h>
#include <vstring.h>

static int hex_to_ulong(char *, unsigned longunsigned long *);

#define STR(x) 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 = mystrdup(names);
    char   *bp = saved_names;
    int     result = 0;
    const NAME_MASK *np;
    char   *name;
    int     (*lookup) (const char *, const char *);
    unsigned long ulval;

    if ((flags & NAME_MASK_REQUIRED) == 0)
 msg_panic("%s: missing NAME_MASK_FATAL/RETURN/WARN/IGNORE flag",
    myname);

    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 = mystrtok(&bp, delim)) != 0) {
 for (np = table; /* void */ ; np++) {
     if (np->name == 0) {
  if ((flags & NAME_MASK_NUMBER)
      && hex_to_ulong(name, ~0U, &ulval)) {
      result |= (unsigned int) ulval;
  } else if (flags & NAME_MASK_FATAL) {
      msg_fatal("unknown %s value \"%s\" in \"%s\"",
         context, name, names);
  } else if (flags & NAME_MASK_RETURN) {
      msg_warn("unknown %s value \"%s\" in \"%s\"",
        context, name, names);
      myfree(saved_names);
      return (0);
  } else if (flags & NAME_MASK_WARN) {
      msg_warn("unknown %s value \"%s\" in \"%s\"",
        context, name, names);
  }
  break;
     }
     if (lookup(name, np->name) == 0) {
  if (msg_verbose)
      msg_info("%s: %s", myname, name);
  result |= np->mask;
  break;
     }
 }
    }
    myfree(saved_names);
    return (result);
}

/* str_name_mask_delim_opt - mask to string */

const char *str_name_mask_delim_opt(VSTRING *buf, const char *context,
                const NAME_MASK *table,
                int mask, const char *delim,
                int flags)
{
    const char *myname = "str_name_mask";
    const NAME_MASK *np;
    ssize_t len;
    static VSTRING *my_buf = 0;

    if ((flags & STR_NAME_MASK_REQUIRED) == 0)
 msg_panic("%s: missing NAME_MASK_NUMBER/FATAL/RETURN/WARN/IGNORE flag",
    myname);

    if (buf == 0) {
 if (my_buf == 0)
     my_buf = vstring_alloc(1);
 buf = my_buf;
    }
    VSTRING_RESET(buf);

    for (np = table; mask != 0; np++) {
 if (np->name == 0) {
     if (flags & NAME_MASK_NUMBER) {
  vstring_sprintf_append(buf, "0x%x%s", mask, delim);
     } else if (flags & NAME_MASK_FATAL) {
  msg_fatal("%s: unknown %s bit in mask: 0x%x",
     myname, context, mask);
     } else if (flags & NAME_MASK_RETURN) {
  msg_warn("%s: unknown %s bit in mask: 0x%x",
    myname, context, mask);
  return (0);
     } else if (flags & NAME_MASK_WARN) {
  msg_warn("%s: unknown %s bit in mask: 0x%x",
    myname, context, mask);
     }
     break;
 }
 if (mask & np->mask) {
     mask &= ~np->mask;
     vstring_sprintf_append(buf, "%s%s", np->name, delim);
 }
    }
    if ((len = VSTRING_LEN(buf)) > 0)
 vstring_truncate(buf, len - strlen(delim));
    VSTRING_TERMINATE(buf);

    return (STR(buf));
}

/* str_name_mask_opt - mask to string */

const char *str_name_mask_opt(VSTRING *buf, const char *context,
                 const NAME_MASK *table,
                 int mask, int flags)
{
    const char *delim = (flags & NAME_MASK_COMMA ? "," :
    (flags & NAME_MASK_PIPE ? "|" : " "));

    return (str_name_mask_delim_opt(buf, context, table, mask, delim, flags));
}

/* long_name_mask_delim_opt - compute mask corresponding to list of names */

long    long_name_mask_delim_opt(const char *context,
             const LONG_NAME_MASK *table,
                  const char *names, const char *delim,
             int flags)
{
    const char *myname = "name_mask";
    char   *saved_names = mystrdup(names);
    char   *bp = saved_names;
    long    result = 0;
    const LONG_NAME_MASK *np;
    char   *name;
    int     (*lookup) (const char *, const char *);
    unsigned long ulval;

    if ((flags & NAME_MASK_REQUIRED) == 0)
 msg_panic("%s: missing NAME_MASK_FATAL/RETURN/WARN/IGNORE flag",
    myname);

    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 = mystrtok(&bp, delim)) != 0) {
 for (np = table; /* void */ ; np++) {
     if (np->name == 0) {
  if ((flags & NAME_MASK_NUMBER)
      && hex_to_ulong(name, ~0UL, &ulval)) {
      result |= ulval;
  } else if (flags & NAME_MASK_FATAL) {
      msg_fatal("unknown %s value \"%s\" in \"%s\"",
         context, name, names);
  } else if (flags & NAME_MASK_RETURN) {
      msg_warn("unknown %s value \"%s\" in \"%s\"",
        context, name, names);
      myfree(saved_names);
      return (0);
  } else if (flags & NAME_MASK_WARN) {
      msg_warn("unknown %s value \"%s\" in \"%s\"",
        context, name, names);
  }
  break;
     }
     if (lookup(name, np->name) == 0) {
  if (msg_verbose)
      msg_info("%s: %s", myname, name);
  result |= np->mask;
  break;
     }
 }
    }

    myfree(saved_names);
    return (result);
}

/* str_long_name_mask_opt - mask to string */

const char *str_long_name_mask_opt(VSTRING *buf, const char *context,
               const LONG_NAME_MASK *table,
               long mask, int flags)
{
    const char *myname = "name_mask";
    ssize_t len;
    static VSTRING *my_buf = 0;
    int     delim = (flags & NAME_MASK_COMMA ? ',' :
       (flags & NAME_MASK_PIPE ? '|' : ' '));
    const LONG_NAME_MASK *np;

    if ((flags & STR_NAME_MASK_REQUIRED) == 0)
 msg_panic("%s: missing NAME_MASK_NUMBER/FATAL/RETURN/WARN/IGNORE flag",
    myname);

    if (buf == 0) {
 if (my_buf == 0)
     my_buf = vstring_alloc(1);
 buf = my_buf;
    }
    VSTRING_RESET(buf);

    for (np = table; mask != 0; np++) {
 if (np->name == 0) {
     if (flags & NAME_MASK_NUMBER) {
  vstring_sprintf_append(buf, "0x%lx%c", mask, delim);
     } else if (flags & NAME_MASK_FATAL) {
  msg_fatal("%s: unknown %s bit in mask: 0x%lx",
     myname, context, mask);
     } else if (flags & NAME_MASK_RETURN) {
  msg_warn("%s: unknown %s bit in mask: 0x%lx",
    myname, context, mask);
  return (0);
     } else if (flags & NAME_MASK_WARN) {
  msg_warn("%s: unknown %s bit in mask: 0x%lx",
    myname, context, mask);
     }
     break;
 }
 if (mask & np->mask) {
     mask &= ~np->mask;
     vstring_sprintf_append(buf, "%s%c", np->name, delim);
 }
    }
    if ((len = VSTRING_LEN(buf)) > 0)
 vstring_truncate(buf, len - 1);
    VSTRING_TERMINATE(buf);

    return (STR(buf));
}

/* hex_to_ulong - 0x... to unsigned long or smaller */

static int hex_to_ulong(char *value, unsigned long mask, unsigned long *ulp)
{
    unsigned long result;
    char   *cp;

    if (strncasecmp(value, "0x"2) != 0)
 return (0);

    /*
     * Check for valid hex number. Since the value starts with 0x, strtoul()
     * will not allow a negative sign before the first nibble. So we don't
     * need to worry about explicit +/- signs.
     */

    errno = 0;
    result = strtoul(value, &cp, 16);
    if (*cp != '\0' || errno == ERANGE)
 return (0);

    *ulp = (result & mask);
    return (*ulp == result);
}

#ifdef TEST

 /*
  * Stand-alone test program.
  */

#include <stdlib.h>
#include <vstream.h>
#include <vstring_vstream.h>

int     main(int argc, char **argv)
{
    static const NAME_MASK demo_table[] = {
 "zero"1 << 0,
 "one"1 << 1,
 "two"1 << 2,
 "three"1 << 3,
 00,
    };
    static const NAME_MASK feature_table[] = {
 "DEFAULT", NAME_MASK_DEFAULT,
 "FATAL", NAME_MASK_FATAL,
 "ANY_CASE", NAME_MASK_ANY_CASE,
 "RETURN", NAME_MASK_RETURN,
 "COMMA", NAME_MASK_COMMA,
 "PIPE", NAME_MASK_PIPE,
 "NUMBER", NAME_MASK_NUMBER,
 "WARN", NAME_MASK_WARN,
 "IGNORE", NAME_MASK_IGNORE,
 0,
    };
    int     in_feature_mask;
    int     out_feature_mask;
    int     demo_mask;
    const char *demo_str;
    VSTRING *out_buf = vstring_alloc(1);
    VSTRING *in_buf = vstring_alloc(1);

    if (argc != 3)
 msg_fatal("usage: %s in-feature-mask out-feature-mask", argv[0]);
    in_feature_mask = name_mask(argv[1], feature_table, argv[1]);
    out_feature_mask = name_mask(argv[2], feature_table, argv[2]);
    while (vstring_get_nonl(in_buf, VSTREAM_IN) != VSTREAM_EOF) {
 demo_mask = name_mask_opt("name", demo_table,
      STR(in_buf), in_feature_mask);
 demo_str = str_name_mask_opt(out_buf, "mask", demo_table,
         demo_mask, out_feature_mask);
 vstream_printf("%s -> 0x%x -> %s\n",
         STR(in_buf), demo_mask,
         demo_str ? demo_str : "(null)");
 vstream_fflush(VSTREAM_OUT);
    }
    vstring_free(in_buf);
    vstring_free(out_buf);
    exit(0);
}

#endif

Messung V0.5 in Prozent
C=73 H=96 G=85

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet am  2026-08-09) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.