Coverage Report

Created: 2026-01-17 06:46

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
5
{
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
5
  return name;
85
5
}
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
1.02k
{
174
1.02k
  const unsigned char *buf = buffer;
175
1.02k
  const unsigned char *t = (const unsigned char *)buf;
176
1.02k
  const unsigned char *s = (const unsigned char *)sub;
177
1.02k
  size_t n = buflen;
178
179
3.61k
  for ( ; n ; t++, n-- )
180
3.33k
    {
181
3.33k
      if (*t == *s)
182
1.30k
        {
183
2.05k
          for (buf = t++, buflen = n--, s++; n && *t ==*s; t++, s++, n--)
184
750
            ;
185
1.30k
          if (!*s)
186
750
            return (const char*)buf;
187
552
          t = (const unsigned char *)buf;
188
552
          s = (const unsigned char *)sub ;
189
552
          n = buflen;
190
552
  }
191
3.33k
    }
192
278
  return NULL;
193
1.02k
}
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
74.7k
{
206
74.7k
  char *d;
207
74.7k
  const char *s;
208
209
74.7k
  if (n)
210
74.7k
    {
211
74.7k
      if (!dest)
212
0
        dest = xmalloc (n);
213
74.7k
      d = dest;
214
74.7k
      s = src ;
215
1.56M
      for (n--; n && *s; n--)
216
1.49M
        *d++ = *s++;
217
74.7k
      *d = '\0' ;
218
74.7k
    }
219
220
74.7k
  return dest;
221
74.7k
}
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
896k
{
306
896k
    byte *p, *mark;
307
896k
    unsigned n;
308
309
5.52M
    for(mark=NULL, p=line, n=0; n < len; n++, p++ ) {
310
4.63M
  if( strchr(trimchars, *p ) ) {
311
2.47M
      if( !mark )
312
1.64M
    mark = p;
313
2.47M
  }
314
2.16M
  else
315
2.16M
      mark = NULL;
316
4.63M
    }
317
318
896k
    if( mark ) {
319
896k
  *mark = 0;
320
896k
  return mark - line;
321
896k
    }
322
439
    return len;
323
896k
}
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
58.8k
{
338
58.8k
  const unsigned char *p, *mark;
339
58.8k
  size_t n;
340
341
623k
  for( mark=NULL, p=line, n=0; n < len; n++, p++ )
342
564k
    {
343
564k
      if (strchr (trimchars, *p ))
344
159k
        {
345
159k
          if( !mark )
346
92.2k
            mark = p;
347
159k
        }
348
405k
      else
349
405k
        mark = NULL;
350
564k
    }
351
352
58.8k
  if (mark)
353
57.9k
    return mark - line;
354
870
  return len;
355
58.8k
}
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
58.8k
{
363
58.8k
  return length_sans_trailing_chars (line, len, " \t\r\n");
364
58.8k
}
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
5
{
477
5
  const char *argv[32];
478
5
  int argc;
479
5
  size_t n;
480
5
  int skip = 1;
481
5
  char *home_buffer = NULL;
482
5
  char *name, *home, *p;
483
5
  int want_abs;
484
485
5
  want_abs = !!(xmode & 2);
486
5
  xmode &= 1;
487
488
5
  n = strlen (first_part) + 1;
489
5
  argc = 0;
490
7
  while ( (argv[argc] = va_arg (arg_ptr, const char *)) )
491
2
    {
492
2
      n += strlen (argv[argc]) + 1;
493
2
      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
      argc++;
501
2
    }
502
5
  n++;
503
504
5
  home = NULL;
505
5
  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
5
  if (xmode)
544
5
    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
5
  if (home)
556
1
    p = stpcpy (stpcpy (name, home), first_part + skip);
557
4
  else
558
4
    p = stpcpy (name, first_part);
559
560
5
  xfree (home_buffer);
561
7
  for (argc=0; argv[argc]; argc++)
562
2
    {
563
      /* Avoid a leading double slash if the first part was "/".  */
564
2
      if (!argc && name[0] == '/' && !name[1])
565
0
        p = stpcpy (p, argv[argc]);
566
2
      else
567
2
        p = stpcpy (stpcpy (p, "/"), argv[argc]);
568
2
    }
569
570
5
  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
5
  return change_slashes (name);
637
5
}
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
{
645
2
  va_list arg_ptr;
646
2
  char *result;
647
648
2
  va_start (arg_ptr, first_part);
649
2
  result = do_make_filename (1, first_part, arg_ptr);
650
2
  va_end (arg_ptr);
651
2
  return result;
652
2
}
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
/* Convert a base-10 number in STRING into a 64 bit unsigned int
730
 * value.  Leading white spaces are skipped but no error checking is
731
 * done.  Thus it is similar to atoi().  See also scan_secondsstr.  */
732
uint64_t
733
string_to_u64 (const char *string)
734
0
{
735
0
  uint64_t val = 0;
736
737
0
  while (spacep (string))
738
0
    string++;
739
0
  for (; digitp (string); string++)
740
0
    {
741
0
      val *= 10;
742
0
      val += *string - '0';
743
0
    }
744
0
  return val;
745
0
}
746
747
748
/* Convert 2 hex characters at S to a byte value.  Return this value
749
   or -1 if there is an error. */
