paul_string.h

Includes:
<stdint.h>
<stdlib.h>
<string.h>
<wchar.h>
<stdbool.h>

Introduction

Unified ascii+wide string type for C/C++.

Discussion

Implementation is included when PAUL_STRING_IMPLEMENTATION or PAUL_IMPLEMENTATION is defined.

Updated:
Saturday, July 19, 2025


Functions

str_append_char

Append a single ASCII character to an ASCII `str_t`.

str_char_at

Get the ASCII character at the specified index.

str_cmp

Compare two `str_t` values. Returns <0, 0, >0 similar to strcmp/wcscmp.

str_concat

Concatenate src to the end of *dest (dest is resized as needed).

str_copy

Copy the contents of src into dest. Both must be the same underlying type.

str_dup

Duplicate a string handle.

str_ends_with

Return true when s ends with suffix.

str_equal

Equality test between two `str_t` values.

str_erase

Erase len characters from *s starting at pos.

str_find

Find the first occurrence of substr in s.

str_find_char

Find the first occurrence of ASCII character c in s (ASCII only).

str_from_cstr

Create a `str_t` from a NUL-terminated C string (ASCII).

str_from_wcstr

Create a `str_t` from a NUL-terminated wide string (wchar_t).

str_insert

Insert substr into *s at position pos.

str_is_ascii

Query whether the `str_t` stores ASCII (narrow) characters.

str_is_utf16

Query whether the `str_t` stores wide (wchar_t) characters.

str_length

Get the length of the string in characters.

str_make_ascii

Convert a `str_t` to an ASCII representation.

str_make_utf16

Convert a `str_t` to a wide (wchar_t) representation.

str_raw_cstr

Return a raw NUL-terminated C string pointer for ASCII `str_t`.

str_raw_wcstr

Return a raw NUL-terminated wide string pointer for wide `str_t`.

str_replace

Replace the first occurrence of old_sub in *s with new_sub.

str_resize

Resize a `str_t` in-place to new length (truncates or extends with NUL).

str_starts_with

Return true when s starts with prefix.

str_to_lower

Convert the string in-place to lower-case.

str_to_upper

Convert the string in-place to upper-case.

str_trim

Trim leading and trailing whitespace (ASCII only) from *s.

str_wchar_at

Get the wide character at the specified index.

str_wildcard_ascii

Match ASCII `str_t` against a glob-style pattern using '*', '?', and character classes like [a-z] or [^aeiou].

str_wildcard_wide

Match wide `str_t` against a wide glob-style pattern (wchar_t pattern).


str_append_char


Append a single ASCII character to an ASCII `str_t`.

void str_append_char(
    str_t *s,
    char c);  
Parameters
s

Pointer to an ASCII `str_t`.

c

Character to append.


str_char_at


Get the ASCII character at the specified index.

char str_char_at(
    const str_t s,
    size_t index);  
Parameters
s

The ASCII str_t handle.

index

The index (0-based).

Return Value

The character, or 0 if out of bounds or not ASCII.


str_cmp


Compare two `str_t` values. Returns <0, 0, >0 similar to strcmp/wcscmp.

int str_cmp(
    const str_t a,
    const str_t b);  
Parameters
a

First string.

b

Second string.


str_concat


Concatenate src to the end of *dest (dest is resized as needed).

void str_concat(
    str_t *dest,
    const str_t src);  
Parameters
dest

Pointer to destination `str_t` handle.

src

Source `str_t` to append.


str_copy


Copy the contents of src into dest. Both must be the same underlying type.

void str_copy(
    str_t dest,
    const str_t src);  
Parameters
dest

Destination `str_t` data pointer.

src

Source `str_t`.


str_dup


Duplicate a string handle.

str_t str_dup(
    const str_t s);  
Parameters
s

A `str_t` previously returned by the library.

Return Value

A new `str_t` owning a copy of the string, or NULL on allocation failure.


str_ends_with


Return true when s ends with suffix.

bool str_ends_with(
    const str_t s,
    const str_t suffix);  
Parameters
s

String to test.

suffix

Suffix string.


str_equal


Equality test between two `str_t` values.

bool str_equal(
    const str_t a,
    const str_t b);  
Parameters
a

First string.

b

Second string.

Return Value

true when equal, false otherwise.


str_erase


