LCOV - code coverage report
Current view: top level - common - stringhelp.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 439 558 78.7 %
Date: 2016-09-12 13:01:59 Functions: 41 48 85.4 %

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

Generated by: LCOV version 1.11