Coverage Report

Created: 2026-09-01 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnupg/common/stringhelp.c
Line
Count
Source
1
/* stringhelp.c -  standard string helper functions
2
 * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007,
3
 *               2008, 2009, 2010  Free Software Foundation, Inc.
4
 * Copyright (C) 2014 Werner Koch
5
 * Copyright (C) 2015, 2021, 2025  g10 Code GmbH
6
 *
7
 * This file is part of GnuPG.
8
 *
9
 * GnuPG is free software; you can redistribute and/or modify this
10
 * part of GnuPG under the terms of either
11
 *
12
 *   - the GNU Lesser General Public License as published by the Free
13
 *     Software Foundation; either version 3 of the License, or (at
14
 *     your option) any later version.
15
 *
16
 * or
17
 *
18
 *   - the GNU General Public License as published by the Free
19
 *     Software Foundation; either version 2 of the License, or (at
20
 *     your option) any later version.
21
 *
22
 * or both in parallel, as here.
23
 *
24
 * GnuPG is distributed in the hope that it will be useful, but
25
 * WITHOUT ANY WARRANTY; without even the implied warranty of
26
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
27
 * General Public License for more details.
28
 *
29
 * You should have received a copies of the GNU General Public License
30
 * and the GNU Lesser General Public License along with this program;
31
 * if not, see <https://www.gnu.org/licenses/>.
32
 * SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
33
 */
34
35
#include <config.h>
36
#include <stdlib.h>
37
#include <string.h>
38
#include <stdarg.h>
39
#include <ctype.h>
40
#include <errno.h>
41
#ifdef HAVE_PWD_H
42
# include <pwd.h>
43
#endif
44
#include <unistd.h>
45
#include <sys/types.h>
46
#ifdef HAVE_W32_SYSTEM
47
# ifdef HAVE_WINSOCK2_H
48
#  include <winsock2.h>
49
# endif
50
# include <windows.h>
51
#endif
52
#include <limits.h>
53
54
#include "util.h"
55
#include "common-defs.h"
56
#include "utf8conv.h"
57
#include "sysutils.h"
58
#include "stringhelp.h"
59
60
0
#define tohex_lower(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'a'))
61
62
63
/* Sometimes we want to avoid mixing slashes and backslashes on W32
64
   and prefer backslashes.  There is usual no problem with mixing
65
   them, however a very few W32 API calls can't grok plain slashes.
66
   Printing filenames with mixed slashes also looks a bit strange.
67
   This function has no effext on POSIX. */
68
static inline char *
69
change_slashes (char *name)
70
2.39k
{
71
#ifdef HAVE_DOSISH_SYSTEM
72
  char *p;
73
74
  if (windows_semihosted_by_wine)
75
    return name;
76
77
  if (strchr (name, '\\'))
78
    {
79
      for (p=name; *p; p++)
80
        if (*p == '/')
81
          *p = '\\';
82
    }
83
#endif /*HAVE_DOSISH_SYSTEM*/
84
2.39k
  return name;
85
2.39k
}
86
87
88
/*
89
 * Check whether STRING starts with KEYWORD.  The keyword is
90
 * delimited by end of string, a space or a tab.  Returns NULL if not
91
 * found or a pointer into STRING to the next non-space character
92
 * after the KEYWORD (which may be end of string).
93
 */
94
char *
95
has_leading_keyword (const char *string, const char *keyword)
96
0
{
97
0
  size_t n = strlen (keyword);
98
99
0
  if (!strncmp (string, keyword, n)
100
0
      && (!string[n] || string[n] == ' ' || string[n] == '\t'))
101
0
    {
102
0
      string += n;
103
0
      while (*string == ' ' || *string == '\t')
104
0
        string++;
105
0
      return (char*)string;
106
0
    }
107
0
  return NULL;
108
0
}
109
110
111
/*
112
 * Look for the substring SUB in buffer and return a pointer to that
113
 * substring in BUFFER or NULL if not found.
114
 * Comparison is case-insensitive.
115
 */
116
const char *
117
memistr (const void *buffer, size_t buflen, const char *sub)
118
0
{
119
0
  const unsigned char *buf = buffer;
120
0
  const unsigned char *t = (const unsigned char *)buffer;
121
0
  const unsigned char *s = (const unsigned char *)sub;
122
0
  size_t n = buflen;
123
124
0
  for ( ; n ; t++, n-- )
125
0
    {
126
0
      if ( toupper (*t) == toupper (*s) )
127
0
        {
128
0
          for ( buf=t++, buflen = n--, s++;
129
0
                n && toupper (*t) == toupper (*s); t++, s++, n-- )
130
0
            ;
131
0
          if (!*s)
132
0
            return (const char*)buf;
133
0
          t = buf;
134
0
          s = (const unsigned char *)sub ;
135
0
          n = buflen;
136
0
  }
137
0
    }
138
0
  return NULL;
139
0
}
140
141
const char *
142
ascii_memistr ( const void *buffer, size_t buflen, const char *sub )
143
0
{
144
0
  const unsigned char *buf = buffer;
145
0
  const unsigned char *t = (const unsigned char *)buf;
146
0
  const unsigned char *s = (const unsigned char *)sub;
147
0
  size_t n = buflen;
148
149
0
  for ( ; n ; t++, n-- )
150
0
    {
151
0
      if (ascii_toupper (*t) == ascii_toupper (*s) )
152
0
        {
153
0
          for ( buf=t++, buflen = n--, s++;
154
0
                n && ascii_toupper (*t) == ascii_toupper (*s); t++, s++, n-- )
155
0
            ;
156
0
          if (!*s)
157
0
            return (const char*)buf;
158
0
          t = (const unsigned char *)buf;
159
0
          s = (const unsigned char *)sub ;
160
0
          n = buflen;
161
0
  }
162
0
    }
163
0
  return NULL;
164
0
}
165
166
167
/* This is a case-sensitive version of our memistr.  I wonder why no
168
 * standard function memstr exists but we better do not use the name
169
 * memstr to avoid future conflicts.
170
 */
171
const char *
172
gnupg_memstr (const void *buffer, size_t buflen, const char *sub)
173
567
{
174
567
  const unsigned char *buf = buffer;
175
567
  const unsigned char *t = (const unsigned char *)buf;
176
567
  const unsigned char *s = (const unsigned char *)sub;
177
567
  size_t n = buflen;
178
179
3.79k
  for ( ; n ; t++, n-- )
180
3.65k
    {
181
3.65k
      if (*t == *s)
182
1.32k
        {
183
1.75k
          for (buf = t++, buflen = n--, s++; n && *t ==*s; t++, s++, n--)
184
429
            ;
185
1.32k
          if (!*s)
186
429
            return (const char*)buf;
187
899
          t = (const unsigned char *)buf;
188
899
          s = (const unsigned char *)sub ;
189
899
          n = buflen;
190
899
  }
191
3.65k
    }
192
138
  return NULL;
193
567
}
194
195
196
/* This function is similar to strncpy().  However it won't copy more
197
 * than N - 1 characters and makes sure that a '\0' is appended. With
198
 * N given as 0, nothing will happen.  With DEST given as NULL, memory
199
 * will be allocated using xmalloc (i.e. if it runs out of core the
200
 * function terminates).  Returns DEST or a pointer to the allocated
201
 * memory.
202
 */
203
char *
204
mem2str (char *dest, const void *src, size_t n)
205
0
{
206
0
  char *d;
207
0
  const char *s;
208
209
0
  if (n)
210
0
    {
211
0
      if (!dest)
212
0
        dest = xmalloc (n);
213
0
      d = dest;
214
0
      s = src ;
215
0
      for (n--; n && *s; n--)
216
0
        *d++ = *s++;
217
0
      *d = '\0' ;
218
0
    }
219
220
0
  return dest;
221
0
}
222
223
224
/****************
225
 * remove leading and trailing white spaces
226
 */