Erase len characters from *s starting at pos.

void str_erase(
    str_t *s,
    size_t pos,
    size_t len);  
Parameters
s

Pointer to `str_t`.

pos

Start index.

len

Number of characters to remove.


str_find


Find the first occurrence of substr in s.

size_t str_find(
    const str_t s,
    const str_t substr);  
Parameters
s

The string to search.

substr

The substring to find.

Return Value

Index of first match or (size_t)-1 if not found.


str_find_char


Find the first occurrence of ASCII character c in s (ASCII only).

size_t str_find_char(
    const str_t s,
    char c);  
Parameters
s

The ASCII string to search.

c

Character to find.

Return Value

Index or (size_t)-1 if not found.


str_from_cstr


Create a `str_t` from a NUL-terminated C string (ASCII).

str_t str_from_cstr(
    const char *cstr);  
Parameters
cstr

NUL-terminated ASCII string.

Return Value

A new `str_t` representing the same contents.

Discussion

This function is the target of the `str_from` / `str` helper macros when called with a `const char *` (see the macro documentation above). Use the macros when convenient; you may call this function directly when generics are not available.


str_from_wcstr


Create a `str_t` from a NUL-terminated wide string (wchar_t).

str_t str_from_wcstr(
    const wchar_t *cstr);  
Parameters
cstr

NUL-terminated wide string.

Return Value

A new `str_t` representing the same contents as wide characters.

Discussion

This function is the wide-string variant targeted by the `str_from` / `str` helper macros when called with `const wchar_t *`.


str_insert


Insert substr into *s at position pos.

void str_insert(
    str_t *s,
    size_t pos,
    const str_t substr);  
Parameters
s

Pointer to destination `str_t` handle.

pos

Insertion index (must be <= length).

substr

Substring to insert.


str_is_ascii


Query whether the `str_t` stores ASCII (narrow) characters.

bool str_is_ascii(
    const str_t s);  
Parameters
s

The `str_t` handle.

Return Value

true when ASCII, false otherwise.


str_is_utf16


Query whether the `str_t` stores wide (wchar_t) characters.

bool str_is_utf16(
    const str_t s);  
Parameters
s

The `str_t` handle.

Return Value

true when wide, false otherwise.


str_length


Get the length of the string in characters.

size_t str_length(
    const str_t s);  
Parameters
s

The str_t handle.

Return Value

The number of characters (not including NUL).


str_make_ascii


Convert a `str_t` to an ASCII representation.

Parameters
s

The source `str_t`.

Return Value

A new ASCII `str_t` or NULL on failure.

Discussion

If the string is already ASCII this returns a duplicate. If the source contains non-ASCII characters the function will return NULL.


str_make_utf16


Convert a `str_t` to a wide (wchar_t) representation.

Parameters
s

The source `str_t`.

Return Value

A new wide `str_t` or NULL on failure.

Discussion

If the string is already wide this returns a duplicate.


str_raw_cstr


Return a raw NUL-terminated C string pointer for ASCII `str_t`.

const char* str_raw_cstr(
    const str_t s);  
Parameters
s

The `str_t` handle.

Return Value

Pointer to NUL-terminated char data when ASCII, otherwise NULL.


str_raw_wcstr


Return a raw NUL-terminated wide string pointer for wide `str_t`.

const wchar_t* str_raw_wcstr(
    const str_t s);  
Parameters
s

The `str_t` handle.

Return Value

Pointer to NUL-terminated wchar_t data when wide, otherwise NULL.


str_replace


Replace the first occurrence of old_sub in *s with new_sub.

void str_replace(
    str_t *s,
    const str_t old_sub,
    const str_t new_sub);  
Parameters
s

Pointer to `str_t` to modify.

old_sub

Substring to replace.

new_sub

Replacement substring.


str_resize


Resize a `str_t` in-place to new length (truncates or extends with NUL).

void str_resize(
    str_t *s,
    size_t new_len);  
Parameters
s

Pointer to the `str_t` handle to resize.

new_len

New length in characters (not including NUL).


str_starts_with


Return true when s starts with prefix.

bool str_starts_with(
    const str_t s,
    const str_t prefix);  
Parameters
s

String to test.

prefix

Prefix string.


str_to_lower


Convert the string in-place to lower-case.

void str_to_lower(
    str_t *s);  