750
int
751
hextobyte (const char *s)
752
0
{
753
0
  int c;
754
755
0
  if ( *s >= '0' && *s <= '9' )
756
0
    c = 16 * (*s - '0');
757
0
  else if ( *s >= 'A' && *s <= 'F' )
758
0
    c = 16 * (10 + *s - 'A');
759
0
  else if ( *s >= 'a' && *s <= 'f' )
760
0
    c = 16 * (10 + *s - 'a');
761
0
  else
762
0
    return -1;
763
0
  s++;
764
0
  if ( *s >= '0' && *s <= '9' )
765
0
    c += *s - '0';
766
0
  else if ( *s >= 'A' && *s <= 'F' )
767
0
    c += 10 + *s - 'A';
768
0
  else if ( *s >= 'a' && *s <= 'f' )
769
0
    c += 10 + *s - 'a';
770
0
  else
771
0
    return -1;
772
0
  return c;
773
0
}
774
775
/* Given a string containing an UTF-8 encoded text, return the number
776
   of characters in this string.  It differs from strlen in that it
777
   only counts complete UTF-8 characters.  SIZE is the maximum length
778
   of the string in bytes.  If SIZE is -1, then a NUL character is
779
   taken to be the end of the string.  Note, that this function does
780
   not take combined characters into account.  */
781
size_t
782
utf8_charcount (const char *s, int len)
783
0
{
784
0
  size_t n;
785
786
0
  if (len == 0)
787
0
    return 0;
788
789
0
  for (n=0; *s; s++)
790
0
    {
791
0
      if ( (*s&0xc0) != 0x80 ) /* Exclude continuation bytes: 10xxxxxx */
792
0
        n++;
793
794
0
      if (len != -1)
795
0
        {
796
0
          len --;
797
0
          if (len == 0)
798
0
            break;
799
0
        }
800
0
    }
801
802
0
  return n;
803
0
}
804
805
806
/****************************************************
807
 **********  W32 specific functions  ****************
808
 ****************************************************/
809
810
#ifdef HAVE_W32_SYSTEM
811
const char *
812
w32_strerror (int ec)
813
{
814
  static char strerr[256];
815
816
  if (ec == -1)
817
    ec = (int)GetLastError ();
818
  FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec,
819
                 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
820
                 strerr, DIM (strerr)-1, NULL);
821
  {
822
    /* Strip the CR,LF - we want just the string.  */
823
    size_t n = strlen (strerr);
824
    if (n > 2 && strerr[n-2] == '\r' && strerr[n-1] == '\n' )
825
      strerr[n-2] = 0;
826
  }
827
  return strerr;
828
}
829
#endif /*HAVE_W32_SYSTEM*/
830
831
832
/****************************************************
833
 ******** Locale insensitive ctype functions ********
834
 ****************************************************/
835
/* FIXME: replace them by a table lookup and macros */
836
int
837
ascii_isupper (int c)
838
0
{
839
0
    return c >= 'A' && c <= 'Z';
840
0
}
841
842
int
843
ascii_islower (int c)
844
0
{
845
0
    return c >= 'a' && c <= 'z';
846
0
}
847
848
int
849
ascii_toupper (int c)
850
615
{
851
615
    if (c >= 'a' && c <= 'z')
852
258
        c &= ~0x20;
853
615
    return c;
854
615
}
855
856
int
857
ascii_tolower (int c)
858
0
{
859
0
    if (c >= 'A' && c <= 'Z')
860
0
        c |= 0x20;
861
0
    return c;
862
0
}
863
864
/* Lowercase all ASCII characters in S.  */
865
char *
866
ascii_strlwr (char *s)
867
931
{
868
931
  char *p = s;
869
870
6.95k
  for (p=s; *p; p++ )
871
6.02k
    if (isascii (*p) && *p >= 'A' && *p <= 'Z')
872
294
      *p |= 0x20;
873
874
931
  return s;
875
931
}
876
877
/* Upcase all ASCII characters in S.  */
878
char *
879
ascii_strupr (char *s)
880
0
{
881
0
  char *p = s;
882
883
0
  for (p=s; *p; p++ )
884
0
    if (isascii (*p) && *p >= 'a' && *p <= 'z')
885
0
      *p &= ~0x20;
886
887
0
  return s;
888
0
}
889
890
int
891
ascii_strcasecmp( const char *a, const char *b )
892
0
{
893
0
    if (a == b)
894
0
        return 0;
895
896
0
    for (; *a && *b; a++, b++) {
897
0
  if (*a != *b && ascii_toupper(*a) != ascii_toupper(*b))
898
0
      break;
899
0
    }
900
0
    return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
901
0
}
902
903
int
904
ascii_strncasecmp (const char *a, const char *b, size_t n)
905
0
{
906
0
  const unsigned char *p1 = (const unsigned char *)a;
907
0
  const unsigned char *p2 = (const unsigned char *)b;
908
0
  unsigned char c1, c2;
909
910
0
  if (p1 == p2 || !n )
911
0
    return 0;
912
913
0
  do
914
0
    {
915
0
      c1 = ascii_tolower (*p1);
916
0
      c2 = ascii_tolower (*p2);
917
918
0
      if ( !--n || c1 == '\0')
919
0
  break;
920
921
0
      ++p1;
922
0
      ++p2;
923
0
    }
924
0
  while (c1 == c2);
925
926
0
  return c1 - c2;
927
0
}
928
929
930
int
931
ascii_memcasecmp (const void *a_arg, const void *b_arg, size_t n )
932
0
{
933
0
  const char *a = a_arg;
934
0
  const char *b = b_arg;
935
936
0
  if (a == b)
937
0
    return 0;
938
0
  for ( ; n; n--, a++, b++ )
939
0
    {
940
0
      if( *a != *b  && ascii_toupper (*a) != ascii_toupper (*b) )
941
0
        return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
942
0
    }
943
0
  return 0;
944
0
}
945
946
int
947
ascii_strcmp( const char *a, const char *b )
948
0
{
949
0
    if (a == b)
950
0
        return 0;
951
952
0
    for (; *a && *b; a++, b++) {
953
0
  if (*a != *b )
954
0
      break;
955
0
    }
956
0
    return *a == *b? 0 : (*(signed char *)a - *(signed char *)b);
957
0
}
958
959
960
void *
961
ascii_memcasemem (const void *haystack, size_t nhaystack,
962
                  const void *needle, size_t nneedle)
