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