#include <math.h>
#include <stdio.h>
#include <errno.h>
+#include <stdlib.h>
enum strncpy_behaviour{
k_strncpy_always_add_null = 0,
}
typedef struct vg_str vg_str;
+typedef struct vg_str_dynamic vg_str_dynamic;
+
struct vg_str{
char *buffer;
- i32 i, len;
+ i32 i, /* -1: error condition. otherwise, current cursor position */
+ len; /* -1: dynamically allocated. otherwise, buffer length */
+};
+
+struct vg_str_dynamic {
+ i32 len;
};
+/*
+ * Returns the current storage size of the string
+ */
+static i32 vg_str_storage( vg_str *str ){
+ if( str->len == -1 ){
+ if( str->buffer ){
+ vg_str_dynamic *arr = (vg_str_dynamic *)str->buffer;
+ return (arr-1)->len;
+ }
+ else return 0;
+ }
+ else return str->len;
+}
+
+/*
+ * Reset string. If len is -1 (dynamically allocated), buffer must be either
+ * NULL or be acquired from malloc or realloc
+ */
static void vg_strnull( vg_str *str, char *buffer, i32 len ){
str->buffer = buffer;
- str->buffer[0] = '\0';
+ if( buffer )
+ str->buffer[0] = '\0';
+
str->i = 0;
str->len = len;
assert(len);
}
-static void vg_strcat( vg_str *str, const char *append ){
- if( !append ) return;
- if( str->i == -1 ) return;
+static void vg_strfree( vg_str *str ){
+ if( str->len == -1 ){
+ if( str->buffer ){
+ vg_str_dynamic *arr = (vg_str_dynamic *)str->buffer;
+ free( arr-1 );
+
+ str->buffer = NULL;
+ str->i = 0;
+ }
+ }
+}
- for( u32 i=0; str->i < str->len; str->i ++, i ++ ){
- str->buffer[ str->i ] = append[ i ];
+/*
+ * Double the size of the dynamically allocated string. If unallocated, alloc of
+ * 16 bytes minimum.
+ */
+static i32 vg_str_dynamic_grow( vg_str *str ){
+ if( str->buffer ){
+ vg_str_dynamic *hdr = ((vg_str_dynamic *)str->buffer) - 1;
+ i32 total = (hdr->len + sizeof(vg_str_dynamic)) * 2;
+ hdr = realloc( hdr, total );
+ hdr->len = total - sizeof(vg_str_dynamic);
+ str->buffer = (char *)(hdr+1);
+ return hdr->len;
+ }
+ else {
+ vg_str_dynamic *hdr = malloc(16);
+ hdr->len = 16-sizeof(vg_str_dynamic);
+ str->buffer = (char *)(hdr+1);
+ str->buffer[0] = '\0';
+ return hdr->len;
+ }
+}
- if( append[ i ] == '\0' )
+/*
+ * Append null terminated string to vg_str
+ */
+static void vg_strcat( vg_str *str, const char *append ){
+ if( !append || (str->i == -1) ) return;
+
+ i32 max = vg_str_storage( str ),
+ i = 0;
+
+append:
+ if( str->i == max ){
+ if( str->len == -1 )
+ max = vg_str_dynamic_grow( str );
+ else{
+ str->i = -1;
+ str->buffer[ max-1 ] = '\0';
return;
+ }
}
- /* overflow */
- str->buffer[ str->len-1 ] = '\0';
- str->i = -1;
+ char c = append[ i ++ ];
+ str->buffer[ str->i ] = c;
+
+ if( c == '\0' )
+ return;
+
+ str->i ++;
+ goto append;
}
+/*
+ * Append character to vg_str
+ */
static void vg_strcatch( vg_str *str, char c ){
- if( str->i == -1 ) return;
- if( (str->i + 2) > str->len ){
- str->i = -1;
- return;
- }
- str->buffer[ str->i ++ ] = c;
- str->buffer[ str->i ] = '\0';
+ vg_strcat( str, (char[]){ c, '\0' } );
}
-/* FIXME: Negative numbers */
+/*
+ * FIXME: Negative numbers
+ */
static void vg_strcati32( vg_str *str, i32 value ){
if( value ){
char temp[32];
vg_strcat( str, temp );
}
+/*
+ * Returns 1 if string did not overflow while building
+ */
static int vg_strgood( vg_str *str ){
if( str->i == -1 ) return 0;
else return 1;
}
+/*
+ * Returns pointer to first instance of character
+ */
static char *vg_strch( vg_str *str, char c ){
char *ptr = NULL;
for( i32 i=0; i<str->i; i++ ){