Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .cirrus.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
freebsd_instance:
image_family: freebsd-13-0
image_family: freebsd-14
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

15 is out now


task:
install_script: pkg install -y cmake
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ jobs:
EOF

- name: Compile Test Amalgamation
run: gcc -Wall -Wextra -Werror -o test_amalg test_amalg.c
run: gcc -std=c89 -Wpedantic -Wall -Wextra -Werror -o test_amalg test_amalg.c

- name: Run Test Amalgamation
run: ./test_amalg
23 changes: 23 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,34 @@
cmake_minimum_required(VERSION 3.11)
project(c89stringutils VERSION 0.0.2 LANGUAGES C)

include(CheckCSourceCompiles)

check_c_source_compiles("#include <stdarg.h>
void t(int i, ...) { va_list a, b; va_start(a,i); va_copy(b,a); va_end(b); va_end(a); }
int main() { return 0; }" HAVE_VA_COPY)

check_c_source_compiles("#include <stdarg.h>
void t(int i, ...) { va_list a, b; va_start(a,i); __va_copy(b,a); va_end(b); va_end(a); }
int main() { return 0; }" HAVE___VA_COPY)

check_c_source_compiles("#include <stdarg.h>
void t(int i, ...) { va_list a, b; va_start(a,i); b = a; va_end(a); }
int main() { return 0; }" HAVE_VA_LIST_ASSIGNMENT)

set(CMAKE_C_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN YES)
set(CMAKE_C_STANDARD 90)

add_library("${PROJECT_NAME}_compiler_flags" INTERFACE)

if(HAVE_VA_COPY)
target_compile_definitions("${PROJECT_NAME}_compiler_flags" INTERFACE HAVE_VA_COPY)
elseif(HAVE___VA_COPY)
target_compile_definitions("${PROJECT_NAME}_compiler_flags" INTERFACE HAVE___VA_COPY)
elseif(HAVE_VA_LIST_ASSIGNMENT)
target_compile_definitions("${PROJECT_NAME}_compiler_flags" INTERFACE HAVE_VA_LIST_ASSIGNMENT)
endif()

if (NOT DEFINED MSVC_VERSION
OR MSVC_VERSION STRGREATER "1900" # 2015
OR NOT (CMAKE_C_COMPILER_ID STREQUAL "OpenWatcom"))
Expand Down
2 changes: 2 additions & 0 deletions c89stringutils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ source_group("Source Files" FILES "${Source_Files}")

add_library("${LIBRARY_NAME}" "${Header_Files}" "${Source_Files}")

target_link_libraries("${LIBRARY_NAME}" PUBLIC "${PROJECT_NAME}_compiler_flags")

include(GNUInstallDirs)
target_include_directories(
"${LIBRARY_NAME}"
Expand Down
28 changes: 16 additions & 12 deletions c89stringutils/c89stringutils_string_extras.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,11 @@ char *strnstr(const char *buffer, const char *target, size_t bufferLength) {
character of the first occurrence of little is returned.

[this doc (c) FreeBSD <3 clause BSD license> from their manpage] */
const size_t targetLength = strlen(target);
size_t targetLength;
const char *start;

/* Fix assignment of targetLength. C89 requires variables to be defined at beginning of a scope */
targetLength = strlen(target);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was defined at the top of scope? - And the way I had it enabled it to be const

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right change was unnecessory. sorry about that.

if (targetLength == 0)
return (char *)buffer;
for (start = buffer; *start && start + targetLength <= buffer + bufferLength;
Expand All @@ -125,7 +128,8 @@ char *strnstr(const char *buffer, const char *target, size_t bufferLength) {
/* `strcasestr` from MUSL */

char *strcasestr(const char *h, const char *n) {
const size_t l = strlen(n);
size_t l;
l = strlen(n);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was defined at the top of scope? - And the way I had it enabled it to be const

for (; *h; h++)
if (!strncasecmp(h, n, l))
return (char *)h;
Expand Down Expand Up @@ -186,16 +190,16 @@ size_t strerrorlen_s(errno_t errnum) {
#define HAVE_ASPRINTF

#ifndef VA_COPY
#if defined(HAVE_VA_COPY) || defined(va_copy)
#define VA_COPY(dest, src) va_copy(dest, src)
#else
#ifdef HAVE___VA_COPY
#define VA_COPY(dest, src) __va_copy(dest, src)
#else
#define VA_COPY(dest, src) (dest) = (src)
#endif
#endif
#endif /* ! VA_COPY */
# if defined(HAVE_VA_COPY)
# define VA_COPY(dest, src) va_copy(dest, src)
# elif defined(HAVE___VA_COPY)
# define VA_COPY(dest, src) __va_copy(dest, src)
# elif defined(HAVE_VA_LIST_ASSIGNMENT)
# define VA_COPY(dest, src) ((dest) = (src))
# else
# define VA_COPY(dest, src) memcpy(&(dest), &(src), sizeof(va_list))
# endif
#endif /* !VA_COPY */

#define INIT_SZ 128

Expand Down
3 changes: 2 additions & 1 deletion c89stringutils/c89stringutils_string_extras.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ extern "C" {
#if defined(_MSC_VER)
#define NUM_FORMAT "%I64d"
#else
#define NUM_FORMAT "%lld"
/* Fix:- Change from C99 long long to long */
#define NUM_FORMAT "%ld"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might want to guard this behind an if c89 do lld else do ld

#endif

#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \
Expand Down
Binary file removed cmake/BundleIcon.icns
Binary file not shown.
7 changes: 0 additions & 7 deletions cmake/CTestConfig.cmake

This file was deleted.

4 changes: 1 addition & 3 deletions cmake/Config.cmake.in
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@

@PACKAGE_INIT@

include ( "${CMAKE_CURRENT_LIST_DIR}/c89stringutilsTargets.cmake" )
include("${CMAKE_CURRENT_LIST_DIR}/c89stringutilsTargets.cmake")
Binary file removed cmake/CustomVolumeIcon.icns
Binary file not shown.
14 changes: 0 additions & 14 deletions cmake/Info.plist

This file was deleted.

8 changes: 7 additions & 1 deletion cmake/LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
(Apache-2.0 OR MIT)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You posted the wrong license text, use SPDX expression

Copyright 2020-2022 Samuel Marks (for Offscale.io)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
6 changes: 0 additions & 6 deletions cmake/MultiCPackConfig.cmake

This file was deleted.

158 changes: 157 additions & 1 deletion cmake/README.txt
Original file line number Diff line number Diff line change
@@ -1 +1,157 @@
string functions from newer standards / common non-standards for C89.
c89stringutils
==============
[![License](https://img.shields.io/badge/license-Apache--2.0%20OR%20MIT-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![CI for Linux, Windows, macOS](https://github.com/offscale/c89stringutils/actions/workflows/ci.yml/badge.svg)](https://github.com/offscale/c89stringutils/actions/workflows/ci.yml)
[![CI for FreeBSD](https://api.cirrus-ci.com/github/offscale/c89stringutils.svg)](https://cirrus-ci.com/github/offscale/c89stringutils)
![coverage](reports/test_coverage.svg)
[![C89](https://img.shields.io/badge/C-89-blue)](https://en.wikipedia.org/wiki/C89_(C_version))

C89 is missing some nice things. As is MSVC.
This adds the string related functionality for:

- **Windows**
- MSVC 2005 through MSVC 2026+
- MinGW
- Cygwin
- Open Watcom 2.0 (including **DOS** target)
- **SunOS**
- **Linux**
- ***BSD**
- **macOS**

Everything is hidden behind `ifdef`s so if the compiler/OS supports the function, that function will be used instead of
the one provided by this library.

### Architecture & Standards

- **Strict C89 Compliance:** The entire codebase strictly conforms to ISO C90 (C89), preventing compilation issues on extremely old enterprise toolchains.
- **Header Guards & C++ Interop:** Fully instrumented with `extern "C"` blocks and robust guards, playing nicely when directly `#include`d into C++ sources.
- **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.
- **Quality Metrics:** Maintains 100% Doxygen documentation and 100% test coverage locally.

### Single-File Header-Only Amalgamation (STB-style)

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!

When building the project via CMake, toggle `C89STRINGUTILS_BUILD_AMALGAMATION=ON`:
```sh
cmake -B build -DC89STRINGUTILS_BUILD_AMALGAMATION=ON
```
This generates `build/c89stringutils/c89stringutils_amalgamation.h`.

**To use the amalgamation in your project:**
Drop it into your source tree and define `C89STRINGUTILS_IMPLEMENTATION` in **exactly one** `.c` or `.cpp` file before including the header:

```c
#define C89STRINGUTILS_IMPLEMENTATION
#include "c89stringutils_amalgamation.h"

int main(void) {
char* str = NULL;
asprintf(&str, "Hello %s", "World");
free(str);
return 0;
}
```

### String functions implemented

| Function | Citation |
|-------------------------------------------------------------------------|------------------------------|
| [`strcasestr`](https://www.freebsd.org/cgi/man.cgi?query=strcasestr) | From MUSL |
| [`strncasecmp`](https://www.freebsd.org/cgi/man.cgi?query=strncasecmp) | Alias for MSVC's `_strnicmp` |
| [`strcasecmp`](https://www.freebsd.org/cgi/man.cgi?query=strcasecmp) | Alias for MSVC's `_stricmp` |
| [`snprintf`](https://www.freebsd.org/cgi/man.cgi?query=snprintf) | Mostly from WTF_StringExtras |
| [`vsnprintf`](https://www.freebsd.org/cgi/man.cgi?query=vsnprintf) | Mostly from WTF_StringExtras |
| [`strnstr`](https://www.freebsd.org/cgi/man.cgi?query=strnstr) | Mostly from WTF_StringExtras |
| [`strerrorlen_s`](https://en.cppreference.com/w/c/string/byte/strerror) | From Safe C Library |
| [`asprintf`](https://www.freebsd.org/cgi/man.cgi?query=asprintf) | From libressl-portable |

Additionally `jasprintf`, a version of `asprintf` that concatenates on successive calls.

### Dependencies

- [CMake](https://cmake.org) (3.11 for MSVC 2005 or newer versions for other targets)
- C compiler (any that work with CMake, and were released within the last 30 years)

### Configure, build, and test

```sh
cmake -S . -B build -DBUILD_TESTING=ON
cmake --build build
ctest --test-dir build -C Debug
```

**Advanced CMake Toggles:**
The build environment seamlessly supports several CDD-style switches out of the box:
* `CDD_CHARSET`: `Unicode` or `ANSI` (Sets `UNICODE` and `_UNICODE` defines).
* `CDD_THREADING`: `ON` or `OFF`.
* `CDD_LTO`: `ON` or `OFF` (Validates and sets `CMAKE_INTERPROCEDURAL_OPTIMIZATION`).
* `CDD_MSVC_RTC`: `RTC1`, `RTCu`, or `RTCs` (Automatically injects `/RTCx` flags on MSVC).

### Script to automatically build

Build, test, and package for:

- Cygwin;
- MinGW (32-bit and 64-bit);
- MSVC 2005 (32-bit and 64-bit);
- MSVC 2022 / 2026 (32-bit and 64-bit);
- OpenWatcom's DOS target (16-bit).

…by running in Command Prompt: https://github.com/offscale/win-cmake-multi-build

(also handles upload to GitHub Releases)

#### Instructions for MSVC 2005

With cmake-3.11.4 specified, do:

```sh
mkdir build_msvc2005 && cd build_msvc2005
cmake-3.11.4-win64-x64\bin\cmake -DCMAKE_WARN_VS8=OFF -DCMAKE_BUILD_TYPE="Debug" -G "Visual Studio 8 2005" ..
cmake-3.11.4-win64-x64\bin\cmake --build .
cmake-3.11.4-win64-x64\bin\ctest -C Debug
```

(the last two commands can be run by opening the solution in Visual Studio 2005)

Alternatively with newer versions of CMake (tested 3.26.3):

```sh
mkdir build_msvc_nmake2005 && cd build_msvc_nmake2005
cmake -DCMAKE_BUILD_TYPE="Debug" -G "NMake Makefiles" ..
cmake --build .
ctest -C Debug
```

#### Instructions for Open Watcom (DOS target)

With v2 from https://github.com/open-watcom/open-watcom-v2/releases installed:

```sh
[path]\WATCOM\owsetenv.bat
mkdir build_dos && cd build_dos
cmake -G "Watcom WMake" -D CMAKE_SYSTEM_NAME "DOS" -D CMAKE_SYSTEM_PROCESSOR "I86" ..
cmake --build .
ctest -C Debug
```

(that test phase might fail if you're running this on a non-DOS host)

---

## License

Licensed under either of

- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or <https://www.apache.org/licenses/LICENSE-2.0>)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or <https://opensource.org/licenses/MIT>)

at your option.

### Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.
3 changes: 0 additions & 3 deletions cmake/Welcome.txt
Original file line number Diff line number Diff line change
@@ -1,3 +0,0 @@
string functions from newer standards / common non-standards for C89

https://github.com/offscale/c89stringutils
11 changes: 2 additions & 9 deletions cmake/config.h.in
Original file line number Diff line number Diff line change
@@ -1,9 +1,2 @@
#ifndef C89STRINGUTILS_CONFIG_H
#define C89STRINGUTILS_CONFIG_H

#define C89STRINGUTILS_VERSION_MAJOR @c89stringutils_VERSION_MAJOR@
#define C89STRINGUTILS_VERSION_MINOR @c89stringutils_VERSION_MINOR@
#define C89STRINGUTILS_VERSION_PATCH @c89stringutils_VERSION_PATCH@
#define C89STRINGUTILS_VERSION "@c89stringutils_VERSION@"

#endif /* C89STRINGUTILS_CONFIG_H */
#define c89stringutils_VERSION_MAJOR @c89stringutils_VERSION_MAJOR@
#define c89stringutils_VERSION_MINOR @c89stringutils_VERSION_MINOR@