1 /* $NetBSD: dict_random.c,v 1.2 2017/02/14 01:16:49 christos Exp $ */ 2 3 /*++ 4 /* NAME 5 /* dict_random 3 6 /* SUMMARY 7 /* dictionary manager interface for randomized tables 8 /* SYNOPSIS 9 /* #include <dict_random.h> 10 /* 11 /* DICT *dict_random_open(name, open_flags, dict_flags) 12 /* const char *name; 13 /* int open_flags; 14 /* int dict_flags; 15 /* DESCRIPTION 16 /* dict_random_open() opens an in-memory, read-only, table. 17 /* Example: "\fBrandmap:{\fIresult_1, ... ,result_n}\fR". 18 /* 19 /* Each table query returns a random choice from the specified 20 /* results. Other table access methods are not supported. 21 /* 22 /* The first and last characters of the "randmap:" table name 23 /* must be '{' and '}'. Within these, individual maps are 24 /* separated with comma or whitespace. 25 /* SEE ALSO 26 /* dict(3) generic dictionary manager 27 /* LICENSE 28 /* .ad 29 /* .fi 30 /* The Secure Mailer license must be distributed with this software. 31 /* AUTHOR(S) 32 /* Wietse Venema 33 /* IBM T.J. Watson Research 34 /* P.O. Box 704 35 /* Yorktown Heights, NY 10598, USA 36 /*--*/ 37 38 /* System library. */ 39 40 #include <sys_defs.h> 41 #include <string.h> 42 43 /* Utility library. */ 44 45 #include <msg.h> 46 #include <mymalloc.h> 47 #include <myrand.h> 48 #include <stringops.h> 49 #include <dict_random.h> 50 51 /* Application-specific. */ 52 53 typedef struct { 54 DICT dict; /* generic members */ 55 ARGV *replies; /* reply values */ 56 } DICT_RANDOM; 57 58 #define STR(x) vstring_str(x) 59 60 /* dict_random_lookup - find randomized-table entry */ 61 62 static const char *dict_random_lookup(DICT *dict, const char *unused_query) 63 { 64 DICT_RANDOM *dict_random = (DICT_RANDOM *) dict; 65 66 DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, 67 dict_random->replies->argv[myrand() % dict_random->replies->argc]); 68 } 69 70 /* dict_random_close - disassociate from randomized table */ 71 72 static void dict_random_close(DICT *dict) 73 { 74 DICT_RANDOM *dict_random = (DICT_RANDOM *) dict; 75 76 argv_free(dict_random->replies); 77 dict_free(dict); 78 } 79 80 /* dict_random_open - open a randomized table */ 81 82 DICT *dict_random_open(const char *name, int open_flags, int dict_flags) 83 { 84 DICT_RANDOM *dict_random; 85 char *saved_name = 0; 86 ARGV *argv; 87 size_t len; 88 89 /* 90 * Clarity first. Let the optimizer worry about redundant code. 91 */ 92 #define DICT_RANDOM_RETURN(x) do { \ 93 if (saved_name != 0) \ 94 myfree(saved_name); \ 95 return (x); \ 96 } while (0) 97 98 /* 99 * Sanity checks. 100 */ 101 if (open_flags != O_RDONLY) 102 DICT_RANDOM_RETURN(dict_surrogate(DICT_TYPE_RANDOM, name, 103 open_flags, dict_flags, 104 "%s:%s map requires O_RDONLY access mode", 105 DICT_TYPE_RANDOM, name)); 106 107 /* 108 * Split the name name into its constituent parts. 109 */ 110 if ((len = balpar(name, CHARS_BRACE)) == 0 || name[len] != 0 111 || *(saved_name = mystrndup(name + 1, len - 2)) == 0 112 || ((argv = argv_splitq(saved_name, CHARS_COMMA_SP, CHARS_BRACE)), 113 (argv->argc == 0))) 114 DICT_RANDOM_RETURN(dict_surrogate(DICT_TYPE_RANDOM, name, 115 open_flags, dict_flags, 116 "bad syntax: \"%s:%s\"; " 117 "need \"%s:{value...}\"", 118 DICT_TYPE_RANDOM, name, 119 DICT_TYPE_RANDOM)); 120 121 /* 122 * Bundle up the result. 123 */ 124 dict_random = 125 (DICT_RANDOM *) dict_alloc(DICT_TYPE_RANDOM, name, sizeof(*dict_random)); 126 dict_random->dict.lookup = dict_random_lookup; 127 dict_random->dict.close = dict_random_close; 128 dict_random->dict.flags = dict_flags | DICT_FLAG_PATTERN; 129 dict_random->replies = argv; 130 dict_random->dict.owner.status = DICT_OWNER_TRUSTED; 131 dict_random->dict.owner.uid = 0; 132 133 DICT_RANDOM_RETURN(DICT_DEBUG (&dict_random->dict)); 134 } 135