xref: /netbsd-src/external/ibm-public/postfix/dist/src/util/dict_inline.c (revision 67b9b338a7386232ac596b5fd0cd5a9cc8a03c71)
1 /*	$NetBSD: dict_inline.c,v 1.4 2022/10/08 16:12:50 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 
dict_inline_open(const char * name,int open_flags,int dict_flags)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_string(name, strlen(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_open3(DICT_TYPE_HT, 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_DEBUG (dict));
152 }
153