227
char *
228
trim_spaces( char *str )
229
0
{
230
0
    char *string, *p, *mark;
231
232
0
    string = str;
233
    /* find first non space character */
234
0
    for( p=string; *p && isspace( *(byte*)p ) ; p++ )
235
0
  ;
236
    /* move characters */
237
0
    for( (mark = NULL); (*string = *p); string++, p++ )
238
0
  if( isspace( *(byte*)p ) ) {
239
0
      if( !mark )
240
0
    mark = string ;
241
0
  }
242
0
  else
243
0
      mark = NULL ;
244
0
    if( mark )
245
0
  *mark = '\0' ;  /* remove trailing spaces */
246
247
0
    return str ;
248
0
}
249
250
251
/* Same as trim_spaces but only consider, space, tab, cr and lf as space.  */
252
char *
253
ascii_trim_spaces (char *str)
254
0
{
255
0
  char *string, *p, *mark;
256
257
0
  string = str;
258
259
  /* Find first non-ascii space character.  */
260
0
  for (p=string; *p && ascii_isspace (*p); p++)
261
0
    ;
262
  /* Move characters.  */
263
0
  for (mark=NULL; (*string = *p); string++, p++ )
264
0
    {
265
0
      if (ascii_isspace (*p))
266
0
        {
267
0
          if (!mark)
268
0
            mark = string;
269
0
        }
270
0
      else
271
0
        mark = NULL ;
272
0
    }
273
0
  if (mark)
274
0
    *mark = '\0' ;  /* Remove trailing spaces. */
275
276
0
  return str ;
277
0
}
278
279
280
/****************
281
 * remove trailing white spaces
282
 */
283
char *
284
trim_trailing_spaces( char *string )
285
0
{
286
0
    char *p, *mark;
287
288
0
    for( mark = NULL, p = string; *p; p++ ) {
289
0
  if( isspace( *(byte*)p ) ) {
290
0
      if( !mark )
291
0
    mark = p;
292
0
  }
293
0
  else
294
0
      mark = NULL;
295
0
    }
296
0
    if( mark )
297
0
  *mark = '\0' ;
298
299
0
    return string ;
300
0
}
301
302
303
unsigned
304
trim_trailing_chars( byte *line, unsigned len, const char *trimchars )
305
0
{
306
0
    byte *p, *mark;
307
0
    unsigned n;
308
309
0
    for(mark=NULL, p=line, n=0; n < len; n++, p++ ) {
310
0
  if( strchr(trimchars, *p ) ) {
311
0
      if( !mark )
312
0
    mark = p;
313
0
  }
314
0
  else
315
0
      mark = NULL;
316
0
    }
317
318
0
    if( mark ) {
319
0
  *mark = 0;
320
0
  return mark - line;
321
0
    }
322
0
    return len;
323
0
}
324
325
/****************
326
 * remove trailing white spaces and return the length of the buffer
327
 */
328
unsigned
329
trim_trailing_ws( byte *line, unsigned len )
330
0
{
331
0
    return trim_trailing_chars( line, len, " \t\r\n" );
332
0
}
333
334
size_t
335
length_sans_trailing_chars (const unsigned char *line, size_t len,
336
                            const char *trimchars )
337
11.7k
{
338
11.7k
  const unsigned char *p, *mark;
339
11.7k
  size_t n;
340
341
175k
  for( mark=NULL, p=line, n=0; n < len; n++, p++ )
342
163k
    {
343
163k
      if (strchr (trimchars, *p ))
344
24.0k
        {
345
24.0k
          if( !mark )
346
20.3k
            mark = p;
347
24.0k
        }
348
139k
      else
349
139k
        mark = NULL;
350
163k
    }
351
352
11.7k
  if (mark)
353
11.3k
    return mark - line;
354
350
  return len;
355
11.7k
}
356
357
/*
358
 *  Return the length of line ignoring trailing white-space.
359
 */
360
size_t
361
length_sans_trailing_ws (const unsigned char *line, size_t len)
362
11.7k
{
363
11.7k
  return length_sans_trailing_chars (line, len, " \t\r\n");
364
11.7k
}
365
366
367
368
/*
369
 * Extract from a given path the filename component.  This function
370
 * terminates the process on memory shortage.
371
 */
372
char *
373
make_basename(const char *filepath, const char *inputpath)
374
0
{
375
#ifdef __riscos__
376
    return riscos_make_basename(filepath, inputpath);
377
#else
378
0
    char *p;
379
380
0
    (void)inputpath; /* Only required for riscos.  */
381
382
0
    if ( !(p=strrchr(filepath, '/')) )
383
#ifdef HAVE_DOSISH_SYSTEM
384
  if ( !(p=strrchr(filepath, '\\')) )
385
#endif
386
#ifdef HAVE_DRIVE_LETTERS
387
      if ( !(p=strrchr(filepath, ':')) )
388
#endif
389
0
        {
390
0
    return xstrdup(filepath);
391
0
        }
392
393
0
    return xstrdup(p+1);
394
0
#endif
395
0
}
396
397
398
399
/*
400
 * Extract from a given filename the path prepended to it.  If there
401
 * isn't a path prepended to the filename, a dot is returned ('.').
402
 * This function terminates the process on memory shortage.
403
 */
404
char *
405
make_dirname(const char *filepath)
406
0
{
407
0
    char *dirname;
408
0
    int  dirname_length;
409
0
    char *p;
410
411
0
    if ( !(p=strrchr(filepath, '/')) )
412
#ifdef HAVE_DOSISH_SYSTEM
413
  if ( !(p=strrchr(filepath, '\\')) )
414
#endif
415
#ifdef HAVE_DRIVE_LETTERS
416
      if ( !(p=strrchr(filepath, ':')) )
417
#endif
418
0
        {
419
0
    return xstrdup(".");
420
0
        }
421
422
0
    dirname_length = p-filepath;
423
0
    dirname = xmalloc(dirname_length+1);
424
0
    strncpy(dirname, filepath, dirname_length);
425
0
    dirname[dirname_length] = 0;
426
427
0
    return dirname;
428
0
}
429
430
431

432
static char *
433
get_pwdir (int xmode, const char *name)
434
0
{
435
0
  char *result = NULL;
436
0
#ifdef HAVE_PWD_H
437
0
  struct passwd *pwd = NULL;
438
439
0
  if (name)
440
0
    {
441
0
#ifdef HAVE_GETPWNAM
442
      /* Fixme: We should use getpwnam_r if available.  */
443
0
      pwd = getpwnam (name);
444
0
#endif
445
0
    }
446
0
  else
447
0
    {
448
0
#ifdef HAVE_GETPWUID
449
      /* Fixme: We should use getpwuid_r if available.  */
450
0
      pwd = getpwuid (getuid());
451
0
#endif
452
0
    }
453
0
  if (pwd)
454
0
    {
455
0
      if (xmode)
456
0
        result = xstrdup (pwd->pw_dir);
457
0
      else
458
0
        result = xtrystrdup (pwd->pw_dir);
459
0
    }
460
#else /*!HAVE_PWD_H*/
461
  /* No support at all.  */
462
  (void)xmode;
463
  (void)name;
464
#endif /*HAVE_PWD_H*/
465
0
  return result;
466
0
}
467
468
469
/* xmode 0 := Return NULL on error
470
         1 := Terminate on error
471
         2 := Make sure that name is absolute; return NULL on error
472
         3 := Make sure that name is absolute; terminate on error
473
 */
