1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-22 10:19:57 +01:00
gnupg/common/mapstrings.c
Werner Koch c145366549
common: New function map_static_strings
* common/mapstrings.c (struct intmapping_s): New.
(map_static_strings): New.
* common/stringhelp.c (do_strconcat): Rename to ...
(vstrconcat): this and make global.

* common/t-mapstrings.c (test_map_static_strings): New test.
2022-03-18 13:47:10 +01:00

217 lines
5.3 KiB
C

/* 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;
}