963
0
{
964
965
0
  if (!nneedle)
966
0
    return (void*)haystack; /* finding an empty needle is really easy */
967
0
  if (nneedle <= nhaystack)
968
0
    {
969
0
      const char *a = haystack;
970
0
      const char *b = a + nhaystack - nneedle;
971
972
0
      for (; a <= b; a++)
973
0
        {
974
0
          if ( !ascii_memcasecmp (a, needle, nneedle) )
975
0
            return (void *)a;
976
0
        }
977
0
    }
978
0
  return NULL;
979
0
}
980
981
/*********************************************
982
 ********** missing string functions *********
983
 *********************************************/
984
985
#ifndef HAVE_STPCPY
986
char *
987
stpcpy(char *a,const char *b)
988
{
989
    while( *b )
990
  *a++ = *b++;
991
    *a = 0;
992
993
    return (char*)a;
994
}
995
#endif
996
997
#ifndef HAVE_STRPBRK
998
/* Find the first occurrence in S of any character in ACCEPT.
999
   Code taken from glibc-2.6/string/strpbrk.c (LGPLv2.1+) and modified. */
1000
char *
1001
strpbrk (const char *s, const char *accept)
1002
{
1003
  while (*s != '\0')
1004
    {
1005
      const char *a = accept;
1006
      while (*a != '\0')
1007
  if (*a++ == *s)
1008
    return (char *) s;
1009
      ++s;
1010
    }
1011
1012
  return NULL;
1013
}
1014
#endif /*!HAVE_STRPBRK*/
1015
1016
1017
#ifndef HAVE_STRSEP
1018
/* Code taken from glibc-2.2.1/sysdeps/generic/strsep.c. */
1019
char *
1020
strsep (char **stringp, const char *delim)
1021
{
1022
  char *begin, *end;
1023
1024
  begin = *stringp;
1025
  if (begin == NULL)
1026
    return NULL;
1027
1028
  /* A frequent case is when the delimiter string contains only one
1029
     character.  Here we don't need to call the expensive 'strpbrk'
1030
     function and instead work using 'strchr'.  */
1031
  if (delim[0] == '\0' || delim[1] == '\0')
1032
    {
1033
      char ch = delim[0];
1034
1035
      if (ch == '\0')
1036
        end = NULL;
1037
      else
1038
        {
1039
          if (*begin == ch)
1040
            end = begin;
1041
          else if (*begin == '\0')
1042
            end = NULL;
1043
          else
1044
            end = strchr (begin + 1, ch);
1045
        }
1046
    }
1047
  else
1048
    /* Find the end of the token.  */
1049
    end = strpbrk (begin, delim);
1050
1051
  if (end)
1052
    {
1053
      /* Terminate the token and set *STRINGP past NUL character.  */
1054
      *end++ = '\0';
1055
      *stringp = end;
1056
    }
1057
  else
1058
    /* No more delimiters; this is the last token.  */
1059
    *stringp = NULL;
1060
1061
  return begin;
1062
}
1063
#endif /*HAVE_STRSEP*/
1064
1065
1066
#ifndef HAVE_STRLWR
1067
char *
1068
strlwr(char *s)
1069
0
{
1070
0
    char *p;
1071
0
    for(p=s; *p; p++ )
1072
0
  *p = tolower(*p);
1073
0
    return s;
1074
0
}
1075
#endif
1076
1077
1078
#ifndef HAVE_STRCASECMP
1079
int
1080
strcasecmp( const char *a, const char *b )
1081
{
1082
    for( ; *a && *b; a++, b++ ) {
1083
  if( *a != *b && toupper(*a) != toupper(*b) )
1084
      break;
1085
    }
1086
    return *(const byte*)a - *(const byte*)b;
1087
}
1088
#endif
1089
1090
1091
/****************
1092
 * mingw32/cpd has a memicmp()
1093
 */
1094
#ifndef HAVE_MEMICMP
1095
int
1096
memicmp( const char *a, const char *b, size_t n )
1097
0
{
1098
0
    for( ; n; n--, a++, b++ )
1099
0
  if( *a != *b  && toupper(*(const byte*)a) != toupper(*(const byte*)b) )
1100
0
      return *(const byte *)a - *(const byte*)b;
1101
0
    return 0;
1102
0
}
1103
#endif
1104
1105
1106
#ifndef HAVE_MEMRCHR
1107
void *
1108
memrchr (const void *buffer, int c, size_t n)
1109
{
1110
  const unsigned char *p = buffer;
1111
1112
  for (p += n; n ; n--)
1113
    if (*--p == c)
1114
      return (void *)p;
1115
  return NULL;
1116
}
1117
#endif /*HAVE_MEMRCHR*/
1118
1119

1120
/* Percent-escape the string STR by replacing colons with '%3a'.  If
1121
   EXTRA is not NULL all characters in EXTRA are also escaped.  */