474
static char *
475
do_make_filename (int xmode, const char *first_part, va_list arg_ptr)
476
2.39k
{
477
2.39k
  const char *argv[32];
478
2.39k
  int argc;
479
2.39k
  size_t n;
480
2.39k
  int skip = 1;
481
2.39k
  char *home_buffer = NULL;
482
2.39k
  char *name, *home, *p;
483
2.39k
  int want_abs;
484
485
2.39k
  want_abs = !!(xmode & 2);
486
2.39k
  xmode &= 1;
487
488
2.39k
  n = strlen (first_part) + 1;
489
2.39k
  argc = 0;
490
4.79k
  while ( (argv[argc] = va_arg (arg_ptr, const char *)) )
491
2.39k
    {
492
2.39k
      n += strlen (argv[argc]) + 1;
493
2.39k
      if (argc >= DIM (argv)-1)
494
0
        {
495
0
          if (xmode)
496
0
            BUG ();
497
0
          gpg_err_set_errno (EINVAL);
498
0
          return NULL;
499
0
        }
500
2.39k
      argc++;
501
2.39k
    }
502
2.39k
  n++;
503
504
2.39k
  home = NULL;
505
2.39k
  if (*first_part == '~')
506
1
    {
507
1
      if (first_part[1] == '/' || !first_part[1])
508
1
        {
509
          /* This is the "~/" or "~" case.  */
510
1
          home = getenv("HOME");
511
1
          if (!home)
512
0
            home = home_buffer = get_pwdir (xmode, NULL);
513
1
          if (home && *home)
514
1
            n += strlen (home);
515
1
        }
516
0
      else
517
0
        {
518
          /* This is the "~username/" or "~username" case.  */
519
0
          char *user;
520
521
0
          if (xmode)
522
0
            user = xstrdup (first_part+1);
523
0
          else
524
0
            {
525
0
              user = xtrystrdup (first_part+1);
526
0
              if (!user)
527
0
                return NULL;
528
0
            }
529
0
          p = strchr (user, '/');
530
0
          if (p)
531
0
            *p = 0;
532
0
          skip = 1 + strlen (user);
533
534
0
          home = home_buffer = get_pwdir (xmode, user);
535
0
          xfree (user);
536
0
          if (home)
537
0
            n += strlen (home);
538
0
          else
539
0
            skip = 1;
540
0
        }
541
1
    }
542
543
2.39k
  if (xmode)
544
2.39k
    name = xmalloc (n);
545
0
  else
546
0
    {
547
0
      name = xtrymalloc (n);
548
0
      if (!name)
549
0
        {
550
0
          xfree (home_buffer);
551
0
          return NULL;
552
0
        }
553
0
    }
554
555
2.39k
  if (home)
556
1
    p = stpcpy (stpcpy (name, home), first_part + skip);
557
2.39k
  else
558
2.39k
    p = stpcpy (name, first_part);
559
560
2.39k
  xfree (home_buffer);
561
4.79k
  for (argc=0; argv[argc]; argc++)
562
2.39k
    {
563
      /* Avoid a leading double slash if the first part was "/".  */
564
2.39k
      if (!argc && name[0] == '/' && !name[1])
565
0
        p = stpcpy (p, argv[argc]);
566
2.39k
      else
567
2.39k
        p = stpcpy (stpcpy (p, "/"), argv[argc]);
568
2.39k
    }
569
570
2.39k
  if (want_abs)
571
3
    {
572
#ifdef HAVE_DRIVE_LETTERS
573
      p = strchr (name, ':');
574
      if (p)
575
        p++;
576
      else
577
        p = name;
578
#else
579
3
      p = name;
580
3
#endif
581
3
      if (*p != '/'
582
#ifdef HAVE_DRIVE_LETTERS
583
          && *p != '\\'
584
#endif
585
3
          )
586
0
        {
587
0
          home = gnupg_getcwd ();
588
0
          if (!home)
589
0
            {
590
0
              if (xmode)
591
0
                {
592
0
                  fprintf (stderr, "\nfatal: getcwd failed: %s\n",
593
0
                           strerror (errno));
594
0
                  exit(2);
595
0
                }
596
0
              xfree (name);
597
0
              return NULL;
598
0
            }
599
0
          n = strlen (home) + 1 + strlen (name) + 1;
600
0
          if (xmode)
601
0
            home_buffer = xmalloc (n);
602
0
          else
603
0
            {
604
0
              home_buffer = xtrymalloc (n);
605
0
              if (!home_buffer)
606
0
                {
607
0
                  xfree (home);
608
0
                  xfree (name);
609
0
                  return NULL;
610
0
                }
611
0
            }
612
0
          if (p == name)
613
0
            p = home_buffer;
614
0
          else /* Windows case.  */
615
0
            {
616
0
              memcpy (home_buffer, p, p - name + 1);
617
0
              p = home_buffer + (p - name + 1);
618
0
            }
619
620
          /* Avoid a leading double slash if the cwd is "/".  */
621
0
          if (home[0] == '/' && !home[1])
622
0
            strcpy (stpcpy (p, "/"), name);
623
0
          else
624
0
            strcpy (stpcpy (stpcpy (p, home), "/"), name);
625
626
0
          xfree (home);
627
0
          xfree (name);
628
0
          name = home_buffer;
629
          /* Let's do a simple compression to catch the most common
630
             case of using "." for gpg's --homedir option.  */
631
0
          n = strlen (name);
632
0
          if (n > 2 && name[n-2] == '/' && name[n-1] == '.')
633
0
            name[n-2] = 0;
634
0
        }
635
3
    }
636
2.39k
  return change_slashes (name);
637
2.39k
}
638
639
/* Construct a filename from the NULL terminated list of parts.  Tilde
640
   expansion is done for the first argument.  This function terminates
641
   the process on memory shortage. */
642
char *
643
make_filename (const char *first_part, ... )
644
2.39k
{
645
2.39k
  va_list arg_ptr;
646
2.39k
  char *result;
647
648
2.39k
  va_start (arg_ptr, first_part);
649
2.39k
  result = do_make_filename (1, first_part, arg_ptr);
650
2.39k
  va_end (arg_ptr);
651
2.39k
  return result;
652
2.39k
}
653
654
/* Construct a filename from the NULL terminated list of parts.  Tilde
655
   expansion is done for the first argument.  This function may return
656
   NULL on error. */
657
char *
658
make_filename_try (const char *first_part, ... )
659
0
{
660
0
  va_list arg_ptr;
661
0
  char *result;
662
663
0
  va_start (arg_ptr, first_part);
664
0
  result = do_make_filename (0, first_part, arg_ptr);
665
0
  va_end (arg_ptr);
666
0
  return result;
667
0
}
668
669
/* Construct an absolute filename from the NULL terminated list of
670
   parts.  Tilde expansion is done for the first argument.  This
671
   function terminates the process on memory shortage. */
672
char *
673
make_absfilename (const char *first_part, ... )
674
3
{
675
3
  va_list arg_ptr;
676
3
  char *result;
677
678
3
  va_start (arg_ptr, first_part);
679
3
  result = do_make_filename (3, first_part, arg_ptr);
680
3
  va_end (arg_ptr);
681
3
  return result;
682
3
}
683
684
/* Construct an absolute filename from the NULL terminated list of
685
   parts.  Tilde expansion is done for the first argument.  This
686
   function may return NULL on error. */
687
char *
688
make_absfilename_try (const char *first_part, ... )
689
0
{
690
0
  va_list arg_ptr;
691
0
  char *result;
692
693
0
  va_start (arg_ptr, first_part);
694
0
  result = do_make_filename (2, first_part, arg_ptr);
695
0
  va_end (arg_ptr);
696
0
  return result;
697
0
}
698
699
700

701
/* Compare whether the filenames are identical.  This is a
702
   special version of strcmp() taking the semantics of filenames in
703
   account.  Note that this function works only on the supplied names
704
   without considering any context like the current directory.  See
705
   also same_file_p(). */
706
int
707
compare_filenames (const char *a, const char *b)
708
1
{
709
#ifdef HAVE_DOSISH_SYSTEM
710
  for ( ; *a && *b; a++, b++ )
711
    {
712
      if (*a != *b
713
          && (toupper (*(const unsigned char*)a)
714
              != toupper (*(const unsigned char*)b) )
715
          && !((*a == '/' && *b == '\\') || (*a == '\\' && *b == '/')))
716
        break;
717
    }
718
  if ((*a == '/' && *b == '\\') || (*a == '\\' && *b == '/'))
719
    return 0;
720
  else
721
    return (toupper (*(const unsigned char*)a)
722
            - toupper (*(const unsigned char*)b));
723
#else
724
1
    return strcmp(a,b);
725
1
#endif
726
1
}
727
728
729
/* Check if the FNAME has SUFFIX */
730
int
731
has_suffix (const char *fname, const char *suffix)
732
0
{
733
0
  size_t len = strlen (fname);
734
0
  size_t suffix_len = strlen (suffix);
735
736
0
  if (len > suffix_len
737
0
      && !memcmp (fname + len - suffix_len, suffix, suffix_len))
738
0
    return 1;
739
0
  else
740
0
    return 0;
741
0
}
742
743
/* Convert a base-10 number in STRING into a 64 bit unsigned int
744
 * value.  Leading white spaces are skipped but no error checking is
745
 * done.  Thus it is similar to atoi().  See also scan_secondsstr.  */
