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')
813 /* Upcase all ASCII characters in S. */
815 ascii_strupr (char *s)
820 if (isascii (*p) && *p >= 'a' && *p <= 'z')
827 ascii_strcasecmp( const char *a, const char *b )
832 for (; *a && *b; a++, b++) {
833 if (*a != *b && ascii_toupper(*a) != ascii_toupper(*b))
836 return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
840 ascii_strncasecmp (const char *a, const char *b, size_t n)
842 const unsigned char *p1 = (const unsigned char *)a;
843 const unsigned char *p2 = (const unsigned char *)b;
844 unsigned char c1, c2;
851 c1 = ascii_tolower (*p1);
852 c2 = ascii_tolower (*p2);
854 if ( !--n || c1 == '\0')
867 ascii_memcasecmp (const void *a_arg, const void *b_arg, size_t n )
869 const char *a = a_arg;
870 const char *b = b_arg;
874 for ( ; n; n--, a++, b++ )
876 if( *a != *b && ascii_toupper (*a) != ascii_toupper (*b) )
877 return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
883 ascii_strcmp( const char *a, const char *b )
888 for (; *a && *b; a++, b++) {
892 return *a == *b? 0 : (*(signed char *)a - *(signed char *)b);
897 ascii_memcasemem (const void *haystack, size_t nhaystack,
898 const void *needle, size_t nneedle)
902 return (void*)haystack; /* finding an empty needle is really easy */
903 if (nneedle <= nhaystack)
905 const char *a = haystack;
906 const char *b = a + nhaystack - nneedle;
910 if ( !ascii_memcasecmp (a, needle, nneedle) )
917 /*********************************************
918 ********** missing string functions *********
919 *********************************************/
923 stpcpy(char *a,const char *b)
934 /* Find the first occurrence in S of any character in ACCEPT.
935 Code taken from glibc-2.6/string/strpbrk.c (LGPLv2.1+) and modified. */
937 strpbrk (const char *s, const char *accept)
941 const char *a = accept;
950 #endif /*!HAVE_STRPBRK*/
954 /* Code taken from glibc-2.2.1/sysdeps/generic/strsep.c. */
956 strsep (char **stringp, const char *delim)
964 /* A frequent case is when the delimiter string contains only one
965 character. Here we don't need to call the expensive 'strpbrk'
966 function and instead work using 'strchr'. */
967 if (delim[0] == '\0' || delim[1] == '\0')
977 else if (*begin == '\0')
980 end = strchr (begin + 1, ch);
984 /* Find the end of the token. */
985 end = strpbrk (begin, delim);
989 /* Terminate the token and set *STRINGP past NUL character. */
994 /* No more delimiters; this is the last token. */
999 #endif /*HAVE_STRSEP*/
1014 #ifndef HAVE_STRCASECMP
1016 strcasecmp( const char *a, const char *b )
1018 for( ; *a && *b; a++, b++ ) {
1019 if( *a != *b && toupper(*a) != toupper(*b) )
1022 return *(const byte*)a - *(const byte*)b;
1028 * mingw32/cpd has a memicmp()
1030 #ifndef HAVE_MEMICMP
1032 memicmp( const char *a, const char *b, size_t n )
1034 for( ; n; n--, a++, b++ )
1035 if( *a != *b && toupper(*(const byte*)a) != toupper(*(const byte*)b) )
1036 return *(const byte *)a - *(const byte*)b;
1042 #ifndef HAVE_MEMRCHR
1044 memrchr (const void *buffer, int c, size_t n)
1046 const unsigned char *p = buffer;
1048 for (p += n; n ; n--)
1053 #endif /*HAVE_MEMRCHR*/
1056 /* Percent-escape the string STR by replacing colons with '%3a'. If
1057 EXTRA is not NULL all characters in EXTRA are also escaped. */
1059 do_percent_escape (const char *str, const char *extra, int die)
1067 for (i=j=0; str[i]; i++)
1068 if (str[i] == ':' || str[i] == '%' || str[i] == '\n'
1069 || (extra && strchr (extra, str[i])))
1072 ptr = xmalloc (i + 2 * j + 1);
1075 ptr = xtrymalloc (i + 2 * j + 1);
1088 else if (*str == '%')
1094 else if (*str == '\n')
1096 /* The newline is problematic in a line-based format. */
1101 else if (extra && strchr (extra, *str))
1104 ptr[i++] = tohex_lower ((*str>>4)&15);
1105 ptr[i++] = tohex_lower (*str&15);
1116 /* Percent-escape the string STR by replacing colons with '%3a'. If
1117 EXTRA is not NULL all characters in EXTRA are also escaped. This
1118 function terminates the process on memory shortage. */
1120 percent_escape (const char *str, const char *extra)
1122 return do_percent_escape (str, extra, 1);
1125 /* Same as percent_escape but return NULL instead of exiting on memory
1128 try_percent_escape (const char *str, const char *extra)
1130 return do_percent_escape (str, extra, 0);
1136 do_strconcat (const char *s1, va_list arg_ptr)
1138 const char *argv[48];
1145 needed = strlen (s1);
1146 while (((argv[argc] = va_arg (arg_ptr, const char *))))
1148 needed += strlen (argv[argc]);
1149 if (argc >= DIM (argv)-1)
1151 gpg_err_set_errno (EINVAL);
1157 buffer = xtrymalloc (needed);
1160 for (p = buffer, argc=0; argv[argc]; argc++)
1161 p = stpcpy (p, argv[argc]);
1167 /* Concatenate the string S1 with all the following strings up to a
1168 NULL. Returns a malloced buffer with the new string or NULL on a
1169 malloc error or if too many arguments are given. */
1171 strconcat (const char *s1, ...)
1177 result = xtrystrdup ("");
1180 va_start (arg_ptr, s1);
1181 result = do_strconcat (s1, arg_ptr);
1187 /* Same as strconcat but terminate the process with an error message
1188 if something goes wrong. */
1190 xstrconcat (const char *s1, ...)
1196 result = xstrdup ("");
1199 va_start (arg_ptr, s1);
1200 result = do_strconcat (s1, arg_ptr);
1205 if (errno == EINVAL)
1206 fputs ("\nfatal: too many args for xstrconcat\n", stderr);
1208 fputs ("\nfatal: out of memory\n", stderr);
1214 /* Split a string into fields at DELIM. REPLACEMENT is the character
1215 to replace the delimiter with (normally: '\0' so that each field is
1216 NUL terminated). The caller is responsible for freeing the result.
1217 Note: this function modifies STRING! If you need the original
1218 value, then you should pass a copy to this function.
1220 If malloc fails, this function returns NULL. */
1222 strsplit (char *string, char delim, char replacement, int *count)
1228 /* First, count the number of fields. */
1229 for (t = strchr (string, delim); t; t = strchr (t + 1, delim))
1232 result = xtrycalloc ((fields + 1), sizeof (*result));
1238 for (t = strchr (string, delim); t; t = strchr (t + 1, delim))
1240 result[fields ++] = t + 1;
1251 /* Tokenize STRING using the set of delimiters in DELIM. Leading
1252 * spaces and tabs are removed from all tokens. The caller must xfree
1255 * Returns: A malloced and NULL delimited array with the tokens. On
1256 * memory error NULL is returned and ERRNO is set.
1259 strtokenize (const char *string, const char *delim)
1265 char *p, *px, *pend;
1268 /* Count the number of fields. */
1269 for (fields = 1, s = strpbrk (string, delim); s; s = strpbrk (s + 1, delim))
1271 fields++; /* Add one for the terminating NULL. */
1273 /* Allocate an array for all fields, a terminating NULL, and space
1274 for a copy of the string. */
1275 bytes = fields * sizeof *result;
1276 if (bytes / sizeof *result != fields)
1278 gpg_err_set_errno (ENOMEM);
1281 n = strlen (string) + 1;
1285 gpg_err_set_errno (ENOMEM);
1288 result = xtrymalloc (bytes);
1291 buffer = (char*)(result + fields);
1293 /* Copy and parse the string. */
1294 strcpy (buffer, string);
1295 for (n = 0, p = buffer; (pend = strpbrk (p, delim)); p = pend + 1)
1300 for (px = pend - 1; px >= p && spacep (px); px--)
1306 for (px = p + strlen (p) - 1; px >= p && spacep (px); px--)
1311 assert ((char*)(result + n + 1) == buffer);
1317 /* Split a string into space delimited fields and remove leading and
1318 * trailing spaces from each field. A pointer to each field is stored
1319 * in ARRAY. Stop splitting at ARRAYSIZE fields. The function
1320 * modifies STRING. The number of parsed fields is returned.
1324 * if (split_fields (string, fields, DIM (fields)) < 2)
1325 * return // Not enough args.
1330 split_fields (char *string, char **array, int arraysize)
1335 for (p = string; *p == ' '; p++)
1342 pend = strchr (p, ' ');
1346 for (p = pend; *p == ' '; p++)
1355 /* Split a string into colon delimited fields A pointer to each field
1356 * is stored in ARRAY. Stop splitting at ARRAYSIZE fields. The
1357 * function modifies STRING. The number of parsed fields is returned.
1358 * Note that leading and trailing spaces are not removed from the fields.
1362 * if (split_fields (string, fields, DIM (fields)) < 2)
1363 * return // Not enough args.
1368 split_fields_colon (char *string, char **array, int arraysize)
1379 pend = strchr (p, ':');
1392 /* Version number parsing. */
1394 /* This function parses the first portion of the version number S and
1395 stores it in *NUMBER. On success, this function returns a pointer
1396 into S starting with the first character, which is not part of the
1397 initial number portion; on failure, NULL is returned. */
1399 parse_version_number (const char *s, int *number)
1403 if (*s == '0' && digitp (s+1))
1404 return NULL; /* Leading zeros are not allowed. */
1405 for (; digitp (s); s++)
1411 return val < 0 ? NULL : s;
1415 /* This function breaks up the complete string-representation of the
1416 version number S, which is of the following struture: <major
1417 number>.<minor number>[.<micro number>]<patch level>. The major,
1418 minor, and micro number components will be stored in *MAJOR, *MINOR
1419 and *MICRO. If MICRO is not given 0 is used instead.
1421 On success, the last component, the patch level, will be returned;
1422 in failure, NULL will be returned. */
1424 parse_version_string (const char *s, int *major, int *minor, int *micro)
1426 s = parse_version_number (s, major);
1427 if (!s || *s != '.')
1430 s = parse_version_number (s, minor);
1436 s = parse_version_number (s, micro);
1442 return s; /* Patchlevel. */
1446 /* Compare the version string MY_VERSION to the version string
1447 * REQ_VERSION. Returns -1, 0, or 1 if MY_VERSION is found,
1448 * respectively, to be less than, to match, or be greater than
1449 * REQ_VERSION. This function works for three and two part version
1450 * strings; for a two part version string the micro part is assumed to
1451 * be 0. Patch levels are compared as strings. If a version number
1452 * is invalid INT_MIN is returned. If REQ_VERSION is given as NULL
1453 * the function returns 0 if MY_VERSION is parsable version string. */
1455 compare_version_strings (const char *my_version, const char *req_version)
1457 int my_major, my_minor, my_micro;
1458 int rq_major, rq_minor, rq_micro;
1459 const char *my_patch, *rq_patch;
1465 my_patch = parse_version_string (my_version, &my_major, &my_minor, &my_micro);
1469 return 0; /* MY_VERSION can be parsed. */
1470 rq_patch = parse_version_string (req_version, &rq_major, &rq_minor,&rq_micro);
1474 if (my_major == rq_major)
1476 if (my_minor == rq_minor)
1478 if (my_micro == rq_micro)
1479 result = strcmp (my_patch, rq_patch);
1481 result = my_micro - rq_micro;
1484 result = my_minor - rq_minor;
1487 result = my_major - rq_major;
1489 return !result? 0 : result < 0 ? -1 : 1;
1494 /* Format a string so that it fits within about TARGET_COLS columns.
1495 * TEXT_IN is copied to a new buffer, which is returned. Normally,
1496 * target_cols will be 72 and max_cols is 80. On error NULL is
1497 * returned and ERRNO is set. */
1499 format_text (const char *text_in, int target_cols, int max_cols)
1501 /* const int do_debug = 0; */
1503 /* The character under consideration. */
1505 /* The start of the current line. */
1507 /* The last space that we saw. */
1508 char *last_space = NULL;
1509 int last_space_cols = 0;
1510 int copied_last_space = 0;
1513 text = xtrystrdup (text_in);
1520 /* The number of columns including any trailing space. */
1523 p = p + strcspn (p, "\n ");
1525 /* P now points to the NUL character. */
1526 p = &text[strlen (text)];
1529 /* Pass through any newlines. */
1534 last_space_cols = 0;
1535 copied_last_space = 1;
1539 /* Have a space or a NUL. Note: we don't count the trailing
1541 cols = utf8_charcount (line, (uintptr_t) p - (uintptr_t) line);
1542 if (cols < target_cols)
1545 /* Nothing left to break. */
1549 last_space_cols = cols;
1551 /* Skip any immediately following spaces. If we break:
1552 "... foo bar ..." between "foo" and "bar" then we want:
1553 "... foo\nbar ...", which means that the left space has
1554 to be the first space after foo, not the last space
1561 int cols_with_left_space;
1562 int cols_with_right_space;
1566 cols_with_left_space = last_space_cols;
1567 cols_with_right_space = cols;
1570 /* log_debug ("Breaking: '%.*s'\n", */
1571 /* (int) ((uintptr_t) p - (uintptr_t) line), line); */
1573 /* The number of columns away from TARGET_COLS. We prefer
1574 to underflow than to overflow. */
1575 left_penalty = target_cols - cols_with_left_space;
1576 right_penalty = 2 * (cols_with_right_space - target_cols);
1578 if (cols_with_right_space > max_cols)
1579 /* Add a large penalty for each column that exceeds
1581 right_penalty += 4 * (cols_with_right_space - max_cols);
1584 /* log_debug ("Left space => %d cols (penalty: %d); " */
1585 /* "right space => %d cols (penalty: %d)\n", */
1586 /* cols_with_left_space, left_penalty, */
1587 /* cols_with_right_space, right_penalty); */
1588 if (last_space_cols && left_penalty <= right_penalty)
1590 /* Prefer the left space. */
1592 /* log_debug ("Breaking at left space.\n"); */
1598 /* log_debug ("Breaking at right space.\n"); */
1609 for (spaces = 1; p[spaces] == ' '; spaces ++)
1611 memmove (p, &p[spaces], strlen (&p[spaces]) + 1);
1615 last_space_cols = 0;
1616 copied_last_space = 0;
1620 /* Chop off any trailing space. */
1621 trim_trailing_chars (text, strlen (text), " ");
1622 /* If we inserted the trailing newline, then remove it. */
1623 if (! copied_last_space && *text && text[strlen (text) - 1] == '\n')
1624 text[strlen (text) - 1] = '\0';