common: New function map_static_macro_string.
authorWerner Koch <wk@gnupg.org>
Wed, 26 Feb 2014 15:18:45 +0000 (16:18 +0100)
committerWerner Koch <wk@gnupg.org>
Wed, 26 Feb 2014 15:18:45 +0000 (16:18 +0100)
* common/mapstrings.c: New.
* common/t-mapstrings.c: New.
* common/t-support.h (DIM, DIMof): Define if not defined.
* common/Makefile.am: Add new files.

common/Makefile.am
common/mapstrings.c [new file with mode: 0644]
common/stringhelp.h
common/t-mapstrings.c [new file with mode: 0644]
common/t-support.h

index a777a34..21f779c 100644 (file)
@@ -42,7 +42,7 @@ include $(top_srcdir)/am/cmacros.am
 jnlib_sources = \
        libjnlib-config.h \
        types.h host2net.h dynload.h w32help.h \
-       stringhelp.c stringhelp.h \
+       mapstrings.c stringhelp.c stringhelp.h \
        strlist.c strlist.h \
        utf8conv.c utf8conv.h \
        argparse.c argparse.h \
@@ -165,7 +165,8 @@ if HAVE_W32_SYSTEM
 jnlib_tests += t-w32-reg
 endif
 module_tests = t-convert t-percent t-gettime t-sysutils t-sexputil \
-              t-session-env t-openpgp-oid t-ssh-utils t-dns-cert
+              t-session-env t-openpgp-oid t-ssh-utils t-dns-cert \
+              t-mapstrings
 if !HAVE_W32CE_SYSTEM
 module_tests += t-exechelp
 endif
@@ -200,3 +201,4 @@ t_session_env_LDADD = $(t_common_ldadd)
 t_openpgp_oid_LDADD = $(t_common_ldadd)
 t_ssh_utils_LDADD = $(t_common_ldadd)
 t_dns_cert_LDADD = $(t_common_ldadd) $(DNSLIBS)
+t_mapstrings_LDADD = $(t_common_ldadd)
diff --git a/common/mapstrings.c b/common/mapstrings.c
new file mode 100644 (file)
index 0000000..91795d5
--- /dev/null
@@ -0,0 +1,167 @@
+/* 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 <http://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;
+
+
+/* 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 allocated 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);
+}
index c1f7ea1..21bb20d 100644 (file)
@@ -34,6 +34,7 @@
 
 #include "types.h"
 
+/*-- stringhelp.c --*/
 char *has_leading_keyword (const char *string, const char *keyword);
 
 const char *memistr (const void *buf, size_t buflen, const char *sub);
@@ -145,5 +146,8 @@ char *strconcat (const char *s1, ...) GNUPG_GCC_A_SENTINEL(0);
 char *xstrconcat (const char *s1, ...) GNUPG_GCC_A_SENTINEL(0);
 
 
+/*-- mapstrings.c --*/
+const char *map_static_macro_string (const char *string);
+
 
 #endif /*LIBJNLIB_STRINGHELP_H*/
diff --git a/common/t-mapstrings.c b/common/t-mapstrings.c
new file mode 100644 (file)
index 0000000..14e4bb9
--- /dev/null
@@ -0,0 +1,101 @@
+/* t-mapstrings.c - Regression tests for mapstrings.c
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stringhelp.h"
+
+#include "t-support.h"
+
+static void
+test_map_static_macro_string (void)
+{
+  static struct {
+    const char *string;
+    const char *expected;
+    const char *lastresult;
+  } tests[] = {
+    { "@GPG@ (@GNUPG@)",
+      GPG_NAME " (" GNUPG_NAME ")" },
+    { "@GPG@(@GNUPG@)",
+      GPG_NAME "(" GNUPG_NAME ")" },
+    { "@GPG@@GNUPG@",
+      GPG_NAME  GNUPG_NAME },
+    { " @GPG@@GNUPG@",
+      " " GPG_NAME  GNUPG_NAME },
+    { " @GPG@@GNUPG@ ",
+      " " GPG_NAME  GNUPG_NAME " " },
+    { " @GPG@GNUPG@ ",
+      " " GPG_NAME "GNUPG@ " },
+    { " @ GPG@GNUPG@ ",
+      " @ GPG" GNUPG_NAME " " },
+    { "--@GPGTAR@",
+      "--" GPGTAR_NAME }
+  };
+  int testno;
+  const char *result;
+
+  for (testno=0; testno < DIM(tests); testno++)
+    {
+      result = map_static_macro_string (tests[testno].string);
+      if (!result)
+        fail (testno);
+      if (strcmp (result, tests[testno].expected))
+        fail (testno);
+      if (!tests[testno].lastresult)
+        tests[testno].lastresult = result;
+    }
+
+  /* A second time to check that the same string is been returned.  */
+  for (testno=0; testno < DIM(tests); testno++)
+    {
+      result = map_static_macro_string (tests[testno].string);
+      if (!result)
+        fail (testno);
+      if (strcmp (result, tests[testno].expected))
+        fail (testno);
+      if (result != tests[testno].lastresult)
+        fail (testno);
+    }
+}
+
+
+int
+main (int argc, char **argv)
+{
+  (void)argc;
+  (void)argv;
+
+  test_map_static_macro_string ();
+
+  return 0;
+}
index 8316909..0dfcc7a 100644 (file)
 # define getenv(a)  (NULL)
 #endif
 
+#ifndef DIM
+# define DIM(v)                     (sizeof(v)/sizeof((v)[0]))
+# define DIMof(type,member)   DIM(((type *)0)->member)
+#endif
+
 
 /* Replacement prototypes. */
 void *gcry_xmalloc (size_t n);