746
uint64_t
747
string_to_u64 (const char *string)
748
0
{
749
0
  uint64_t val = 0;
750
751
0
  while (spacep (string))
752
0
    string++;
753
0
  for (; digitp (string); string++)
754
0
    {
755
0
      val *= 10;
756
0
      val += *string - '0';
757
0
    }
758
0
  return val;
759
0
}
760
761
762
/* Convert 2 hex characters at S to a byte value.  Return this value
763
   or -1 if there is an error. */
764
int
765
hextobyte (const char *s)
766
0
{
767
0
  int c;
768
769
0
  if ( *s >= '0' && *s <= '9' )
770
0
    c = 16 * (*s - '0');
771
0
  else if ( *s >= 'A' && *s <= 'F' )
772
0
    c = 16 * (10 + *s - 'A');
773
0
  else if ( *s >= 'a' && *s <= 'f' )
774
0
    c = 16 * (10 + *s - 'a');
775
0
  else
776
0
    return -1;
777
0
  s++;
778
0
  if ( *s >= '0' && *s <= '9' )
779
0
    c += *s - '0';
780
0
  else if ( *s >= 'A' && *s <= 'F' )
781
0
    c += 10 + *s - 'A';
782
0
  else if ( *s >= 'a' && *s <= 'f' )
783
0
    c += 10 + *s - 'a';
784
0
  else
785
0
    return -1;
786
0
  return c;
787
0
}
788
789
/* Given a string containing an UTF-8 encoded text, return the number
790
   of characters in this string.  It differs from strlen in that it
791
   only counts complete UTF-8 characters.  SIZE is the maximum length
792
   of the string in bytes.  If SIZE is -1, then a NUL character is
793
   taken to be the end of the string.  Note, that this function does
794
   not take combined characters into account.  */
795
size_t
796
utf8_charcount (const char *s, int len)
797
0
{
798
0
  size_t n;
799
800
0
  if (len == 0)
801
0
    return 0;
802
803
0
  for (n=0; *s; s++)
804
0
    {
805
0
      if ( (*s&0xc0) != 0x80 ) /* Exclude continuation bytes: 10xxxxxx */
806
0
        n++;
807
808
0
      if (len != -1)
809
0
        {
810
0
          len --;
811
0
          if (len == 0)
812
0
            break;
813
0
        }
814
0
    }
815
816
0
  return n;
817
0
}
818
819
820
/****************************************************
821
 **********  W32 specific functions  ****************
822
 ****************************************************/
823
824
#ifdef HAVE_W32_SYSTEM
825
const char *
826
w32_strerror (int ec)
827
{
828
  static char strerr[256];
829
830
  if (ec == -1)
831
    ec = (int)GetLastError ();
832
  FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec,
833
                 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
834
                 strerr, DIM (strerr)-1, NULL);
835
  {
836
    /* Strip the CR,LF - we want just the string.  */
837
    size_t n = strlen (strerr);
838
    if (n > 2 && strerr[n-2] == '\r' && strerr[n-1] == '\n' )
839
      strerr[n-2] = 0;
840
  }
841
  return strerr;
842
}
843
#endif /*HAVE_W32_SYSTEM*/
844
845
846
/****************************************************
847
 ******** Locale insensitive ctype functions ********
848
 ****************************************************/
849
/* FIXME: replace them by a table lookup and macros */
850
int
851
ascii_isupper (int c)
852
0
{
853
0
    return c >= 'A' && c <= 'Z';
854
0
}
855
856
int
857
ascii_islower (int c)
858
0
{
859
0
    return c >= 'a' && c <= 'z';
860
0
}
861
862
int
863
ascii_toupper (int c)
864
717
{
865
717
    if (c >= 'a' && c <= 'z')
866
192
        c &= ~0x20;
867
717
    return c;
868
717
}
869
870
int
871
ascii_tolower (int c)
872
0
{
873
0
    if (c >= 'A' && c <= 'Z')
874
0
        c |= 0x20;
875
0
    return c;
876
0
}
877
878
/* Lowercase all ASCII characters in S.  */
879
char *
880
ascii_strlwr (char *s)
881
370
{
882
370
  char *p = s;
883
884
6.46k
  for (p=s; *p; p++ )
885
6.09k
    if (isascii (*p) && *p >= 'A' && *p <= 'Z')
886
44
      *p |= 0x20;
887
888
370
  return s;
889
370
}
890
891
/* Upcase all ASCII characters in S.  */
892
char *
893
ascii_strupr (char *s)
894
0
{
895
0
  char *p = s;
896
897
0
  for (p=s; *p; p++ )
898
0
    if (isascii (*p) && *p >= 'a' && *p <= 'z')
899
0
      *p &= ~0x20;
900
901
0
  return s;
902
0
}
903
904
int
905
ascii_strcasecmp( const char *a, const char *b )
906
0
{
907
0
    if (a == b)
908
0
        return 0;
909
910
0
    for (; *a && *b; a++, b++) {
911
0
  if (*a != *b && ascii_toupper(*a) != ascii_toupper(*b))
912
0
      break;
913
0
    }
914
0
    return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
915
0
}
916
917
int
918
ascii_strncasecmp (const char *a, const char *b, size_t n)
919
0
{
920
0
  const unsigned char *p1 = (const unsigned char *)a;
921
0
  const unsigned char *p2 = (const unsigned char *)b;
922
0
  unsigned char c1, c2;
923
924
0
  if (p1 == p2 || !n )
925
0
    return 0;
926
927
0
  do
928
0
    {
929
0
      c1 = ascii_tolower (*p1);
930
0
      c2 = ascii_tolower (*p2);
931
932
0
      if ( !--n || c1 == '\0')
933
0
  break;
934
935
0
      ++p1;
936
0
      ++p2;
937
0
    }
938
0
  while (c1 == c2);
939
940
0
  return c1 - c2;
941
0
}
942
943
944
int
945
ascii_memcasecmp (const void *a_arg, const void *b_arg, size_t n )
946
0
{
947
0
  const char *a = a_arg;
948
0
  const char *b = b_arg;
949
950
0
  if (a == b)
951
0
    return 0;
952
0
  for ( ; n; n--, a++, b++ )
953
0
    {
954
0
      if( *a != *b  && ascii_toupper (*a) != ascii_toupper (*b) )
955
0
        return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
956
0
    }
957
0
  return 0;
958
0
}
959
960
int
961
ascii_strcmp( const char *a, const char *b )
962
0
{
963
0
    if (a == b)
964
0
        return 0;
965
966
0
    for (; *a && *b; a++, b++) {
967
0
  if (*a != *b )
968
0
      break;
969
0
    }
970
0
    return *a == *b? 0 : (*(signed char *)a - *(signed char *)b);
971
0
}
972
973
974
void *
975
ascii_memcasemem (const void *haystack, size_t nhaystack,
976
                  const void *needle, size_t nneedle)
977
0
{
978
979
0
  if (!nneedle)
980
0
    return (void*)haystack; /* finding an empty needle is really easy */
981
0
  if (nneedle <= nhaystack)
982
0
    {
983
0
      const char *a = haystack;
984
0
      const char *b = a + nhaystack - nneedle;
985
986
0
      for (; a <= b; a++)
987
0
        {
988
0
          if ( !ascii_memcasecmp (a, needle, nneedle) )
989
0
            return (void *)a;
990
0
        }
991
0
    }
992
0
  return NULL;
993
0
}
994
995
/*********************************************
996
 ********** missing string functions *********
997
 *********************************************/
