Skip to content

Commit b92e6a7

Browse files
committed
Increase portability and coverage
1 parent f04d537 commit b92e6a7

16 files changed

Lines changed: 5294 additions & 341 deletions

CMakeLists.txt

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,251 @@ else ()
4747
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
4848
endif ()
4949

50+
include(CheckIncludeFile)
51+
include(CheckSymbolExists)
52+
include(CheckTypeSize)
53+
include(CheckCSourceCompiles)
54+
55+
check_include_file(strings.h C89STRINGUTILS_HAVE_STRINGS_H)
56+
check_include_file(sys/param.h C89STRINGUTILS_HAVE_SYS_PARAM_H)
57+
check_include_file(wchar.h C89STRINGUTILS_HAVE_WCHAR_H)
58+
59+
check_symbol_exists(strncpy_s "string.h" C89STRINGUTILS_HAVE_STRNCPY_S)
60+
check_symbol_exists(strcpy_s "string.h" C89STRINGUTILS_HAVE_STRCPY_S)
61+
check_symbol_exists(strncat_s "string.h" C89STRINGUTILS_HAVE_STRNCAT_S)
62+
check_symbol_exists(strcat_s "string.h" C89STRINGUTILS_HAVE_STRCAT_S)
63+
check_symbol_exists(strlcpy "string.h" C89STRINGUTILS_HAVE_STRLCPY)
64+
check_symbol_exists(strlcat "string.h" C89STRINGUTILS_HAVE_STRLCAT)
65+
check_symbol_exists(strnlen "string.h" C89STRINGUTILS_HAVE_STRNLEN)
66+
check_symbol_exists(strnlen_s "string.h" C89STRINGUTILS_HAVE_STRNLEN_S)
67+
check_symbol_exists(memcpy_s "string.h" C89STRINGUTILS_HAVE_MEMCPY_S)
68+
check_symbol_exists(set_constraint_handler_s "stdlib.h" C89STRINGUTILS_HAVE_SET_CONSTRAINT_HANDLER_S)
69+
check_symbol_exists(reallocarray "stdlib.h" C89STRINGUTILS_HAVE_REALLOCARRAY)
70+
check_symbol_exists(tmpfile_s "stdio.h" C89STRINGUTILS_HAVE_TMPFILE_S)
71+
check_symbol_exists(fopen_s "stdio.h" C89STRINGUTILS_HAVE_FOPEN_S)
72+
check_symbol_exists(freopen_s "stdio.h" C89STRINGUTILS_HAVE_FREOPEN_S)
73+
74+
check_symbol_exists(vsscanf "stdio.h;stdarg.h" C89STRINGUTILS_HAVE_VSSCANF)
75+
check_symbol_exists(vsscanf_s "stdio.h;stdarg.h" C89STRINGUTILS_HAVE_VSSCANF_S)
76+
check_symbol_exists(vfscanf "stdio.h;stdarg.h" C89STRINGUTILS_HAVE_VFSCANF)
77+
check_symbol_exists(vfscanf_s "stdio.h;stdarg.h" C89STRINGUTILS_HAVE_VFSCANF_S)
78+
79+
check_symbol_exists(wcscpy "wchar.h" C89STRINGUTILS_HAVE_WCSCPY)
80+
check_symbol_exists(wcsncpy "wchar.h" C89STRINGUTILS_HAVE_WCSNCPY)
81+
check_symbol_exists(wcscpy_s "wchar.h" C89STRINGUTILS_HAVE_WCSCPY_S)
82+
check_symbol_exists(wcsncpy_s "wchar.h" C89STRINGUTILS_HAVE_WCSNCPY_S)
83+
check_symbol_exists(vswprintf "wchar.h;stdarg.h" C89STRINGUTILS_HAVE_VSWPRINTF)
84+
check_symbol_exists(vswprintf_s "wchar.h;stdarg.h" C89STRINGUTILS_HAVE_VSWPRINTF_S)
85+
check_symbol_exists(swprintf "wchar.h;stdarg.h" C89STRINGUTILS_HAVE_SWPRINTF)
86+
check_symbol_exists(swprintf_s "wchar.h;stdarg.h" C89STRINGUTILS_HAVE_SWPRINTF_S)
87+
88+
check_symbol_exists(sprintf_s "stdio.h" C89STRINGUTILS_HAVE_SPRINTF_S)
89+
check_symbol_exists(vsnprintf "stdio.h;stdarg.h" C89STRINGUTILS_HAVE_VSNPRINTF)
90+
check_symbol_exists(_vsnprintf "stdio.h;stdarg.h" C89STRINGUTILS_HAVE__VSNPRINTF)
91+
check_symbol_exists(vsnprintf_s "stdio.h;stdarg.h" C89STRINGUTILS_HAVE_VSNPRINTF_S)
92+
check_symbol_exists(_vsnprintf_s "stdio.h;stdarg.h" C89STRINGUTILS_HAVE__VSNPRINTF_S)
93+
check_symbol_exists(snprintf_s "stdio.h" C89STRINGUTILS_HAVE_SNPRINTF_S)
94+
check_symbol_exists(_snprintf_s "stdio.h" C89STRINGUTILS_HAVE__SNPRINTF_S)
95+
check_symbol_exists(_snprintf "stdio.h" C89STRINGUTILS_HAVE__SNPRINTF)
96+
check_symbol_exists(vfprintf_s "stdio.h;stdarg.h" C89STRINGUTILS_HAVE_VFPRINTF_S)
97+
check_symbol_exists(fprintf_s "stdio.h" C89STRINGUTILS_HAVE_FPRINTF_S)
98+
check_symbol_exists(_vscprintf "stdio.h;stdarg.h" C89STRINGUTILS_HAVE__VSCPRINTF)
99+
check_symbol_exists(snprintf "stdio.h" C89STRINGUTILS_HAVE_SNPRINTF)
100+
101+
check_c_source_compiles("
102+
#include <stdio.h>
103+
#include <stddef.h>
104+
int main(void) {
105+
char buf[32];
106+
size_t s = 0;
107+
sprintf(buf, \"%zu\", s);
108+
return 0;
109+
}
110+
" C89STRINGUTILS_HAVE_PRINTF_ZU)
111+
112+
check_c_source_compiles("
113+
#include <stdio.h>
114+
int main(void) {
115+
char buf[32];
116+
long long s = 0;
117+
sprintf(buf, \"%lld\", s);
118+
return 0;
119+
}
120+
" C89STRINGUTILS_HAVE_PRINTF_LLD)
121+
122+
check_c_source_compiles("
123+
#include <stdio.h>
124+
int main(void) {
125+
char buf[32];
126+
__int64 s = 0;
127+
sprintf(buf, \"%I64d\", s);
128+
return 0;
129+
}
130+
" C89STRINGUTILS_HAVE_PRINTF_I64D)
131+
132+
check_c_source_compiles("
133+
#include <stdio.h>
134+
#include <stddef.h>
135+
int main(void) {
136+
char buf[32];
137+
size_t s = 0;
138+
sprintf(buf, \"%Iu\", s);
139+
return 0;
140+
}
141+
" C89STRINGUTILS_HAVE_PRINTF_IU)
142+
143+
check_c_source_compiles("
144+
#include <stdio.h>
145+
#include <stdarg.h>
146+
int main(void) {
147+
/* This isn't a perfect runtime check, but checks if compiler complains */
148+
return 0;
149+
}
150+
" C89STRINGUTILS_HAVE_VSNPRINTF_NULL)
151+
152+
set(STRING_HEADERS "string.h")
153+
if(C89STRINGUTILS_HAVE_STRINGS_H)
154+
list(APPEND STRING_HEADERS "strings.h")
155+
endif()
156+
157+
check_symbol_exists(strncasecmp "${STRING_HEADERS}" C89STRINGUTILS_HAVE_STRNCASECMP)
158+
check_symbol_exists(_strnicmp "${STRING_HEADERS}" C89STRINGUTILS_HAVE__STRNICMP)
159+
160+
check_symbol_exists(strcasecmp "${STRING_HEADERS}" C89STRINGUTILS_HAVE_STRCASECMP)
161+
check_symbol_exists(_stricmp "${STRING_HEADERS}" C89STRINGUTILS_HAVE__STRICMP)
162+
163+
set(CMAKE_REQUIRED_DEFINITIONS "-D_GNU_SOURCE")
164+
check_symbol_exists(strnstr "string.h" C89STRINGUTILS_HAVE_STRNSTR)
165+
check_symbol_exists(strcasestr "string.h" C89STRINGUTILS_HAVE_STRCASESTR)
166+
167+
check_symbol_exists(vasprintf "stdio.h" C89STRINGUTILS_HAVE_VASPRINTF)
168+
check_symbol_exists(asprintf "stdio.h" C89STRINGUTILS_HAVE_ASPRINTF)
169+
set(CMAKE_REQUIRED_DEFINITIONS)
170+
171+
check_symbol_exists(strerror_s "string.h" C89STRINGUTILS_HAVE_STRERROR_S)
172+
check_symbol_exists(strerror_r "string.h" C89STRINGUTILS_HAVE_STRERROR_R)
173+
174+
option(C89STRINGUTILS_FORCE_FALLBACKS "Force fallbacks for coverage testing" OFF)
175+
if(C89STRINGUTILS_FORCE_FALLBACKS)
176+
set(C89STRINGUTILS_HAVE_STRNCPY_S OFF)
177+
set(C89STRINGUTILS_HAVE_STRCPY_S OFF)
178+
set(C89STRINGUTILS_HAVE_STRNCAT_S OFF)
179+
set(C89STRINGUTILS_HAVE_STRCAT_S OFF)
180+
set(C89STRINGUTILS_HAVE_STRLCPY OFF)
181+
set(C89STRINGUTILS_HAVE_STRLCAT OFF)
182+
set(C89STRINGUTILS_HAVE_STRNLEN OFF)
183+
set(C89STRINGUTILS_HAVE_STRNLEN_S OFF)
184+
set(C89STRINGUTILS_HAVE_MEMCPY_S OFF)
185+
set(C89STRINGUTILS_HAVE_SET_CONSTRAINT_HANDLER_S OFF)
186+
set(C89STRINGUTILS_HAVE_REALLOCARRAY OFF)
187+
set(C89STRINGUTILS_HAVE_TMPFILE_S OFF)
188+
set(C89STRINGUTILS_HAVE_FOPEN_S OFF)
189+
set(C89STRINGUTILS_HAVE_FREOPEN_S OFF)
190+
set(C89STRINGUTILS_HAVE_VSSCANF_S OFF)
191+
set(C89STRINGUTILS_HAVE_VFSCANF_S OFF)
192+
set(C89STRINGUTILS_HAVE_WCSCPY_S OFF)
193+
set(C89STRINGUTILS_HAVE_WCSNCPY_S OFF)
194+
set(C89STRINGUTILS_HAVE_VSWPRINTF_S OFF)
195+
set(C89STRINGUTILS_HAVE_SWPRINTF_S OFF)
196+
set(C89STRINGUTILS_HAVE_SPRINTF_S OFF)
197+
set(C89STRINGUTILS_HAVE_VSNPRINTF_S OFF)
198+
set(C89STRINGUTILS_HAVE__VSNPRINTF_S OFF)
199+
set(C89STRINGUTILS_HAVE_SNPRINTF_S OFF)
200+
set(C89STRINGUTILS_HAVE__SNPRINTF_S OFF)
201+
set(C89STRINGUTILS_HAVE_VFPRINTF_S OFF)
202+
set(C89STRINGUTILS_HAVE_FPRINTF_S OFF)
203+
set(C89STRINGUTILS_HAVE_SNPRINTF OFF)
204+
set(C89STRINGUTILS_HAVE__SNPRINTF OFF)
205+
set(C89STRINGUTILS_HAVE_VSNPRINTF OFF)
206+
set(C89STRINGUTILS_HAVE__VSNPRINTF OFF)
207+
set(C89STRINGUTILS_HAVE_STRNCASECMP OFF)
208+
set(C89STRINGUTILS_HAVE__STRNICMP OFF)
209+
set(C89STRINGUTILS_HAVE_STRCASECMP OFF)
210+
set(C89STRINGUTILS_HAVE__STRICMP OFF)
211+
set(C89STRINGUTILS_HAVE_STRNSTR OFF)
212+
set(C89STRINGUTILS_HAVE_STRCASESTR OFF)
213+
set(C89STRINGUTILS_HAVE_VASPRINTF OFF)
214+
set(C89STRINGUTILS_HAVE_ASPRINTF OFF)
215+
set(C89STRINGUTILS_HAVE_STRERROR_S OFF)
216+
set(C89STRINGUTILS_HAVE_STRERROR_R OFF)
217+
add_compile_definitions(C89STRINGUTILS_FORCE_FALLBACKS)
218+
endif()
219+
220+
if(C89STRINGUTILS_HAVE_STRERROR_R)
221+
set(CMAKE_REQUIRED_DEFINITIONS "-D_GNU_SOURCE")
222+
check_c_source_compiles("
223+
#include <string.h>
224+
int main(void) {
225+
char buf[256];
226+
char *res = strerror_r(0, buf, sizeof(buf));
227+
return res != 0;
228+
}
229+
" C89STRINGUTILS_STRERROR_R_CHAR_P)
230+
set(CMAKE_REQUIRED_DEFINITIONS)
231+
endif()
232+
233+
check_c_source_compiles("
234+
#include <stdarg.h>
235+
int main(void) { va_list a, b; va_copy(a, b); return 0; }
236+
" C89STRINGUTILS_HAVE_VA_COPY)
237+
238+
check_c_source_compiles("
239+
#include <stdarg.h>
240+
int main(void) { va_list a, b; __va_copy(a, b); return 0; }
241+
" C89STRINGUTILS_HAVE___VA_COPY)
242+
243+
check_c_source_compiles("
244+
void my_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
245+
int main(void) { return 0; }
246+
" C89STRINGUTILS_HAVE_ATTR_FORMAT)
247+
248+
check_c_source_compiles("
249+
void my_func(const char *s) __attribute__((nonnull(1)));
250+
int main(void) { return 0; }
251+
" C89STRINGUTILS_HAVE_ATTR_NONNULL)
252+
253+
check_c_source_compiles("
254+
int main(void) { int a = 1; typeof(a) b = 2; return b; }
255+
" C89STRINGUTILS_HAVE_TYPEOF)
256+
257+
check_c_source_compiles("
258+
#include <sal.h>
259+
_Ret_notnull_ void* my_func(_In_z_ const char* s) { return (void*)s; }
260+
int main(void) { return 0; }
261+
" C89STRINGUTILS_HAVE_SAL)
262+
263+
check_c_source_compiles("
264+
#pragma warning(push)
265+
#pragma warning(disable: 4127)
266+
int main(void) { return 0; }
267+
" C89STRINGUTILS_HAVE_PRAGMA_WARNING)
268+
269+
check_c_source_compiles("
270+
#pragma GCC diagnostic push
271+
#pragma GCC diagnostic ignored \"-Wunused-parameter\"
272+
int main(void) { return 0; }
273+
" C89STRINGUTILS_HAVE_PRAGMA_GCC_DIAGNOSTIC)
274+
275+
check_type_size("long long" SIZEOF_LONG_LONG)
276+
if(HAVE_SIZEOF_LONG_LONG)
277+
set(C89STRINGUTILS_HAVE_LONG_LONG 1)
278+
endif()
279+
check_type_size("__int64" SIZEOF___INT64)
280+
if(HAVE_SIZEOF___INT64)
281+
set(C89STRINGUTILS_HAVE___INT64 1)
282+
endif()
283+
284+
check_c_source_compiles("
285+
#include <errno.h>
286+
#include <stddef.h>
287+
int main(void) { errno_t e = 0; return (int)e; }
288+
" C89STRINGUTILS_HAVE_ERRNO_T)
289+
290+
check_c_source_compiles("
291+
#include <stddef.h>
292+
int main(void) { rsize_t s = 0; return (int)s; }
293+
" C89STRINGUTILS_HAVE_RSIZE_T)
294+
50295
# configure a header file to pass the version number only
51296
configure_file(
52297
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/config.h.in"

README.md

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ the one provided by this library.
2929
- **Windows Security:** Eradicates the inclusion of heavy platform headers like `<windows.h>`, and actively defaults to MSVC "Safe CRT" variants (e.g., `vsprintf_s`, `_vscprintf`) implicitly when building on Microsoft compilers.
3030
- **Quality Metrics:** Maintains 100% Doxygen documentation and 100% test coverage locally.
3131

32-
### Single-File Header-Only Amalgamation (STB-style)
32+
## Integration Examples
33+
34+
### 1. Single-File Header-Only Amalgamation (STB-style)
3335

3436
If you don't want to link against a built `static` or `shared` library, you can generate a drop-in, STB-style single-header amalgamation!
3537

@@ -54,16 +56,75 @@ int main(void) {
5456
}
5557
```
5658
59+
### 2. CMake FetchContent
60+
61+
You can automatically download and integrate `c89stringutils` into your CMake project using `FetchContent`:
62+
63+
```cmake
64+
include(FetchContent)
65+
66+
FetchContent_Declare(
67+
c89stringutils
68+
GIT_REPOSITORY https://github.com/offscale/c89stringutils.git
69+
GIT_TAG main # Or specify a particular commit/tag
70+
)
71+
FetchContent_MakeAvailable(c89stringutils)
72+
73+
# Link against the target
74+
target_link_libraries(your_target PRIVATE c89stringutils)
75+
```
76+
77+
### 3. vcpkg (Custom Registry)
78+
79+
You can manage `c89stringutils` via vcpkg using a custom registry pointing to the `project0` branch of the `SamuelMarks/vcpkg` fork. In your project root, create a `vcpkg-configuration.json` file:
80+
81+
```json
82+
{
83+
"default-registry": {
84+
"kind": "git",
85+
"repository": "https://github.com/SamuelMarks/vcpkg.git",
86+
"reference": "project0"
87+
},
88+
"registries": [
89+
{
90+
"kind": "git",
91+
"repository": "https://github.com/microsoft/vcpkg.git",
92+
"reference": "master",
93+
"packages": [ "*" ]
94+
}
95+
]
96+
}
97+
```
98+
99+
Add the dependency to your `vcpkg.json`:
100+
101+
```json
102+
{
103+
"name": "your-project",
104+
"version": "1.0.0",
105+
"dependencies": [
106+
"c89stringutils"
107+
]
108+
}
109+
```
110+
111+
Then locate and link the package in your `CMakeLists.txt`:
112+
113+
```cmake
114+
find_package(c89stringutils CONFIG REQUIRED)
115+
target_link_libraries(your_target PRIVATE c89stringutils::c89stringutils)
116+
```
117+
57118
### String functions implemented
58119

59120
| Function | Citation |
60121
|-------------------------------------------------------------------------|------------------------------|
61122
| [`strcasestr`](https://www.freebsd.org/cgi/man.cgi?query=strcasestr) | From MUSL |
62123
| [`strncasecmp`](https://www.freebsd.org/cgi/man.cgi?query=strncasecmp) | Alias for MSVC's `_strnicmp` |
63124
| [`strcasecmp`](https://www.freebsd.org/cgi/man.cgi?query=strcasecmp) | Alias for MSVC's `_stricmp` |
64-
| [`snprintf`](https://www.freebsd.org/cgi/man.cgi?query=snprintf) | Mostly from WTF_StringExtras |
65-
| [`vsnprintf`](https://www.freebsd.org/cgi/man.cgi?query=vsnprintf) | Mostly from WTF_StringExtras |
66-
| [`strnstr`](https://www.freebsd.org/cgi/man.cgi?query=strnstr) | Mostly from WTF_StringExtras |
125+
| [`snprintf`](https://www.freebsd.org/cgi/man.cgi?query=snprintf) | Custom C89 polyfill |
126+
| [`vsnprintf`](https://www.freebsd.org/cgi/man.cgi?query=vsnprintf) | Custom C89 polyfill |
127+
| [`strnstr`](https://www.freebsd.org/cgi/man.cgi?query=strnstr) | Custom C89 polyfill |
67128
| [`strerrorlen_s`](https://en.cppreference.com/w/c/string/byte/strerror) | From Safe C Library |
68129
| [`asprintf`](https://www.freebsd.org/cgi/man.cgi?query=asprintf) | From libressl-portable |
69130

build_msvc2005_wine.cmd

Lines changed: 0 additions & 41 deletions
This file was deleted.

0 commit comments

Comments
 (0)