1122
static char *
1123
do_percent_escape (const char *str, const char *extra, int die)
1124
0
{
1125
0
  int i, j;
1126
0
  char *ptr;
1127
1128
0
  if (!str)
1129
0
    return NULL;
1130
1131
0
  for (i=j=0; str[i]; i++)
1132
0
    if (str[i] == ':' || str[i] == '%' || str[i] == '\n'
1133
0
        || (extra && strchr (extra, str[i])))
1134
0
      j++;
1135
0
  if (die)
1136
0
    ptr = xmalloc (i + 2 * j + 1);
1137
0
  else
1138
0
    {
1139
0
      ptr = xtrymalloc (i + 2 * j + 1);
1140
0
      if (!ptr)
1141
0
        return NULL;
1142
0
    }
1143
0
  i = 0;
1144
0
  while (*str)
1145
0
    {
1146
0
      if (*str == ':')
1147
0
  {
1148
0
    ptr[i++] = '%';
1149
0
    ptr[i++] = '3';
1150
0
    ptr[i++] = 'a';
1151
0
  }
1152
0
      else if (*str == '%')
1153
0
  {
1154
0
    ptr[i++] = '%';
1155
0
    ptr[i++] = '2';
1156
0
    ptr[i++] = '5';
1157
0
  }
1158
0
      else if (*str == '\n')
1159
0
  {
1160
    /* The newline is problematic in a line-based format.  */
1161
0
    ptr[i++] = '%';
1162
0
    ptr[i++] = '0';
1163
0
    ptr[i++] = 'a';
1164
0
  }
1165
0
      else if (extra && strchr (extra, *str))
1166
0
        {
1167
0
    ptr[i++] = '%';
1168
0
          ptr[i++] = tohex_lower ((*str>>4)&15);
1169
0
          ptr[i++] = tohex_lower (*str&15);
1170
0
        }
1171
0
      else
1172
0
  ptr[i++] = *str;
1173
0
      str++;
1174
0
    }
1175
0
  ptr[i] = '\0';
1176
1177
0
  return ptr;
1178
0
}
1179
1180
/* Percent-escape the string STR by replacing colons with '%3a'.  If
1181
   EXTRA is not NULL all characters in EXTRA are also escaped.  This
1182
   function terminates the process on memory shortage.  */
1183
char *
1184
percent_escape (const char *str, const char *extra)
1185
0
{
1186
0
  return do_percent_escape (str, extra, 1);
1187
0
}
1188
1189
/* Same as percent_escape but return NULL instead of exiting on memory
1190
   error. */
1191
char *
1192
try_percent_escape (const char *str, const char *extra)
1193
0
{
1194
0
  return do_percent_escape (str, extra, 0);
1195
0
}
1196
1197
1198
/* Same as strconcat but takes a va_list.  Returns EINVAL if the list
1199
 * is too long, all other errors are due to an ENOMEM condition.  */
1200
char *
1201
vstrconcat (const char *s1, va_list arg_ptr)
1202
0
{
1203
0
  const char *argv[48];
1204
0
  size_t argc;
1205
0
  size_t needed;
1206
0
  char *buffer, *p;
1207
1208
0
  argc = 0;
1209
0
  argv[argc++] = s1;
1210
0
  needed = strlen (s1);
1211
0
  while (((argv[argc] = va_arg (arg_ptr, const char *))))
1212
0
    {
1213
0
      needed += strlen (argv[argc]);
1214
0
      if (argc >= DIM (argv)-1)
1215
0
        {
1216
0
          gpg_err_set_errno (EINVAL);
1217
0
          return NULL;
1218
0
        }
1219
0
      argc++;
1220
0
    }
1221
0
  needed++;
1222
0
  buffer = xtrymalloc (needed);
1223
0
  if (buffer)
1224
0
    {
1225
0
      for (p = buffer, argc=0; argv[argc]; argc++)
1226
0
        p = stpcpy (p, argv[argc]);
1227
0
    }
1228
0
  return buffer;
1229
0
}
1230
1231
1232
/* Concatenate the string S1 with all the following strings up to a
1233
   NULL.  Returns a malloced buffer with the new string or NULL on a
1234
   malloc error or if too many arguments are given.  */
1235
char *
1236
strconcat (const char *s1, ...)
1237
0
{
1238
0
  va_list arg_ptr;
1239
0
  char *result;
1240
1241
0
  if (!s1)
1242
0
    result = xtrystrdup ("");
1243
0
  else
1244
0
    {
1245
0
      va_start (arg_ptr, s1);
1246
0
      result = vstrconcat (s1, arg_ptr);
1247
0
      va_end (arg_ptr);
1248
0
    }
1249
0
  return result;
1250
0
}
1251
1252
/* Same as strconcat but terminate the process with an error message
1253
   if something goes wrong.  */
1254
char *
1255
xstrconcat (const char *s1, ...)
1256
0
{
1257
0
  va_list arg_ptr;
1258
0
  char *result;
1259
1260
0
  if (!s1)
1261
0
    result = xstrdup ("");
1262
0
  else
1263
0
    {
1264
0
      va_start (arg_ptr, s1);
1265
0
      result = vstrconcat (s1, arg_ptr);
1266
0
      va_end (arg_ptr);
1267
0
    }
1268
0
  if (!result)
1269
0
    {
1270
0
      if (errno == EINVAL)
1271
0
        fputs ("\nfatal: too many args for xstrconcat\n", stderr);
1272
0
      else
1273
0
        fputs ("\nfatal: out of memory\n", stderr);
1274
0
      exit (2);
1275
0
    }
1276
0
  return result;
1277
0
}
1278
1279
/* Split a string into fields at DELIM.  REPLACEMENT is the character
1280
   to replace the delimiter with (normally: '\0' so that each field is
1281
   NUL terminated).  The caller is responsible for freeing the result.
1282
   Note: this function modifies STRING!  If you need the original
1283
   value, then you should pass a copy to this function.
1284
1285
   If malloc fails, this function returns NULL.  */