998
999
#ifndef HAVE_STPCPY
1000
char *
1001
stpcpy(char *a,const char *b)
1002
{
1003
    while( *b )
1004
  *a++ = *b++;
1005
    *a = 0;
1006
1007
    return (char*)a;
1008
}
1009
#endif
1010
1011
#ifndef HAVE_STRPBRK
1012
/* Find the first occurrence in S of any character in ACCEPT.
1013
   Code taken from glibc-2.6/string/strpbrk.c (LGPLv2.1+) and modified. */
1014
char *
1015
strpbrk (const char *s, const char *accept)
1016
{
1017
  while (*s != '\0')
1018
    {
1019
      const char *a = accept;
1020
      while (*a != '\0')
1021
  if (*a++ == *s)
1022
    return (char *) s;
1023
      ++s;
1024
    }
1025
1026
  return NULL;
1027
}
1028
#endif /*!HAVE_STRPBRK*/
1029
1030
1031
#ifndef HAVE_STRSEP
1032
/* Code taken from glibc-2.2.1/sysdeps/generic/strsep.c. */
1033
char *
1034
strsep (char **stringp, const char *delim)
1035
{
1036
  char *begin, *end;
1037
1038
  begin = *stringp;
1039
  if (begin == NULL)
1040
    return NULL;
1041
1042
  /* A frequent case is when the delimiter string contains only one
1043
     character.  Here we don't need to call the expensive 'strpbrk'
1044
     function and instead work using 'strchr'.  */
1045
  if (delim[0] == '\0' || delim[1] == '\0')
1046
    {
1047
      char ch = delim[0];
1048
1049
      if (ch == '\0')
1050
        end = NULL;
1051
      else
1052
        {
1053
          if (*begin == ch)
1054
            end = begin;
1055
          else if (*begin == '\0')
1056
            end = NULL;
1057
          else
1058
            end = strchr (begin + 1, ch);
1059
        }
1060
    }
1061
  else
1062
    /* Find the end of the token.  */
1063
    end = strpbrk (begin, delim);
1064
1065
  if (end)
1066
    {
1067
      /* Terminate the token and set *STRINGP past NUL character.  */
1068
      *end++ = '\0';
1069
      *stringp = end;
1070
    }
1071
  else
1072
    /* No more delimiters; this is the last token.  */
1073
    *stringp = NULL;
1074
1075
  return begin;
1076
}
1077
#endif /*HAVE_STRSEP*/
1078
1079
1080
#ifndef HAVE_STRLWR
1081
char *
1082
strlwr(char *s)
1083
0
{
1084
0
    char *p;
1085
0
    for(p=s; *p; p++ )
1086
0
  *p = tolower(*p);
1087
0
    return s;
1088
0
}
1089
#endif
1090
1091
1092
#ifndef HAVE_STRCASECMP
1093
int
1094
strcasecmp( const char *a, const char *b )
1095
{
1096
    for( ; *a && *b; a++, b++ ) {
1097
  if( *a != *b && toupper(*a) != toupper(*b) )
1098
      break;
1099
    }
1100
    return *(const byte*)a - *(const byte*)b;
1101
}
1102
#endif
1103
1104
1105
/****************
1106
 * mingw32/cpd has a memicmp()
1107
 */
1108
#ifndef HAVE_MEMICMP
1109
int
1110
memicmp( const char *a, const char *b, size_t n )
1111
0
{
1112
0
    for( ; n; n--, a++, b++ )
1113
0
  if( *a != *b  && toupper(*(const byte*)a) != toupper(*(const byte*)b) )
1114
0
      return *(const byte *)a - *(const byte*)b;
1115
0
    return 0;
1116
0
}
1117
#endif
1118
1119
1120
#ifndef HAVE_MEMRCHR
1121
void *
1122
memrchr (const void *buffer, int c, size_t n)
1123
{
1124
  const unsigned char *p = buffer;
1125
1126
  for (p += n; n ; n--)
1127
    if (*--p == c)
1128
      return (void *)p;
1129
  return NULL;
1130
}
1131
#endif /*HAVE_MEMRCHR*/
1132
1133

1134
/* Percent-escape the string STR by replacing colons with '%3a'.  If
1135
   EXTRA is not NULL all characters in EXTRA are also escaped.  */
1136
static char *
1137
do_percent_escape (const char *str, const char *extra, int die)
1138
0
{
1139
0
  int i, j;
1140
0
  char *ptr;
1141
1142
0
  if (!str)
1143
0
    return NULL;
1144
1145
0
  for (i=j=0; str[i]; i++)
1146
0
    if (str[i] == ':' || str[i] == '%' || str[i] == '\n'
1147
0
        || (extra && strchr (extra, str[i])))
1148
0
      j++;
1149
0
  if (die)
1150
0
    ptr = xmalloc (i + 2 * j + 1);
1151
0
  else
1152
0
    {
1153
0
      ptr = xtrymalloc (i + 2 * j + 1);
1154
0
      if (!ptr)
1155
0
        return NULL;
1156
0
    }
1157
0
  i = 0;
1158
0
  while (*str)
1159
0
    {
1160
0
      if (*str == ':')
1161
0
  {
1162
0
    ptr[i++] = '%';
1163
0
    ptr[i++] = '3';
1164
0
    ptr[i++] = 'a';
1165
0
  }
1166
0
      else if (*str == '%')
1167
0
  {
1168
0
    ptr[i++] = '%';
1169
0
    ptr[i++] = '2';
1170
0
    ptr[i++] = '5';
1171
0
  }
1172
0
      else if (*str == '\n')
1173
0
  {
1174
    /* The newline is problematic in a line-based format.  */
1175
0
    ptr[i++] = '%';
1176
0
    ptr[i++] = '0';
1177
0
    ptr[i++] = 'a';
1178
0
  }
1179
0
      else if (extra && strchr (extra, *str))
1180
0
        {
1181
0
    ptr[i++] = '%';
1182
0
          ptr[i++] = tohex_lower ((*str>>4)&15);
1183
0
          ptr[i++] = tohex_lower (*str&15);
1184
0
        }
1185
0
      else
1186
0
  ptr[i++] = *str;
1187
0
      str++;
1188
0
    }
1189
0
  ptr[i] = '\0';
1190
1191
0
  return ptr;
1192
0
}
1193
1194
/* Percent-escape the string STR by replacing colons with '%3a'.  If
1195
   EXTRA is not NULL all characters in EXTRA are also escaped.  This
1196
   function terminates the process on memory shortage.  */
1197
char *
1198
percent_escape (const char *str, const char *extra)
1199
0
{
1200
0
  return do_percent_escape (str, extra, 1);
1201
0
}
1202
1203
/* Same as percent_escape but return NULL instead of exiting on memory
1204
   error. */
1205
char *
1206
try_percent_escape (const char *str, const char *extra)
1207
0
{
1208
0
  return do_percent_escape (str, extra, 0);
1209
0
}
1210
1211
1212
/* Same as strconcat but takes a va_list.  Returns EINVAL if the list
1213
 * is too long, all other errors are due to an ENOMEM condition.  */
1214
char *
1215
vstrconcat (const char *s1, va_list arg_ptr)
1216
1
{
1217
1
  const char *argv[48];
1218
1
  size_t argc;
1219
1
  size_t needed;
1220
1
  char *buffer, *p;
1221
1222
1
  argc = 0;
1223
1
  argv[argc++] = s1;
1224
1
  needed = strlen (s1);
1225
2
  while (((argv[argc] = va_arg (arg_ptr, const char *))))
1226
1
    {
1227
1
      needed += strlen (argv[argc]);
1228
1
      if (argc >= DIM (argv)-1)
1229
0
        {
1230
0
          gpg_err_set_errno (EINVAL);
1231
0
          return NULL;
1232
0
        }
1233
1
      argc++;
1234
1
    }
1235
1
  needed++;
1236
1
  buffer = xtrymalloc (needed);
1237
1
  if (buffer)
1238
1
    {
1239
3
      for (p = buffer, argc=0; argv[argc]; argc++)
1240
2
        p = stpcpy (p, argv[argc]);
1241
1
    }
1242
1
  return buffer;
1243
1
}
1244
1245
1246
/* Concatenate the string S1 with all the following strings up to a
1247
   NULL.  Returns a malloced buffer with the new string or NULL on a
1248
   malloc error or if too many arguments are given.  */
