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 it and/or modify it
10 * 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] == '%' || (extra && strchr (extra, str[i])))
1058 ptr = xmalloc (i + 2 * j + 1);
1061 ptr = xtrymalloc (i + 2 * j + 1);
1074 else if (*str == '%')
1080 else if (extra && strchr (extra, *str))
1083 ptr[i++] = tohex_lower ((*str>>4)&15);
1084 ptr[i++] = tohex_lower (*str&15);
1095 /* Percent-escape the string STR by replacing colons with '%3a'. If
1096 EXTRA is not NULL all characters in EXTRA are also escaped. This
1097 function terminates the process on memory shortage. */
1099 percent_escape (const char *str, const char *extra)
1101 return do_percent_escape (str, extra, 1);
1104 /* Same as percent_escape but return NULL instead of exiting on memory
1107 try_percent_escape (const char *str, const char *extra)
1109 return do_percent_escape (str, extra, 0);
1115 do_strconcat (const char *s1, va_list arg_ptr)
1117 const char *argv[48];
1124 needed = strlen (s1);
1125 while (((argv[argc] = va_arg (arg_ptr, const char *))))
1127 needed += strlen (argv[argc]);
1128 if (argc >= DIM (argv)-1)
1130 gpg_err_set_errno (EINVAL);
1136 buffer = xtrymalloc (needed);
1139 for (p = buffer, argc=0; argv[argc]; argc++)
1140 p = stpcpy (p, argv[argc]);
1146 /* Concatenate the string S1 with all the following strings up to a
1147 NULL. Returns a malloced buffer with the new string or NULL on a
1148 malloc error or if too many arguments are given. */
1150 strconcat (const char *s1, ...)
1156 result = xtrystrdup ("");
1159 va_start (arg_ptr, s1);
1160 result = do_strconcat (s1, arg_ptr);
1166 /* Same as strconcat but terminate the process with an error message
1167 if something goes wrong. */
1169 xstrconcat (const char *s1, ...)
1175 result = xstrdup ("");
1178 va_start (arg_ptr, s1);
1179 result = do_strconcat (s1, arg_ptr);
1184 if (errno == EINVAL)
1185 fputs ("\nfatal: too many args for xstrconcat\n", stderr);
1187 fputs ("\nfatal: out of memory\n", stderr);
1193 /* Split a string into fields at DELIM. REPLACEMENT is the character
1194 to replace the delimiter with (normally: '\0' so that each field is
1195 NUL terminated). The caller is responsible for freeing the result.
1196 Note: this function modifies STRING! If you need the original
1197 value, then you should pass a copy to this function.
1199 If malloc fails, this function returns NULL. */
1201 strsplit (char *string, char delim, char replacement, int *count)
1207 /* First, count the number of fields. */
1208 for (t = strchr (string, delim); t; t = strchr (t + 1, delim))
1211 result = xtrycalloc ((fields + 1), sizeof (*result));
1217 for (t = strchr (string, delim); t; t = strchr (t + 1, delim))
1219 result[fields ++] = t + 1;
1230 /* Tokenize STRING using the set of delimiters in DELIM. Leading
1231 * spaces and tabs are removed from all tokens. The caller must xfree
1234 * Returns: A malloced and NULL delimited array with the tokens. On
1235 * memory error NULL is returned and ERRNO is set.
1238 strtokenize (const char *string, const char *delim)
1244 char *p, *px, *pend;
1247 /* Count the number of fields. */
1248 for (fields = 1, s = strpbrk (string, delim); s; s = strpbrk (s + 1, delim))
1250 fields++; /* Add one for the terminating NULL. */
1252 /* Allocate an array for all fields, a terminating NULL, and space
1253 for a copy of the string. */
1254 bytes = fields * sizeof *result;
1255 if (bytes / sizeof *result != fields)
1257 gpg_err_set_errno (ENOMEM);
1260 n = strlen (string) + 1;
1264 gpg_err_set_errno (ENOMEM);
1267 result = xtrymalloc (bytes);
1270 buffer = (char*)(result + fields);
1272 /* Copy and parse the string. */
1273 strcpy (buffer, string);
1274 for (n = 0, p = buffer; (pend = strpbrk (p, delim)); p = pend + 1)
1279 for (px = pend - 1; px >= p && spacep (px); px--)
1285 for (px = p + strlen (p) - 1; px >= p && spacep (px); px--)
1290 assert ((char*)(result + n + 1) == buffer);
1296 /* Split a string into space delimited fields and remove leading and
1297 * trailing spaces from each field. A pointer to each field is stored
1298 * in ARRAY. Stop splitting at ARRAYSIZE fields. The function
1299 * modifies STRING. The number of parsed fields is returned.
1303 * if (split_fields (string, fields, DIM (fields)) < 2)
1304 * return // Not enough args.
1309 split_fields (char *string, char **array, int arraysize)
1314 for (p = string; *p == ' '; p++)
1321 pend = strchr (p, ' ');
1325 for (p = pend; *p == ' '; p++)
1335 /* Version number parsing. */
1337 /* This function parses the first portion of the version number S and
1338 stores it in *NUMBER. On success, this function returns a pointer
1339 into S starting with the first character, which is not part of the
1340 initial number portion; on failure, NULL is returned. */
1342 parse_version_number (const char *s, int *number)
1346 if (*s == '0' && digitp (s+1))
1347 return NULL; /* Leading zeros are not allowed. */
1348 for (; digitp (s); s++)
1354 return val < 0 ? NULL : s;
1358 /* This function breaks up the complete string-representation of the
1359 version number S, which is of the following struture: <major
1360 number>.<minor number>[.<micro number>]<patch level>. The major,
1361 minor, and micro number components will be stored in *MAJOR, *MINOR
1362 and *MICRO. If MICRO is not given 0 is used instead.
1364 On success, the last component, the patch level, will be returned;
1365 in failure, NULL will be returned. */
1367 parse_version_string (const char *s, int *major, int *minor, int *micro)
1369 s = parse_version_number (s, major);
1370 if (!s || *s != '.')
1373 s = parse_version_number (s, minor);
1379 s = parse_version_number (s, micro);
1385 return s; /* Patchlevel. */
1389 /* Compare the version string MY_VERSION to the version string
1390 * REQ_VERSION. Returns -1, 0, or 1 if MY_VERSION is found,
1391 * respectively, to be less than, to match, or be greater than
1392 * REQ_VERSION. This function works for three and two part version
1393 * strings; for a two part version string the micro part is assumed to
1394 * be 0. Patch levels are compared as strings. If a version number
1395 * is invalid INT_MIN is returned. If REQ_VERSION is given as NULL
1396 * the function returns 0 if MY_VERSION is parsable version string. */
1398 compare_version_strings (const char *my_version, const char *req_version)
1400 int my_major, my_minor, my_micro;
1401 int rq_major, rq_minor, rq_micro;
1402 const char *my_patch, *rq_patch;
1408 my_patch = parse_version_string (my_version, &my_major, &my_minor, &my_micro);
1412 return 0; /* MY_VERSION can be parsed. */
1413 rq_patch = parse_version_string (req_version, &rq_major, &rq_minor,&rq_micro);
1417 if (my_major == rq_major)
1419 if (my_minor == rq_minor)
1421 if (my_micro == rq_micro)
1422 result = strcmp (my_patch, rq_patch);
1424 result = my_micro - rq_micro;
1427 result = my_minor - rq_minor;
1430 result = my_major - rq_major;
1432 return !result? 0 : result < 0 ? -1 : 1;
1437 /* Format a string so that it fits within about TARGET_COLS columns.
1438 If IN_PLACE is 0, then TEXT is copied to a new buffer, which is
1439 returned. Otherwise, TEXT is modified in place and returned.
1440 Normally, target_cols will be 72 and max_cols is 80. */
1442 format_text (char *text, int in_place, int target_cols, int max_cols)
1444 const int do_debug = 0;
1446 /* The character under consideration. */
1448 /* The start of the current line. */
1450 /* The last space that we saw. */
1451 char *last_space = NULL;
1452 int last_space_cols = 0;
1453 int copied_last_space = 0;
1456 text = xstrdup (text);
1461 /* The number of columns including any trailing space. */
1464 p = p + strcspn (p, "\n ");
1466 /* P now points to the NUL character. */
1467 p = &text[strlen (text)];
1470 /* Pass through any newlines. */
1475 last_space_cols = 0;
1476 copied_last_space = 1;
1480 /* Have a space or a NUL. Note: we don't count the trailing
1482 cols = utf8_charcount (line, (uintptr_t) p - (uintptr_t) line);
1483 if (cols < target_cols)
1486 /* Nothing left to break. */
1490 last_space_cols = cols;
1492 /* Skip any immediately following spaces. If we break:
1493 "... foo bar ..." between "foo" and "bar" then we want:
1494 "... foo\nbar ...", which means that the left space has
1495 to be the first space after foo, not the last space
1502 int cols_with_left_space;
1503 int cols_with_right_space;
1507 cols_with_left_space = last_space_cols;
1508 cols_with_right_space = cols;
1511 log_debug ("Breaking: '%.*s'\n",
1512 (int) ((uintptr_t) p - (uintptr_t) line), line);
1514 /* The number of columns away from TARGET_COLS. We prefer
1515 to underflow than to overflow. */
1516 left_penalty = target_cols - cols_with_left_space;
1517 right_penalty = 2 * (cols_with_right_space - target_cols);
1519 if (cols_with_right_space > max_cols)
1520 /* Add a large penalty for each column that exceeds
1522 right_penalty += 4 * (cols_with_right_space - max_cols);
1525 log_debug ("Left space => %d cols (penalty: %d); right space => %d cols (penalty: %d)\n",
1526 cols_with_left_space, left_penalty,
1527 cols_with_right_space, right_penalty);
1528 if (last_space_cols && left_penalty <= right_penalty)
1529 /* Prefer the left space. */
1532 log_debug ("Breaking at left space.\n");
1538 log_debug ("Breaking at right space.\n");
1549 for (spaces = 1; p[spaces] == ' '; spaces ++)
1551 memmove (p, &p[spaces], strlen (&p[spaces]) + 1);
1555 last_space_cols = 0;
1556 copied_last_space = 0;
1560 /* Chop off any trailing space. */
1561 trim_trailing_chars (text, strlen (text), " ");
1562 /* If we inserted the trailing newline, then remove it. */
1563 if (! copied_last_space && *text && text[strlen (text) - 1] == '\n')
1564 text[strlen (text) - 1] = '\0';