7 /* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
9 typedef unsigned int uint
;
24 typedef struct vg_tex2d vg_tex2d
;
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))
49 enum strncpy_behaviour
{
50 k_strncpy_always_add_null
= 0,
51 k_strncpy_allow_cutoff
= 1,
52 k_strncpy_overflow_fatal
= 2
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
)
59 for( u32 i
=0; i
<len
; i
++ ){
62 if( !src
[i
] ) return i
;
65 if( behaviour
== k_strncpy_always_add_null
){
69 else if( behaviour
== k_strncpy_overflow_fatal
){
70 vg_fatal_error( "Strncpy dest exceeded buffer length\n" );
78 typedef struct vg_str vg_str
;
79 typedef struct vg_str_dynamic vg_str_dynamic
;
83 i32 i
, /* -1: error condition. otherwise, current cursor position */
84 len
; /* -1: dynamically allocated. otherwise, buffer length */
87 struct vg_str_dynamic
{
92 * Returns the current storage size of the string
94 static i32
vg_str_storage( vg_str
*str
){
97 vg_str_dynamic
*arr
= (vg_str_dynamic
*)str
->buffer
;
102 else return str
->len
;
106 * Reset string. If len is -1 (dynamically allocated), buffer must be either
107 * NULL or be acquired from malloc or realloc
109 static void vg_strnull( vg_str
*str
, char *buffer
, i32 len
){
110 str
->buffer
= buffer
;
112 str
->buffer
[0] = '\0';
120 static void vg_strfree( vg_str
*str
){
121 if( str
->len
== -1 ){
123 vg_str_dynamic
*arr
= (vg_str_dynamic
*)str
->buffer
;
133 * Double the size of the dynamically allocated string. If unallocated, alloc of
136 static i32
vg_str_dynamic_grow( vg_str
*str
){
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);
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';
155 * Append null terminated string to vg_str
157 static void vg_strcat( vg_str
*str
, const char *append
){
158 if( !append
|| (str
->i
== -1) ) return;
160 i32 max
= vg_str_storage( str
),
166 max
= vg_str_dynamic_grow( str
);
169 str
->buffer
[ max
-1 ] = '\0';
174 char c
= append
[ i
++ ];
175 str
->buffer
[ str
->i
] = c
;
185 * Append character to vg_str
187 static void vg_strcatch( vg_str
*str
, char c
){
188 vg_strcat( str
, (char[]){ c
, '\0' } );
192 * FIXME: Negative numbers
194 static void vg_strcati32( vg_str
*str
, i32 value
){
198 while( value
&& (i
<31) ){
199 temp
[ i
++ ] = '0' + (value
% 10);
204 for( int j
=0; j
<i
; j
++ )
205 reverse
[j
] = temp
[ i
-1-j
];
208 vg_strcat( str
, reverse
);
211 vg_strcat( str
, "0" );
214 static void vg_strcati32r( vg_str
*str
, i32 value
, i32 n
, char alt
){
221 temp
[ n
-1 - (i
++) ] = '0' + (value
% 10);
226 temp
[ n
-1 - i
] = alt
;
229 vg_strcat( str
, temp
);
233 * Returns 1 if string did not overflow while building
235 static int vg_strgood( vg_str
*str
){
236 if( str
->i
== -1 ) return 0;
241 * Returns pointer to first instance of character
243 static char *vg_strch( vg_str
*str
, char c
){
245 for( i32 i
=0; i
<str
->i
; i
++ ){
246 if( str
->buffer
[i
] == c
)
253 static u32
vg_strdjb2( const char *str
){
256 while( (c
= *str
++) )
257 hash
= ((hash
<< 5) + hash
) + c
; /* hash * 33 + c */
262 static int vg_strdjb2_eq( const char *s1
, u32 h1
,
263 const char *s2
, u32 h2
)
266 if(!strcmp(s1
, s2
)) return 1;
271 #define VG_STRDJB2_EQ( CS1, S2, H2 ) \
272 vg_strdjb2_eq( CS1, vg_strdjb2(CS1), S2, H2 )
275 #define VG_MIN( A, B ) ((A)<(B)?(A):(B))
276 #define VG_MAX( A, B ) ((A)>(B)?(A):(B))