1249
char *
1250
strconcat (const char *s1, ...)
1251
0
{
1252
0
  va_list arg_ptr;
1253
0
  char *result;
1254
1255
0
  if (!s1)
1256
0
    result = xtrystrdup ("");
1257
0
  else
1258
0
    {
1259
0
      va_start (arg_ptr, s1);
1260
0
      result = vstrconcat (s1, arg_ptr);
1261
0
      va_end (arg_ptr);
1262
0
    }
1263
0
  return result;
1264
0
}
1265
1266
/* Same as strconcat but terminate the process with an error message
1267
   if something goes wrong.  */
1268
char *
1269
xstrconcat (const char *s1, ...)
1270
1
{
1271
1
  va_list arg_ptr;
1272
1
  char *result;
1273
1274
1
  if (!s1)
1275
0
    result = xstrdup ("");
1276
1
  else
1277
1
    {
1278
1
      va_start (arg_ptr, s1);
1279
1
      result = vstrconcat (s1, arg_ptr);
1280
1
      va_end (arg_ptr);
1281
1
    }
1282
1
  if (!result)
1283
0
    {
1284
0
      if (errno == EINVAL)
1285
0
        fputs ("\nfatal: too many args for xstrconcat\n", stderr);
1286
0
      else
1287
0
        fputs ("\nfatal: out of memory\n", stderr);
1288
0
      exit (2);
1289
0
    }
1290
1
  return result;
1291
1
}
1292
1293
/* Split a string into fields at DELIM.  REPLACEMENT is the character
1294
   to replace the delimiter with (normally: '\0' so that each field is
1295
   NUL terminated).  The caller is responsible for freeing the result.
1296
   Note: this function modifies STRING!  If you need the original
1297
   value, then you should pass a copy to this function.
1298
1299
   If malloc fails, this function returns NULL.  */
1300
char **
1301
strsplit (char *string, char delim, char replacement, int *count)
1302
0
{
1303
0
  int fields = 1;
1304
0
  char *t;
1305
0
  char **result;
1306
1307
  /* First, count the number of fields.  */
1308
0
  for (t = strchr (string, delim); t; t = strchr (t + 1, delim))
1309
0
    fields ++;
1310
1311
0
  result = xtrycalloc ((fields + 1), sizeof (*result));
1312
0
  if (! result)
1313
0
    return NULL;
1314
1315
0
  result[0] = string;
1316
0
  fields = 1;
1317
0
  for (t = strchr (string, delim); t; t = strchr (t + 1, delim))
1318
0
    {
1319
0
      result[fields ++] = t + 1;
1320
0
      *t = replacement;
1321
0
    }
1322
1323
0
  if (count)
1324
0
    *count = fields;
1325
1326
0
  return result;
1327
0
}
1328
1329
1330
/* Tokenize STRING using the set of delimiters in DELIM.  Leading
1331
 * spaces and tabs are removed from all tokens.  The caller must xfree
1332
 * the result.
1333
 *
1334
 * Returns: A malloced and NULL delimited array with the tokens.  On
1335
 *          memory error NULL is returned and ERRNO is set.
1336
 */
1337
static char **
1338
do_strtokenize (const char *string, const char *delim, int trim)
1339
0
{
1340
0
  const char *s;
1341
0
  size_t fields;
1342
0
  size_t bytes, n;
1343
0
  char *buffer;
1344
0
  char *p, *px, *pend;
1345
0
  char **result;
1346
1347
  /* Count the number of fields.  */
1348
0
  for (fields = 1, s = strpbrk (string, delim); s; s = strpbrk (s + 1, delim))
1349
0
    fields++;
1350
0
  fields++; /* Add one for the terminating NULL.  */
1351
1352
  /* Allocate an array for all fields, a terminating NULL, and space
1353
     for a copy of the string.  */
1354
0
  bytes = fields * sizeof *result;
1355
0
  if (bytes / sizeof *result != fields)
1356
0
    {
1357
0
      gpg_err_set_errno (ENOMEM);
1358
0
      return NULL;
1359
0
    }
1360
0
  n = strlen (string) + 1;
1361
0
  bytes += n;
1362
0
  if (bytes < n)
1363
0
    {
1364
0
      gpg_err_set_errno (ENOMEM);
1365
0
      return NULL;
1366
0
    }
1367
0
  result = xtrymalloc (bytes);
1368
0
  if (!result)
1369
0
    return NULL;
1370
0
  buffer = (char*)(result + fields);
1371
1372
  /* Copy and parse the string.  */
1373
0
  strcpy (buffer, string);
1374
0
  for (n = 0, p = buffer; (pend = strpbrk (p, delim)); p = pend + 1)
1375
0
    {
1376
0
      *pend = 0;
1377
0
      if (trim)
1378
0
        {
1379
0
          while (spacep (p))
1380
0
            p++;
1381
0
          for (px = pend - 1; px >= p && spacep (px); px--)
1382
0
            *px = 0;
1383
0
        }
1384
0
      result[n++] = p;
1385
0
    }
1386
0
  if (trim)
1387
0
    {
1388
0
      while (spacep (p))
1389
0
        p++;
1390
0
      for (px = p + strlen (p) - 1; px >= p && spacep (px); px--)
1391
0
        *px = 0;
1392
0
    }
1393
0
  result[n++] = p;
1394
0
  result[n] = NULL;
1395
1396
0
  log_assert ((char*)(result + n + 1) == buffer);
1397
1398
0
  return result;
1399
0
}
1400
1401
/* Tokenize STRING using the set of delimiters in DELIM.  Leading
1402
 * spaces and tabs are removed from all tokens.  The caller must xfree
1403
 * the result.
1404
 *
1405
 * Returns: A malloced and NULL delimited array with the tokens.  On
1406
 *          memory error NULL is returned and ERRNO is set.
1407
 */
1408
char **
1409
strtokenize (const char *string, const char *delim)
1410
0
{
1411
0
  return do_strtokenize (string, delim, 1);
1412
0
}
1413
1414
/* Same as strtokenize but does not trim leading and trailing spaces
1415
 * from the fields.  */
1416
char **
1417
strtokenize_nt (const char *string, const char *delim)
1418
0
{
1419
0
  return do_strtokenize (string, delim, 0);
1420
0
}
1421
1422
1423
/* Split a string into space delimited fields and remove leading and
1424
 * trailing spaces from each field.  A pointer to each field is stored
1425
 * in ARRAY.  Stop splitting at ARRAYSIZE fields.  The function
1426
 * modifies STRING.  The number of parsed fields is returned.
1427
 * Example:
1428
 *
1429
 *   char *fields[2];
1430
 *   if (split_fields (string, fields, DIM (fields)) < 2)
1431
 *     return  // Not enough args.
1432
 *   foo (fields[0]);
1433
 *   foo (fields[1]);
1434
 */
1435
int
1436
split_fields (char *string, const char **array, int arraysize)
1437
0
{
1438
0
  int n = 0;
1439
0
  const char *p;
1440
0
  char *pend;
1441
1442
0
  for (p = string; *p == ' '; p++)
1443
0
    ;
1444
0
  do
1445
0
    {
1446
0
      if (n == arraysize)
1447
0
        break;
1448
0
      array[n++] = p;
1449
0
      pend = strchr (p, ' ');
1450
0
      if (!pend)
1451
0
        break;
1452
0
      *pend++ = 0;
1453
0
      for (p = pend; *p == ' '; p++)
1454
0
        ;
1455
0
    }
1456
0
  while (*p);
1457
1458
0
  return n;
1459
0
}
1460
1461
1462
/* Split a string into colon delimited fields A pointer to each field
1463
 * is stored in ARRAY.  Stop splitting at ARRAYSIZE fields.  The
1464
 * function modifies STRING.  The number of parsed fields is returned.
1465
 * Note that leading and trailing spaces are not removed from the fields.
1466
 * Example:
1467
 *
1468
 *   char *fields[2];
1469
 *   if (split_fields (string, fields, DIM (fields)) < 2)
1470
 *     return  // Not enough args.
1471
 *   foo (fields[0]);
1472
 *   foo (fields[1]);
1473
 */
