Coverage Report

Created: 2022-12-08 06:10

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