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 20090 : 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 20090 : 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 1864 : has_leading_keyword (const char *string, const char *keyword)
92 : {
93 1864 : size_t n = strlen (keyword);
94 :
95 1864 : if (!strncmp (string, keyword, n)
96 764 : && (!string[n] || string[n] == ' ' || string[n] == '\t'))
97 : {
98 764 : string += n;
99 1999 : while (*string == ' ' || *string == '\t')
100 471 : string++;
101 764 : return (char*)string;
102 : }
103 1100 : 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 20092 : 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 20092 : int skip = 1;
416 20092 : char *home_buffer = NULL;
417 : char *name, *home, *p;
418 : int want_abs;
419 :
420 20092 : want_abs = !!(xmode & 2);
421 20092 : xmode &= 1;
422 :
423 20092 : n = strlen (first_part) + 1;
424 20092 : argc = 0;
425 56214 : while ( (argv[argc] = va_arg (arg_ptr, const char *)) )
426 : {
427 16032 : n += strlen (argv[argc]) + 1;
428 16032 : 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 16030 : argc++;
436 : }
437 20090 : n++;
438 :
439 20090 : home = NULL;
440 20090 : 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 20090 : if (xmode)
479 19410 : 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 20090 : if (home)
491 2184 : p = stpcpy (stpcpy (name, home), first_part + skip);
492 : else
493 17906 : p = stpcpy (name, first_part);
494 :
495 20090 : xfree (home_buffer);
496 36058 : for (argc=0; argv[argc]; argc++)
497 : {
498 : /* Avoid a leading double slash if the first part was "/". */
499 15968 : if (!argc && name[0] == '/' && !name[1])
500 0 : p = stpcpy (p, argv[argc]);
501 : else
502 15968 : p = stpcpy (stpcpy (p, "/"), argv[argc]);
503 : }
504 :
505 20090 : 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 20090 : 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 13862 : make_filename (const char *first_part, ... )
579 : {
580 : va_list arg_ptr;
581 : char *result;
582 :
583 13862 : va_start (arg_ptr, first_part);
584 13862 : result = do_make_filename (1, first_part, arg_ptr);
585 13862 : va_end (arg_ptr);
586 13862 : 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 386 : 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 15921 : ascii_strcasecmp( const char *a, const char *b )
814 : {
815 15921 : if (a == b)
816 0 : return 0;
817 :
818 58596 : for (; *a && *b; a++, b++) {
819 55340 : if (*a != *b && ascii_toupper(*a) != ascii_toupper(*b))
820 12665 : break;
821 : }
822 15921 : 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 : }
|