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
7 * This file is part of GnuPG.
9 * GnuPG is free software; you can redistribute and/or modify this
10 * part of GnuPG under the terms of either
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.
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.
22 * or both in parallel, as here.
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.
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/>.
44 #include <sys/types.h>
45 #ifdef HAVE_W32_SYSTEM
46 # ifdef HAVE_WINSOCK2_H
47 # include <winsock2.h>
55 #include "common-defs.h"
58 #include "stringhelp.h"
60 #define tohex_lower(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'a'))
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. */
69 change_slashes (char *name)
71 #ifdef HAVE_DOSISH_SYSTEM
74 if (strchr (name, '\\'))
80 #endif /*HAVE_DOSISH_SYSTEM*/
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).
92 has_leading_keyword (const char *string, const char *keyword)
94 size_t n = strlen (keyword);
96 if (!strncmp (string, keyword, n)
97 && (!string[n] || string[n] == ' ' || string[n] == '\t'))
100 while (*string == ' ' || *string == '\t')
102 return (char*)string;
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.
114 memistr (const void *buffer, size_t buflen, const char *sub)
116 const unsigned char *buf = buffer;
117 const unsigned char *t = (const unsigned char *)buffer;
118 const unsigned char *s = (const unsigned char *)sub;
121 for ( ; n ; t++, n-- )
123 if ( toupper (*t) == toupper (*s) )
125 for ( buf=t++, buflen = n--, s++;
126 n && toupper (*t) == toupper (*s); t++, s++, n-- )
129 return (const char*)buf;
131 s = (const unsigned char *)sub ;
139 ascii_memistr ( const void *buffer, size_t buflen, const char *sub )
141 const unsigned char *buf = buffer;
142 const unsigned char *t = (const unsigned char *)buf;
143 const unsigned char *s = (const unsigned char *)sub;
146 for ( ; n ; t++, n-- )
148 if (ascii_toupper (*t) == ascii_toupper (*s) )
150 for ( buf=t++, buflen = n--, s++;
151 n && ascii_toupper (*t) == ascii_toupper (*s); t++, s++, n-- )
154 return (const char*)buf;
155 t = (const unsigned char *)buf;
156 s = (const unsigned char *)sub ;
163 /* This function is similar to strncpy(). However it won't copy more
164 than N - 1 characters and makes sure that a '\0' is appended. With
165 N given as 0, nothing will happen. With DEST given as NULL, memory
166 will be allocated using xmalloc (i.e. if it runs out of core
167 the function terminates). Returns DES or a pointer to the
171 mem2str( char *dest , const void *src , size_t n )
178 dest = xmalloc( n ) ;
181 for(n--; n && *s; n-- )
191 * remove leading and trailing white spaces
194 trim_spaces( char *str )
196 char *string, *p, *mark;
199 /* find first non space character */
200 for( p=string; *p && isspace( *(byte*)p ) ; p++ )
202 /* move characters */
203 for( (mark = NULL); (*string = *p); string++, p++ )
204 if( isspace( *(byte*)p ) ) {
211 *mark = '\0' ; /* remove trailing spaces */
217 * remove trailing white spaces
220 trim_trailing_spaces( char *string )
224 for( mark = NULL, p = string; *p; p++ ) {
225 if( isspace( *(byte*)p ) ) {
240 trim_trailing_chars( byte *line, unsigned len, const char *trimchars )
245 for(mark=NULL, p=line, n=0; n < len; n++, p++ ) {
246 if( strchr(trimchars, *p ) ) {
262 * remove trailing white spaces and return the length of the buffer
265 trim_trailing_ws( byte *line, unsigned len )
267 return trim_trailing_chars( line, len, " \t\r\n" );
271 length_sans_trailing_chars (const unsigned char *line, size_t len,
272 const char *trimchars )
274 const unsigned char *p, *mark;
277 for( mark=NULL, p=line, n=0; n < len; n++, p++ )
279 if (strchr (trimchars, *p ))
294 * Return the length of line ignoring trailing white-space.
297 length_sans_trailing_ws (const unsigned char *line, size_t len)
299 return length_sans_trailing_chars (line, len, " \t\r\n");
305 * Extract from a given path the filename component. This function
306 * terminates the process on memory shortage.
309 make_basename(const char *filepath, const char *inputpath)
312 return riscos_make_basename(filepath, inputpath);
316 (void)inputpath; /* Only required for riscos. */
318 if ( !(p=strrchr(filepath, '/')) )
319 #ifdef HAVE_DOSISH_SYSTEM
320 if ( !(p=strrchr(filepath, '\\')) )
322 #ifdef HAVE_DRIVE_LETTERS
323 if ( !(p=strrchr(filepath, ':')) )
326 return xstrdup(filepath);
336 * Extract from a given filename the path prepended to it. If there
337 * isn't a path prepended to the filename, a dot is returned ('.').
338 * This function terminates the process on memory shortage.
341 make_dirname(const char *filepath)
347 if ( !(p=strrchr(filepath, '/')) )
348 #ifdef HAVE_DOSISH_SYSTEM
349 if ( !(p=strrchr(filepath, '\\')) )
351 #ifdef HAVE_DRIVE_LETTERS
352 if ( !(p=strrchr(filepath, ':')) )
358 dirname_length = p-filepath;
359 dirname = xmalloc(dirname_length+1);
360 strncpy(dirname, filepath, dirname_length);
361 dirname[dirname_length] = 0;
369 get_pwdir (int xmode, const char *name)
373 struct passwd *pwd = NULL;
378 /* Fixme: We should use getpwnam_r if available. */
379 pwd = getpwnam (name);
385 /* Fixme: We should use getpwuid_r if available. */
386 pwd = getpwuid (getuid());
392 result = xstrdup (pwd->pw_dir);
394 result = xtrystrdup (pwd->pw_dir);
396 #else /*!HAVE_PWD_H*/
397 /* No support at all. */
400 #endif /*HAVE_PWD_H*/
405 /* xmode 0 := Return NULL on error
406 1 := Terminate on error
407 2 := Make sure that name is absolute; return NULL on error
408 3 := Make sure that name is absolute; terminate on error
411 do_make_filename (int xmode, const char *first_part, va_list arg_ptr)
413 const char *argv[32];
417 char *home_buffer = NULL;
418 char *name, *home, *p;
421 want_abs = !!(xmode & 2);
424 n = strlen (first_part) + 1;
426 while ( (argv[argc] = va_arg (arg_ptr, const char *)) )
428 n += strlen (argv[argc]) + 1;
429 if (argc >= DIM (argv)-1)
433 gpg_err_set_errno (EINVAL);
441 if (*first_part == '~')
443 if (first_part[1] == '/' || !first_part[1])
445 /* This is the "~/" or "~" case. */
446 home = getenv("HOME");
448 home = home_buffer = get_pwdir (xmode, NULL);
454 /* This is the "~username/" or "~username" case. */
458 user = xstrdup (first_part+1);
461 user = xtrystrdup (first_part+1);
465 p = strchr (user, '/');
468 skip = 1 + strlen (user);
470 home = home_buffer = get_pwdir (xmode, user);
483 name = xtrymalloc (n);
492 p = stpcpy (stpcpy (name, home), first_part + skip);
494 p = stpcpy (name, first_part);
497 for (argc=0; argv[argc]; argc++)
499 /* Avoid a leading double slash if the first part was "/". */
500 if (!argc && name[0] == '/' && !name[1])
501 p = stpcpy (p, argv[argc]);
503 p = stpcpy (stpcpy (p, "/"), argv[argc]);
508 #ifdef HAVE_DRIVE_LETTERS
509 p = strchr (name, ':');
518 #ifdef HAVE_DRIVE_LETTERS
523 home = gnupg_getcwd ();
528 fprintf (stderr, "\nfatal: getcwd failed: %s\n",
535 n = strlen (home) + 1 + strlen (name) + 1;
537 home_buffer = xmalloc (n);
540 home_buffer = xtrymalloc (n);
550 else /* Windows case. */
552 memcpy (home_buffer, p, p - name + 1);
553 p = home_buffer + (p - name + 1);
556 /* Avoid a leading double slash if the cwd is "/". */
557 if (home[0] == '/' && !home[1])
558 strcpy (stpcpy (p, "/"), name);
560 strcpy (stpcpy (stpcpy (p, home), "/"), name);
565 /* Let's do a simple compression to catch the most common
566 case of using "." for gpg's --homedir option. */
568 if (n > 2 && name[n-2] == '/' && name[n-1] == '.')
572 return change_slashes (name);
575 /* Construct a filename from the NULL terminated list of parts. Tilde
576 expansion is done for the first argument. This function terminates
577 the process on memory shortage. */
579 make_filename (const char *first_part, ... )
584 va_start (arg_ptr, first_part);
585 result = do_make_filename (1, first_part, arg_ptr);
590 /* Construct a filename from the NULL terminated list of parts. Tilde
591 expansion is done for the first argument. This function may return
594 make_filename_try (const char *first_part, ... )
599 va_start (arg_ptr, first_part);
600 result = do_make_filename (0, first_part, arg_ptr);
605 /* Construct an absolute filename from the NULL terminated list of
606 parts. Tilde expansion is done for the first argument. This
607 function terminates the process on memory shortage. */
609 make_absfilename (const char *first_part, ... )
614 va_start (arg_ptr, first_part);
615 result = do_make_filename (3, first_part, arg_ptr);
620 /* Construct an absolute filename from the NULL terminated list of
621 parts. Tilde expansion is done for the first argument. This
622 function may return NULL on error. */
624 make_absfilename_try (const char *first_part, ... )
629 va_start (arg_ptr, first_part);
630 result = do_make_filename (2, first_part, arg_ptr);
637 /* Compare whether the filenames are identical. This is a
638 special version of strcmp() taking the semantics of filenames in
639 account. Note that this function works only on the supplied names
640 without considering any context like the current directory. See
641 also same_file_p(). */
643 compare_filenames (const char *a, const char *b)
645 #ifdef HAVE_DOSISH_SYSTEM
646 for ( ; *a && *b; a++, b++ )
649 && (toupper (*(const unsigned char*)a)
650 != toupper (*(const unsigned char*)b) )
651 && !((*a == '/' && *b == '\\') || (*a == '\\' && *b == '/')))
654 if ((*a == '/' && *b == '\\') || (*a == '\\' && *b == '/'))
657 return (toupper (*(const unsigned char*)a)
658 - toupper (*(const unsigned char*)b));
665 /* Convert a base-10 number in STRING into a 64 bit unsigned int
666 * value. Leading white spaces are skipped but no error checking is
667 * done. Thus it is similar to atoi(). */
669 string_to_u64 (const char *string)
673 while (spacep (string))
675 for (; digitp (string); string++)
678 val += *string - '0';
684 /* Convert 2 hex characters at S to a byte value. Return this value
685 or -1 if there is an error. */
687 hextobyte (const char *s)
691 if ( *s >= '0' && *s <= '9' )
693 else if ( *s >= 'A' && *s <= 'F' )
694 c = 16 * (10 + *s - 'A');
695 else if ( *s >= 'a' && *s <= 'f' )
696 c = 16 * (10 + *s - 'a');
700 if ( *s >= '0' && *s <= '9' )
702 else if ( *s >= 'A' && *s <= 'F' )
704 else if ( *s >= 'a' && *s <= 'f' )
711 /* Given a string containing an UTF-8 encoded text, return the number
712 of characters in this string. It differs from strlen in that it
713 only counts complete UTF-8 characters. SIZE is the maximum length
714 of the string in bytes. If SIZE is -1, then a NUL character is
715 taken to be the end of the string. Note, that this function does
716 not take combined characters into account. */
718 utf8_charcount (const char *s, int len)
727 if ( (*s&0xc0) != 0x80 ) /* Exclude continuation bytes: 10xxxxxx */
742 /****************************************************
743 ********** W32 specific functions ****************
744 ****************************************************/
746 #ifdef HAVE_W32_SYSTEM
748 w32_strerror (int ec)
750 static char strerr[256];
753 ec = (int)GetLastError ();
754 #ifdef HAVE_W32CE_SYSTEM
755 /* There is only a wchar_t FormatMessage. It does not make much
756 sense to play the conversion game; we print only the code. */
757 snprintf (strerr, sizeof strerr, "ec=%d", (int)GetLastError ());
759 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec,
760 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
761 strerr, DIM (strerr)-1, NULL);
765 #endif /*HAVE_W32_SYSTEM*/
768 /****************************************************
769 ******** Locale insensitive ctype functions ********
770 ****************************************************/
771 /* FIXME: replace them by a table lookup and macros */
773 ascii_isupper (int c)
775 return c >= 'A' && c <= 'Z';
779 ascii_islower (int c)
781 return c >= 'a' && c <= 'z';
785 ascii_toupper (int c)
787 if (c >= 'a' && c <= 'z')
793 ascii_tolower (int c)
795 if (c >= 'A' && c <= 'Z')
800 /* Lowercase all ASCII characters in S. */
802 ascii_strlwr (char *s)
807 if (isascii (*p) && *p >= 'A' && *p <= 'Z')
814 ascii_strcasecmp( const char *a, const char *b )
819 for (; *a && *b; a++, b++) {
820 if (*a != *b && ascii_toupper(*a) != ascii_toupper(*b))
823 return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
827 ascii_strncasecmp (const char *a, const char *b, size_t n)
829 const unsigned char *p1 = (const unsigned char *)a;
830 const unsigned char *p2 = (const unsigned char *)b;
831 unsigned char c1, c2;
838 c1 = ascii_tolower (*p1);
839 c2 = ascii_tolower (*p2);
841 if ( !--n || c1 == '\0')
854 ascii_memcasecmp (const void *a_arg, const void *b_arg, size_t n )
856 const char *a = a_arg;
857 const char *b = b_arg;
861 for ( ; n; n--, a++, b++ )
863 if( *a != *b && ascii_toupper (*a) != ascii_toupper (*b) )
864 return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
870 ascii_strcmp( const char *a, const char *b )
875 for (; *a && *b; a++, b++) {
879 return *a == *b? 0 : (*(signed char *)a - *(signed char *)b);
884 ascii_memcasemem (const void *haystack, size_t nhaystack,
885 const void *needle, size_t nneedle)
889 return (void*)haystack; /* finding an empty needle is really easy */
890 if (nneedle <= nhaystack)
892 const char *a = haystack;
893 const char *b = a + nhaystack - nneedle;
897 if ( !ascii_memcasecmp (a, needle, nneedle) )
904 /*********************************************
905 ********** missing string functions *********
906 *********************************************/
910 stpcpy(char *a,const char *b)
921 /* Find the first occurrence in S of any character in ACCEPT.
922 Code taken from glibc-2.6/string/strpbrk.c (LGPLv2.1+) and modified. */
924 strpbrk (const char *s, const char *accept)
928 const char *a = accept;
937 #endif /*!HAVE_STRPBRK*/
941 /* Code taken from glibc-2.2.1/sysdeps/generic/strsep.c. */
943 strsep (char **stringp, const char *delim)
951 /* A frequent case is when the delimiter string contains only one
952 character. Here we don't need to call the expensive 'strpbrk'
953 function and instead work using 'strchr'. */
954 if (delim[0] == '\0' || delim[1] == '\0')
964 else if (*begin == '\0')
967 end = strchr (begin + 1, ch);
971 /* Find the end of the token. */
972 end = strpbrk (begin, delim);
976 /* Terminate the token and set *STRINGP past NUL character. */
981 /* No more delimiters; this is the last token. */
986 #endif /*HAVE_STRSEP*/
1001 #ifndef HAVE_STRCASECMP
1003 strcasecmp( const char *a, const char *b )
1005 for( ; *a && *b; a++, b++ ) {
1006 if( *a != *b && toupper(*a) != toupper(*b) )
1009 return *(const byte*)a - *(const byte*)b;
1015 * mingw32/cpd has a memicmp()
1017 #ifndef HAVE_MEMICMP
1019 memicmp( const char *a, const char *b, size_t n )
1021 for( ; n; n--, a++, b++ )
1022 if( *a != *b && toupper(*(const byte*)a) != toupper(*(const byte*)b) )
1023 return *(const byte *)a - *(const byte*)b;
1029 #ifndef HAVE_MEMRCHR
1031 memrchr (const void *buffer, int c, size_t n)
1033 const unsigned char *p = buffer;
1035 for (p += n; n ; n--)
1040 #endif /*HAVE_MEMRCHR*/
1043 /* Percent-escape the string STR by replacing colons with '%3a'. If
1044 EXTRA is not NULL all characters in EXTRA are also escaped. */
1046 do_percent_escape (const char *str, const char *extra, int die)
1054 for (i=j=0; str[i]; i++)
1055 if (str[i] == ':' || str[i] == '%' || str[i] == '\n'
1056 || (extra && strchr (extra, str[i])))
1059 ptr = xmalloc (i + 2 * j + 1);
1062 ptr = xtrymalloc (i + 2 * j + 1);
1075 else if (*str == '%')
1081 else if (*str == '\n')
1083 /* The newline is problematic in a line-based format. */
1088 else if (extra && strchr (extra, *str))
1091 ptr[i++] = tohex_lower ((*str>>4)&15);
1092 ptr[i++] = tohex_lower (*str&15);
1103 /* Percent-escape the string STR by replacing colons with '%3a'. If
1104 EXTRA is not NULL all characters in EXTRA are also escaped. This
1105 function terminates the process on memory shortage. */
1107 percent_escape (const char *str, const char *extra)
1109 return do_percent_escape (str, extra, 1);
1112 /* Same as percent_escape but return NULL instead of exiting on memory
1115 try_percent_escape (const char *str, const char *extra)
1117 return do_percent_escape (str, extra, 0);
1123 do_strconcat (const char *s1, va_list arg_ptr)
1125 const char *argv[48];
1132 needed = strlen (s1);
1133 while (((argv[argc] = va_arg (arg_ptr, const char *))))
1135 needed += strlen (argv[argc]);
1136 if (argc >= DIM (argv)-1)
1138 gpg_err_set_errno (EINVAL);
1144 buffer = xtrymalloc (needed);
1147 for (p = buffer, argc=0; argv[argc]; argc++)
1148 p = stpcpy (p, argv[argc]);
1154 /* Concatenate the string S1 with all the following strings up to a
1155 NULL. Returns a malloced buffer with the new string or NULL on a
1156 malloc error or if too many arguments are given. */
1158 strconcat (const char *s1, ...)
1164 result = xtrystrdup ("");
1167 va_start (arg_ptr, s1);
1168 result = do_strconcat (s1, arg_ptr);
1174 /* Same as strconcat but terminate the process with an error message
1175 if something goes wrong. */
1177 xstrconcat (const char *s1, ...)
1183 result = xstrdup ("");
1186 va_start (arg_ptr, s1);
1187 result = do_strconcat (s1, arg_ptr);
1192 if (errno == EINVAL)
1193 fputs ("\nfatal: too many args for xstrconcat\n", stderr);
1195 fputs ("\nfatal: out of memory\n", stderr);
1201 /* Split a string into fields at DELIM. REPLACEMENT is the character
1202 to replace the delimiter with (normally: '\0' so that each field is
1203 NUL terminated). The caller is responsible for freeing the result.
1204 Note: this function modifies STRING! If you need the original
1205 value, then you should pass a copy to this function.
1207 If malloc fails, this function returns NULL. */
1209 strsplit (char *string, char delim, char replacement, int *count)
1215 /* First, count the number of fields. */
1216 for (t = strchr (string, delim); t; t = strchr (t + 1, delim))
1219 result = xtrycalloc ((fields + 1), sizeof (*result));
1225 for (t = strchr (string, delim); t; t = strchr (t + 1, delim))
1227 result[fields ++] = t + 1;
1238 /* Tokenize STRING using the set of delimiters in DELIM. Leading
1239 * spaces and tabs are removed from all tokens. The caller must xfree
1242 * Returns: A malloced and NULL delimited array with the tokens. On
1243 * memory error NULL is returned and ERRNO is set.
1246 strtokenize (const char *string, const char *delim)
1252 char *p, *px, *pend;
1255 /* Count the number of fields. */
1256 for (fields = 1, s = strpbrk (string, delim); s; s = strpbrk (s + 1, delim))
1258 fields++; /* Add one for the terminating NULL. */
1260 /* Allocate an array for all fields, a terminating NULL, and space
1261 for a copy of the string. */
1262 bytes = fields * sizeof *result;
1263 if (bytes / sizeof *result != fields)
1265 gpg_err_set_errno (ENOMEM);
1268 n = strlen (string) + 1;
1272 gpg_err_set_errno (ENOMEM);
1275 result = xtrymalloc (bytes);
1278 buffer = (char*)(result + fields);
1280 /* Copy and parse the string. */
1281 strcpy (buffer, string);
1282 for (n = 0, p = buffer; (pend = strpbrk (p, delim)); p = pend + 1)
1287 for (px = pend - 1; px >= p && spacep (px); px--)
1293 for (px = p + strlen (p) - 1; px >= p && spacep (px); px--)
1298 assert ((char*)(result + n + 1) == buffer);
1304 /* Split a string into space delimited fields and remove leading and
1305 * trailing spaces from each field. A pointer to each field is stored
1306 * in ARRAY. Stop splitting at ARRAYSIZE fields. The function
1307 * modifies STRING. The number of parsed fields is returned.
1311 * if (split_fields (string, fields, DIM (fields)) < 2)
1312 * return // Not enough args.
1317 split_fields (char *string, char **array, int arraysize)
1322 for (p = string; *p == ' '; p++)
1329 pend = strchr (p, ' ');
1333 for (p = pend; *p == ' '; p++)
1342 /* Split a string into colon delimited fields A pointer to each field
1343 * is stored in ARRAY. Stop splitting at ARRAYSIZE fields. The
1344 * function modifies STRING. The number of parsed fields is returned.
1345 * Note that leading and trailing spaces are not removed from the fields.
1349 * if (split_fields (string, fields, DIM (fields)) < 2)
1350 * return // Not enough args.
1355 split_fields_colon (char *string, char **array, int arraysize)
1366 pend = strchr (p, ':');
1379 /* Version number parsing. */
1381 /* This function parses the first portion of the version number S and
1382 stores it in *NUMBER. On success, this function returns a pointer
1383 into S starting with the first character, which is not part of the
1384 initial number portion; on failure, NULL is returned. */
1386 parse_version_number (const char *s, int *number)
1390 if (*s == '0' && digitp (s+1))
1391 return NULL; /* Leading zeros are not allowed. */
1392 for (; digitp (s); s++)
1398 return val < 0 ? NULL : s;
1402 /* This function breaks up the complete string-representation of the
1403 version number S, which is of the following struture: <major
1404 number>.<minor number>[.<micro number>]<patch level>. The major,
1405 minor, and micro number components will be stored in *MAJOR, *MINOR
1406 and *MICRO. If MICRO is not given 0 is used instead.
1408 On success, the last component, the patch level, will be returned;
1409 in failure, NULL will be returned. */
1411 parse_version_string (const char *s, int *major, int *minor, int *micro)
1413 s = parse_version_number (s, major);
1414 if (!s || *s != '.')
1417 s = parse_version_number (s, minor);
1423 s = parse_version_number (s, micro);
1429 return s; /* Patchlevel. */
1433 /* Compare the version string MY_VERSION to the version string
1434 * REQ_VERSION. Returns -1, 0, or 1 if MY_VERSION is found,
1435 * respectively, to be less than, to match, or be greater than
1436 * REQ_VERSION. This function works for three and two part version
1437 * strings; for a two part version string the micro part is assumed to
1438 * be 0. Patch levels are compared as strings. If a version number
1439 * is invalid INT_MIN is returned. If REQ_VERSION is given as NULL
1440 * the function returns 0 if MY_VERSION is parsable version string. */
1442 compare_version_strings (const char *my_version, const char *req_version)
1444 int my_major, my_minor, my_micro;
1445 int rq_major, rq_minor, rq_micro;
1446 const char *my_patch, *rq_patch;
1452 my_patch = parse_version_string (my_version, &my_major, &my_minor, &my_micro);
1456 return 0; /* MY_VERSION can be parsed. */
1457 rq_patch = parse_version_string (req_version, &rq_major, &rq_minor,&rq_micro);
1461 if (my_major == rq_major)
1463 if (my_minor == rq_minor)
1465 if (my_micro == rq_micro)
1466 result = strcmp (my_patch, rq_patch);
1468 result = my_micro - rq_micro;
1471 result = my_minor - rq_minor;
1474 result = my_major - rq_major;
1476 return !result? 0 : result < 0 ? -1 : 1;
1481 /* Format a string so that it fits within about TARGET_COLS columns.
1482 * TEXT_IN is copied to a new buffer, which is returned. Normally,
1483 * target_cols will be 72 and max_cols is 80. On error NULL is
1484 * returned and ERRNO is set. */
1486 format_text (const char *text_in, int target_cols, int max_cols)
1488 /* const int do_debug = 0; */
1490 /* The character under consideration. */
1492 /* The start of the current line. */
1494 /* The last space that we saw. */
1495 char *last_space = NULL;
1496 int last_space_cols = 0;
1497 int copied_last_space = 0;
1500 text = xtrystrdup (text_in);
1507 /* The number of columns including any trailing space. */
1510 p = p + strcspn (p, "\n ");
1512 /* P now points to the NUL character. */
1513 p = &text[strlen (text)];
1516 /* Pass through any newlines. */
1521 last_space_cols = 0;
1522 copied_last_space = 1;
1526 /* Have a space or a NUL. Note: we don't count the trailing
1528 cols = utf8_charcount (line, (uintptr_t) p - (uintptr_t) line);
1529 if (cols < target_cols)
1532 /* Nothing left to break. */
1536 last_space_cols = cols;
1538 /* Skip any immediately following spaces. If we break:
1539 "... foo bar ..." between "foo" and "bar" then we want:
1540 "... foo\nbar ...", which means that the left space has
1541 to be the first space after foo, not the last space
1548 int cols_with_left_space;
1549 int cols_with_right_space;
1553 cols_with_left_space = last_space_cols;
1554 cols_with_right_space = cols;
1557 /* log_debug ("Breaking: '%.*s'\n", */
1558 /* (int) ((uintptr_t) p - (uintptr_t) line), line); */
1560 /* The number of columns away from TARGET_COLS. We prefer
1561 to underflow than to overflow. */
1562 left_penalty = target_cols - cols_with_left_space;
1563 right_penalty = 2 * (cols_with_right_space - target_cols);
1565 if (cols_with_right_space > max_cols)
1566 /* Add a large penalty for each column that exceeds
1568 right_penalty += 4 * (cols_with_right_space - max_cols);
1571 /* log_debug ("Left space => %d cols (penalty: %d); " */
1572 /* "right space => %d cols (penalty: %d)\n", */
1573 /* cols_with_left_space, left_penalty, */
1574 /* cols_with_right_space, right_penalty); */
1575 if (last_space_cols && left_penalty <= right_penalty)
1577 /* Prefer the left space. */
1579 /* log_debug ("Breaking at left space.\n"); */
1585 /* log_debug ("Breaking at right space.\n"); */
1596 for (spaces = 1; p[spaces] == ' '; spaces ++)
1598 memmove (p, &p[spaces], strlen (&p[spaces]) + 1);
1602 last_space_cols = 0;
1603 copied_last_space = 0;
1607 /* Chop off any trailing space. */
1608 trim_trailing_chars (text, strlen (text), " ");
1609 /* If we inserted the trailing newline, then remove it. */
1610 if (! copied_last_space && *text && text[strlen (text) - 1] == '\n')
1611 text[strlen (text) - 1] = '\0';