1474
int
1475
split_fields_colon (char *string, const char **array, int arraysize)
1476
0
{
1477
0
  int n = 0;
1478
0
  const char *p;
1479
0
  char *pend;
1480
1481
0
  p = string;
1482
0
  do
1483
0
    {
1484
0
      if (n == arraysize)
1485
0
        break;
1486
0
      array[n++] = p;
1487
0
      pend = strchr (p, ':');
1488
0
      if (!pend)
1489
0
        break;
1490
0
      *pend++ = 0;
1491
0
      p = pend;
1492
0
    }
1493
0
  while (*p);
1494
1495
0
  return n;
1496
0
}
1497
1498
1499

1500
/* Version number parsing.  */
1501
1502
/* This function parses the first portion of the version number S and
1503
   stores it in *NUMBER.  On success, this function returns a pointer
1504
   into S starting with the first character, which is not part of the
1505
   initial number portion; on failure, NULL is returned.  */
1506
static const char*
1507
parse_version_number (const char *s, int *number)
1508
0
{
1509
0
  int val = 0;
1510
1511
0
  if (*s == '0' && digitp (s+1))
1512
0
    return NULL;  /* Leading zeros are not allowed.  */
1513
0
  for (; digitp (s); s++)
1514
0
    {
1515
0
      val *= 10;
1516
0
      val += *s - '0';
1517
0
    }
1518
0
  *number = val;
1519
0
  return val < 0 ? NULL : s;
1520
0
}
1521
1522
1523
/* This function breaks up the complete string-representation of the
1524
   version number S, which is of the following structure: <major
1525
   number>.<minor number>[.<micro number>]<patch level>.  The major,
1526
   minor, and micro number components will be stored in *MAJOR, *MINOR
1527
   and *MICRO.  If MICRO is not given 0 is used instead.
1528
1529
   On success, the last component, the patch level, will be returned;
1530
   in failure, NULL will be returned.  */
1531
static const char *
1532
parse_version_string (const char *s, int *major, int *minor, int *micro)
1533
0
{
1534
0
  s = parse_version_number (s, major);
1535
0
  if (!s || *s != '.')
1536
0
    return NULL;
1537
0
  s++;
1538
0
  s = parse_version_number (s, minor);
1539
0
  if (!s)
1540
0
    return NULL;
1541
0
  if (*s == '.')
1542
0
    {
1543
0
      s++;
1544
0
      s = parse_version_number (s, micro);
1545
0
      if (!s)
1546
0
        return NULL;
1547
0
    }
1548
0
  else
1549
0
    *micro = 0;
1550
0
  return s;  /* Patchlevel.  */
1551
0
}
1552
1553
1554
/* Compare the version string MY_VERSION to the version string
1555
 * REQ_VERSION.  Returns -1, 0, or 1 if MY_VERSION is found,
1556
 * respectively, to be less than, to match, or be greater than
1557
 * REQ_VERSION.  This function works for three and two part version
1558
 * strings; for a two part version string the micro part is assumed to
1559
 * be 0.  Patch levels are compared as strings.  If a version number
1560
 * is invalid INT_MIN is returned.  If REQ_VERSION is given as NULL
1561
 * the function returns 0 if MY_VERSION is parsable version string. */
1562
int
1563
compare_version_strings (const char *my_version, const char *req_version)
1564
0
{
1565
0
  int my_major, my_minor, my_micro;
1566
0
  int rq_major, rq_minor, rq_micro;
1567
0
  const char *my_patch, *rq_patch;
1568
0
  int result;
1569
1570
0
  if (!my_version)
1571
0
    return INT_MIN;
1572
1573
0
  my_patch = parse_version_string (my_version, &my_major, &my_minor, &my_micro);
1574
0
  if (!my_patch)
1575
0
    return INT_MIN;
1576
0
  if (!req_version)
1577
0
    return 0; /* MY_VERSION can be parsed.  */
1578
0
  rq_patch = parse_version_string (req_version, &rq_major, &rq_minor,&rq_micro);
1579
0
  if (!rq_patch)
1580
0
    return INT_MIN;
1581
1582
0
  if (my_major == rq_major)
1583
0
    {
1584
0
      if (my_minor == rq_minor)
1585
0
        {
1586
0
          if (my_micro == rq_micro)
1587
0
            result = strcmp (my_patch, rq_patch);
1588
0
          else
1589
0
            result = my_micro - rq_micro;
1590
0
        }
1591
0
      else
1592
0
        result = my_minor - rq_minor;
1593
0
    }
1594
0
  else
1595
0
    result = my_major - rq_major;
1596
1597
0
  return !result? 0 : result < 0 ? -1 : 1;
1598
0
}
1599
1600
1601

1602
/* Format a string so that it fits within about TARGET_COLS columns.
1603
 * TEXT_IN is copied to a new buffer, which is returned.  Normally,
1604
 * target_cols will be 72 and max_cols is 80.  On error NULL is
1605
 * returned and ERRNO is set. */
