New fucntions strconcat and xstrconcat.

This commit is contained in:
Werner Koch 2009-08-25 20:19:37 +00:00
parent fa4a237b6c
commit 24e5a68f9e
5 changed files with 260 additions and 2 deletions

View File

@ -1,3 +1,12 @@
2009-08-25 Werner Koch <wk@g10code.com>
* stringhelp.c: Include errno.h.
(do_strconcat): New.
(strconcat, xstrconcat): New.
* types.h (GNUPG_GCC_A_SENTINEL): New.
* t-stringhelp.c (test_strconcat, test_xstrconcat): New.
(main): Run them.
2009-07-07 Werner Koch <wk@g10code.com>
* stringhelp.c (make_filename_try): Use jnlib_malloc.

View File

@ -1,6 +1,6 @@
/* stringhelp.c - standard string helper functions
* Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005,
* 2006, 2007, 2008 Free Software Foundation, Inc.
* 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
*
* This file is part of JNLIB.
*
@ -23,6 +23,7 @@
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include <errno.h>
#ifdef HAVE_W32_SYSTEM
#include <windows.h>
#endif
@ -956,3 +957,85 @@ try_percent_escape (const char *str, const char *extra)
{
return do_percent_escape (str, extra, 0);
}
static char *
do_strconcat (const char *s1, va_list arg_ptr)
{
const char *argv[48];
size_t argc;
size_t needed;
char *buffer, *p;
argc = 0;
argv[argc++] = s1;
needed = strlen (s1);
while (((argv[argc] = va_arg (arg_ptr, const char *))))
{
needed += strlen (argv[argc]);
if (argc >= DIM (argv)-1)
{
errno = EINVAL;
return NULL;
}
argc++;
}
needed++;
buffer = jnlib_malloc (needed);
if (buffer)
{
for (p = buffer, argc=0; argv[argc]; argc++)
p = stpcpy (p, argv[argc]);
}
return buffer;
}
/* Concatenate the string S1 with all the following strings up to a
NULL. Returns a malloced buffer with the new string or NULL on a
malloc error or if too many arguments are given. */
char *
strconcat (const char *s1, ...)
{
va_list arg_ptr;
char *result;
if (!s1)
result = jnlib_strdup ("");
else
{
va_start (arg_ptr, s1);
result = do_strconcat (s1, arg_ptr);
va_end (arg_ptr);
}
return result;
}
/* Same as strconcat but terminate the process with an error message
if something goes wrong. */
char *
xstrconcat (const char *s1, ...)
{
va_list arg_ptr;
char *result;
if (!s1)
result = jnlib_xstrdup ("");
else
{
va_start (arg_ptr, s1);
result = do_strconcat (s1, arg_ptr);
va_end (arg_ptr);
}
if (!result)
{
if (errno == EINVAL)
fputs ("\nfatal: too many args for xstrconcat\n", stderr);
else
fputs ("\nfatal: out of memory\n", stderr);
exit (2);
}
return result;
}

View File

@ -1,6 +1,6 @@
/* stringhelp.h
* Copyright (C) 1998, 1999, 2000, 2001, 2003,
* 2006, 2007 Free Software Foundation, Inc.
* 2006, 2007, 2009 Free Software Foundation, Inc.
*
* This file is part of JNLIB.
*
@ -124,4 +124,13 @@ char *percent_escape (const char *str, const char *extra);
char *try_percent_escape (const char *str, const char *extra);
/* Concatenate the string S1 with all the following strings up to a
NULL. Returns a malloced buffer with the new string or NULL on a
malloc error or if too many arguments are given. */
char *strconcat (const char *s1, ...) GNUPG_GCC_A_SENTINEL(0);
/* Ditto, but die on error. */
char *xstrconcat (const char *s1, ...) GNUPG_GCC_A_SENTINEL(0);
#endif /*LIBJNLIB_STRINGHELP_H*/

View File

