Home | History | Annotate | Line # | Download | only in util
      1 /*	$NetBSD: dict_inline.c,v 1.6 2026/05/09 18:49:22 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	dict_inline 3
      6 /* SUMMARY
      7 /*	dictionary manager interface for inline table
      8 /* SYNOPSIS
      9 /*	#include <dict_inline.h>
     10 /*
     11 /*	DICT	*dict_inline_open(name, open_flags, dict_flags)
     12 /*	const char *name;
     13 /*	int	open_flags;
     14 /*	int	dict_flags;
     15 /* DESCRIPTION
     16 /*	dict_inline_open() opens a read-only, in-memory table.
     17 /*	Example: "\fBinline:{\fIkey_1=value_1, ..., key_n=value_n\fR}".
     18 /*	The longer form with { key = value } allows values that
     19 /*	contain whitespace or comma.
     20 /* SEE ALSO
     21 /*	dict(3) generic dictionary manager
     22 /* LICENSE
     23 /* .ad
     24 /* .fi
     25 /*	The Secure Mailer license must be distributed with this software.
     26 /* AUTHOR(S)
     27 /*	Wietse Venema
     28 /*	IBM T.J. Watson Research
     29 /*	P.O. Box 704
     30 /*	Yorktown Heights, NY 10598, USA
     31 /*
     32 /*	Wietse Venema
     33 /*	Google, Inc.
     34 /*	111 8th Avenue
     35 /*	New York, NY 10011, 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 <stringops.h>
     48 #include <dict.h>
     49 #include <dict_ht.h>
     50 #include <dict_inline.h>
     51 
     52 /* Application-specific. */
     53 
     54 /* dict_inline_open - open inline table */
     55 
     56 DICT   *dict_inline_open(const char *name, int open_flags, int dict_flags)
     57 {
     58     DICT   *dict;
     59     char   *cp, *saved_name = 0;
     60     size_t  len;
     61     char   *nameval, *vname, *value;
     62     const char *err = 0;
     63     char   *free_me = 0;
     64     int     count = 0;
     65 
     66     /*
     67      * Clarity first. Let the optimizer worry about redundant code.
     68      */
     69 #define DICT_INLINE_RETURN(x) do { \
     70 	    DICT *__d = (x); \
     71 	    if (saved_name != 0) \
     72 		myfree(saved_name); \
     73 	    if (free_me != 0) \
     74 		myfree(free_me); \
     75 	    return (__d); \
     76 	} while (0)
     77 
     78     /*
     79      * Sanity checks.
     80      */
     81     if (open_flags != O_RDONLY)
     82 	DICT_INLINE_RETURN(dict_surrogate(DICT_TYPE_INLINE, name,
     83 					  open_flags, dict_flags,
     84 				  "%s:%s map requires O_RDONLY access mode",
     85 					  DICT_TYPE_INLINE, name));
     86 
     87     /*
     88      * UTF-8 syntax check.
     89      */
     90     if (DICT_NEED_UTF8_ACTIVATION(util_utf8_enable, dict_flags)
     91 	&& allascii(name) == 0
     92 	&& valid_utf8_stringz(name) == 0)
     93 	DICT_INLINE_RETURN(dict_surrogate(DICT_TYPE_INLINE, name,
     94 					  open_flags, dict_flags,
     95 					  "bad UTF-8 syntax: \"%s:%s\"; "
     96 					  "need \"%s:{name=value...}\"",
     97 					  DICT_TYPE_INLINE, name,
     98 					  DICT_TYPE_INLINE));
     99 
    100     /*
    101      * Parse the table into its constituent name=value pairs.
    102      */
    103     if ((len = balpar(name, CHARS_BRACE)) == 0 || name[len] != 0
    104 	|| *(cp = saved_name = mystrndup(name + 1, len - 2)) == 0)
    105 	DICT_INLINE_RETURN(dict_surrogate(DICT_TYPE_INLINE, name,
    106 					  open_flags, dict_flags,
    107 					  "bad syntax: \"%s:%s\"; "
    108 					  "need \"%s:{name=value...}\"",
    109 					  DICT_TYPE_INLINE, name,
    110 					  DICT_TYPE_INLINE));
    111 
    112     /*
    113      * Reuse the "internal" dictionary type.
    114      */
    115     dict = dict_ht_open(name, open_flags, dict_flags);
    116     dict_type_override(dict, DICT_TYPE_INLINE);
    117     while ((nameval = mystrtokq(&cp, CHARS_COMMA_SP, CHARS_BRACE)) != 0) {
    118 	if (nameval[0] == CHARS_BRACE[0])
    119 	    err = free_me = extpar(&nameval, CHARS_BRACE, EXTPAR_FLAG_STRIP);
    120 	if (err != 0 || (err = split_qnameval(nameval, &vname, &value)) != 0)
    121 	    break;
    122 
    123 	if ((dict->flags & DICT_FLAG_SRC_RHS_IS_FILE) != 0) {
    124 	    VSTRING *base64_buf;
    125 
    126 	    if ((base64_buf = dict_file_to_b64(dict, value)) == 0) {
    127 		err = free_me = dict_file_get_error(dict);
    128 		break;
    129 	    }
    130 	    value = vstring_str(base64_buf);
    131 	}
    132 	/* No duplicate checks. See comments in dict_thash.c. */
    133 	dict->update(dict, vname, value);
    134 	count += 1;
    135     }
    136     if (err != 0 || count == 0) {
    137 	dict->close(dict);
    138 	DICT_INLINE_RETURN(dict_surrogate(DICT_TYPE_INLINE, name,
    139 					  open_flags, dict_flags,
    140 					  "%s: \"%s:%s\"; "
    141 					  "need \"%s:{name=%s...}\"",
    142 					  err != 0 ? err : "empty table",
    143 					  DICT_TYPE_INLINE, name,
    144 					  DICT_TYPE_INLINE,
    145 				  (dict_flags & DICT_FLAG_SRC_RHS_IS_FILE) ?
    146 					  "filename" : "value"));
    147     }
    148     dict->owner.status = DICT_OWNER_TRUSTED;
    149 
    150     dict_file_purge_buffers(dict);
    151     DICT_INLINE_RETURN(dict);
    152 }
    153