1606
char *
1607
format_text (const char *text_in, int target_cols, int max_cols)
1608
0
{
1609
  /* const int do_debug = 0; */
1610
1611
  /* The character under consideration.  */
1612
0
  char *p;
1613
  /* The start of the current line.  */
1614
0
  char *line;
1615
  /* The last space that we saw.  */
1616
0
  char *last_space = NULL;
1617
0
  int last_space_cols = 0;
1618
0
  int copied_last_space = 0;
1619
0
  char *text;
1620
1621
0
  text = xtrystrdup (text_in);
1622
0
  if (!text)
1623
0
    return NULL;
1624
1625
0
  p = line = text;
1626
0
  while (1)
1627
0
    {
1628
      /* The number of columns including any trailing space.  */
1629
0
      int cols;
1630
1631
0
      p = p + strcspn (p, "\n ");
1632
0
      if (! p)
1633
        /* P now points to the NUL character.  */
1634
0
        p = &text[strlen (text)];
1635
1636
0
      if (*p == '\n')
1637
        /* Pass through any newlines.  */
1638
0
        {
1639
0
          p ++;
1640
0
          line = p;
1641
0
          last_space = NULL;
1642
0
          last_space_cols = 0;
1643
0
          copied_last_space = 1;
1644
0
          continue;
1645
0
        }
1646
1647
      /* Have a space or a NUL.  Note: we don't count the trailing
1648
         space.  */
1649
0
      cols = utf8_charcount (line, (uintptr_t) p - (uintptr_t) line);
1650
0
      if (cols < target_cols)
1651
0
        {
1652
0
          if (! *p)
1653
            /* Nothing left to break.  */
1654
0
            break;
1655
1656
0
          last_space = p;
1657
0
          last_space_cols = cols;
1658
0
          p ++;
1659
          /* Skip any immediately following spaces.  If we break:
1660
             "... foo bar ..." between "foo" and "bar" then we want:
1661
             "... foo\nbar ...", which means that the left space has
1662
             to be the first space after foo, not the last space
1663
             before bar.  */
1664
0
          while (*p == ' ')
1665
0
            p ++;
1666
0
        }
1667
0
      else
1668
0
        {
1669
0
          int cols_with_left_space;
1670
0
          int cols_with_right_space;
1671
0
          int left_penalty;
1672
0
          int right_penalty;
1673
1674
0
          cols_with_left_space = last_space_cols;
1675
0
          cols_with_right_space = cols;
1676
1677
          /* if (do_debug) */
1678
          /*   log_debug ("Breaking: '%.*s'\n", */
1679
          /*              (int) ((uintptr_t) p - (uintptr_t) line), line); */
1680
1681
          /* The number of columns away from TARGET_COLS.  We prefer
1682
             to underflow than to overflow.  */
1683
0
          left_penalty = target_cols - cols_with_left_space;
1684
0
          right_penalty = 2 * (cols_with_right_space - target_cols);
1685
1686
0
          if (cols_with_right_space > max_cols)
1687
            /* Add a large penalty for each column that exceeds
1688
               max_cols.  */
1689
0
            right_penalty += 4 * (cols_with_right_space - max_cols);
1690
1691
          /* if (do_debug) */
1692
          /*   log_debug ("Left space => %d cols (penalty: %d); " */
1693
          /*              "right space => %d cols (penalty: %d)\n", */
1694
          /*              cols_with_left_space, left_penalty, */
1695
          /*              cols_with_right_space, right_penalty); */
1696
0
          if (last_space_cols && left_penalty <= right_penalty)
1697
0
            {
1698
              /* Prefer the left space.  */
1699
              /* if (do_debug) */
1700
              /*   log_debug ("Breaking at left space.\n"); */
1701
0
              p = last_space;
1702
0
            }
1703
0
          else
1704
0
            {
1705
              /* if (do_debug) */
1706
              /*   log_debug ("Breaking at right space.\n"); */
1707
0
            }
1708
1709
0
          if (! *p)
1710
0
            break;
1711
1712
0
          *p = '\n';
1713
0
          p ++;
1714
0
          if (*p == ' ')
1715
0
            {
1716
0
              int spaces;
1717
0
              for (spaces = 1; p[spaces] == ' '; spaces ++)
1718
0
                ;
1719
0
              memmove (p, &p[spaces], strlen (&p[spaces]) + 1);
1720
0
            }
1721
0
          line = p;
1722
0
          last_space = NULL;
1723
0
          last_space_cols = 0;
1724
0
          copied_last_space = 0;
1725
0
        }
1726
0
    }
1727
1728
  /* Chop off any trailing space.  */
1729
0
  trim_trailing_chars (text, strlen (text), " ");
1730
  /* If we inserted the trailing newline, then remove it.  */
1731
0
  if (! copied_last_space && *text && text[strlen (text) - 1] == '\n')
1732
0
    text[strlen (text) - 1] = '\0';
1733
1734
0
  return text;
1735
0
}
1736
1737
1738
/* In STRING replace the first occurance of SUBSTR by the string
1739
 * REPLACE.  Return a new malloced string or set ERRNO and set NULL on
1740
 * error.  If SUBSTR is not found a verbatim copy of STRING is
1741
 * returned.  */
1742
char *
1743
replace_substr (const char *string, const char *substr, const char *replace)
1744
0
{
1745
0
  size_t stringlen, substrlen, replacelen, n;
1746
0
  const char *s;
1747
0
  char *buffer;
1748
1749
0
  stringlen = strlen (string);
1750
0
  substrlen = strlen (substr);
1751
0
  replacelen = strlen (replace);
1752
1753
0
  if (stringlen < substrlen || !(s = strstr (string, substr)))
1754
0
    return xtrystrdup (string);
1755
1756
0
  stringlen -= substrlen;  /* Found thus sryinglen >= substrlen */
1757
0
  buffer = xtrymalloc (stringlen + replacelen +1);
1758
0
  if (!buffer)
1759
0
    return NULL;
1760
0
  memcpy (buffer, string, n=(s-string));
1761
0
  memcpy (buffer+n, replace, replacelen);
1762
0
  strcpy (buffer+n+replacelen, s+substrlen);
1763
1764
1765
0
  return buffer;
1766
0
}
1767
1768
1769
/* Substitute variables in STRING and return a new string.  GETVAL is
1770
 * a function which maps NAME to its value; that value is a string
1771
 * which may not change during the execution time of this function.
1772
 * If GETVAL returns NULL substitute_vars returns NULL and the caller
1773
 * may inspect ERRNO for the reason.  In all other error cases this
1774
 * function also returns NULL.  Caller must free the returned string.  */
1775
char *
1776
substitute_vars (const char *string,
1777
                 const char *(*getval)(void *cookie, const char *name),
1778
                 void *cookie)
1779
0
{
1780
0
  char *line, *p, *pend;
1781
0
  const char *value;
1782
0
  size_t valuelen, n;
1783
0
  char *result = NULL;
1784
1785
0
  result = line = xtrystrdup (string);
1786
0
  if (!result)
1787
0
    return NULL; /* Ooops */
1788
1789
0
  while (*line)
1790
0
    {
1791
0
      p = strchr (line, '$');
1792
0
      if (!p)
1793
0
        goto leave; /* No or no more variables.  */
1794
1795
0
      if (p[1] == '$') /* Escaped dollar sign. */
1796
0
        {
1797
0
          memmove (p, p+1, strlen (p+1)+1);
1798
0
          line = p + 1;
1799
0
          continue;
1800
0
        }
1801
1802
0
      if (p[1] == '{')
1803
0
        {
1804
0
          int count = 0;
1805
1806
0
          for (pend=p+2; *pend; pend++)
1807
0
            {
1808
0
              if (*pend == '{')
1809
0
                count++;
1810
0
              else if (*pend == '}')
1811
0
                {
1812
0
                  if (--count < 0)
1813
0
                    break;
1814
0
                }
1815
0
            }
1816
0
          if (!*pend)
1817
0
            goto leave; /* Unclosed - don't substitute.  */
1818
0
        }
1819
0
      else
1820
0
        {
1821
0
          for (pend = p+1; *pend && (alnump (pend) || *pend == '_'); pend++)
1822
0
            ;
1823
0
        }
1824
1825
0
      if (p[1] == '{' && *pend == '}')
1826
0
        {
1827
0
          int save = *pend;
1828
0
          *pend = 0;
1829
0
          value = getval (cookie, p+2);
1830
0
          *pend++ = save;
1831
0
        }
1832
0
      else
1833
0
        {
1834
0
          int save = *pend;
1835
0
          *pend = 0;
1836
0
          value = getval (cookie, p+1);
1837
0
          *pend = save;
1838
0
        }
1839
1840
0
      if (!value)
1841
0
        {
1842
0
          xfree (result);
1843
0
          return NULL;
1844
0
        }
1845
0
      valuelen = strlen (value);
1846
0
      if (valuelen <= pend - p)
1847
0
        {
1848
0
          memcpy (p, value, valuelen);
1849
0
          p += valuelen;
1850
0
          n = pend - p;
1851
0
          if (n)
1852
0
            memmove (p, p+n, strlen (p+n)+1);
1853
0
          line = p;
1854
0
        }
1855
0
      else
1856
0
        {
1857
0
          char *src = result;
1858
0
          char *dst;
1859
1860
0
          dst = xtrymalloc (strlen (src) + valuelen + 1);
1861
0
          if (!dst)
1862
0
            {
1863
0
              xfree (result);
1864
0
              return NULL;
1865
0
            }
1866
0
          n = p - src;
1867
0
          memcpy (dst, src, n);
1868
0
          memcpy (dst + n, value, valuelen);
1869
0
          n += valuelen;
1870
0
          strcpy (dst + n, pend);
1871
0
          line = dst + n;
1872
0
          xfree (result);
1873
0
          result = dst;
1874
0
        }
1875
0
    }
1876
1877
0
 leave:
1878
0
  return result;
1879
0
}
1880
1881
1882
/* Helper for substitute_envvars.  */
1883
static const char *
1884
subst_getenv (void *cookie, const char *name)
1885
0
{
1886
0
  const char *s;
1887
1888
0
  (void)cookie;
1889
1890
0
  s = getenv (name);
1891
0
  return s? s : "";
1892
0
}
1893
1894
1895
/* Substitute environment variables in STRING and return a new string.
1896
 * On error the function returns NULL.  */
1897
char *
1898
substitute_envvars (const char *string)
1899
0
{
1900
0
  return substitute_vars (string, subst_getenv, NULL);
1901
1902
0
}