Coverage Report

Created: 2026-01-17 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnupg/common/mapstrings.c
Line
Count
Source
1
/* mapstrings.c - Static string mapping
2
 * Copyright (C) 2014 Werner Koch
3
 *
4
 * This file is part of GnuPG.
5
 *
6
 * This file is free software; you can redistribute it and/or modify
7
 * it under the terms of either
8
 *
9
 *   - the GNU Lesser General Public License as published by the Free
10
 *     Software Foundation; either version 3 of the License, or (at
11
 *     your option) any later version.
12
 *
13
 * or
14
 *
15
 *   - the GNU General Public License as published by the Free
16
 *     Software Foundation; either version 2 of the License, or (at
17
 *     your option) any later version.
18
 *
19
 * or both in parallel, as here.
20
 *
21
 * This file is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 * GNU General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU General Public License
27
 * along with this program; if not, see <https://www.gnu.org/licenses/>.
28
 */
29
30
#include <config.h>
31
#include <stdlib.h>
32
#include <errno.h>
33
34
#include "util.h"
35
#include "stringhelp.h"
36
#include "membuf.h"
37
38
39
static struct {
40
  const char *name;
41
  const char *value;
42
} macros[] = {
43
#ifdef PACKAGE_BUGREPORT
44
  { "EMAIL", PACKAGE_BUGREPORT },
45
#else
46
  { "EMAIL", "bug@example.org" },
47
#endif
48
  { "GNUPG",     GNUPG_NAME },
49
  { "GPG",       GPG_NAME },
50
  { "GPGSM",     GPGSM_NAME },
51
  { "GPG_AGENT", GPG_AGENT_NAME },
52
  { "SCDAEMON",  SCDAEMON_NAME },
53
  { "TPM2DAEMON",TPM2DAEMON_NAME},
54
  { "DIRMNGR",   DIRMNGR_NAME },
55
  { "G13",       G13_NAME },
56
  { "GPGCONF",   GPGCONF_NAME },
57
  { "GPGTAR",    GPGTAR_NAME }
58
};
59
60
61
62
/* A list to remember already done mappings.  */
63
struct mapping_s
64
{
65
  struct mapping_s *next;
66
  const char *key;
67
  const char *value;
68
};
69
static struct mapping_s *mappings;
70
71
72
/* Similar to above but using two integers and a domain as key.  */
73
struct intmapping_s
74
{
75
  struct intmapping_s *next;
76
  int key1;
77
  int key2;
78
  const char *string;
79
  char domain[1];
80
};
81
static struct intmapping_s *intmappings;
82
83
84
/* If STRING has already been mapped, return the mapped string.  If
85
   not return NULL.  */
86
static const char *
87
already_mapped (const char *string)
88
0
{
89
0
  struct mapping_s *m;
90
91
0
  for (m=mappings; m; m = m->next)
92
0
    if (m->key == string && !strcmp (m->key, string))
93
0
      return m->value;
94
0
  return NULL;
95
0
}
96
97
98
/* Store NEWSTRING under key STRING and return NEWSTRING.  */
99
static const char *
100
store_mapping (const char *string, char *newstring)
101
0
{
102
0
  struct mapping_s *m;
103
104
0
  m = xmalloc (sizeof *m);
105
0
  m->key = string;
106
0
  m->value = newstring;
107
0
  m->next = mappings;
108
0
  mappings = m;
109
0
  return newstring;
110
0
}
111
112
113
/* Find the first macro in STRING.  Return a pointer to the
114
   replacement value, set BEGPTR to the leading '@', and set ENDPTR to
115
   the terminating '@'.  If no macro is found return NULL.  */
116
const char *
117
find_macro (const char *string,  const char **begptr,
118
            const char **endptr)
119
0
{
120
0
  const char *s, *s2, *s3;
121
0
  int idx;
122
123
0
  s = string;
124
0
  if (!s)
125
0
    return NULL;
126
127
0
  for (; (s2 = strchr (s, '@')); s = s2)
128
0
    {
129
0
      s2++;
130
0
      if (*s2 >= 'A' && *s2 <= 'Z' && (s3 = (strchr (s2, '@'))))
131
0
        {
132
0
          for (idx=0; idx < DIM (macros); idx++)
133
0
            if (strlen (macros[idx].name) == (s3 - s2)
134
0
                && !memcmp (macros[idx].name, s2, (s3 - s2)))
135
0
              {
136
0
                *begptr = s2 - 1;
137
0
                *endptr = s3;
138
0
                return macros[idx].value;
139
0
              }
140
0
        }
141
0
    }
142
0
  return NULL;
143
0
}
144
145
146
/* If STRING includes known @FOO@ macros, replace these macros and
147
   return a new static string.  Warning: STRING must have been
148
   allocated statically.  Note that this function allocates memory
149
   which will not be released (similar to gettext).  */
150
const char *
151
map_static_macro_string (const char *string)
152
0
{
153
0
  const char *s, *s2, *s3, *value;
154
0
  membuf_t mb;
155
0
  char *p;
156
157
0
  if ((s = already_mapped (string)))
158
0
    return s;
159
0
  s = string;
160
0
  value = find_macro (s, &s2, &s3);
161
0
  if (!value)
162
0
    return string; /* No macros at all.  */
163
164
0
  init_membuf (&mb, strlen (string) + 100);
165
0
  do
166
0
    {
167
0
      put_membuf (&mb, s, s2 - s);
168
0
      put_membuf_str (&mb, value);
169
0
      s = s3 + 1;
170
0
    }
171
0
  while ((value = find_macro (s, &s2, &s3)));
172
0
  put_membuf_str (&mb, s);
173
0
  put_membuf (&mb, "", 1);
174
175
0
  p = get_membuf_shrink (&mb, NULL);
176
0
  if (!p)
177
0
    log_fatal ("map_static_macro_string failed: %s\n", strerror (errno));
178
179
0
  return store_mapping (string, p);
180
0
}
181
182
183
/* If a list of strings has already been mapped to a the tuple
184
 * (DOMAIN,KEY1,KEY2) return that string.  If not, create a mapping
185
 * made up of the concatenation of the given strings.  */
186
const char *
187
map_static_strings (const char *domain, int key1, int key2,
188
                    const char *string1, ...)
189
0
{
190
0
  va_list arg_ptr;
191
0
  struct intmapping_s *m;
192
193
0
  if (!string1 || !domain)
194
0
    return "";
195
196
0
  for (m = intmappings; m; m = m->next)
197
0
    if (m->key1 == key1 && m->key2 == key2 && !strcmp (domain, m->domain))
198
0
      return m->string;
199
200
0
  m = xmalloc (sizeof *m + strlen (domain));
201
0
  strcpy (m->domain, domain);
202
0
  m->key1 = key1;
203
0
  m->key2 = key2;
204
205
0
  va_start (arg_ptr, string1);
206
0
  m->string = vstrconcat (string1, arg_ptr);
207
0
  va_end (arg_ptr);
208
0
  if (!m->string)
209
0
    log_fatal ("map_static_strings failed: %s\n", strerror (errno));
210
211
0
  gpgrt_annotate_leaked_object (m->string);
212
0
  gpgrt_annotate_leaked_object (m);
213
214
0
  m->next = intmappings;
215
0
  intmappings = m;
216
0
  return m->string;
217
0
}