/* stringy.h -- a product of boredom and pondering
* by Pegasus Epsilon <pegasus@pimpninjas.org>
* (C)2014 Educational Purposes Only
* Probably not useful for actual things anyway, honestly.
*/
#include <stdlib.h> /* malloc(), realloc(), free() */
#include <string.h> /* str*() */
/* behold! the stringy string, a subclass of the "C string". */
typedef struct string {
/* We put the "C string" first, so that if it's dereferenced incorrectly,
* it still works just fine. The compiler will bitch, though. */
char *cstr;
size_t len;
}* string;
/* Note: the typedef itself is a struct pointer already
* this allows us to directly recast and dereference,
* and treat stringy strings as a builtin type. Mostly. */
/* not sure which of these would offer more sensible type checking... */
#define unstringify(x) ((x)->cstr)
//#define unstringify(x) (*(char **)x)
//char *unstringify (string x) { return x->cstr; }
//char *unstringify (string x) { return *(char **)x; }
/* this is also writeable, but that's a secret */
#define string_len(x) ((x)->len)
/* string_free properly disposes of a stringy string
* DO NOT FREE DIRECTLY, YOU'LL LEAK MEMORY */
void string_free (const string trash) {
free(unstringify(trash));
free(trash);
}
/* stringify converts a C string into a new stringy string
* (and returns said new stringy string).
* Remember to string_free()! */
string stringify (const char *const src) {
string new = malloc(sizeof(string));
strcpy(unstringify(new) = malloc((string_len(new) = strlen(src)) + 1), src);
return new;
}
/* string_dup returns a new stringy string identical to src
* the new cstr is freshly allocated memory, nothing is tied to src.
* Remember to string_free()! */
string string_dup (const string src) {
string new = malloc(sizeof(string));
strcpy(unstringify(new) = malloc((string_len(new) = string_len(src)) + 1), unstringify(src));
return new;
}
/* string_cpy reuses dest's structure, if it exists, but frees and rellocates
* cstr, copying the src's cstr into the new cstr, and copying len as well. */
string string_cpy (string *dest, const string *const src) {
if (NULL == *dest) { *dest = malloc(sizeof(string)); }
else if (unstringify(*dest)) { free(unstringify(*dest)); }
strcpy(unstringify(*dest) = malloc((string_len(*dest) = string_len(*src)) + 1), unstringify(*src));
return *dest;
}
/* string_ncpy is like string_cpy, except at most N bytes are copied.
* Note: a null terminator is NOT explicitly added. See strncpy(3). */
string string_ncpy (string *dest, const string *src, const size_t n) {
if (NULL == *dest) { *dest = malloc(sizeof(string)); }
else if (unstringify(*dest)) { free(unstringify(*dest)); }
strncpy(unstringify(*dest) = malloc((string_len(*dest) = n) + 1), unstringify(*src), n);
return *dest;
}
/* string_cat resizes dest's cstr and copies src's cstr into it, updating len */
string string_cat (string *dest, const string *src) {
strcat(realloc(unstringify(*dest), (string_len(*dest) += string_len(*src)) + 1), unstringify(*src));
return *dest;
}
/* string_ncat is like string_cat, except at most N bytes are copied.
* Note: a null terminator is NOT explicitly added. See strncat(3). */
string string_ncat (string *dest, const string *src, const size_t n) {
strncat(realloc(unstringify(*dest), (string_len(*dest) += n) + 1), unstringify(*src), n);
return *dest;
}