NAME

libslack(str) - string module

SYNOPSIS

#include <slack/std.h>
#include <slack/str.h>

typedef struct String String;
typedef struct StringTR StringTR;

enum StringAlignment
{
    ALIGN_LEFT       = '<',
    ALIGN_RIGHT      = '>',
    ALIGN_CENTRE     = '|',
    ALIGN_CENTER     = '|',
    ALIGN_FULL       = '='
};

enum StringTROption
{
    TR_COMPLEMENT = 1,
    TR_DELETE     = 2,
    TR_SQUASH     = 4
};

typedef enum StringAlignment StringAlignment;
typedef enum StringTROption StringTROption;

String *str_create(const char *format, ...);
String *str_create_with_locker(Locker *locker, const char *format, ...);
String *str_vcreate(const char *format, va_list args);
String *str_vcreate_with_locker(Locker *locker, const char *format, va_list args);
String *str_create_sized(size_t size, const char *format, ...);
String *str_create_with_locker_sized(Locker *locker, size_t size, const char *format, ...);
String *str_vcreate_sized(size_t size, const char *format, va_list args);
String *str_vcreate_with_locker_sized(Locker *locker, size_t size, const char *format, va_list args);
String *str_copy(const String *str);
String *str_copy_unlocked(const String *str);
String *str_copy_with_locker(Locker *locker, const String *str);
String *str_copy_with_locker_unlocked(Locker *locker, const String *str);
String *str_fgetline(FILE *stream);
String *str_fgetline_with_locker(Locker *locker, FILE *stream);
void str_release(String *str);
void *str_destroy(String **str);
int str_rdlock(const String *str);
int str_wrlock(const String *str);
int str_unlock(const String *str);
int str_empty(const String *str);
int str_empty_unlocked(const String *str);
ssize_t str_length(const String *str);
ssize_t str_length_unlocked(const String *str);
char *cstr(const String *str);
ssize_t str_set_length(String *str, size_t length);
ssize_t str_set_length_unlocked(String *str, size_t length);
ssize_t str_recalc_length(String *str);
ssize_t str_recalc_length_unlocked(String *str);
String *str_clear(String *str);
String *str_clear_unlocked(String *str);
String *str_remove(String *str, ssize_t index);
String *str_remove_unlocked(String *str, ssize_t index);
String *str_remove_range(String *str, ssize_t index, ssize_t range);
String *str_remove_range_unlocked(String *str, ssize_t index, ssize_t range);
String *str_insert(String *str, ssize_t index, const char *format, ...);
String *str_insert_unlocked(String *str, ssize_t index, const char *format, ...);
String *str_vinsert(String *str, ssize_t index, const char *format, va_list args);
String *str_vinsert_unlocked(String *str, ssize_t index, const char *format, va_list args);
String *str_insert_str(String *str, ssize_t index, const String *src);
String *str_insert_str_unlocked(String *str, ssize_t index, const String *src);
String *str_append(String *str, const char *format, ...);
String *str_append_unlocked(String *str, const char *format, ...);
String *str_vappend(String *str, const char *format, va_list args);
String *str_vappend_unlocked(String *str, const char *format, va_list args);
String *str_append_str(String *str, const String *src);
String *str_append_str_unlocked(String *str, const String *src);
String *str_prepend(String *str, const char *format, ...);
String *str_prepend_unlocked(String *str, const char *format, ...);
String *str_vprepend(String *str, const char *format, va_list args);
String *str_vprepend_unlocked(String *str, const char *format, va_list args);
String *str_prepend_str(String *str, const String *src);
String *str_prepend_str_unlocked(String *str, const String *src);
String *str_replace(String *str, ssize_t index, ssize_t range, const char *format, ...);
String *str_replace_unlocked(String *str, ssize_t index, ssize_t range, const char *format, ...);
String *str_vreplace(String *str, ssize_t index, ssize_t range, const char *format, va_list args);
String *str_vreplace_unlocked(String *str, ssize_t index, ssize_t range, const char *format, va_list args);
String *str_replace_str(String *str, ssize_t index, ssize_t range, const String *src);
String *str_replace_str_unlocked(String *str, ssize_t index, ssize_t range, const String *src);
String *str_substr(const String *str, ssize_t index, ssize_t range);
String *str_substr_unlocked(const String *str, ssize_t index, ssize_t range);
String *str_substr_with_locker(Locker *locker, const String *str, ssize_t index, ssize_t range);
String *str_substr_with_locker_unlocked(Locker *locker, const String *str, ssize_t index, ssize_t range);
String *substr(const char *str, ssize_t index, ssize_t range);
String *substr_with_locker(Locker *locker, const char *str, ssize_t index, ssize_t range);
String *str_splice(String *str, ssize_t index, ssize_t range);
String *str_splice_unlocked(String *str, ssize_t index, ssize_t range);
String *str_splice_with_locker(Locker *locker, String *str, ssize_t index, ssize_t range);
String *str_splice_with_locker_unlocked(Locker *locker, String *str, ssize_t index, ssize_t range);
String *str_repeat(size_t count, const char *format, ...);
String *str_repeat_with_locker(Locker *locker, size_t count, const char *format, ...);
String *str_vrepeat(size_t count, const char *format, va_list args);
String *str_vrepeat_with_locker(Locker *locker, size_t count, const char *format, va_list args);
int str_tr(String *str, const char *from, const char *to, int option);
int str_tr_unlocked(String *str, const char *from, const char *to, int option);
int str_tr_str(String *str, const String *from, const String *to, int option);
int str_tr_str_unlocked(String *str, const String *from, const String *to, int option);
int tr(char *str, const char *from, const char *to, int option);
StringTR *tr_compile(const char *from, const char *to, int option);
StringTR *tr_compile_with_locker(Locker *locker, const char *from, const char *to, int option);
StringTR *str_tr_compile(const String *from, const String *to, int option);
StringTR *str_tr_compile_unlocked(const String *from, const String *to, int option);
StringTR *str_tr_compile_with_locker(Locker *locker, const String *from, const String *to, int option);
StringTR *str_tr_compile_with_locker_unlocked(Locker *locker, const String *from, const String *to, int option);
void tr_release(StringTR *table);
void *tr_destroy(StringTR **table);
int str_tr_compiled(String *str, StringTR *table);
int str_tr_compiled_unlocked(String *str, StringTR *table);
int tr_compiled(char *str, StringTR *table);
List *str_regexpr(const char *pattern, const String *text, int cflags, int eflags);
List *str_regexpr_unlocked(const char *pattern, const String *text, int cflags, int eflags);
List *str_regexpr_with_locker(Locker *locker, const char *pattern, const String *text, int cflags, int eflags);
List *str_regexpr_with_locker_unlocked(Locker *locker, const char *pattern, const String *text, int cflags, int eflags);
List *regexpr(const char *pattern, const char *text, int cflags, int eflags);
List *regexpr_with_locker(Locker *locker, const char *pattern, const char *text, int cflags, int eflags);
int regexpr_compile(regex_t *compiled, const char *pattern, int cflags);
void regexpr_release(regex_t *compiled);
List *str_regexpr_compiled(const regex_t *compiled, const String *text, int eflags);
List *str_regexpr_compiled_unlocked(const regex_t *compiled, const String *text, int eflags);
List *str_regexpr_compiled_with_locker(Locker *locker, const regex_t *compiled, const String *text, int eflags);
List *str_regexpr_compiled_with_locker_unlocked(Locker *locker, const regex_t *compiled, const String *text, int eflags);
List *regexpr_compiled(const regex_t *compiled, const char *text, int eflags);
List *regexpr_compiled_with_locker(Locker *locker, const regex_t *compiled, const char *text, int eflags);
String *str_regsub(const char *pattern, const char *replacement, String *text, int cflags, int eflags, int all);
String *str_regsub_unlocked(const char *pattern, const char *replacement, String *text, int cflags, int eflags, int all);
String *str_regsub_compiled(const regex_t *compiled, const char *replacement, String *text, int eflags, int all);
String *str_regsub_compiled_unlocked(const regex_t *compiled, const char *replacement, String *text, int eflags, int all);
List *str_fmt(const String *str, size_t line_width, StringAlignment alignment);
List *str_fmt_unlocked(const String *str, size_t line_width, StringAlignment alignment);
List *str_fmt_with_locker(Locker *locker, const String *str, size_t line_width, StringAlignment alignment);
List *str_fmt_with_locker_unlocked(Locker *locker, const String *str, size_t line_width, StringAlignment alignment);
List *fmt(const char *str, size_t line_width, StringAlignment alignment);
List *fmt_with_locker(Locker *locker, const char *str, size_t line_width, StringAlignment alignment);
List *str_split(const String *str, const char *delim);
List *str_split_unlocked(const String *str, const char *delim);
List *str_split_with_locker(Locker *locker, const String *str, const char *delim);
List *str_split_with_locker_unlocked(Locker *locker, const String *str, const char *delim);
List *split(const char *str, const char *delim);
List *split_with_locker(Locker *locker, const char *str, const char *delim);
List *str_regexpr_split(const String *str, const char *delim, int cflags, int eflags);
List *str_regexpr_split_unlocked(const String *str, const char *delim, int cflags, int eflags);
List *str_regexpr_split_with_locker(Locker *locker, const String *str, const char *delim, int cflags, int eflags);
List *str_regexpr_split_with_locker_unlocked(Locker *locker, const String *str, const char *delim, int cflags, int eflags);
List *regexpr_split(const char *str, const char *delim, int cflags, int eflags);
List *regexpr_split_with_locker(Locker *locker, const char *str, const char *delim, int cflags, int eflags);
String *str_join(const List *list, const char *delim);
String *str_join_unlocked(const List *list, const char *delim);
String *str_join_with_locker(Locker *locker, const List *list, const char *delim);
String *str_join_with_locker_unlocked(Locker *locker, const List *list, const char *delim);
String *join(const List *list, const char *delim);
String *join_with_locker(Locker *locker, const List *list, const char *delim);
int str_soundex(const String *str);
int str_soundex_unlocked(const String *str);
int soundex(const char *str);
String *str_trim(String *str);
String *str_trim_unlocked(String *str);
char *trim(char *str);
String *str_trim_left(String *str);
String *str_trim_left_unlocked(String *str);
char *trim_left(char *str);
String *str_trim_right(String *str);
String *str_trim_right_unlocked(String *str);
char *trim_right(char *str);
String *str_squeeze(String *str);
String *str_squeeze_unlocked(String *str);
char *squeeze(char *str);
String *str_quote(const String *str, const char *quotable, char quote_char);
String *str_quote_unlocked(const String *str, const char *quotable, char quote_char);
String *str_quote_with_locker(Locker *locker, const String *str, const char *quotable, char quote_char);
String *str_quote_with_locker_unlocked(Locker *locker, const String *str, const char *quotable, char quote_char);
String *quote(const char *str, const char *quotable, char quote_char);
String *quote_with_locker(Locker *locker, const char *str, const char *quotable, char quote_char);
String *str_unquote(const String *str, const char *quotable, char quote_char);
String *str_unquote_unlocked(const String *str, const char *quotable, char quote_char);
String *str_unquote_with_locker(Locker *locker, const String *str, const char *quotable, char quote_char);
String *str_unquote_with_locker_unlocked(Locker *locker, const String *str, const char *quotable, char quote_char);
String *unquote(const char *str, const char *quotable, char quote_char);
String *unquote_with_locker(Locker *locker, const char *str, const char *quotable, char quote_char);
String *str_encode(const String *str, const char *uncoded, const char *coded, char quote_char, int printable);
String *str_encode_unlocked(const String *str, const char *uncoded, const char *coded, char quote_char, int printable);
String *str_encode_with_locker(Locker *locker, const String *str, const char *uncoded, const char *coded, char quote_char, int printable);
String *str_encode_with_locker_unlocked(Locker *locker, const String *str, const char *uncoded, const char *coded, char quote_char, int printable);
String *str_decode(const String *str, const char *uncoded, const char *coded, char quote_char, int printable);
String *str_decode_unlocked(const String *str, const char *uncoded, const char *coded, char quote_char, int printable);
String *str_decode_with_locker(Locker *locker, const String *str, const char *uncoded, const char *coded, char quote_char, int printable);
String *str_decode_with_locker_unlocked(Locker *locker, const String *str, const char *uncoded, const char *coded, char quote_char, int printable);
String *encode(const char *str, const char *uncoded, const char *coded, char quote_char, int printable);
String *encode_with_locker(Locker *locker, const char *str, const char *uncoded, const char *coded, char quote_char, int printable);
String *decode(const char *str, const char *uncoded, const char *coded, char quote_char, int printable);
String *decode_with_locker(Locker *locker, const char *str, const char *uncoded, const char *coded, char quote_char, int printable);
String *str_lc(String *str);
String *str_lc_unlocked(String *str);
char *lc(char *str);
String *str_lcfirst(String *str);
String *str_lcfirst_unlocked(String *str);
char *lcfirst(char *str);
String *str_uc(String *str);
String *str_uc_unlocked(String *str);
char *uc(char *str);
String *str_ucfirst(String *str);
String *str_ucfirst_unlocked(String *str);
char *ucfirst(char *str);
int str_chop(String *str);
int str_chop_unlocked(String *str);
int chop(char *str);
int str_chomp(String *str);
int str_chomp_unlocked(String *str);
int chomp(char *str);
int str_bin(const String *str);
int str_bin_unlocked(const String *str);
int bin(const char *str);
int str_hex(const String *str);
int str_hex_unlocked(const String *str);
int hex(const char *str);
int str_oct(const String *str);
int str_oct_unlocked(const String *str);
int oct(const char *str);
int strcasecmp(const char *s1, const char *s2);
int strncasecmp(const char *s1, const char *s2, size_t n);
size_t strlcpy(char *dst, const char *src, size_t size);
size_t strlcat(char *dst, const char *src, size_t size);
char *cstrcpy(char *dst, const char *src);
char *cstrcat(char *dst, const char *src);
char *cstrchr(const char *str, int c);
char *cstrpbrk(const char *str, const char *brk);
char *cstrrchr(const char *str, int c);
char *cstrstr(const char *str, const char *srch);
int asprintf(char **str, const char *format, ...);
int vasprintf(char **str, const char *format, va_list args);

