~ubuntu-branches/ubuntu/saucy/postfix/saucy

« back to all changes in this revision

Viewing changes to src/util/name_mask.c

  • Committer: Bazaar Package Importer
  • Author(s): LaMont Jones
  • Date: 2011-02-22 11:20:43 UTC
  • mfrom: (1.1.27 upstream)
  • Revision ID: james.westby@ubuntu.com-20110222112043-c34ht219w3ybrilr
Tags: 2.8.0-2
* a little more lintian cleanup
* Fix missing format strings in smtp-sink.c

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
/*      const NAME_MASK *table;
12
12
/*      const char *names;
13
13
/*
 
14
/*      long    long_name_mask(context, table, names)
 
15
/*      const char *context;
 
16
/*      const LONG_NAME_MASK *table;
 
17
/*      const char *names;
 
18
/*
14
19
/*      const char *str_name_mask(context, table, mask)
15
20
/*      const char *context;
16
21
/*      const NAME_MASK *table;
17
22
/*      int     mask;
18
23
/*
 
24
/*      const char *str_long_name_mask(context, table, mask)
 
25
/*      const char *context;
 
26
/*      const LONG_NAME_MASK *table;
 
27
/*      long    mask;
 
28
/*
19
29
/*      int     name_mask_opt(context, table, names, flags)
20
30
/*      const char *context;
21
31
/*      const NAME_MASK *table;
22
32
/*      const char *names;
23
33
/*      int     flags;
24
34
/*
 
35
/*      long    long_name_mask_opt(context, table, names, flags)
 
36
/*      const char *context;
 
37
/*      const LONG_NAME_MASK *table;
 
38
/*      const char *names;
 
39
/*      int     flags;
 
40
/*
25
41
/*      int     name_mask_delim_opt(context, table, names, delim, flags)
26
42
/*      const char *context;
27
43
/*      const NAME_MASK *table;
29
45
/*      const char *delim;
30
46
/*      int     flags;
31
47
/*
 
48
/*      long    long_name_mask_delim_opt(context, table, names, delim, flags)
 
49
/*      const char *context;
 
50
/*      const LONG_NAME_MASK *table;
 
51
/*      const char *names;
 
52
/*      const char *delim;
 
53
/*      int     flags;
 
54
/*
32
55
/*      const char *str_name_mask_opt(buf, context, table, mask, flags)
33
56
/*      VSTRING *buf;
34
57
/*      const char *context;
35
58
/*      const NAME_MASK *table;
36
59
/*      int     mask;
37
60
/*      int     flags;
 
61
/*
 
62
/*      const char *str_long_name_mask_opt(buf, context, table, mask, flags)
 
63
/*      VSTRING *buf;
 
64
/*      const char *context;
 
65
/*      const LONG_NAME_MASK *table;
 
66
/*      long    mask;
 
67
/*      int     flags;
38
68
/* DESCRIPTION
39
69
/*      name_mask() takes a null-terminated \fItable\fR with (name, mask)
40
70
/*      values and computes the bit-wise OR of the masks that correspond
41
71
/*      to the names listed in the \fInames\fR argument, separated by
42
 
/*      comma and/or whitespace characters.
 
72
/*      comma and/or whitespace characters. The "long_" version returns
 
73
/*      a "long int" bitmask, rather than an "int" bitmask.
43
74
/*
44
 
/*      str_name_mask() translates a mask into its equivalent names.
 
75
/*      str_name_mask() translates a mask into its equlvalent names.
45
76
/*      The result is written to a static buffer that is overwritten
46
 
/*      upon each call.
 
77
/*      upon each call. The "long_" version converts a "long int"
 
78
/*      bitmask, rather than an "int" bitmask.
47
79
/*
48
80
/*      name_mask_opt() and str_name_mask_opt() are extended versions
49
81
/*      with additional fine control. name_mask_delim_opt() supports
63
95
/*      A list of names that is to be converted into a bit mask.
64
96
/* .IP mask
65
97
/*      A bit mask.
66
 
/* .IP flags
67
 
/*      Bit-wise OR of zero or more of the following:
68
98
/* .IP delim
69
99
/*      Delimiter characters to use instead of whitespace and commas.
 
100
/* .IP flags
 
101
/*      Bit-wise OR of one or more of the following.  Where features
 
102
/*      would have conflicting results (e.g., FATAL versus IGNORE),
 
103
/*      the feature that takes precedence is described first.
 
104
/*
 
105
/*      When converting from string to mask, at least one of the
 
106
/*      following must be specified: NAME_MASK_FATAL, NAME_MASK_RETURN,
 
107
/*      NAME_MASK_WARN or NAME_MASK_IGNORE.
 
108
/*
 
109
/*      When converting from mask to string, at least one of the
 
110
/*      following must be specified: NAME_MASK_NUMBER, NAME_MASK_FATAL,
 
111
/*      NAME_MASK_RETURN, NAME_MASK_WARN or NAME_MASK_IGNORE.
70
112
/* .RS
 
113
/* .IP NAME_MASK_NUMBER
 
114
/*      When converting from string to mask, accept hexadecimal
 
115
/*      inputs starting with "0x" followed by hexadecimal digits.
 
116
/*      Each hexadecimal input may specify multiple bits.  This
 
117
/*      feature is ignored for hexadecimal inputs that cannot be
 
118
/*      converted (malformed, out of range, etc.).
 
119
/*
 
120
/*      When converting from mask to string, represent bits not
 
121
/*      defined in \fItable\fR as "0x" followed by hexadecimal
 
122
/*      digits. This conversion always succeeds.
71
123
/* .IP NAME_MASK_FATAL
72
 
/*      Require that all names listed in \fIname\fR exist in \fItable\fR,
73
 
/*      and that all bits listed in \fImask\fR exist in \fItable\fR.
74
 
/*      Terminate with a fatal run-time error if this condition is not met.
75
 
/*      This feature is enabled by default when calling name_mask()
76
 
/*      or str_name_mask().
 
124
/*      Require that all names listed in \fIname\fR exist in
 
125
/*      \fItable\fR or that they can be parsed as a hexadecimal
 
126
/*      string, and require that all bits listed in \fImask\fR exist
 
127
/*      in \fItable\fR or that they can be converted to hexadecimal
 
128
/*      string.  Terminate with a fatal run-time error if this
 
129
/*      condition is not met.  This feature is enabled by default
 
130
/*      when calling name_mask() or str_name_mask().
77
131
/* .IP NAME_MASK_RETURN
78
 
/*      Require that all names listed in \fIname\fR exist in \fItable\fR,
79
 
/*      and that all bits listed in \fImask\fR exist in \fItable\fR.
80
 
/*      Log a warning, and return 0 (name_mask()) or a null pointer
81
 
/*      (str_name_mask()) if this condition is not met.
82
 
/* .IP NAME_MASK_NUMBER
83
 
/*      Require that all bits listed in \fImask\fR exist in \fItable\fR.
84
 
/*      For unrecognized bits, print the numerical hexadecimal form.
 
132
/*      Require that all names listed in \fIname\fR exist in
 
133
/*      \fItable\fR or that they can be parsed as a hexadecimal
 
134
/*      string, and require that all bits listed in \fImask\fR exist
 
135
/*      in \fItable\fR or that they can be converted to hexadecimal
 
136
/*      string.  Log a warning, and return 0 (name_mask()) or a
 
137
/*      null pointer (str_name_mask()) if this condition is not
 
138
/*      met.  This feature is not enabled by default when calling
 
139
/*      name_mask() or str_name_mask().
 
140
/* .IP NAME_MASK_WARN
 
141
/*      Require that all names listed in \fIname\fR exist in
 
142
/*      \fItable\fR or that they can be parsed as a hexadecimal
 
143
/*      string, and require that all bits listed in \fImask\fR exist
 
144
/*      in \fItable\fR or that they can be converted to hexadecimal
 
145
/*      string.  Log a warning if this condition is not met, continue
 
146
/*      processing, and return all valid bits or names.  This feature
 
147
/*      is not enabled by default when calling name_mask() or
 
148
/*      str_name_mask().
 
149
/* .IP NAME_MASK_IGNORE
 
150
/*      Silently ignore names listed in \fIname\fR that don't exist
 
151
/*      in \fItable\fR and that can't be parsed as a hexadecimal
 
152
/*      string, and silently ignore bits listed in \fImask\fR that
 
153
/*      don't exist in \fItable\fR and that can't be converted to
 
154
/*      hexadecimal string.
85
155
/* .IP NAME_MASK_ANY_CASE
86
156
/*      Enable case-insensitive matching.
87
157
/*      This feature is not enabled by default when calling name_mask();
112
182
 
113
183
#include <sys_defs.h>
114
184
#include <string.h>
 
185
#include <errno.h>
 
186
#include <stdlib.h>
115
187
 
116
188
#ifdef STRCASECMP_IN_STRINGS_H
117
189
#include <strings.h>
125
197
#include <name_mask.h>
126
198
#include <vstring.h>
127
199
 
 
200
static int hex_to_ulong(char *, unsigned long, unsigned long *);
 
201
 
128
202
#define STR(x) vstring_str(x)
129
203
 
130
204
/* name_mask_delim_opt - compute mask corresponding to list of names */
139
213
    const NAME_MASK *np;
