diff --git a/common/mapstrings.c b/common/mapstrings.c index 318ca5bd1..172e198ea 100644 --- a/common/mapstrings.c +++ b/common/mapstrings.c @@ -69,6 +69,18 @@ struct mapping_s 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 * @@ -166,3 +178,40 @@ map_static_macro_string (const char *string) 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; +} diff --git a/common/stringhelp.c b/common/stringhelp.c index c9e10800d..3e56d664d 100644 --- a/common/stringhelp.c +++ b/common/stringhelp.c @@ -1169,9 +1169,10 @@ try_percent_escape (const char *str, const char *extra) } - -static char * -do_strconcat (const char *s1, va_list arg_ptr) +/* Same as strconcat but takes a va_list. Returns EINVAL if the list + * is too long, all other errors are due to an ENOMEM condition. */ +char * +vstrconcat (const char *s1, va_list arg_ptr) { const char *argv[48]; size_t argc; @@ -1216,7 +1217,7 @@ strconcat (const char *s1, ...) else { va_start (arg_ptr, s1); - result = do_strconcat (s1, arg_ptr); + result = vstrconcat (s1, arg_ptr); va_end (arg_ptr); } return result; @@ -1235,7 +1236,7 @@ xstrconcat (const char *s1, ...) else { va_start (arg_ptr, s1); - result = do_strconcat (s1, arg_ptr); + result = vstrconcat (s1, arg_ptr); va_end (arg_ptr); } if (!result) diff --git a/common/stringhelp.h b/common/stringhelp.h index cd874af2e..915b3aa72 100644 --- a/common/stringhelp.h +++ b/common/stringhelp.h @@ -141,9 +141,12 @@ char *try_percent_escape (const char *str, const char *extra); NULL. Returns a malloced buffer with the new string or NULL on a malloc error or if too many arguments are given. */ char *strconcat (const char *s1, ...) GPGRT_ATTR_SENTINEL(0); +/* Same but taking a va_list. */ +char *vstrconcat (const char *s1, va_list arg_ptr); /* Ditto, but die on error. */ char *xstrconcat (const char *s1, ...) GPGRT_ATTR_SENTINEL(0); + char **strsplit (char *string, char delim, char replacement, int *count); /* Tokenize STRING using the set of delimiters in DELIM. */ @@ -172,5 +175,7 @@ char *substitute_envvars (const char *string); /*-- mapstrings.c --*/ const char *map_static_macro_string (const char *string); +const char *map_static_strings (const char *domain, int key1, int key2, + const char *string1, ...); #endif /*GNUPG_COMMON_STRINGHELP_H*/ diff --git a/common/t-mapstrings.c b/common/t-mapstrings.c index 0856c3cc4..7dc622177 100644 --- a/common/t-mapstrings.c +++ b/common/t-mapstrings.c @@ -88,6 +88,31 @@ test_map_static_macro_string (void) } +static void +test_map_static_strings (void) +{ + const char *s, *s1; + + s1 = map_static_strings ("mydomain", 0, 42, + "This", " ", "is", " ", "my"," ","string", NULL); + if (strcmp (s1, "This is my string")) + fail (1); + s = map_static_strings ("mydomain", 0, 42, + "This", " ", "is", " ", "my"," ","string", NULL); + if (strcmp (s1, s)) + fail (2); + s = map_static_strings ("mydomain", 0, 42, "foo", NULL); + if (strcmp (s1, s)) + fail (3); + s = map_static_strings ("mydomain", 1, 42, "foo 1.42", NULL); + if (!strcmp (s1, s)) + fail (4); + s = map_static_strings ("xdomain", 1, 42, "foo 1.42 other domain", NULL); + if (!strcmp (s1, s)) + fail (5); +} + + int main (int argc, char **argv) { @@ -95,6 +120,7 @@ main (int argc, char **argv) (void)argv; test_map_static_macro_string (); + test_map_static_strings (); return 0; }