Home | History | Annotate | Download | only in libiberty
      1 /* Concatenate variable number of strings.
      2    Copyright (C) 1991, 1994, 2001, 2011, 2013 Free Software Foundation, Inc.
      3    Written by Fred Fish @ Cygnus Support
      4 
      5 This file is part of the libiberty library.
      6 Libiberty is free software; you can redistribute it and/or
      7 modify it under the terms of the GNU Library General Public
      8 License as published by the Free Software Foundation; either
      9 version 2 of the License, or (at your option) any later version.
     10 
     11 Libiberty is distributed in the hope that it will be useful,
     12 but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14 Library General Public License for more details.
     15 
     16 You should have received a copy of the GNU Library General Public
     17 License along with libiberty; see the file COPYING.LIB.  If
     18 not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
     19 Boston, MA 02110-1301, USA.  */
     20 
     21 
     22 /*
     23 
     24 @deftypefn Extension char* concat (const char *@var{s1}, const char *@var{s2}, @
     25   @dots{}, @code{NULL})
     26 
     27 Concatenate zero or more of strings and return the result in freshly
     28 @code{xmalloc}ed memory.  The argument list is terminated by the first
     29 @code{NULL} pointer encountered.  Pointers to empty strings are ignored.
     30 
     31 @end deftypefn
     32 
     33 */
     34 
     35 
     36 #ifdef HAVE_CONFIG_H
     37 #include "config.h"
     38 #endif
     39 #include "ansidecl.h"
     40 #include "libiberty.h"
     41 #include <sys/types.h>		/* size_t */
     42 
     43 #include <stdarg.h>
     44 
     45 # if HAVE_STRING_H
     46 #  include <string.h>
     47 # else
     48 #  if HAVE_STRINGS_H
     49 #   include <strings.h>
     50 #  endif
     51 # endif
     52 
     53 #if HAVE_STDLIB_H
     54 #include <stdlib.h>
     55 #endif
     56 
     57 static inline unsigned long vconcat_length (const char *, va_list);
     58 static inline unsigned long
     59 vconcat_length (const char *first, va_list args)
     60 {
     61   unsigned long length = 0;
     62   const char *arg;
     63 
     64   for (arg = first; arg ; arg = va_arg (args, const char *))
     65     length += strlen (arg);
     66 
     67   return length;
     68 }
     69 
     70 static inline char *
     71 vconcat_copy (char *dst, const char *first, va_list args)
     72 {
     73   char *end = dst;
     74   const char *arg;
     75 
     76   for (arg = first; arg ; arg = va_arg (args, const char *))
     77     {
     78       unsigned long length = strlen (arg);
     79       memcpy (end, arg, length);
     80       end += length;
     81     }
     82   *end = '\000';
     83 
     84   return dst;
     85 }
     86 
     87 /* @undocumented concat_length */
     88 
     89 unsigned long
     90 concat_length (const char *first, ...)
     91 {
     92   unsigned long length;
     93   va_list args;
     94 
     95   va_start (args, first);
     96   length = vconcat_length (first, args);
     97   va_end (args);
     98 
     99   return length;
    100 }
    101 
    102 /* @undocumented concat_copy */
    103 
    104 char *
    105 concat_copy (char *dst, const char *first, ...)
    106 {
    107   char *save_dst;
    108   va_list args;
    109 
    110   va_start (args, first);
    111   vconcat_copy (dst, first, args);
    112   save_dst = dst; /* With K&R C, dst goes out of scope here.  */
    113   va_end (args);
    114 
    115   return save_dst;
    116 }
    117 
    118 #ifdef __cplusplus
    119 extern "C" {
    120 #endif /* __cplusplus */
    121 char *libiberty_concat_ptr;
    122 #ifdef __cplusplus
    123 }
    124 #endif /* __cplusplus */
    125 
    126 /* @undocumented concat_copy2 */
    127 
    128 char *
    129 concat_copy2 (const char *first, ...)
    130 {
    131   va_list args;
    132   va_start (args, first);
    133   vconcat_copy (libiberty_concat_ptr, first, args);
    134   va_end (args);
    135 
    136   return libiberty_concat_ptr;
    137 }
    138 
    139 char *
    140 concat (const char *first, ...)
    141 {
    142   char *newstr;
    143   va_list args;
    144 
    145   /* First compute the size of the result and get sufficient memory.  */
    146   va_start (args, first);
    147   newstr = XNEWVEC (char, vconcat_length (first, args) + 1);
    148   va_end (args);
    149 
    150   /* Now copy the individual pieces to the result string. */
    151   va_start (args, first);
    152   vconcat_copy (newstr, first, args);
    153   va_end (args);
    154 
    155   return newstr;
    156 }
    157 
    158 /*
    159 
    160 @deftypefn Extension char* reconcat (char *@var{optr}, const char *@var{s1}, @
    161   @dots{}, @code{NULL})
    162 
    163 Same as @code{concat}, except that if @var{optr} is not @code{NULL} it
    164 is freed after the string is created.  This is intended to be useful
    165 when you're extending an existing string or building up a string in a
    166 loop:
    167 
    168 @example
    169   str = reconcat (str, "pre-", str, NULL);
    170 @end example
    171 
    172 @end deftypefn
    173 
    174 */
    175 
    176 char *
    177 reconcat (char *optr, const char *first, ...)
    178 {
    179   char *newstr;
    180   va_list args;
    181 
    182   /* First compute the size of the result and get sufficient memory.  */
    183   va_start (args, first);
    184   newstr = XNEWVEC (char, vconcat_length (first, args) + 1);
    185   va_end (args);
    186 
    187   /* Now copy the individual pieces to the result string. */
    188   va_start (args, first);
    189   vconcat_copy (newstr, first, args);
    190   if (optr) /* Done before VA_CLOSE so optr stays in scope for K&R C.  */
    191     free (optr);
    192   va_end (args);
    193 
    194   return newstr;
    195 }
    196 
    197 #ifdef MAIN
    198 #define NULLP (char *)0
    199 
    200 /* Simple little test driver. */
    201 
    202 #include <stdio.h>
    203 
    204 int
    205 main (void)
    206 {
    207   printf ("\"\" = \"%s\"\n", concat (NULLP));
    208   printf ("\"a\" = \"%s\"\n", concat ("a", NULLP));
    209   printf ("\"ab\" = \"%s\"\n", concat ("a", "b", NULLP));
    210   printf ("\"abc\" = \"%s\"\n", concat ("a", "b", "c", NULLP));
    211   printf ("\"abcd\" = \"%s\"\n", concat ("ab", "cd", NULLP));
    212   printf ("\"abcde\" = \"%s\"\n", concat ("ab", "c", "de", NULLP));
    213   printf ("\"abcdef\" = \"%s\"\n", concat ("", "a", "", "bcd", "ef", NULLP));
    214   return 0;
    215 }
    216 
    217 #endif
    218