Skip to content

Commit 5cbd597

Browse files
committed
[c89stringutils/{CMakeLists.txt,c89stringutils_string_extras{.h,.c}}] Shared|static version of library (as precursor to applying my new C compiler to convert betwixt header-only and this)
1 parent efa52aa commit 5cbd597

File tree

3 files changed

+308
-237
lines changed

3 files changed

+308
-237
lines changed

c89stringutils/CMakeLists.txt

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
get_filename_component(LIBRARY_NAME "${CMAKE_CURRENT_SOURCE_DIR}" NAME)
22

33
set(Header_Files "c89stringutils_string_extras.h")
4-
54
source_group("Header Files" FILES "${Header_Files}")
65

7-
add_library("${LIBRARY_NAME}" INTERFACE "${Header_Files}")
6+
set(Source_Files "c89stringutils_string_extras.c")
7+
source_group("Source Files" FILES "${Header_Files}")
8+
9+
add_library("${LIBRARY_NAME}" "${Header_Files}" "${Source_Files}")
810

911
include(GNUInstallDirs)
1012
target_include_directories(
1113
"${LIBRARY_NAME}"
12-
INTERFACE
14+
PUBLIC
1315
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
16+
"$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}>"
1417
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
1518
)
1619

@@ -21,6 +24,10 @@ set_target_properties(
2124
C
2225
)
2326