1286
char **
1287
strsplit (char *string, char delim, char replacement, int *count)
1288
0
{
1289
0
  int fields = 1;
1290
0
  char *t;
1291
0
  char **result;
1292
1293
  /* First, count the number of fields.  */
1294
0
  for (t = strchr (string, delim); t; t = strchr (t + 1, delim))
1295
0
    fields ++;
1296
1297
0
  result = xtrycalloc ((fields + 1), sizeof (*result));
1298
0
  if (! result)
1299
0
    return NULL;
1300
1301
0
  result[0] = string;
1302
0
  fields = 1;
1303
0
  for (t = strchr (string, delim); t; t = strchr (t + 1, delim))
1304
0
    {
1305
0
      result[fields ++] = t + 1;
1306
0
      *t = replacement;
1307
0
    }
1308
1309
0
  if (count)
1310
0
    *count = fields;
1311
1312
0
  return result;
1313
0
}
1314
1315
1316
/* Tokenize STRING using the set of delimiters in DELIM.  Leading
1317
 * spaces and tabs are removed from all tokens.  The caller must xfree
1318
 * the result.
1319
 *
1320
 * Returns: A malloced and NULL delimited array with the tokens.  On
1321
 *          memory error NULL is returned and ERRNO is set.
1322
 */
1323
static char **
1324
do_strtokenize (const char *string, const char *delim, int trim)
1325
0
{
1326
0
  const char *s;
1327
0
  size_t fields;
1328
0
  size_t bytes, n;
1329
0
  char *buffer;
1330
0
  char *p, *px, *pend;
1331
0
  char **result;
1332
1333
  /* Count the number of fields.  */
1334
0
  for (fields = 1, s = strpbrk (string, delim); s; s = strpbrk (s + 1, delim))
1335
0
    fields++;
1336
0
  fields++; /* Add one for the terminating NULL.  */
1337
1338
  /* Allocate an array for all fields, a terminating NULL, and space
1339
     for a copy of the string.  */
1340
0
  bytes = fields * sizeof *result;
1341
0
  if (bytes / sizeof *result != fields)
1342
0
    {
1343
0
      gpg_err_set_errno (ENOMEM);
1344
0
      return NULL;
1345
0
    }
1346
0
  n = strlen (string) + 1;
1347
0
  bytes += n;
1348
0
  if (bytes < n)
1349
0
    {
1350
0
      gpg_err_set_errno (ENOMEM);
1351
0
      return NULL;
1352
0
    }
1353
0
  result = xtrymalloc (bytes);
1354
0
  if (!result)
1355
0
    return NULL;
1356
0
  buffer = (char*)(result + fields);
1357
1358
  /* Copy and parse the string.  */
1359
0
  strcpy (buffer, string);
1360
0
  for (n = 0, p = buffer; (pend = strpbrk (p, delim)); p = pend + 1)
1361
0
    {
1362
0
      *pend = 0;
1363
0
      if (trim)
1364
0
        {
1365
0
          while (spacep (p))
1366
0
            p++;
1367
0
          for (px = pend - 1; px >= p && spacep (px); px--)
1368
0
            *px = 0;
1369
0
        }
1370
0
      result[n++] = p;
1371
0
    }
1372
0
  if (trim)
1373
0
    {
1374
0
      while (spacep (p))
1375
0
        p++;
1376
0
      for (px = p + strlen (p) - 1; px >= p && spacep (px); px--)
1377
0
        *px = 0;
1378
0
    }
1379
0
  result[n++] = p;
1380
0
  result[n] = NULL;
1381
1382
0
  log_assert ((char*)(result + n + 1) == buffer);
1383
1384
0
  return result;
1385
0
}
1386
1387
/* Tokenize STRING using the set of delimiters in DELIM.  Leading
1388
 * spaces and tabs are removed from all tokens.  The caller must xfree
1389
 * the result.
1390
 *
1391
 * Returns: A malloced and NULL delimited array with the tokens.  On
1392
 *          memory error NULL is returned and ERRNO is set.
1393
 */
1394
char **
1395
strtokenize (const char *string, const char *delim)
1396
0
{
1397
0
  return do_strtokenize (string, delim, 1);
1398
0
}
1399
1400
/* Same as strtokenize but does not trim leading and trailing spaces
1401
 * from the fields.  */
1402
char **
1403
strtokenize_nt (const char *string, const char *delim)
1404
0
{
1405
0
  return do_strtokenize (string, delim, 0);
1406
0
}
1407
1408
1409
/* Split a string into space delimited fields and remove leading and
1410
 * trailing spaces from each field.  A pointer to each field is stored
1411
 * in ARRAY.  Stop splitting at ARRAYSIZE fields.  The function
1412
 * modifies STRING.  The number of parsed fields is returned.
1413
 * Example:
1414
 *
1415
 *   char *fields[2];
1416
 *   if (split_fields (string, fields, DIM (fields)) < 2)
1417
 *     return  // Not enough args.
1418
 *   foo (fields[0]);
1419
 *   foo (fields[1]);
1420
 */