@ -21,6 +21,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "stringhelp.h"
@ -118,6 +119,148 @@ test_compare_filenames (void)
}
static void
test_strconcat (void)
{
char *out;
out = strconcat ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", "3", "4", "5", "6", "7", NULL);
if (!out)
fail (0);
else
xfree (out);
out = strconcat ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", "3", "4", "5", "6", "7", "8", NULL);
if (out)
fail (0);
else if (errno != EINVAL)
fail (0);
out = strconcat ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", "3", "4", "5", "6", "7", "8", "9", NULL);
if (out)
fail (0);
else if (errno != EINVAL)
fail (0);
#if __GNUC__ < 4 /* gcc 4.0 has a sentinel attribute. */
out = strconcat (NULL);
if (!out || *out)
fail (1);
#endif
out = strconcat (NULL, NULL);
if (!out || *out)
fail (1);
out = strconcat ("", NULL);
if (!out || *out)
fail (1);
xfree (out);
out = strconcat ("", "", NULL);
if (!out || *out)
fail (2);
xfree (out);
out = strconcat ("a", "b", NULL);
if (!out || strcmp (out, "ab"))
fail (3);
xfree (out);
out = strconcat ("a", "b", "c", NULL);
if (!out || strcmp (out, "abc"))
fail (3);
xfree (out);
out = strconcat ("a", "b", "cc", NULL);
if (!out || strcmp (out, "abcc"))
fail (4);
xfree (out);
out = strconcat ("a1", "b1", "c1", NULL);
if (!out || strcmp (out, "a1b1c1"))
fail (4);
xfree (out);
out = strconcat ("", " long b ", "", "--even-longer--", NULL);
if (!out || strcmp (out, " long b --even-longer--"))
fail (5);
xfree (out);
out = strconcat ("", " long b ", "", "--even-longer--", NULL);
if (!out || strcmp (out, " long b --even-longer--"))
fail (5);
xfree (out);
}
static void
test_xstrconcat (void)
{
char *out;
out = xstrconcat ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", "3", "4", "5", "6", "7", NULL);
if (!out)
fail (0);
#if __GNUC__ < 4 /* gcc 4.0 has a sentinel attribute. */
out = xstrconcat (NULL);
if (!out)
fail (1);
#endif
out = xstrconcat (NULL, NULL);
if (!out)
fail (1);
out = xstrconcat ("", NULL);
if (!out || *out)
fail (1);
xfree (out);
out = xstrconcat ("", "", NULL);
if (!out || *out)
fail (2);
xfree (out);
out = xstrconcat ("a", "b", NULL);
if (!out || strcmp (out, "ab"))
fail (3);
xfree (out);
out = xstrconcat ("a", "b", "c", NULL);
if (!out || strcmp (out, "abc"))
fail (3);
xfree (out);
out = xstrconcat ("a", "b", "cc", NULL);
if (!out || strcmp (out, "abcc"))
fail (4);
xfree (out);
out = xstrconcat ("a1", "b1", "c1", NULL);
if (!out || strcmp (out, "a1b1c1"))
fail (4);
xfree (out);
out = xstrconcat ("", " long b ", "", "--even-longer--", NULL);
if (!out || strcmp (out, " long b --even-longer--"))
fail (5);
xfree (out);
out = xstrconcat ("", " long b ", "", "--even-longer--", NULL);
if (!out || strcmp (out, " long b --even-longer--"))
fail (5);
xfree (out);
}
int
main (int argc, char **argv)
{
@ -126,6 +269,8 @@ main (int argc, char **argv)
test_percent_escape ();
test_compare_filenames ();
test_strconcat ();
test_xstrconcat ();
return 0;
}

View File

@ -99,4 +99,16 @@
# endif
#endif
/* Some GCC attributes. Note that we use also define some in
mischelp.h, but this header and types.h are not always included.
Should eventually be put into one file (e.g. nlib-common.h). */
#if __GNUC__ >= 4
# define GNUPG_GCC_A_SENTINEL(a) __attribute__ ((sentinel(a)))
#else
# define GNUPG_GCC_A_SENTINEL(a)
#endif
#endif /*LIBJNLIB_TYPES_H*/