DESCRIPTION

This module provides text strings that grow and shrink automatically, and functions for manipulating them. Some of the functions were modelled on the list(3) module. Others were modelled on the string functions and operators in perlfunc(1) and perlop(1). Others came from OpenBSD.

String *str_create(const char *format, ...)

Creates a String specified by format and the following arguments as in sprintf(3). On success, returns the new string. It is the caller's responsibility to deallocate the new string with str_release(3) or str_destroy(3). It is strongly recommended to use str_destroy(3), because it also sets the pointer variable to null. On error, returns null with errno set appropriately.

Warning: Do not under any circumstances ever pass a non-literal string as the format argument unless you know exactly how many conversions will take place. Being careless with this is a very good way to build potential security vulnerabilities into your programs. The same is true for all functions that take a printf()-like format string as an argument.

String *str = str_create(buf);       // EVIL
String *str = str_create("%s", buf); // GOOD
String *str_create_with_locker(Locker *locker, const char *format, ...)

Equivalent to str_create(3) except that multiple threads accessing the new string will be synchronized by locker.

String *str_vcreate(const char *format, va_list args)

Equivalent to str_create(3) with the variable argument list specified directly as for vprintf(3).

String *str_vcreate_with_locker(Locker *locker, const char *format, va_list args)

Equivalent to str_vcreate(3) except that multiple threads accessing the new string will be synchronized by locker.

String *str_create_sized(size_t size, const char *format, ...)

Creates a String specified by format and the following arguments as in sprintf(3). The initial allocation for the string data is at least size bytes. On success, returns the new string. It is the caller's responsibility to deallocate the new string with str_release(3) or str_destroy(3). It is strongly recommended to use str_destroy(3), because it also sets the pointer variable to null. On error, returns null with errno set appropriately.

String *str_create_with_locker_sized(Locker *locker, size_t size, const char *format, ...)

Equivalent to str_create_sized(3) except that multiple threads accessing the new string will be synchronised by locker.

String *str_vcreate_sized(size_t size, const char *format, va_list args)

Equivalent to str_create_sized(3) with the variable argument list specified directly as for vprintf(3).

String *str_vcreate_with_locker_sized(Locker *locker, size_t size, const char *format, va_list args)

Equivalent to str_vcreate_sized(3) except that multiple threads accessing the new string will be synchronised by locker.

String *str_copy(const String *str)

Creates a copy of str. On success, returns the copy. It is the caller's responsibility to deallocate the new string with str_release(3) or str_destroy(3). It is strongly recommended to use str_destroy(3), because it also sets the pointer variable to null. On error, returns null with errno set appropriately.

String *str_copy_unlocked(const String *str)

Equivalent to str_copy(3) except that str is not read-locked.

String *str_copy_with_locker(Locker *locker, const String *str)

Equivalent to str_copy(3) except that multiple threads accessing the new string will be synchronised by locker.

String *str_copy_with_locker_unlocked(Locker *locker, const String *str)

Equivalent to str_copy_with_locker(3) except that str is not read-locked.

String *str_fgetline(FILE *stream)

Similar to fgets(3) except that it recognises UNIX ("\n"), DOS/Windows ("\r\n") and old Macintosh ("\r") line endings (even different line endings in the same file), and it can read a line of any size into the String that it returns. Reading stops after the EOF, or after the end of the line is reached. Line endings are always stored as a single "\n" character. A nul is placed after the last character in the buffer. On success, returns a new String. It is the caller's responsibility to deallocate the new string with str_release(3) or str_destroy(3). It is strongly recommended to use str_destroy(3), because it also sets the pointer variable to null. On error, or when the end of file occurs while no characters have been read, returns null. Calls to this function can be mixed with calls to other input functions from the stdio library on the same input stream.

String *str_fgetline_with_locker(Locker *locker, FILE *stream)

Equivalent to str_fgetline(3) except that multiple threads accessing the new string will be synchronised by locker.

void str_release(String *str)

Releases (deallocates) str.

void *str_destroy(String **str)

Destroys (deallocates and sets to null) *str. Returns null. Note: strings shared by multiple threads must not be destroyed until after all threads have finished with it.

int str_rdlock(const String *str)

Claims a read lock on str (if str was created with a Locker). Clients must call this before calling cstr(3) (for the purpose of reading the raw string data) on a string that was created with a Locker. It is the client's responsibility to call str_unlock(3) when finished with the raw string data. It is also needed when multiple read-only str(3) module functions need to be called atomically. It is the caller's responsibility to call str_unlock(3) after the atomic operation. The only functions that may be called on str between calls to str_rdlock(3) and str_unlock(3) are cstr(3) and any read-only str(3) module functions whose name ends with _unlocked. On success, returns 0. On error, returns an error code.

int str_wrlock(const String *str)

Claims a write lock on str (if str was created with a Locker). Clients need to call this before calling cstr(3) (for the purpose of modifying the raw string data) on a string that was created with a Locker. It is the client's responsibility to call str_unlock(3) when finished with the raw string data. It is also needed when multiple read/write str(3) module functions need to be called atomically. It is the caller's responsibility to call str_unlock(3) after the atomic operation. The only functions that may be called on str between calls to str_wrlock(3) and str_unlock(3) are cstr(3) and any str(3) module functions whose name ends with _unlocked. On success, returns 0. On error, returns an error code.

int str_unlock(const String *str)

Unlocks a read lock or a write lock on str obtained with str_rdlock(3) or str_wrlock(3) (if str was created with a Locker). On success, returns 0. On error, returns an error code.

int str_empty(const String *str)

Returns whether or not str is the empty string. On error, returns -1 with errno set appropriately.

int str_empty_unlocked(const String *str)

