summaryrefslogtreecommitdiffstats
path: root/common/mapstrings.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/mapstrings.c')
-rw-r--r--common/mapstrings.c216
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;
+}