1421
int
1422
split_fields (char *string, const char **array, int arraysize)
1423
0
{
1424
0
  int n = 0;
1425
0
  const char *p;
1426
0
  char *pend;
1427
1428
0
  for (p = string; *p == ' '; p++)
1429
0
    ;
1430
0
  do
1431
0
    {
1432
0
      if (n == arraysize)
1433
0
        break;
1434
0
      array[n++] = p;
1435
0
      pend = strchr (p, ' ');
1436
0
      if (!pend)
1437
0
        break;
1438
0
      *pend++ = 0;
1439
0
      for (p = pend; *p == ' '; p++)
1440
0
        ;
1441
0
    }
1442
0
  while (*p);
1443
1444
0
  return n;
1445
0
}
1446
1447
1448
/* Split a string into colon delimited fields A pointer to each field
1449
 * is stored in ARRAY.  Stop splitting at ARRAYSIZE fields.  The
1450
 * function modifies STRING.  The number of parsed fields is returned.
1451
 * Note that leading and trailing spaces are not removed from the fields.
1452
 * Example:
1453
 *
1454
 *   char *fields[2];
1455
 *   if (split_fields (string, fields, DIM (fields)) < 2)
1456
 *     return  // Not enough args.
1457
 *   foo (fields[0]);
1458
 *   foo (fields[1]);
1459
 */
1460
int
1461
split_fields_colon (char *string, const char **array, int arraysize)
1462
0
{
1463
0
  int n = 0;
1464
0
  const char *p;
1465
0
  char *pend;
1466
1467
0
  p = string;
1468
0
  do
1469
0
    {
1470
0
      if (n == arraysize)
1471
0
        break;
1472
0
      array[n++] = p;
1473
0
      pend = strchr (p, ':');
1474
0
      if (!pend)
1475
0
        break;
1476
0
      *pend++ = 0;
1477
0
      p = pend;
1478
0
    }
1479
0
  while (*p);
1480
1481
0
  return n;
1482
0
}
1483
1484
1485

1486
/* Version number parsing.  */
1487
1488
/* This function parses the first portion of the version number S and
1489
   stores it in *NUMBER.  On success, this function returns a pointer
1490
   into S starting with the first character, which is not part of the
1491
   initial number portion; on failure, NULL is returned.  */
1492
static const char*
1493
parse_version_number (const char *s, int *number)
1494
0
{
1495
0
  int val = 0;
1496
1497
0
  if (*s == '0' && digitp (s+1))
1498
0
    return NULL;  /* Leading zeros are not allowed.  */
1499
0
  for (; digitp (s); s++)
1500
0
    {
1501
0
      val *= 10;
1502
0
      val += *s - '0';
1503
0
    }
1504
0
  *number = val;
1505
0
  return val < 0 ? NULL : s;
1506
0
}
1507
1508
1509
/* This function breaks up the complete string-representation of the
1510
   version number S, which is of the following structure: <major
1511
   number>.<minor number>[.<micro number>]<patch level>.  The major,
1512
   minor, and micro number components will be stored in *MAJOR, *MINOR
1513
   and *MICRO.  If MICRO is not given 0 is used instead.
1514
1515
   On success, the last component, the patch level, will be returned;
1516
   in failure, NULL will be returned.  */
1517
static const char *
1518
parse_version_string (const char *s, int *major, int *minor, int *micro)
1519
0
{
1520
0
  s = parse_version_number (s, major);
1521
0
  if (!s || *s != '.')
1522
0
    return NULL;
1523
0
  s++;
1524
0
  s = parse_version_number (s, minor);
1525
0
  if (!s)
1526
0
    return NULL;
1527
0
  if (*s == '.')
1528
0
    {
1529
0
      s++;
1530
0
      s = parse_version_number (s, micro);
1531
0
      if (!s)
1532
0
        return NULL;
1533
0
    }
1534
0
  else
1535
0
    *micro = 0;
1536
0
  return s;  /* Patchlevel.  */
1537
0
}
1538
1539
1540
/* Compare the version string MY_VERSION to the version string
1541
 * REQ_VERSION.  Returns -1, 0, or 1 if MY_VERSION is found,
1542
 * respectively, to be less than, to match, or be greater than
1543
 * REQ_VERSION.  This function works for three and two part version
1544
 * strings; for a two part version string the micro part is assumed to
1545
 * be 0.  Patch levels are compared as strings.  If a version number
1546
 * is invalid INT_MIN is returned.  If REQ_VERSION is given as NULL
1547
 * the function returns 0 if MY_VERSION is parsable version string. */
1548
int
1549
compare_version_strings (const char *my_version, const char *req_version)
1550
0
{
1551
0
  int my_major, my_minor, my_micro;
1552
0
  int rq_major, rq_minor, rq_micro;
1553
0
  const char *my_patch, *rq_patch;
1554
0
  int result;
1555
1556
0
  if (!my_version)
1557
0
    return INT_MIN;
1558
1559
0
  my_patch = parse_version_string (my_version, &my_major, &my_minor, &my_micro);
1560
0
  if (!my_patch)
1561
0
    return INT_MIN;
1562
0
  if (!req_version)
1563
0
    return 0; /* MY_VERSION can be parsed.  */
1564
0
  rq_patch = parse_version_string (req_version, &rq_major, &rq_minor,&rq_micro);
1565
0
  if (!rq_patch)
1566
0
    return INT_MIN;
1567
1568
0
  if (my_major == rq_major)
1569
0
    {
1570
0
      if (my_minor == rq_minor)
1571
0
        {
1572
0
          if (my_micro == rq_micro)
1573
0
            result = strcmp (my_patch, rq_patch);
1574
0
          else
1575
0
            result = my_micro - rq_micro;
1576
0
        }
1577
0
      else
1578
0
        result = my_minor - rq_minor;
1579
0
    }
1580
0
  else
1581
0
    result = my_major - rq_major;
1582
1583
0
  return !result? 0 : result < 0 ? -1 : 1;
1584
0
}
1585
1586
1587

