add support for dynamic vg_str's (tooling)
[vg.git] / vg_platform.h
1 #ifndef VG_PLATFORM_H
2 #define VG_PLATFORM_H
3
4 //#include "vg.h"
5 #include "vg_stdint.h"
6
7 /* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
8
9 typedef unsigned int uint;
10
11 typedef int v2i[2];
12 typedef int v3i[3];
13 typedef int v4i[4];
14 typedef float v2f[2];
15 typedef float v3f[3];
16 typedef float v4f[4];
17 typedef v2f m2x2f[2];
18 typedef v3f m3x3f[3];
19 typedef v3f m4x3f[4];
20 typedef v4f m4x4f[4];
21 typedef v3f boxf[2];
22
23 // Resource types
24 typedef struct vg_tex2d vg_tex2d;
25
26 struct vg_achievement
27 {
28 int is_set;
29 const char *name;
30 };
31
32 #define vg_static_assert _Static_assert
33 #define vg_list_size( A ) (sizeof(A)/sizeof(A[0]))
34 #define VG_MUST_USE_RESULT __attribute__((warn_unused_result))
35
36 #include <stdio.h>
37 #include <string.h>
38 #include <stdarg.h>
39 #include <ctype.h>
40 #include <math.h>
41 #include <assert.h>
42 #include <setjmp.h>
43 #include <sys/time.h>
44 #include <math.h>
45 #include <stdio.h>
46 #include <errno.h>
47 #include <stdlib.h>
48
49 enum strncpy_behaviour{
50 k_strncpy_always_add_null = 0,
51 k_strncpy_allow_cutoff = 1,
52 k_strncpy_overflow_fatal = 2
53 };
54
55 static void vg_fatal_error( const char *fmt, ... );
56 static u32 vg_strncpy( const char *src, char *dst, u32 len,
57 enum strncpy_behaviour behaviour )
58 {
59 for( u32 i=0; i<len; i++ ){
60 dst[i] = src[i];
61
62 if( !src[i] ) return i;
63
64 if( i == len-1 ){
65 if( behaviour == k_strncpy_always_add_null ){
66 dst[i] = '\0';
67 return i;
68 }
69 else if( behaviour == k_strncpy_overflow_fatal ){
70 vg_fatal_error( "Strncpy dest exceeded buffer length\n" );
71 }
72 }
73 }
74
75 return 0;
76 }
77
78 typedef struct vg_str vg_str;
79 typedef struct vg_str_dynamic vg_str_dynamic;
80
81 struct vg_str{
82 char *buffer;
83 i32 i, /* -1: error condition. otherwise, current cursor position */
84 len; /* -1: dynamically allocated. otherwise, buffer length */
85 };
86
87 struct vg_str_dynamic {
88 i32 len;
89 };
90
91 /*
92 * Returns the current storage size of the string
93 */
94 static i32 vg_str_storage( vg_str *str ){
95 if( str->len == -1 ){
96 if( str->buffer ){
97 vg_str_dynamic *arr = (vg_str_dynamic *)str->buffer;
98 return (arr-1)->len;
99 }
100 else return 0;
101 }
102 else return str->len;
103 }
104
105 /*
106 * Reset string. If len is -1 (dynamically allocated), buffer must be either
107 * NULL or be acquired from malloc or realloc
108 */
109 static void vg_strnull( vg_str *str, char *buffer, i32 len ){
110 str->buffer = buffer;
111 if( buffer )
112 str->buffer[0] = '\0';
113
114 str->i = 0;
115 str->len = len;
116
117 assert(len);
118 }
119
120 static void vg_strfree( vg_str *str ){
121 if( str->len == -1 ){
122 if( str->buffer ){
123 vg_str_dynamic *arr = (vg_str_dynamic *)str->buffer;
124 free( arr-1 );
125
126 str->buffer = NULL;
127 str->i = 0;
128 }
129 }
130 }
131
132 /*
133 * Double the size of the dynamically allocated string. If unallocated, alloc of
134 * 16 bytes minimum.
135 */
136 static i32 vg_str_dynamic_grow( vg_str *str ){
137 if( str->buffer ){
138 vg_str_dynamic *hdr = ((vg_str_dynamic *)str->buffer) - 1;
139 i32 total = (hdr->len + sizeof(vg_str_dynamic)) * 2;
140 hdr = realloc( hdr, total );
141 hdr->len = total - sizeof(vg_str_dynamic);
142 str->buffer = (char *)(hdr+1);
143 return hdr->len;
144 }
145 else {
146 vg_str_dynamic *hdr = malloc(16);
147 hdr->len = 16-sizeof(vg_str_dynamic);
148 str->buffer = (char *)(hdr+1);
149 str->buffer[0] = '\0';
150 return hdr->len;
151 }
152 }
153
154 /*
155 * Append null terminated string to vg_str
156 */
157 static void vg_strcat( vg_str *str, const char *append ){
158 if( !append || (str->i == -1) ) return;
159
160 i32 max = vg_str_storage( str ),
161 i = 0;
162
163 append:
164 if( str->i == max ){
165 if( str->len == -1 )
166 max = vg_str_dynamic_grow( str );
167 else{
168 str->i = -1;
169 str->buffer[ max-1 ] = '\0';
170 return;
171 }
172 }
173
174 char c = append[ i ++ ];
175 str->buffer[ str->i ] = c;
176
177 if( c == '\0' )
178 return;
179
180 str->i ++;
181 goto append;
182 }
183
184 /*
185 * Append character to vg_str
186 */
187 static void vg_strcatch( vg_str *str, char c ){
188 vg_strcat( str, (char[]){ c, '\0' } );
189 }
190
191 /*
192 * FIXME: Negative numbers
193 */
194 static void vg_strcati32( vg_str *str, i32 value ){
195 if( value ){
196 char temp[32];
197 int i=0;
198 while( value && (i<31) ){
199 temp[ i ++ ] = '0' + (value % 10);
200 value /= 10;
201 }
202
203 char reverse[32];
204 for( int j=0; j<i; j ++ )
205 reverse[j] = temp[ i-1-j ];
206 reverse[i] = '\0';
207
208 vg_strcat( str, reverse );
209 }
210 else
211 vg_strcat( str, "0" );
212 }
213
214 static void vg_strcati32r( vg_str *str, i32 value, i32 n, char alt ){
215 char temp[32];
216 i32 i=0;
217 while( value ){
218 if( i>=n )
219 break;
220
221 temp[ n-1 - (i ++) ] = '0' + (value % 10);
222 value /= 10;
223 }
224
225 for( ;i<n; i ++ )
226 temp[ n-1 - i ] = alt;
227
228 temp[n]='\0';
229 vg_strcat( str, temp );
230 }
231
232 /*
233 * Returns 1 if string did not overflow while building
234 */
235 static int vg_strgood( vg_str *str ){
236 if( str->i == -1 ) return 0;
237 else return 1;
238 }
239
240 /*
241 * Returns pointer to first instance of character
242 */
243 static char *vg_strch( vg_str *str, char c ){
244 char *ptr = NULL;
245 for( i32 i=0; i<str->i; i++ ){
246 if( str->buffer[i] == c )
247 ptr = str->buffer+i;
248 }
249
250 return ptr;
251 }
252
253 static u32 vg_strdjb2( const char *str ){
254 u32 hash = 5381, c;
255
256 while( (c = *str++) )
257 hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
258
259 return hash;
260 }
261
262 static int vg_strdjb2_eq( const char *s1, u32 h1,
263 const char *s2, u32 h2 )
264 {
265 if( h1 == h2 ){
266 if(!strcmp(s1, s2)) return 1;
267 else return 0;
268 } else return 0;
269 }
270
271 #define VG_STRDJB2_EQ( CS1, S2, H2 ) \
272 vg_strdjb2_eq( CS1, vg_strdjb2(CS1), S2, H2 )
273
274
275 #define VG_MIN( A, B ) ((A)<(B)?(A):(B))
276 #define VG_MAX( A, B ) ((A)>(B)?(A):(B))
277 #endif