Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
106 commits
Select commit Hold shift + click to select a range
902ab0b
general boilerplate / project-support improvements (#16)
synesissoftware Aug 9, 2026
ee3e693
squash-commit
synesissoftware Aug 9, 2026
4526cb5
4.0.14
synesissoftware Aug 9, 2026
52e55d8
fix
synesissoftware Aug 9, 2026
c5e1400
Merge branch 'master' into 'dev'
synesissoftware Aug 9, 2026
a1cc131
4.0.15 (#20)
mwsis Sep 6, 2026
5517777
markdown
synesissoftware Sep 16, 2026
72487c5
chore(c-cpp): union files.associations from ~/dev vscode settings
synesissoftware Sep 16, 2026
a708e89
.gitattributes
synesissoftware Sep 17, 2026
e140930
.vscode/settings.json
synesissoftware Sep 17, 2026
39738e2
.vimrc
synesissoftware Sep 17, 2026
c51736e
CHANGES.md
synesissoftware Sep 17, 2026
93fbbfa
chore(<lib>): use computed PREFIX_VER with documented PATCH
synesissoftware Sep 17, 2026
277e74f
test(<lib>): ship scratch libver version reporter
synesissoftware Sep 17, 2026
9a77dbb
test(<lib>): rename scratch libver to versions
synesissoftware Sep 17, 2026
bce400d
test: add canonical scratch versions reporter
synesissoftware Sep 17, 2026
a7fc836
.gitattributes
synesissoftware Sep 21, 2026
3948256
fix(c-cpp): quote Dir resolution in CMake helper scripts
synesissoftware Sep 21, 2026
6b044ee
Merge branch 'master' into 'dev'
synesissoftware Sep 22, 2026
27af964
Merge branch 'dev' into 'boilerplate'
synesissoftware Sep 22, 2026
6455ea4
chore(scratch test): **versions** => **test.scratch.version**
synesissoftware Sep 22, 2026
1c9819a
doc(README.md): adding afferent dependencies (**errni**, **rstrip**)
synesissoftware Sep 22, 2026
91c2b4b
feat(cstring): colour prepare_cmake and unify cmake configure
synesissoftware Sep 22, 2026
ad2a143
feat(cstring): force colours via env and -A in prepare_cmake
synesissoftware Sep 22, 2026
b121a6f
refactor(cstring): drive prepare builds with cmake --build
synesissoftware Sep 22, 2026
12078a7
refactor(cstring): drive build_cmake via cmake --build
synesissoftware Sep 22, 2026
e524810
refactor(cstring): drive clean_cmake via cmake --build --target clean
synesissoftware Sep 22, 2026
a078db8
refactor(cstring): align remove_cmake_artefacts with helper dialect
synesissoftware Sep 22, 2026
4f30aba
refactor(cstring): drive ctest_cmake via cmake --build then ctest
synesissoftware Sep 22, 2026
bc54b6e
refactor(cstring): unit/component runners use sis_cmake_build dialect
synesissoftware Sep 22, 2026
aa62ebb
fix(cstring): accept category-only flags; fix CI component runner
synesissoftware Sep 22, 2026
9e5083c
refactor(cstring): drive run_all_examples via cmake --build dialect
synesissoftware Sep 22, 2026
45bb3bb
fix(cstring): gate cstring_vector no-arg demo on SIS_EXAMPLE_SMOKE
synesissoftware Sep 22, 2026
d30ab59
refactor(cstring): drive run_all_scratch via cmake --build dialect
synesissoftware Sep 22, 2026
7e77034
refactor(cstring): native CMD runners for unit, component, examples
synesissoftware Sep 22, 2026
66fd7b4
feat(cstring): add run_all_automated_tests aggregate (.sh/.cmd)
synesissoftware Sep 22, 2026
b54e4c6
refactor(cstring): drive run_all_performance via cmake --build dialect
synesissoftware Sep 22, 2026
b0b25cd
style(cstring): SisClr polish on run_all_automated_tests.sh
synesissoftware Sep 22, 2026
dbf5e80
ci(cstring): exercise prepare/build/clean helpers in CI
synesissoftware Sep 22, 2026
c95dc2d
ci(cstring): dogfood native run_all *.cmd on Windows cells
synesissoftware Sep 22, 2026
7ddfd90
ci(cstring): dogfood prepare/build in cells; order test jobs
synesissoftware Sep 22, 2026
f29cff5
ci(cstring): invoke ctest, remove, and automated helpers
synesissoftware Sep 22, 2026
fed0f53
fix(cstring): harden prepare empty-args and multi-config ctest
synesissoftware Sep 22, 2026
9f62cae
ci(cstring): dogfood run_all_automated_tests.cmd on Windows
synesissoftware Sep 22, 2026
6a622c2
ci(cstring): collapse cell suites into one post-build test job
synesissoftware Sep 22, 2026
57b6486
docs(cstring): target 4.0.16 release for 23 September 2026
synesissoftware Sep 23, 2026
47669c5
feat(cstring): add competitive performance tests for 4.0.17
synesissoftware Sep 23, 2026
205b5e3
test(cstring): time ifstream getline in the file-lines suite
synesissoftware Sep 23, 2026
5608670
test(cstring): pair borrowed_fixed_assign with std::string
synesissoftware Sep 23, 2026
031564c
prep
synesissoftware Sep 23, 2026
fb9b3f8
perf(cstring): copy known lengths with memcpy
synesissoftware Sep 23, 2026
6f7cde6
perf(cstring): grow vector inserts by 3/2
synesissoftware Sep 23, 2026
474547c
refactor(impl): simplification
synesissoftware Sep 23, 2026
836d67a
perf(cstring): free on destroy instead of realloc
synesissoftware Sep 23, 2026
aa357f7
fix(cstring): shift vector elements on insertAt
synesissoftware Sep 23, 2026
7e21244
perf(cstring): skip allocation for empty strings
synesissoftware Sep 23, 2026
c7f0082
perf(cstring): append in place when capacity fits
synesissoftware Sep 23, 2026
a78263f
refactor(impl): added common internal helper `cstring_vector_destroy_…
synesissoftware Sep 23, 2026
3686ada
refactor(impl): added common internal helper `cstring_vector_init_emp…
synesissoftware Sep 23, 2026
ecb49fa
tidying
synesissoftware Sep 26, 2026
d26faab
squash-commit
synesissoftware Sep 26, 2026
14fbc4f
squash-commit
synesissoftware Sep 27, 2026
818eff0
Merge branch 'dev' into 'perf-optimisations'
synesissoftware Sep 27, 2026
8b3e261
Perf tests (#22)
mwsis Sep 27, 2026
cc85bf7
More component tests (#23)
synesissoftware Sep 27, 2026
589c51f
fix
synesissoftware Sep 27, 2026
f17597a
Flags fixes (#24)
synesissoftware Sep 27, 2026
eb9fd45
squash-commit
synesissoftware Sep 27, 2026
7783fc2
Merge branch 'dev' into 'perf-optimisations'
synesissoftware Sep 27, 2026
d0840e6
version
synesissoftware Sep 27, 2026
d302239
Merge branch 'dev' into 'perf-optimisations'
synesissoftware Sep 27, 2026
91e63f1
chore: trivial ordering
synesissoftware Sep 27, 2026
9dd8d4c
TODO.md
synesissoftware Sep 27, 2026
aa0b4e0
TODO.md
synesissoftware Sep 27, 2026
0af6b71
fix
synesissoftware Sep 27, 2026
9da3ff7
Merge branch 'dev' into 'perf-optimisations'
synesissoftware Sep 27, 2026
8606170
fix
synesissoftware Sep 27, 2026
85c52c8
fix(cstring): gate Windows arenas on `_WIN32` for 4.1.0 (#25)
synesissoftware Sep 29, 2026
864bdb5
Merge branch 'dev' into 'perf-optimisations'
synesissoftware Sep 29, 2026
def3924
test(cstring): time Windows global, process-heap, and COM task arenas…
synesissoftware Sep 29, 2026
87eb7f8
Merge branch 'dev' into 'perf-optimisations'
synesissoftware Sep 29, 2026
e460f9f
squash-commit (test.performance.cstring_readline)
synesissoftware Sep 27, 2026
2c16779
Merge branch 'dev' into 'perf-optimisations'
synesissoftware Sep 29, 2026
0de2177
date
synesissoftware Sep 29, 2026
e7be85e
Merge branch 'dev' into 'perf-optimisations'
synesissoftware Sep 29, 2026
218afc4
portability
synesissoftware Sep 29, 2026
36603b0
test(cstring): use auto_buffer in borrowed_fixed_assign harness
synesissoftware Sep 29, 2026
1e0bc91
(fix(performance tests): `scenario_borrowed_fixed_assign()` all ancho…
synesissoftware Sep 29, 2026
e1ff75e
feature(performance tests): added `scenario_borrowed_fixed_construct()`
synesissoftware Sep 29, 2026
e18e915
Merge branch 'dev' into 'perf-optimisations'
synesissoftware Sep 29, 2026
a467c4a
fix(cstring): silence GCC free-nonheap-object in the perf harness
synesissoftware Sep 29, 2026
e057536
misc
synesissoftware Sep 29, 2026
def0488
Merge branch 'dev' into 'perf-optimisations'
synesissoftware Sep 29, 2026
72ef8b8
fix(cstring): initialise COM before Windows task-allocator tests
synesissoftware Sep 29, 2026
06111ac
Internal refac (#35)
synesissoftware Sep 29, 2026
656523b
Merge branch 'dev' into 'perf-optimisations'
synesissoftware Sep 29, 2026
d25a654
misc
synesissoftware Sep 29, 2026
f88daf1
Merge branch 'dev' into 'perf-optimisations'
synesissoftware Sep 30, 2026
13a628d
`cstring_readline()` fix for readonly string (#38)
synesissoftware Oct 3, 2026
8780363
fix: `cstring_readline()` (#37)
synesissoftware Oct 3, 2026
74ece39
Merge branch 'dev' into 'perf-optimisations'
synesissoftware Oct 3, 2026
41319ff
feature(performance tests): added `scenario_append_len_inc8()`
synesissoftware Oct 3, 2026
178d40a
test(cstring): shorten test directories and name cases in `TEST_` for…
synesissoftware Oct 3, 2026
af19397
release
synesissoftware Oct 4, 2026
91d029a
test(cstring): add a C unit suite and shorten example and test names …
synesissoftware Oct 4, 2026
476da2a
Merge branch 'dev' into 'perf-optimisations'
synesissoftware Oct 4, 2026
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 .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on:
- rc1
- rc2
- rc3
- perf-tests-win
- directories
pull_request:

concurrency:
Expand Down
26 changes: 26 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,32 @@
# cstring - Changes <!-- omit in toc -->


## 4.2.0 - 6th October 2026

* performance optimisations;


## 4.0.19 - 4th October 2026

* Corrected `cstring_readline()` so `numRead` counts every character read from the stream for the line, including the terminator; CR and LF are not stored;
* Treated a lone CR (not followed by LF, including CR at end of stream) as a line terminator that returns `CSTRING_RC_SUCCESS` and pushes the following character back;
* Freed a zero-size realloc-arena block on every platform (`realloc(pv, 0)` allocates on some), leaving a `NULL` pointer unchanged;
* `cstring_readline()` returns the result of its opening `cstring_truncate()`, so a readonly destination yields `CSTRING_RC_READONLY` for an empty line or immediate end of file, and the payload and stream position are left unchanged;
* Suppressed the GCC 15 `-Wfree-nonheap-object` false positive on inlined `stlsoft::auto_buffer` destruction in **test.performance.cstring**;
* Documented memory contracts, allocators, and a default-use sketch in **README.md**, including `cstring_getStatusCodeStringLength()`, `CSTRING_VER`, and the default and index macros;
* Added **test.performance.cstring_readline** (filesystem timings gated on **p99**);
* Added **test.component.cstring_readline** case `TEST_cstring_readline_READONLY_RETAINS_PAYLOAD`;
* Added single-line LF, CRLF, and CR cases to **test.component.cstring_readline**; **test.component.cstring_vector_readLines** splits an embedded CR into its own line;
* Added borrowed-fixed construct and assign scenarios to **test.performance.cstring**, using `stlsoft::auto_buffer` for the borrowed anchor;
* Split regular unit-test into **test.unit.cstring** (C) and **unit.cstring.cxx** (C++);
* Shared component file fixtures in **test/component/component_fixture.hpp**, and shared `time_iterations`, `emit_row`, and `write_lines_file` in **test/performance/perf_harness.hpp**;
* Named unit cases `TEST_` in shouting snake case, keeping each API or type in its real spelling, and switched assertions to the terse xTests API;
* Passed `temp_file::CloseOnOpen` in **test.component.cstring_readline** so the creating handle is closed before `fopen`, which Windows otherwise rejects as a sharing violation;
* Removed empty unit cases and unused temporary-file names;
* Shortened unit-test directories under **test/unit/** to the subject: **auto-buffer** (**test.unit.auto-buffer**, formerly **test.unit.cstring.auto_buffer**), **cstring.cxx** (**test.unit.cstring.cxx**, formerly **test.unit.cstring.1**), **insert-replace** (**test.unit.insert-replace**, formerly **test.unit.cstring.2**), **status-codes** (**test.unit.status-codes**, formerly **test.unit.cstring_getStatusCodeString**), and **cstring_vector** (**test.unit.cstring_vector**);
* Shortened example directories under **examples/** to the subject (**auto-buffer**, **cstring**, **cstring_create**, **cstring_vector**, **cstring.dynload**, **cstring.global_memory**), with CMake targets **example.c.cstring.auto_buffer**, **example.c.cstring**, **example.c.cstring_create**, **example.c.cstring_vector**, **example.cpp.cstring.dynload**, and **example.cpp.cstring.global_memory** (formerly **example.cpp.HGLOBAL_on_x64**);


## 4.0.18 - 29th September 2026

* Gated Windows arena flags and WinAPI allocators on `_WIN32` in **cstring.h** and **cstring.core.c**, so 32- and 64-bit Windows builds expose them without a `WIN32` or `WIN64` define;
Expand Down
12 changes: 6 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# Purpose: Top-level CMake lists file for cstring
#
# Created: 21st December 2023
# Updated: 29th September 2026
# Updated: 3rd October 2026
#
# ######################################################################## #

Expand Down Expand Up @@ -137,8 +137,8 @@ option(NO_SHWILD "Do not recognise shwild for xTests pattern-match assertions" O
#
# optional:
# - p99 - optional for performance tests: per-iteration percentiles
# throughout when found; also gates the filesystem file_lines vs
# cstring_vector_readLines suite (unless NO_P99);
# throughout when found; also gates the filesystem suites
# (file_lines, cstring_readline) unless NO_P99;
# - shwild - for enhanced match constructs in xTests (unless NO_SHWILD);
#
# note: NO_CSTRING_CPP_API skips C++ examples and remaining C++ tests; C
Expand Down Expand Up @@ -214,7 +214,7 @@ endif(BUILD_TESTING)

if(BUILD_TESTING)

set(xTests_REQUIRED_VERSION_ 0.26)
set(xTests_REQUIRED_VERSION_ 0.26.5)

find_package(xTests ${xTests_REQUIRED_VERSION_} REQUIRED)

Expand All @@ -236,11 +236,11 @@ if(BUILD_TESTING)
message("-- CMake package p99 found (version ${p99_VERSION})")
else()

message("-- CMake package p99 not found; performance percentiles and file_lines suite disabled")
message("-- CMake package p99 not found; performance percentiles and filesystem suites disabled")
endif()
else()

message("-- p99 recognition disabled (NO_P99); performance percentiles and file_lines suite disabled")
message("-- p99 recognition disabled (NO_P99); performance percentiles and filesystem suites disabled")
endif()
endif(BUILD_TESTING)

Expand Down
2 changes: 1 addition & 1 deletion Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

PROJECT_NAME = "cstring"
PROJECT_BRIEF = "Extensible C-style strings and vectors of such, for Unix and Windows"
PROJECT_NUMBER = 4.0.18
PROJECT_NUMBER = 4.2.0

# Prefer SIS_CMAKE_BUILD_DIR-aligned output (same convention as Diagnosticism).
# ./dox/ remains gitignored for legacy/local runs that override OUTPUT_DIRECTORY.
Expand Down
6 changes: 3 additions & 3 deletions FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,10 @@ require **STLSoft** and **xTests** (and may optionally recognise **shwild**).
## Q5: "How do I build without the C++ examples and tests?"

Pass `--no-cpp` (or `-C`) to **prepare_cmake.sh**, which sets CMake
`NO_CSTRING_CPP_API=ON`. That omits C++ examples and remaining C++ tests.
`NO_CSTRING_CPP_API=ON`. That omits C++ examples and **test.unit.cstring.cxx**.

The **C** unit-tests still require **STLSoft** and **xTests** unless you also
pass `--disable-testing` / `-T`.
The **C** unit-tests, including **test.unit.cstring**, still require
**STLSoft** and **xTests** unless you also pass `--disable-testing` / `-T`.


## Q6: "Where are the examples?"
Expand Down
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
| Date | News Item | Details |
| ------------------- | -------------------------------- | ------- |
| Available from [**cstring** project on GitHub](https://synesissoftware.com/cstring): |
| 5th October 2026 | Release of [cstring 4.2.0](https://github.com/synesissoftware/cstring/releases/tag/4.2.0) | Performance optimisations |
| 4th October 2026 | Release of [cstring 4.0.19](https://github.com/synesissoftware/cstring/releases/tag/4.0.19) | lone CR ends a line; `numRead` includes EOL; readonly truncate; zero-size realloc frees; **test.performance.cstring_readline**; shortened test and example directories; **test.unit.cstring**; README usage modes |
| 29th September 2026 | Release of [cstring 4.0.18](https://github.com/synesissoftware/cstring/releases/tag/4.0.18) | `_WIN32` arena gate; **win.c**; static `CoTaskMem*` (**ole32**) |
| 29th September 2026 | Release of [cstring 4.0.17](https://github.com/synesissoftware/cstring/releases/tag/4.0.17) | Perf tests; `insertAt` fix; component I/O; Windows arena rename |
| 27th September 2026 | Release of [cstring 4.0.16](https://github.com/synesissoftware/cstring/releases/tag/4.0.16) | Phase 4b helpers, native `.cmd`, CI dogfood |
Expand Down
107 changes: 95 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
# cstring <!-- omit in toc -->

**C**-style **string**s is a small, standalone library, that provides extensible C-style string instances and extensible arrays of such, for Unix and Windows.
Small standalone C library that provides extensible C-style strings and extensible arrays of those strings, for Unix and Windows.


![C](https://img.shields.io/badge/C-00599C?style=flat&logo=c&logoColor=white)
![C++](https://img.shields.io/badge/C%2B%2B-00599C?style=flat&logo=c%2B%2B&logoColor=white)
[![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
[![GitHub release](https://img.shields.io/github/v/release/synesissoftware/cstring.svg)](https://github.com/synesissoftware/cstring/releases/latest)
[![Last Commit](https://img.shields.io/github/last-commit/synesissoftware/cstring)](https://github.com/synesissoftware/cstring/commits/master)
Expand All @@ -14,9 +13,14 @@
## Table of Contents <!-- omit in toc -->

- [Introduction](#introduction)
- [Usage modes](#usage-modes)
- [Default use](#default-use)
- [Storage contract](#storage-contract)
- [Allocators](#allocators)
- [Installation](#installation)
- [Components](#components)
- [Types](#types)
- [Constants](#constants)
- [String API](#string-api)
- [Status and capacity](#status-and-capacity)
- [Creation/destruction functions](#creationdestruction-functions)
Expand All @@ -34,9 +38,79 @@

## Introduction

**cstring** is a small, standalone library that provides extensible C-style string instances and extensible arrays of such, for Unix and Windows.
**cstring** provides one resizeable string, `cstring_t`, and a vector of those strings, `cstring_vector_t`. A `cstring_t` is always a length, a pointer, a capacity, and flags. The flags select a memory contract. An owned growable string is the default. Fixed, borrowed, auto-buffer, and readonly are the other contracts. Which heap owns the memory is a separate choice: `realloc` by default, and the Windows heaps where those flags exist.

The **C** API has no non-standard dependencies. Optional C++ examples and remaining C++ tests may be omitted with `--no-cpp` / `NO_CSTRING_CPP_API`. Building tests requires **STLSoft** and **xTests** (and may optionally recognise **shwild**).
The **C** API has no non-standard dependencies. Building tests requires **STLSoft** and **xTests** (and may optionally recognise **shwild**).


## Usage modes

Ordinary code uses the default contract and never sets a flag. The other contracts exist so a caller can cap growth, write into a buffer they already have, or select a Windows heap, without a second string type.


### Default use

```c
#include <cstring/cstring.h>

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
cstring_t cs;
CSTRING_RC rc = cstring_create(&cs, "Hello");

if (CSTRING_RC_SUCCESS != rc)
{
return EXIT_FAILURE;
}

printf("%s\n", cs.ptr);

cstring_destroy(&cs);

return EXIT_SUCCESS;
}
```


### Storage contract

Pass memory flags to `cstring_createEx()` or `cstring_createLenEx()`. For a borrowed buffer, `arena` is that buffer and `capacity` is its size. With no memory flags, those parameters are ignored and the string is an owned heap allocation.

| Mode | Flags | Familiar form | If it cannot grow |
| --- | --- | --- | --- |
| Owned, growable | (none) | A heap `std::string`, or Rust `String` | `CSTRING_RC_OUTOFMEMORY` |
| Owned, fixed | `CSTRING_F_MEMORY_IS_FIXED` | That same owned string, with a hard ceiling | `CSTRING_RC_EXCEEDFIXEDCAPACITY` |
| Borrowed | `CSTRING_F_MEMORY_IS_BORROWED` (implies fixed) | A caller-owned `char buf[N]`, writable up to `N` | `CSTRING_RC_EXCEEDBORROWEDCAPACITY` |
| Auto-buffer | `CSTRING_F_MEMORY_IS_BORROWED` \| `CSTRING_F_MEMORY_CAN_GROW_TO_HEAP` | **`stlsoft::auto_buffer`** / `llvm::SmallString` | Spills to the heap, then stays there |
| Readonly | `CSTRING_F_MEMORY_IS_READONLY` | A frozen instance; with borrowed, `std::string_view` or Rust `&str` | `CSTRING_RC_READONLY` |

`std::string` SSO keeps a small buffer inside the object; **cstring**'s auto-buffer uses a buffer you supply, of a size you choose, and `cstring_t` stays four fields; after a spill the instance stays on the heap (Rust's standard `String` has no SSO).

* Owned, fixed, and borrowed (including Windows allocators, where the host has them): [**example.c.cstring**](./examples/c/cstring/);
* Auto-buffer: [**example.c.cstring.auto_buffer**](./examples/c/auto-buffer/);
* Win32 global memory: [**example.cpp.cstring.global_memory**](./examples/cpp/cstring.global_memory/).


### Allocators

The arena flags apply to memory the library owns: the default heap, a fixed owned buffer, and the heap side of an auto-buffer.

| Arena | Flag | Where |
| --- | --- | --- |
| `realloc` | `CSTRING_F_USE_REALLOC` (the default) | Unix and Windows |
| Win32 global memory | `CSTRING_F_USE_WINDOWS_GLOBAL_MEMORY` | Windows |
| Process heap | `CSTRING_F_USE_WINDOWS_PROCESSHEAP_MEMORY` | Windows |
| COM task allocator | `CSTRING_F_USE_WINDOWS_COM_TASK_MEMORY` | Windows |

A few further rules:

* `cstring_init()` stores `cstring_t_DEFAULT`. That instance does not need `cstring_destroy()`. Every `cstring_create*` does;
* `cstring_yield2()` hands back an owned payload. Borrowed and readonly instances refuse it. A Windows DLL built on `realloc` returns `CSTRING_RC_CANNOTYIELDFROMSO`;
* The character type is `char` unless `CSTRING_USE_WIDE_STRINGS` is set (normally both `UNICODE` and `_UNICODE` on Windows). `CSTRING_NO_USE_WIDE_STRINGS` forces `char`. That choice is made at compile time;
* Custom arenas (`CSTRING_F_USE_CUSTOMARENAFUNCTIONS`) are declared and return `CSTRING_RC_CUSTOMARENANOTSUPPORTED`. `CSTRING_F_MEMORY_IS_OFFSET` is set by the implementation and is not a client mode.


## Installation
Expand Down Expand Up @@ -76,6 +150,15 @@ The C API is based around two structures:
```


### Constants

* `CSTRING_VER` — the composite library version;
* `cstring_t_DEFAULT` — `{ 0, NULL, 0, 0 }`, an uninitialised `cstring_t`. `cstring_init()` assigns this;
* `cstring_vector_t_DEFAULT` — the same shape for a `cstring_vector_t`;
* `cstring_vector_DEFAULT_CAPACITY` — sentinel (`~(size_t)0`) passed to creators so the implementation chooses the capacity;
* `CSTRING_FROM_END(x)` — reverse index for `cstring_insert()`, `cstring_insertLen()`, `cstring_replace()`, and `cstring_replaceLen()`;


### String API

Defined in **cstring/cstring.h**:
Expand All @@ -84,6 +167,7 @@ Defined in **cstring/cstring.h**:
#### Status and capacity

* `cstring_getStatusCodeString()` — returns a nul-terminated description of a `CSTRING_RC` code;
* `cstring_getStatusCodeStringLength()` — returns the length of that description, or 0 if the code is not recognised;
* `cstring_setCapacity()` — adjusts capacity (subject to fixed / borrowed / readonly rules);
* `cstring_yield2()` — yields ownership of the payload (and raw buffer) to the caller;

Expand Down Expand Up @@ -134,16 +218,16 @@ Defined in **cstring/cstring.vector.h**:

## Examples

Examples live under **examples/** (`c/` and `cpp/`), each with a short **README.md**. Build them with `BUILD_EXAMPLES` (on by default); run via **run_all_examples.sh**.
Examples live under **examples/** (`c/` and `cpp/`). The directory is the subject; the built program is `example.<lang>.<subject>`. Each has a short **README.md**. Build them with `BUILD_EXAMPLES` (on by default); run via **run_all_examples.sh**.

| Example | Language | Notes |
| ------- | -------- | ----- |
| [**example.c.auto_buffer**](./examples/c/example.c.auto_buffer/) | C | Borrowed buffer that may grow to the heap |
| [**example.c.cstring**](./examples/c/example.c.cstring/) | C | Core `cstring_t` create / assign / append / truncate / copy / swap |
| [**example.c.cstring_create**](./examples/c/example.c.cstring_create/) | C | Minimal `cstring_create()` |
| [**example.c.cstring_vector**](./examples/c/example.c.cstring_vector/) | C | Read lines into `cstring_vector_t` and sort (input path or `--`; `SIS_EXAMPLE_SMOKE` enables no-arg demo) |
| [**example.cpp.cstring.dynload**](./examples/cpp/example.cpp.cstring.dynload/) | C++ | Windows-only dynamic load of the cstring DLL |
| [**example.cpp.HGLOBAL_on_x64**](./examples/cpp/example.cpp.HGLOBAL_on_x64/) | C++ | Windows-only `CSTRING_F_USE_WINDOWS_GLOBAL_MEMORY` |
| [**example.c.cstring**](./examples/c/cstring/) | C | Core `cstring_t` create / assign / append / truncate / copy / swap |
| [**example.c.cstring.auto_buffer**](./examples/c/auto-buffer/) | C | Borrowed buffer that may grow to the heap |
| [**example.c.cstring_create**](./examples/c/cstring_create/) | C | Minimal `cstring_create()` |
| [**example.c.cstring_vector**](./examples/c/cstring_vector/) | C | Read lines into `cstring_vector_t` and sort (input path or `--`; `SIS_EXAMPLE_SMOKE` enables no-arg demo) |
| [**example.cpp.cstring.dynload**](./examples/cpp/cstring.dynload/) | C++ | Windows-only dynamic load of the cstring DLL |
| [**example.cpp.cstring.global_memory**](./examples/cpp/cstring.global_memory/) | C++ | Windows-only `CSTRING_F_USE_WINDOWS_GLOBAL_MEMORY` |


## Project Information
Expand Down Expand Up @@ -197,4 +281,3 @@ Projects in which **cstring** is used include:


<!-- ########################### end of file ########################### -->

7 changes: 6 additions & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@
* [x] ~~~Delete Visual Studio 98 files~~~ - ✅;
* [x] ~~~Delete Visual Studio 2003+ files~~~ - ✅;
* [x] ~~~discriminate on `_WIN32` in implementation (and maybe also in API)~~~ - ✅;
* [ ] check `CSTRING_USE_WINAPI_`;
* [x] ~~~check `CSTRING_USE_WINAPI_`~~~;
* [ ] custom arena(s);
* [ ] `cstring_vector_readlineEx()` that takes a flag to prevent truncate, thereby allowing client code to add to an existing string;
* [ ] when go to 5.x, change the name of `cstring_vector_readLines()` to `cstring_vector_readlines()`;
* [ ] when go to 5.x, consider use of SSO;
* [ ] when go to 5.x, consider expanding `cstring_vector_t` to allow it to own the memory of the strings it manages, such that can do a single file read and then break up into strings without allocating payload memory;


## Performance improvements
Expand All @@ -38,6 +42,7 @@
* [x] ~~~`CMAKE_INSTALL_LIBDIR` (replaces legacy `LIB_INSTALL_DIR`)~~~ - ✅;
* [x] ~~~**CTest**~~~ - ✅;
* [ ] build DLL on Windows;
* [ ] build dylib on macOS;
* [x] ~~~`/MT` build option for Visual C++ (`--msvc-mt` / `MSVC_USE_MT`)~~~ - ✅;
* [x] ~~~**shwild** dependency (testing only; `--no-shwild` / `NO_SHWILD`)~~~ - ✅;
* [x] ~~~Doxygen (**Doxyfile**, **doc/mainpage.md**, **generate_doxygen.sh**)~~~ - ✅;
Expand Down
8 changes: 4 additions & 4 deletions examples/c/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten
add_subdirectory(example.c.auto_buffer)
add_subdirectory(example.c.cstring)
add_subdirectory(example.c.cstring_create)
add_subdirectory(example.c.cstring_vector)
add_subdirectory(auto-buffer)
add_subdirectory(cstring)
add_subdirectory(cstring_create)
add_subdirectory(cstring_vector)
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten
define_example_program(example.cpp.HGLOBAL_on_x64 main.cpp)
define_example_program(example.c.cstring.auto_buffer main.c)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# example.c.auto_buffer <!-- omit in toc -->
# example.c.cstring.auto_buffer <!-- omit in toc -->


## Purpose
Expand All @@ -14,7 +14,7 @@ Built when `BUILD_EXAMPLES` is enabled (the default).
## Run

```sh
${SIS_CMAKE_BUILD_DIR:-./_build}/examples/c/example.c.auto_buffer/example.c.auto_buffer
${SIS_CMAKE_BUILD_DIR:-./_build}/examples/c/auto-buffer/example.c.cstring.auto_buffer
```


Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/* /////////////////////////////////////////////////////////////////////////
* File: examples/c/example.c.auto_buffer/main.c
* File: examples/c/auto-buffer/main.c
*
* Purpose: Example illustrating borrowed buffer growth to the heap
* (`CSTRING_F_MEMORY_IS_BORROWED` +
* `CSTRING_F_MEMORY_CAN_GROW_TO_HEAP`).
*
* Created: 28th July 2011
* Updated: 2nd August 2026
* Updated: 4th October 2026
*
* ////////////////////////////////////////////////////////////////////// */

Expand Down
Loading
Loading