/src/gnupg/common/mapstrings.c
Line | Count | Source |
1 | | /* mapstrings.c - Static string mapping |
2 | | * Copyright (C) 2014 Werner Koch |
3 | | * |
4 | | * This file is part of GnuPG. |
5 | | * |
6 | | * This file is free software; you can redistribute it and/or modify |
7 | | * it under the terms of either |
8 | | * |
9 | | * - the GNU Lesser General Public License as published by the Free |
10 | | * Software Foundation; either version 3 of the License, or (at |
11 | | * your option) any later version. |
12 | | * |
13 | | * or |
14 | | * |
15 | | * - the GNU General Public License as published by the Free |
16 | | * Software Foundation; either version 2 of the License, or (at |
17 | | * your option) any later version. |
18 | | * |
19 | | * or both in parallel, as here. |
20 | | * |
21 | | * This file is distributed in the hope that it will be useful, |
22 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
23 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
24 | | * GNU General Public License for more details. |
25 | | * |
26 | | * You should have received a copy of the GNU General Public License |
27 | | * along with this program; if not, see <https://www.gnu.org/licenses/>. |
28 | | */ |
29 | | |
30 | | #include <config.h> |
31 | | #include <stdlib.h> |
32 | | #include <errno.h> |
33 | | |
34 | | #include "util.h" |
35 | | #include "stringhelp.h" |
36 | | #include "membuf.h" |
37 | | |
38 | | |
39 | | static struct { |
40 | | const char *name; |
41 | | const char *value; |
42 | | } macros[] = { |
43 | | #ifdef PACKAGE_BUGREPORT |
44 | | { "EMAIL", PACKAGE_BUGREPORT }, |
45 | | #else |
46 | | { "EMAIL", "bug@example.org" }, |
47 | | #endif |
48 | | { "GNUPG", GNUPG_NAME }, |
49 | | { "GPG", GPG_NAME }, |
50 | | { "GPGSM", GPGSM_NAME }, |
51 | | { "GPG_AGENT", GPG_AGENT_NAME }, |
52 | | { "SCDAEMON", SCDAEMON_NAME }, |
53 | | { "TPM2DAEMON",TPM2DAEMON_NAME}, |
54 | | { "DIRMNGR", DIRMNGR_NAME }, |
55 | | { "G13", G13_NAME }, |
56 | | { "GPGCONF", GPGCONF_NAME }, |
57 | | { "GPGTAR", GPGTAR_NAME } |
58 | | }; |
59 | | |
60 | | |
61 | | |
62 | | /* A list to remember already done mappings. */ |
63 | | struct mapping_s |
64 | | { |
65 | | struct mapping_s *next; |
66 | | const char *key; |
67 | | const char *value; |
68 | | }; |
69 | | static struct mapping_s *mappings; |
70 | | |
71 | | |
72 | | /* Similar to above but using two integers and a domain as key. */ |
73 | | struct intmapping_s |
74 | | { |
75 | | struct intmapping_s *next; |
76 | | int key1; |
77 | | int key2; |
78 | | const char *string; |
79 | | char domain[1]; |
80 | | }; |
81 | | static struct intmapping_s *intmappings; |
82 | | |
83 | | |
84 | | /* If STRING has already been mapped, return the mapped string. If |
85 | | not return NULL. */ |
86 | | static const char * |
87 | | already_mapped (const char *string) |
88 | 0 | { |
89 | 0 | struct mapping_s *m; |
90 | |
|
91 | 0 | for (m=mappings; m; m = m->next) |
92 | 0 | if (m->key == string && !strcmp (m->key, string)) |
93 | 0 | return m->value; |
94 | 0 | return NULL; |
95 | 0 | } |
96 | | |
97 | | |
98 | | /* Store NEWSTRING under key STRING and return NEWSTRING. */ |
99 | | static const char * |
100 | | store_mapping (const char *string, char *newstring) |
101 | 0 | { |
102 | 0 | struct mapping_s *m; |
103 | |
|
104 | 0 | m = xmalloc (sizeof *m); |
105 | 0 | m->key = string; |
106 | 0 | m->value = newstring; |
107 | 0 | m->next = mappings; |
108 | 0 | mappings = m; |
109 | 0 | return newstring; |
110 | 0 | } |
111 | | |
112 | | |
113 | | /* Find the first macro in STRING. Return a pointer to the |
114 | | replacement value, set BEGPTR to the leading '@', and set ENDPTR to |
115 | | the terminating '@'. If no macro is found return NULL. */ |
116 | | const char * |
117 | | find_macro (const char *string, const char **begptr, |
118 | | const char **endptr) |
119 | 0 | { |
120 | 0 | const char *s, *s2, *s3; |
121 | 0 | int idx; |
122 | |
|
123 | 0 | s = string; |
124 | 0 | if (!s) |
125 | 0 | return NULL; |
126 | | |
127 | 0 | for (; (s2 = strchr (s, '@')); s = s2) |
128 | 0 | { |
129 | 0 | s2++; |
130 | 0 | if (*s2 >= 'A' && *s2 <= 'Z' && (s3 = (strchr (s2, '@')))) |
131 | 0 | { |
132 | 0 | for (idx=0; idx < DIM (macros); idx++) |
133 | 0 | if (strlen (macros[idx].name) == (s3 - s2) |
134 | 0 | && !memcmp (macros[idx].name, s2, (s3 - s2))) |
135 | 0 | { |
136 | 0 | *begptr = s2 - 1; |
137 | 0 | *endptr = s3; |
138 | 0 | return macros[idx].value; |
139 | 0 | } |
140 | 0 | } |
141 | 0 | } |
142 | 0 | return NULL; |
143 | 0 | } |
144 | | |
145 | | |
146 | | /* If STRING includes known @FOO@ macros, replace these macros and |
147 | | return a new static string. Warning: STRING must have been |
148 | | allocated statically. Note that this function allocates memory |
149 | | which will not be released (similar to gettext). */ |
150 | | const char * |
151 | | map_static_macro_string (const char *string) |
152 | 0 | { |
153 | 0 | const char *s, *s2, *s3, *value; |
154 | 0 | membuf_t mb; |
155 | 0 | char *p; |
156 | |
|
157 | 0 | if ((s = already_mapped (string))) |
158 | 0 | return s; |
159 | 0 | s = string; |
160 | 0 | value = find_macro (s, &s2, &s3); |
161 | 0 | if (!value) |
162 | 0 | return string; /* No macros at all. */ |
163 | | |
164 | 0 | init_membuf (&mb, strlen (string) + 100); |
165 | 0 | do |
166 | 0 | { |
167 | 0 | put_membuf (&mb, s, s2 - s); |
168 | 0 | put_membuf_str (&mb, value); |
169 | 0 | s = s3 + 1; |
170 | 0 | } |
171 | 0 | while ((value = find_macro (s, &s2, &s3))); |
172 | 0 | put_membuf_str (&mb, s); |
173 | 0 | put_membuf (&mb, "", 1); |
174 | |
|
175 | 0 | p = get_membuf_shrink (&mb, NULL); |
176 | 0 | if (!p) |
177 | 0 | log_fatal ("map_static_macro_string failed: %s\n", strerror (errno)); |
178 | | |
179 | 0 | return store_mapping (string, p); |
180 | 0 | } |
181 | | |
182 | | |
183 | | /* If a list of strings has already been mapped to a the tuple |
184 | | * (DOMAIN,KEY1,KEY2) return that string. If not, create a mapping |
185 | | * made up of the concatenation of the given strings. */ |
186 | | const char * |
187 | | map_static_strings (const char *domain, int key1, int key2, |
188 | | const char *string1, ...) |
189 | 0 | { |
190 | 0 | va_list arg_ptr; |
191 | 0 | struct intmapping_s *m; |
192 | |
|
193 | 0 | if (!string1 || !domain) |
194 | 0 | return ""; |
195 | | |
196 | 0 | for (m = intmappings; m; m = m->next) |
197 | 0 | if (m->key1 == key1 && m->key2 == key2 && !strcmp (domain, m->domain)) |
198 | 0 | return m->string; |
199 | | |
200 | 0 | m = xmalloc (sizeof *m + strlen (domain)); |
201 | 0 | strcpy (m->domain, domain); |
202 | 0 | m->key1 = key1; |
203 | 0 | m->key2 = key2; |
204 | |
|
205 | 0 | va_start (arg_ptr, string1); |
206 | 0 | m->string = vstrconcat (string1, arg_ptr); |
207 | 0 | va_end (arg_ptr); |
208 | 0 | if (!m->string) |
209 | 0 | log_fatal ("map_static_strings failed: %s\n", strerror (errno)); |
210 | | |
211 | 0 | gpgrt_annotate_leaked_object (m->string); |
212 | 0 | gpgrt_annotate_leaked_object (m); |
213 | |
|
214 | 0 | m->next = intmappings; |
215 | 0 | intmappings = m; |
216 | 0 | return m->string; |
217 | 0 | } |