Skip to content

Commit 43bd8d9

Browse files
committed
[c89stringutils/c89stringutils_string_extras.h] Add concat_asprintf; guard implementations better ; [README.md] Add concat_asprintf
1 parent aa7f8ac commit 43bd8d9

File tree

2 files changed

+49
-14
lines changed

2 files changed

+49
-14
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ Header only (to simplify including). Just `#define C89STRINGUTILS_IMPLEMENTATION
2525
| [`strerrorlen_s`](https://en.cppreference.com/w/c/string/byte/strerror) | From Safe C Library |
2626
| [`asprintf`](https://www.freebsd.org/cgi/man.cgi?query=asprintf) | From libressl-portable |
2727

28+
Additionally `concat_asprintf`, a version of `asprintf` that can concatenates on successive calls.
29+
2830
### Dependencies
2931

3032
- [CMake](https://cmake.org) (3.19 or later)

c89stringutils/c89stringutils_string_extras.h

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -135,21 +135,21 @@ extern int strncasecmp(const char *, const char *, size_t);
135135

136136
extern int strcasecmp(const char *, const char *);
137137

138-
#ifdef C89STRINGUTILS_IMPLEMENTATION
138+
#if defined(C89STRINGUTILS_IMPLEMENTATION) && !defined(HAVE_STRNCASECMP_H)
139139
#define HAVE_STRNCASECMP_H
140140
#define strncasecmp _strnicmp
141141

142142
#define strcasecmp _stricmp
143143

144-
#endif /* C89STRINGUTILS_IMPLEMENTATION */
144+
#endif /* defined(C89STRINGUTILS_IMPLEMENTATION) && !defined(HAVE_STRNCASECMP_H) */
145145

146146
#endif /* !HAVE_STRNCASECMP_H */
147147

148148
#ifndef HAVE_STRNSTR
149149

150150
extern char *strnstr(const char *, const char *, size_t);
151151

152-
#ifdef C89STRINGUTILS_IMPLEMENTATION
152+
#if defined(C89STRINGUTILS_IMPLEMENTATION) && !defined(HAVE_STRNSTR)
153153
#define HAVE_STRNSTR
154154
char *strnstr(const char *buffer, const char *target, size_t bufferLength) {
155155
/*
@@ -178,14 +178,14 @@ char *strnstr(const char *buffer, const char *target, size_t bufferLength) {
178178
}
179179
return 0;
180180
}
181-
#endif /* C89STRINGUTILS_IMPLEMENTATION */
181+
#endif /* defined(C89STRINGUTILS_IMPLEMENTATION) && !defined(HAVE_STRNSTR) */
182182

183-
#endif /* ! HAVE_STRNSTR */
183+
#endif /* !HAVE_STRNSTR */
184184

185185
#ifndef HAVE_STRCASESTR_H
186186
extern char *strcasestr(const char *, const char *);
187187

188-
#ifdef C89STRINGUTILS_IMPLEMENTATION
188+
#if defined(C89STRINGUTILS_IMPLEMENTATION) && !defined(HAVE_STRCASESTR_H)
189189
#define HAVE_STRCASESTR_H
190190

191191
/* `strcasestr` from MUSL */
@@ -197,15 +197,15 @@ char *strcasestr(const char *h, const char *n)
197197
return 0;
198198
}
199199

200-
#endif /* C89STRINGUTILS_IMPLEMENTATION */
200+
#endif /* defined(C89STRINGUTILS_IMPLEMENTATION) && !defined(HAVE_STRCASESTR_H) */
201201

202-
#endif /* ! HAVE_STRCASESTR_H */
202+
#endif /* !HAVE_STRCASESTR_H */
203203

204204
#ifndef HAVE_STRERRORLEN_S
205205

206206
extern size_t strerrorlen_s(errno_t);
207207

208-
#ifdef C89STRINGUTILS_IMPLEMENTATION
208+
#if defined(C89STRINGUTILS_IMPLEMENTATION) && !defined(HAVE_STRERRORLEN_S)
209209
#define HAVE_STRERRORLEN_S
210210
/* MIT licensed function from Safe C Library */
211211

@@ -255,7 +255,7 @@ size_t strerrorlen_s(errno_t errnum)
255255
}
256256
}
257257

258-
#endif /* C89STRINGUTILS_IMPLEMENTATION */
258+
#endif /* defined(C89STRINGUTILS_IMPLEMENTATION) && !defined(HAVE_STRERRORLEN_S) */
259259

260260
#endif /* !HAVE_STRERRORLEN_S */
261261

@@ -265,8 +265,7 @@ extern int vasprintf(char **str, const char *fmt, va_list ap);
265265

266266
extern int asprintf(char **str, const char *fmt, ...);
267267

268-
#ifdef C89STRINGUTILS_IMPLEMENTATION
269-
268+
#if defined(C89STRINGUTILS_IMPLEMENTATION) && !defined(HAVE_ASPRINTF)
270269
#define HAVE_ASPRINTF
271270

272271
#include <errno.h>
@@ -342,8 +341,42 @@ extern int asprintf(char **str, const char *fmt, ...)
342341
return ret;
343342
}
344343

345-
#endif /* C89STRINGUTILS_IMPLEMENTATION */
344+
#endif /* defined(C89STRINGUTILS_IMPLEMENTATION) && !defined(HAVE_ASPRINTF) */
346345

347346
#endif /* !HAVE_ASPRINTF */
348347

349-
#endif /* ! C89STRINGUTILS_STRING_EXTRAS_H */
348+
/* a version of `asprintf` that can be called multiple times:
349+
* char *s; concat_asprintf(&s, "foo%s", "bar");
350+
* concat_asprintf(&s, "can%s", "haz"); free(s);
351+
* */
352+
char *concat_asprintf(char **unto, const char *fmt, ...);
353+
354+
#ifndef HAVE_CONCAT_ASPRINTF
355+
#define HAVE_CONCAT_ASPRINTF
356+
char *concat_asprintf(char **unto, const char *fmt, ...) {
357+
va_list args;
358+
size_t base_length = unto && *unto ? strlen(*unto) : 0;
359+
int length;
360+
char *result;
361+
362+
va_start(args, fmt);
363+
/* check length for failure */
364+
length = vsnprintf(NULL, 0, fmt, args);
365+
va_end(args);
366+
367+
/* check result for failure */
368+
result = realloc(unto ? *unto : NULL, base_length + length + 1);
369+
370+
va_start(args, fmt);
371+
/* check for failure*/
372+
vsprintf(result + base_length, fmt, args);
373+
va_end(args);
374+
375+
if (unto)
376+
*unto = result;
377+
378+
return result;
379+
}
380+
#endif /* !HAVE_CONCAT_ASPRINTF */
381+
382+
#endif /* !C89STRINGUTILS_STRING_EXTRAS_H */

0 commit comments

Comments
 (0)