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