27+
include(GenerateExportHeader)
28+
set(_export_file "${CMAKE_BINARY_DIR}/${LIBRARY_NAME}_export.h")
29+
generate_export_header("${LIBRARY_NAME}" EXPORT_FILE_NAME "${_export_file}")
30+
2431
# install rules
2532
set(installable_libs "${LIBRARY_NAME}")
2633
if (TARGET "${DEPENDANT_LIBRARY}")
@@ -31,4 +38,4 @@ install(TARGETS ${installable_libs}
3138
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
3239
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
3340
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
34-
install(FILES ${Header_Files} TYPE "INCLUDE")
41+
install(FILES ${Header_Files} "${_export_file}" TYPE "INCLUDE")
Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
/*
2+
* string functions helpful on Linux (and sometimes BSD)
3+
* are now made available on other platforms (Windows, SunOS, &etc.)
4+
* */
5+
6+
#include <stdlib.h>
7+
#include "c89stringutils_string_extras.h"
8+
9+
#if !defined(HAVE_SNPRINTF_H)
10+
#define HAVE_SNPRINTF_H
11+
/*
12+
* `snprintf`, `vsnprintf`, `strnstr` taken from:
13+
* https://chromium.googlesource.com/chromium/blink/+/5cedd2fd208daf119b9ea47c7c1e22d760a586eb/Source/wtf/StringExtras.h
14+
* …then modified to remove C++ specifics and WebKit specific macros
15+
*
16+
* Copyright (C) 2006, 2010 Apple Inc. All rights reserved.
17+
* Copyright (C) 2020 Offscale.io. All rights reserved.
18+
*
19+
* SPDX-License-Identifier: BSD-2-Clause
20+
*/
21+
22+
inline int snprintf(char *buffer, size_t count, const char *format, ...) {
23+
int result;
24+
va_list args;
25+
va_start(args, format);
26+
result = _vsnprintf(buffer, count, format, args);
27+
va_end(args);
28+
/* In the case where the string entirely filled the buffer, _vsnprintf will
29+
not null-terminate it, but snprintf must. */
30+
if (count > 0)
31+
buffer[count - 1] = '\0';
32+
return result;
33+
}
34+
35+
inline double wtf_vsnprintf(char *buffer, size_t count, const char *format,
36+
va_list args) {
37+
int result = _vsnprintf(buffer, count, format, args);
38+
/* In the case where the string entirely filled the buffer, _vsnprintf will
39+
not null-terminate it, but vsnprintf must. */
40+
if (count > 0)
41+
buffer[count - 1] = '\0';
42+
return result;
43+
}
44+
45+
/* Work around a difference in Microsoft's implementation of vsnprintf, where
46+
vsnprintf does not null terminate the buffer. WebKit can rely on the null
47+
termination. Microsoft's implementation is fixed in VS 2015. */
48+
#define vsnprintf(buffer, count, format, args) \
49+
wtf_vsnprintf(buffer, count, format, args)
50+
51+
#endif /* !defined(HAVE_SNPRINTF_H) */
52+
53+
#ifndef HAVE_STRNCASECMP_H
54+
55+
#if defined(C89STRINGUTILS_IMPLEMENTATION)
56+
#define HAVE_STRNCASECMP_H
57+
58+
#define strncasecmp _strnicmp
59+
#define strcasecmp _stricmp
60+
61+
#endif /* !defined(HAVE_STRNCASECMP_H) */
62+
63+
#endif /* !HAVE_STRNCASECMP_H */
64+
65+
#ifndef HAVE_STRNSTR
66+
67+
#if !defined(HAVE_STRNSTR)
68+
#define HAVE_STRNSTR
69+
char *strnstr(const char *buffer, const char *target, size_t bufferLength) {
70+
/*
71+
Find the first occurrence of find in s, where the search is limited to the
72+
first slen characters of s.
73+
74+
DESCRIPTION
75+
The strnstr() function locates the first occurrence of the
76+
null-termi-
77+
nated string little in the string big, where not more than len
78+
characters are searched. Characters that appear after a `\0' character are
79+
not searched.
80+
81+
RETURN VALUES
82+
If little is an empty string, big is returned; if little occurs
83+
nowhere in big, NULL is returned; otherwise a pointer to the first
84+
character of the first occurrence of little is returned.
85+
86+
[this doc (c) FreeBSD <3 clause BSD license> from their manpage] */
87+
const size_t targetLength = strlen(target);
88+
const char *start;
89+
if (targetLength == 0)
90+
return (char *)buffer;
91+
for (start = buffer; *start && start + targetLength <= buffer + bufferLength;
92+
start++) {
93+
if (*start == *target &&
94+
strncmp(start + 1, target + 1, targetLength - 1) == 0)
95+
return (char *)(start);
96+
}
97+
return 0;
98+
}
99+
#endif /* !defined(HAVE_STRNSTR) */
100+
101+
#endif /* !HAVE_STRNSTR */
102+
103+
#ifndef HAVE_STRCASESTR_H
104+
105+
#if !defined(HAVE_STRCASESTR_H)
106+
#define HAVE_STRCASESTR_H
107+
108+
/* `strcasestr` from MUSL */
109+
110+
char *strcasestr(const char *h, const char *n) {
111+
const size_t l = strlen(n);
112+
for (; *h; h++)
113+
if (!strncasecmp(h, n, l))
114+
return (char *)h;
115+
return 0;
116+
}
117+
118+
#endif /* !defined(HAVE_STRCASESTR_H) */
119+
120+
#endif /* !HAVE_STRCASESTR_H */
121+
122+
#ifndef HAVE_STRERRORLEN_S
123+
124+
#if !defined(HAVE_STRERRORLEN_S)
125+
#define HAVE_STRERRORLEN_S
126+
/* MIT licensed function from Safe C Library */
127+
128+
size_t strerrorlen_s(errno_t errnum) {
129+
#ifndef ESNULLP
130+
#define ESNULLP (400) /* null ptr */
131+
#endif
132+
133+
#ifndef ESLEWRNG
134+
#define ESLEWRNG (410) /* wrong size */
135+
#endif
136+
137+
#ifndef ESLAST
138+
#define ESLAST ESLEWRNG
139+
#endif
140+
141+
static const int len_errmsgs_s[] = {
142+
sizeof "null ptr", /* ESNULLP */
143+
sizeof "length is zero", /* ESZEROL */
144+
sizeof "length is below min", /* ESLEMIN */
145+
sizeof "length exceeds RSIZE_MAX", /* ESLEMAX */
146+
sizeof "overlap undefined", /* ESOVRLP */
147+
sizeof "empty string", /* ESEMPTY */
148+
sizeof "not enough space", /* ESNOSPC */
149+
sizeof "unterminated string", /* ESUNTERM */
150+
sizeof "no difference", /* ESNODIFF */
151+
sizeof "not found", /* ESNOTFND */
152+
sizeof "wrong size", /* ESLEWRNG */
153+
};
154+
155+
if (errnum >= ESNULLP && errnum <= ESLAST) {
156+
return len_errmsgs_s[errnum - ESNULLP] - 1;
157+
} else {
158+
#ifdef _MSC_VER
159+
#pragma warning(push)
160+
#pragma warning(disable : 4996)
161+
#endif /* _MSC_VER */
162+
const char *buf = strerror(errnum);
163+
#ifdef _MSC_VER
164+
#pragma warning(pop)
165+
#endif /* _MSC_VER */
166+
return buf ? strlen(buf) : 0;
167+
}
168+
}
169+
170+
#endif /* !defined(HAVE_STRERRORLEN_S) */
171+
172+
#endif /* !HAVE_STRERRORLEN_S */
173+
174+
#ifndef HAVE_ASPRINTF
175+
176+
#if !defined(HAVE_ASPRINTF)
177+
#define HAVE_ASPRINTF
178+
179+
#include <errno.h>
180+
#include <limits.h> /* for INT_MAX */
181+
#include <stdlib.h>
182+
183+
#ifndef VA_COPY
184+
#if defined(HAVE_VA_COPY) || defined(va_copy)
185+
#define VA_COPY(dest, src) va_copy(dest, src)
186+
#else
187+
#ifdef HAVE___VA_COPY
188+
#define VA_COPY(dest, src) __va_copy(dest, src)
189+
#else
190+
#define VA_COPY(dest, src) (dest) = (src)
191+
#endif
192+
#endif
193+
#endif /* ! VA_COPY */
194+
195+
#define INIT_SZ 128
196+
197+
extern int vasprintf(char **str, const char *fmt, va_list ap) {
198+
int ret;
199+
va_list ap2;
200+
char *string, *newstr;
201+
size_t len;
202+
203+
if ((string = (char *)malloc(INIT_SZ)) == NULL)
204+
goto fail;
205+
206+
VA_COPY(ap2, ap);
207+
ret = vsnprintf(string, INIT_SZ, fmt, ap2);
208+
va_end(ap2);
209+
if (ret >= 0 && ret < INIT_SZ) { /* succeeded with initial alloc */
210+
*str = string;
211+
} else if (ret == INT_MAX || ret < 0) { /* Bad length */
212+
free(string);
213+
goto fail;
214+
} else { /* bigger than initial, realloc allowing for nul */
215+
len = (size_t)ret + 1;
216+
if ((newstr = (char *)realloc(string, len)) == NULL) {
217+
free(string);
218+
goto fail;
219+
}
220+
VA_COPY(ap2, ap);
221+
ret = vsnprintf(newstr, len, fmt, ap2);
222+
va_end(ap2);
223+
if (ret < 0 || (size_t)ret >= len) { /* failed with realloc'ed string */
224+
free(newstr);
225+
goto fail;
226+
}
227+
*str = newstr;
228+
}
229+
return ret;
230+
231+
fail:
232+
*str = NULL;
233+
errno = ENOMEM;
234+
return -1;
235+
}
236+
237+
extern int asprintf(char **str, const char *fmt, ...) {
238+
va_list ap;
239+
int ret;
240+
241+
*str = NULL;
242+
va_start(ap, fmt);
243+
ret = vasprintf(str, fmt, ap);
244+
va_end(ap);
245+
246+
return ret;
247+
}
248+
249+
#endif /* !defined(HAVE_ASPRINTF) */
250+
251+
#endif /* !HAVE_ASPRINTF */
252+
253+
#ifndef HAVE_JASPRINTF
254+
255+
#if !defined(HAVE_JASPRINTF)
256+
#define HAVE_JASPRINTF
257+
char *jasprintf(char **unto, const char *fmt, ...) {
258+
va_list args;
259+
size_t base_length = unto && *unto ? strlen(*unto) : 0;
260+
int length;
261+
char *result;
262+
263+
va_start(args, fmt);
264+
/* check length for failure */
265+
length = vsnprintf(NULL, 0, fmt, args);
266+
va_end(args);
267+
268+
/* check result for failure */
269+
result = realloc(unto ? *unto : NULL, base_length + length + 1);
270+
271+
va_start(args, fmt);
272+
/* check for failure*/
273+
vsprintf(result + base_length, fmt, args);
274+
va_end(args);
275+
276+
if (unto)
277+
*unto = result;
278+
279+
return result;
280+
}
281+
#endif /* !defined(HAVE_JASPRINTF) */
282+
#endif /* !HAVE_JASPRINTF */

0 commit comments

Comments
 (0)