Equivalent to str_empty(3) except that str is not read-locked.

ssize_t str_length(const String *str)

Returns the length of str. On error, returns -1 with errno set appropriately.

ssize_t str_length_unlocked(const String *str)

Equivalent to str_length(3) except that str is not read-locked.

char *cstr(const String *str)

Returns the raw C string in str. Do not use this pointer to extend the length of the string. It's OK to use it to reduce the length of the string, provided that you call str_set_length_unlocked(3) or str_recalc_length_unlocked(3) immediately afterwards. When used on a string that is shared by multiple threads, cstr(3) must appear between calls to str_rdlock(3) or str_wrlock(3) and str_unlock(3).

ssize_t str_set_length(String *str, size_t length)

Sets the length of str to length. Only needed after the raw C string returned by cstr(3) has been used to shorten a string. On success, returns the length of str. On error, returns -1 with errno set appropriately.

ssize_t str_set_length_unlocked(String *str, size_t length)

Equivalent to str_set_length(3) except that str is not write-locked.

ssize_t str_recalc_length(String *str)

Calculates and stores the length of str. Only needed after the raw C string returned by cstr(3) has been used to shorten a string. Note: Treats str as a nul-terminated string and should be avoided. Use str_set_length(3) instead. On success, returns the length of str. On error, returns -1 with errno set appropriately.

ssize_t str_recalc_length_unlocked(String *str)

Equivalent to str_recalc_length(3) except that str is not write-locked.

String *str_clear(String *str)

Makes str the empty string. On success, returns str. On error, returns null with errno set appropriately.

String *str_clear_unlocked(String *str)

Equivalent to str_clear(3) except that str is not write-locked.

String *str_remove(String *str, ssize_t index)

Removes the index'th character from str. If index is negative, it refers to a character position relative to the end of the string (-1 is the position after the last character, -2 is the position of the last character, and so on). On success, returns str. On error, returns null with errno set appropriately.

String *str_remove_unlocked(String *str, ssize_t index)

Equivalent to str_remove(3) except that str is not write-locked.

String *str_remove_range(String *str, ssize_t index, ssize_t range)

Removes range characters from str starting at index. If index or range are negative, they refer to character positions relative to the end of the string (-1 is the position after the last character, -2 is the position of the last character, and so on). On success, returns str. On error, returns null with errno set appropriately.

String *str_remove_range_unlocked(String *str, ssize_t index, ssize_t range)

Equivalent to str_remove_range(3) except that str is not write-locked.

String *str_insert(String *str, ssize_t index, const char *format, ...)

Adds the string specified by format to str at position index. If index is negative, it refers to a character position relative to the end of the string (-1 is the position after the last character, -2 is the position of the last character, and so on). On success, returns str. On error, returns null with errno set appropriately.

String *str_insert_unlocked(String *str, ssize_t index, const char *format, ...)

Equivalent to str_insert(3) except that str is not write-locked.

String *str_vinsert(String *str, ssize_t index, const char *format, va_list args)

Equivalent to str_insert(3) with the variable argument list specified directly as for vprintf(3).

String *str_vinsert_unlocked(String *str, ssize_t index, const char *format, va_list args)

Equivalent to str_vinsert(3) except that str is not write-locked.

String *str_insert_str(String *str, ssize_t index, const String *src)

Inserts src into str, starting at position index. If index is negative, it refers to a character position relative to the end of the string (-1 is the position after the last character, -2 is the position of the last character, and so on). On success, returns str. On error, returns null with errno set appropriately.

String *str_insert_str_unlocked(String *str, ssize_t index, const String *src)

Equivalent to str_insert_str(3) except that str is not write-locked and src is not read-locked. Note: If src needs to be read-locked, it is the caller's responsibility to lock and unlock it explicitly with str_rdlock(3) and str_unlock(3).

String *str_append(String *str, const char *format, ...)

Appends the string specified by format to str. On success, returns str. On error, returns null with errno set appropriately.

String *str_append_unlocked(String *str, const char *format, ...)

Equivalent to str_append(3) except that str is not write-locked.

String *str_vappend(String *str, const char *format, va_list args)

Equivalent to str_append(3) with the variable argument list specified directly as for vprintf(3).

String *str_vappend_unlocked(String *str, const char *format, va_list args)

Equivalent to str_vappend(3) except that str is not write-locked.

String *str_append_str(String *str, const String *src)

Appends src to str. On success, returns str. On error, returns null with errno set appropriately.

String *str_append_str_unlocked(String *str, const String *src)

Equivalent to str_append_str(3) except that str is not write-locked and src is not read-locked. Note: If src needs to be read-locked, it is the caller's responsibility to lock and unlock it explicitly with str_rdlock(3) and str_unlock(3).

String *str_prepend(String *str, const char *format, ...)

Prepends the string specified by format to str. On success, returns str. On error, returns null with errno set appropriately.

String *str_prepend_unlocked(String *str, const char *format, ...)

Equivalent to str_prepend(3) except that str is not write-locked.

String *str_vprepend(String *str, const char *format, va_list args)

Equivalent to str_prepend(3) with the variable argument list specified directly as for vprintf(3).

String *str_vprepend_unlocked(String *str, const char *format, va_list args)

Equivalent to str_vprepend(3) except that str is not write-locked.

String *str_prepend_str(String *str, const String *src)

Prepends src to str. On success, returns str. On error, returns null with errno set appropriately.

String *str_prepend_str_unlocked(String *str, const String *src)

Equivalent to str_prepend_str(3) except that str is not write-locked and src is not read-locked. Note: If src needs to be read-locked, it is the caller's responsibility to lock and unlock it explicitly with str_rdlock(3) and str_unlock(3).

String *str_replace(String *str, ssize_t index, ssize_t range, const char *format, ...)

Replaces range characters in str, starting at index, with the string specified by format. If index or range are negative, they refer to character positions relative to the end of the string (-1 is the position after the last character, -2 is the position of the last character, and so on). On success, returns str. On error, returns null with errno set appropriately.

String *str_replace_unlocked(String *str, ssize_t index, ssize_t range, const char *format, ...)

Equivalent to str_replace(3) except that str is not write-locked.

String *str_vreplace(String *str, ssize_t index, ssize_t range, const char *format, va_list args)

Equivalent to str_replace(3) with the variable argument list specified directly as for vprintf(3).

String *str_vreplace_unlocked(String *str, ssize_t index, ssize_t range, const char *format, va_list args)

Equivalent to str_vreplace(3) except that str is not write-locked.

String *str_replace_str(String *str, ssize_t index, ssize_t range, const String *src)

Replaces range characters in str, starting at index, with src. If index or range are negative, they refer to character positions relative to the end of the string (-1 is the position after the last character, -2 is the position of the last character, and so on). On success, return str. On error, returns null with errno set appropriately.

String *str_replace_str_unlocked(String *str, ssize_t index, ssize_t range, const String *src)

Equivalent to str_replace_str(3) except that str is not write-locked and src is not read-locked. Note: If src needs to be read-locked, it is the caller's responsibility to lock and unlock it explicitly with str_rdlock(3) and str_unlock(3).

String *str_substr(const String *str, ssize_t index, ssize_t range)

Creates a new String object consisting of range characters from str, starting at index. If index or range are negative, they refer to character positions relative to the end of the string (-1 is the position after the last character, -2 is the position of the last character, and so on). On success, returns the new string. It is the caller's responsibility to deallocate the new string with str_release(3) or str_destroy(3). On error, returns null with errno set appropriately.

String *str_substr_unlocked(const String *str, ssize_t index, ssize_t range)

Equivalent to str_substr(3) except that str is not read-locked.

String *str_substr_with_locker(Locker *locker, const String *str, ssize_t index, ssize_t range)

Equivalent to str_substr(3) except that multiple threads accessing the new substring will be synchronised by locker.

String *str_substr_with_locker_unlocked(Locker *locker, const String *str, ssize_t index, ssize_t range)

Equivalent to str_substr_with_locker(3) except that str is not read-locked.

String *substr(const char *str, ssize_t index, ssize_t range)

Equivalent to str_substr(3) but works on an ordinary C string.

String *substr_with_locker(Locker *locker, const char *str, ssize_t index, ssize_t range)

Equivalent to substr(3) except that multiple threads accessing the new substring will be synchronised by locker. Note that no locking is performed on str as it is a raw C string.

String *str_splice(String *str, ssize_t index, ssize_t range)

Removes a substring from str starting at index of length range characters. If index or range are negative, they refer to character positions relative to the end of the string (-1 is the position after the last character, -2 is the position of the last character, and so on). On success, returns the substring. It is the caller's responsibility to deallocate the new substring with str_release(3) or str_destroy(3). It is strongly recommended to use str_destroy(3), because it also sets the pointer variable to null. On error, returns null with errno set appropriately.

String *str_splice_unlocked(String *str, ssize_t index, ssize_t range)

Equivalent to str_splice(3) except that str is not write-locked.

String *str_splice_with_locker(Locker *locker, String *str, ssize_t index, ssize_t range)

Equivalent to str_splice(3) except that multiple threads accessing the new string will be synchronised by locker.

String *str_splice_with_locker_unlocked(Locker *locker, String *str, ssize_t index, ssize_t range)

Equivalent to str_splice_with_locker(3) except that str is not write-locked.

String *str_repeat(size_t count, const char *format, ...)

Creates a new String containing the string determined by format repeated count times. On success, return the new string. It is the caller's responsibility to deallocate the new string with str_release(3) or str_destroy(3). It is strongly recommended to use str_destroy(3), because it also sets the pointer variable to null. On error, returns null with errno set appropriately.

String *str_repeat_with_locker(Locker *locker, size_t count, const char *format, ...)

Equivalent to str_repeat(3) except that multiple threads accessing the new string will be synchronised by locker.

String *str_vrepeat(size_t count, const char *format, va_list args)

Equivalent to str_repeat(3) with the variable argument list specified directly as for vprintf(3).

String *str_vrepeat_with_locker(Locker *locker, size_t count, const char *format, va_list args)

