New fucntions strconcat and xstrconcat.
[gnupg.git] / jnlib / stringhelp.c
blobe8a69081f4d04b4069c938e95569f4dabe6d0a73
1 /* stringhelp.c - standard string helper functions
2 * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005,
3 * 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
5 * This file is part of JNLIB.
7 * JNLIB is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 3 of
10 * the License, or (at your option) any later version.
12 * JNLIB is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include <config.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdarg.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #ifdef HAVE_W32_SYSTEM
28 #include <windows.h>
29 #endif
31 #include "libjnlib-config.h"
32 #include "utf8conv.h"
33 #include "stringhelp.h"
36 #define tohex_lower(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'a'))
38 /* Sometimes we want to avoid mixing slashes and backslashes on W32
39 and prefer backslashes. There is usual no problem with mixing
40 them, however a very few W32 API calls can't grok plain slashes.
41 Printing filenames with mixed slashes also looks a bit strange.
42 This function has no effext on POSIX. */
43 static inline char *
44 change_slashes (char *name)
46 #ifdef HAVE_DRIVE_LETTERS
47 char *p;
49 if (strchr (name, '\\'))
51 for (p=name; *p; p++)
52 if (*p == '/')
53 *p = '\\';
55 #endif /*HAVE_DRIVE_LETTERS*/
56 return name;
61 * Look for the substring SUB in buffer and return a pointer to that
62 * substring in BUFFER or NULL if not found.
63 * Comparison is case-insensitive.
65 const char *
66 memistr (const void *buffer, size_t buflen, const char *sub)
68 const unsigned char *buf = buffer;
69 const unsigned char *t = (const unsigned char *)buffer;
70 const unsigned char *s = (const unsigned char *)sub;
71 size_t n = buflen;
73 for ( ; n ; t++, n-- )
75 if ( toupper (*t) == toupper (*s) )
77 for ( buf=t++, buflen = n--, s++;
78 n && toupper (*t) == toupper (*s); t++, s++, n-- )
80 if (!*s)
81 return (const char*)buf;
82 t = buf;
83 s = (const unsigned char *)sub ;
84 n = buflen;
87 return NULL;
90 const char *
91 ascii_memistr ( const void *buffer, size_t buflen, const char *sub )
93 const unsigned char *buf = buffer;
94 const unsigned char *t = (const unsigned char *)buf;
95 const unsigned char *s = (const unsigned char *)sub;
96 size_t n = buflen;
98 for ( ; n ; t++, n-- )
100 if (ascii_toupper (*t) == ascii_toupper (*s) )
102 for ( buf=t++, buflen = n--, s++;
103 n && ascii_toupper (*t) == ascii_toupper (*s); t++, s++, n-- )
105 if (!*s)
106 return (const char*)buf;
107 t = (const unsigned char *)buf;
108 s = (const unsigned char *)sub ;
109 n = buflen;
112 return NULL;
115 /* This function is similar to strncpy(). However it won't copy more
116 than N - 1 characters and makes sure that a '\0' is appended. With
117 N given as 0, nothing will happen. With DEST given as NULL, memory
118 will be allocated using jnlib_xmalloc (i.e. if it runs out of core
119 the function terminates). Returns DES or a pointer to the
120 allocated memory.
122 char *
123 mem2str( char *dest , const void *src , size_t n )
125 char *d;
126 const char *s;
128 if( n ) {
129 if( !dest )
130 dest = jnlib_xmalloc( n ) ;
131 d = dest;
132 s = src ;
133 for(n--; n && *s; n-- )
134 *d++ = *s++;
135 *d = '\0' ;
138 return dest ;
142 /****************
143 * remove leading and trailing white spaces
145 char *
146 trim_spaces( char *str )
148 char *string, *p, *mark;
150 string = str;
151 /* find first non space character */
152 for( p=string; *p && isspace( *(byte*)p ) ; p++ )
154 /* move characters */
155 for( (mark = NULL); (*string = *p); string++, p++ )
156 if( isspace( *(byte*)p ) ) {
157 if( !mark )
158 mark = string ;
160 else
161 mark = NULL ;
162 if( mark )
163 *mark = '\0' ; /* remove trailing spaces */
165 return str ;
168 /****************
169 * remove trailing white spaces
171 char *
172 trim_trailing_spaces( char *string )
174 char *p, *mark;
176 for( mark = NULL, p = string; *p; p++ ) {
177 if( isspace( *(byte*)p ) ) {
178 if( !mark )
179 mark = p;
181 else
182 mark = NULL;
184 if( mark )
185 *mark = '\0' ;
187 return string ;
191 unsigned
192 trim_trailing_chars( byte *line, unsigned len, const char *trimchars )
194 byte *p, *mark;
195 unsigned n;
197 for(mark=NULL, p=line, n=0; n < len; n++, p++ ) {
198 if( strchr(trimchars, *p ) ) {
199 if( !mark )
200 mark = p;
202 else
203 mark = NULL;
206 if( mark ) {
207 *mark = 0;
208 return mark - line;
210 return len;
213 /****************
214 * remove trailing white spaces and return the length of the buffer
216 unsigned
217 trim_trailing_ws( byte *line, unsigned len )
219 return trim_trailing_chars( line, len, " \t\r\n" );
222 size_t
223 length_sans_trailing_chars (const unsigned char *line, size_t len,
224 const char *trimchars )
226 const unsigned char *p, *mark;
227 size_t n;
229 for( mark=NULL, p=line, n=0; n < len; n++, p++ )
231 if (strchr (trimchars, *p ))
233 if( !mark )
234 mark = p;
236 else
237 mark = NULL;
240 if (mark)
241 return mark - line;
242 return len;
246 * Return the length of line ignoring trailing white-space.
248 size_t
249 length_sans_trailing_ws (const unsigned char *line, size_t len)
251 return length_sans_trailing_chars (line, len, " \t\r\n");
257 * Extract from a given path the filename component. This function
258 * terminates the process on memory shortage.
260 char *
261 make_basename(const char *filepath, const char *inputpath)
263 #ifdef __riscos__
264 return riscos_make_basename(filepath, inputpath);
265 #else
266 char *p;
268 (void)inputpath; /* Only required for riscos. */
270 if ( !(p=strrchr(filepath, '/')) )
271 #ifdef HAVE_DRIVE_LETTERS
272 if ( !(p=strrchr(filepath, '\\')) )
273 if ( !(p=strrchr(filepath, ':')) )
274 #endif
276 return jnlib_xstrdup(filepath);
279 return jnlib_xstrdup(p+1);
280 #endif
286 * Extract from a given filename the path prepended to it. If there
287 * isn't a path prepended to the filename, a dot is returned ('.').
288 * This function terminates the process on memory shortage.
290 char *
291 make_dirname(const char *filepath)
293 char *dirname;
294 int dirname_length;
295 char *p;
297 if ( !(p=strrchr(filepath, '/')) )
298 #ifdef HAVE_DRIVE_LETTERS
299 if ( !(p=strrchr(filepath, '\\')) )
300 if ( !(p=strrchr(filepath, ':')) )
301 #endif
303 return jnlib_xstrdup(".");
306 dirname_length = p-filepath;
307 dirname = jnlib_xmalloc(dirname_length+1);
308 strncpy(dirname, filepath, dirname_length);
309 dirname[dirname_length] = 0;
311 return dirname;
316 /* Implementation of make_filename and make_filename_try. We need to
317 use macros here to avoid the use of the sometimes problematic
318 va_copy function which is not available on all systems. */
319 #define MAKE_FILENAME_PART1 \
320 va_list arg_ptr; \
321 size_t n; \
322 const char *s; \
323 char *name, *home, *p; \
325 va_start (arg_ptr, first_part); \
326 n = strlen (first_part) + 1; \
327 while ( (s = va_arg (arg_ptr, const char *)) ) \
328 n += strlen(s) + 1; \
329 va_end(arg_ptr); \
331 home = NULL; \
332 if ( *first_part == '~' && first_part[1] == '/' \
333 && (home = getenv("HOME")) && *home ) \
334 n += strlen (home);
336 #define MAKE_FILENAME_PART2 \
337 p = (home \
338 ? stpcpy (stpcpy (name,home), first_part + 1)\
339 : stpcpy(name, first_part)); \
341 va_start (arg_ptr, first_part); \
342 while ( (s = va_arg(arg_ptr, const char *)) ) \
343 p = stpcpy (stpcpy (p,"/"), s); \
344 va_end(arg_ptr); \
345 return change_slashes (name);
348 /* Construct a filename from the NULL terminated list of parts. Tilde
349 expansion is done here. This function terminates the process on
350 memory shortage. */
351 char *
352 make_filename (const char *first_part, ... )
354 MAKE_FILENAME_PART1
355 name = jnlib_xmalloc (n);
356 MAKE_FILENAME_PART2
359 /* Construct a filename from the NULL terminated list of parts. Tilde
360 expansion is done here. This function may return NULL on error. */
361 char *
362 make_filename_try (const char *first_part, ... )
364 MAKE_FILENAME_PART1
365 name = jnlib_malloc (n);
366 if (!name)
367 return NULL;
368 MAKE_FILENAME_PART2
370 #undef MAKE_FILENAME_PART1
371 #undef MAKE_FILENAME_PART2
375 /* Compare whether the filenames are identical. This is a
376 special version of strcmp() taking the semantics of filenames in
377 account. Note that this function works only on the supplied names
378 without considereing any context like the current directory. See
379 also same_file_p(). */
381 compare_filenames (const char *a, const char *b)
383 #ifdef HAVE_DRIVE_LETTERS
384 for ( ; *a && *b; a++, b++ )
386 if (*a != *b
387 && (toupper (*(const unsigned char*)a)
388 != toupper (*(const unsigned char*)b) )
389 && !((*a == '/' && *b == '\\') || (*a == '\\' && *b == '/')))
390 break;
392 if ((*a == '/' && *b == '\\') || (*a == '\\' && *b == '/'))
393 return 0;
394 else
395 return (toupper (*(const unsigned char*)a)
396 - toupper (*(const unsigned char*)b));
397 #else
398 return strcmp(a,b);
399 #endif
403 /* Convert 2 hex characters at S to a byte value. Return this value
404 or -1 if there is an error. */
406 hextobyte (const char *s)
408 int c;
410 if ( *s >= '0' && *s <= '9' )
411 c = 16 * (*s - '0');
412 else if ( *s >= 'A' && *s <= 'F' )
413 c = 16 * (10 + *s - 'A');
414 else if ( *s >= 'a' && *s <= 'f' )
415 c = 16 * (10 + *s - 'a');
416 else
417 return -1;
418 s++;
419 if ( *s >= '0' && *s <= '9' )
420 c += *s - '0';
421 else if ( *s >= 'A' && *s <= 'F' )
422 c += 10 + *s - 'A';
423 else if ( *s >= 'a' && *s <= 'f' )
424 c += 10 + *s - 'a';
425 else
426 return -1;
427 return c;
431 /* Print a BUFFER to stream FP while replacing all control characters
432 and the characters DELIM and DELIM2 with standard C escape
433 sequences. Returns the number of characters printed. */
434 size_t
435 print_sanitized_buffer2 (FILE *fp, const void *buffer, size_t length,
436 int delim, int delim2)
438 const unsigned char *p = buffer;
439 size_t count = 0;
441 for (; length; length--, p++, count++)
443 if (*p < 0x20
444 || *p == 0x7f
445 || *p == delim
446 || *p == delim2
447 || ((delim || delim2) && *p=='\\'))
449 putc ('\\', fp);
450 count++;
451 if (*p == '\n')
453 putc ('n', fp);
454 count++;
456 else if (*p == '\r')
458 putc ('r', fp);
459 count++;
461 else if (*p == '\f')
463 putc ('f', fp);
464 count++;
466 else if (*p == '\v')
468 putc ('v', fp);
469 count++;
471 else if (*p == '\b')
473 putc ('b', fp);
474 count++;
476 else if (!*p)
478 putc('0', fp);
479 count++;
481 else
483 fprintf (fp, "x%02x", *p);
484 count += 3;
487 else
489 putc (*p, fp);
490 count++;
494 return count;
497 /* Same as print_sanitized_buffer2 but with just one delimiter. */
498 size_t
499 print_sanitized_buffer (FILE *fp, const void *buffer, size_t length,
500 int delim)
502 return print_sanitized_buffer2 (fp, buffer, length, delim, 0);
506 size_t
507 print_sanitized_utf8_buffer (FILE *fp, const void *buffer,
508 size_t length, int delim)
510 const char *p = buffer;
511 size_t i;
513 /* We can handle plain ascii simpler, so check for it first. */
514 for (i=0; i < length; i++ )
516 if ( (p[i] & 0x80) )
517 break;
519 if (i < length)
521 char *buf = utf8_to_native (p, length, delim);
522 /*(utf8 conversion already does the control character quoting)*/
523 i = strlen (buf);
524 fputs (buf, fp);
525 jnlib_free (buf);
526 return i;
528 else
529 return print_sanitized_buffer (fp, p, length, delim);
533 size_t
534 print_sanitized_string2 (FILE *fp, const char *string, int delim, int delim2)
536 return string? print_sanitized_buffer2 (fp, string, strlen (string),
537 delim, delim2):0;
540 size_t
541 print_sanitized_string (FILE *fp, const char *string, int delim)
543 return string? print_sanitized_buffer (fp, string, strlen (string), delim):0;
546 size_t
547 print_sanitized_utf8_string (FILE *fp, const char *string, int delim)
549 return string? print_sanitized_utf8_buffer (fp,
550 string, strlen (string),
551 delim) : 0;
554 /* Create a string from the buffer P_ARG of length N which is suitable
555 for printing. Caller must release the created string using xfree.
556 This function terminates the process on memory shortage. */
557 char *
558 sanitize_buffer (const void *p_arg, size_t n, int delim)
560 const unsigned char *p = p_arg;
561 size_t save_n, buflen;
562 const unsigned char *save_p;
563 char *buffer, *d;
565 /* First count length. */
566 for (save_n = n, save_p = p, buflen=1 ; n; n--, p++ )
568 if ( *p < 0x20 || *p == 0x7f || *p == delim || (delim && *p=='\\'))
570 if ( *p=='\n' || *p=='\r' || *p=='\f'
571 || *p=='\v' || *p=='\b' || !*p )
572 buflen += 2;
573 else
574 buflen += 5;
576 else
577 buflen++;
579 p = save_p;
580 n = save_n;
581 /* And now make the string */
582 d = buffer = jnlib_xmalloc( buflen );
583 for ( ; n; n--, p++ )
585 if (*p < 0x20 || *p == 0x7f || *p == delim || (delim && *p=='\\')) {
586 *d++ = '\\';
587 if( *p == '\n' )
588 *d++ = 'n';
589 else if( *p == '\r' )
590 *d++ = 'r';
591 else if( *p == '\f' )
592 *d++ = 'f';
593 else if( *p == '\v' )
594 *d++ = 'v';
595 else if( *p == '\b' )
596 *d++ = 'b';
597 else if( !*p )
598 *d++ = '0';
599 else {
600 sprintf(d, "x%02x", *p );
601 d += 3;
604 else
605 *d++ = *p;
607 *d = 0;
608 return buffer;
612 /* Given a string containing an UTF-8 encoded text, return the number
613 of characters in this string. It differs from strlen in that it
614 only counts complete UTF-8 characters. Note, that this function
615 does not take combined characters into account. */
616 size_t
617 utf8_charcount (const char *s)
619 size_t n;
621 for (n=0; *s; s++)
622 if ( (*s&0xc0) != 0x80 ) /* Exclude continuation bytes: 10xxxxxx */
623 n++;
625 return n;
629 /****************************************************
630 ********** W32 specific functions ****************
631 ****************************************************/
633 #ifdef HAVE_W32_SYSTEM
634 const char *
635 w32_strerror (int ec)
637 static char strerr[256];
639 if (ec == -1)
640 ec = (int)GetLastError ();
641 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec,
642 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
643 strerr, DIM (strerr)-1, NULL);
644 return strerr;
646 #endif /*HAVE_W32_SYSTEM*/
649 /****************************************************
650 ******** Locale insensitive ctype functions ********
651 ****************************************************/
652 /* FIXME: replace them by a table lookup and macros */
654 ascii_isupper (int c)
656 return c >= 'A' && c <= 'Z';
660 ascii_islower (int c)
662 return c >= 'a' && c <= 'z';
665 int
666 ascii_toupper (int c)
668 if (c >= 'a' && c <= 'z')
669 c &= ~0x20;
670 return c;
673 int
674 ascii_tolower (int c)
676 if (c >= 'A' && c <= 'Z')
677 c |= 0x20;
678 return c;
683 ascii_strcasecmp( const char *a, const char *b )
685 if (a == b)
686 return 0;
688 for (; *a && *b; a++, b++) {
689 if (*a != *b && ascii_toupper(*a) != ascii_toupper(*b))
690 break;
692 return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
695 int
696 ascii_strncasecmp (const char *a, const char *b, size_t n)
698 const unsigned char *p1 = (const unsigned char *)a;
699 const unsigned char *p2 = (const unsigned char *)b;
700 unsigned char c1, c2;
702 if (p1 == p2 || !n )
703 return 0;
707 c1 = ascii_tolower (*p1);
708 c2 = ascii_tolower (*p2);
710 if ( !--n || c1 == '\0')
711 break;
713 ++p1;
714 ++p2;
716 while (c1 == c2);
718 return c1 - c2;
723 ascii_memcasecmp (const void *a_arg, const void *b_arg, size_t n )
725 const char *a = a_arg;
726 const char *b = b_arg;
728 if (a == b)
729 return 0;
730 for ( ; n; n--, a++, b++ )
732 if( *a != *b && ascii_toupper (*a) != ascii_toupper (*b) )
733 return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
735 return 0;
739 ascii_strcmp( const char *a, const char *b )
741 if (a == b)
742 return 0;
744 for (; *a && *b; a++, b++) {
745 if (*a != *b )
746 break;
748 return *a == *b? 0 : (*(signed char *)a - *(signed char *)b);
752 void *
753 ascii_memcasemem (const void *haystack, size_t nhaystack,
754 const void *needle, size_t nneedle)
757 if (!nneedle)
758 return (void*)haystack; /* finding an empty needle is really easy */
759 if (nneedle <= nhaystack)
761 const char *a = haystack;
762 const char *b = a + nhaystack - nneedle;
764 for (; a <= b; a++)
766 if ( !ascii_memcasecmp (a, needle, nneedle) )
767 return (void *)a;
770 return NULL;
773 /*********************************************
774 ********** missing string functions *********
775 *********************************************/
777 #ifndef HAVE_STPCPY
778 char *
779 stpcpy(char *a,const char *b)
781 while( *b )
782 *a++ = *b++;
783 *a = 0;
785 return (char*)a;
787 #endif
789 #ifndef HAVE_STRSEP
790 /* Code taken from glibc-2.2.1/sysdeps/generic/strsep.c. */
791 char *
792 strsep (char **stringp, const char *delim)
794 char *begin, *end;
796 begin = *stringp;
797 if (begin == NULL)
798 return NULL;
800 /* A frequent case is when the delimiter string contains only one
801 character. Here we don't need to call the expensive `strpbrk'
802 function and instead work using `strchr'. */
803 if (delim[0] == '\0' || delim[1] == '\0')
805 char ch = delim[0];
807 if (ch == '\0')
808 end = NULL;
809 else
811 if (*begin == ch)
812 end = begin;
813 else if (*begin == '\0')
814 end = NULL;
815 else
816 end = strchr (begin + 1, ch);
819 else
820 /* Find the end of the token. */
821 end = strpbrk (begin, delim);
823 if (end)
825 /* Terminate the token and set *STRINGP past NUL character. */
826 *end++ = '\0';
827 *stringp = end;
829 else
830 /* No more delimiters; this is the last token. */
831 *stringp = NULL;
833 return begin;
835 #endif /*HAVE_STRSEP*/
838 #ifndef HAVE_STRLWR
839 char *
840 strlwr(char *s)
842 char *p;
843 for(p=s; *p; p++ )
844 *p = tolower(*p);
845 return s;
847 #endif
850 #ifndef HAVE_STRCASECMP
852 strcasecmp( const char *a, const char *b )
854 for( ; *a && *b; a++, b++ ) {
855 if( *a != *b && toupper(*a) != toupper(*b) )
856 break;
858 return *(const byte*)a - *(const byte*)b;
860 #endif
863 /****************
864 * mingw32/cpd has a memicmp()
866 #ifndef HAVE_MEMICMP
868 memicmp( const char *a, const char *b, size_t n )
870 for( ; n; n--, a++, b++ )
871 if( *a != *b && toupper(*(const byte*)a) != toupper(*(const byte*)b) )
872 return *(const byte *)a - *(const byte*)b;
873 return 0;
875 #endif
878 #ifndef HAVE_MEMRCHR
879 void *
880 memrchr (const void *buffer, int c, size_t n)
882 const unsigned char *p = buffer;
884 for (p += n; n ; n--)
885 if (*--p == c)
886 return (void *)p;
887 return NULL;
889 #endif /*HAVE_MEMRCHR*/
892 /* Percent-escape the string STR by replacing colons with '%3a'. If
893 EXTRA is not NULL all characters in EXTRA are also escaped. */
894 static char *
895 do_percent_escape (const char *str, const char *extra, int die)
897 int i, j;
898 char *ptr;
900 if (!str)
901 return NULL;
903 for (i=j=0; str[i]; i++)
904 if (str[i] == ':' || str[i] == '%' || (extra && strchr (extra, str[i])))
905 j++;
906 if (die)
907 ptr = jnlib_xmalloc (i + 2 * j + 1);
908 else
910 ptr = jnlib_malloc (i + 2 * j + 1);
911 if (!ptr)
912 return NULL;
914 i = 0;
915 while (*str)
917 if (*str == ':')
919 ptr[i++] = '%';
920 ptr[i++] = '3';
921 ptr[i++] = 'a';
923 else if (*str == '%')
925 ptr[i++] = '%';
926 ptr[i++] = '2';
927 ptr[i++] = '5';
929 else if (extra && strchr (extra, *str))
931 ptr[i++] = '%';
932 ptr[i++] = tohex_lower ((*str>>4)&15);
933 ptr[i++] = tohex_lower (*str&15);
935 else
936 ptr[i++] = *str;
937 str++;
939 ptr[i] = '\0';
941 return ptr;
944 /* Percent-escape the string STR by replacing colons with '%3a'. If
945 EXTRA is not NULL all characters in EXTRA are also escaped. This
946 function terminates the process on memory shortage. */
947 char *
948 percent_escape (const char *str, const char *extra)
950 return do_percent_escape (str, extra, 1);
953 /* Same as percent_escape but return NULL instead of exiting on memory
954 error. */
955 char *
956 try_percent_escape (const char *str, const char *extra)
958 return do_percent_escape (str, extra, 0);
963 static char *
964 do_strconcat (const char *s1, va_list arg_ptr)
966 const char *argv[48];
967 size_t argc;
968 size_t needed;
969 char *buffer, *p;
971 argc = 0;
972 argv[argc++] = s1;
973 needed = strlen (s1);
974 while (((argv[argc] = va_arg (arg_ptr, const char *))))
976 needed += strlen (argv[argc]);
977 if (argc >= DIM (argv)-1)
979 errno = EINVAL;
980 return NULL;
982 argc++;
984 needed++;
985 buffer = jnlib_malloc (needed);
986 if (buffer)
988 for (p = buffer, argc=0; argv[argc]; argc++)
989 p = stpcpy (p, argv[argc]);
991 return buffer;
995 /* Concatenate the string S1 with all the following strings up to a
996 NULL. Returns a malloced buffer with the new string or NULL on a
997 malloc error or if too many arguments are given. */
998 char *
999 strconcat (const char *s1, ...)
1001 va_list arg_ptr;
1002 char *result;
1004 if (!s1)
1005 result = jnlib_strdup ("");
1006 else
1008 va_start (arg_ptr, s1);
1009 result = do_strconcat (s1, arg_ptr);
1010 va_end (arg_ptr);
1012 return result;
1015 /* Same as strconcat but terminate the process with an error message
1016 if something goes wrong. */
1017 char *
1018 xstrconcat (const char *s1, ...)
1020 va_list arg_ptr;
1021 char *result;
1023 if (!s1)
1024 result = jnlib_xstrdup ("");
1025 else
1027 va_start (arg_ptr, s1);
1028 result = do_strconcat (s1, arg_ptr);
1029 va_end (arg_ptr);
1031 if (!result)
1033 if (errno == EINVAL)
1034 fputs ("\nfatal: too many args for xstrconcat\n", stderr);
1035 else
1036 fputs ("\nfatal: out of memory\n", stderr);
1037 exit (2);
1039 return result;