diff options
Diffstat (limited to '')
-rw-r--r-- | common/mapstrings.c | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/common/mapstrings.c b/common/mapstrings.c new file mode 100644 index 0000000..16da48e --- /dev/null +++ b/common/mapstrings.c @@ -0,0 +1,216 @@ +/* mapstrings.c - Static string mapping + * Copyright (C) 2014 Werner Koch + * + * This file is part of GnuPG. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either + * + * - the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at + * your option) any later version. + * + * or + * + * - the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * or both in parallel, as here. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdlib.h> +#include <errno.h> + +#include "util.h" +#include "stringhelp.h" +#include "membuf.h" + + +static struct { + const char *name; + const char *value; +} macros[] = { +#ifdef PACKAGE_BUGREPORT + { "EMAIL", PACKAGE_BUGREPORT }, +#else + { "EMAIL", "bug@example.org" }, +#endif + { "GNUPG", GNUPG_NAME }, + { "GPG", GPG_NAME }, + { "GPGSM", GPGSM_NAME }, + { "GPG_AGENT", GPG_AGENT_NAME }, + { "SCDAEMON", SCDAEMON_NAME }, + { "DIRMNGR", DIRMNGR_NAME }, + { "G13", G13_NAME }, + { "GPGCONF", GPGCONF_NAME }, + { "GPGTAR", GPGTAR_NAME } +}; + + + +/* A list to remember already done mappings. */ +struct mapping_s +{ + struct mapping_s *next; + const char *key; + const char *value; +}; +static struct mapping_s *mappings; + + +/* Similar to above but using two integers and a domain as key. */ +struct intmapping_s +{ + struct intmapping_s *next; + int key1; + int key2; + const char *string; + char domain[1]; +}; +static struct intmapping_s *intmappings; + + +/* If STRING has already been mapped, return the mapped string. If + not return NULL. */ +static const char * +already_mapped (const char *string) +{ + struct mapping_s *m; + + for (m=mappings; m; m = m->next) + if (m->key == string && !strcmp (m->key, string)) + return m->value; + return NULL; +} + + +/* Store NEWSTRING under key STRING and return NEWSTRING. */ +static const char * +store_mapping (const char *string, char *newstring) +{ + struct mapping_s *m; + + m = xmalloc (sizeof *m); + m->key = string; + m->value = newstring; + m->next = mappings; + mappings = m; + return newstring; +} + + +/* Find the first macro in STRING. Return a pointer to the + replacement value, set BEGPTR to the leading '@', and set ENDPTR to + the terminating '@'. If no macro is found return NULL. */ +const char * +find_macro (const char *string, const char **begptr, + const char **endptr) +{ + const char *s, *s2, *s3; + int idx; + + s = string; + if (!s) + return NULL; + + for (; (s2 = strchr (s, '@')); s = s2) + { + s2++; + if (*s2 >= 'A' && *s2 <= 'Z' && (s3 = (strchr (s2, '@')))) + { + for (idx=0; idx < DIM (macros); idx++) + if (strlen (macros[idx].name) == (s3 - s2) + && !memcmp (macros[idx].name, s2, (s3 - s2))) + { + *begptr = s2 - 1; + *endptr = s3; + return macros[idx].value; + } + } + } + return NULL; +} + + +/* If STRING includes known @FOO@ macros, replace these macros and + return a new static string. Warning: STRING must have been + allocated statically. Note that this function allocates memory + which will not be released (similar to gettext). */ +const char * +map_static_macro_string (const char *string) +{ + const char *s, *s2, *s3, *value; + membuf_t mb; + char *p; + + if ((s = already_mapped (string))) + return s; + s = string; + value = find_macro (s, &s2, &s3); + if (!value) + return string; /* No macros at all. */ + + init_membuf (&mb, strlen (string) + 100); + do + { + put_membuf (&mb, s, s2 - s); + put_membuf_str (&mb, value); + s = s3 + 1; + } + while ((value = find_macro (s, &s2, &s3))); + put_membuf_str (&mb, s); + put_membuf (&mb, "", 1); + + p = get_membuf_shrink (&mb, NULL); + if (!p) + log_fatal ("map_static_macro_string failed: %s\n", strerror (errno)); + + return store_mapping (string, p); +} + + +/* If a list of strings has already been mapped to a the tuple + * (DOMAIN,KEY1,KEY2) return that string. If not, create a mapping + * made up of the concatenation of the given strings. */ +const char * +map_static_strings (const char *domain, int key1, int key2, + const char *string1, ...) +{ + va_list arg_ptr; + struct intmapping_s *m; + + if (!string1 || !domain) + return ""; + + for (m = intmappings; m; m = m->next) + if (m->key1 == key1 && m->key2 == key2 && !strcmp (domain, m->domain)) + return m->string; + + m = xmalloc (sizeof *m + strlen (domain)); + strcpy (m->domain, domain); + m->key1 = key1; + m->key2 = key2; + + va_start (arg_ptr, string1); + m->string = vstrconcat (string1, arg_ptr); + va_end (arg_ptr); + if (!m->string) + log_fatal ("map_static_strings failed: %s\n", strerror (errno)); + + gpgrt_annotate_leaked_object (m->string); + gpgrt_annotate_leaked_object (m); + + m->next = intmappings; + intmappings = m; + return m->string; +} |