Equivalent to str_vrepeat(3) except that multiple threads accessing the new string will be synchronised by locker.

int str_tr(String *str, const char *from, const char *to, int option)

This is just like the perl(1) tr operator. The following documentation was taken from perlop(1).

Transliterates all occurrences of the characters in from with the corresponding character in to. On success, returns the number of characters replaced or deleted. On error, returns -1 with errno set appropriately.

A character range can be specified with a hyphen, so str_tr(str, "A-J", "0-9") does the same replacement as str_tr(str, "ACEGIBDFHJ", "0246813579").

Note also that the whole range idea is rather unportable between character sets - and even within character sets they might cause results you probably didn't expect. A sound principle is to use only ranges that begin from and end at either alphabets of equal case (a-e, A-E), or digits (0-4). Anything else is unsafe. If in doubt, spell out the character sets in full.

Options:

TR_COMPLEMENT Complement from.
TR_DELETE     Delete found but unreplaced characters.
TR_SQUASH     Squash duplicate replaced characters.

If TR_COMPLEMENT is specified, from is complemented. If TR_DELETE is specified, any characters specified by from not found in to are deleted. (Note that this is slightly more flexible than the behavior of some tr programs, which delete anything they find in from.) If TR_SQUASH is specified, sequences of characters that were transliterated to the same character are squashed down to a single instance of the character.

If TR_DELETE is used, to is always interpreted exactly as specified. Otherwise, if to is shorter than from, the final character is replicated till it is long enough. If to is empty or null, from is replicated. This latter is useful for counting characters in a class or for squashing character sequences in a class.

Examples:

str_tr(s, "A-Z", "a-z", 0);             // canonicalize to lower case
str_tr(s, "a-z", "A-Z", 0);             // canonicalize to upper case
str_tr(s, "a-zA-Z", "A-Za-z", 0);       // swap upper and lower case
str_tr(s, "*", "*", 0);                 // count the stars in str
str_tr(s, "0-9", "", 0);                // count the digits in $_
str_tr(s, "a-zA-Z", "", TR_SQUASH);     // bookkeeper -> bokeper
str_tr(s, "a-zA-Z", " ", TR_COMPLEMENT | TR_SQUASH); // change non-alphas to single space
str_tr(c, "a-zA-Z", "n-za-mN-ZA-M", 0); // Rot13

from = str_create("\200-\377");
to = str_create("%c-\177", '\000');
str_tr_str(s, from, to, 0);             // clear 8th bit

If multiple transliterations are given for a character, only the first one is used:

str_tr(str, "AAA", "XYZ", 0);

will transliterate any A to X.

int str_tr_unlocked(String *str, const char *from, const char *to, int option)

Equivalent to str_tr(3) except that str is not write-locked.

int str_tr_str(String *str, const String *from, const String *to, int option)

Equivalent to str_tr(3) except that from and to are String objects. This is needed when from or to need to contain nul characters.

int str_tr_str_unlocked(String *str, const String *from, const String *to, int option)

Equivalent to str_tr_str(3) except that str is not write-locked and from and to are not read-locked. Note: If to and from need to be read-locked, it is the caller's responsibility to lock and unlock them explicitly with str_rdlock(3) and str_unlock(3).

int tr(char *str, const char *from, const char *to, int option)

Equivalent to str_tr(3) but works on an ordinary C string.

StringTR *tr_compile(const char *from, const char *to, int option)

Compiles from, to and option into a translation table to be passed to str_tr_compiled(3) or tr_compiled(3). On success, returns the new translation table. It is the caller's responsibility to deallocate the translation table with tr_release(3) or tr_destroy(3). It is strongly recommended to use tr_destroy(3), because it also sets the pointer variable to null. On error, returns null with errno set appropriately.

StringTR *tr_compile_with_locker(Locker *locker, const char *from, const char *to, int option)

Equivalent to tr_compile(3) except that multiple threads accessing the new translation table will be synchronised by locker.

StringTR *str_tr_compile(const String *from, const String *to, int option)

Equivalent to tr_compile(3) except that from and to are String objects. This is needed when from or to need to contain nul characters.

StringTR *str_tr_compile_unlocked(const String *from, const String *to, int option)

Equivalent to str_tr_compile(3) except that from and to are not read-locked.

StringTR *str_tr_compile_with_locker(Locker *locker, const String *from, const String *to, int option)

Equivalent to str_tr_compile(3) except that multiple threads accessing the new translation table will be synchronised by locker.

StringTR *str_tr_compile_with_locker_unlocked(Locker *locker, const String *from, const String *to, int option)

Equivalent to str_tr_compile_with_locker(3) except that from and to are not read-locked. Note: If to and from need to be read-locked, it is the caller's responsibility to lock and unlock them explicitly with str_rdlock(3) and str_unlock(3).

void tr_release(StringTR *table)

Releases (deallocates) table.

void *tr_destroy(StringTR **table)

Destroys (deallocates and sets to null) *table. Returns null. Note: translation tables shared by multiple threads must not be destroyed until after all threads have finished with it.

int str_tr_compiled(String *str, StringTR *table)

Performs the character translation specified by table (as created by tr_compile(3) or equivalent) on str. Use this whenever the same translation will be performed multiple times. On success, returns the number of characters replaced or deleted. On error, returns -1 with errno set appropriately.

int str_tr_compiled_unlocked(String *str, StringTR *table)

Equivalent to str_tr_compiled(3) except that str is not write-locked.

int tr_compiled(char *str, StringTR *table)

Equivalent to str_tr_compiled(3) but works on an ordinary C string.

List *str_regexpr(const char *pattern, const String *text, int cflags, int eflags)

str_regexpr(3) is an interface to POSIX 1003.2-compliant regular expression matching. pattern is a regular expression. text is the string to be searched for matches. cflags is passed to regcomp(3) along with REG_EXTENDED. eflags is passed to regexec(3). On success, returns a List of (at most 33) Strings containing the matching substring followed by the matching substrings of any parenthesised subexpressions. It is the caller's responsibility to deallocate the list with list_release(3) or list_destroy(3). On error (including no match), returns null with errno set appropriately. Only use this function when the regular expression will be used only once. Otherwise, use regexpr_compile(3) or regcomp(3) and str_regexpr_compiled(3) or regexpr_compiled(3) or regexec(3).

Note: If you require perl pattern matching, you could use Philip Hazel's PCRE package, ftp://ftp.cus.cam.ac.uk/pub/software/programs/pcre/ or link against the perl library itself.

List *str_regexpr_unlocked(const char *pattern, const String *text, int cflags, int eflags)

Equivalent to str_regexpr(3) except that text is not read-locked.

List *str_regexpr_with_locker(Locker *locker, const char *pattern, const String *text, int cflags, int eflags)

Equivalent to str_regexpr(3) except that multiple threads accessing the new list will be synchronised by locker.

List *str_regexpr_with_locker_unlocked(Locker *locker, const char *pattern, const String *text, int cflags, int eflags)

Equivalent to str_regexpr_with_locker(3) except that text is not read-locked.

List *regexpr(const char *pattern, const char *text, int cflags, int eflags)

Equivalent to str_regexpr(3) but works on an ordinary C string.

List *regexpr_with_locker(Locker *locker, const char *pattern, const char *text, int cflags, int eflags)

Equivalent to regexpr(3) except that multiple threads accessing the new list will be synchronised by locker.

int regexpr_compile(regex_t *compiled, const char *pattern, int cflags)

Compiles a POSIX 1003.2-compliant regular expression. compiled is the location in which to compile the expression. pattern is the regular expression. cflags is passed to regcomp(3) along with REG_EXTENDED. Call this, followed by re_compiled(3) when the regular expression will be used multiple times. On success, returns 0. On error, returns an error code.

void regexpr_release(regex_t *compiled)

Just another name for regfree(3).

List *str_regexpr_compiled(const regex_t *compiled, const String *text, int eflags)

regexpr_compiled(3) is an interface to the POSIX 1003.2 regular expression function, regexec(3). compiled is the compiled regular expression prepared by regexpr_compile(3) or regcomp(3). text is the string to be searched for a match. eflags is passed to regexec(3). On success, returns a List of (at most 33) Strings containing the matching substring followed by the matching substrings of any parenthesised subexpressions. It is the caller's responsibility to deallocate the list with list_release(3) or list_destroy(3). On error (including no match), returns null with errno set appropriately.

List *str_regexpr_compiled_unlocked(const regex_t *compiled, const String *text, int eflags)

Equivalent to str_regexpr_compiled(3) except that text is not write-locked.

List *str_regexpr_compiled_with_locker(Locker *locker, const regex_t *compiled, const String *text, int eflags)

Equivalent to str_regexpr_compiled(3) except that multiple threads accessing the new list will be synchronised by locker.

List *str_regexpr_compiled_with_locker_unlocked(Locker *locker, const regex_t *compiled, const String *text, int eflags)

Equivalent to str_regexpr_compiled_with_locker(3) except that text is not read-locked.

List *regexpr_compiled(const regex_t *compiled, const char *text, int eflags)

Equivalent to str_regexpr_compiled(3) but works on an ordinary C string.

List *regexpr_compiled_with_locker(Locker *locker, const regex_t *compiled, const char *text, int eflags)

Equivalent to regexpr_compiled(3) except that multiple threads accessing the new list will be synchronised by locker.

String *str_regsub(const char *pattern, const char *replacement, String *text, int cflags, int eflags, int all)

str_regsub(3) is an interface to POSIX 1003.2-compliant regular expression matching and substitution. pattern is a regular expression. text is the string to be searched for matches. cflags is passed to regcomp(3) along with REG_EXTENDED. eflags is passed to regexec(3). all specifies whether to substitute the first match (if zero) or all matches (if non-zero). replacement specifies the string that replaces each match. If replacement contains "$#" or "${##}" (where "#" is a decimal digit), the substring that matches the corresponding subexpression is interpolated in its place. Up to 32 subexpressions are supported. If replacement contains "$$", then "$" is interpolated in its place. The following perl(1) quote escape sequences are also understood:

