1 /* $Id$
2  *  Provides funstions to operate dinamically allocated strings.
3 
4  * Copyright (C) 1997-2000
5  *
6  * Kolya Nesterov
7  *
8  * Fido:     2:463/567
9  * Kiev, Ukraine
10  *
11  *  Latest version may be foind on http://husky.sourceforge.net
12  *
13  *
14  * HUSKYLIB: common defines, types and functions for HUSKY
15  *
16  * This is part of The HUSKY Fidonet Software project:
17  * see http://husky.sourceforge.net for details
18  *
19  *
20  * HUSKYLIB is free software; you can redistribute it and/or
21  * modify it under the terms of the GNU Lesser General Public
22  * License as published by the Free Software Foundation; either
23  * version 2 of the License, or (at your option) any later version.
24  *
25  * HUSKYLIB is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
28  * General Public License for more details.
29  *
30  * You should have received a copy of the GNU Lesser General Public
31  * License along with this library; see file COPYING. If not, write to the
32  * Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33  *
34  * See also http://www.gnu.org, license may be found here.
35  */
36 
37 /* standard headers */
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <stdarg.h>
41 #include <string.h>
42 
43 
44 /* huskylib: compiler.h */
45 #include <compiler.h>
46 
47 /* huskylib headers */
48 #define DLLEXPORT
49 #include <huskyext.h>
50 
51 /* huskylib headers */
52 #include <memory.h>
53 #include <xstr.h>
54 
55 
56 /***  Declarations & defines  ***********************************************/
57 
58 #if defined(VSPRINTF_ONLY)
59 #undef HAS_vsnprintf
60 #undef HAS_vasprintf
61 #endif
62 
63 #define N_PRINTFBUF     1024
64 
65 /***  Implementation  *******************************************************/
66 
xstralloc(char ** s,size_t add)67  char *xstralloc(char **s, size_t add)
68 {
69     int n;
70     if (*s == NULL) {
71         *s = smalloc(add + 1); **s = '\0'; n = 0;
72     } else {
73         *s = srealloc(*s, (n = strlen(*s)) + add + 1);
74     };
75     if (*s == NULL) {
76 	fprintf(stderr, "out of memory");
77 	abort();
78     }
79     return *s + n;
80 }
81 
xstrcat(char ** s,const char * add)82  char *xstrcat(char **s, const char *add)
83 {
84 	if(add == NULL)
85 		return *s;
86     return strcat(xstralloc(s, strlen(add)), add);
87 }
88 
xstrcpy(char ** s,const char * add)89  char *xstrcpy(char **s, const char *add)
90 {
91     nfree(*s);
92     return xstrcat(s, add);
93 }
94 
95 
xstrscat(char ** s,...)96  char *xstrscat(char **s, ...)
97 {
98     va_list	ap;
99     char	*q, *p;
100     int	ncat;
101     for (va_start(ap, s), ncat = 0; (p = va_arg(ap, char *)) != NULLP; )
102 	    ncat += strlen(p);
103 	va_end(ap);
104     p = xstralloc(s, ncat);
105     for (va_start(ap, s); (q = va_arg(ap, char *)) != NULLP; )
106 	    p = strcat(p, q);
107 	va_end(ap);
108     return p;
109 }
110 
xscatprintf(char ** s,const char * format,...)111  int xscatprintf(char **s, const char *format, ...)
112 {
113     va_list ap;
114 #if defined(HAS_vasprintf)
115     char *addline;
116 #elif defined(HAS_vsnprintf)
117     char *addline;
118     int  nmax;
119 #else
120     char addline[N_PRINTFBUF];
121 #endif
122     int  nprint;
123 
124     va_start(ap, format);
125 #if defined(HAS_vasprintf)
126     vasprintf(&addline, format, ap);
127 #elif defined(HAS_vsnprintf)
128     addline = NULL;
129     for (nmax = N_PRINTFBUF; ; ) {
130 	    xstralloc(&addline, nmax);
131 	    nprint = vsnprintf(addline, nmax, format, ap);
132 	    /* If that worked, return the string. */
133 	    if (nprint > -1 && nprint < nmax)
134                  break;
135 	    /* Else try again with more space. */
136 	    if (nprint > -1)
137 		 nmax = nprint+1;  /* precisely what is needed */
138 	    else
139 		 nmax += N_PRINTFBUF;        /* twice the old size */
140     };
141 #else
142     nprint = vsprintf(addline, format, ap);
143     if (nprint > N_PRINTFBUF) {
144 	    fprintf(stderr, "sprintf buffer overflow at xscatprintf.\n" \
145 			    "used %d bytes instead of %d\n" \
146 			    "format leading to this was : %s\n"\
147 			    "please tell the developers\n", nprint,
148 			    N_PRINTFBUF, format);
149 	    abort();
150     };
151 #endif
152     va_end(ap);
153     xstrcat(s, addline);
154 #if defined(HAS_vasprintf) || defined(HAS_vsnprintf)
155     free(addline);
156 #endif
157     return nprint;
158 }
159 
160 #ifdef TEST
161 
main(void)162 int main(void)
163 {
164 	char *s = NULL;
165 	xstralloc(&s, 10);
166 	strcpy(s, "1234567890");
167 	xstrcat(&s, " test");
168 	xstrscat(&s, " this", " one", NULL);
169 	xscatprintf(&s, " %d %d", 3, 4);
170 	printf("%s", s);
171 	return strcmp(s, "1234567890 test this one 3 4");
172 }
173 
174 #endif
175