140
214
    char   *name;
141
215
    int     (*lookup) (const char *, const char *);
 
216
    unsigned long ulval;
 
217
 
 
218
    if ((flags & NAME_MASK_REQUIRED) == 0)
 
219
        msg_panic("%s: missing NAME_MASK_FATAL/RETURN/WARN/IGNORE flag",
 
220
                  myname);
142
221
 
143
222
    if (flags & NAME_MASK_ANY_CASE)
144
223
        lookup = strcasecmp;
152
231
    while ((name = mystrtok(&bp, delim)) != 0) {
153
232
        for (np = table; /* void */ ; np++) {
154
233
            if (np->name == 0) {
155
 
                if (flags & NAME_MASK_FATAL)
 
234
                if ((flags & NAME_MASK_NUMBER)
 
235
                    && hex_to_ulong(name, ~0U, &ulval)) {
 
236
                    result |= (unsigned int) ulval;
 
237
                } else if (flags & NAME_MASK_FATAL) {
156
238
                    msg_fatal("unknown %s value \"%s\" in \"%s\"",
157
239
                              context, name, names);
158
 
                if (flags & NAME_MASK_RETURN) {
 
240
                } else if (flags & NAME_MASK_RETURN) {
159
241
                    msg_warn("unknown %s value \"%s\" in \"%s\"",
160
242
                             context, name, names);
161
243
                    return (0);
 
244
                } else if (flags & NAME_MASK_WARN) {
 
245
                    msg_warn("unknown %s value \"%s\" in \"%s\"",
 
246
                             context, name, names);
162
247
                }
163
248
                break;
164
249
            }
187
272
    int     delim = (flags & NAME_MASK_COMMA ? ',' :
188
273
                     (flags & NAME_MASK_PIPE ? '|' : ' '));
189
274
 
 
275
    if ((flags & STR_NAME_MASK_REQUIRED) == 0)
 
276
        msg_panic("%s: missing NAME_MASK_NUMBER/FATAL/RETURN/WARN/IGNORE flag",
 
277
                  myname);
 
278
 
190
279
    if (buf == 0) {
191
280
        if (my_buf == 0)
192
281
            my_buf = vstring_alloc(1);
196
285
 
197
286
    for (np = table; mask != 0; np++) {
198
287
        if (np->name == 0) {
199
 
            if (flags & NAME_MASK_FATAL) {
 
288
            if (flags & NAME_MASK_NUMBER) {
 
289
                vstring_sprintf_append(buf, "0x%x%c", mask, delim);
 
290
            } else if (flags & NAME_MASK_FATAL) {
200
291
                msg_fatal("%s: unknown %s bit in mask: 0x%x",
201
292
                          myname, context, mask);
202
293
            } else if (flags & NAME_MASK_RETURN) {
203
294
                msg_warn("%s: unknown %s bit in mask: 0x%x",
204
295
                         myname, context, mask);
205
296
                return (0);
206
 
            } else if (flags & NAME_MASK_NUMBER) {
207
 
                vstring_sprintf_append(buf, "0x%x%c", mask, delim);
208
 
            }
209
 
            break;
210
 
        }
211
 
        if (mask & np->mask) {
212
 
            mask &= ~np->mask;
213
 
            vstring_sprintf_append(buf, "%s%c", np->name, delim);
214
 
        }
215
 
    }
216
 
    if ((len = VSTRING_LEN(buf)) > 0)
217
 
        vstring_truncate(buf, len - 1);
218
 
    VSTRING_TERMINATE(buf);
219
 
 
220
 
    return (STR(buf));
 
297
            } else if (flags & NAME_MASK_WARN) {
 
298
                msg_warn("%s: unknown %s bit in mask: 0x%x",
 
299
                         myname, context, mask);
 
300
            }
 
301
            break;
 
302
        }
 
303
        if (mask & np->mask) {
 
304
            mask &= ~np->mask;
 
305
            vstring_sprintf_append(buf, "%s%c", np->name, delim);
 
306
        }
 
307
    }
 
308
    if ((len = VSTRING_LEN(buf)) > 0)
 
309
        vstring_truncate(buf, len - 1);
 
310
    VSTRING_TERMINATE(buf);
 
311
 
 
312
    return (STR(buf));
 
313
}
 
314
 
 
315
/* long_name_mask_delim_opt - compute mask corresponding to list of names */
 
316
 
 
317
long    long_name_mask_delim_opt(const char *context,
 
318
                                         const LONG_NAME_MASK * table,
 
319
                                       const char *names, const char *delim,
 
320
                                         int flags)
 
321
{
 
322
    const char *myname = "name_mask";
 
323
    char   *saved_names = mystrdup(names);
 
324
    char   *bp = saved_names;
 
325
    long    result = 0;
 
326
    const LONG_NAME_MASK *np;
 
327
    char   *name;
 
328
    int     (*lookup) (const char *, const char *);
 
329
    unsigned long ulval;
 
330
 
 
331
    if ((flags & NAME_MASK_REQUIRED) == 0)
 
332
        msg_panic("%s: missing NAME_MASK_FATAL/RETURN/WARN/IGNORE flag",
 
333
                  myname);
 
334
 
 
335
    if (flags & NAME_MASK_ANY_CASE)
 
336
        lookup = strcasecmp;
 
337
    else
 
338
        lookup = strcmp;
 
339
 
 
340
    /*
 
341
     * Break up the names string, and look up each component in the table. If
 
342
     * the name is found, merge its mask with the result.
 
343
     */
 
344
    while ((name = mystrtok(&bp, delim)) != 0) {
 
345
        for (np = table; /* void */ ; np++) {
 
346
            if (np->name == 0) {
 
347
                if ((flags & NAME_MASK_NUMBER)
 
348
                    && hex_to_ulong(name, ~0UL, &ulval)) {
 
349
                    result |= ulval;
 
350
                } else if (flags & NAME_MASK_FATAL) {
 
351
                    msg_fatal("unknown %s value \"%s\" in \"%s\"",
 
352
                              context, name, names);
 
353
                } else if (flags & NAME_MASK_RETURN) {
 
354
                    msg_warn("unknown %s value \"%s\" in \"%s\"",
 
355
                             context, name, names);
 
356
                    return (0);
 
357
                } else if (flags & NAME_MASK_WARN) {
 
358
                    msg_warn("unknown %s value \"%s\" in \"%s\"",
 
359
                             context, name, names);
 
360
                }
 
361
                break;
 
362
            }
 
363
            if (lookup(name, np->name) == 0) {
 
364
                if (msg_verbose)
 
365
                    msg_info("%s: %s", myname, name);
 
366
                result |= np->mask;
 
367
                break;
 
368
            }
 
369
        }
 
370
    }
 
371
 
 
372
    myfree(saved_names);
 
373
    return (result);
 
374
}
 
375
 
 
376
/* str_long_name_mask_opt - mask to string */
 
377
 
 
378
const char *str_long_name_mask_opt(VSTRING *buf, const char *context,
 
379
                                           const LONG_NAME_MASK * table,
 
380
                                           long mask, int flags)
 
381
{
 
382
    const char *myname = "name_mask";
 
383
    int     len;
 
384
    static VSTRING *my_buf = 0;
 
385
    int     delim = (flags & NAME_MASK_COMMA ? ',' :
 
386
                     (flags & NAME_MASK_PIPE ? '|' : ' '));
 
387
    const LONG_NAME_MASK *np;
 
388
 
 
389
    if ((flags & STR_NAME_MASK_REQUIRED) == 0)
 
390
        msg_panic("%s: missing NAME_MASK_NUMBER/FATAL/RETURN/WARN/IGNORE flag",
 
391
                  myname);
 
392
 
 
393
    if (buf == 0) {
 
394
        if (my_buf == 0)
 
395
            my_buf = vstring_alloc(1);
 
396
        buf = my_buf;
 
397
    }
 
398
    VSTRING_RESET(buf);
 
399
 
 
400
    for (np = table; mask != 0; np++) {
 
401
        if (np->name == 0) {
 
402
            if (flags & NAME_MASK_NUMBER) {
 
403
                vstring_sprintf_append(buf, "0x%lx%c", mask, delim);
 
404
            } else if (flags & NAME_MASK_FATAL) {
 
405
                msg_fatal("%s: unknown %s bit in mask: 0x%lx",
 
406
                          myname, context, mask);
 
407
            } else if (flags & NAME_MASK_RETURN) {
 
408
                msg_warn("%s: unknown %s bit in mask: 0x%lx",
 
409
                         myname, context, mask);
 
410
                return (0);
 
411
            } else if (flags & NAME_MASK_WARN) {
 
412
                msg_warn("%s: unknown %s bit in mask: 0x%lx",
 
413
                         myname, context, mask);
 
414
            }
 
415
            break;
 
416
        }
 
417
        if (mask & np->mask) {
 
418
            mask &= ~np->mask;
 
419
            vstring_sprintf_append(buf, "%s%c", np->name, delim);
 
420
        }
 
421
    }
 
422
    if ((len = VSTRING_LEN(buf)) > 0)
 
423
        vstring_truncate(buf, len - 1);
 
424
    VSTRING_TERMINATE(buf);
 
425
 
 
426
    return (STR(buf));
 
427
}
 
428
 
 
429
/* hex_to_ulong - 0x... to unsigned long or smaller */
 
430
 
 
431
static int hex_to_ulong(char *value, unsigned long mask, unsigned long *ulp)
 
432
{
 
433
    unsigned long result;
 
434
    char   *cp;
 
435
 
 
436
    if (strncasecmp(value, "0x", 2) != 0)
 
437
        return (0);
 
438
 
 
439
    /*
 
440
     * Check for valid hex number. Since the value starts with 0x, strtoul()
 
441
     * will not allow a negative sign before the first nibble. So we don't
 
442
     * need to worry about explicit +/- signs.
 
443
     */
 
444
    errno = 0;
 
445
    result = strtoul(value, &cp, 16);
 
446
    if (*cp != '\0' || errno == ERANGE)
 
447
        return (0);
 
448
 
 
449
    if (ulp)
 
450
        *ulp = (result & mask);
 
451
    return (*ulp == result);
221
452
}
222
453
 
223
454
#ifdef TEST
227
458
  */
228
459
#include <stdlib.h>
229
460
#include <vstream.h>
 
461
#include <vstring_vstream.h>
230
462
 
231
463
int     main(int argc, char **argv)
232
464
{
233
 
    static const NAME_MASK table[] = {
 
465
    static const NAME_MASK demo_table[] = {
234
466
        "zero", 1 << 0,
235
467
        "one", 1 << 1,
236
468
        "two", 1 << 2,
237
469
        "three", 1 << 3,
238
470
        0, 0,
239
471
    };
240
 
    int     mask;
241
 
    VSTRING *buf = vstring_alloc(1);
 
472
    static const NAME_MASK feature_table[] = {
 
473
        "DEFAULT", NAME_MASK_DEFAULT,
 
474
        "FATAL", NAME_MASK_FATAL,
 
475
        "ANY_CASE", NAME_MASK_ANY_CASE,
 
476
        "RETURN", NAME_MASK_RETURN,
 
477
        "COMMA", NAME_MASK_COMMA,
 
478
        "PIPE", NAME_MASK_PIPE,
 
479
        "NUMBER", NAME_MASK_NUMBER,
 
480
        "WARN", NAME_MASK_WARN,
 
481
        "IGNORE", NAME_MASK_IGNORE,
 
482
        0,
 
483
    };
 
484
    int     in_feature_mask;
 
485
    int     out_feature_mask;
 
486
    int     demo_mask;
 
487
    const char *demo_str;
 
488
    VSTRING *out_buf = vstring_alloc(1);
 
489
    VSTRING *in_buf = vstring_alloc(1);
242
490
 
243
 
    while (--argc && *++argv) {
244
 
        mask = name_mask("test", table, *argv);
 
491
    if (argc != 3)
 
492
        msg_fatal("usage: %s in-feature-mask out-feature-mask", argv[0]);
 
493
    in_feature_mask = name_mask(argv[1], feature_table, argv[1]);
 
494
    out_feature_mask = name_mask(argv[2], feature_table, argv[2]);
 
495
    while (vstring_get_nonl(in_buf, VSTREAM_IN) != VSTREAM_EOF) {
 
496
        demo_mask = name_mask_opt("name", demo_table,
 
497
                                  STR(in_buf), in_feature_mask);
 
498
        demo_str = str_name_mask_opt(out_buf, "mask", demo_table,
 
499
                                     demo_mask, out_feature_mask);
245
500
        vstream_printf("%s -> 0x%x -> %s\n",
246
 
                       *argv, mask, str_name_mask("mask_test", table, mask));
 
501
                       STR(in_buf), demo_mask,
 
502
                       demo_str ? demo_str : "(null)");
247
503
        vstream_fflush(VSTREAM_OUT);
248
504
    }
249
 
    vstring_free(buf);
 
505
    vstring_free(in_buf);
 
506
    vstring_free(out_buf);
250
507
    exit(0);
251
508
}
252
509