\l  lowercase next character
\u  uppercase next character
\L  lowercase until matching \E
\U  uppercase until matching \E
\Q  backslash non-alphanumeric characters until matching \E
\E  end case/quotemeta modification

Note that these sequences don't behave exactly like in perl(1). Namely, an \l appearing between a \U and an \E does lowercase the next character and a \E sequence without a matching \L, \U or \Q is an error. Also note that only 32 levels of nesting are supported.

On success, returns text. On error (including no match), returns null with errno set appropriately. Only use this function when the regular expression will be used only once. Otherwise, use regexpr_compile(3) or regcomp(3) and str_regsub_compiled(3).

String *str_regsub_unlocked(const char *pattern, const char *replacement, String *text, int cflags, int eflags, int all)

Equivalent to str_regsub(3) except that text is not write-locked.

String *str_regsub_compiled(const regex_t *compiled, const char *replacement, String *text, int eflags, int all)

Equivalent to str_regsub(3) but works on an already compiled regex_t, compiled.

String *str_regsub_compiled_unlocked(const regex_t *compiled, const char *replacement, String *text, int eflags, int all)

Equivalent to str_regsub_compiled(3) except that text is not write-locked.

List *str_fmt(const String *str, size_t line_width, StringAlignment alignment)

Formats str into a List of String objects with length no greater than line_width (unless there are individual words longer than line_width) with the alignment specified by alignment:

ALIGN_LEFT ('<')

The lines will be left justified (with one space between words).

ALIGN_RIGHT ('>')

The lines will be right justified (with one space between words).

ALIGN_CENTRE or ALIGN_CENTER ('|')

str will be split into lines at each newline character ('\n'). The lines will then be centred (with one space between words) padded with spaces to the left.

ALIGN_FULL ('=')

The lines will be fully justified (possibly with multiple spaces between words).

On success, returns a new List of String objects. It is the caller's responsibility to deallocate the list with list_release(3) or list_destroy(3). On error, returns null with errno set appropriately. Note that str is interpreted as a nul-terminated string.