Parameters
s

Pointer to `str_t`.

Discussion

Works for ASCII and wide strings.


str_to_upper


Convert the string in-place to upper-case.

void str_to_upper(
    str_t *s);  
Parameters
s

Pointer to `str_t`.

Discussion

Works for ASCII and wide strings.


str_trim


Trim leading and trailing whitespace (ASCII only) from *s.

void str_trim(
    str_t *s);  
Parameters
s

Pointer to ASCII `str_t`.


str_wchar_at


Get the wide character at the specified index.

wchar_t str_wchar_at(
    const str_t s,
    size_t index);  
Parameters
s

The wide str_t handle.

index

The index (0-based).

Return Value

The wide character, or 0 if out of bounds or not wide.


str_wildcard_ascii


Match ASCII `str_t` against a glob-style pattern using '*', '?', and character classes like [a-z] or [^aeiou].

bool str_wildcard_ascii(
    const str_t s,
    const char *pattern);  
Parameters
s

The ASCII `str_t` to test.

pattern

NUL-terminated pattern using ASCII characters.

Return Value

true on match, false otherwise.

Discussion

This is the ASCII helper invoked by the `str_wildcard` macro when `_Generic` is available and the argument is an ASCII `const char *`.


str_wildcard_wide


Match wide `str_t` against a wide glob-style pattern (wchar_t pattern).

bool str_wildcard_wide(
    const str_t s,
    const wchar_t *pattern);  
Parameters
s

The wide `str_t` to test.

pattern

NUL-terminated wide pattern using `wchar_t` characters.

Return Value

true on match, false otherwise.

Discussion

This is the wide helper invoked by the `str_wildcard` macro when `_Generic` is available and the argument is a `const wchar_t *`.


Typedefs

str_t

Opaque string handle used by the paul string API.


str_t


Opaque string handle used by the paul string API.

typedef void* str_t;  
Discussion

A `str_t` points to an internal buffer allocated by the paul library that stores either an ASCII (char) or wide (wchar_t) string. The implementation stores a small header placed immediately before the returned data pointer to track the stored type and the character length. Callers must treat `str_t` as an opaque handle and use the provided API functions to manipulate strings.


Macro Definitions

str

Shortcut wrapper that calls `str_from` and constructs a `str_t` from a literal or pointer.

str_from

Convenience generic constructor that selects `str_from_cstr` or `str_from_wcstr`.

str_wildcard

Generic wildcard matcher dispatcher.


str


Shortcut wrapper that calls `str_from` and constructs a `str_t` from a literal or pointer.

#define str(S) \ 
    _Generic((S), \ 
    const char *: str_from_cstr(S), \ 
    const wchar_t *: str_from_wcstr(S), \ 
    char *: str_from_cstr(S), \ 
    wchar_t *: str_from_wcstr(S), \ 
    default: NULL)(S) 
Discussion

See `str_from` for details. This macro is handy when passing string literals directly (it will pick the correct constructor based on the literal's type).


str_from


Convenience generic constructor that selects `str_from_cstr` or `str_from_wcstr`.

#define str_from(S) \ 
    _Generic((S), \ 
    const char *: str_from_cstr, \ 
    const wchar_t *: str_from_wcstr, \ 
    char *: str_from_cstr, \ 
    wchar_t *: str_from_wcstr, \ 
    default: NULL)(S) 
Discussion

When the compiler supports C11 `_Generic` selections this macro dispatches at compile-time based on the type of the argument. It expands to `str_from_cstr(const char*)` for narrow C strings and to `str_from_wcstr(const wchar_t*)` for wide strings. If `_Generic` is not available then `PAUL_NO_GENERICS` is defined and these macros are not provided.


str_wildcard


Generic wildcard matcher dispatcher.

#define str_wildcard(S, P) \ 
    _Generic((S), \ 
    const char *: str_wildcard_ascii, \ 
    char *: str_wildcard_ascii, \ 
    const wchar_t *: str_wildcard_wide, \ 
    wchar_t *: str_wildcard_wide, \ 
    default: NULL)(S, P) 
Discussion

When `_Generic` is available this macro selects `str_wildcard_ascii` or `str_wildcard_wide` based on the type of the first argument. If `_Generic` is not available the macro is omitted and callers must call the correct helper directly.