Home | History | Annotate | Line # | Download | only in util
      1 /*	$NetBSD: dict_random.c,v 1.5 2026/05/09 18:49:22 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 /*	Wietse Venema
     38 /*	Google, Inc.
     39 /*	111 8th Avenue
     40 /*	New York, NY 10011, USA
     41 /*--*/
     42 
     43 /* System library. */
     44 
     45 #include <sys_defs.h>
     46 #include <string.h>
     47 
     48 /* Utility library. */
     49 
     50 #include <msg.h>
     51 #include <mymalloc.h>
     52 #include <myrand.h>
     53 #include <stringops.h>
     54 #include <dict_random.h>
     55 
     56 /* Application-specific. */
     57 
     58 typedef struct {
     59     DICT    dict;			/* generic members */
     60     ARGV   *replies;			/* reply values */
     61 } DICT_RANDOM;
     62 
     63 #define STR(x) vstring_str(x)
     64 
     65 /* dict_random_lookup - find randomized-table entry */
     66 
     67 static const char *dict_random_lookup(DICT *dict, const char *unused_query)
     68 {
     69     DICT_RANDOM *dict_random = (DICT_RANDOM *) dict;
     70 
     71     DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE,
     72 	 dict_random->replies->argv[myrand() % dict_random->replies->argc]);
     73 }
     74 
     75 /* dict_random_close - disassociate from randomized table */
     76 
     77 static void dict_random_close(DICT *dict)
     78 {
     79     DICT_RANDOM *dict_random = (DICT_RANDOM *) dict;
     80 
     81     if (dict_random->replies)
     82 	argv_free(dict_random->replies);
     83     dict_free(dict);
     84 }
     85 
     86 static char *dict_random_parse_name(DICT *dict, ARGV **argv,
     87 				            const char *string,
     88 				            const char *delim,
     89 				            const char *parens)
     90 {
     91     ARGV   *argvp = argv_alloc(1);
     92     char   *saved_string = mystrdup(string);
     93     char   *bp = saved_string;
     94     char   *arg;
     95     VSTRING *b64 = 0;
     96     char   *err = 0;
     97 
     98     while ((arg = mystrtokq(&bp, delim, parens)) != 0) {
     99 	if (dict->flags & DICT_FLAG_SRC_RHS_IS_FILE) {
    100 	    if ((b64 = dict_file_to_b64(dict, arg)) != 0) {
    101 		argv_add(argvp, vstring_str(b64), (char *) 0);
    102 	    } else {
    103 		err = dict_file_get_error(dict);
    104 		break;
    105 	    }
    106 	} else {
    107 	    argv_add(argvp, arg, (char *) 0);
    108 	}
    109     }
    110     argv_terminate(argvp);
    111     myfree(saved_string);
    112     *argv = argvp;
    113     return (err);
    114 }
    115 
    116 /* dict_random_open - open a randomized table */
    117 
    118 DICT   *dict_random_open(const char *name, int open_flags, int dict_flags)
    119 {
    120     DICT_RANDOM *dict_random;
    121     char   *saved_name = 0;
    122     size_t  len;
    123     char   *err = 0;
    124 
    125     /*
    126      * Clarity first. Let the optimizer worry about redundant code.
    127      */
    128 #define DICT_RANDOM_RETURN(x) do { \
    129 	DICT *__d = (x); \
    130 	if (saved_name != 0) \
    131 	    myfree(saved_name); \
    132 	if (err != 0) \
    133 	    myfree(err); \
    134 	return (__d); \
    135     } while (0)
    136 
    137     /*
    138      * Sanity checks.
    139      */
    140     if (open_flags != O_RDONLY)
    141 	DICT_RANDOM_RETURN(dict_surrogate(DICT_TYPE_RANDOM, name,
    142 					  open_flags, dict_flags,
    143 				  "%s:%s map requires O_RDONLY access mode",
    144 					  DICT_TYPE_RANDOM, name));
    145 
    146     /*
    147      * Bundle up preliminary results.
    148      */
    149     dict_random =
    150 	(DICT_RANDOM *) dict_alloc(DICT_TYPE_RANDOM, name, sizeof(*dict_random));
    151     dict_random->dict.lookup = dict_random_lookup;
    152     dict_random->dict.close = dict_random_close;
    153     dict_random->dict.flags = dict_flags | DICT_FLAG_PATTERN;
    154     dict_random->replies = 0;
    155     dict_random->dict.owner.status = DICT_OWNER_TRUSTED;
    156     dict_random->dict.owner.uid = 0;
    157 
    158     /*
    159      * Split the table name into its constituent parts.
    160      */
    161     if ((len = balpar(name, CHARS_BRACE)) == 0 || name[len] != 0
    162 	|| *(saved_name = mystrndup(name + 1, len - 2)) == 0
    163 	|| (err = dict_random_parse_name(&dict_random->dict,
    164 					 &dict_random->replies, saved_name,
    165 					 CHARS_COMMA_SP, CHARS_BRACE)) != 0
    166 	|| dict_random->replies->argc == 0) {
    167 	dict_random_close(&dict_random->dict);
    168 	DICT_RANDOM_RETURN(err == 0 ?
    169 			   dict_surrogate(DICT_TYPE_RANDOM, name,
    170 					  open_flags, dict_flags,
    171 					  "bad syntax: \"%s:%s\"; "
    172 					  "need \"%s:{value...}\"",
    173 					  DICT_TYPE_RANDOM, name,
    174 					  DICT_TYPE_RANDOM) :
    175 			   dict_surrogate(DICT_TYPE_RANDOM, name,
    176 					  open_flags, dict_flags,
    177 					  "%s", err));
    178     }
    179     dict_file_purge_buffers(&dict_random->dict);
    180     DICT_RANDOM_RETURN(&dict_random->dict);
    181 }
    182