Note: str_fmt(3) provides straightforward formatting completely lacking in any aesthetic sensibilities. If you need awesome paragraph formatting, pipe text through par(1) instead (available from http://www.cs.berkeley.edu/~amc/Par/).

List *str_fmt_unlocked(const String *str, size_t line_width, StringAlignment alignment)

Equivalent to str_fmt(3) except that str is not read-locked.

List *str_fmt_with_locker(Locker *locker, const String *str, size_t line_width, StringAlignment alignment)

Equivalent to str_fmt(3) except that multiple threads accessing the new list will be synchronised by locker.

List *str_fmt_with_locker_unlocked(Locker *locker, const String *str, size_t line_width, StringAlignment alignment)

Equivalent to str_fmt_with_locker(3) except that str is not read-locked.

List *fmt(const char *str, size_t line_width, StringAlignment alignment)

Equivalent to str_fmt(3) but works on an ordinary C string.

List *fmt_with_locker(Locker *locker, const char *str, size_t line_width, StringAlignment alignment)

Equivalent to fmt(3) except that multiple threads accessing the new list will be synchronised by locker.

List *str_split(const String *str, const char *delim)

Splits str into tokens separated by sequences of characters occurring in delim. On success, returns a new List of String objects. It is the caller's responsibility to deallocate the list with list_release(3) or list_destroy(3). On error, returns null with errno set appropriately.

List *str_split_unlocked(const String *str, const char *delim)

Equivalent to str_split(3) except that str is not read-locked.

List *str_split_with_locker(Locker *locker, const String *str, const char *delim)

Equivalent to str_split(3) except that multiple threads accessing the new list will be synchronised by locker.

List *str_split_with_locker_unlocked(Locker *locker, const String *str, const char *delim)

Equivalent to str_split_with_locker(3) except that str is not read-locked.

List *split(const char *str, const char *delim)

Equivalent to str_split(3) but works on an ordinary C string.

List *split_with_locker(Locker *locker, const char *str, const char *delim)

Equivalent to split(3) except that multiple threads accessing the new list will be synchronised by locker.

List *str_regexpr_split(const String *str, const char *delim, int cflags, int eflags)

Splits str into tokens separated by occurrences of the regular expression, delim. str is interpreted as a nul-terminated C string. cflags is passed to regcomp(3) along with REG_EXTENDED and eflags is passed to regexec(3). On success, returns a new List of String objects. It is the caller's responsibility to deallocate the list with list_release(3) or list_destroy(3). On error, returns null with errno set appropriately.

List *str_regexpr_split_unlocked(const String *str, const char *delim, int cflags, int eflags)

Equivalent to str_regexpr_split(3) except that str is not read-locked.

List *str_regexpr_split_with_locker(Locker *locker, const String *str, const char *delim, int cflags, int eflags)

Equivalent to str_regexpr_split(3) except that multiple threads accessing the new list will be synchronised by locker.

List *str_regexpr_split_with_locker_unlocked(Locker *locker, const String *str, const char *delim, int cflags, int eflags)

Equivalent to str_regexpr_split_with_locker(3) except that str is not read-locked.

List *regexpr_split(const char *str, const char *delim, int cflags, int eflags)

Equivalent to str_regexpr_split(3) but works on an ordinary C string.

List *regexpr_split_with_locker(Locker *locker, const char *str, const char *delim, int cflags, int eflags)

Equivalent to regexpr_split(3) except that multiple threads accessing the new list will be synchronised by locker.

String *str_join(const List *list, const char *delim)

Joins the String objects in list with delim inserted between each one. On success, returns the resulting String. It is the caller's responsibility to deallocate the string with str_release(3) or str_destroy(3). On error, returns null with errno set appropriately.

String *str_join_unlocked(const List *list, const char *delim)

Equivalent to str_join(3) except that list is not read-locked.

String *str_join_with_locker(Locker *locker, const List *list, const char *delim)

Equivalent to str_join(3) except that multiple threads accessing the new string will be synchronised by locker.

String *str_join_with_locker_unlocked(Locker *locker, const List *list, const char *delim)

Equivalent to str_join_with_locker(3) except that list is not read-locked.

String *join(const List *list, const char *delim)

Equivalent to str_join(3) but works on a list of ordinary C strings.

String *join_with_locker(Locker *locker, const List *list, const char *delim)

Equivalent to join(3) except that multiple threads accessing the new string will be synchronised by locker.

int str_soundex(const String *str)

Returns the soundex code of str as an integer. On error, returns -1 with errno set appropriately.

int str_soundex_unlocked(const String *str)

Equivalent to str_soundex(3) except that str is not read-locked.

int soundex(const char *str)

Equivalent to str_soundex(3) but works on an ordinary C string.

String *str_trim(String *str)

Trims leading and trailing whitespace from str. On success, returns str. On error, returns null with errno set appropriately.

String *str_trim_unlocked(String *str)

Equivalent to str_trim(3) except that str is not write-locked.

char *trim(char *str)

Equivalent to str_trim(3) but works on an ordinary C string.

String *str_trim_left(String *str)

Trims leading whitespace from str. On success, returns str. On error, returns null with errno set appropriately.

String *str_trim_left_unlocked(String *str)

Equivalent to str_trim_left(3) except that str is not write-locked.

char *trim_left(char *str)

Equivalent to str_trim_left(3) but works on an ordinary C string.

String *str_trim_right(String *str)

Trims trailing whitespace from str. On success, returns str. On error, returns null with errno set appropriately.

String *str_trim_right_unlocked(String *str)

Equivalent to str_trim_right(3) except that str is not write-locked.

char *trim_right(char *str)

Equivalent to str_trim_right(3) but works on an ordinary C string.

String *str_squeeze(String *str)

Trims leading and trailing whitespace from str and replaces all other sequences of whitespace with a single space. On success, returns str. On error, returns null with errno set appropriately.

String *str_squeeze_unlocked(String *str)

Equivalent to str_squeeze(3) except that str is not write-locked.

char *squeeze(char *str)

Equivalent to str_squeeze(3) but works on an ordinary C string.

String *str_quote(const String *str, const char *quotable, char quote_char)

Creates a new String containing str with every occurrence of any character in quotable preceded by quote_char. On success, returns the new string. It is the caller's responsibility to deallocate the new string with str_release(3) or str_destroy(3). On error, returns null with errno set appropriately.

String *str_quote_unlocked(const String *str, const char *quotable, char quote_char)

Equivalent to str_quote(3) except that str is not read-locked.

String *str_quote_with_locker(Locker *locker, const String *str, const char *quotable, char quote_char)

Equivalent to str_quote(3) except that multiple threads accessing the new string will be synchronised by locker.

String *str_quote_with_locker_unlocked(Locker *locker, const String *str, const char *quotable, char quote_char)

Equivalent to str_quote_with_locker(3) except that str is not read-locked.

String *quote(const char *str, const char *quotable, char quote_char)

Equivalent to str_quote(3) but works on an ordinary C string.

String *quote_with_locker(Locker *locker, const char *str, const char *quotable, char quote_char)

Equivalent to quote(3) except that multiple threads accessing the new string will be synchronised by locker.

String *str_unquote(const String *str, const char *quotable, char quote_char)

Creates a new string containing str with every occurrence of quote_char that is followed by any character in quotable removed. On success, returns the new String. It is the caller's responsibility to deallocate the new string with str_release(3) or str_destroy(3). On error, returns null with errno set appropriately.

String *str_unquote_unlocked(const String *str, const char *quotable, char quote_char)

Equivalent to str_unquote(3) except that str is not read-locked.

String *str_unquote_with_locker(Locker *locker, const String *str, const char *quotable, char quote_char)

Equivalent to str_unquote(3) except that multiple threads accessing the new string will be synchronised by locker.

String *str_unquote_with_locker_unlocked(Locker *locker, const String *str, const char *quotable, char quote_char)

Equivalent to str_unquote_with_locker(3) except that str is not read-locked.

String *unquote(const char *str, const char *quotable, char quote_char)

Equivalent to str_unquote(3) but works on an ordinary C string.

String *unquote_with_locker(Locker *locker, const char *str, const char *quotable, char quote_char)

Equivalent to unquote(3) except that multiple threads accessing the new string will be synchronised by locker.

String *str_encode(const String *str, const char *uncoded, const char *coded, char quote_char, int printable)

Returns a copy of str with every occurrence in str of characters in uncoded replaced with quote_char followed by the corresponding (by position) character in coded. If printable is non-zero, other non-printable characters are replaced with their ASCII codes in hexadecimal. It is the caller's responsibility to deallocate the new string with str_release(3) or str_destroy(3). It is strongly recommended to use str_destroy(3), because it also sets the pointer variable to null. On error, returns null with errno set appropriately.

Example:

// Encode a string into a C string literal
str_encode(str, "\a\b\t\n\v\f\r\\", "abtnvfr\\", '\\', 1);

// Decode a C string literal
str_decode(str, "\a\b\t\n\v\f\r\\", "abtnvfr\\", '\\', 1);
String *str_encode_unlocked(const String *str, const char *uncoded, const char *coded, char quote_char, int printable)

Equivalent to str_encode(3) except that str is not read-locked.

String *str_encode_with_locker(Locker *locker, const String *str, const char *uncoded, const char *coded, char quote_char, int printable)

Equivalent to str_encode(3) except that multiple threads accessing the new string will be synchronised by locker.

String *str_encode_with_locker_unlocked(Locker *locker, const String *str, const char *uncoded, const char *coded, char quote_char, int printable)

Equivalent to str_encode_with_locker(3) except that str is not read-locked.

String *str_decode(const String *str, const char *uncoded, const char *coded, char quote_char, int printable)

Returns a copy of str with every occurrence in str of quote_char followed by a character in coded replaced with the corresponding (by position) character in uncoded. If printable is non-zero, every occurrence in str of an ASCII code in octal or hexadecimal (i.e. "\ooo" or "\xhh") is replaced with the corresponding ASCII character. It is the caller's responsibility to deallocate the new string with str_release(3) or str_destroy(3). It is strongly recommended to use str_destroy(3), because it also sets the pointer variable to null. On error, returns null with errno set appropriately.

String *str_decode_unlocked(const String *str, const char *uncoded, const char *coded, char quote_char, int printable)

Equivalent to str_decode(3) except that str is not read-locked.

String *str_decode_with_locker(Locker *locker, const String *str, const char *uncoded, const char *coded, char quote_char, int printable)

Equivalent to str_decode(3) except that multiple threads accessing the new string will be synchronised by locker.

String *str_decode_with_locker_unlocked(Locker *locker, const String *str, const char *uncoded, const char *coded, char quote_char, int printable)

Equivalent to str_decode_with_locker(3) except that str is not read-locked.

String *encode(const char *str, const char *uncoded, const char *coded, char quote_char, int printable)

Equivalent to str_encode(3) but works on an ordinary C string.

String *encode_with_locker(Locker *locker, const char *str, const char *uncoded, const char *coded, char quote_char, int printable)

Equivalent to encode(3) except that multiple threads accessing the new string will be synchronised by locker.

String *decode(const char *str, const char *uncoded, const char *coded, char quote_char, int printable)

Equivalent to str_decode(3) but works on an ordinary C string.

String *decode_with_locker(Locker *locker, const char *str, const char *uncoded, const char *coded, char quote_char, int printable)

Equivalent to decode(3) except that multiple threads accessing the new string will be synchronised by locker.

String *str_lc(String *str)

Converts str into lower case. On success, returns str. On error, returns null with errno set appropriately.

String *str_lc_unlocked(String *str)

Equivalent to str_lc(3) except that str is not write-locked.

char *lc(char *str)

Converts str into lower case. On success, returns str. On error, returns null with errno set appropriately.

String *str_lcfirst(String *str)

Converts the first character in str into lower case. On success, returns str. On error, returns null with errno set appropriately.

String *str_lcfirst_unlocked(String *str)

Equivalent to str_lcfirst(3) except that str is not write-locked.

char *lcfirst(char *str)

Converts the first character in str into lower case. On success, returns str. On error, returns null with errno set appropriately.

String *str_uc(String *str)

Converts str into upper case. On success, returns str. On error, returns null with errno set appropriately.

String *str_uc_unlocked(String *str)

Equivalent to str_uc(3) except that str is not write-locked.

char *uc(char *str)

Converts str into upper case. On success, returns str. On error, returns null with errno set appropriately.

String *str_ucfirst(String *str)

Converts the first character in str into upper case. On success, returns str. On error, returns null with errno set appropriately.

String *str_ucfirst_unlocked(String *str)

Equivalent to str_ucfirst(3) except that str is not write-locked.

char *ucfirst(char *str)

Converts the first character in str into upper case. On success, returns str. On error, returns null with errno set appropriately.

int str_chop(String *str)

Removes a character from the end of str. On success, returns the character that was removed. On error, returns -1 with errno set appropriately.

int str_chop_unlocked(String *str)

Equivalent to str_chop(3) except that str is not write-locked.

int chop(char *str)

Removes a character from the end of str. On success, returns the character that was removed. On error, returns -1 with errno set appropriately.

int str_chomp(String *str)

Removes line ending characters (i.e. '\n' and '\r') from the end of str. On success, returns the number of characters that were removed. On error, returns -1 with errno set appropriately.

int str_chomp_unlocked(String *str)

Equivalent to str_chomp(3) except that str is not write-locked.

int chomp(char *str)

Removes line ending characters (i.e. '\n' and '\r') from the end of str. On success, returns the number of characters that were removed. On error, returns -1 with errno set appropriately.

int str_bin(const String *str)

Returns the integer specified by the binary string, str. str can either be a string of [0-1], or "0b" followed by a string of [0-1]. On error, returns -1 with errno set appropriately.

int str_bin_unlocked(const String *str)

Equivalent to str_bin(3) except that str is not read-locked.

int bin(const char *str)

Returns the integer specified by the binary string, str. str can either be a string of [0-1], or "0b" followed by a string of [0-1]. On error, returns -1 with errno set appropriately.

int str_hex(const String *str)

Returns the integer specified by the hexadecimal string, str. str can either be a string of [0-9a-fA-F], or "0x" followed by a string of [0-9a-fA-f]. On error, returns -1 with errno set appropriately.

int str_hex_unlocked(const String *str)

Equivalent to str_hex(3) except that str is not read-locked.

int hex(const char *str)

Returns the integer specified by the hexadecimal string, str. str can either be a string of [0-9a-fA-F], or "0x" followed by a string of [0-9a-fA-f]. On error, returns -1 with errno set appropriately.

int str_oct(const String *str)

Returns the integer specified by the binary, octal or hexadecimal string, str. str can either be "0x" followed by a string of [0-9a-fA-F] (hexadecimal), "0b" followed by a string of [0-1] (binary), or "0" followed by a string of [0-7] (octal). On error, returns -1 with errno set appropriately.

int str_oct_unlocked(const String *str)

Equivalent to str_oct(3) except that str is not read-locked.

int oct(const char *str)

Returns the integer specified by the binary, octal or hexadecimal string, str. str can either be "0x" followed by a string of [0-9a-fA-F] (hexadecimal), "0b" followed by a string of [0-1] (binary), or "0" followed by a string of [0-7] (octal). On error, returns -1 with errno set appropriately.

int strcasecmp(const char *s1, const char *s2)

Compares two strings, s1 and s2, ignoring the case of the characters. It returns an integer less than, equal to, or greater than zero if s1 is found to be less than, equal to, or greater than s2, respectively.

int strncasecmp(const char *s1, const char *s2, size_t n)

Equivalent to strcasecmp(3) except that it only compares the first n characters.

size_t strlcpy(char *dst, const char *src, size_t size)

Copies src into dst (which is size bytes long). The result, dst, will be no longer than size - 1 bytes, and will be nul-terminated (unless size is zero). This is similar to strncpy(3) except that it always terminates the string with a nul byte (so it's safer), and it doesn't fill the remainder of the buffer with nul bytes (so it's faster). Returns the length of src (If this is >= size, truncation occurred). Use this rather than strcpy(3) or strncpy(3).

size_t strlcat(char *dst, const char *src, size_t size)

Appends src to dst (which is size bytes long). The result, dst, will be no longer than size - 1 bytes, and will be nul-terminated (unless size is zero). This is similar to strncat(3) except that the last argument is the size of the buffer, not the amount of space available (so it's more intuitive and hence safer). Returns the sum of the lengths of src and dst (If this is >= size, truncation occurred). Use this rather than strcat(3) or strncat(3).

char *cstrcpy(char *dst, const char *src)

Copies the string pointed to by src (including the terminating nul character) to the array pointed to by dst. The memory areas must not overlap. The array dst must be large enough to store the copy. Unless you know that this is the case, use strlcpy(3) instead. This is just like strcpy(3) except that instead of returning dst (which you already know), this function returns the address of the terminating nul character (dst + strlen(src)).

char *cstrcat(char *dst, const char *src)

Appends the string src to the string dst. The strings must not overlap. The string dst must be large enough to store the appended copy of src. Unless you know that this is the case, use strlcat(3) instead. This is just like strcat(3) except that, instead of returning dst (which you already know), this function returns the address of the terminating nul character (dst + strlen(dst) + strlen(src)).

char *cstrchr(const char *str, int c)

Scans the string str looking for the character c. Returns a pointer to the first occurrence of the character c in the string str. This is just like strchr(3) except that, instead of returning null when c does not appear in str, this function returns the address of the terminating nul character (str + strlen(str)).

char *cstrpbrk(const char *str, const char *brk)

Scans the string str looking for any of the characters in brk. Returns a pointer to the first occurrence of any character in brk in the string str. This is just like strpbrk(3) except that, instead of returning null when no match is found in str, this function returns the address of the terminating nul character (str + strlen(str)).

char *cstrrchr(const char *str, int c)

Scans the string str looking for the character c. Returns a pointer to the last occurrence of the character c in the string str. This is just like strrchr(3) except that, instead of returning null when c does not appear in str, this function returns the address of the terminating nul character (str + strlen(str)).

char *cstrstr(const char *str, const char *srch)

Scans the string str looking for the string srch. Returns a pointer to the first occurrence of the string srch in the string str. This is just like strstr(3) except that, instead of returning null when srch does not appear in str, this function returns the address of the terminating nul character (str + strlen(str)).

int asprintf(char **str, const char *format, ...)

Equivalent to sprintf(3) except that, instead of formatting format and subsequent arguments into a buffer supplied by the caller, they are formatted into a buffer that is internally allocated and stored in *str. On success, returns the number of bytes stored in *str excluding the terminating nul character. On error, returns -1 and stores null in *str.

int vasprintf(char **str, const char *format, va_list args)

Equivalent to asprintf(3) with the variable argument list specified directly as for vprintf(3).

ERRORS

On error, errno is set either by an underlying function, or as follows:

EINVAL

When arguments to any of the functions are invalid.

MT-Level

MT-Disciplined

By default, Strings are not MT-Safe because most programs are single-threaded and synchronisation doesn't come for free. Even in multi-threaded programs, not all Strings are necessarily shared between multiple threads.

When a String is shared between multiple threads which need to be synchronised, the method of synchronisation must be carefully selected by the client code. There are tradeoffs between concurrency and overhead. The greater the concurrency, the greater the overhead. More locks give greater concurrency, but have greater overhead. Readers/Writer locks can give greater concurrency than Mutex locks, but have greater overhead. One lock for each String might be required, or one lock for all (or a set of) Strings might be more appropriate.

Generally, the best synchronisation strategy for a given application can only be determined by testing/benchmarking the written application. It is important to be able to experiment with the synchronisation strategy at this stage of development without pain.

To facilitate this, Strings can be created with string_create_with_locker(3) which takes a Locker argument. The Locker specifies a lock and a set of functions for manipulating the lock. Each String can have its own lock by creating a separate Locker for each String. Multiple Strings can share the same lock by sharing the same Locker. Only the application developer can determine what is appropriate for each application on a string by string basis.

MT-Disciplined means that the application developer has a mechanism for specifying the synchronisation requirements to be applied to library code.

MT-Safe - str_fgetline(3)

Mac OS X doesn't have flockfile(3), funlockfile(3) or getc_unlocked(3). fgetline(3) is not MT-Safe on such platforms. You must guard all stdio calls with explicit synchronisation variables.

EXAMPLES

Create and manipulate strings:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    String *str1 = str_create("%s %d", "string", 1);
    String *str2 = str_copy(str1);
    String *str3;
    String *str4;
    String *str5;
    String *str6;

    str_remove(str1, 6);
    str_remove_range(str2, 6, 2);
    str_clear(str1);
    str_insert(str1, 0, "%d", 123);
    str_insert_str(str1, 1, str2);
    str_append(str2, "abc");
    str_append_str(str2, str1);
    str_prepend(str1, "abc");
    str_prepend_str(str1, str2);
    str_replace(str1, 1, -2, "abc");
    str_replace_str(str2, 1, 2, str1);

    str3 = str_substr(str1, 1, 3);
    str4 = substr("abc", 1, 1);
    str5 = str_splice(str3, 1, 1);
    str6 = str_repeat(3, "%c", ' ');

    *cstr(str5) = '\0';
    str_set_length(str5, 0);
    str_recalc_length(str5);

    printf("str1 = '%s' %d\n", cstr(str1), str_length(str1));
    printf("str2 = '%s' %d\n", cstr(str2), str_length(str2));
    printf("str3 = '%s' %d\n", cstr(str3), str_length(str3));
    printf("str4 = '%s' %d\n", cstr(str4), str_length(str4));
    printf("str5 = '%s' %d\n", cstr(str5), str_length(str5));
    printf("str6 = '%s' %d\n", cstr(str6), str_length(str6));

    str_destroy(&str1);
    str_destroy(&str2);
    str_destroy(&str3);
    str_destroy(&str4);
    str_destroy(&str5);
    str_destroy(&str6);

    return EXIT_SUCCESS;
}

Convert a text file from any system into the local text file format:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    String *line;

    while (line = str_fgetline(stdin))
    {
        printf("%s", cstr(line));
        str_destroy(&line);
    }

    return EXIT_SUCCESS;
}

Perform character translation with a pre-compiled translation table to rot13 the input:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    StringTR *trtable = tr_compile("a-zA-Z", "n-za-mN-ZA-M", 0);
    String *line;

    while (line = str_fgetline(stdin))
    {
        str_tr_compiled(line, trtable);
        printf("%s", cstr(line));
        str_destroy(&line);
    }

    tr_destroy(&trtable);

    return EXIT_SUCCESS;
}

The same as above but using ordinary C strings:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    StringTR *trtable = tr_compile("a-zA-Z", "n-za-mN-ZA-M", 0);
    char line[BUFSIZ];

    while (fgets(line, BUFSIZ, stdin))
    {
        int count = tr_compiled(line, trtable);
        printf("%s", line);
    }

    tr_destroy(&trtable);

    return EXIT_SUCCESS;
}

