1a38479e139243635011b0c272a6af081c6d6b80
[vg.git] / vg_string.c
1 #include "vg_string.h"
2 #include "vg_platform.h"
3 #include <string.h>
4
5 i32 vg_str_storage( vg_str *str )
6 {
7 if( str->len == -1 ){
8 if( str->buffer ){
9 vg_str_dynamic *arr = (vg_str_dynamic *)str->buffer;
10 return (arr-1)->len;
11 }
12 else return 0;
13 }
14 else return str->len;
15 }
16
17 /*
18 * Reset string. If len is -1 (dynamically allocated), buffer must be either
19 * NULL or be acquired from malloc or realloc
20 */
21 void vg_strnull( vg_str *str, char *buffer, i32 len )
22 {
23 str->buffer = buffer;
24 if( buffer )
25 str->buffer[0] = '\0';
26
27 str->i = 0;
28 str->len = len;
29
30 if( len == 0 )
31 vg_fatal_error( "0 length string allocation\n" );
32 }
33
34 void vg_strfree( vg_str *str )
35 {
36 if( str->len == -1 ){
37 if( str->buffer ){
38 vg_str_dynamic *arr = (vg_str_dynamic *)str->buffer;
39 free( arr-1 );
40
41 str->buffer = NULL;
42 str->i = 0;
43 }
44 }
45 }
46
47 /*
48 * Double the size of the dynamically allocated string. If unallocated, alloc of
49 * 16 bytes minimum.
50 */
51 static i32 vg_str_dynamic_grow( vg_str *str )
52 {
53 if( str->buffer ){
54 vg_str_dynamic *hdr = ((vg_str_dynamic *)str->buffer) - 1;
55 i32 total = (hdr->len + sizeof(vg_str_dynamic)) * 2;
56 hdr = realloc( hdr, total );
57 hdr->len = total - sizeof(vg_str_dynamic);
58 str->buffer = (char *)(hdr+1);
59 return hdr->len;
60 }
61 else {
62 vg_str_dynamic *hdr = malloc(16);
63 hdr->len = 16-sizeof(vg_str_dynamic);
64 str->buffer = (char *)(hdr+1);
65 str->buffer[0] = '\0';
66 return hdr->len;
67 }
68 }
69
70 void vg_strcat( vg_str *str, const char *append )
71 {
72 if( !append || (str->i == -1) ) return;
73
74 i32 max = vg_str_storage( str ),
75 i = 0;
76
77 append:
78 if( str->i == max ){
79 if( str->len == -1 )
80 max = vg_str_dynamic_grow( str );
81 else{
82 str->i = -1;
83 str->buffer[ max-1 ] = '\0';
84 return;
85 }
86 }
87
88 char c = append[ i ++ ];
89 str->buffer[ str->i ] = c;
90
91 if( c == '\0' )
92 return;
93
94 str->i ++;
95 goto append;
96 }
97
98 void vg_strcatch( vg_str *str, char c )
99 {
100 vg_strcat( str, (char[]){ c, '\0' } );
101 }
102
103 /*
104 * FIXME: Negative numbers
105 */
106 void vg_strcati32( vg_str *str, i32 value )
107 {
108 if( value ){
109 char temp[32];
110 int i=0;
111 while( value && (i<31) ){
112 temp[ i ++ ] = '0' + (value % 10);
113 value /= 10;
114 }
115
116 char reverse[32];
117 for( int j=0; j<i; j ++ )
118 reverse[j] = temp[ i-1-j ];
119 reverse[i] = '\0';
120
121 vg_strcat( str, reverse );
122 }
123 else
124 vg_strcat( str, "0" );
125 }
126
127 void vg_strcati32r( vg_str *str, i32 value, i32 n, char alt )
128 {
129 char temp[32];
130 i32 i=0;
131 while( value ){
132 if( i>=n )
133 break;
134
135 temp[ n-1 - (i ++) ] = '0' + (value % 10);
136 value /= 10;
137 }
138
139 for( ;i<n; i ++ )
140 temp[ n-1 - i ] = alt;
141
142 temp[n]='\0';
143 vg_strcat( str, temp );
144 }
145
146 int vg_strgood( vg_str *str )
147 {
148 if( str->i == -1 ) return 0;
149 else return 1;
150 }
151
152 /*
153 * Returns pointer to last instance of character
154 */
155 char *vg_strch( vg_str *str, char c )
156 {
157 char *ptr = NULL;
158 for( i32 i=0; i<str->i; i++ ){
159 if( str->buffer[i] == c )
160 ptr = str->buffer+i;
161 }
162
163 return ptr;
164 }
165
166 u32 vg_strncpy( const char *src, char *dst, u32 len,
167 enum strncpy_behaviour behaviour )
168 {
169 for( u32 i=0; i<len; i++ ){
170 dst[i] = src[i];
171
172 if( !src[i] ) return i;
173
174 if( i == len-1 ){
175 if( behaviour == k_strncpy_always_add_null ){
176 dst[i] = '\0';
177 return i;
178 }
179 else if( behaviour == k_strncpy_overflow_fatal ){
180 vg_fatal_error( "Strncpy dest exceeded buffer length\n" );
181 }
182 }
183 }
184
185 return 0;
186 }
187
188 u32 vg_strdjb2( const char *str )
189 {
190 u32 hash = 5381, c;
191
192 while( (c = *str++) )
193 hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
194
195 return hash;
196 }
197
198 int vg_strdjb2_eq( const char *s1, u32 h1, const char *s2, u32 h2 )
199 {
200 if( h1 == h2 ){
201 if(!strcmp(s1, s2)) return 1;
202 else return 0;
203 } else return 0;
204 }