1588
/* Format a string so that it fits within about TARGET_COLS columns.
1589
 * TEXT_IN is copied to a new buffer, which is returned.  Normally,
1590
 * target_cols will be 72 and max_cols is 80.  On error NULL is
1591
 * returned and ERRNO is set. */
1592
char *
1593
format_text (const char *text_in, int target_cols, int max_cols)
1594
0
{
1595
  /* const int do_debug = 0; */
1596
1597
  /* The character under consideration.  */
1598
0
  char *p;
1599
  /* The start of the current line.  */
1600
0
  char *line;
1601
  /* The last space that we saw.  */
1602
0
  char *last_space = NULL;
1603
0
  int last_space_cols = 0;
1604
0
  int copied_last_space = 0;
1605
0
  char *text;
1606
1607
0
  text = xtrystrdup (text_in);
1608
0
  if (!text)
1609
0
    return NULL;
1610
1611
0
  p = line = text;
1612
0
  while (1)
1613
0
    {
1614
      /* The number of columns including any trailing space.  */
1615
0
      int cols;
1616
1617
0
      p = p + strcspn (p, "\n ");
1618
0
      if (! p)
1619
        /* P now points to the NUL character.  */
1620
0
        p = &text[strlen (text)];
1621
1622
0
      if (*p == '\n')
1623
        /* Pass through any newlines.  */
1624
0
        {
1625
0
          p ++;
1626
0
          line = p;
1627
0
          last_space = NULL;
1628
0
          last_space_cols = 0;
1629
0
          copied_last_space = 1;
1630
0
          continue;
1631
0
        }
1632
1633
      /* Have a space or a NUL.  Note: we don't count the trailing
1634
         space.  */
1635
0
      cols = utf8_charcount (line, (uintptr_t) p - (uintptr_t) line);
1636
0
      if (cols < target_cols)
1637
0
        {
1638
0
          if (! *p)
1639
            /* Nothing left to break.  */
1640
0
            break;
1641
1642
0
          last_space = p;
1643
0
          last_space_cols = cols;
1644
0
          p ++;
1645
          /* Skip any immediately following spaces.  If we break:
1646
             "... foo bar ..." between "foo" and "bar" then we want:
1647
             "... foo\nbar ...", which means that the left space has
1648
             to be the first space after foo, not the last space
1649
             before bar.  */
1650
0
          while (*p == ' ')
1651
0
            p ++;
1652
0
        }
1653
0
      else
1654
0
        {
1655
0
          int cols_with_left_space;
1656
0
          int cols_with_right_space;
1657
0
          int left_penalty;
1658
0
          int right_penalty;
1659
1660
0
          cols_with_left_space = last_space_cols;
1661
0
          cols_with_right_space = cols;
1662
1663
          /* if (do_debug) */
1664
          /*   log_debug ("Breaking: '%.*s'\n", */
1665
          /*              (int) ((uintptr_t) p - (uintptr_t) line), line); */
1666
1667
          /* The number of columns away from TARGET_COLS.  We prefer
1668
             to underflow than to overflow.  */
1669
0
          left_penalty = target_cols - cols_with_left_space;
1670
0
          right_penalty = 2 * (cols_with_right_space - target_cols);
1671
1672
0
          if (cols_with_right_space > max_cols)
1673
            /* Add a large penalty for each column that exceeds
1674
               max_cols.  */
1675
0
            right_penalty += 4 * (cols_with_right_space - max_cols);
1676
1677
          /* if (do_debug) */
1678
          /*   log_debug ("Left space => %d cols (penalty: %d); " */
1679
          /*              "right space => %d cols (penalty: %d)\n", */
1680
          /*              cols_with_left_space, left_penalty, */
1681
          /*              cols_with_right_space, right_penalty); */
1682
0
          if (last_space_cols && left_penalty <= right_penalty)
1683
0
            {
1684
              /* Prefer the left space.  */
1685
              /* if (do_debug) */
1686
              /*   log_debug ("Breaking at left space.\n"); */
1687
0
              p = last_space;
1688
0
            }
1689
0
          else
1690
0
            {
1691
              /* if (do_debug) */
1692
              /*   log_debug ("Breaking at right space.\n"); */
1693
0
            }
1694
1695
0
          if (! *p)
1696
0
            break;
1697
1698
0
          *p = '\n';
1699
0
          p ++;
1700
0
          if (*p == ' ')
1701
0
            {
1702
0
              int spaces;
1703
0
              for (spaces = 1; p[spaces] == ' '; spaces ++)
1704
0
                ;
1705
0
              memmove (p, &p[spaces], strlen (&p[spaces]) + 1);
1706
0
            }
1707
0
          line = p;
1708
0
          last_space = NULL;
1709
0
          last_space_cols = 0;
1710
0
          copied_last_space = 0;
1711
0
        }
1712
0
    }
1713
1714
  /* Chop off any trailing space.  */
1715
0
  trim_trailing_chars (text, strlen (text), " ");
1716
  /* If we inserted the trailing newline, then remove it.  */
1717
0
  if (! copied_last_space && *text && text[strlen (text) - 1] == '\n')
1718
0
    text[strlen (text) - 1] = '\0';
1719
1720
0
  return text;
1721
0
}
1722
1723
1724
/* In STRING replace the first occurance of SUBSTR by the string
1725
 * REPLACE.  Return a new malloced string or set ERRNO and set NULL on
1726
 * error.  If SUBSTR is not found a verbatim copy of STRING is
1727
 * returned.  */