Perform regular expression matching and substitution:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    // Find matches in a String object

    String *str = str_create("abcabcabc");
    List *list = str_regexpr("a((.*)a(.*))a", str, 0, 0);
    regex_t compiled[1];

    while (list_has_next(list))
        printf("%s\n", cstr(list_next(list)));

    str_destroy(&str);
    list_destroy(&list);

    // Find matches in an ordinary C string

    list = regexpr("a((.*)a(.*))a", "abcabcabc", 0, 0);

    while (list_has_next(list) == 1)
        printf("%s\n", cstr(list_next(list)));

    list_destroy(&list);

    // Use a pre-compiled regular expression on a String object

    str = str_create("abcabcabc");

    if (!regexpr_compile(compiled, "a((.*)a(.*))a", 0))
    {
        list = str_regexpr_compiled(compiled, str, 0);
        regexpr_release(compiled);
    }

    while (list_has_next(list) == 1)
        printf("%s\n", cstr(list_next(list)));

    str_destroy(&str);
    list_destroy(&list);

    // Use a pre-compiled regular expression on an ordinary C string

    if (!regexpr_compile(compiled, "a((.*)a(.*))a", 0))
    {
        list = regexpr_compiled(compiled, "abcabcabc", 0);
        regexpr_release(compiled);
    }

    while (list_has_next(list) == 1)
        printf("%s\n", cstr(list_next(list)));

    list_destroy(&list);

    // Perform regular expression substitution on a String object

    str = str_create("abcabcabc");
    str_regsub("a", "z", str, 0, 0, 1);
    printf("%s\n", cstr(str));

    str_destroy(&str);

    // Perform regular expression substitution with a pre-compiled pattern

    str = str_create("abcabcabc");

    if (!regexpr_compile(compiled, "a", 0))
    {
        str_regsub_compiled(compiled, "z", str, 0, 1);
        printf("%s\n", cstr(str));
        regexpr_release(compiled);
    }

    str_destroy(&str);

    return EXIT_SUCCESS;
}

Format some text in a String object in several different ways:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    String *text = str_create("This is a string with\na few little words");
    List *left = str_fmt(text, 20, ALIGN_LEFT);     // or '<'
    List *right = str_fmt(text, 20, ALIGN_RIGHT);   // or '>'
    List *centre = str_fmt(text, 20, ALIGN_CENTRE); // or '|' or ALIGN_CENTER
    List *full = str_fmt(text, 20, ALIGN_FULL);     // or '='

    printf("Left:\n");
    while (list_has_next(left))
        printf("%s\n", cstr(list_next(left)));

    printf("Right:\n");
    while (list_has_next(right))
        printf("%s\n", cstr(list_next(right)));

    printf("Centre:\n");
    while (list_has_next(centre))
        printf("%s\n", cstr(list_next(centre)));

    printf("Full:\n");
    while (list_has_next(full))
        printf("%s\n", cstr(list_next(full)));

    str_destroy(&text);
    list_destroy(&left);
    list_destroy(&right);
    list_destroy(&centre);
    list_destroy(&full);

    return EXIT_SUCCESS;
}

Perform the same formatting but on an ordinary C string:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    char *text = "This is a string with\na few little words";
    List *left = fmt(text, 20, ALIGN_LEFT);     // or '<'
    List *right = fmt(text, 20, ALIGN_RIGHT);   // or '>'
    List *centre = fmt(text, 20, ALIGN_CENTRE); // or '|' or ALIGN_CENTER
    List *full = fmt(text, 20, ALIGN_FULL);     // or '='

    printf("Left:\n");
    while (list_has_next(left))
        printf("%s\n", cstr(list_next(left)));

    printf("Right:\n");
    while (list_has_next(right))
        printf("%s\n", cstr(list_next(right)));

    printf("Centre:\n");
    while (list_has_next(centre))
        printf("%s\n", cstr(list_next(centre)));

    printf("Full:\n");
    while (list_has_next(full))
        printf("%s\n", cstr(list_next(full)));

    list_destroy(&left);
    list_destroy(&right);
    list_destroy(&centre);
    list_destroy(&full);

    return EXIT_SUCCESS;
}

Split and join a String object without using regular expressions:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    String *text = str_create("line1\nline2\nline3\n");
    List *lines = str_split(text, "\n");
    String *copy;

    while (list_has_next(lines))
        printf("%s\n", cstr(list_next(lines)));

    copy = str_join(lines, "\n");
    printf("%s\n", cstr(copy));

    str_destroy(&text);
    str_destroy(&copy);
    list_destroy(&lines);

    return EXIT_SUCCESS;
}

Split an ordinary C string without using regular expressions:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    char *text = "line1\nline2\nline3\n";
    List *lines = split(text, "\n");

    while (list_has_next(lines))
        printf("%s\n", cstr(list_next(lines)));

    list_destroy(&lines);

    return EXIT_SUCCESS;
}

