diff --git a/common/Makefile.am b/common/Makefile.am index a777a344b..21f779c8a 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -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 index 000000000..91795d572 --- /dev/null +++ b/common/mapstrings.c @@ -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 . + */ + +#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 }, + { "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); +} diff --git a/common/stringhelp.h b/common/stringhelp.h index c1f7ea12d..21bb20d5a 100644 --- a/common/stringhelp.h +++ b/common/stringhelp.h @@ -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 index 000000000..14e4bb9ae --- /dev/null +++ b/common/t-mapstrings.c @@ -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 . + */ + +#include +#include +#include +#include + +#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; +} diff --git a/common/t-support.h b/common/t-support.h index 8316909b5..0dfcc7a40 100644 --- a/common/t-support.h +++ b/common/t-support.h @@ -44,6 +44,11 @@ # 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);