1728
char *
1729
replace_substr (const char *string, const char *substr, const char *replace)
1730
0
{
1731
0
  size_t stringlen, substrlen, replacelen, n;
1732
0
  const char *s;
1733
0
  char *buffer;
1734
1735
0
  stringlen = strlen (string);
1736
0
  substrlen = strlen (substr);
1737
0
  replacelen = strlen (replace);
1738
1739
0
  if (stringlen < substrlen || !(s = strstr (string, substr)))
1740
0
    return xtrystrdup (string);
1741
1742
0
  stringlen -= substrlen;  /* Found thus sryinglen >= substrlen */
1743
0
  buffer = xtrymalloc (stringlen + replacelen +1);
1744
0
  if (!buffer)
1745
0
    return NULL;
1746
0
  memcpy (buffer, string, n=(s-string));
1747
0
  memcpy (buffer+n, replace, replacelen);
1748
0
  strcpy (buffer+n+replacelen, s+substrlen);
1749
1750
1751
0
  return buffer;
1752
0
}
1753
1754
1755
/* Substitute variables in STRING and return a new string.  GETVAL is
1756
 * a function which maps NAME to its value; that value is a string
1757
 * which may not change during the execution time of this function.
1758
 * If GETVAL returns NULL substitute_vars returns NULL and the caller
1759
 * may inspect ERRNO for the reason.  In all other error cases this
1760
 * function also returns NULL.  Caller must free the returned string.  */
1761
char *
1762
substitute_vars (const char *string,
1763
                 const char *(*getval)(void *cookie, const char *name),
1764
                 void *cookie)
1765
0
{
1766
0
  char *line, *p, *pend;
1767
0
  const char *value;
1768
0
  size_t valuelen, n;
1769
0
  char *result = NULL;
1770
1771
0
  result = line = xtrystrdup (string);
1772
0
  if (!result)
1773
0
    return NULL; /* Ooops */
1774
1775
0
  while (*line)
1776
0
    {
1777
0
      p = strchr (line, '$');
1778
0
      if (!p)
1779
0
        goto leave; /* No or no more variables.  */
1780
1781
0
      if (p[1] == '$') /* Escaped dollar sign. */
1782
0
        {
1783
0
          memmove (p, p+1, strlen (p+1)+1);
1784
0
          line = p + 1;
1785
0
          continue;
1786
0
        }
1787
1788
0
      if (p[1] == '{')
1789
0
        {
1790
0
          int count = 0;
1791
1792
0
          for (pend=p+2; *pend; pend++)
1793
0
            {
1794
0
              if (*pend == '{')
1795
0
                count++;
1796
0
              else if (*pend == '}')
1797
0
                {
1798
0
                  if (--count < 0)
1799
0
                    break;
1800
0
                }
1801
0
            }
1802
0
          if (!*pend)
1803
0
            goto leave; /* Unclosed - don't substitute.  */
1804
0
        }
1805
0
      else
1806
0
        {
1807
0
          for (pend = p+1; *pend && (alnump (pend) || *pend == '_'); pend++)
1808
0
            ;
1809
0
        }
1810
1811
0
      if (p[1] == '{' && *pend == '}')
1812
0
        {
1813
0
          int save = *pend;
1814
0
          *pend = 0;
1815
0
          value = getval (cookie, p+2);
1816
0
          *pend++ = save;
1817
0
        }
1818
0
      else
1819
0
        {
1820
0
          int save = *pend;
1821
0
          *pend = 0;
1822
0
          value = getval (cookie, p+1);
1823
0
          *pend = save;
1824
0
        }
1825
1826
0
      if (!value)
1827
0
        {
1828
0
          xfree (result);
1829
0
          return NULL;
1830
0
        }
1831
0
      valuelen = strlen (value);
1832
0
      if (valuelen <= pend - p)
1833
0
        {
1834
0
          memcpy (p, value, valuelen);
1835
0
          p += valuelen;
1836
0
          n = pend - p;
1837
0
          if (n)
1838
0
            memmove (p, p+n, strlen (p+n)+1);
1839
0
          line = p;
1840
0
        }
1841
0
      else
1842
0
        {
1843
0
          char *src = result;
1844
0
          char *dst;
1845
1846
0
          dst = xtrymalloc (strlen (src) + valuelen + 1);
1847
0
          if (!dst)
1848
0
            {
1849
0
              xfree (result);
1850
0
              return NULL;
1851
0
            }
1852
0
          n = p - src;
1853
0
          memcpy (dst, src, n);
1854
0
          memcpy (dst + n, value, valuelen);
1855
0
          n += valuelen;
1856
0
          strcpy (dst + n, pend);
1857
0
          line = dst + n;
1858
0
          xfree (result);
1859
0
          result = dst;
1860
0
        }
1861
0
    }
1862
1863
0
 leave:
1864
0
  return result;
1865
0
}
1866
1867
1868
/* Helper for substitute_envvars.  */
1869
static const char *
1870
subst_getenv (void *cookie, const char *name)
1871
0
{
1872
0
  const char *s;
1873
1874
0
  (void)cookie;
1875
1876
0
  s = getenv (name);
1877
0
  return s? s : "";
1878
0
}
1879
1880
1881
/* Substitute environment variables in STRING and return a new string.
1882
 * On error the function returns NULL.  */
1883
char *
1884
substitute_envvars (const char *string)
1885
0
{
1886
0
  return substitute_vars (string, subst_getenv, NULL);
1887
1888
0
}