Split a String object using regular expressions:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    String *text = str_create("line1\rline2\r\nline3\n");
    List *lines = str_regexpr_split(text, "(\n|\r|\r\n)", 0, 0);

    while (list_has_next(lines))
        printf("%s\n", cstr(list_next(lines)));

    str_destroy(&text);
    list_destroy(&lines);

    return EXIT_SUCCESS;
}

Split an ordinary C string using regular expressions:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    char *text = "line1\rline2\r\nline3\n";
    List *lines = regexpr_split(text, "(\n|\r|\r\n)", 0, 0);

    while (list_has_next(lines))
        printf("%s\n", cstr(list_next(lines)));

    list_destroy(&lines);

    return EXIT_SUCCESS;
}

Trim and squeeze String objects:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    String *str1 = str_create("   a  b  c   ");
    String *str2 = str_create("   a  b  c   ");
    String *str3 = str_create("   a  b  c   ");
    String *str4 = str_create("   a  b  c   ");

    str_trim(str1);
    str_trim_left(str2);
    str_trim_right(str3);
    str_squeeze(str4);

    printf("'%s'\n", cstr(str1));
    printf("'%s'\n", cstr(str2));
    printf("'%s'\n", cstr(str3));
    printf("'%s'\n", cstr(str4));

    str_destroy(&str1);
    str_destroy(&str2);
    str_destroy(&str3);
    str_destroy(&str4);

    return EXIT_SUCCESS;
}

Trim and squeeze ordinary C strings:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    char *str1 = strdup("   a  b  c   ");
    char *str2 = strdup("   a  b  c   ");
    char *str3 = strdup("   a  b  c   ");
    char *str4 = strdup("   a  b  c   ");

    trim(str1);
    trim_left(str2);
    trim_right(str3);
    squeeze(str4);

    printf("'%s'\n", str1);
    printf("'%s'\n", str2);
    printf("'%s'\n", str3);
    printf("'%s'\n", str4);

    free(str1);
    free(str2);
    free(str3);
    free(str4);

    return EXIT_SUCCESS;
}

Quote whitespace in a String object:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    String *str = str_create("this is\ta\nstring with  whitespaces");
    String *quoted = str_quote(str, " \t\n", '\\');
    String *unquoted = str_unquote(quoted, " \t\n", '\\');

    printf("'%s'\n", cstr(str));
    printf("'%s'\n", cstr(quoted));
    printf("'%s'\n", cstr(unquoted));

    str_destroy(&str);
    str_destroy(&quoted);
    str_destroy(&unquoted);

    return EXIT_SUCCESS;
}

Quote whitespace in an ordinary C string:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    char *str = "this is\ta\nstring with  whitespaces";
    String *quoted = quote(str, " \t\n", '\\');
    String *unquoted = unquote(cstr(quoted), " \t\n", '\\');

    printf("'%s'\n", str);
    printf("'%s'\n", cstr(quoted));
    printf("'%s'\n", cstr(unquoted));

    str_destroy(&quoted);
    str_destroy(&unquoted);

    return EXIT_SUCCESS;
}

Apply C string literal encoding and decoded to a String object:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    String *str = str_create("\a\b\t\n\v\f\rabc123\x16\034");
    String *encoded = str_encode(str, "\a\b\t\n\v\f\r", "abtnvfr", '\\', 1);
    String *decoded = str_decode(str, "\a\b\t\n\v\f\r", "abtnvfr", '\\', 1);

    printf("'%s'\n", cstr(str));
    printf("'%s'\n", cstr(encoded));
    printf("'%s'\n", cstr(decoded));

    str_destroy(&str);
    str_destroy(&encoded);
    str_destroy(&decoded);

    return EXIT_SUCCESS;
}

Apply C string literal encoding and decoded to an ordinary C string:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    char *str = "\a\b\t\n\v\f\rabc123\x16\034";
    String *encoded = encode(str, "\a\b\t\n\v\f\r", "abtnvfr", '\\', 1);
    String *decoded = decode(str, "\a\b\t\n\v\f\r", "abtnvfr", '\\', 1);

    printf("'%s'\n", str);
    printf("'%s'\n", cstr(encoded));
    printf("'%s'\n", cstr(decoded));

    str_destroy(&encoded);
    str_destroy(&decoded);

    return EXIT_SUCCESS;
}

Get the soundex code of a String object:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    String *smith = str_create("Smith");

    printf("%s %d\n", cstr(smith), str_soundex(smith));

    str_destroy(&smith);

    return EXIT_SUCCESS;
}

Get the soundex code of an ordinary C string:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    char *smith = "Smith";

    printf("%s %d\n", smith, soundex(smith));

    return EXIT_SUCCESS;
}

Convert between upper and lower case in a String object:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    String *str = str_create("smith");

    printf("%s\n", cstr(str));

    str_ucfirst(str);
    printf("%s\n", cstr(str));

    str_uc(str);
    printf("%s\n", cstr(str));

    str_lcfirst(str);
    printf("%s\n", cstr(str));

    str_lc(str);
    printf("%s\n", cstr(str));

    str_destroy(&str);

    return EXIT_SUCCESS;
}

Convert between upper and lower case in an ordinary C string:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    char *str = strdup("smith");
    printf("%s\n", str);
    ucfirst(str);
    printf("%s\n", str);
    uc(str);
    printf("%s\n", str);
    lcfirst(str);
    printf("%s\n", str);
    lc(str);
    printf("%s\n", str);

    free(str);

    return EXIT_SUCCESS;
}

Chomp line ending characters off the end of a String object, and chop a character off the end of a String object:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    String *str = str_create("aaa\r\n");
    int bytes = str_chomp(str);

    printf("'%s' %d\n", cstr(str), bytes);
    bytes = str_chop(str);
    printf("'%s' '%c'\n", cstr(str), bytes);

    str_destroy(&str);

    return EXIT_SUCCESS;
}

Chomp line ending characters off the end of an ordinary C string, and chop a character off the end of an ordinary C string:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    char *str = strdup("aaa\r\n");
    int bytes = chomp(str);

    printf("'%s' %d\n", str, bytes);
    bytes = chop(str);
    printf("'%s' '%c'\n", str, bytes);

    free(str);

    return EXIT_SUCCESS;
}

Parse binary, octal, and hexadecimal integers in String objects:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    String *b = str_create("0b1010");
    String *h = str_create("0x0a1b2c3d");
    String *o = str_create("0177");

    printf("%d\n", str_bin(b));
    printf("%d\n", str_hex(h));
    printf("%d\n", str_oct(o));
    printf("%d\n", str_oct(h));
    printf("%d\n", str_oct(b));

    str_destroy(&b);
    str_destroy(&h);
    str_destroy(&o);

    return EXIT_SUCCESS;
}

Parse binary, octal and hexadecimal integers in ordinary C strings:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    char *b = "0b1010";
    char *h = "0x0a1b2c3d";
    char *o = "0177";

    printf("%d\n", bin(b));
    printf("%d\n", hex(h));
    printf("%d\n", oct(o));
    printf("%d\n", oct(h));
    printf("%d\n", oct(b));

    return EXIT_SUCCESS;
}

Examples of versions of some standard string functions with more informative interfaces:

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    char *src = "text";
    char dst[BUFSIZ];
    char *pos;

    char *eos = cstrcpy(dst, src);
    printf("length '%s' = %d\n", dst, eos - dst);

    eos = cstrcat(dst, src);
    printf("length '%s' = %d\n", dst, eos - dst);

    eos = cstrchr(dst, 'z');
    printf("length '%s' = %d\n", dst, eos - dst);

    for (pos = dst; *(pos = cstrpbrk(pos, "xyz")); ++pos)
        printf("x|y|z at pos %d in %s\n", pos - dst, dst);

    if (*(pos = cstrrchr(dst, 'x')))
        printf("last x in %s at pos %d\n", dst, pos - dst);
    else
        printf("there is no x in %s\n", dst);

    for (pos = dst; *(pos = cstrstr(pos, "text")); ++pos)
        printf("text at pos %d in %s\n", pos - dst, dst);

    return EXIT_SUCCESS;
}

Examples of string functions that are supplied if they are not already present on the local system.

#include <slack/std.h>
#include <slack/str.h>

int main()
{
    char *str1 = "smith, john";
    char *str2 = "Smith, Mary";
    char *str3 = NULL;
    char buf[16];
    size_t len;

    printf("%d\n", strcasecmp(str1, str2));
    printf("%d\n", strncasecmp(str1, str2, 5));
    printf("%d\n", strncasecmp(str1, str2, 8));

    if (strlcpy(buf, str1, 16) >= 16)
        printf("truncation occurred\n");
    printf("%s\n", buf);

    if (strlcat(buf, str2, 16) >= 16)
        printf("truncation occurred\n");
    printf("%s\n", buf);

    if (strlcpy(buf, str1, 1) >= 1)
        printf("truncation occurred\n");
    printf("%s\n", buf);

    len = strlcpy(NULL, str1, 0);
    printf("%d\n", len);

    len = asprintf(&str3, "test");
    printf("%s %d\n", str3, len);
    free(str3);

    return EXIT_SUCCESS;
}

CAVEAT

The delim parameter to the split(3) and join(3) functions is an ordinary C string, so it can't contain nul characters.

The quotable parameter to the quote(3) and unquote(3) functions is an ordinary C string, so it can't contain nul characters.

The uncoded and coded parameters to the str_encode(3) and str_decode(3) functions are ordinary C strings, so they can't contain nul characters.

BUGS

Doesn't support multi-byte/widechar strings, UTF8, UNICODE or ISO 10646 but support can probably be layered over the top of String.

Uses malloc(3) directly. The type of memory used and the allocation strategy should be decoupled from this code.

SEE ALSO

libslack(3), locker(3), string(3), regcomp(3), regexec(3), regerror(3), regfree(3), perlfunc(1), perlop(1)

AUTHOR

20230824 raf <raf@raf.org>