/* 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 . */ #include #include #include #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 }, { "TPM2DAEMON",TPM2DAEMON_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; /* 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); }