diff --git a/build_ld_meta.sh b/build_ld_meta.sh index a9b1ae0..cecdab1 100644 --- a/build_ld_meta.sh +++ b/build_ld_meta.sh @@ -2,9 +2,9 @@ code=$PWD opts=-Wno-switch -inc="-I$code/ld_meta/mr4th" +inc="-I$code/symbol_set.ld_meta/mr4th" mkdir -p build cd build -clang -o symbol_set.ld_meta "$code/ld_meta/symbol_set.ld_meta.c" $opts $inc +clang -o symbol_set.ld_meta "$code/symbol_set.ld_meta/symbol_set.ld_meta.c" $opts $inc diff --git a/mr4th/mr4th_base.c b/mr4th/mr4th_base.c deleted file mode 100644 index 42dac71..0000000 --- a/mr4th/mr4th_base.c +++ /dev/null @@ -1,5861 +0,0 @@ -//////////////////////////////////////////////// -//////////////////////////////////////////////// -/////////// BASE IMPLEMENTATION //////////// -//////////////////////////////////////////////// -//////////////////////////////////////////////// - -//////////////////////////////// -// Functions: Numerical/Math - -// infinity - -MR4TH_SYMBOL B32 -is_inf_or_nan_F32(F32 x){ - U32 u = *(U32*)&x; - B32 result = ((u&0x7f800000) == 0x7f800000); - return(result); -} - -MR4TH_SYMBOL B32 -is_inf_or_nan_F64(F64 x){ - U64 u = *(U64*)&x; - B64 result = ((u&0x7ff0000000000000) == 0x7ff0000000000000); - return(result); -} - -// float signs, rounding, and modulus - -MR4TH_SYMBOL F32 -abs_F32(F32 x){ - union{ F32 f; U32 u; } r; - r.f = x; - r.u &= 0x7fffffff; - return(r.f); -} - -MR4TH_SYMBOL F32 -sign_F32(F32 x){ - union{ F32 f; U32 u; } r; - r.f = x; - F32 result = (r.u&0x80000000)?-1.f:1.f; - return(result); -} - -MR4TH_SYMBOL F32 -trunc_F32(F32 x){ - return((x < 0x1p23)?(F32)(S32)x:x); -} - -MR4TH_SYMBOL F32 -floor_F32(F32 x){ - F32 r = trunc_F32(x); - if (x < r){ - r -= 1.f; - } - return(r); -} - -MR4TH_SYMBOL F32 -ceil_F32(F32 x){ - F32 r = trunc_F32(x); - if (x > r){ - r += 1.f; - } - return(r); -} - -MR4TH_SYMBOL F32 -nearest_F32(F32 x){ - F32 r = floor_F32(x + 0.5f); - return(r); -} - -MR4TH_SYMBOL F32 -mod_F32(F32 x, F32 m){ - Assert(m > 0.f); - // + | - - F32 q = (x/m); // (x/m) | (x/m) - S32 q_s32 = (S32)q; // floor(x/m) | ceil(x/m) - F32 r = m*(F32)q_s32;// m*floor(x/m) | m*ceil(x/m) - // <= x | >= x - F32 d = x - r; - if (d < 0){ - d += m; - } - return(d); -} - -MR4TH_SYMBOL F32 -frac_F32(F32 x){ - // + | - - F32 q = (x); // (x) | (x) - S32 q_s32 = (S32)q; // floor(x) | ceil(x) - F32 r = (F32)q_s32; // floor(x) | ceil(x) - // <= x | >= x - F32 d = x - r; - return(d); -} - -MR4TH_SYMBOL F64 -abs_F64(F64 x){ - union{ F64 f; U64 u; } r; - r.f = x; - r.u &= 0x7fffffffffffffff; - return(r.f); -} - -MR4TH_SYMBOL F64 -sign_F64(F64 x){ - union{ F64 f; U32 u; } r; - r.f = x; - F64 result = (r.u&0x8000000000000000)?-1.:1.; - return(result); -} - -MR4TH_SYMBOL F64 -trunc_F64(F64 x){ - return((x < 0x1p52)?(F64)(S64)x:x); -} - -MR4TH_SYMBOL F64 -floor_F64(F64 x){ - F64 r = trunc_F64(x); - if (x < r){ - r -= 1.f; - } - return(r); -} - -MR4TH_SYMBOL F64 -ceil_F64(F64 x){ - F64 r = trunc_F64(x); - if (x > r){ - r += 1.f; - } - return(r); -} - -MR4TH_SYMBOL F64 -nearest_F64(F64 x){ - F64 r = floor_F64(x + 0.5f); - return(r); -} - -MR4TH_SYMBOL F64 -mod_F64(F64 x, F64 m){ - Assert(m > 0.f); - // + | - - F64 q = (x/m); // (x/m) | (x/m) - S64 q_s64 = (S64)q; // floor(x/m) | ceil(x/m) - F64 r = m*(F64)q_s64;// m*floor(x/m) | m*ceil(x/m) - // <= x | >= x - F64 d = x - r; - if (d < 0){ - d += m; - } - return(d); -} - -MR4TH_SYMBOL F64 -frac_F64(F64 x){ - // + | - - F64 q = (x); // (x) | (x) - S64 q_s64 = (S64)q; // floor(x) | ceil(x) - F64 r = (F64)q_s64; // floor(x) | ceil(x) - // <= x | >= x - F64 d = x - r; - return(d); -} - -// transcendental functions - -#include - -MR4TH_SYMBOL F32 -sin_F32(F32 x){ - return(sinf(x*tau_F32)); -} - -MR4TH_SYMBOL F32 -cos_F32(F32 x){ - return(cosf(x*tau_F32)); -} - -MR4TH_SYMBOL F32 -tan_F32(F32 x){ - return(tanf(x*tau_F32)); -} - -MR4TH_SYMBOL F32 -atan_F32(F32 x){ - return(atanf(x)/tau_F32); -} - -MR4TH_SYMBOL F32 -atan2_F32(F32 x, F32 y){ - return(atan2f(y, x)/tau_F32); -} - -MR4TH_SYMBOL F32 -sqrt_F32(F32 x){ - return(sqrtf(x)); -} - -MR4TH_SYMBOL F32 -inv_sqrt_F32(F32 x){ - return(1.f/sqrtf(x)); -} - -MR4TH_SYMBOL F32 -ln_F32(F32 x){ - return(logf(x)); -} - -MR4TH_SYMBOL F32 -pow_F32(F32 base, F32 x){ - return(powf(base, x)); -} - -MR4TH_SYMBOL F64 -sin_F64(F64 x){ - return(sin(x*tau_F64)); -} - -MR4TH_SYMBOL F64 -cos_F64(F64 x){ - return(cos(x*tau_F64)); -} - -MR4TH_SYMBOL F64 -tan_F64(F64 x){ - return(tan(x*tau_F64)); -} - -MR4TH_SYMBOL F64 -atan_F64(F64 x){ - return(atan(x)/tau_F64); -} - -MR4TH_SYMBOL F64 -atan2_F64(F64 x, F64 y){ - return(atan2(x, y)/tau_F64); -} - -MR4TH_SYMBOL F64 -sqrt_F64(F64 x){ - return(sqrt(x)); -} - -MR4TH_SYMBOL F64 -inv_sqrt_F64(F64 x){ - return(1.f/sqrt(x)); -} - -MR4TH_SYMBOL F64 -ln_F64(F64 x){ - return(log(x)); -} - -MR4TH_SYMBOL F64 -pow_F64(F64 base, F64 x){ - return(powf(base, x)); -} - -// linear interpolation - -MR4TH_SYMBOL F32 -lerp(F32 a, F32 t, F32 b){ - F32 x = a + (b - a)*t; - return(x); -} - -MR4TH_SYMBOL F32 -unlerp(F32 a, F32 x, F32 b){ - F32 t = 0.f; - if (a != b){ - t = (x - a)/(b - a); - } - return(t); -} - -// integer rounding - -MR4TH_SYMBOL U32 -next_pow2_U32(U32 x){ - U32 result = x; - if (result == 0){ - result = 1; - } - else{ - // TODO(allen): speed up with bit scan intrinsic - result -= 1; - result |= (result >> 1); - result |= (result >> 2); - result |= (result >> 4); - result |= (result >> 8); - result |= (result >> 16); - result += 1; - } - return(result); -} - -MR4TH_SYMBOL S32 -sign_extend_S32(S32 x, U32 bitidx){ - U32 shiftn = (31 - bitidx); - x = x << shiftn; - x = x >> shiftn; - return(x); -} - -MR4TH_SYMBOL U64 -next_pow2_U64(U32 x){ - U64 result = x; - if (result == 0){ - result = 1; - } - else{ - // TODO(allen): speed up with bit scan intrinsic - result -= 1; - result |= (result >> 1); - result |= (result >> 2); - result |= (result >> 4); - result |= (result >> 8); - result |= (result >> 16); - result |= (result >> 32); - result += 1; - } - return(result); -} - -MR4TH_SYMBOL S64 -sign_extend_S64(S64 x, U32 bitidx){ - U32 shiftn = (63 - bitidx); - x = x << shiftn; - x = x >> shiftn; - return(x); -} - -//////////////////////////////// -// Functions: Compound Types - -// 2d vectors - -MR4TH_SYMBOL V2F32 -v2_polar(F32 theta, F32 radius){ - V2F32 result = {radius*cos_F32(theta), radius*sin_F32(theta)}; - return(result); -} - -MR4TH_SYMBOL F32 -angle_from_v2f32(V2F32 v){ - F32 result = atan2_F32(v.x, v.y); - return(result); -} - -MR4TH_SYMBOL V2F32 -v2_unit(V2F32 v){ - F32 recip = inv_sqrt_F32(v.x*v.x + v.y*v.y); - V2F32 r = {0}; - r.x = v.x*recip; - r.y = v.y*recip; - return(r); -} - -// 3d vectors - -MR4TH_SYMBOL V3F32 -v3_spherical(F32 theta_xz, F32 theta_yz, F32 radius){ - F32 sxz = sin_F32(theta_xz); - F32 syz = sin_F32(theta_yz); - F32 cxz = cos_F32(theta_xz); - F32 cyz = cos_F32(theta_yz); - - V3F32 result = {0}; - result.x = radius*sxz; - result.y = radius*syz; - result.z = radius*cxz*cyz; - return(result); -} - -MR4TH_SYMBOL V3F32 -v3_cross(V3F32 a, V3F32 b){ - V3F32 result = { - a.y*b.z - a.z*b.y, - a.z*b.x - a.x*b.z, - a.x*b.y - a.y*b.x, - }; - return(result); -} - -MR4TH_SYMBOL V3F32 -v3_unit(V3F32 v){ - F32 recip = inv_sqrt_F32(v.x*v.x + v.y*v.y + v.z*v.z); - V3F32 r = {0}; - r.x = v.x*recip; - r.y = v.y*recip; - r.z = v.z*recip; - return(r); -} - -// 4x4 matrix - -MR4TH_SYMBOL B32 -mat4x4_inv(F32 *in, F32 *out){ - /* credit: https://github.com/niswegmann/small-matrix-inverse/tree/master */ - - out[0] = - + in[ 5]*in[10]*in[15] - - in[ 5]*in[11]*in[14] - - in[ 9]*in[ 6]*in[15] - + in[ 9]*in[ 7]*in[14] - + in[13]*in[ 6]*in[11] - - in[13]*in[ 7]*in[10]; - - out[1] = - - in[ 1]*in[10]*in[15] - + in[ 1]*in[11]*in[14] - + in[ 9]*in[ 2]*in[15] - - in[ 9]*in[ 3]*in[14] - - in[13]*in[ 2]*in[11] - + in[13]*in[ 3]*in[10]; - - out[2] = - + in[ 1]*in[ 6]*in[15] - - in[ 1]*in[ 7]*in[14] - - in[ 5]*in[ 2]*in[15] - + in[ 5]*in[ 3]*in[14] - + in[13]*in[ 2]*in[ 7] - - in[13]*in[ 3]*in[ 6]; - - out[3] = - - in[ 1]*in[ 6]*in[11] - + in[ 1]*in[ 7]*in[10] - + in[ 5]*in[ 2]*in[11] - - in[ 5]*in[ 3]*in[10] - - in[ 9]*in[ 2]*in[ 7] - + in[ 9]*in[ 3]*in[ 6]; - - out[4] = - - in[ 4]*in[10]*in[15] - + in[ 4]*in[11]*in[14] - + in[ 8]*in[ 6]*in[15] - - in[ 8]*in[ 7]*in[14] - - in[12]*in[ 6]*in[11] - + in[12]*in[ 7]*in[10]; - - out[5] = - + in[ 0]*in[10]*in[15] - - in[ 0]*in[11]*in[14] - - in[ 8]*in[ 2]*in[15] - + in[ 8]*in[ 3]*in[14] - + in[12]*in[ 2]*in[11] - - in[12]*in[ 3]*in[10]; - - out[6] = - - in[ 0]*in[ 6]*in[15] - + in[ 0]*in[ 7]*in[14] - + in[ 4]*in[ 2]*in[15] - - in[ 4]*in[ 3]*in[14] - - in[12]*in[ 2]*in[ 7] - + in[12]*in[ 3]*in[ 6]; - - out[7] = - + in[ 0]*in[ 6]*in[11] - - in[ 0]*in[ 7]*in[10] - - in[ 4]*in[ 2]*in[11] - + in[ 4]*in[ 3]*in[10] - + in[ 8]*in[ 2]*in[ 7] - - in[ 8]*in[ 3]*in[ 6]; - - out[8] = - + in[ 4]*in[ 9]*in[15] - - in[ 4]*in[11]*in[13] - - in[ 8]*in[ 5]*in[15] - + in[ 8]*in[ 7]*in[13] - + in[12]*in[ 5]*in[11] - - in[12]*in[ 7]*in[ 9]; - - out[9] = - - in[ 0]*in[ 9]*in[15] - + in[ 0]*in[11]*in[13] - + in[ 8]*in[ 1]*in[15] - - in[ 8]*in[ 3]*in[13] - - in[12]*in[ 1]*in[11] - + in[12]*in[ 3]*in[ 9]; - - out[10] = - + in[ 0]*in[ 5]*in[15] - - in[ 0]*in[ 7]*in[13] - - in[ 4]*in[ 1]*in[15] - + in[ 4]*in[ 3]*in[13] - + in[12]*in[ 1]*in[ 7] - - in[12]*in[ 3]*in[ 5]; - - out[11] = - - in[ 0]*in[ 5]*in[11] - + in[ 0]*in[ 7]*in[ 9] - + in[ 4]*in[ 1]*in[11] - - in[ 4]*in[ 3]*in[ 9] - - in[ 8]*in[ 1]*in[ 7] - + in[ 8]*in[ 3]*in[ 5]; - - out[12] = - - in[ 4]*in[ 9]*in[14] - + in[ 4]*in[10]*in[13] - + in[ 8]*in[ 5]*in[14] - - in[ 8]*in[ 6]*in[13] - - in[12]*in[ 5]*in[10] - + in[12]*in[ 6]*in[ 9]; - - out[13] = - + in[ 0]*in[ 9]*in[14] - - in[ 0]*in[10]*in[13] - - in[ 8]*in[ 1]*in[14] - + in[ 8]*in[ 2]*in[13] - + in[12]*in[ 1]*in[10] - - in[12]*in[ 2]*in[ 9]; - - out[14] = - - in[ 0]*in[ 5]*in[14] - + in[ 0]*in[ 6]*in[13] - + in[ 4]*in[ 1]*in[14] - - in[ 4]*in[ 2]*in[13] - - in[12]*in[ 1]*in[ 6] - + in[12]*in[ 2]*in[ 5]; - - out[15] = - + in[ 0]*in[ 5]*in[10] - - in[ 0]*in[ 6]*in[ 9] - - in[ 4]*in[ 1]*in[10] - + in[ 4]*in[ 2]*in[ 9] - + in[ 8]*in[ 1]*in[ 6] - - in[ 8]*in[ 2]*in[ 5]; - - F32 det = in[0]*out[0] + in[1]*out[4] + in[2]*out[8] + in[3]*out[12]; - - B32 result = 0; - if (det != 0.f){ - F32 invdet = 1.f/det; - for (U32 i = 0; i < 16; i += 1){ - out[i] *= invdet; - } - result = 1; - } - - return(result); -} - -MR4TH_SYMBOL void -mat4x4_mul(F32 *a, F32 *b, F32 *out){ - out[ 0] = a[ 0]*b[ 0] + a[ 1]*b[ 4] + a[ 2]*b[ 8] + a[ 3]*b[12]; - out[ 1] = a[ 0]*b[ 1] + a[ 1]*b[ 5] + a[ 2]*b[ 9] + a[ 3]*b[13]; - out[ 2] = a[ 0]*b[ 2] + a[ 1]*b[ 6] + a[ 2]*b[10] + a[ 3]*b[14]; - out[ 3] = a[ 0]*b[ 3] + a[ 1]*b[ 7] + a[ 2]*b[11] + a[ 3]*b[15]; - out[ 4] = a[ 4]*b[ 0] + a[ 5]*b[ 4] + a[ 6]*b[ 8] + a[ 7]*b[12]; - out[ 5] = a[ 4]*b[ 1] + a[ 5]*b[ 5] + a[ 6]*b[ 9] + a[ 7]*b[13]; - out[ 6] = a[ 4]*b[ 2] + a[ 5]*b[ 6] + a[ 6]*b[10] + a[ 7]*b[14]; - out[ 7] = a[ 4]*b[ 3] + a[ 5]*b[ 7] + a[ 6]*b[11] + a[ 7]*b[15]; - out[ 8] = a[ 8]*b[ 0] + a[ 9]*b[ 4] + a[10]*b[ 8] + a[11]*b[12]; - out[ 9] = a[ 8]*b[ 1] + a[ 9]*b[ 5] + a[10]*b[ 9] + a[11]*b[13]; - out[10] = a[ 8]*b[ 2] + a[ 9]*b[ 6] + a[10]*b[10] + a[11]*b[14]; - out[11] = a[ 8]*b[ 3] + a[ 9]*b[ 7] + a[10]*b[11] + a[11]*b[15]; - out[12] = a[12]*b[ 0] + a[13]*b[ 4] + a[14]*b[ 8] + a[15]*b[12]; - out[13] = a[12]*b[ 1] + a[13]*b[ 5] + a[14]*b[ 9] + a[15]*b[13]; - out[14] = a[12]*b[ 2] + a[13]*b[ 6] + a[14]*b[10] + a[15]*b[14]; - out[15] = a[12]*b[ 3] + a[13]*b[ 7] + a[14]*b[11] + a[15]*b[15]; -} - -//////////////////////////////// -// Functions: Memory Operations - -MR4TH_SYMBOL void -memory_zero(void *ptr, U64 size){ - U64 z64 = size/8; - U64 z8 = size%8; - - U64 *p64 = (U64*)ptr; - for (;z64 > 0;){ - *p64 = 0; - p64 += 1; - z64 -= 1; - } - U8 *p8 = (U8*)p64; - for (;z8 > 0;){ - *p8 = 0; - p8 += 1; - z8 -= 1; - } -} - -MR4TH_SYMBOL void -memory_fill(void *ptr, U64 size, U8 fillbyte){ - U64 fillqword = fillbyte; - { - fillqword |= fillqword << 8; - fillqword |= fillqword << 16; - fillqword |= fillqword << 32; - } - - U64 z64 = size/8; - U64 z8 = size%8; - - U64 *p64 = (U64*)ptr; - for (;z64 > 0;){ - *p64 = fillqword; - p64 += 1; - z64 -= 1; - } - U8 *p8 = (U8*)p64; - for (;z8 > 0;){ - *p8 = fillbyte; - p8 += 1; - z8 -= 1; - } -} - -MR4TH_SYMBOL B32 -memory_match(void *a, void *b, U64 size){ - U64 z64 = size/8; - U64 z8 = size%8; - - U64 *a64 = (U64*)a; - U64 *b64 = (U64*)b; - for (;z64 > 0;){ - if (*a64 != *b64){ - return(0); - } - a64 += 1; - b64 += 1; - z64 -= 1; - } - - U8 *a8 = (U8*)a64; - U8 *b8 = (U8*)b64; - for (;z8 > 0;){ - if (*a8 != *b8){ - return(0); - } - a8 += 1; - b8 += 1; - z8 -= 1; - } - - return(1); -} - -MR4TH_SYMBOL void* -memory_move(void *dst, void *src, U64 size){ - U64 z64 = size/8; - U64 z8 = size%8; - - // backwards - if ((U8*)src < (U8*)dst){ - U8 *dst8 = ((U8*)dst) + size; - U8 *src8 = ((U8*)src) + size; - for (;z8 > 0;){ - dst8 -= 1; - src8 -= 1; - *dst8 = *src8; - z8 -= 1; - } - U64 *dst64 = (U64*)dst8; - U64 *src64 = (U64*)src8; - for (;z64 > 0;){ - dst64 -= 1; - src64 -= 1; - *dst64 = *src64; - z64 -= 1; - } - } - - // forwards - else if ((U8*)src > (U8*)dst){ - U64 *dst64 = (U64*)dst; - U64 *src64 = (U64*)src; - for (;z64 > 0;){ - *dst64 = *src64; - dst64 += 1; - src64 += 1; - z64 -= 1; - } - U8 *dst8 = (U8*)dst64; - U8 *src8 = (U8*)src64; - for (;z8 > 0;){ - *dst8 = *src8; - dst8 += 1; - src8 += 1; - z8 -= 1; - } - } - - return(dst); -} - -//////////////////////////////// -// Functions: Symbolic Constants - -MR4TH_SYMBOL OperatingSystem -operating_system_from_context(void){ - OperatingSystem result = OperatingSystem_Null; -#if OS_WINDOWS - result = OperatingSystem_Windows; -#elif OS_LINUX - result = OperatingSystem_Linux; -#elif OS_MAC - result = OperatingSystem_Mac; -#endif - return(result); -} - -MR4TH_SYMBOL Architecture -architecture_from_context(void){ - Architecture result = Architecture_Null; -#if ARCH_X64 - result = Architecture_X64; -#elif ARCH_X86 - result = Architecture_X86; -#elif ARCH_ARM - result = Architecture_Arm; -#elif ARCH_ARM64 - result = Architecture_Arm64; -#endif - return(result); -} - -MR4TH_SYMBOL char* -string_from_operating_system(OperatingSystem os){ - char *result = "(null)"; - switch (os){ - default:break; - case OperatingSystem_Windows: - { - result = "windows"; - }break; - case OperatingSystem_Linux: - { - result = "linux"; - }break; - case OperatingSystem_Mac: - { - result = "mac"; - }break; - } - return(result); -} - -MR4TH_SYMBOL char* -string_from_architecture(Architecture arch){ - char *result = "(null)"; - switch (arch){ - default:break; - case Architecture_X64: - { - result = "x64"; - }break; - case Architecture_X86: - { - result = "x86"; - }break; - case Architecture_Arm: - { - result = "arm"; - }break; - case Architecture_Arm64: - { - result = "armm64"; - }break; - } - return(result); -} - -MR4TH_SYMBOL char* -string_from_month(Month month){ - char *result = "(null)"; - switch (month){ - case Month_Jan: - { - result = "jan"; - }break; - case Month_Feb: - { - result = "feb"; - }break; - case Month_Mar: - { - result = "mar"; - }break; - case Month_Apr: - { - result = "apr"; - }break; - case Month_May: - { - result = "may"; - }break; - case Month_Jun: - { - result = "jun"; - }break; - case Month_Jul: - { - result = "jul"; - }break; - case Month_Aug: - { - result = "aug"; - }break; - case Month_Sep: - { - result = "sep"; - }break; - case Month_Oct: - { - result = "oct"; - }break; - case Month_Nov: - { - result = "nov"; - }break; - case Month_Dec: - { - result = "dec"; - }break; - } - return(result); -} - -MR4TH_SYMBOL char* -string_from_day_of_week(DayOfWeek day_of_week){ - char *result = "(null)"; - switch (day_of_week){ - case DayOfWeek_Sunday: - { - result = "sunday"; - }break; - case DayOfWeek_Monday: - { - result = "monday"; - }break; - case DayOfWeek_Tuesday: - { - result = "tuesday"; - }break; - case DayOfWeek_Wednesday: - { - result = "wednesday"; - }break; - case DayOfWeek_Thursday: - { - result = "thursday"; - }break; - case DayOfWeek_Friday: - { - result = "friday"; - }break; - case DayOfWeek_Saturday: - { - result = "saturday"; - }break; - } - return(result); -} - -//////////////////////////////// -// Functions: Time - -MR4TH_SYMBOL DenseTime -dense_time_from_date_time(DateTime *in){ - U32 year_encoded = (U32)((S32)in->year + 0x8000); - DenseTime result = 0; - result += year_encoded; - result *= 12; - result += (in->mon - 1); - result *= 31; - result += (in->day - 1); - result *= 24; - result += in->hour; - result *= 60; - result += in->min; - result *= 61; - result += in->sec; - result *= 1000; - result += in->msec; - return(result); -} - -MR4TH_SYMBOL DateTime -date_time_from_dense_time(DenseTime in){ - DateTime result = {0}; - result.msec = in%1000; - in /= 1000; - result.sec = in%61; - in /= 61; - result.min = in%60; - in /= 60; - result.hour = in%24; - in /= 24; - result.day = (in%31) + 1; - in /= 31; - result.mon = (in%12) + 1; - in /= 12; - S32 year_encoded = (S32)in; - result.year = (year_encoded - 0x8000); - return(result); -} - -//////////////////////////////// -// Functions: Arena - -// arena core implementation - -#define MR4TH_MEM_COMMIT_BLOCK_SIZE MB(64) -#define MR4TH_MEM_MAX_ALIGN 64 -#define MR4TH_MEM_SCRATCH_POOL_COUNT 2 - -struct Arena{ - Arena *current; - Arena *prev; - U64 default_reserve_size; - U16 alignment; - B8 growing; - U8 filler[5]; - U64 base_pos; - U64 chunk_cap; - U64 chunk_pos; - U64 chunk_commit_pos; -}; - -#define MEM_INITIAL_COMMIT KB(4) -#define MEM_INTERNAL_MIN_SIZE AlignUpPow2(sizeof(Arena), MR4TH_MEM_MAX_ALIGN) - -#if !MR4TH_PLUGIN_MODE - -// arena pre-requisites - -StaticAssert(sizeof(Arena) <= MEM_INITIAL_COMMIT, mem_check_arena_size); - -StaticAssert(IsPow2OrZero(MR4TH_MEM_COMMIT_BLOCK_SIZE) && - MR4TH_MEM_COMMIT_BLOCK_SIZE != 0, - mem_check_commit_block_size); - -StaticAssert(IsPow2OrZero(MR4TH_MEM_MAX_ALIGN) && MR4TH_MEM_MAX_ALIGN != 0, - mem_check_max_align); - -// arena functions - -MR4TH_SYMBOL_MUST_SHARE Arena* -arena_new(U64 reserve_size, U64 alignment, B32 growing){ - ProfBeginFunc(); - - Arena *result = 0; - if (reserve_size >= MEM_INITIAL_COMMIT){ - void *memory = os_memory_reserve(reserve_size); - if (os_memory_commit(memory, MEM_INITIAL_COMMIT)){ - AsanPoison(memory, reserve_size); - AsanUnpoison(memory, MEM_INTERNAL_MIN_SIZE); - result = (Arena*)memory; - result->current = result; - result->prev = 0; - result->alignment = alignment; - result->default_reserve_size = reserve_size; - result->growing = growing; - result->base_pos = 0; - result->chunk_cap = reserve_size; - result->chunk_pos = MEM_INTERNAL_MIN_SIZE; - result->chunk_commit_pos = MEM_INITIAL_COMMIT; - } - } - Assert(result != 0); - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL_MUST_SHARE void -arena_release(Arena *arena){ - ProfBeginFunc(); - - Arena *ptr = arena->current; - for (;ptr != 0;){ - Arena *prev = ptr->prev; - AsanPoison(ptr, ptr->chunk_cap); - os_memory_release(ptr, ptr->chunk_cap); - ptr = prev; - } - - ProfEndFunc(); -} - -MR4TH_SYMBOL_MUST_SHARE void* -arena_push_no_zero(Arena *arena, U64 size){ - ProfBeginFunc(); - - void *result = 0; - Arena *current = arena->current; - - // allocate new chunk if necessary - if (arena->growing){ - U64 next_chunk_pos = AlignUpPow2(current->chunk_pos, arena->alignment); - next_chunk_pos += size; - if (next_chunk_pos > current->chunk_cap){ - U64 new_reserve_size = arena->default_reserve_size; - U64 enough_to_fit = size + MEM_INTERNAL_MIN_SIZE; - if (new_reserve_size < enough_to_fit){ - new_reserve_size = AlignUpPow2(enough_to_fit, KB(4)); - } - - void *memory = os_memory_reserve(new_reserve_size); - if (os_memory_commit(memory, MEM_INITIAL_COMMIT)){ - AsanPoison(memory, new_reserve_size); - AsanUnpoison(memory, MEM_INTERNAL_MIN_SIZE); - Arena *new_chunk = (Arena*)memory; - new_chunk->prev = current; - new_chunk->base_pos = current->base_pos + current->chunk_cap; - new_chunk->chunk_cap = new_reserve_size; - new_chunk->chunk_pos = MEM_INTERNAL_MIN_SIZE; - new_chunk->chunk_commit_pos = MEM_INITIAL_COMMIT; - current = arena->current = new_chunk; - } - } - } - - { - // if there is room in this chunk's reserve ... - U64 result_pos = AlignUpPow2(current->chunk_pos, arena->alignment); - U64 next_chunk_pos = result_pos + size; - if (next_chunk_pos <= current->chunk_cap){ - - // commit more memory if necessary - if (next_chunk_pos > current->chunk_commit_pos){ - U64 next_commit_pos_aligned = - AlignUpPow2(next_chunk_pos, MR4TH_MEM_COMMIT_BLOCK_SIZE); - U64 next_commit_pos = - ClampTop(next_commit_pos_aligned, current->chunk_cap); - U64 commit_size = next_commit_pos - current->chunk_commit_pos; - if (os_memory_commit((U8*)current + current->chunk_commit_pos, commit_size)){ - current->chunk_commit_pos = next_commit_pos; - } - } - - // if there is room in the commit range, return memory & advance pos - if (next_chunk_pos <= current->chunk_commit_pos){ - AsanUnpoison((U8*)current + current->chunk_pos, - next_chunk_pos - current->chunk_pos); - result = (U8*)current + result_pos; - current->chunk_pos = next_chunk_pos; - } - } - } - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL_MUST_SHARE void -arena_pop_to(Arena *arena, U64 pos){ - ProfBeginFunc(); - - U64 clamped_total_pos = ClampBot(pos, MEM_INTERNAL_MIN_SIZE); - - Arena *current = arena->current; - U64 total_pos = current->base_pos + current->chunk_pos; - if (clamped_total_pos < total_pos){ - // release all chunks that begin after this pos - for (; clamped_total_pos < current->base_pos; ){ - Arena *prev = current->prev; - AsanPoison(current, current->chunk_cap); - os_memory_release(current, current->chunk_cap); - current = prev; - } - - // update arena's current - { - arena->current = current; - } - - // update the chunk position of the chunk in - // the chain that contains this position. - { - U64 chunk_pos = clamped_total_pos - current->base_pos; - U64 clamped_chunk_pos = ClampBot(chunk_pos, MEM_INTERNAL_MIN_SIZE); - AsanPoison((U8*)current + clamped_chunk_pos, - current->chunk_pos - clamped_chunk_pos); - current->chunk_pos = clamped_chunk_pos; - } - } - - ProfEndFunc(); -} - -MR4TH_SYMBOL_MUST_SHARE U64 -arena_current_pos(Arena *arena){ - Arena *current = arena->current; - U64 result = current->base_pos + current->chunk_pos; - return(result); -} - -MR4TH_SYMBOL_MUST_SHARE U64 -arena_current_align(Arena *arena){ - return(arena->alignment); -} - -MR4TH_SYMBOL_MUST_SHARE void -arena_set_align(Arena *arena, U64 alignment){ - arena->alignment = alignment; -} - -MR4TH_SYMBOL_STATIC MR4TH_THREADVAR -Arena *arena__scratch_pool[MR4TH_MEM_SCRATCH_POOL_COUNT] = {0}; - -MR4TH_SYMBOL_MUST_SHARE ArenaTemp -arena_get_scratch(Arena **conflict_array, U32 count){ - ProfBeginFunc(); - - // init on first time - if (arena__scratch_pool[0] == 0){ - Arena **scratch_slot = arena__scratch_pool; - for (U64 i = 0; - i < MR4TH_MEM_SCRATCH_POOL_COUNT; - i += 1, scratch_slot += 1){ - *scratch_slot = arena_alloc(); - } - } - - // get non-conflicting arena - ArenaTemp result = {0}; - Arena **scratch_slot = arena__scratch_pool; - for (U64 i = 0; - i < MR4TH_MEM_SCRATCH_POOL_COUNT; - i += 1, scratch_slot += 1){ - B32 is_non_conflict = 1; - Arena **conflict_ptr = conflict_array; - for (U32 j = 0; j < count; j += 1, conflict_ptr += 1){ - if (*scratch_slot == *conflict_ptr){ - is_non_conflict = 0; - break; - } - } - if (is_non_conflict){ - result = arena_begin_temp(*scratch_slot); - break; - } - } - - ProfEndFunc(); - return(result); -} - -#endif /* arena core implementation */ - -// arena helpers - -#if !defined(MR4TH_MEM_DEFAULT_RESERVE_SIZE) -# define MR4TH_MEM_DEFAULT_RESERVE_SIZE GB(1) -#endif -#if !defined(MR4TH_MEM_DEFAULT_ALIGNMENT) -# define MR4TH_MEM_DEFAULT_ALIGNMENT sizeof(void*) -#endif - -MR4TH_SYMBOL Arena* -arena_alloc(void){ - Arena *result = arena_new(MR4TH_MEM_DEFAULT_RESERVE_SIZE, MR4TH_MEM_DEFAULT_ALIGNMENT, 1); - return(result); -} - -MR4TH_SYMBOL void* -arena_push(Arena *arena, U64 size){ - void *result = arena_push_no_zero(arena, size); - MemoryZero(result, size); - return(result); -} - -MR4TH_SYMBOL void -arena_pop_amount(Arena *arena, U64 amount){ - U64 pos = arena_current_pos(arena); - U64 new_pos = 0; - if (pos > amount){ - new_pos = pos - amount; - } - arena_pop_to(arena, new_pos); -} - -MR4TH_SYMBOL void -arena_align(Arena *arena, U64 pow2_align){ - Assert(IsPow2OrZero(pow2_align) && pow2_align != 0 && - pow2_align <= MR4TH_MEM_MAX_ALIGN); - U64 pos = arena_current_pos(arena); - U64 align_pos = AlignUpPow2(pos, pow2_align); - U64 z = align_pos - pos; - if (z > 0){ - arena_push(arena, z); - } -} - -MR4TH_SYMBOL ArenaTemp -arena_begin_temp(Arena *arena){ - U64 pos = arena_current_pos(arena); - ArenaTemp temp = {arena, pos}; - return(temp); -} - -MR4TH_SYMBOL void -arena_end_temp(ArenaTemp *temp){ - arena_pop_to(temp->arena, temp->pos); -} - -//////////////////////////////// -// Functions: Strings - -// characters - -MR4TH_SYMBOL B32 -char_is_whitespace(U8 c){ - return(c == ' ' || c == '\n' || c == '\t' || - c == '\r' || c == '\f' || c == '\v'); -} - -MR4TH_SYMBOL B32 -char_is_slash(U8 c){ - return(c == '/' || c == '\\'); -} - -MR4TH_SYMBOL B32 -char_is_digit(U8 c){ - return('0' <= c && c <= '9'); -} - -MR4TH_SYMBOL U8 -char_to_uppercase(U8 c){ - if ('a' <= c && c <= 'z'){ - c += 'A' - 'a'; - } - return(c); -} - -MR4TH_SYMBOL U8 -char_to_lowercase(U8 c){ - if ('A' <= c && c <= 'Z'){ - c += 'a' - 'A'; - } - return(c); -} - -// in-place constructors - -MR4TH_SYMBOL String8 -str8_range(U8 *first, U8 *opl){ - String8 result = {first, (U64)(opl - first)}; - return(result); -} - -MR4TH_SYMBOL String8 -str8_cstring(U8 *cstr){ - U8 *ptr = cstr; - for (;*ptr != 0; ptr += 1); - String8 result = str8_range(cstr, ptr); - return(result); -} - -MR4TH_SYMBOL String8 -str8_cstring_capped(U8 *cstr, U8 *opl){ - U8 *ptr = cstr; - for (;ptr < opl && *ptr != 0; ptr += 1); - String8 result = str8_range(cstr, ptr); - return(result); -} - -MR4TH_SYMBOL String16 -str16_cstring(U16 *cstr){ - U16 *ptr = cstr; - for (;*ptr != 0; ptr += 1); - String16 result = {cstr, (U64)(ptr - cstr)}; - return(result); -} - -// compound constructors - -MR4TH_SYMBOL void -str8_list_push(Arena *arena, String8List *list, String8 string){ - String8Node *node = push_array(arena, String8Node, 1); - node->string = string; - SLLQueuePush(list->first, list->last, node); - list->node_count += 1; - list->total_size += string.size; -} - -MR4TH_SYMBOL void -str8_list_push_front(Arena *arena, String8List *list, String8 string){ - String8Node *node = push_array(arena, String8Node, 1); - node->string = string; - SLLQueuePushFront(list->first, list->last, node); - list->node_count += 1; - list->total_size += string.size; -} - -MR4TH_SYMBOL String8List -str8_list_copy(Arena *arena, String8List *list){ - String8List result = {0}; - for (String8Node *node = list->first; - node != 0; - node = node->next){ - String8 string = str8_push_copy(arena, node->string); - str8_list_push(arena, &result, string); - } - return(result); -} - -MR4TH_SYMBOL String8 -str8_join(Arena *arena, String8List *list, StringJoin *join_optional){ - ProfBeginFunc(); - - // setup join parameters - MR4TH_SYMBOL_STATIC StringJoin dummy_join = {0}; - StringJoin *join = join_optional; - if (join == 0){ - join = &dummy_join; - } - - // compute total size - U64 size = (join->pre.size + - join->post.size + - ((list->node_count>0)? - (join->mid.size*(list->node_count - 1)):0) + - list->total_size); - - // begin string build - U8 *str = push_array(arena, U8, size + 1); - U8 *ptr = str; - - // write pre - MemoryCopy(ptr, join->pre.str, join->pre.size); - ptr += join->pre.size; - - B32 is_mid = 0; - for (String8Node *node = list->first; - node != 0; - node = node->next){ - // write mid - if (is_mid){ - MemoryCopy(ptr, join->mid.str, join->mid.size); - ptr += join->mid.size; - } - - // write node string - MemoryCopy(ptr, node->string.str, node->string.size); - ptr += node->string.size; - - is_mid = 1; - } - - // write post - MemoryCopy(ptr, join->post.str, join->post.size); - ptr += join->post.size; - - // write null - *ptr = 0; - - String8 result = CLiteral(String8){str, size}; - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL String8List -str8_split(Arena *arena, String8 string, U8 *splits, U32 count){ - ProfBeginFunc(); - - String8List result = {0}; - - U8 *ptr = string.str; - U8 *word_first = ptr; - U8 *opl = string.str + string.size; - for (;ptr < opl; ptr += 1){ - // is this a split - U8 byte = *ptr; - B32 is_split_byte = 0; - for (U32 i = 0; i < count; i += 1){ - if (byte == splits[i]){ - is_split_byte = 1; - break; - } - } - - if (is_split_byte){ - // try to emit word, advance word first pointer - if (word_first < ptr){ - str8_list_push(arena, &result, str8_range(word_first, ptr)); - } - word_first = ptr + 1; - } - } - - // try to emit final word - if (word_first < ptr){ - str8_list_push(arena, &result, str8_range(word_first, ptr)); - } - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL String8 -str8_pushfv(Arena *arena, char *fmt, va_list args){ - ProfBeginFunc(); - - // in case we need to try a second time - va_list args2; - va_copy(args2, args); - - // try to build the string in 1024 bytes - U64 buffer_size = 1024; - U8 *buffer = push_array(arena, U8, buffer_size); - U64 actual_size = m4_vsnprintf((char*)buffer, buffer_size, fmt, args); - - String8 result = {0}; - if (actual_size < buffer_size){ - // if first try worked, put back what we didn't use and finish - arena_pop_amount(arena, buffer_size - actual_size - 1); - result = CLiteral(String8){buffer, actual_size}; - } - else{ - // if first try failed, reset and try again with correct size - arena_pop_amount(arena, buffer_size); - U8 *fixed_buffer = push_array(arena, U8, actual_size + 1); - U64 final_size = m4_vsnprintf((char*)fixed_buffer, actual_size + 1, fmt, args2); - result = CLiteral(String8){fixed_buffer, final_size}; - } - - // end args2 - va_end(args2); - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL String8 -str8_pushf(Arena *arena, char *fmt, ...){ - va_list args; - va_start(args, fmt); - String8 result = str8_pushfv(arena, fmt, args); - va_end(args); - return(result); -} - -MR4TH_SYMBOL void -str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...){ - va_list args; - va_start(args, fmt); - String8 string = str8_pushfv(arena, fmt, args); - va_end(args); - str8_list_push(arena, list, string); -} - -MR4TH_SYMBOL String8 -str8_push_copy(Arena *arena, String8 string){ - String8 result = {0}; - result.str = push_array(arena, U8, string.size + 1); - result.size = string.size; - MemoryCopy(result.str, string.str, string.size); - result.str[result.size] = 0; - return(result); -} - -// substrings - -MR4TH_SYMBOL String8 -str8_prefix(String8 str, U64 size){ - U64 size_clamped = ClampTop(size, str.size); - String8 result = {str.str, size_clamped}; - return(result); -} - -MR4TH_SYMBOL String8 -str8_chop(String8 str, U64 amount){ - U64 amount_clamped = ClampTop(amount, str.size); - U64 remaining_size = str.size - amount_clamped; - String8 result = {str.str, remaining_size}; - return(result); -} - -MR4TH_SYMBOL String8 -str8_postfix(String8 str, U64 size){ - U64 size_clamped = ClampTop(size, str.size); - U64 skip_to = str.size - size_clamped; - String8 result = {str.str + skip_to, size_clamped}; - return(result); -} - -MR4TH_SYMBOL String8 -str8_skip(String8 str, U64 amount){ - U64 amount_clamped = ClampTop(amount, str.size); - U64 remaining_size = str.size - amount_clamped; - String8 result = {str.str + amount_clamped, remaining_size}; - return(result); -} - -MR4TH_SYMBOL String8 -str8_skip_chop_whitespace(String8 str){ - String8 result = str; - if (result.size > 0){ - U8 *sptr = str.str; - U8 *eptr = str.str + str.size - 1; - for (;sptr < eptr && char_is_whitespace(*sptr); sptr += 1); - for (;sptr < eptr && char_is_whitespace(*eptr); eptr -= 1); - result = str8_range(sptr, eptr + 1); - } - return(result); -} - -// hash - -MR4TH_SYMBOL U64 -str8_hash(String8 str){ - U64 hash = 5381; - for (U8 *ptr = str.str, *opl = str.str + str.size; - ptr < opl; - ptr += 1){ - U8 c = *ptr; - hash = (hash*33)^c; - } - return(hash); -} - -// compare - -MR4TH_SYMBOL B32 -str8_match(String8 a, String8 b, StringMatchFlags flags){ - ProfBeginFunc(); - - B32 result = 0; - if ((flags & StringMatchFlag_PrefixMatch) != 0 || a.size == b.size){ - U64 size = a.size; - if ((flags & StringMatchFlag_PrefixMatch) != 0){ - size = Min(a.size, b.size); - } - - result = 1; - B32 no_case = ((flags & StringMatchFlag_NoCase) != 0); - for (U64 i = 0; i < size; i += 1){ - U8 ac = a.str[i]; - U8 bc = b.str[i]; - if (no_case){ - ac = char_to_uppercase(ac); - bc = char_to_uppercase(bc); - } - if (ac != bc){ - result = 0; - break; - } - } - } - - ProfEndFunc(); - return(result); -} - -// path helpers - -MR4TH_SYMBOL String8 -str8_chop_last_slash(String8 string){ - String8 result = string; - if (string.size > 0){ - // pos one past last slash - U64 pos = string.size; - for (S64 i = string.size - 1; i >= 0; i -= 1){ - if (char_is_slash(string.str[i])){ - pos = i; - break; - } - } - - // chop result string - result.size = pos; - } - return(result); -} - -MR4TH_SYMBOL String8 -str8_file_name_from_path(String8 full_file_name){ - String8 result = {0}; - if (full_file_name.size > 0){ - U8 *opl = full_file_name.str + full_file_name.size; - U8 *ptr = opl; - for (;ptr > full_file_name.str; ptr -= 1){ - U8 c = ptr[-1]; - if (c == '/' || c == '\\'){ - break; - } - } - result = str8_range(ptr, opl); - } - return(result); -} - -MR4TH_SYMBOL String8 -str8_base_name_from_file_name(String8 file_name){ - String8 result = {0}; - if (file_name.size > 0){ - U8 *opl = file_name.str + file_name.size; - U8 *ptr = file_name.str; - for (;ptr < opl; ptr += 1){ - U8 c = ptr[0]; - if (c == '.'){ - break; - } - } - result = str8_range(file_name.str, ptr); - } - return(result); -} - -// stylized constructors - -MR4TH_SYMBOL String8 -str8_join_flags(Arena *arena, String8List *list){ - StringJoin join = {0}; - join.mid = str8_lit(" | "); - String8 result = str8_join(arena, list, &join); - if (result.size == 0){ - result = str8_lit("0"); - } - return(result); -} - -// unicode - -MR4TH_SYMBOL StringDecode -str_decode_utf8(U8 *str, U32 cap){ - ProfBeginFunc(); - - MR4TH_SYMBOL_STATIC U8 length[] = { - 1, 1, 1, 1, // 000xx - 1, 1, 1, 1, - 1, 1, 1, 1, - 1, 1, 1, 1, - 0, 0, 0, 0, // 100xx - 0, 0, 0, 0, - 2, 2, 2, 2, // 110xx - 3, 3, // 1110x - 4, // 11110 - 0, // 11111 - }; - MR4TH_SYMBOL_STATIC U8 first_byte_mask[] = { 0, 0x7F, 0x1F, 0x0F, 0x07 }; - MR4TH_SYMBOL_STATIC U8 final_shift[] = { 0, 18, 12, 6, 0 }; - - StringDecode result = {0}; - if (cap > 0){ - result.codepoint = '#'; - result.size = 1; - - U8 byte = str[0]; - U8 l = length[byte >> 3]; - if (0 < l && l <= cap){ - U32 cp = (byte & first_byte_mask[l]) << 18; - switch (l){ - case 4: cp |= ((str[3] & 0x3F) << 0); - case 3: cp |= ((str[2] & 0x3F) << 6); - case 2: cp |= ((str[1] & 0x3F) << 12); - default: break; - } - cp >>= final_shift[l]; - - result.codepoint = cp; - result.size = l; - } - } - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL U32 -str_encode_utf8(U8 *dst, U32 codepoint){ - ProfBeginFunc(); - - U32 size = 0; - if (codepoint < (1 << 7)){ - dst[0] = codepoint; - size = 1; - } - else if (codepoint < (1 << 11)){ - dst[0] = 0xC0 | (codepoint >> 6); - dst[1] = 0x80 | (codepoint & 0x3F); - size = 2; - } - else if (codepoint < (1 << 16)){ - dst[0] = 0xE0 | (codepoint >> 12); - dst[1] = 0x80 | ((codepoint >> 6) & 0x3F); - dst[2] = 0x80 | (codepoint & 0x3F); - size = 3; - } - else if (codepoint < (1 << 21)){ - dst[0] = 0xF0 | (codepoint >> 18); - dst[1] = 0x80 | ((codepoint >> 12) & 0x3F); - dst[2] = 0x80 | ((codepoint >> 6) & 0x3F); - dst[3] = 0x80 | (codepoint & 0x3F); - size = 4; - } - else{ - dst[0] = '#'; - size = 1; - } - - ProfEndFunc(); - return(size); -} - -MR4TH_SYMBOL StringDecode -str_decode_utf16(U16 *str, U32 cap){ - ProfBeginFunc(); - - StringDecode result = {'#', 1}; - U16 x = str[0]; - if (x < 0xD800 || 0xDFFF < x){ - result.codepoint = x; - } - else if (cap >= 2){ - U16 y = str[1]; - if (0xD800 <= x && x < 0xDC00 && - 0xDC00 <= y && y < 0xE000){ - U16 xj = x - 0xD800; - U16 yj = y - 0xDc00; - U32 xy = (xj << 10) | yj; - result.codepoint = xy + 0x10000; - result.size = 2; - } - } - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL U32 -str_encode_utf16(U16 *dst, U32 codepoint){ - ProfBeginFunc(); - - U32 size = 0; - if (codepoint < 0x10000){ - dst[0] = codepoint; - size = 1; - } - else{ - U32 cpj = codepoint - 0x10000; - dst[0] = (cpj >> 10) + 0xD800; - dst[1] = (cpj & 0x3FF) + 0xDC00; - size = 2; - } - - ProfEndFunc(); - return(size); -} - -MR4TH_SYMBOL String32 -str32_from_str8(Arena *arena, String8 string){ - ProfBeginFunc(); - - U32 *memory = push_array(arena, U32, string.size + 1); - - U32 *dptr = memory; - U8 *ptr = string.str; - U8 *opl = string.str + string.size; - for (; ptr < opl;){ - StringDecode decode = str_decode_utf8(ptr, (U64)(opl - ptr)); - *dptr = decode.codepoint; - ptr += decode.size; - dptr += 1; - } - - *dptr = 0; - - U64 alloc_count = string.size + 1; - U64 string_count = (U64)(dptr - memory); - U64 unused_count = alloc_count - string_count - 1; - arena_pop_amount(arena, unused_count*sizeof(*memory)); - - String32 result = {memory, string_count}; - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL String8 -str8_from_str32(Arena *arena, String32 string){ - ProfBeginFunc(); - - U8 *memory = push_array(arena, U8, string.size*4 + 1); - - U8 *dptr = memory; - U32 *ptr = string.str; - U32 *opl = string.str + string.size; - for (; ptr < opl;){ - U32 size = str_encode_utf8(dptr, *ptr); - ptr += 1; - dptr += size; - } - - *dptr = 0; - - U64 alloc_count = string.size*4 + 1; - U64 string_count = (U64)(dptr - memory); - U64 unused_count = alloc_count - string_count - 1; - arena_pop_amount(arena, unused_count*sizeof(*memory)); - - String8 result = {memory, string_count}; - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL String16 -str16_from_str8(Arena *arena, String8 string){ - ProfBeginFunc(); - U16 *memory = push_array(arena, U16, string.size*2 + 1); - - U16 *dptr = memory; - U8 *ptr = string.str; - U8 *opl = string.str + string.size; - for (; ptr < opl;){ - StringDecode decode = str_decode_utf8(ptr, (U64)(opl - ptr)); - U32 enc_size = str_encode_utf16(dptr, decode.codepoint); - ptr += decode.size; - dptr += enc_size; - } - - *dptr = 0; - - U64 alloc_count = string.size*2 + 1; - U64 string_count = (U64)(dptr - memory); - U64 unused_count = alloc_count - string_count - 1; - arena_pop_amount(arena, unused_count*sizeof(*memory)); - - String16 result = {memory, string_count}; - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL String8 -str8_from_str16(Arena *arena, String16 string){ - ProfBeginFunc(); - U8 *memory = push_array(arena, U8, string.size*3 + 1); - - U8 *dptr = memory; - U16 *ptr = string.str; - U16 *opl = string.str + string.size; - for (; ptr < opl;){ - StringDecode decode = str_decode_utf16(ptr, (U64)(opl - ptr)); - U16 enc_size = str_encode_utf8(dptr, decode.codepoint); - ptr += decode.size; - dptr += enc_size; - } - - *dptr = 0; - - U64 alloc_count = string.size*3 + 1; - U64 string_count = (U64)(dptr - memory); - U64 unused_count = alloc_count - string_count - 1; - arena_pop_amount(arena, unused_count*sizeof(*memory)); - - String8 result = {memory, string_count}; - ProfEndFunc(); - return(result); -} - -// numeric conversion - -MR4TH_SYMBOL B32 -str8_is_u64(String8 string, U32 radix){ - Assert(2 <= radix && radix <= 16); - - B32 result = 1; - { - U8 *ptr = string.str; - U8 *opl = string.str + string.size; - for (; ptr < opl; ptr += 1){ - U8 num = 0xFF; - - // extract - U8 s = *ptr - '0'; - if (s <= 9){ - num = s; - } - else{ - s = *ptr - 'A'; - if (s <= 5){ - num = 0xA + s; - } - else{ - s = *ptr - 'a'; - if (s <= 5){ - num = 0xA + s; - } - } - } - - // bad parse check - if (num >= radix){ - result = 0; - break; - } - } - } - - return(result); -} - -MR4TH_SYMBOL U64 -u64_from_str8(String8 string, U32 radix){ - Assert(2 <= radix && radix <= 16); - - U64 result = 0; - { - U8 *ptr = string.str; - U8 *opl = string.str + string.size; - for (; ptr < opl; ptr += 1){ - U8 num = 0xFF; - - // extract - U8 s = *ptr - '0'; - if (s <= 9){ - num = s; - } - else{ - s = *ptr - 'A'; - if (s <= 5){ - num = 0xA + s; - } - else{ - s = *ptr - 'a'; - if (s <= 5){ - num = 0xA + s; - } - } - } - - // bad parse check - if (num >= radix){ - result = 0; - break; - } - - // increment result - result *= radix; - result += num; - } - } - - return(result); -} - -MR4TH_SYMBOL U64 -u64_from_str8_c_syntax(String8 string){ - U8 *ptr = string.str; - U8 *opl = string.str + string.size; - - U32 radix = 10; - if (ptr < opl && *ptr == '0'){ - radix = 010; - ptr += 1; - if (ptr < opl && *ptr == 'x'){ - radix = 0x10; - ptr += 1; - } - else if (ptr < opl && *ptr == 'b'){ - radix = 2; - ptr += 1; - } - } - - U64 result = u64_from_str8(str8_range(ptr, opl), radix); - return(result); -} - -MR4TH_SYMBOL S64 -s64_from_str8_c_syntax(String8 string){ - U8 *ptr = string.str; - U8 *opl = string.str + string.size; - - B32 negative = 0; - if (ptr < opl){ - if (*ptr == '-'){ - negative = 1; - ptr += 1; - } - else if (*ptr == '+'){ - ptr += 1; - } - } - - S64 result = u64_from_str8_c_syntax(str8_range(ptr, opl)); - if (negative){ - result = -result; - } - - return(result); -} - -MR4TH_SYMBOL F64 -f64_from_str8(String8 string){ - F64 result = 0.f; - - U8 *ptr = string.str; - U8 *opl = string.str + string.size; - - B32 negative = 0; - if (ptr < opl){ - if (*ptr == '-'){ - negative = 1; - ptr += 1; - } - else if (*ptr == '+'){ - ptr += 1; - } - } - - for (; ptr < opl; ptr += 1){ - if (*ptr == '.'){ - ptr += 1; - break; - } - U32 x = 0; - if ('0' <= *ptr && *ptr <= '9'){ - x = *ptr - '0'; - } - result *= 10.f; - result += x; - } - - F32 mul = 0.1f; - for (; ptr < opl; ptr += 1){ - U32 x = 0; - if ('0' <= *ptr && *ptr <= '9'){ - x = *ptr - '0'; - } - result += x*mul; - mul /= 10.f; - } - - if (negative){ - result = -result; - } - - return(result); -} - -//////////////////////////////// -// Functions: Stream - -// stream core implementation - -typedef struct STREAM_Node{ - struct STREAM_Node *next; - U64 size; - U8 data[0]; -} STREAM_Node; - -#define STREAM_NODE_FROM_DATA(d) (STREAM_Node*)((U8*)(d) - sizeof(STREAM_Node)) - -struct STREAM{ - Arena *arena; - U64 clear_pos; - STREAM_Node *first_node; - STREAM_Node *last_node; - U64 buffer_cap; - U64 total_size; - STREAM_Node *unused_node; -}; - -#define STREAM_ALLOC_SIZE MB(16) - -#if !MR4TH_PLUGIN_MODE - -MR4TH_SYMBOL_MUST_SHARE STREAM* -stream_new(void){ - Arena *arena = arena_alloc(); - STREAM *stream = push_array(arena, STREAM, 1); - stream->arena = arena; - stream->clear_pos = arena_current_pos(arena); - return(stream); -} - -MR4TH_SYMBOL_MUST_SHARE void -stream_release(STREAM *stream){ - stream_clear(stream); -} - -MR4TH_SYMBOL_MUST_SHARE void -stream_clear(STREAM *stream){ - Arena *arena = stream->arena; - U64 clear_pos = stream->clear_pos; - arena_pop_to(arena, clear_pos); - MemoryZeroStruct(stream); - stream->arena = arena; - stream->clear_pos = clear_pos; -} - -MR4TH_SYMBOL_MUST_SHARE void -stream_write(STREAM *stream, String8 data){ - U64 data_pos = 0; - - for (;data_pos < data.size;){ - U64 remaining_size = data.size - data_pos; - - // try to get a node with buffer space from the stream - // (don't return a node with no space!) - STREAM_Node *node = 0; - { - if (stream->buffer_cap > 0){ - node = stream->last_node; - } - if (node != 0 && stream->buffer_cap <= node->size){ - node = 0; - } - } - - // if we didn't get a buffer, try the unused node - if (node == 0){ - if (stream->unused_node != 0){ - node = stream->unused_node; - stream->unused_node = 0; - stream->buffer_cap = node->size; - node->size = 0; - SLLQueuePush(stream->first_node, stream->last_node, node); - } - } - - // if we didn't get a buffer, make one now - if (node == 0){ - U64 alloc_size = sizeof(STREAM_Node) + remaining_size; - alloc_size = ClampBot(STREAM_ALLOC_SIZE, alloc_size); - - node = (STREAM_Node*)push_array_no_zero(stream->arena, U8, alloc_size); - SLLQueuePush(stream->first_node, stream->last_node, node); - node->size = 0; - - stream->buffer_cap = alloc_size - sizeof(STREAM_Node); - } - - // get buffer from the node - U8 *buffer = node->data + node->size; - U64 buffer_size = stream->buffer_cap - node->size; - - // calculate amount to copy - U64 copy_amount = ClampTop(remaining_size, buffer_size); - - // copy memory and increment counters - MemoryCopy(buffer, data.str + data_pos, copy_amount); - node->size += copy_amount; - stream->total_size += copy_amount; - data_pos += copy_amount; - } -} - -MR4TH_SYMBOL_MUST_SHARE U8* -stream_alloc(STREAM *stream, U64 size){ - // try to get a node with buffer space - // (don't return a node with no space) - STREAM_Node *node = 0; - { - if (stream->buffer_cap > 0){ - node = stream->last_node; - } - if (node != 0 && stream->buffer_cap <= node->size){ - node = 0; - } - } - - // if there is a node but it's not big enough... - if (node != 0 && stream->buffer_cap - node->size < size){ - U64 remaining_cap = stream->buffer_cap - node->size; - U64 unused_ptr = IntFromPtr(node->data) + node->size; - U64 unused_opl = IntFromPtr(node->data) + stream->buffer_cap; - U64 unused_ptr_aligned = AlignUpPow2(unused_ptr, sizeof(void*)); - if (unused_opl > unused_ptr_aligned && - unused_opl - unused_ptr_aligned >= sizeof(STREAM_Node) + 32){ - STREAM_Node *unused_node = (STREAM_Node*)PtrFromInt(unused_ptr_aligned); - U64 leftover_buffer_size = unused_opl - unused_ptr_aligned - sizeof(STREAM_Node); - unused_node->size = leftover_buffer_size; - SLLStackPush(stream->unused_node, unused_node); - } - node = 0; - } - - // if we don't have a node then setup a new node with sufficient space. - if (node == 0){ - U64 alloc_size = sizeof(STREAM_Node) + size; - alloc_size = ClampBot(STREAM_ALLOC_SIZE, alloc_size); - - node = (STREAM_Node*)push_array_no_zero(stream->arena, U8, alloc_size); - SLLQueuePush(stream->first_node, stream->last_node, node); - node->size = 0; - - stream->buffer_cap = alloc_size - sizeof(STREAM_Node); - } - - // return the buffer - U8 *result = node->data + node->size; - node->size += size; - stream->total_size += size; - return(result); -} - -MR4TH_SYMBOL_MUST_SHARE U64 -stream_total_size(STREAM *stream){ - return(stream->total_size); -} - -MR4TH_SYMBOL_MUST_SHARE STREAM_Handle* -stream_next_chunk(STREAM *stream, STREAM_Handle *handle, String8 *chunk_out){ - STREAM_Node *node = (STREAM_Node*)handle; - if (node == 0){ - node = stream->first_node; - } - else{ - node = node->next; - } - if (node != 0){ - chunk_out->size = node->size; - chunk_out->str = node->data; - } - else{ - chunk_out->size = 0; - chunk_out->str = 0; - } - return((STREAM_Handle*)node); -} - -#endif /* stream core implementation */ - -// stream helpers - -MR4TH_SYMBOL String8 -stream_read(Arena *arena, STREAM *stream){ - String8 result = {0}; - result.str = push_array(arena, U8, stream->total_size); - result.size = stream->total_size; - - U64 pos = 0; - for (STREAM_Node *node = stream->first_node; - node != 0; - node = node->next){ - MemoryCopy(result.str + pos, node->data, node->size); - pos += node->size; - } - return(result); -} - -MR4TH_SYMBOL void -stream_printfv(STREAM *stream, char *fmt, va_list args){ - // in case we need to try a second time - va_list args2; - va_copy(args2, args); - - // try to get a buffer from the stream - STREAM_Node *node = 0; - U8 *buffer = 0; - U64 buffer_size = 0; - if (stream->buffer_cap > 0){ - node = stream->last_node; - buffer = node->data + node->size; - buffer_size = stream->buffer_cap - node->size; - } - - // try to build the string in the current block - U64 actual_size = 0; - if (buffer_size > 0){ - actual_size = m4_vsnprintf((char*)buffer, buffer_size, fmt, args); - } - else{ - actual_size = m4_vsnprintf(0, 0, fmt, args); - } - - // if first try worked, increment block size - if (actual_size <= buffer_size){ - node->size += actual_size; - stream->total_size += actual_size; - } - - // if first try failed, reset and try again with correct size - else{ - // TODO(allen): super annoying extra buffer copy, need to fix. - ArenaTemp scratch = arena_get_scratch(0, 0); - U8 *temp_buffer = push_array(scratch.arena, U8,actual_size + 1); - U64 final_size = m4_vsnprintf((char*)temp_buffer, actual_size + 1, fmt, args2); - Assert(final_size == actual_size); - U8 *new_buffer = stream_alloc(stream, actual_size); - MemoryCopy(new_buffer, temp_buffer, actual_size); - arena_release_scratch(&scratch); - } - - // end args2 - va_end(args2); -} - -MR4TH_SYMBOL void -stream_printf(STREAM *stream, char *fmt, ...){ - va_list args; - va_start(args, fmt); - stream_printfv(stream, fmt, args); - va_end(args); -} - -//////////////////////////////// -// Functions: Buffer - -MR4TH_SYMBOL void -buffer_alloc(BUFFER *buffer, U64 size){ - MemoryZeroStruct(buffer); - U64 real_size = AlignUpPow2(size, KB(4)); - buffer->base = os_memory_reserve(real_size); - if (buffer->base != 0){ - buffer->size = real_size; - buffer->commit_pos = 0; - } -} - -MR4TH_SYMBOL void -buffer_release(BUFFER *buffer){ - os_memory_release(buffer->base, buffer->size); -} - -MR4TH_SYMBOL void -buffer_reset(BUFFER *buffer){ - if (buffer->commit_pos > 0){ - os_memory_decommit((U8*)buffer->base, buffer->commit_pos); - } - buffer->commit_pos = 0; -} - -MR4TH_SYMBOL void -buffer_commit_off__call(BUFFER *buffer, U64 off){ - U64 new_commit_pos = AlignUpPow2(off, MR4TH_MEM_COMMIT_BLOCK_SIZE); - new_commit_pos = ClampTop(new_commit_pos, buffer->size); - if (os_memory_commit((U8*)buffer->base + buffer->commit_pos, new_commit_pos - buffer->commit_pos)){ - buffer->commit_pos = new_commit_pos; - } -} - -//////////////////////////////// -// Types: Hash Table - -MR4TH_SYMBOL void -hash_buckets_init(BUFFER *buckets, U64 count){ - Assert(count > 0 && IsPow2OrZero(count)); - buffer_commit_off(buckets, sizeof(void*)*count); -} - -MR4TH_SYMBOL HASH_Node* -hash_buckets_first(BUFFER *buckets, U64 hash){ - U64 count = buckets->commit_pos/sizeof(void*); - U64 bidx = hash&(count - 1); - HASH_Node *result = ((HASH_Node**)buckets->base)[bidx]; - return(result); -} - -MR4TH_SYMBOL void -hash_buckets_expand(BUFFER *buckets, U64 capacity){ - static const U32 ALPHA_NUMERATOR = 7; - static const U32 ALPHA_DENOMINATOR = 8; - - U64 count = buckets->commit_pos/sizeof(void*); - U64 max = buckets->size/sizeof(void*); - U32 dbl_count = count*2; - if (capacity*ALPHA_DENOMINATOR > count*ALPHA_NUMERATOR && - dbl_count <= max){ - U32 old_count = count; - U32 new_count = count*4; - if (new_count > max){ - new_count = dbl_count; - } - buffer_commit_off(buckets, sizeof(void*)*new_count); - U64 mask = new_count - 1; - U64 rehash_mask = mask&~(old_count - 1); - HASH_Node **buckets_base = (HASH_Node**)buckets->base; - for (U32 i = 0; i < old_count; i += 1){ - for (HASH_Node **ptr = buckets_base + i; - *ptr != 0;){ - HASH_Node *node = *ptr; - if ((node->hash&rehash_mask) != 0){ - U64 bidx = node->hash&mask; - *ptr = (*ptr)->next; - SLLStackPush(buckets_base[bidx], node); - } - else{ - ptr = &node->next; - } - } - } - } -} - -MR4TH_SYMBOL void -hash_buckets_insert(Arena *arena, BUFFER *buckets, U64 hash, U64 val){ - U64 count = buckets->commit_pos/sizeof(void*); - U64 bucket_idx = hash&(count - 1); - HASH_Node *bucket = push_array(arena, HASH_Node, 1); - bucket->hash = hash; - bucket->val = val; - SLLStackPush(((HASH_Node**)buckets->base)[bucket_idx], bucket); -} - -//////////////////////////////// -// Functions: Log - -MR4TH_SYMBOL_MUST_SHARE MR4TH_THREADVAR -LOG_ThreadVars *log_vars = 0; - -MR4TH_SYMBOL void -log_accum_begin(LOG_LogToProc *proc, void *uptr){ - LOG_ThreadVars *vars = log_vars; - if (vars == 0){ - Arena *arena = arena_alloc(); - vars = log_vars = push_array(arena, LOG_ThreadVars, 1); - vars->arena = arena; - } - - U64 pos = arena_current_pos(vars->arena); - LOG_Node *node = push_array(vars->arena, LOG_Node, 1); - node->pos = pos; - node->logto = proc; - node->uptr = uptr; - SLLStackPush(vars->stack, node); -} - -MR4TH_SYMBOL B32 -log_gathering(void){ - LOG_ThreadVars *vars = log_vars; - return(vars != 0 && vars->stack != 0); -} - -MR4TH_SYMBOL void -log_emit(String8 message){ - LOG_ThreadVars *vars = log_vars; - if (vars != 0 && vars->stack != 0){ - LOG_Node *node = vars->stack; - String8 msg_copy = str8_push_copy(vars->arena, message); - str8_list_push(vars->arena, &node->log, msg_copy); - if (node->logto != 0){ - node->logto(node->uptr, msg_copy); - } - } -} - -MR4TH_SYMBOL void -log_emitf(char *fmt, ...){ - LOG_ThreadVars *vars = log_vars; - if (vars != 0 && vars->stack != 0){ - LOG_Node *node = vars->stack; - va_list args; - va_start(args, fmt); - String8 string = str8_pushfv(vars->arena, fmt, args); - va_end(args); - str8_list_push(vars->arena, &node->log, string); - if (node->logto != 0){ - node->logto(node->uptr, string); - } - } -} - -MR4TH_SYMBOL String8 -log_accum_end(Arena *arena){ - String8 result = {0}; - LOG_ThreadVars *vars = log_vars; - if (vars != 0){ - LOG_Node *node = vars->stack; - if (node != 0){ - result = str8_join(arena, &node->log, 0); - SLLStackPop(vars->stack); - arena_pop_to(vars->arena, node->pos); - } - } - return(result); -} - -//////////////////////////////// -// Functions: Errors - -// IMPORTANT: It is important that strings get pushed -// *on top* of the node that holds them within the arena. -// basically: Assert((U8*)node < (U8*)node->error.str); -// except that stops working if the arena is chained... - -MR4TH_SYMBOL_MUST_SHARE MR4TH_THREADVAR -ER_ThreadVars *er_vars = 0; - -MR4TH_SYMBOL void -er_accum_begin(void){ - ER_ThreadVars *vars = er_vars; - if (vars == 0){ - Arena *arena = arena_new(KB(64), 1, 0); - vars = er_vars = push_array(arena, ER_ThreadVars, 1); - vars->arena = arena; - } - - U64 pos = arena_current_pos(vars->arena); - ER_Node *node = push_array(vars->arena, ER_Node, 1); - if (node == 0){ - vars->over_stack += 1; - } - else{ - node->pos = pos; - SLLStackPush(vars->stack, node); - } -} - -MR4TH_SYMBOL void -er_emit(String8 error){ - ER_ThreadVars *vars = er_vars; - if (vars != 0 && - vars->over_stack == 0){ - ER_Node *node = vars->stack; - if (node != 0 && node->error.size == 0){ - node->error = str8_push_copy(vars->arena, error); - } - } -} - -MR4TH_SYMBOL void -er_emitf(char *fmt, ...){ - ER_ThreadVars *vars = er_vars; - if (vars != 0 && - vars->over_stack == 0){ - ER_Node *node = vars->stack; - if (node != 0 && node->error.size == 0){ - va_list args; - va_start(args, fmt); - String8 string = str8_pushfv(vars->arena, fmt, args); - va_end(args); - node->error = string; - } - } -} - -MR4TH_SYMBOL String8 -er_accum_end(Arena *arena){ - String8 result = {0}; - ER_ThreadVars *vars = er_vars; - if (vars != 0){ - if (vars->over_stack == 0){ - ER_Node *node = vars->stack; - if (node != 0){ - result = str8_push_copy(arena, node->error); - SLLStackPop(vars->stack); - arena_pop_to(vars->arena, node->pos); - } - } - else{ - vars->over_stack -= 1; - } - } - return(result); -} - - -//////////////////////////////////////////////// -//////////////////////////////////////////////// -//////// OS IMPLEMENTATION SHARED ////////// -//////////////////////////////////////////////// -//////////////////////////////////////////////// - -//////////////////////////////// -// Helper Implementation: File Handling - -MR4TH_SYMBOL B32 -os_file_write(String8 file_name, String8 data){ - String8Node node = {0}; - node.string = data; - B32 result = os_file_write_list(file_name, &node); - return(result); -} - -MR4TH_SYMBOL String8 -os__file_write_callback__list(void *udata){ - String8Node **ptr = (String8Node**)udata; - String8 result = {0}; - if (*ptr != 0){ - result = (*ptr)->string; - (*ptr) = (*ptr)->next; - } - return(result); -} - -MR4TH_SYMBOL B32 -os_file_write_list(String8 file_name, String8Node *first_node){ - B32 result = os_file_write_callback(file_name, &first_node, os__file_write_callback__list); - return(result); -} - -MR4TH_SYMBOL String8 -os__file_write_callback__stream(void *udata){ - STREAM *stream = *(STREAM**) ((void**)udata + 0); - STREAM_Handle**handle = (STREAM_Handle**)((void**)udata + 1); - String8 result = {0}; - *handle = stream_next_chunk(stream, *handle, &result); - return(result); -} - -MR4TH_SYMBOL B32 -os_file_write_stream(String8 file_name, STREAM *stream){ - void *udata[2] = { stream, 0 }; - B32 result = os_file_write_callback(file_name, udata, os__file_write_callback__stream); - return(result); -} - -//////////////////////////////// -// Helper Implementation: Libraries - -MR4TH_SYMBOL OS_VRange -os_this_image(void){ - OS_VRange result = {0}; - OS_Library *this_lib = os_lib_from_addr((void*)os_this_image); - if (this_lib != 0){ - result = os_lib_image_range(this_lib); - } - return(result); -} - - - -/******************************* -** Begin Base Win32 ** -*******************************/ - -#if OS_WINDOWS - -//////////////////////////////// -// Win32 Implementation: Global Variables - -MR4TH_SYMBOL_STATIC U64 w32_ticks_per_second = 1; - -MR4TH_SYMBOL_STATIC Arena *w32_perm_arena = 0; -MR4TH_SYMBOL_STATIC String8 w32_binary_path = {0}; -MR4TH_SYMBOL_STATIC String8 w32_user_path = {0}; -MR4TH_SYMBOL_STATIC String8 w32_temp_path = {0}; - -MR4TH_SYMBOL_STATIC String8List w32_cmd_line = {0}; - -//////////////////////////////// -// Win32 Implementation: Process Setup - -MR4TH_SYMBOL void -os_main_init(int argc, char **argv){ - ProfBeginFunc(); - - // setup precision time - LARGE_INTEGER perf_freq = {0}; - if (QueryPerformanceFrequency(&perf_freq)){ - w32_ticks_per_second = ((U64)perf_freq.HighPart << 32) | perf_freq.LowPart; - } - timeBeginPeriod(1); - - // arena - w32_perm_arena = arena_alloc(); - - // command line arguments - for (int i = 0; i < argc; i += 1){ - String8 arg = str8_cstring((U8*)argv[i]); - str8_list_push(w32_perm_arena, &w32_cmd_line, arg); - } - - // paths - ArenaTemp scratch = arena_get_scratch(0, 0); - - // binary path - { - DWORD cap = 2048; - U16 *buffer = 0; - DWORD size = 0; - for (U64 r = 0; r < 4; r += 1, cap *= 4){ - U16 *try_buffer = push_array(scratch.arena, U16, cap); - DWORD try_size = GetModuleFileNameW(0, (WCHAR*)try_buffer, cap); - if (try_size == cap && GetLastError() == ERROR_INSUFFICIENT_BUFFER){ - arena_end_temp(&scratch); - } - else{ - buffer = try_buffer; - size = try_size; - break; - } - } - - String8 full_path = str8_from_str16(scratch.arena, CLiteral(String16){buffer, size}); - String8 binary_path = str8_chop_last_slash(full_path); - w32_binary_path = str8_push_copy(w32_perm_arena, binary_path); - } - - // user data - { - HANDLE token = GetCurrentProcessToken(); - DWORD cap = 2048; - U16 *buffer = push_array(scratch.arena, U16, cap); - if (!GetUserProfileDirectoryW(token, (WCHAR*)buffer, &cap)){ - arena_end_temp(&scratch); - buffer = push_array(scratch.arena, U16, cap + 1); - if (GetUserProfileDirectoryW(token, (WCHAR*)buffer, &cap)){ - buffer = 0; - } - } - - if (buffer != 0){ - // the docs make it sound like we can only count on - // cap getting the size on failure; so we're just going to cstring - // this to be safe. - w32_user_path = str8_from_str16(w32_perm_arena, str16_cstring(buffer)); - } - } - - // temp data - { - DWORD cap = 2048; - U16 *buffer = push_array(scratch.arena, U16, cap); - DWORD size = GetTempPathW(cap, (WCHAR*)buffer); - if (size >= cap){ - arena_end_temp(&scratch); - buffer = push_array(scratch.arena, U16, size + 1); - size = GetTempPathW(size + 1, (WCHAR*)buffer); - } - - // size - 1, because this particular string function - // in the Win32 API is different from the others and it includes - // the trailing backslash. We want consistency, so the "- 1" removes it. - w32_temp_path = str8_from_str16(w32_perm_arena, CLiteral(String16){buffer, size - 1}); - } - - arena_release_scratch(&scratch); - - ProfEndFunc(); -} - -MR4TH_SYMBOL String8List -os_command_line_arguments(void){ - String8List result = w32_cmd_line; - return(result); -} - -MR4TH_SYMBOL void -os_exit_process(U32 code){ - ProfClose(); - ExitProcess(code); -} - -//////////////////////////////// -// Win32 Implementation: Memory Functions - -MR4TH_SYMBOL void* -os_memory_reserve(U64 size){ - void *result = VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE); - return(result); -} - -MR4TH_SYMBOL B32 -os_memory_commit(void *ptr, U64 size){ - B32 result = (VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE) != 0); - return(result); -} - -MR4TH_SYMBOL void -os_memory_decommit(void *ptr, U64 size){ - VirtualFree(ptr, size, MEM_DECOMMIT); -} - -MR4TH_SYMBOL void -os_memory_release(void *ptr, U64 size){ - VirtualFree(ptr, 0, MEM_RELEASE); -} - -MR4TH_SYMBOL B32 -os_memory_protect(void *ptr, U64 size, DataAccessFlags access_flags){ - DWORD protect = PAGE_NOACCESS; - switch (access_flags&0x7){ - case 0: protect = PAGE_NOACCESS; break; - case DataAccessFlag_Read: protect = PAGE_READONLY; break; - case DataAccessFlag_Write: - case DataAccessFlag_Read|DataAccessFlag_Write: protect = PAGE_READWRITE; break; - case DataAccessFlag_Execute: protect = PAGE_EXECUTE; break; - case DataAccessFlag_Read|DataAccessFlag_Execute: protect = PAGE_EXECUTE_READ; break; - case DataAccessFlag_Write|DataAccessFlag_Execute: - case DataAccessFlag_Read|DataAccessFlag_Write|DataAccessFlag_Execute: protect = PAGE_EXECUTE_READWRITE; break; - } - - DWORD dummy = 0; - B32 result = VirtualProtect(ptr, size, protect, &dummy); - return(result); -} - -//////////////////////////////// -// Win32 Implementation: File Handling - -MR4TH_SYMBOL String8 -os_file_read(Arena *arena, String8 file_name){ - ProfBeginFunc(); - - // get handle - ArenaTemp scratch = arena_get_scratch(&arena, 1); - String16 file_name16 = str16_from_str8(scratch.arena, file_name); - HANDLE file = CreateFileW((WCHAR*)file_name16.str, - GENERIC_READ, 0, 0, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, - 0); - - String8 result = {0}; - if (file != INVALID_HANDLE_VALUE){ - // get size - DWORD hi_size = 0; - DWORD lo_size = GetFileSize(file, &hi_size); - U64 total_size = (((U64)hi_size) << 32) | (U64)lo_size; - - // allocate buffer - ArenaTemp restore_point = arena_begin_temp(arena); - U8 *buffer = push_array_no_zero(arena, U8, total_size + 1); - - // read - U8 *ptr = buffer; - U8 *opl = buffer + total_size; - B32 success = 1; - for (;ptr < opl;){ - U64 total_to_read = (U64)(opl - ptr); - DWORD to_read = (DWORD)total_to_read; - if (total_to_read > max_U32){ - to_read = max_U32; - } - DWORD actual_read = 0; - if (!ReadFile(file, ptr, to_read, &actual_read, 0)){ - success = 0; - break; - } - ptr += actual_read; - } - - // set result or reset memory - if (success){ - buffer[total_size] = 0; - result.str = buffer; - result.size = total_size; - } - else{ - arena_end_temp(&restore_point); - } - - CloseHandle(file); - } - - arena_release_scratch(&scratch); - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL B32 -os_file_write_callback(String8 file_name, void *udata, OS_FileWriteCallback *callback){ - ProfBeginFunc(); - - // get handle - ArenaTemp scratch = arena_get_scratch(0, 0); - String16 file_name16 = str16_from_str8(scratch.arena, file_name); - HANDLE file = CreateFileW((WCHAR*)file_name16.str, - GENERIC_WRITE, 0, 0, - CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, - 0); - - B32 result = 0; - if (file != INVALID_HANDLE_VALUE){ - result = 1; - - for (;;){ - String8 chunk = callback(udata); - if (chunk.size == 0){ - break; - } - - U8 *ptr = chunk.str; - U8 *opl = chunk.str + chunk.size; - for (;ptr < opl;){ - U64 total_to_write = (U64)(opl - ptr); - DWORD to_write = total_to_write; - if (total_to_write > max_U32){ - to_write = max_U32; - } - DWORD actual_write = 0; - if (!WriteFile(file, ptr, to_write, &actual_write, 0)){ - result = 0; - goto dblbreak; - } - ptr += actual_write; - } - } - dblbreak:; - - // close file - CloseHandle(file); - } - - arena_release_scratch(&scratch); - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL B32 -os_file_write_list(String8 file_name, String8Node *first_node){ - ProfBeginFunc(); - - // get handle - ArenaTemp scratch = arena_get_scratch(0, 0); - String16 file_name16 = str16_from_str8(scratch.arena, file_name); - HANDLE file = CreateFileW((WCHAR*)file_name16.str, - GENERIC_WRITE, 0, 0, - CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, - 0); - - B32 result = 0; - if (file != INVALID_HANDLE_VALUE){ - result = 1; - - for (String8Node *node = first_node; - node != 0; - node = node->next){ - U8 *ptr = node->string.str; - U8 *opl = ptr + node->string.size; - for (;ptr < opl;){ - U64 total_to_write = (U64)(opl - ptr); - DWORD to_write = total_to_write; - if (total_to_write > max_U32){ - to_write = max_U32; - } - DWORD actual_write = 0; - if (!WriteFile(file, ptr, to_write, &actual_write, 0)){ - result = 0; - goto dblbreak; - } - ptr += actual_write; - } - } - dblbreak:; - - CloseHandle(file); - } - - arena_release_scratch(&scratch); - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL FileProperties -os_file_properties(String8 file_name){ - ProfBeginFunc(); - - // convert name - ArenaTemp scratch = arena_get_scratch(0, 0); - String16 file_name16 = str16_from_str8(scratch.arena, file_name); - - // get attribs and convert to properties - FileProperties result = {0}; - WIN32_FILE_ATTRIBUTE_DATA attribs = {0}; - if (GetFileAttributesExW((WCHAR*)file_name16.str, GetFileExInfoStandard, - &attribs)){ - result.size = ((U64)attribs.nFileSizeHigh << 32) | (U64)attribs.nFileSizeLow; - result.flags = w32_prop_flags_from_attribs(attribs.dwFileAttributes); - result.create_time = w32_dense_time_from_file_time(&attribs.ftCreationTime); - result.modify_time = w32_dense_time_from_file_time(&attribs.ftLastWriteTime); - result.access = w32_access_from_attributes(attribs.dwFileAttributes); - } - - arena_release_scratch(&scratch); - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL B32 -os_file_delete(String8 file_name){ - ProfBeginFunc(); - - // convert name - ArenaTemp scratch = arena_get_scratch(0, 0); - String16 file_name16 = str16_from_str8(scratch.arena, file_name); - // delete file - B32 result = DeleteFileW((WCHAR*)file_name16.str); - arena_release_scratch(&scratch); - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL B32 -os_file_rename(String8 og_name, String8 new_name){ - ProfBeginFunc(); - - // convert name - ArenaTemp scratch = arena_get_scratch(0, 0); - String16 og_name16 = str16_from_str8(scratch.arena, og_name); - String16 new_name16 = str16_from_str8(scratch.arena, new_name); - // rename file - B32 result = MoveFileW((WCHAR*)og_name16.str, (WCHAR*)new_name16.str); - arena_release_scratch(&scratch); - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL B32 -os_file_make_directory(String8 path){ - ProfBeginFunc(); - - // convert name - ArenaTemp scratch = arena_get_scratch(0, 0); - String16 path16 = str16_from_str8(scratch.arena, path); - // make directory - B32 result = CreateDirectoryW((WCHAR*)path16.str, 0); - arena_release_scratch(&scratch); - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL B32 -os_file_delete_directory(String8 path){ - ProfBeginFunc(); - - // convert name - ArenaTemp scratch = arena_get_scratch(0, 0); - String16 path16 = str16_from_str8(scratch.arena, path); - // make directory - B32 result = RemoveDirectoryW((WCHAR*)path16.str); - arena_release_scratch(&scratch); - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL OS_FileIter -os_file_iter_init(Arena *arena, String8 path){ - ProfBeginFunc(); - - // convert name - String8Node nodes[2]; - String8List list; - - nodes[0].string = path; - nodes[0].next = nodes + 1; - nodes[1].string = str8_lit("\\*"); - nodes[1].next = 0; - - list.first = nodes + 0; - list.last = nodes + 1; - list.node_count = 2; - list.total_size = path.size + 2; - - ArenaTemp scratch = arena_get_scratch(&arena, 1); - String8 path_star = str8_join(scratch.arena, &list, 0); - // TODO(allen): Better unicode conversions here - String16 path16 = str16_from_str8(scratch.arena, path_star); - - // store into iter - OS_FileIter result = {0}; - W32_FileIter *w32_iter = (W32_FileIter*)&result; - w32_iter->handle = FindFirstFileW((WCHAR*)path16.str, &w32_iter->find_data); - arena_release_scratch(&scratch); - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL B32 -os_file_iter_next(Arena *arena, OS_FileIter *iter, - String8 *name, FileProperties *props){ - ProfBeginFunc(); - - B32 result = 0; - - W32_FileIter *w32_iter = (W32_FileIter*)iter; - if (w32_iter->handle != 0 && - w32_iter->handle != INVALID_HANDLE_VALUE){ - for (;!w32_iter->done;){ - // check for . and .. - WCHAR *file_name = w32_iter->find_data.cFileName; - B32 is_dot = (file_name[0] == '.' && file_name[1] == 0); - B32 is_dotdot = (file_name[0] == '.' && file_name[1] == '.' && - file_name[2] == 0); - - // setup to emit - B32 emit = (!is_dot && !is_dotdot); - WIN32_FIND_DATAW data = {0}; - if (emit){ - MemoryCopyStruct(&data, &w32_iter->find_data); - } - - // increment the iterator - if (!FindNextFileW(w32_iter->handle, &w32_iter->find_data)){ - w32_iter->done = 1; - } - - // do the emit if we saved one earlier - if (emit){ - *name = str8_from_str16(arena, str16_cstring((U16*)data.cFileName)); - props->size = ((U64)data.nFileSizeHigh << 32) | (U64)data.nFileSizeLow; - props->flags = w32_prop_flags_from_attribs(data.dwFileAttributes); - props->create_time = w32_dense_time_from_file_time(&data.ftCreationTime); - props->modify_time = w32_dense_time_from_file_time(&data.ftLastWriteTime); - props->access = w32_access_from_attributes(data.dwFileAttributes); - result = 1; - break; - } - } - } - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL void -os_file_iter_end(OS_FileIter *iter){ - ProfBeginFunc(); - - W32_FileIter *w32_iter = (W32_FileIter*)iter; - if (w32_iter->handle != 0 && - w32_iter->handle != INVALID_HANDLE_VALUE){ - FindClose(w32_iter->handle); - } - - ProfEndFunc(); -} - -MR4TH_SYMBOL String8 -os_file_path(Arena *arena, OS_SystemPath path){ - ProfBeginFunc(); - - String8 result = {0}; - - switch (path){ - case OS_SystemPath_CurrentDirectory: - { - ArenaTemp scratch = arena_get_scratch(&arena, 1); - DWORD cap = 2048; - U16 *buffer = push_array(scratch.arena, U16, cap); - DWORD size = GetCurrentDirectoryW(cap, (WCHAR*)buffer); - if (size >= cap){ - arena_end_temp(&scratch); - buffer = push_array(scratch.arena, U16, size + 1); - size = GetCurrentDirectoryW(size + 1, (WCHAR*)buffer); - } - result = str8_from_str16(arena, CLiteral(String16){buffer, size}); - arena_release_scratch(&scratch); - }break; - - case OS_SystemPath_Binary: - { - result = str8_push_copy(arena, w32_binary_path); - }break; - - case OS_SystemPath_UserData: - { - result = str8_push_copy(arena, w32_user_path); - }break; - - case OS_SystemPath_TempData: - { - result = str8_push_copy(arena, w32_temp_path); - }break; - } - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL void -os_set_current_directory(String8 path){ - ArenaTemp scratch = arena_get_scratch(0, 0); - - String16 path16 = str16_from_str8(scratch.arena, path); - SetCurrentDirectoryW((WCHAR*)path16.str); - - arena_release_scratch(&scratch); -} - - -//////////////////////////////// -// Win32 Implementation: Time - -MR4TH_SYMBOL DateTime -os_now_universal_time(void){ - SYSTEMTIME system_time = {0}; - GetSystemTime(&system_time); - DateTime result = w32_date_time_from_system_time(&system_time); - return(result); -} - -MR4TH_SYMBOL DateTime -os_local_time_from_universal(DateTime *univ_date_time){ - SYSTEMTIME univ_system_time = w32_system_time_from_date_time(univ_date_time); - FILETIME univ_file_time = {0}; - SystemTimeToFileTime(&univ_system_time, &univ_file_time); - FILETIME local_file_time = {0}; - FileTimeToLocalFileTime(&univ_file_time, &local_file_time); - SYSTEMTIME local_system_time = {0}; - FileTimeToSystemTime(&local_file_time, &local_system_time); - DateTime result = w32_date_time_from_system_time(&local_system_time); - return(result); -} - -MR4TH_SYMBOL DateTime -os_universal_time_from_local(DateTime *local_date_time){ - SYSTEMTIME local_system_time = w32_system_time_from_date_time(local_date_time); - FILETIME local_file_time = {0}; - SystemTimeToFileTime(&local_system_time, &local_file_time); - FILETIME univ_file_time = {0}; - LocalFileTimeToFileTime(&local_file_time, &univ_file_time); - SYSTEMTIME univ_system_time = {0}; - FileTimeToSystemTime(&univ_file_time, &univ_system_time); - DateTime result = w32_date_time_from_system_time(&univ_system_time); - return(result); -} - -MR4TH_SYMBOL U32 -os_time_stamp_32_from_date_time(DateTime *date_time){ - SYSTEMTIME system_time = w32_system_time_from_date_time(date_time); - FILETIME file_time = {0}; - SystemTimeToFileTime(&system_time, &file_time); - U64 file_time64 = ( (U64) file_time.dwLowDateTime + - ((U64)(file_time.dwHighDateTime) << 32ll) - ); - U32 result = (U32) ((file_time64 - 116444736000000000ll)/10000000ll); - return(result); -} - - -MR4TH_SYMBOL U64 -os_now_ticks(void){ - U64 result = 0; - LARGE_INTEGER perf_counter = {0}; - if (QueryPerformanceCounter(&perf_counter)){ - result = ((U64)perf_counter.HighPart << 32) | perf_counter.LowPart; - } - return(result); -} - -MR4TH_SYMBOL void -os_get_microseconds_per_tick(U64 *usecs_out, U64 *ticks_out){ - *usecs_out = Million(1); - *ticks_out = w32_ticks_per_second; -} - -MR4TH_SYMBOL void -os_sleep_milliseconds(U32 t){ - Sleep(t); -} - -//////////////////////////////// -// Win32 Implementation: Libraries - -MR4TH_SYMBOL OS_Library* -os_lib_load(String8 path){ - ArenaTemp scratch = arena_get_scratch(0, 0); - String16 path16 = str16_from_str8(scratch.arena, path); - OS_Library *result = (OS_Library*)(LoadLibraryW((WCHAR*)path16.str)); - arena_release_scratch(&scratch); - return(result); -} - -MR4TH_SYMBOL VoidFunc* -os_lib_get_proc(OS_Library *lib, char *name){ - HMODULE module = (HMODULE)(lib); - VoidFunc *result = (VoidFunc*)(GetProcAddress(module, name)); - return(result); -} - -MR4TH_SYMBOL void -os_lib_release(OS_Library *lib){ - HMODULE module = (HMODULE)(lib); - FreeLibrary(module); -} - -MR4TH_SYMBOL OS_Library* -os_lib_from_addr(void *addr){ - HMODULE module = 0; - GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, - (LPWSTR)addr, &module); - return((OS_Library*)module); -} - -MR4TH_SYMBOL OS_VRange -os_lib_image_range(OS_Library *lib){ - OS_VRange result = {0}; - HANDLE process = GetCurrentProcess(); - MODULEINFO module_info = {0}; - if (GetModuleInformation(process, (HMODULE)lib, - &module_info, sizeof(module_info))){ - result.addr = (U8*)module_info.lpBaseOfDll; - result.size = module_info.SizeOfImage; - } - return(result); -} - -//////////////////////////////// -// Win32 Implementation: Entropy - -MR4TH_SYMBOL void -os_get_entropy(void *data, U64 size){ - HCRYPTPROV prov = 0; - CryptAcquireContextW(&prov, 0, 0, PROV_DSS, CRYPT_VERIFYCONTEXT); - CryptGenRandom(prov, size, (BYTE*)data); - CryptReleaseContext(prov, 0); -} - -//////////////////////////////// -// Win32 Functions: Specialized Init for WinMain - -MR4TH_SYMBOL_STATIC HINSTANCE w32_instance = 0; - -MR4TH_SYMBOL void -w32_WinMain_init(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPSTR lpCmdLine, - int nShowCmd){ - int argc = __argc; - char **argv = __argv; - w32_instance = hInstance; - os_main_init(argc, argv); -} - -MR4TH_SYMBOL HINSTANCE -w32_get_instance(void){ - if (w32_instance == 0){ - w32_instance = GetModuleHandle(0); - } - return(w32_instance); -} - -//////////////////////////////// -// Win32 Functions: Time Helpers - -MR4TH_SYMBOL DateTime -w32_date_time_from_system_time(SYSTEMTIME *in){ - DateTime result = {0}; - result.year = in->wYear; - result.mon = (U8)in->wMonth; - result.day = in->wDay; - result.hour = in->wHour; - result.min = in->wMinute; - result.sec = in->wSecond; - result.msec = in->wMilliseconds; - return(result); -} - -MR4TH_SYMBOL SYSTEMTIME -w32_system_time_from_date_time(DateTime *in){ - SYSTEMTIME result = {0}; - result.wYear = in->year; - result.wMonth = in->mon; - result.wDay = in->day; - result.wHour = in->hour; - result.wMinute = in->min; - result.wSecond = in->sec; - result.wMilliseconds = in->msec; - return(result); -} - -MR4TH_SYMBOL DenseTime -w32_dense_time_from_file_time(FILETIME *file_time){ - SYSTEMTIME system_time = {0}; - FileTimeToSystemTime(file_time, &system_time); - DateTime date_time = w32_date_time_from_system_time(&system_time); - DenseTime result = dense_time_from_date_time(&date_time); - return(result); -} - -//////////////////////////////// -// Win32 Functions: File Helpers - -MR4TH_SYMBOL FilePropertyFlags -w32_prop_flags_from_attribs(DWORD attribs){ - FilePropertyFlags result = 0; - if (attribs & FILE_ATTRIBUTE_DIRECTORY){ - result |= FilePropertyFlag_IsFolder; - } - return(result); -} - -MR4TH_SYMBOL DataAccessFlags -w32_access_from_attributes(DWORD attribs){ - DataAccessFlags result = DataAccessFlag_Read|DataAccessFlag_Execute; - if (!(attribs & FILE_ATTRIBUTE_READONLY)){ - result |= DataAccessFlag_Write; - } - return(result); -} - -#endif /* OS_WINDOWS */ - -/******************************* -** End Base Win32 ** -*******************************/ - - - -/******************************* -** Begin Base Linux ** -*******************************/ - -#if OS_LINUX - -//////////////////////////////// -// Linux Implementation: Global Variables - -MR4TH_SYMBOL_STATIC Arena *lnx_perm_arena = 0; -MR4TH_SYMBOL_STATIC String8 lnx_binary_path = {0}; -MR4TH_SYMBOL_STATIC String8 lnx_user_path = {0}; -MR4TH_SYMBOL_STATIC String8 lnx_temp_path = {0}; - -MR4TH_SYMBOL_STATIC String8List lnx_cmd_line = {0}; - -//////////////////////////////// -// Linux Implementation: Process Setup - -MR4TH_SYMBOL void -os_main_init(int argc, char **argv){ - ProfBeginFunc(); - - // arena - lnx_perm_arena = arena_alloc(); - - // command line arguments - for (int i = 0; i < argc; i += 1){ - String8 arg = str8_cstring((U8*)argv[i]); - str8_list_push(lnx_perm_arena, &lnx_cmd_line, arg); - } - - // paths - ArenaTemp scratch = arena_get_scratch(0, 0); - - // binary path - { - B32 got_final_result = 0; - U8 *buffer = 0; - int size = 0; - for (U64 cap = PATH_MAX, r = 0; r < 4; cap *= 2, r += 1){ - arena_end_temp(&scratch); - buffer = push_array_no_zero(scratch.arena, U8, cap); - size = readlink("/proc/self/exe", (char*)buffer, cap); - if (size < cap){ - got_final_result = 1; - break; - } - } - - if (got_final_result && size > 0){ - String8 full_name = str8(buffer, (U64)size); - String8 name_chopped = str8_chop_last_slash(full_name); - lnx_binary_path = str8_push_copy(lnx_perm_arena, name_chopped); - } - } - - // user data path - { - char *home = getenv("HOME"); - lnx_user_path = str8_cstring((U8*)home); - } - - // temp data path - { - lnx_temp_path = str8_lit("/var/tmp"); - } - - arena_release_scratch(&scratch); - - ProfEndFunc(); -} - -MR4TH_SYMBOL String8List -os_command_line_arguments(void){ - String8List result = lnx_cmd_line; - return(result); -} - -MR4TH_SYMBOL void -os_exit_process(U32 code){ - ProfClose(); - exit((int)code); -} - -//////////////////////////////// -// Linux Implementation: Memory Functions - -MR4TH_SYMBOL void* -os_memory_reserve(U64 size){ - void *result = mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); - if (result == MAP_FAILED){ - result = 0; - } - return(result); -} - -MR4TH_SYMBOL B32 -os_memory_commit(void *ptr, U64 size){ - B32 result = 0; - if (mprotect(ptr, size, PROT_READ|PROT_WRITE) == 0){ - result = 1; - } - return(result); -} - -MR4TH_SYMBOL void -os_memory_decommit(void *ptr, U64 size){ - madvise(ptr, size, MADV_DONTNEED); - mprotect(ptr, size, PROT_NONE); -} - -MR4TH_SYMBOL void -os_memory_release(void *ptr, U64 size){ - munmap(ptr, size); -} - -MR4TH_SYMBOL B32 -os_memory_protect(void *ptr, U64 size, DataAccessFlags access_flags){ - int prot = PROT_NONE; - if ((access_flags&DataAccessFlag_Read) == 0){ - prot |= PROT_READ; - } - if ((access_flags&DataAccessFlag_Write) == 0){ - prot |= PROT_WRITE; - } - if ((access_flags&DataAccessFlag_Execute) == 0){ - prot |= PROT_EXEC; - } - - B32 result = (mprotect(ptr, size, prot)); - return(result); -} - -//////////////////////////////// -// Linux Implementation: File Handling - -MR4TH_SYMBOL String8 -os_file_read(Arena *arena, String8 file_name){ - ProfBeginFunc(); - - // get handle - ArenaTemp scratch = arena_get_scratch(&arena, 1); - // (this ensures file_name8 has a null terminator) - String8 file_name8 = str8_push_copy(scratch.arena, file_name); - int file = open((char*)file_name8.str, O_RDONLY); - - String8 result = {0}; - if (file >= 0){ - // get size - struct stat file_stat = {0}; - U64 size = 0; - if (fstat(file, &file_stat) == 0){ - size = file_stat.st_size; - } - - // allocate buffer - if (size > 0){ - ArenaTemp restore_point = arena_begin_temp(arena); - U8 *buffer = push_array_no_zero(arena, U8, size + 1); - - // read - U8 *ptr = buffer; - U8 *opl = buffer + size; - B32 success = 1; - for (;ptr < opl;){ - U64 total_to_read = (U64)(opl - ptr); - U32 to_read = (U32)total_to_read; - if (total_to_read > max_U32){ - to_read = max_U32; - } - int read_result = read(file, buffer, to_read); - if (read_result < 0){ - success = 0; - break; - } - else if (read_result == 0){ - break; - } - ptr += read_result; - } - - // set result or reset memory - if (success){ - U64 final_size = (U64)(ptr - buffer); - final_size = ClampTop(final_size, size); - buffer[final_size] = 0; - result.str = buffer; - result.size = final_size; - } - else{ - arena_end_temp(&restore_point); - } - } - - // close file - close(file); - } - - arena_release_scratch(&scratch); - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL B32 -os_file_write_callback(String8 file_name, void *udata, OS_FileWriteCallback *callback){ - ProfBeginFunc(); - - // get handle - ArenaTemp scratch = arena_get_scratch(0, 0); - String8 file_name8 = str8_push_copy(scratch.arena, file_name); - int file = open((char*)file_name8.str, O_CREAT|O_WRONLY|O_TRUNC, 0666); - - B32 result = 0; - if (file >= 0){ - result = 1; - - for (;;){ - String8 chunk = callback(udata); - if (chunk.size == 0){ - break; - } - - U8 *ptr = chunk.str; - U8 *opl = chunk.str + chunk.size; - for (;ptr < opl;){ - U64 total_to_write = (U64)(opl - ptr); - U32 to_write = total_to_write; - if (total_to_write > (U32)SSIZE_MAX){ - to_write = (U32)SSIZE_MAX; - } - int write_result = write(file, ptr, to_write); - - if (write_result <= 0){ - result = 0; - goto dblbreak; - } - ptr += write_result; - } - - } - dblbreak:; - - // close file - close(file); - } - - arena_release_scratch(&scratch); - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL FileProperties -os_file_properties(String8 file_name){ - ProfBeginFunc(); - - // convert name - ArenaTemp scratch = arena_get_scratch(0, 0); - // (this ensures file_name8 has a null terminator) - String8 file_name8 = str8_push_copy(scratch.arena, file_name); - int file = open((char*)file_name8.str, O_RDONLY); - - // get file stat and convert to properties - FileProperties result = {0}; - struct stat file_stat = {0}; - if (fstat(file, &file_stat) == 0){ - result = lnx_file_properties_from_stat(&file_stat); - } - - arena_release_scratch(&scratch); - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL B32 -os_file_delete(String8 file_name){ - ProfBeginFunc(); - - ArenaTemp scratch = arena_get_scratch(0, 0); - String8 file_name8 = str8_push_copy(scratch.arena, file_name); - - B32 result = 0; - if (remove((char*)file_name8.str) >= 0){ - result = 1; - } - - arena_end_temp(&scratch); - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL B32 -os_file_rename(String8 og_name, String8 new_name){ - ProfBeginFunc(); - - ArenaTemp scratch = arena_get_scratch(0, 0); - String8 og_name8 = str8_push_copy(scratch.arena, og_name); - String8 new_name8 = str8_push_copy(scratch.arena, new_name); - - int rename_result = rename((char*)og_name8.str, (char*)new_name8.str); - B32 result = (rename_result >= 0); - - arena_release_scratch(&scratch); - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL B32 -os_file_make_directory(String8 path){ - ProfBeginFunc(); - - ArenaTemp scratch = arena_get_scratch(0, 0); - String8 path8 = str8_push_copy(scratch.arena, path); - - B32 result = 0; - if (mkdir((char*)path8.str, 0755) >= 0){ - result = 1; - } - - arena_release_scratch(&scratch); - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL B32 -os_file_delete_directory(String8 path){ - ProfBeginFunc(); - - ArenaTemp scratch = arena_get_scratch(0, 0); - String8 path8 = str8_push_copy(scratch.arena, path); - - B32 result = 0; - if (rmdir((char*)path8.str) >= 0){ - result = 1; - } - - arena_release_scratch(&scratch); - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL OS_FileIter -os_file_iter_init(Arena *arena, String8 path){ - ProfBeginFunc(); - - String8 path8 = str8_push_copy(arena, path); - - OS_FileIter result = {0}; - LNX_FileIter *lnx_iter = (LNX_FileIter*)&result; - lnx_iter->dir = opendir((char*)path8.str); - lnx_iter->path = path8; - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL B32 -os_file_iter_next(Arena *arena, OS_FileIter *iter, - String8 *name, FileProperties *props){ - B32 result = 0; - LNX_FileIter *lnx_iter = (LNX_FileIter*)iter; - - String8 path = lnx_iter->path; - - for (;lnx_iter->dir != 0;){ - struct dirent *dp = readdir(lnx_iter->dir); - result = (dp != 0); - - String8 file_name = {0}; - if (result){ - file_name = str8_cstring((U8*)dp->d_name); - } - - struct stat st = {0}; - int stat_result = 0; - if (result){ - ArenaTemp scratch = arena_get_scratch(&arena, 1); - - String8 full_path = {0}; - full_path.size = path.size + 1 + file_name.size; - full_path.str = push_array_no_zero(scratch.arena, U8, full_path.size + 1); - MemoryCopy(full_path.str, path.str, path.size); - full_path.str[path.size] = '/'; - MemoryCopy(full_path.str, file_name.str, file_name.size); - full_path.str[full_path.size] = 0; - - stat_result = stat((char*)full_path.str, &st); - - arena_release_scratch(&scratch); - } - - B32 filtered = 0; - if (result){ - if (file_name.str != 0 && - ((file_name.str[0] == '.' && file_name.str[1] == 0) || - (file_name.str[0] == '.' && file_name.str[1] == 0 && file_name.str[2] == 0))){ - filtered = 1; - } - } - - if (result && !filtered){ - *name = str8_push_copy(arena, file_name); - if (stat_result >= 0){ - *props = lnx_file_properties_from_stat(&st); - } - result = 1; - break; - } - } - - return(result); -} - -MR4TH_SYMBOL void -os_file_iter_end(OS_FileIter *iter){ - ProfBeginFunc(); - - LNX_FileIter *lnx_iter = (LNX_FileIter*)iter; - if (lnx_iter->dir != 0){ - closedir(lnx_iter->dir); - lnx_iter->dir = 0; - } - - ProfEndFunc(); -} - -MR4TH_SYMBOL String8 -os_file_path(Arena *arena, OS_SystemPath path){ - ProfBeginFunc(); - - String8 result = {0}; - - switch (path){ - default:break; - - case OS_SystemPath_CurrentDirectory: - { - char *cwd = getcwd(0, 0); - result = str8_push_copy(arena, str8_cstring((U8*)cwd)); - free(cwd); - }break; - - case OS_SystemPath_Binary: - { - result = str8_push_copy(arena, lnx_binary_path); - }break; - - case OS_SystemPath_UserData: - { - result = str8_push_copy(arena, lnx_user_path); - }break; - - case OS_SystemPath_TempData: - { - result = str8_push_copy(arena, lnx_temp_path); - }break; - } - - ProfEndFunc(); - return(result); -} - -MR4TH_SYMBOL void -os_set_current_directory(String8 path){ - ArenaTemp scratch = arena_get_scratch(0, 0); - String8 path8 = str8_push_copy(scratch.arena, path); - chdir((char*)path8.str); - arena_release_scratch(&scratch); -} - - -//////////////////////////////// -// Linux Implementation: Time - -MR4TH_SYMBOL DateTime -os_now_universal_time(void){ - time_t t = time(0); - struct tm tm = {0}; - struct tm *tmptr = gmtime_r(&t, &tm); - DateTime result = {0}; - if (tmptr != 0){ - result = lnx_date_time_from_tm(&tm); - } - return(result); -} - -MR4TH_SYMBOL DateTime -os_local_time_from_universal(DateTime *date_time){ - struct tm univ_tm = lnx_tm_from_date_time(date_time); - univ_tm.tm_isdst = -1; - time_t univ_time_t = timegm(&univ_tm); - struct tm local_tm = {0}; - localtime_r(&univ_time_t, &local_tm); - DateTime result = lnx_date_time_from_tm(&local_tm); - return(result); -} - -MR4TH_SYMBOL DateTime -os_universal_time_from_local(DateTime *date_time){ - struct tm local_tm = lnx_tm_from_date_time(date_time); - local_tm.tm_isdst = -1; - time_t univ_time_t = mktime(&local_tm); - struct tm univ_tm = {0}; - gmtime_r(&univ_time_t, &univ_tm); - DateTime result = lnx_date_time_from_tm(&univ_tm); - return(result); -} - -MR4TH_SYMBOL U32 -os_time_stamp_32_from_date_time(DateTime *date_time){ - struct tm tm = lnx_tm_from_date_time(date_time); - time_t t = timegm(&tm); - return((U32)t); -} - -MR4TH_SYMBOL U64 -os_now_ticks(void){ - struct timespec t = {0}; - clock_gettime(CLOCK_MONOTONIC, &t); - U64 result = t.tv_sec*Million(1) + t.tv_nsec/Thousand(1); - return(result); -} - -MR4TH_SYMBOL void -os_get_microseconds_per_tick(U64 *usecs_out, U64 *ticks_out){ - *usecs_out = 1; - *ticks_out = 1; -} - -MR4TH_SYMBOL void -os_sleep_milliseconds(U32 t){ - usleep(t*Thousand(1)); -} - -//////////////////////////////// -// Linux Implementation: Libraries - -MR4TH_SYMBOL OS_Library* -os_lib_load(String8 path){ - ArenaTemp scratch = arena_get_scratch(0, 0); - String8 path8 = str8_push_copy(scratch.arena, path); - OS_Library *result = (OS_Library*)dlopen((char*)path8.str, RTLD_LAZY|RTLD_LOCAL); - arena_release_scratch(&scratch); - return(result); -} - -MR4TH_SYMBOL VoidFunc* -os_lib_get_proc(OS_Library *lib, char *name){ - VoidFunc *proc = (VoidFunc*)dlsym((void*)lib, name); - return(proc); -} - -MR4TH_SYMBOL void -os_lib_release(OS_Library *lib){ - dlclose((void*)lib); -} - -MR4TH_SYMBOL OS_Library* -os_lib_from_addr(void *addr){ - UAddr addrx = IntFromPtr(addr); - ArenaTemp scratch = arena_get_scratch(0, 0); - - // NOTE(allen): - // Implementing this on Linux is a lot less solidly - // supported than it is on Windows. - // - // As far as I can tell, reading "/proc/self/maps" is the - // only portable way to get at the information. The fact - // that this information is in only available in this text - // based unaccelerated structured is unfortunate. - // - // But even worse is the fact that, even with this info, - // to actually get one of the opaque handles to the - // library, we have to call dlopen again -- no other API - // appears to exist which can return the required information. - // - // But that also means that the library gets a reference - // count from this call and so we have to then call dlclose - // on the handle just to decrement that reference counter. - // - // I don't even know yet if this handles the base executable - // of the program correctly. - - // read "/proc/self/maps" - B32 got_result = 0; - U8 *buffer = 0; - int size = 0; - for (U64 cap = KB(4), r = 0; r < 6; cap *= 64, r += 1){ - arena_end_temp(&scratch); - buffer = push_array_no_zero(scratch.arena, U8, cap); - size = readlink("/proc/self/maps", (char*)buffer, cap); - if (size < cap){ - got_result = 1; - break; - } - } - - // parse contents from "/proc/self/maps" - String8 contents = str8(buffer, (U64)size); - String8List lines = str8_split(scratch.arena, contents, (U8*)"\n", 1); - for (String8Node *node = lines.first; - node != 0; - node = node->next){ - String8 line = node->string; - U8 *opl = line.str + line.size; - - - U8 *dash_ptr = line.str; - for (;dash_ptr < opl && *dash_ptr != '-'; dash_ptr += 1); - - U8 *addr_max_opl = dash_ptr; - for (;dash_ptr < opl && *dash_ptr != ' '; dash_ptr += 1); - - U8 *slash_ptr = addr_max_opl; - for (;slash_ptr < opl && *slash_ptr != '/'; slash_ptr += 1); - - U64 addr_min = u64_from_str8(str8_range(line.str, dash_ptr), 0x10); - U64 addr_max = u64_from_str8(str8_range(dash_ptr + 1, addr_max_opl), 0x10); - String8 path = str8_range(slash_ptr, opl); - - - } - - push_array_no_zero(scratch.arena, U8, size); - - arena_release_scratch(&scratch); - - OS_Library *library = 0; - return(library); -} - -MR4TH_SYMBOL OS_VRange -os_lib_image_range(OS_Library *lib){ - OS_VRange result = {0}; - // TODO(allen): - return(result); -} - -//////////////////////////////// -// Linux Implementation: Entropy - -MR4TH_SYMBOL void -os_get_entropy(void *data, U64 size){ - getrandom(data, size, 0); -} - -//////////////////////////////// -// Linux Functions: Time Helpers - -MR4TH_SYMBOL DateTime -lnx_date_time_from_tm(struct tm *tm){ - DateTime result = {0}; - result.year = tm->tm_year + 1900; - result.mon = tm->tm_mon + 1; - result.day = tm->tm_mday; - result.hour = tm->tm_hour; - result.min = tm->tm_min; - result.sec = tm->tm_sec; - result.msec = 0; - return(result); -} - -MR4TH_SYMBOL DenseTime -lnx_dense_time_from_time_t(time_t time){ - struct tm system_time = *gmtime(&time); - DateTime date_time = lnx_date_time_from_tm(&system_time); - DenseTime result = dense_time_from_date_time(&date_time); - return(result); -} - -MR4TH_SYMBOL struct tm -lnx_tm_from_date_time(DateTime *date_time){ - struct tm result = {0}; - result.tm_sec = date_time->sec; - result.tm_min = date_time->min; - result.tm_hour = date_time->hour; - result.tm_mday = date_time->day; - result.tm_mon = date_time->mon - 1; - result.tm_year = date_time->year; - return(result); -} - -//////////////////////////////// -// Linux Functions: File Helpers - -MR4TH_SYMBOL FilePropertyFlags -lnx_prop_flags_from_mode(mode_t mode){ - FilePropertyFlags result = 0; - if ((mode&S_IFDIR) != 0){ - result |= FilePropertyFlag_IsFolder; - } - return(result); -} - -MR4TH_SYMBOL DataAccessFlags -lnx_access_from_mode(mode_t mode){ - DataAccessFlags result = 0; - if ((mode&(S_IRUSR|S_IRGRP)) != 0){ - result |= DataAccessFlag_Read; - } - if ((mode&(S_IWUSR|S_IWGRP)) != 0){ - result |= DataAccessFlag_Write; - } - if ((mode&(S_IXUSR|S_IXGRP)) != 0){ - result |= DataAccessFlag_Execute; - } - return(result); -} - -MR4TH_SYMBOL FileProperties -lnx_file_properties_from_stat(struct stat *st){ - FileProperties result = {0}; - result.size = st->st_size; - result.flags = lnx_prop_flags_from_mode(st->st_mode); - result.create_time = lnx_dense_time_from_time_t(st->st_ctime); - result.modify_time = lnx_dense_time_from_time_t(st->st_mtime); - // TODO(allen): research: - // how do these flags from fstat behave? - // S_IRUSR, S_IWUSR, S_IXUSR - // S_IRGRP, S_IWGRP, S_IXGRP - // S_IROTH, S_IWOTH, S_IXOTH - result.access = lnx_access_from_mode(st->st_mode); - return(result); -} - -MR4TH_SYMBOL String8 -lnx_proc_file_read(Arena *arena, char *path){ - ArenaTemp scratch = arena_get_scratch(&arena, 1); - - int file = open(path, O_RDONLY); - - String8List list = {0}; - if (file >= 0){ - S64 cap = KB(4); - for (;;){ - U8 *buffer = push_array_no_zero(scratch.arena, U8, cap); - int size = read(file, buffer, cap); - if (size > 0){ - str8_list_push(scratch.arena, &list, str8(buffer, (U64)size)); - } - if (size < cap){ - break; - } - cap *= 4; - } - } - - String8 result = str8_join(arena, &list, 0); - - arena_release_scratch(&scratch); - - return(result); -} - -#endif /* OS_LINUX */ - -/******************************* -** End Base Linux ** -*******************************/ - - -//////////////////////////////////////////////// -//////////////////////////////////////////////// -///////////////// M4 Printf //////////////// -//////////////////////////////////////////////// -//////////////////////////////////////////////// - -// stb_sprintf.h STB_SPRINTF_IMPLEMENTATION - -#define stbsp__uint32 U32 -#define stbsp__int32 S32 -#define stbsp__uint64 U64 -#define stbsp__int64 S64 -#define stbsp__uint16 U16 -#define stbsp__uintptr UAddr - -// NOTE: modification - removed STB_SPRINTF_MSVC_MODE -- compatibility mode for behavior from MSVC2013 and earlier - -#ifdef STB_SPRINTF_NOUNALIGNED // define this before inclusion to force stbsp_sprintf to always use aligned accesses -#define STBSP__UNALIGNED(code) -#else -#define STBSP__UNALIGNED(code) code -#endif - -// internal float utility functions -static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits); -static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value); -#define STBSP__SPECIAL 0x7000 - -static char stbsp__period = '.'; -static char stbsp__comma = ','; -static struct{ - short temp; // force next field to be 2-byte aligned - char pair[201]; -} stbsp__digitpair = -{ - 0, - "00010203040506070809101112131415161718192021222324" - "25262728293031323334353637383940414243444546474849" - "50515253545556575859606162636465666768697071727374" - "75767778798081828384858687888990919293949596979899" -}; - -STBSP__PUBLICDEF void m4_set_separators(char pcomma, char pperiod) -{ - stbsp__period = pperiod; - stbsp__comma = pcomma; -} - -#define STBSP__LEFTJUST 1 -#define STBSP__LEADINGPLUS 2 -#define STBSP__LEADINGSPACE 4 -#define STBSP__LEADING_0X 8 -#define STBSP__LEADINGZERO 16 -#define STBSP__INTMAX 32 -#define STBSP__TRIPLET_COMMA 64 -#define STBSP__NEGATIVE 128 -#define STBSP__MEMORY_SIZES 256 -#define STBSP__HALFWIDTH 512 - -static void stbsp__lead_sign(stbsp__uint32 fl, char *sign) -{ - sign[0] = 0; - if (fl & STBSP__NEGATIVE) { - sign[0] = 1; - sign[1] = '-'; - } else if (fl & STBSP__LEADINGSPACE) { - sign[0] = 1; - sign[1] = ' '; - } else if (fl & STBSP__LEADINGPLUS) { - sign[0] = 1; - sign[1] = '+'; - } -} - -static STBSP__ASAN stbsp__uint32 stbsp__strlen_limited(char const *s, stbsp__uint32 limit) -{ - char const * sn = s; - - // get up to 4-byte alignment - for (;;) { - if (((stbsp__uintptr)sn & 3) == 0) - break; - - if (!limit || *sn == 0) - return (stbsp__uint32)(sn - s); - - ++sn; - --limit; - } - - // scan over 4 bytes at a time to find terminating 0 - // this will intentionally scan up to 3 bytes past the end of buffers, - // but becase it works 4B aligned, it will never cross page boundaries - // (hence the STBSP__ASAN markup; the over-read here is intentional - // and harmless) - while (limit >= 4) { - stbsp__uint32 v = *(stbsp__uint32 *)sn; - // bit hack to find if there's a 0 byte in there - if ((v - 0x01010101) & (~v) & 0x80808080UL) - break; - - sn += 4; - limit -= 4; - } - - // handle the last few characters to find actual size - while (limit && *sn) { - ++sn; - --limit; - } - - return (stbsp__uint32)(sn - s); -} - -STBSP__PUBLICDEF int m4_vsprintfcb(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va) -{ - static char hex[] = "0123456789abcdefxp"; - static char hexu[] = "0123456789ABCDEFXP"; - static char spaces[] = - " " - " " - " " - " "; - char *bf = buf; - char const *f = fmt; - int tlen = 0; - - for (;;){ - stbsp__int32 field_width; - stbsp__int32 precision; - stbsp__int32 tz; - stbsp__uint32 flags; - - // macros for the callback buffer stuff -#define stbsp__chk_cb_bufL(bytes) \ -{ \ -int len = (int)(bf - buf); \ -if ((len + (bytes)) >= STB_SPRINTF_MIN){ \ -tlen += len; \ -if (0 == (bf = buf = callback(buf, user, len))) goto done; \ -} \ -} - -#define stbsp__chk_cb_buf(bytes) \ -{ \ -if (callback) { \ -stbsp__chk_cb_bufL(bytes); \ -} \ -} - -#define stbsp__flush_cb() \ -{ \ -stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \ -} // flush if there is even one byte in the buffer - -#define stbsp__cb_buf_clamp(cl, v) \ -cl = v; \ -if (callback) { \ -int lg = STB_SPRINTF_MIN - (int)(bf - buf); \ -if (cl > lg) \ -cl = lg; \ -} - - // fast copy everything up to the next % (or end of string) - for (;;) { - while (((stbsp__uintptr)f) & 3) { - schk1: - if (f[0] == '%') goto scandd; - schk2: - if (f[0] == 0) goto endfmt; - stbsp__chk_cb_buf(1); - *bf++ = f[0]; - ++f; - } - for (;;) { - // Check if the next 4 bytes contain %(0x25) or end of string. - // Using the 'hasless' trick: - // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord - stbsp__uint32 v, c; - v = *(stbsp__uint32 *)f; - c = (~v) & 0x80808080; - if (((v ^ 0x25252525) - 0x01010101) & c) - goto schk1; - if ((v - 0x01010101) & c) - goto schk2; - if (callback) - if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4) - goto schk1; -#ifdef STB_SPRINTF_NOUNALIGNED - if(((stbsp__uintptr)bf) & 3) { - bf[0] = f[0]; - bf[1] = f[1]; - bf[2] = f[2]; - bf[3] = f[3]; - } else -#endif - { - *(stbsp__uint32 *)bf = v; - } - bf += 4; - f += 4; - } - } - scandd: - - ++f; - - // ok, we have a percent, read the modifiers first - field_width = 0; - precision = -1; - flags = 0; - tz = 0; - - // flags - for (;;) { - switch (f[0]) { - // if we have left justify - case '-': - flags |= STBSP__LEFTJUST; - ++f; - continue; - // if we have leading plus - case '+': - flags |= STBSP__LEADINGPLUS; - ++f; - continue; - // if we have leading space - case ' ': - flags |= STBSP__LEADINGSPACE; - ++f; - continue; - // if we have leading 0x - case '#': - flags |= STBSP__LEADING_0X; - ++f; - continue; - // if we have thousand commas - case '\'': - flags |= STBSP__TRIPLET_COMMA; - ++f; - continue; - // if we have memory sizes - case '$': - flags |= STBSP__MEMORY_SIZES; - ++f; - continue; - // if we have leading zero - case '0': - flags |= STBSP__LEADINGZERO; - ++f; - goto flags_done; - default: goto flags_done; - } - } - flags_done: - - // get the field width - if (f[0] == '*'){ - field_width = va_arg(va, stbsp__uint32); - ++f; - } - else{ - while ((f[0] >= '0') && (f[0] <= '9')) { - field_width = field_width*10 + f[0] - '0'; - f++; - } - } - - // get the precision - if (f[0] == '.'){ - ++f; - if (f[0] == '*'){ - precision = va_arg(va, stbsp__uint32); - ++f; - } - else{ - precision = 0; - while ((f[0] >= '0') && (f[0] <= '9')){ - precision = precision*10 + f[0] - '0'; - f++; - } - } - } - - // handle integer size overrides - switch (f[0]){ - // are we halfwidth? - case 'h': - flags |= STBSP__HALFWIDTH; - ++f; - if (f[0] == 'h') - ++f; // QUARTERWIDTH - break; - // are we 64-bit (unix style) - case 'l': - flags |= ((sizeof(long) == 8) ? STBSP__INTMAX : 0); - ++f; - if (f[0] == 'l') { - flags |= STBSP__INTMAX; - ++f; - } - break; - // are we 64-bit on intmax? (c99) - case 'j': - flags |= (sizeof(size_t) == 8) ? STBSP__INTMAX : 0; - ++f; - break; - // are we 64-bit on size_t or ptrdiff_t? (c99) - case 'z': - flags |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0; - ++f; - break; - case 't': - flags |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0; - ++f; - break; - // are we 64-bit (msft style) - case 'I': - if ((f[1] == '6') && (f[2] == '4')) { - flags |= STBSP__INTMAX; - f += 3; - } else if ((f[1] == '3') && (f[2] == '2')) { - f += 3; - } else { - flags |= ((sizeof(void *) == 8) ? STBSP__INTMAX : 0); - ++f; - } - break; - default: break; - } - - // handle each replacement - switch (f[0]){ -#define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307 - char num[STBSP__NUMSZ]; - char lead[8]; - char tail[8]; - char *s; - char const *h; - stbsp__uint32 l; - stbsp__uint32 n; - stbsp__uint32 cs; - stbsp__uint64 n64; - double fv; - stbsp__int32 dp; - char const *sn; - - // NOTE(allen): MODIFICATION - // %S prints str (parameter: String8 str) - case 'S': - { - String8 *str = va_arg(va, String8*); - s = (char*)str->str; - l = (precision >= 0 && precision < str->size) ? precision : (U32)str->size; - lead[0] = 0; - tail[0] = 0; - precision = 0; - dp = 0; - cs = 0; - goto scopy; - } - - // NOTE(allen): MODIFICATION - // %N prints n spaces (parameter: int n) - case 'N': - { - // TODO(allen): there's probably a better way to set this - // up so that it doesn't rely on the buffer of spaces - - // perhaps a way to apply the space filling in the left justify path? - l = va_arg(va, int); - l = (sizeof(spaces) - 1 < l) ? (sizeof(spaces) - 1) : l; - l = (precision >= 0 && precision < l) ? precision : l; - s = spaces; - lead[0] = 0; - tail[0] = 0; - precision = 0; - dp = 0; - cs = 0; - goto scopy; - } - - case 's': - { - // get the string - s = va_arg(va, char *); - if (s == 0){ - s = (char *)"null"; - } - // get the length, limited to desired precision - // always limit to ~0u chars since our counts are 32b - l = stbsp__strlen_limited(s, (precision >= 0) ? precision : ~0u); - lead[0] = 0; - tail[0] = 0; - precision = 0; - dp = 0; - cs = 0; - // copy the string in - goto scopy; - } - - case 'c': // char - { - // get the character - s = num + STBSP__NUMSZ - 1; - *s = (char)va_arg(va, int); - l = 1; - lead[0] = 0; - tail[0] = 0; - precision = 0; - dp = 0; - cs = 0; - goto scopy; - } - - case 'n': // weird write-bytes specifier - { - int *d = va_arg(va, int *); - *d = tlen + (int)(bf - buf); - } break; - - case 'A': // hex float - case 'a': // hex float - { - h = (f[0] == 'A') ? hexu : hex; - fv = va_arg(va, double); - if (precision == -1){ - precision = 6; // default is 6 - } - // read the double into a string - if (stbsp__real_to_parts((stbsp__int64 *)&n64, &dp, fv)){ - flags |= STBSP__NEGATIVE; - } - - s = num + 64; - - stbsp__lead_sign(flags, lead); - - if (dp == -1023){ - dp = (n64) ? -1022 : 0; - } - else{ - n64 |= (((stbsp__uint64)1) << 52); - } - n64 <<= (64 - 56); - if (precision < 15){ - n64 += ((((stbsp__uint64)8) << 56) >> (precision*4)); - } - // add leading chars - - lead[1 + lead[0]] = '0'; - lead[2 + lead[0]] = 'x'; - lead[0] += 2; - - *s++ = h[(n64 >> 60) & 15]; - n64 <<= 4; - if (precision){ - *s++ = stbsp__period; - } - sn = s; - - // print the bits - n = precision; - if (n > 13){ - n = 13; - } - if (precision > (stbsp__int32)n){ - tz = precision - n; - } - precision = 0; - while (n--) { - *s++ = h[(n64 >> 60) & 15]; - n64 <<= 4; - } - - // print the expo - tail[1] = h[17]; - if (dp < 0){ - tail[2] = '-'; - dp = -dp; - } - else{ - tail[2] = '+'; - } - n = (dp >= 1000) ? 6 : ((dp >= 100) ? 5 : ((dp >= 10) ? 4 : 3)); - tail[0] = (char)n; - for (;;) { - tail[n] = '0' + dp % 10; - if (n <= 3) break; - --n; - dp /= 10; - } - - dp = (int)(s - sn); - l = (int)(s - (num + 64)); - s = num + 64; - cs = 1 + (3 << 24); - goto scopy; - } - - case 'G': // float - case 'g': // float - { - h = (f[0] == 'G') ? hexu : hex; - fv = va_arg(va, double); - if (precision == -1){ - precision = 6; - } - else if (precision == 0){ - precision = 1; // default is 6 - } - // read the double into a string - if (stbsp__real_to_str(&sn, &l, num, &dp, fv, (precision - 1) | 0x80000000)){ - flags |= STBSP__NEGATIVE; - } - - // clamp the precision and delete extra zeros after clamp - n = precision; - if (l > (stbsp__uint32)precision){ - l = precision; - } - while ((l > 1) && (precision) && (sn[l - 1] == '0')){ - --precision; - --l; - } - - // should we use %e - if ((dp <= -4) || (dp > (stbsp__int32)n)) { - if (precision > (stbsp__int32)l){ - precision = l - 1; - } - else if (precision){ - --precision; // when using %e, there is one digit before the decimal - } - goto doexpfromg; - } - // this is the insane action to get the precision to match %g semantics for %f - if (dp > 0){ - precision = (dp < (stbsp__int32)l) ? l - dp : 0; - } - else{ - precision = -dp + ((precision > (stbsp__int32)l) ? (stbsp__int32) l : precision); - } - goto dofloatfromg; - } - - case 'E': // float - case 'e': // float - { - h = (f[0] == 'E') ? hexu : hex; - fv = va_arg(va, double); - if (precision == -1){ - precision = 6; // default is 6 - } - // read the double into a string - if (stbsp__real_to_str(&sn, &l, num, &dp, fv, precision | 0x80000000)){ - flags |= STBSP__NEGATIVE; - } - goto doexpfromg; - } - - doexpfromg: - { - tail[0] = 0; - stbsp__lead_sign(flags, lead); - if (dp == STBSP__SPECIAL) { - s = (char *)sn; - cs = 0; - precision = 0; - goto scopy; - } - s = num + 64; - // handle leading chars - *s++ = sn[0]; - - if (precision){ - *s++ = stbsp__period; - } - - // handle after decimal - if ((l - 1) > (stbsp__uint32)precision){ - l = precision + 1; - } - for (n = 1; n < l; n++){ - *s++ = sn[n]; - } - // trailing zeros - tz = precision - (l - 1); - precision = 0; - // dump expo - tail[1] = h[0xe]; - dp -= 1; - if (dp < 0){ - tail[2] = '-'; - dp = -dp; - } - else{ - tail[2] = '+'; - } - n = (dp >= 100) ? 5 : 4; - tail[0] = (char)n; - for (;;) { - tail[n] = '0' + dp % 10; - if (n <= 3) - break; - --n; - dp /= 10; - } - cs = 1 + (3 << 24); // how many tens - goto flt_lead; - } - - case 'f': // float - { - fv = va_arg(va, double); - goto doafloat; - } - - doafloat: - { - // do kilos - if (flags & STBSP__MEMORY_SIZES) { - double divisor = 1024.f; - while (flags < 0x4000000) { - if ((fv < divisor) && (fv > -divisor)) - break; - fv /= divisor; - flags += 0x1000000; - } - } - if (precision == -1){ - precision = 6; // default is 6 - } - // read the double into a string - if (stbsp__real_to_str(&sn, &l, num, &dp, fv, precision)){ - flags |= STBSP__NEGATIVE; - } - } - - dofloatfromg: - { - tail[0] = 0; - stbsp__lead_sign(flags, lead); - if (dp == STBSP__SPECIAL) { - s = (char *)sn; - cs = 0; - precision = 0; - goto scopy; - } - s = num + 64; - - // handle the three decimal varieties - if (dp <= 0) { - stbsp__int32 i; - // handle 0.000*000xxxx - *s++ = '0'; - if (precision){ - *s++ = stbsp__period; - } - n = -dp; - if ((stbsp__int32)n > precision){ - n = precision; - } - i = n; - while (i) { - if ((((stbsp__uintptr)s) & 3) == 0) - break; - *s++ = '0'; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)s = 0x30303030; - s += 4; - i -= 4; - } - while (i) { - *s++ = '0'; - --i; - } - if ((stbsp__int32)(l + n) > precision){ - l = precision - n; - } - i = l; - while (i) { - *s++ = *sn++; - --i; - } - tz = precision - (n + l); - cs = 1 + (3 << 24); // how many tens did we write (for commas below) - } - else{ - cs = (flags & STBSP__TRIPLET_COMMA) ? ((600 - (stbsp__uint32)dp) % 3) : 0; - if ((stbsp__uint32)dp >= l) { - // handle xxxx000*000.0 - n = 0; - for (;;) { - if ((flags & STBSP__TRIPLET_COMMA) && (++cs == 4)) { - cs = 0; - *s++ = stbsp__comma; - } else { - *s++ = sn[n]; - ++n; - if (n >= l) - break; - } - } - if (n < (stbsp__uint32)dp) { - n = dp - n; - if ((flags & STBSP__TRIPLET_COMMA) == 0) { - while (n) { - if ((((stbsp__uintptr)s) & 3) == 0) - break; - *s++ = '0'; - --n; - } - while (n >= 4) { - *(stbsp__uint32 *)s = 0x30303030; - s += 4; - n -= 4; - } - } - while (n) { - if ((flags & STBSP__TRIPLET_COMMA) && (++cs == 4)) { - cs = 0; - *s++ = stbsp__comma; - } else { - *s++ = '0'; - --n; - } - } - } - cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens - if (precision) { - *s++ = stbsp__period; - tz = precision; - } - } else { - // handle xxxxx.xxxx000*000 - n = 0; - for (;;) { - if ((flags & STBSP__TRIPLET_COMMA) && (++cs == 4)) { - cs = 0; - *s++ = stbsp__comma; - } else { - *s++ = sn[n]; - ++n; - if (n >= (stbsp__uint32)dp) - break; - } - } - cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens - if (precision){ - *s++ = stbsp__period; - } - if ((l - dp) > (stbsp__uint32)precision){ - l = precision + dp; - } - while (n < l) { - *s++ = sn[n]; - ++n; - } - tz = precision - (l - dp); - } - } - precision = 0; - - // handle k,m,g,t - if (flags & STBSP__MEMORY_SIZES) { - tail[0] = 0; - { - char idx = 1; - tail[idx] = ' '; - idx++; - tail[idx] = " KMGT"[flags >> 24]; - idx++; - tail[idx] = 'b'; - tail[0] = idx; - } - } - goto flt_lead; - } - - flt_lead: - { - // get the length that we copied - l = (stbsp__uint32)(s - (num + 64)); - s = num + 64; - goto scopy; - } - - case 'B': // upper binary - case 'b': // lower binary - { - h = (f[0] == 'B') ? hexu : hex; - lead[0] = 0; - if (flags & STBSP__LEADING_0X) { - lead[0] = 2; - lead[1] = '0'; - lead[2] = h[0xb]; - } - l = (8 << 4) | (1 << 8); - goto radixnum; - } - - case 'o': // octal - { - h = hexu; - lead[0] = 0; - if (flags & STBSP__LEADING_0X) { - lead[0] = 1; - lead[1] = '0'; - } - l = (3 << 4) | (3 << 8); - goto radixnum; - } - - case 'p': // pointer - { - flags |= (sizeof(void *) == 8) ? STBSP__INTMAX : 0; - precision = sizeof(void *) * 2; - flags &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros - // fall through - to X - } - - case 'X': // upper hex - case 'x': // lower hex - { - h = (f[0] == 'X') ? hexu : hex; - l = (4 << 4) | (4 << 8); - lead[0] = 0; - if (flags & STBSP__LEADING_0X) { - lead[0] = 2; - lead[1] = '0'; - lead[2] = h[16]; - } - goto radixnum; - } - - radixnum: - { - // get the number - if (flags & STBSP__INTMAX){ - n64 = va_arg(va, stbsp__uint64); - } - else{ - n64 = va_arg(va, stbsp__uint32); - } - - s = num + STBSP__NUMSZ; - dp = 0; - // clear tail, and clear leading if value is zero - tail[0] = 0; - if (n64 == 0) { - lead[0] = 0; - if (precision == 0) { - l = 0; - cs = 0; - goto scopy; - } - } - // convert to string - for (;;) { - *--s = h[n64 & ((1 << (l >> 8)) - 1)]; - n64 >>= (l >> 8); - if (!((n64) || ((stbsp__int32)((num + STBSP__NUMSZ) - s) < precision))){ - break; - } - if (flags & STBSP__TRIPLET_COMMA) { - ++l; - if ((l & 15) == ((l >> 4) & 15)) { - l &= ~15; - *--s = stbsp__comma; - } - } - }; - // get the tens and the comma pos - cs = (stbsp__uint32)((num + STBSP__NUMSZ) - s) + ((((l >> 4) & 15)) << 24); - // get the length that we copied - l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); - // copy it - goto scopy; - } - - case 'u': // unsigned - case 'i': - case 'd': // integer - { - // get the integer and abs it - if (flags & STBSP__INTMAX) { - stbsp__int64 i64 = va_arg(va, stbsp__int64); - n64 = (stbsp__uint64)i64; - if ((f[0] != 'u') && (i64 < 0)) { - n64 = (stbsp__uint64)-i64; - flags |= STBSP__NEGATIVE; - } - } else { - stbsp__int32 i = va_arg(va, stbsp__int32); - n64 = (stbsp__uint32)i; - if ((f[0] != 'u') && (i < 0)) { - n64 = (stbsp__uint32)-i; - flags |= STBSP__NEGATIVE; - } - } - - if (flags & STBSP__MEMORY_SIZES) { - if (n64 < 1024){ - precision = 0; - } - else if (precision == -1){ - precision = 1; - } - fv = (double)(stbsp__int64)n64; - goto doafloat; - } - - // convert to string - s = num + STBSP__NUMSZ; - l = 0; - - for (;;) { - // do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators) - char *o = s - 8; - if (n64 >= 100000000) { - n = (stbsp__uint32)(n64 % 100000000); - n64 /= 100000000; - } else { - n = (stbsp__uint32)n64; - n64 = 0; - } - if ((flags & STBSP__TRIPLET_COMMA) == 0) { - do { - s -= 2; - *(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; - n /= 100; - } while (n); - } - while (n) { - if ((flags & STBSP__TRIPLET_COMMA) && (l++ == 3)) { - l = 0; - *--s = stbsp__comma; - --o; - } else { - *--s = (char)(n % 10) + '0'; - n /= 10; - } - } - if (n64 == 0) { - if ((s[0] == '0') && (s != (num + STBSP__NUMSZ))){ - ++s; - } - break; - } - while (s != o){ - if ((flags & STBSP__TRIPLET_COMMA) && (l++ == 3)){ - l = 0; - *--s = stbsp__comma; - --o; - } - else{ - *--s = '0'; - } - } - } - - tail[0] = 0; - stbsp__lead_sign(flags, lead); - - // get the length that we copied - l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); - if (l == 0) { - *--s = '0'; - l = 1; - } - cs = l + (3 << 24); - if (precision < 0){ - precision = 0; - } - goto scopy; - } - - default: // unknown, just copy code - { - s = num + STBSP__NUMSZ - 1; - *s = f[0]; - l = 1; - field_width = flags = 0; - lead[0] = 0; - tail[0] = 0; - precision = 0; - dp = 0; - cs = 0; - goto scopy; - } - - scopy: - { - // get field_width=leading/trailing space, precision=leading zeros - if (precision < (stbsp__int32)l){ - precision = l; - } - n = precision + lead[0] + tail[0] + tz; - if (field_width < (stbsp__int32)n){ - field_width = n; - } - field_width -= n; - precision -= l; - - // handle right justify and leading zeros - if ((flags & STBSP__LEFTJUST) == 0){ - // if leading zeros, everything is in precision - if (flags & STBSP__LEADINGZERO){ - precision = (field_width > precision) ? field_width : precision; - field_width = 0; - } - // if no leading zeros, then no commas - else{ - flags &= ~STBSP__TRIPLET_COMMA; - } - } - - // copy the spaces and/or zeros - if (field_width + precision) { - stbsp__int32 i; - stbsp__uint32 c; - - // copy leading spaces (or when doing %8.4d stuff) - if ((flags & STBSP__LEFTJUST) == 0) - while (field_width > 0) { - stbsp__cb_buf_clamp(i, field_width); - field_width -= i; - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = ' '; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x20202020; - bf += 4; - i -= 4; - } - while (i) { - *bf++ = ' '; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy leader - sn = lead + 1; - while (lead[0]) { - stbsp__cb_buf_clamp(i, lead[0]); - lead[0] -= (char)i; - while (i) { - *bf++ = *sn++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy leading zeros - c = cs >> 24; - cs &= 0xffffff; - cs = (flags & STBSP__TRIPLET_COMMA) ? ((stbsp__uint32)(c - ((precision + cs) % (c + 1)))) : 0; - while (precision > 0) { - stbsp__cb_buf_clamp(i, precision); - precision -= i; - if ((flags & STBSP__TRIPLET_COMMA) == 0) { - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = '0'; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x30303030; - bf += 4; - i -= 4; - } - } - while (i) { - if ((flags & STBSP__TRIPLET_COMMA) && (cs++ == c)) { - cs = 0; - *bf++ = stbsp__comma; - } else - *bf++ = '0'; - --i; - } - stbsp__chk_cb_buf(1); - } - } - - // copy leader if there is still one - sn = lead + 1; - while (lead[0]) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, lead[0]); - lead[0] -= (char)i; - while (i) { - *bf++ = *sn++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy the string - n = l; - while (n) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, n); - n -= i; - STBSP__UNALIGNED(while (i >= 4) { - *(stbsp__uint32 volatile *)bf = *(stbsp__uint32 volatile *)s; - bf += 4; - s += 4; - i -= 4; - }) - while (i) { - *bf++ = *s++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy trailing zeros - while (tz) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, tz); - tz -= i; - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = '0'; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x30303030; - bf += 4; - i -= 4; - } - while (i) { - *bf++ = '0'; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy tail if there is one - sn = tail + 1; - while (tail[0]) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, tail[0]); - tail[0] -= (char)i; - while (i) { - *bf++ = *sn++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // handle the left justify - if (flags & STBSP__LEFTJUST){ - if (field_width > 0){ - while (field_width){ - stbsp__int32 i; - stbsp__cb_buf_clamp(i, field_width); - field_width -= i; - while (i){ - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = ' '; - --i; - } - while (i >= 4){ - *(stbsp__uint32 *)bf = 0x20202020; - bf += 4; - i -= 4; - } - while (i--){ - *bf++ = ' '; - } - stbsp__chk_cb_buf(1); - } - } - } - }break; - } - ++f; - } - endfmt: - - if (!callback) - *bf = 0; - else - stbsp__flush_cb(); - - done: - return tlen + (int)(bf - buf); -} - -// cleanup -#undef STBSP__LEFTJUST -#undef STBSP__LEADINGPLUS -#undef STBSP__LEADINGSPACE -#undef STBSP__LEADING_0X -#undef STBSP__LEADINGZERO -#undef STBSP__INTMAX -#undef STBSP__TRIPLET_COMMA -#undef STBSP__NEGATIVE -#undef STBSP__METRIC_SUFFIX -#undef STBSP__NUMSZ -#undef stbsp__chk_cb_bufL -#undef stbsp__chk_cb_buf -#undef stbsp__flush_cb -#undef stbsp__cb_buf_clamp - -// ============================================================================ -// wrapper functions - -STBSP__PUBLICDEF int m4_sprintf(char *buf, char const *fmt, ...) -{ - int result; - va_list va; - va_start(va, fmt); - result = m4_vsprintfcb(0, 0, buf, fmt, va); - va_end(va); - return result; -} - -typedef struct stbsp__context { - char *buf; - int count; - int length; - char tmp[STB_SPRINTF_MIN]; -} stbsp__context; - -static char *stbsp__clamp_callback(const char *buf, void *user, int len) -{ - stbsp__context *c = (stbsp__context *)user; - c->length += len; - - if (len > c->count) - len = c->count; - - if (len) { - if (buf != c->buf) { - const char *s, *se; - char *d; - d = c->buf; - s = buf; - se = buf + len; - do { - *d++ = *s++; - } while (s < se); - } - c->buf += len; - c->count -= len; - } - - if (c->count <= 0) - return c->tmp; - return (c->count >= STB_SPRINTF_MIN) ? c->buf : c->tmp; // go direct into buffer if you can -} - -static char * stbsp__count_clamp_callback( const char * buf, void * user, int len ) -{ - stbsp__context * c = (stbsp__context*)user; - (void) sizeof(buf); - - c->length += len; - return c->tmp; // go direct into buffer if you can -} - -STBSP__PUBLICDEF int m4_vsnprintf( char * buf, int count, char const * fmt, va_list va ) -{ - stbsp__context c; - - if ( (count == 0) && !buf ) - { - c.length = 0; - - m4_vsprintfcb( stbsp__count_clamp_callback, &c, c.tmp, fmt, va ); - } - else - { - int l; - - c.buf = buf; - c.count = count; - c.length = 0; - - m4_vsprintfcb( stbsp__clamp_callback, &c, stbsp__clamp_callback(0,&c,0), fmt, va ); - - // zero-terminate - l = (int)( c.buf - buf ); - if ( l >= count ) // should never be greater, only equal (or less) than count - l = count - 1; - buf[l] = 0; - } - - return c.length; -} - -STBSP__PUBLICDEF int m4_snprintf(char *buf, int count, char const *fmt, ...) -{ - int result; - va_list va; - va_start(va, fmt); - - result = m4_vsnprintf(buf, count, fmt, va); - va_end(va); - - return result; -} - -STBSP__PUBLICDEF int m4_vsprintf(char *buf, char const *fmt, va_list va) -{ - return m4_vsprintfcb(0, 0, buf, fmt, va); -} - -// ======================================================================= -// low level float utility functions - -// copies d to bits w/ strict aliasing (this compiles to nothing on /Ox) -#define STBSP__COPYFP(dest, src) \ -{ \ -int cn; \ -for (cn = 0; cn < 8; cn++) \ -((char *)&dest)[cn] = ((char *)&src)[cn]; \ -} - -// get float info -static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value) -{ - double d; - stbsp__int64 b = 0; - - // load value and round at the frac_digits - d = value; - - STBSP__COPYFP(b, d); - - *bits = b & ((((stbsp__uint64)1) << 52) - 1); - *expo = (stbsp__int32)(((b >> 52) & 2047) - 1023); - - return (stbsp__int32)((stbsp__uint64) b >> 63); -} - -static double const stbsp__bot[23] = { - 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011, - 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022 -}; -static double const stbsp__negbot[22] = { - 1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011, - 1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022 -}; -static double const stbsp__negboterr[22] = { - -5.551115123125783e-018, -2.0816681711721684e-019, -2.0816681711721686e-020, -4.7921736023859299e-021, -8.1803053914031305e-022, 4.5251888174113741e-023, - 4.5251888174113739e-024, -2.0922560830128471e-025, -6.2281591457779853e-026, -3.6432197315497743e-027, 6.0503030718060191e-028, 2.0113352370744385e-029, - -3.0373745563400371e-030, 1.1806906454401013e-032, -7.7705399876661076e-032, 2.0902213275965398e-033, -7.1542424054621921e-034, -7.1542424054621926e-035, - 2.4754073164739869e-036, 5.4846728545790429e-037, 9.2462547772103625e-038, -4.8596774326570872e-039 -}; -static double const stbsp__top[13] = { - 1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207, 1e+230, 1e+253, 1e+276, 1e+299 -}; -static double const stbsp__negtop[13] = { - 1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207, 1e-230, 1e-253, 1e-276, 1e-299 -}; -static double const stbsp__toperr[13] = { - 8388608, - 6.8601809640529717e+028, - -7.253143638152921e+052, - -4.3377296974619174e+075, - -1.5559416129466825e+098, - -3.2841562489204913e+121, - -3.7745893248228135e+144, - -1.7356668416969134e+167, - -3.8893577551088374e+190, - -9.9566444326005119e+213, - 6.3641293062232429e+236, - -5.2069140800249813e+259, - -5.2504760255204387e+282 -}; -static double const stbsp__negtoperr[13] = { - 3.9565301985100693e-040, -2.299904345391321e-063, 3.6506201437945798e-086, 1.1875228833981544e-109, - -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178, -5.7778912386589953e-201, - 7.4997100559334532e-224, -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293, - 8.0970921678014997e-317 -}; - -#if defined(_MSC_VER) && (_MSC_VER <= 1200) -static stbsp__uint64 const stbsp__powten[20] = { - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000, - 100000000000, - 1000000000000, - 10000000000000, - 100000000000000, - 1000000000000000, - 10000000000000000, - 100000000000000000, - 1000000000000000000, - 10000000000000000000U -}; -#define stbsp__tento19th ((stbsp__uint64)1000000000000000000) -#else -static stbsp__uint64 const stbsp__powten[20] = { - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000ULL, - 100000000000ULL, - 1000000000000ULL, - 10000000000000ULL, - 100000000000000ULL, - 1000000000000000ULL, - 10000000000000000ULL, - 100000000000000000ULL, - 1000000000000000000ULL, - 10000000000000000000ULL -}; -#define stbsp__tento19th (1000000000000000000ULL) -#endif - -#define stbsp__ddmulthi(oh, ol, xh, yh) \ -{ \ -double ahi = 0, alo, bhi = 0, blo; \ -stbsp__int64 bt; \ -oh = xh * yh; \ -STBSP__COPYFP(bt, xh); \ -bt &= ((~(stbsp__uint64)0) << 27); \ -STBSP__COPYFP(ahi, bt); \ -alo = xh - ahi; \ -STBSP__COPYFP(bt, yh); \ -bt &= ((~(stbsp__uint64)0) << 27); \ -STBSP__COPYFP(bhi, bt); \ -blo = yh - bhi; \ -ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo; \ -} - -#define stbsp__ddtoS64(ob, xh, xl) \ -{ \ -double ahi = 0, alo, vh, t; \ -ob = (stbsp__int64)xh; \ -vh = (double)ob; \ -ahi = (xh - vh); \ -t = (ahi - xh); \ -alo = (xh - (ahi - t)) - (vh + t); \ -ob += (stbsp__int64)(ahi + alo + xl); \ -} - -#define stbsp__ddrenorm(oh, ol) \ -{ \ -double s; \ -s = oh + ol; \ -ol = ol - (s - oh); \ -oh = s; \ -} - -#define stbsp__ddmultlo(oh, ol, xh, xl, yh, yl) ol = ol + (xh * yl + xl * yh); - -#define stbsp__ddmultlos(oh, ol, xh, yl) ol = ol + (xh * yl); - -static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__int32 power) // power can be -323 to +350 -{ - double ph, pl; - if ((power >= 0) && (power <= 22)) { - stbsp__ddmulthi(ph, pl, d, stbsp__bot[power]); - } else { - stbsp__int32 e, et, eb; - double p2h, p2l; - - e = power; - if (power < 0) - e = -e; - et = (e * 0x2c9) >> 14; /* %23 */ - if (et > 13) - et = 13; - eb = e - (et * 23); - - ph = d; - pl = 0.0; - if (power < 0) { - if (eb) { - --eb; - stbsp__ddmulthi(ph, pl, d, stbsp__negbot[eb]); - stbsp__ddmultlos(ph, pl, d, stbsp__negboterr[eb]); - } - if (et) { - stbsp__ddrenorm(ph, pl); - --et; - stbsp__ddmulthi(p2h, p2l, ph, stbsp__negtop[et]); - stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__negtop[et], stbsp__negtoperr[et]); - ph = p2h; - pl = p2l; - } - } else { - if (eb) { - e = eb; - if (eb > 22) - eb = 22; - e -= eb; - stbsp__ddmulthi(ph, pl, d, stbsp__bot[eb]); - if (e) { - stbsp__ddrenorm(ph, pl); - stbsp__ddmulthi(p2h, p2l, ph, stbsp__bot[e]); - stbsp__ddmultlos(p2h, p2l, stbsp__bot[e], pl); - ph = p2h; - pl = p2l; - } - } - if (et) { - stbsp__ddrenorm(ph, pl); - --et; - stbsp__ddmulthi(p2h, p2l, ph, stbsp__top[et]); - stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__top[et], stbsp__toperr[et]); - ph = p2h; - pl = p2l; - } - } - } - stbsp__ddrenorm(ph, pl); - *ohi = ph; - *olo = pl; -} - -// given a float value, returns the significant bits in bits, and the position of the -// decimal point in decimal_pos. +/-INF and NAN are specified by special values -// returned in the decimal_pos parameter. -// frac_digits is absolute normally, but if you want from first significant digits (got %g and %e), or in 0x80000000 -static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits) -{ - double d; - stbsp__int64 bits = 0; - stbsp__int32 expo, e, ng, tens; - - d = value; - STBSP__COPYFP(bits, d); - expo = (stbsp__int32)((bits >> 52) & 2047); - ng = (stbsp__int32)((stbsp__uint64) bits >> 63); - if (ng) - d = -d; - - if (expo == 2047) // is nan or inf? - { - *start = (bits & ((((stbsp__uint64)1) << 52) - 1)) ? "NaN" : "Inf"; - *decimal_pos = STBSP__SPECIAL; - *len = 3; - return ng; - } - - if (expo == 0) // is zero or denormal - { - if (((stbsp__uint64) bits << 1) == 0) // do zero - { - *decimal_pos = 1; - *start = out; - out[0] = '0'; - *len = 1; - return ng; - } - // find the right expo for denormals - { - stbsp__int64 v = ((stbsp__uint64)1) << 51; - while ((bits & v) == 0) { - --expo; - v >>= 1; - } - } - } - - // find the decimal exponent as well as the decimal bits of the value - { - double ph, pl; - - // log10 estimate - very specifically tweaked to hit or undershoot by no more than 1 of log10 of all expos 1..2046 - tens = expo - 1023; - tens = (tens < 0) ? ((tens * 617) / 2048) : (((tens * 1233) / 4096) + 1); - - // move the significant bits into position and stick them into an int - stbsp__raise_to_power10(&ph, &pl, d, 18 - tens); - - // get full as much precision from double-double as possible - stbsp__ddtoS64(bits, ph, pl); - - // check if we undershot - if (((stbsp__uint64)bits) >= stbsp__tento19th) - ++tens; - } - - // now do the rounding in integer land - frac_digits = (frac_digits & 0x80000000) ? ((frac_digits & 0x7ffffff) + 1) : (tens + frac_digits); - if ((frac_digits < 24)) { - stbsp__uint32 dg = 1; - if ((stbsp__uint64)bits >= stbsp__powten[9]) - dg = 10; - while ((stbsp__uint64)bits >= stbsp__powten[dg]) { - ++dg; - if (dg == 20) - goto noround; - } - if (frac_digits < dg) { - stbsp__uint64 r; - // add 0.5 at the right position and round - e = dg - frac_digits; - if ((stbsp__uint32)e >= 24) - goto noround; - r = stbsp__powten[e]; - bits = bits + (r / 2); - if ((stbsp__uint64)bits >= stbsp__powten[dg]) - ++tens; - bits /= r; - } - noround:; - } - - // kill long trailing runs of zeros - if (bits) { - stbsp__uint32 n; - for (;;) { - if (bits <= 0xffffffff) - break; - if (bits % 1000) - goto donez; - bits /= 1000; - } - n = (stbsp__uint32)bits; - while ((n % 1000) == 0) - n /= 1000; - bits = n; - donez:; - } - - // convert to string - out += 64; - e = 0; - for (;;) { - stbsp__uint32 n; - char *o = out - 8; - // do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned) - if (bits >= 100000000) { - n = (stbsp__uint32)(bits % 100000000); - bits /= 100000000; - } else { - n = (stbsp__uint32)bits; - bits = 0; - } - while (n) { - out -= 2; - *(stbsp__uint16 *)out = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; - n /= 100; - e += 2; - } - if (bits == 0) { - if ((e) && (out[0] == '0')) { - ++out; - --e; - } - break; - } - while (out != o) { - *--out = '0'; - ++e; - } - } - - *decimal_pos = tens; - *start = out; - *len = e; - return ng; -} - -#undef stbsp__ddmulthi -#undef stbsp__ddrenorm -#undef stbsp__ddmultlo -#undef stbsp__ddmultlos -#undef STBSP__SPECIAL -#undef STBSP__COPYFP - -// clean up -#undef stbsp__uint16 -#undef stbsp__uint32 -#undef stbsp__int32 -#undef stbsp__uint64 -#undef stbsp__int64 -#undef STBSP__UNALIGNED - diff --git a/mr4th/mr4th_base.h b/mr4th/mr4th_base.h deleted file mode 100644 index 0601620..0000000 --- a/mr4th/mr4th_base.h +++ /dev/null @@ -1,1891 +0,0 @@ -/* -** -** TODO: instructions will go here -** -*/ - -#if !defined(MR4TH_BASE_H) -#define MR4TH_BASE_H 1 - -//////////////////////////////////////////////// -//////////////////////////////////////////////// -////////////////// MACROS ////////////////// -//////////////////////////////////////////////// -//////////////////////////////////////////////// - -//////////////////////////////// -// Build Mode Defaults & Checks - -#if !defined(MR4TH_DISABLE_UNITY_BUILD) -# define MR4TH_DISABLE_UNITY_BUILD 0 -#endif -#if !defined(MR4TH_CORE_MODE) -# define MR4TH_CORE_MODE 0 -#endif -#if !defined(MR4TH_PLUGIN_MODE) -# define MR4TH_PLUGIN_MODE 0 -#endif -#if !defined(MR4TH_STANDALONE_MODE) -# define MR4TH_STANDALONE_MODE 0 -#endif -#if !defined(MR4TH_PROFILING_PROVIDER) -# define MR4TH_PROFILING_PROVIDER 0 -#endif - -#if !MR4TH_CORE_MODE && !MR4TH_PLUGIN_MODE && !MR4TH_STANDALONE_MODE -# undef MR4TH_STANDALONE_MODE -# define MR4TH_STANDALONE_MODE 1 -#endif - -#if (MR4TH_CORE_MODE && MR4TH_PLUGIN_MODE) -# error conflicing mr4th build mode -#endif -#if (MR4TH_CORE_MODE && MR4TH_STANDALONE_MODE) -# error conflicing mr4th build mode -#endif -#if (MR4TH_PLUGIN_MODE && MR4TH_STANDALONE_MODE) -# error conflicing mr4th build mode -#endif - -//////////////////////////////// -// Context Cracking - -// development settings -#if !defined(MR4TH_ASSERTS) -# define MR4TH_ASSERTS 0 -#endif -#if !defined(MR4TH_SANITIZER) -# define MR4TH_SANITIZER 0 -#endif -#if !defined(MR4TH_PROFILING_MANUAL) -# define MR4TH_PROFILING_MANUAL 0 -#endif -#if !defined(MR4TH_PROFILING_AUTO) -# define MR4TH_PROFILING_AUTO 0 -#endif - -#if defined(MR4TH_PROFILING_USER) -# error the user should not set MR4TH_PROFILING_USER, instead set MR4TH_PROFILING_MANUAL or MR4TH_PROFILING_AUTO -#endif - -#if MR4TH_PROFILING_MANUAL || MR4TH_PROFILING_AUTO -# define MR4TH_PROFILING_USER 1 -#else -# define MR4TH_PROFILING_USER 0 -#endif - -// untangle compiler, os, & architecture -#if defined(__clang__) -# define COMPILER_CLANG 1 - -# if defined(_WIN32) -# define OS_WINDOWS 1 -# elif defined(__gnu_linux__) -# define OS_LINUX 1 -# elif defined(__APPLE__) && defined(__MACH__) -# define OS_MAC 1 -# else -# error missing OS detection -# endif - -# if defined(__amd64__) -# define ARCH_X64 1 -// TODO(allen): verify this works on clang -# elif defined(__i386__) -# define ARCH_X86 1 -// TODO(allen): verify this works on clang -# elif defined(__arm__) -# define ARCH_ARM 1 -// TODO(allen): verify this works on clang -# elif defined(__aarch64__) -# define ARCH_ARM64 1 -# else -# error missing ARCH detection -# endif - -#elif defined(_MSC_VER) -# define COMPILER_CL 1 - -# if defined(_WIN32) -# define OS_WINDOWS 1 -# else -# error missing OS detection -# endif - -# if defined(_M_AMD64) -# define ARCH_X64 1 -# elif defined(_M_I86) -# define ARCH_X86 1 -# elif defined(_M_ARM) -# define ARCH_ARM 1 -// TODO(allen): ARM64? -# else -# error missing ARCH detection -# endif - -#elif defined(__GNUC__) -# define COMPILER_GCC 1 - -# if defined(_WIN32) -# define OS_WINDOWS 1 -# elif defined(__gnu_linux__) -# define OS_LINUX 1 -# elif defined(__APPLE__) && defined(__MACH__) -# define OS_MAC 1 -# else -# error missing OS detection -# endif - -# if defined(__amd64__) -# define ARCH_X64 1 -# elif defined(__i386__) -# define ARCH_X86 1 -# elif defined(__arm__) -# define ARCH_ARM 1 -# elif defined(__aarch64__) -# define ARCH_ARM64 1 -# else -# error missing ARCH detection -# endif - -#else -# error no context cracking for this compiler -#endif - -#if !defined(COMPILER_CL) -# define COMPILER_CL 0 -#endif -#if !defined(COMPILER_CLANG) -# define COMPILER_CLANG 0 -#endif -#if !defined(COMPILER_GCC) -# define COMPILER_GCC 0 -#endif -#if !defined(OS_WINDOWS) -# define OS_WINDOWS 0 -#endif -#if !defined(OS_LINUX) -# define OS_LINUX 0 -#endif -#if !defined(OS_MAC) -# define OS_MAC 0 -#endif -#if !defined(ARCH_X64) -# define ARCH_X64 0 -#endif -#if !defined(ARCH_X86) -# define ARCH_X86 0 -#endif -#if !defined(ARCH_ARM) -# define ARCH_ARM 0 -#endif -#if !defined(ARCH_ARM64) -# define ARCH_ARM64 0 -#endif - - -// language -#if defined(__cplusplus) -# define LANG_CXX 1 -#else -# define LANG_C 1 -#endif - -#if !defined(LANG_CXX) -# define LANG_CXX 0 -#endif -#if !defined(LANG_C) -# define LANG_C 0 -#endif - - -// language version: C -#if LANG_C -# if !defined(__STDC_VERSION__) -# define LANGVER_C90 1 -# elif (__STDC_VERSION__ == 199901) -# define LANGVER_C99 1 -# elif (__STDC_VERSION__ == 201112) -# define LANGVER_C11 1 -# elif (__STDC_VERSION__ == 201710) -# define LANGVER_C17 1 -# elif (__STDC_VERSION__ == 202000) -# define LANGVER_C23 1 -# else -# error unrecorgnized C version -# endif -#endif - -#if !defined(LANGVER_C90) -# define LANGVER_C90 0 -#endif -#if !defined(LANGVER_C99) -# define LANGVER_C99 0 -#endif -#if !defined(LANGVER_C11) -# define LANGVER_C11 0 -#endif -#if !defined(LANGVER_C17) -# define LANGVER_C17 0 -#endif -#if !defined(LANGVER_C23) -# define LANGVER_C23 0 -#endif - - -// language version: C++ -#if LANG_CXX -# if (__cplusplus == 199711) -# define LANGVER_CXX98 1 -# elif (__cplusplus == 201103) -# define LANGVER_CXX11 1 -# elif (__cplusplus == 201402) -# define LANGVER_CXX14 1 -# elif (__cplusplus == 201703) -# define LANGVER_CXX17 1 -# elif (__cplusplus == 202002) -# define LANGVER_CXX20 1 -# elif (__cplusplus == 202302) -# define LANGVER_CXX23 1 -# else -# error unrecorgnized C++ version -# endif -#endif - -#if !defined(LANGVER_CXX98) -# define LANGVER_CXX98 0 -#endif -#if !defined(LANGVER_CXX11) -# define LANGVER_CXX11 0 -#endif -#if !defined(LANGVER_CXX14) -# define LANGVER_CXX14 0 -#endif -#if !defined(LANGVER_CXX17) -# define LANGVER_CXX17 0 -#endif -#if !defined(LANGVER_CXX20) -# define LANGVER_CXX20 0 -#endif -#if !defined(LANGVER_CXX23) -# define LANGVER_CXX23 0 -#endif - -// determine intrinsics mode -#if OS_WINDOWS -# if COMPILER_CL || COMPILER_CLANG -# define INTRINSICS_MICROSOFT 1 -# endif -#endif -#if OS_LINUX -# if COMPILER_CLANG || COMPILER_GCC -# define INTRINSICS_BUILT_IN 1 -# endif -#endif - -#if !defined(INTRINSICS_MICROSOFT) -# define INTRINSICS_MICROSOFT 0 -#endif -#if !defined(INTRINSICS_BUILT_IN) -# define INTRINSICS_BUILT_IN 0 -#endif - -// setup pointer size macro -#if ARCH_X64 || ARCH_ARM64 -# define ARCH_ADDRSIZE 64 -#else -# define ARCH_ADDRSIZE 32 -#endif - - -#define ARCH_LITTLE_ENDIAN 1 -#define ARCH_BIG_ENDIAN 0 - -// TODO(allen): target image format - -//////////////////////////////// -// Macros: Symbol Markers - -// linkage, storage, & other "attribute" like things - -#define MR4TH_SYMBOL_STATIC static - -#if LANG_CXX -# define MR4TH_SYMBOL_LINK extern "C" -#else -# define MR4TH_SYMBOL_LINK extern -#endif - -#if OS_WINDOWS -# define MR4TH_SYMBOL_EXPORT __declspec(dllexport) -#elif OS_LINUX || OS_MAC -# define MR4TH_SYMBOL_EXPORT __attribute__((visibility("default"))) -#else -# error MR4TH_SYMBOL_EXPORT not defined for this OS -#endif - -#if OS_WINDOWS -# define MR4TH_SYM_IMPORT __declspec(dllimport) -#elif OS_LINUX || OS_MAC -# define MR4TH_SYM_IMPORT -#else -# error MR4TH_SYMBOL_IMPORT not defined for this OS -#endif - -#if COMPILER_CL -# define MR4TH_THREADVAR __declspec(thread) -#elif COMPILER_CLANG || COMPILER_GCC -# define MR4TH_THREADVAR __thread -#else -# error MR4TH_THREADVAR not defined for this compiler -#endif - -#if COMPILER_CLANG || COMPILER_GCC -# if OS_MAC -# define MR4TH_SEC_R(N) __attribute__((__section__("__TEXT,"N))) -# define MR4TH_SEC_RW(N) __attribute__((__section__("__READ,"N))) -# else -# define MR4TH_SEC_R(N) __attribute__((__section__(N))) -# define MR4TH_SEC_RW(N) __attribute__((__section__(N))) -# endif -#elif COMPILER_CL -# define MR4TH_SEC_R(N) __declspec(allocate(N)) -# define MR4TH_SEC_RW(N) __declspec(allocate(N)) -#else -# error MR4TH_SEC_R/MR4TH_SEC_RW not defined for this compiler/OS -#endif - -#if COMPILER_CLANG || COMPILER_GCC -#if OS_WINDOWS -# define MR4TH_READ_ONLY MR4TH_SEC_R(".rdata") const -#else -# define MR4TH_READ_ONLY MR4TH_SEC_R(".rodata") const -#endif -#elif COMPILER_CL -# pragma section(".m4rdata",read) -# define MR4TH_READ_ONLY MR4TH_SEC_R(".m4rdata") const -#else -# define MR4TH_READ_ONLY -# error MR4TH_READ_ONLY not defined for this compiler -#endif - -// symbol kinds - -#if MR4TH_DISABLE_UNITY_BUILD -# define MR4TH_SYMBOL MR4TH_SYMBOL_LINK -#else -# define MR4TH_SYMBOL MR4TH_SYMBOL_STATIC -#endif - -#if MR4TH_CORE_MODE -# define MR4TH_SYMBOL_MUST_SHARE MR4TH_SYMBOL_EXPORT -#elif MR4TH_PLUGIN_MODE -# define MR4TH_SYMBOL_MUST_SHARE MR4TH_SYMBOL_IMPORT -#else -# define MR4TH_SYMBOL_MUST_SHARE MR4TH_SYMBOL -#endif - -// align-as - -#if COMPILER_CL -# define MR4TH_ALIGN_AS_LIT(n) __declspec(align(n)) -#elif COMPILER_CLANG || COMPILER_GCC -# define MR4TH_ALIGN_AS_LIT(n) __attribute__(( __aligned__(n) )) -#else -# error MR4TH_ALIGN_AS_LIT not defined for this compiler -#endif - -// do-not-eliminate - -#if OS_WINDOWS - -# define MR4TH_DO_NOT_ELIMINATE__S0(N) __pragma(comment(linker,"/include:" #N)) -# define MR4TH_DO_NOT_ELIMINATE__S1(N) MR4TH_DO_NOT_ELIMINATE__S0(N) -# define MR4TH_DO_NOT_ELIMINATE(N) MR4TH_DO_NOT_ELIMINATE__S1(N) - -#else - -# define MR4TH_DO_NOT_ELIMINATE(N) - -#endif - -// before-main abstraction - -#if OS_WINDOWS - -# pragma section(".CRT$XCU", read) - -# if LANG_CXX - -# define MR4TH_BEFORE_MAIN_(n) \ -static void n(void); \ -__declspec(allocate(".CRT$XCU")) \ -__pragma(comment(linker,"/include:" #n "__")) \ -extern "C" void (*n##__)(void); \ -void (*n##__)(void) = n; \ -static void n(void) - -# else - -# define MR4TH_BEFORE_MAIN_(n) \ -static void n(void); \ -__declspec(allocate(".CRT$XCU")) \ -__pragma(comment(linker,"/include:" #n "__")) \ -void (*n##__)(void) = n; \ -static void n(void) - -# endif - -# define MR4TH_BEFORE_MAIN(n) MR4TH_BEFORE_MAIN_(n) - -#elif OS_LINUX - -# define MR4TH_BEFORE_MAIN(n) \ -__attribute__((constructor)) static void n(void) - -#else -# error MR4TH_BEFORE_MAIN missing for this OS -#endif - -// sanitizer - -#if COMPILER_CLANG && MR4TH_SANITIZER -# include -#endif - -#if MR4TH_SANITIZER -# define AsanPoison(p,z) __asan_poison_memory_region((p),(z)) -# define AsanUnpoison(p,z) __asan_unpoison_memory_region((p),(z)) -#else -# define AsanPoison(p,z) -# define AsanUnpoison(p,z) -#endif - - -//////////////////////////////// -// Macros: Common Expressions - -// macro writing utilities - -#define Stmnt(S) do{ S }while(0) - -#define Stringify_(S) #S -#define Stringify(S) Stringify_(S) -#define Glue_(A,B) A##B -#define Glue(A,B) Glue_(A,B) - -// assert - -#if !defined(AssertBreak) -# define AssertBreak() (*(volatile int*)0 = 0) -#endif - -#if MR4TH_ASSERTS -# define Assert(c) Stmnt( if (!(c)){ AssertBreak(); } ) -#else -# define Assert(c) -#endif - -#define StaticAssert(c,l) typedef U8 Glue(l,__LINE__) [(c)?1:-1] - -// memory operations - -#define MemoryZero(p,z) memory_zero((p), (z)) -#define MemoryZeroStruct(p) MemoryZero((p), sizeof(*(p))) -#define MemoryZeroArray(p) MemoryZero((p), sizeof(p)) -#define MemoryZeroRange(f,o) MemoryZero((f), (U8*)(o) - (U8*)(f)) - -#define MemoryMatch(a,b,z) (memory_match((a),(b),(z))) - -#define MemoryCopy(d,s,z) memory_move((d), (s), (z)) -#define MemoryCopyStruct(d,s) MemoryCopy((d),(s),Min(sizeof(*(d)),sizeof(*(s)))) -#define MemoryCopyArray(d,s) MemoryCopy((d),(s),Min(sizeof(s),sizeof(d))) - -// misc expressions - -#define ArrayCount(a) (sizeof(a)/sizeof(*(a))) - -#define IntFromPtr(p) (UAddr)(p) -#define PtrFromInt(n) (void*)((UAddr)(n)) -#define PtrDif(a,b) ((U8*)(a) - (U8*)(b)) - -#define Member(T,m) (((T*)0)->m) -#define AddrOfMember(T,m) (void*)(&Member(T,m)) -#define OffsetOfMember(T,m) IntFromPtr(&Member(T,m)) -#define OffsetOfMemberV(s,m) PtrDif(&s->m, s) -#define MemberAddr(T,m) AddrOfMember(T,m) -#define MemberOff(T,m) OffsetOfMember(T,m) - -#define Min(a,b) (((a)<(b))?(a):(b)) -#define Max(a,b) (((a)>(b))?(a):(b)) -#define Clamp(a,x,b) (((x)<(a))?(a):((b)<(x))?(b):(x)) -#define ClampTop(a,b) Min(a,b) -#define ClampBot(a,b) Max(a,b) - -#define Swap(T,a,b) Stmnt( T t_ = (a); (a) = (b); (b) = t_; ) - -#define SignedIntFromCompare(a,b) (S32)( ((b)<(a)) - ((a)<(b)) ) - -#define AlignUpPow2(x,p) (((x) + (p) - 1)&~((p) - 1)) -#define AlignDownPow2(x,p) ((x)&~((p) - 1)) -#define IsPow2OrZero(x) (((x)&((x)-1)) == 0) - -#define CeilIntDiv(n,d) (((n) + (d) - 1)/(d)) - -#define KB(x) ((U64)(x) << 10llu) -#define MB(x) ((U64)(x) << 20llu) -#define GB(x) ((U64)(x) << 30llu) -#define TB(x) ((U64)(x) << 40llu) - -#define Thousand(x) ((x)*1000llu) -#define Million(x) ((x)*1000000llu) -#define Billion(x) ((x)*1000000000llu) -#define Trillion(x) ((x)*1000000000000llu) - -#define AsciiID4(a,b,c,d) (((d) << 24) | ((c) << 16) | ((b) << 8) | (a)) - -#if LANG_CXX -# define CLiteral(T) T -#else -# define CLiteral(T) (T) -#endif - -//////////////////////////////// -// Macros: Linked Lists - -#define DLLPushBack_NPZ(f,l,n,next,prev,nil)\ -(((f) == (nil))?\ -((f)=(l)=(n),(n)->next=(n)->prev=(nil)):\ -((n)->prev=(l),(l)->next=(n),(l)=(n),(n)->next=(nil))) - -#define DLLPushBack(f,l,n) DLLPushBack_NPZ(f,l,n,next,prev,0) -#define DLLPushFront(f,l,n) DLLPushBack_NPZ(l,f,n,prev,next,0) - -#define DLLInsert_NPZ(f,l,p,n,next,prev,nil) \ -(((p) != (l))?\ -((n)->next = (p)->next,\ -(n)->prev = (p),\ -(p)->next->prev = (n),\ -(p)->next = (n))\ -:((n)->next = (nil),\ -(n)->prev = (l),\ -(l)->next = (n),\ -(l) = (n))) - -#define DLLInsert(f,l,p,n) DLLInsert_NPZ(f,l,p,n,next,prev,0) - -#define DLLRemove_NPZ(f,l,n,next,prev,nil)\ -((f)==(n)?\ -((f)==(l)?\ -((f)=(l)=(nil)):\ -((f)=(f)->next,(f)->prev=(nil))):\ -(l)==(n)?\ -((l)=(l)->prev,(l)->next=(nil)):\ -((n)->next->prev=(n)->prev,\ -(n)->prev->next=(n)->next)) - -#define DLLRemove(f,l,n) DLLRemove_NPZ(f,l,n,next,prev,0) - -#define SLLQueuePush_NZ(f,l,n,next,nil) (((f)==(nil)?\ -(f)=(l)=(n):\ -((l)->next=(n),(l)=(n))),\ -(n)->next=(nil)) -#define SLLQueuePush(f,l,n) SLLQueuePush_NZ(f,l,n,next,0) - -#define SLLQueuePushFront_NZ(f,l,n,next,nil) ((f)==(nil)?\ -((f)=(l)=(n),(n)->next=(nil)):\ -((n)->next=(f),(f)=(n))) -#define SLLQueuePushFront(f,l,n) SLLQueuePushFront_NZ(f,l,n,next,0) - -#define SLLQueuePop_NZ(f,l,next,nil) ((f)==(l)?\ -(f)=(l)=(nil):\ -((f)=(f)->next)) -#define SLLQueuePop(f,l) SLLQueuePop_NZ(f,l,next,0) - -#define SLLStackPush_N(f,n,next) ((n)->next=(f),(f)=(n)) -#define SLLStackPush(f,n) SLLStackPush_N(f,n,next) - -#define SLLStackPop_NZ(f,next,nil) ((f)==(nil)?(nil):\ -((f)=(f)->next)) -#define SLLStackPop(f) SLLStackPop_NZ(f,next,0) - - -//////////////////////////////////////////////// -//////////////////////////////////////////////// -////////////////// TYPES /////////////////// -//////////////////////////////////////////////// -//////////////////////////////////////////////// - -//////////////////////////////// -// Types: Basic - -#include -#include -#include - -typedef int8_t S8; -typedef int16_t S16; -typedef int32_t S32; -typedef int64_t S64; -typedef uint8_t U8; -typedef uint16_t U16; -typedef uint32_t U32; -typedef uint64_t U64; -typedef S8 B8; -typedef S16 B16; -typedef S32 B32; -typedef S64 B64; -typedef float F32; -typedef double F64; - -#if ARCH_ADDRSIZE == 32 -typedef U32 UAddr; -typedef S32 SAddr; -#elif ARCH_ADDRSIZE == 64 -typedef U64 UAddr; -typedef S64 SAddr; -#else -# error UAddr and SAddr not defined for this architecture -#endif - -typedef void VoidFunc(void); - -//////////////////////////////// -// Types: Symbolic Constants - -typedef enum Axis{ - Axis_X = 0, - Axis_Y = 1, - Axis_Z = 2, - Axis_W = 3 -} Axis; - -typedef enum Side{ - Side_Min = 0, - Side_Max = 1 -} Side; - -typedef enum OperatingSystem{ - OperatingSystem_Null = 0, - OperatingSystem_Windows = 1, - OperatingSystem_Linux = 2, - OperatingSystem_Mac = 3, - OperatingSystem_COUNT -} OperatingSystem; - -typedef enum Architecture{ - Architecture_Null = 0, - Architecture_X64 = 1, - Architecture_X86 = 2, - Architecture_Arm = 3, - Architecture_Arm64 = 4, - Architecture_COUNT -} Architecture; - -typedef enum Month{ - Month_Jan = 1, - Month_Feb = 2, - Month_Mar = 3, - Month_Apr = 4, - Month_May = 5, - Month_Jun = 6, - Month_Jul = 7, - Month_Aug = 8, - Month_Sep = 9, - Month_Oct = 10, - Month_Nov = 11, - Month_Dec = 12, -} Month; - -typedef enum DayOfWeek{ - DayOfWeek_Sunday = 0, - DayOfWeek_Monday = 1, - DayOfWeek_Tuesday = 2, - DayOfWeek_Wednesday = 3, - DayOfWeek_Thursday = 4, - DayOfWeek_Friday = 5, - DayOfWeek_Saturday = 6 -} DayOfWeek; - -typedef U32 DataAccessFlags; -enum{ - DataAccessFlag_Read = (1 << 0), - DataAccessFlag_Write = (1 << 1), - DataAccessFlag_Execute = (1 << 2), -}; - -//////////////////////////////// -// Types: Compound Types - -typedef struct V2F32{ - F32 x; - F32 y; -} V2F32; - -typedef struct V3F32{ - F32 x; - F32 y; - F32 z; -} V3F32; - -typedef struct V4F32{ - F32 x; - F32 y; - F32 z; - F32 w; -} V4F32; - -typedef struct RangeF32{ - F32 min; - F32 max; -} RangeF32; - -typedef struct RectF32{ - union{ - struct{ - F32 x0; - F32 y0; - F32 x1; - F32 y1; - }; - struct{ - V2F32 p0; - V2F32 p1; - }; - }; -} RectF32; - -//////////////////////////////// -// Types: Time - -typedef U64 DenseTime; - -typedef struct DateTime{ - U16 msec; // [0,999] - U8 sec; // [0,60] - U8 min; // [0,59] - U8 hour; // [0,23] - U8 day; // [1,31] - U8 mon; // [1,12] - S16 year; // 1 = 1 CE; 2020 = 2020 CE; 0 = 1 BCE; -100 = 101 BCE; etc. -} DateTime; - -//////////////////////////////// -// Types: File Properties - -typedef U32 FilePropertyFlags; -enum{ - FilePropertyFlag_IsFolder = (1 << 0), -}; - -typedef struct FileProperties{ - U64 size; - FilePropertyFlags flags; - DenseTime create_time; - DenseTime modify_time; - DataAccessFlags access; -} FileProperties; - - -//////////////////////////////// -// Types: Arena - -typedef struct Arena Arena; - -typedef struct ArenaTemp{ - Arena *arena; - U64 pos; -} ArenaTemp; - - -//////////////////////////////// -// Types: String - -typedef struct String8{ - U8 *str; - U64 size; -} String8; - -typedef struct String8Node{ - struct String8Node *next; - String8 string; -} String8Node; - -typedef struct String8List{ - String8Node *first; - String8Node *last; - U64 node_count; - U64 total_size; -} String8List; - -typedef struct StringJoin{ - String8 pre; - String8 mid; - String8 post; -} StringJoin; - -typedef U32 StringMatchFlags; -enum{ - StringMatchFlag_NoCase = (1 << 0), - StringMatchFlag_PrefixMatch = (1 << 1), -}; - -typedef struct String16{ - U16 *str; - U64 size; -} String16; - -typedef struct String32{ - U32 *str; - U64 size; -} String32; - -#define str8_expand(s) (int)((s).size), ((s).str) - -typedef struct StringDecode{ - U32 codepoint; - U32 size; -} StringDecode; - -//////////////////////////////// -// Types: Stream - -typedef struct STREAM STREAM; -typedef void STREAM_Handle; - -//////////////////////////////// -// Types: Buffer - -typedef struct BUFFER{ - void *base; - U64 size; - U64 commit_pos; -} BUFFER; - -#define BUFFER_TYPED(T, name) union{ BUFFER buffer; T *ptr; } name - -//////////////////////////////// -// Types: Hash Table - -typedef struct HASH_Node{ - struct HASH_Node *next; - U64 hash; - U64 val; -} HASH_Node; - -//////////////////////////////// -// Types: Log - -typedef void LOG_LogToProc(void *uptr, String8 str); - -typedef struct LOG_Node{ - struct LOG_Node *next; - U64 pos; - String8List log; - LOG_LogToProc *logto; - void *uptr; -} LOG_Node; - -typedef struct LOG_ThreadVars{ - Arena *arena; - LOG_Node *stack; -} LOG_ThreadVars; - -//////////////////////////////// -// Types: Error - -typedef struct ER_Node{ - struct ER_Node *next; - U64 pos; - String8 error; -} ER_Node; - -typedef struct ER_ThreadVars{ - Arena *arena; - ER_Node *stack; - U64 over_stack; -} ER_ThreadVars; - - -//////////////////////////////////////////////// -//////////////////////////////////////////////// -//////////////// CONSTANTS ///////////////// -//////////////////////////////////////////////// -//////////////////////////////////////////////// - -#define min_S8 ((S8) 0x80) -#define min_S16 ((S16)0x8000) -#define min_S32 ((S32)0x80000000) -#define min_S64 ((S64)0x8000000000000000llu) - -#define max_S8 ((S8) 0x7f) -#define max_S16 ((S16)0x7fff) -#define max_S32 ((S32)0x7fffffff) -#define max_S64 ((S64)0x7fffffffffffffffllu) - -#define max_U8 0xff -#define max_U16 0xffff -#define max_U32 0xffffffff -#define max_U64 0xffffffffffffffffllu - -#define machine_epsilon_F32 1.1920929e-7f -#define pi_F32 3.14159265359f -#define tau_F32 6.28318530718f -#define e_F32 2.71828182846f -#define gold_big_F32 1.61803398875f -#define gold_small_F32 0.61803398875f - -#define machine_epsilon_F64 2.220446e-16 -#define pi_F64 3.14159265359 -#define tau_F64 6.28318530718 -#define e_F64 2.71828182846 -#define gold_big_F64 1.61803398875 -#define gold_small_F64 0.61803398875 - -#define inf_F32_as_U32 0x7f800000 -#define neg_inf_F32_as_U32 0xff800000 -#define inf_F64_as_U64 0x7ff0000000000000 -#define neg_inf_F64_as_U64 0xfff0000000000000 - -#define set_inf_F32(x) (*(U32*)(&(x)) = inf_F32_as_U32) -#define set_neg_inf_F32(x) (*(U32*)(&(x)) = neg_inf_F32_as_U32) -#define set_inf_F64(x) (*(U64*)(&(x)) = inf_F64_as_U64) -#define set_neg_inf_F64(x) (*(U64*)(&(x)) = neg_inf_F64_as_U64) - - -//////////////////////////////////////////////// -//////////////////////////////////////////////// -//////////////// INTRINSICS //////////////// -//////////////////////////////////////////////// -//////////////////////////////////////////////// - -#if INTRINSICS_MICROSOFT - -# include -# define intrinsic_rdtsc() __rdtsc() -# define intrinsic_maxbit(o,x) _BitScanReverse64((o),(x)) - -#elif INTRINSICS_BUILT_IN - -# define intrinsic_rdtsc() __rdtsc() -# define intrinsic_maxbit(o,x) (*(o) = __builtin_clzll(x),(x)!=0) - -#endif - - -//////////////////////////////////////////////// -//////////////////////////////////////////////// -/////////////// DECLARATIONS /////////////// -//////////////////////////////////////////////// -//////////////////////////////////////////////// - -//////////////////////////////// -// Functions: Numerical/Math - -// float infinity/NaN - -MR4TH_SYMBOL B32 is_inf_or_nan_F32(F32 x); -MR4TH_SYMBOL B32 is_inf_or_nan_F64(F64 x); - -// float signs, rounding, and modulus - -MR4TH_SYMBOL F32 abs_F32(F32 x); -MR4TH_SYMBOL F32 sign_F32(F32 x); - -MR4TH_SYMBOL F32 trunc_F32(F32 x); -MR4TH_SYMBOL F32 floor_F32(F32 x); -MR4TH_SYMBOL F32 ceil_F32(F32 x); -MR4TH_SYMBOL F32 nearest_F32(F32 x); -MR4TH_SYMBOL F32 mod_F32(F32 x, F32 m); -MR4TH_SYMBOL F32 frac_F32(F32 x); - -MR4TH_SYMBOL F64 abs_F64(F64 x); -MR4TH_SYMBOL F64 sign_F64(F64 x); - -MR4TH_SYMBOL F64 trunc_F64(F64 x); -MR4TH_SYMBOL F64 floor_F64(F64 x); -MR4TH_SYMBOL F64 ceil_F64(F64 x); -MR4TH_SYMBOL F64 nearest_F64(F64 x); -MR4TH_SYMBOL F64 mod_F64(F64 x, F64 m); -MR4TH_SYMBOL F64 frac_F64(F64 x); - -// transcendental functions - -MR4TH_SYMBOL F32 sin_F32(F32 x); -MR4TH_SYMBOL F32 cos_F32(F32 x); -MR4TH_SYMBOL F32 tan_F32(F32 x); -MR4TH_SYMBOL F32 atan_F32(F32 x); -MR4TH_SYMBOL F32 atan2_F32(F32 x, F32 y); - -MR4TH_SYMBOL F32 sqrt_F32(F32 x); -MR4TH_SYMBOL F32 inv_sqrt_F32(F32 x); -MR4TH_SYMBOL F32 ln_F32(F32 x); -MR4TH_SYMBOL F32 pow_F32(F32 base, F32 x); - -MR4TH_SYMBOL F64 sin_F64(F64 x); -MR4TH_SYMBOL F64 cos_F64(F64 x); -MR4TH_SYMBOL F64 tan_F64(F64 x); -MR4TH_SYMBOL F64 atan_F64(F64 x); -MR4TH_SYMBOL F64 atan2_F64(F64 x, F64 y); - -MR4TH_SYMBOL F64 sqrt_F64(F64 x); -MR4TH_SYMBOL F64 inv_sqrt_F64(F64 x); -MR4TH_SYMBOL F64 ln_F64(F64 x); -MR4TH_SYMBOL F64 pow_F64(F64 base, F64 x); - -// linear interpolation - -MR4TH_SYMBOL F32 lerp(F32 a, F32 t, F32 b); -MR4TH_SYMBOL F32 unlerp(F32 a, F32 x, F32 b); - -// integer rounding & truncating - -MR4TH_SYMBOL U32 next_pow2_U32(U32 x); -MR4TH_SYMBOL S32 sign_extend_S32(S32 x, U32 bitidx); - -MR4TH_SYMBOL U64 next_pow2_U64(U32 x); -MR4TH_SYMBOL S64 sign_extend_S64(S64 x, U32 bitidx); - -//////////////////////////////// -// Functions: Compound Types - -// vector macros - -#define v2(x,y) CLiteral(V2F32){(x),(y)} -#define v3(x,y,z) CLiteral(V3F32){(x),(y),(z)} -#define v4(x,y,z,w) CLiteral(V4F32){(x),(y),(z),(w)} - -#define v2_expanded(v) ((v).x), ((v).y) -#define v3_expanded(v) ((v).x), ((v).y), ((v).z) -#define v4_expanded(v) ((v).x), ((v).y), ((v).z), ((v).w) -#define rect_expanded(r) ((r).x0), ((r).y0), ((r).x1), ((r).y1) - -#define v2_exop_scalar(sc, op, v) ((sc) op ((v).x)), ((sc) op ((v).y)) -#define v3_exop_scalar(sc, op, v) ((sc) op ((v).x)), ((sc) op ((v).y)), ((sc) op ((v).z)) -#define v4_exop_scalar(sc, op, v) ((sc) op ((v).x)), ((sc) op ((v).y)), ((sc) op ((v).z)), ((sc) op ((v).w)) - -#define v2_exop(v1, op, v2) ((v1).x op ((v2).x)), ((v1).y op ((v2).y)) -#define v3_exop(v1, op, v2) ((v1).x op ((v2).x)), ((v1).y op ((v2).y)), ((v1).z op ((v2).z)) -#define v4_exop(v1, op, v2) ((v1).x op ((v2).x)), ((v1).y op ((v2).y)), ((v1).z op ((v2).z)), ((v1).w op ((v2).w)) - -#define v2_op_scalar(sc, op, v) CLiteral(V2F32){ v2_exop_scalar(sc,op,v) } -#define v3_op_scalar(sc, op, v) CLiteral(V3F32){ v3_exop_scalar(sc,op,v) } -#define v4_op_scalar(sc, op, v) CLiteral(V4F32){ v4_exop_scalar(sc,op,v) } - -#define v2_op(v1, op, v2) CLiteral(V2F32){ v2_exop(v1,op,v2) } -#define v3_op(v1, op, v2) CLiteral(V3F32){ v3_exop(v1,op,v2) } -#define v4_op(v1, op, v2) CLiteral(V4F32){ v4_exop(v1,op,v2) } - -#define sc_lerp(s1, l, s2) ((s1) + (l)*((s2) - (s1))) -#define v2_lerp(v1, l, v2) v2( sc_lerp((v1).x, l, (v2).x), sc_lerp((v1).y, l, (v2).y) ) -#define v3_lerp(v1, l, v2) v3( sc_lerp((v1).x, l, (v2).x), sc_lerp((v1).y, l, (v2).y), sc_lerp((v1).z, l, (v2).z) ) -#define v4_lerp(v1, l, v2) v4( sc_lerp((v1).x, l, (v2).x), sc_lerp((v1).y, l, (v2).y), sc_lerp((v1).z, l, (v2).z), sc_lerp((v1).w, l, (v2).w) ) - -#define v2_dim_from_rect(r) CLiteral(V2F32){ (r).x1 - (r).x0, (r).y1 - (r).y0 } - -// range macros - -#define rangef32(min,max) CLiteral(RangeF32){(min),(max)} - -// 2d vectors - -MR4TH_SYMBOL V2F32 v2_polar(F32 theta, F32 radius); -MR4TH_SYMBOL F32 angle_from_v2f32(V2F32 v); - -MR4TH_SYMBOL V2F32 v2_unit(V2F32 v); - -// 3d vectors - -MR4TH_SYMBOL V3F32 v3_spherical(F32 theta_xz, F32 theta_yz, F32 radius); -MR4TH_SYMBOL V3F32 v3_cross(V3F32 a, V3F32 b); - -MR4TH_SYMBOL V3F32 v3_unit(V3F32 v); - -// 4x4 matrix - -MR4TH_SYMBOL B32 mat4x4_inv(F32 *in, F32 *out); -MR4TH_SYMBOL void mat4x4_mul(F32 *a, F32 *b, F32 *out); - -//////////////////////////////// -// Functions: Memory Operations - -MR4TH_SYMBOL void memory_zero(void *ptr, U64 size); -MR4TH_SYMBOL void memory_fill(void *ptr, U64 size, U8 fillbyte); -MR4TH_SYMBOL B32 memory_match(void *a, void *b, U64 size); -MR4TH_SYMBOL void*memory_move(void *a, void *b, U64 size); - -//////////////////////////////// -// Functions: Symbolic Constants - -MR4TH_SYMBOL OperatingSystem operating_system_from_context(void); -MR4TH_SYMBOL Architecture architecture_from_context(void); - -MR4TH_SYMBOL char* string_from_operating_system(OperatingSystem os); -MR4TH_SYMBOL char* string_from_architecture(Architecture arch); -MR4TH_SYMBOL char* string_from_month(Month month); -MR4TH_SYMBOL char* string_from_day_of_week(DayOfWeek day_of_week); - -//////////////////////////////// -// Functions: Time - -MR4TH_SYMBOL DenseTime dense_time_from_date_time(DateTime *date_time); -MR4TH_SYMBOL DateTime date_time_from_dense_time(DenseTime dense_time); - -//////////////////////////////// -// Functions: Arenas - -// arena core - -MR4TH_SYMBOL_MUST_SHARE Arena* arena_new(U64 reserve_size, U64 alignment, B32 growing); -MR4TH_SYMBOL_MUST_SHARE void arena_release(Arena *arena); -MR4TH_SYMBOL_MUST_SHARE void* arena_push_no_zero(Arena *arena, U64 size); -MR4TH_SYMBOL_MUST_SHARE void arena_pop_to(Arena *arena, U64 pos); -MR4TH_SYMBOL_MUST_SHARE U64 arena_current_pos(Arena *arena); -MR4TH_SYMBOL_MUST_SHARE U64 arena_current_align(Arena *arena); -MR4TH_SYMBOL_MUST_SHARE void arena_set_align(Arena *arena, U64 alignment); - -MR4TH_SYMBOL_MUST_SHARE ArenaTemp arena_get_scratch(Arena **conflict_array, U32 count); - -// arena helpers - -MR4TH_SYMBOL Arena* arena_alloc(void); -MR4TH_SYMBOL void* arena_push(Arena *arena, U64 size); -MR4TH_SYMBOL void arena_pop_amount(Arena *arena, U64 amount); -MR4TH_SYMBOL void arena_align(Arena *arena, U64 pow2_align); - -#define push_array(a,T,c) (T*)arena_push((a), sizeof(T)*(c)) -#define push_array_no_zero(a,T,c) (T*)arena_push_no_zero((a), sizeof(T)*(c)) - -#define push_array_copy(a,T,c,p) (T*)(MemoryCopy(push_array(a,T,c), (p), sizeof(T)*(c))) - -MR4TH_SYMBOL ArenaTemp arena_begin_temp(Arena *arena); -MR4TH_SYMBOL void arena_end_temp(ArenaTemp *temp); - -#define arena_release_scratch(temp) arena_end_temp(temp) - -//////////////////////////////// -// Functions: Strings - -// characters - -MR4TH_SYMBOL B32 char_is_whitespace(U8 c); -MR4TH_SYMBOL B32 char_is_slash(U8 c); -MR4TH_SYMBOL B32 char_is_digit(U8 c); - -MR4TH_SYMBOL U8 char_to_uppercase(U8 c); -MR4TH_SYMBOL U8 char_to_lowercase(U8 c); - -// in-place constructors - -#define str8(p,z) CLiteral(String8){(U8*)(p), (z)} - -MR4TH_SYMBOL String8 str8_range(U8 *first, U8 *opl); -MR4TH_SYMBOL String8 str8_cstring(U8 *cstr); -MR4TH_SYMBOL String8 str8_cstring_capped(U8 *cstr, U8 *opl); - -MR4TH_SYMBOL String16 str16_cstring(U16 *cstr); - -// literal constructors - -#define str8_lit(s) CLiteral(String8){(U8*)(s), sizeof(s) - 1} -#define str8_lit_const(s) {(U8*)(s), sizeof(s) - 1} - -// compound constructors - -MR4TH_SYMBOL void str8_list_push(Arena *arena, String8List *list, String8 string); -MR4TH_SYMBOL void str8_list_push_front(Arena *arena, String8List *list, String8 string); - -MR4TH_SYMBOL String8List str8_list_copy(Arena *arena, String8List *list); -MR4TH_SYMBOL String8 str8_join(Arena *arena, String8List *list, StringJoin *optional_join); -MR4TH_SYMBOL String8List str8_split(Arena *arena, String8 string, U8 *split_characters, U32 count); - -MR4TH_SYMBOL String8 str8_pushfv(Arena *arena, char *fmt, va_list args); -MR4TH_SYMBOL String8 str8_pushf(Arena *arena, char *fmt, ...); -MR4TH_SYMBOL void str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...); - -MR4TH_SYMBOL String8 str8_push_copy(Arena *arena, String8 string); - -// substrings - -MR4TH_SYMBOL String8 str8_prefix(String8 str, U64 size); -MR4TH_SYMBOL String8 str8_chop(String8 str, U64 amount); -MR4TH_SYMBOL String8 str8_postfix(String8 str, U64 size); -MR4TH_SYMBOL String8 str8_skip(String8 str, U64 amount); - -MR4TH_SYMBOL String8 str8_skip_chop_whitespace(String8 str); - -// hash - -MR4TH_SYMBOL U64 str8_hash(String8 str); - -// compare - -MR4TH_SYMBOL B32 str8_match(String8 a, String8 b, StringMatchFlags flags); - -// path helpers - -MR4TH_SYMBOL String8 str8_chop_last_slash(String8 string); -MR4TH_SYMBOL String8 str8_file_name_from_path(String8 full_file_name); -MR4TH_SYMBOL String8 str8_base_name_from_file_name(String8 file_name); - -// stylized constructors - -MR4TH_SYMBOL String8 str8_join_flags(Arena *arena, String8List *list); - -// unicode - -MR4TH_SYMBOL StringDecode str_decode_utf8(U8 *str, U32 cap); -MR4TH_SYMBOL U32 str_encode_utf8(U8 *dst, U32 codepoint); -MR4TH_SYMBOL StringDecode str_decode_utf16(U16 *str, U32 cap); -MR4TH_SYMBOL U32 str_encode_utf16(U16 *dst, U32 codepoint); - -MR4TH_SYMBOL String32 str32_from_str8(Arena *arena, String8 string); -MR4TH_SYMBOL String8 str8_from_str32(Arena *arena, String32 string); -MR4TH_SYMBOL String16 str16_from_str8(Arena *arena, String8 string); -MR4TH_SYMBOL String8 str8_from_str16(Arena *arena, String16 string); - -// numeric conversion - -MR4TH_SYMBOL B32 str8_is_u64(String8 string, U32 radix); - -MR4TH_SYMBOL U64 u64_from_str8(String8 string, U32 radix); -MR4TH_SYMBOL U64 u64_from_str8_c_syntax(String8 string); -MR4TH_SYMBOL S64 s64_from_str8_c_syntax(String8 string); -MR4TH_SYMBOL F64 f64_from_str8(String8 string); - -//////////////////////////////// -// Functions: Stream - -// stream core - -MR4TH_SYMBOL_MUST_SHARE STREAM* stream_new(void); -MR4TH_SYMBOL_MUST_SHARE void stream_release(STREAM *stream); - -MR4TH_SYMBOL_MUST_SHARE void stream_clear(STREAM *stream); -MR4TH_SYMBOL_MUST_SHARE void stream_write(STREAM *stream, String8 data); -MR4TH_SYMBOL_MUST_SHARE U8* stream_alloc(STREAM *stream, U64 size); - -MR4TH_SYMBOL_MUST_SHARE U64 stream_total_size(STREAM *stream); -MR4TH_SYMBOL_MUST_SHARE STREAM_Handle* stream_next_chunk(STREAM *stream, STREAM_Handle *handle, String8 *chunk_out); - -// stream helpers - -MR4TH_SYMBOL String8 stream_read(Arena *arena, STREAM *stream); - -MR4TH_SYMBOL void stream_printfv(STREAM *stream, char *fmt, va_list args); -MR4TH_SYMBOL void stream_printf(STREAM *stream, char *fmt, ...); - -//////////////////////////////// -// Functions: Buffer - -MR4TH_SYMBOL void buffer_alloc(BUFFER *buffer, U64 reserve_size); -MR4TH_SYMBOL void buffer_release(BUFFER *buffer); -MR4TH_SYMBOL void buffer_reset(BUFFER *buffer); - -MR4TH_SYMBOL void buffer_commit_off__call(BUFFER *buffer, U64 off); - -#define buffer_commit_off(b, off) \ -if ((b)->commit_pos < (off) && (off) <= (b)->size){ \ -buffer_commit_off__call((b),(off)); } - -#define buffer_typed_commit_idx(b, idx) \ -buffer_commit_off(&(b)->buffer, (idx)*sizeof(*(b)->ptr)) - -//////////////////////////////// -// Types: Hash Table - -MR4TH_SYMBOL void hash_buckets_init(BUFFER *buckets, U64 count); -MR4TH_SYMBOL HASH_Node* hash_buckets_first(BUFFER *buckets, U64 hash); -MR4TH_SYMBOL void hash_buckets_expand(BUFFER *buckets, U64 capacity); -MR4TH_SYMBOL void hash_buckets_insert(Arena *arena, BUFFER *buckets, U64 hash, U64 val); - -//////////////////////////////// -// Functions: Log - -MR4TH_SYMBOL void log_accum_begin(LOG_LogToProc *proc, void *uptr); -MR4TH_SYMBOL B32 log_gathering(void); -MR4TH_SYMBOL void log_emit(String8 message); -MR4TH_SYMBOL void log_emitf(char *fmt, ...); -MR4TH_SYMBOL String8 log_accum_end(Arena *arena); - -//////////////////////////////// -// Functions: Errors - -MR4TH_SYMBOL void er_accum_begin(void); -MR4TH_SYMBOL void er_emit(String8 error); -MR4TH_SYMBOL void er_emitf(char *fmt, ...); -MR4TH_SYMBOL String8 er_accum_end(Arena *arena); - - -//////////////////////////////////////////////// -//////////////////////////////////////////////// -///////// DECLARATIONS PROFILING /////////// -//////////////////////////////////////////////// -//////////////////////////////////////////////// - -//////////////////////////////// -// Profiling: Implementable Interface - -#if MR4TH_PROFILING_USER || MR4TH_PROFILING_PROVIDER - -MR4TH_SYMBOL_LINK void prof_open(char *name); -MR4TH_SYMBOL_LINK void prof_close(void); -MR4TH_SYMBOL_LINK void prof_thread_begin(void); -MR4TH_SYMBOL_LINK void prof_thread_end(void); -MR4TH_SYMBOL_LINK void prof_thread_flush(void); -MR4TH_SYMBOL_LINK void prof_begin(char *name, U32 len); -MR4TH_SYMBOL_LINK void prof_end(void); - -#endif - -//////////////////////////////// -// Profiling: User Interface - -#if MR4TH_PROFILING_USER -# define ProfOpen(n) prof_open((char*)(n)) -# define ProfClose() prof_close() -# define ProfThreadBegin() prof_thread_begin() -# define ProfThreadEnd() prof_thread_end() -# define ProfThreadFlush() prof_thread_flush() -# define ProfBegin(n) prof_begin((n), sizeof(n) - 1) -# define ProfEnd() prof_end() -#else -# define ProfOpen(n) -# define ProfClose() -# define ProfThreadBegin() -# define ProfThreadEnd() -# define ProfThreadFlush() -# define ProfBegin(n) -# define ProfEnd() -#endif - -#if MR4TH_PROFILING_MANUAL -# define ProfBeginManual(n) ProfBegin(n) -# define ProfEndManual() ProfEnd() -#else -# define ProfBeginManual(n) -# define ProfEndManual() -#endif - -#define ProfBeginFunc() ProfBeginManual(__FUNCTION__) -#define ProfEndFunc() ProfEndManual() - - - -//////////////////////////////////////////////// -//////////////////////////////////////////////// -/////// DECLARATIONS OS ABSTRACTION //////// -//////////////////////////////////////////////// -//////////////////////////////////////////////// - -//////////////////////////////// -// Shared Types - -typedef struct OS_FileIter{ - U8 v[640]; -} OS_FileIter; - -typedef enum OS_SystemPath{ - OS_SystemPath_CurrentDirectory = 0, - OS_SystemPath_Binary = 1, - OS_SystemPath_UserData = 2, - OS_SystemPath_TempData = 3, - OS_SystemPath_COUNT -} OS_SystemPath; - -typedef void OS_Library; - -typedef struct OS_VRange{ - void *addr; - U64 size; -} OS_VRange; - -//////////////////////////////// -// Implementable Functions: Process Setup - -MR4TH_SYMBOL void os_main_init(int argc, char **argv); -MR4TH_SYMBOL String8List os_command_line_arguments(void); -MR4TH_SYMBOL void os_exit_process(U32 code); - -//////////////////////////////// -// Implementable Functions: Memory Functions - -MR4TH_SYMBOL void* os_memory_reserve(U64 size); -MR4TH_SYMBOL B32 os_memory_commit(void *ptr, U64 size); -MR4TH_SYMBOL void os_memory_decommit(void *ptr, U64 size); -MR4TH_SYMBOL void os_memory_release(void *ptr, U64 size); - -MR4TH_SYMBOL B32 os_memory_protect(void *ptr, U64 size, DataAccessFlags access_flags); - -//////////////////////////////// -// Implementable Functions: File Handling - -MR4TH_SYMBOL String8 os_file_read(Arena *arena, String8 file_name); - -typedef String8 OS_FileWriteCallback(void *udata); -MR4TH_SYMBOL B32 os_file_write_callback(String8 file_name, void *udata, OS_FileWriteCallback *callback); - -MR4TH_SYMBOL FileProperties os_file_properties(String8 file_name); - -MR4TH_SYMBOL B32 os_file_delete(String8 file_name); -MR4TH_SYMBOL B32 os_file_rename(String8 og_name, String8 new_name); -MR4TH_SYMBOL B32 os_file_make_directory(String8 path); -MR4TH_SYMBOL B32 os_file_delete_directory(String8 path); - -MR4TH_SYMBOL OS_FileIter os_file_iter_init(Arena *arena, String8 path); -MR4TH_SYMBOL B32 os_file_iter_next(Arena *arena, OS_FileIter *iter, - String8 *name_out, FileProperties *prop_out); -MR4TH_SYMBOL void os_file_iter_end(OS_FileIter *iter); - -MR4TH_SYMBOL String8 os_file_path(Arena *arena, OS_SystemPath path); - -MR4TH_SYMBOL void os_set_current_directory(String8 path); - -//////////////////////////////// -// Implementable Functions: Time - -MR4TH_SYMBOL DateTime os_now_universal_time(void); -MR4TH_SYMBOL DateTime os_local_time_from_universal(DateTime *date_time); -MR4TH_SYMBOL DateTime os_universal_time_from_local(DateTime *date_time); - -MR4TH_SYMBOL U32 os_time_stamp_32_from_date_time(DateTime *date_time); - -MR4TH_SYMBOL U64 os_now_ticks(void); -MR4TH_SYMBOL void os_get_microseconds_per_tick(U64 *usecs_out, U64 *ticks_out); -MR4TH_SYMBOL void os_sleep_milliseconds(U32 t); - -//////////////////////////////// -// Implementable Functions: Libraries - -MR4TH_SYMBOL OS_Library* os_lib_load(String8 path); -MR4TH_SYMBOL VoidFunc* os_lib_get_proc(OS_Library *lib, char *name); -MR4TH_SYMBOL void os_lib_release(OS_Library *lib); - -MR4TH_SYMBOL OS_Library* os_lib_from_addr(void *addr); -MR4TH_SYMBOL OS_VRange os_lib_image_range(OS_Library *lib); - -//////////////////////////////// -// Implementable Functions: Entropy - -MR4TH_SYMBOL void os_get_entropy(void *data, U64 size); - -//////////////////////////////// -// Helper Functions: File Handling - -MR4TH_SYMBOL B32 os_file_write(String8 file_name, String8 data); -MR4TH_SYMBOL B32 os_file_write_list(String8 file_name, String8Node *first_node); -MR4TH_SYMBOL B32 os_file_write_stream(String8 file_name, STREAM *stream); - -//////////////////////////////// -// Helper Functions: Libraries - -MR4TH_SYMBOL OS_VRange os_this_image(void); - - - -/******************************* -** Begin Base Win32 ** -*******************************/ - -#if OS_WINDOWS - -//////////////////////////////// -// Win32 Includes - -#include -#include -#include - -//////////////////////////////// -// Win32 Types - -typedef struct W32_FileIter{ - HANDLE handle; - WIN32_FIND_DATAW find_data; - B32 done; -} W32_FileIter; -StaticAssert(sizeof(W32_FileIter) <= sizeof(OS_FileIter), w32_fileiter); - -//////////////////////////////// -// Win32 Functions: Specialized Init for WinMain - -MR4TH_SYMBOL void w32_WinMain_init(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPSTR lpCmdLine, - int nShowCmd); - -MR4TH_SYMBOL HINSTANCE w32_get_instance(void); - -//////////////////////////////// -// Win32 Functions: Time Helpers - -MR4TH_SYMBOL DateTime w32_date_time_from_system_time(SYSTEMTIME *in); -MR4TH_SYMBOL SYSTEMTIME w32_system_time_from_date_time(DateTime *in); -MR4TH_SYMBOL DenseTime w32_dense_time_from_file_time(FILETIME *file_time); - -//////////////////////////////// -// Win32 Functions: File Helpers - -MR4TH_SYMBOL FilePropertyFlags w32_prop_flags_from_attribs(DWORD attribs); -MR4TH_SYMBOL DataAccessFlags w32_access_from_attributes(DWORD attribs); - -//////////////////////////////// -// Win32 Helper Macro - -#define W32_PROC_ADDR(v,m,s) (*(PROC*)(&(v))) = GetProcAddress((m),(s)) - -#endif /* OS_WINDOWS */ - -/******************************* -** End Base Win32 ** -*******************************/ - - - -/******************************* -** Begin Base Linux ** -*******************************/ - -#if OS_LINUX - -//////////////////////////////// -// Linux Includes - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -//////////////////////////////// -// Linux Types - -typedef struct LNX_FileIter{ - DIR *dir; - struct dirent *dp; - String8 path; -} LNX_FileIter; -StaticAssert(sizeof(LNX_FileIter) <= sizeof(OS_FileIter), lnx_fileiter); - -//////////////////////////////// -// Linux Functions: Time Helpers - -MR4TH_SYMBOL DateTime lnx_date_time_from_tm(struct tm *tm); -MR4TH_SYMBOL DenseTime lnx_dense_time_from_time_t(time_t time); -MR4TH_SYMBOL struct tm lnx_tm_from_date_time(DateTime *date_time); - -//////////////////////////////// -// Linux Functions: File Helpers - -MR4TH_SYMBOL FilePropertyFlags lnx_prop_flags_from_mode(mode_t mode); -MR4TH_SYMBOL DataAccessFlags lnx_access_from_mode(mode_t mode); -MR4TH_SYMBOL FileProperties lnx_file_properties_from_stat(struct stat *st); - -MR4TH_SYMBOL String8 lnx_proc_file_read(Arena *arena, char *path); - -#endif /* OS_LINUX */ - -/******************************* -** End Base Linux ** -*******************************/ - - -//////////////////////////////////////////////// -//////////////////////////////////////////////// -///////////////// M4 Printf //////////////// -//////////////////////////////////////////////// -//////////////////////////////////////////////// - -// stb_sprintf.h STB_SPRINTF_H_INCLUDE - -/* -Single file sprintf replacement. - -Originally written by Jeff Roberts at RAD Game Tools - 2015/10/20. -Hereby placed in public domain. - -This is a full sprintf replacement that supports everything that -the C runtime sprintfs support, including float/double, 64-bit integers, -hex floats, field parameters (%*.*d stuff), length reads backs, etc. - -Why would you need this if sprintf already exists? Well, first off, -it's *much* faster (see below). It's also much smaller than the CRT -versions code-space-wise. We've also added some simple improvements -that are super handy (commas in thousands, callbacks at buffer full, -for example). Finally, the format strings for MSVC and GCC differ -for 64-bit integers (among other small things), so this lets you use -the same format strings in cross platform code. - -It uses the standard single file trick of being both the header file -and the source itself. If you just include it normally, you just get -the header file function definitions. To get the code, you include -it from a C or C++ file and define STB_SPRINTF_IMPLEMENTATION first. - -It only uses va_args macros from the C runtime to do it's work. It -does cast doubles to S64s and shifts and divides U64s, which does -drag in CRT code on most platforms. - -It compiles to roughly 8K with float support, and 4K without. -As a comparison, when using MSVC static libs, calling sprintf drags -in 16K. - -API: -==== -int stbsp_sprintf( char * buf, char const * fmt, ... ) -int stbsp_snprintf( char * buf, int count, char const * fmt, ... ) - Convert an arg list into a buffer. stbsp_snprintf always returns - a zero-terminated string (unlike regular snprintf). - -int stbsp_vsprintf( char * buf, char const * fmt, va_list va ) -int stbsp_vsnprintf( char * buf, int count, char const * fmt, va_list va ) - Convert a va_list arg list into a buffer. stbsp_vsnprintf always returns - a zero-terminated string (unlike regular snprintf). - -int stbsp_vsprintfcb( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va ) - typedef char * STBSP_SPRINTFCB( char const * buf, void * user, int len ); - Convert into a buffer, calling back every STB_SPRINTF_MIN chars. - Your callback can then copy the chars out, print them or whatever. - This function is actually the workhorse for everything else. - The buffer you pass in must hold at least STB_SPRINTF_MIN characters. - // you return the next buffer to use or 0 to stop converting - -void stbsp_set_separators( char comma, char period ) - Set the comma and period characters to use. - -FLOATS/DOUBLES: -=============== -This code uses a internal float->ascii conversion method that uses -doubles with error correction (double-doubles, for ~105 bits of -precision). This conversion is round-trip perfect - that is, an atof -of the values output here will give you the bit-exact double back. - -One difference is that our insignificant digits will be different than -with MSVC or GCC (but they don't match each other either). We also -don't attempt to find the minimum length matching float (pre-MSVC15 -doesn't either). - -If you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT -and you'll save 4K of code space. -NOTE(allen): MODIFICATION - I've hard coded that this copy *does* use floats - -64-BIT INTS: -============ -This library also supports 64-bit integers and you can use MSVC style or -GCC style indicators (%I64d or %lld). It supports the C99 specifiers -for size_t and ptr_diff_t (%jd %zd) as well. - -EXTRAS: -======= -Like some GCCs, for integers and floats, you can use a ' (single quote) -specifier and commas will be inserted on the thousands: "%'d" on 12345 -would print 12,345. - -For integers and floats, you can use a "$" specifier and the number -will be converted to float and then divided to get kilo, mega, giga or -tera and then printed, so "%$d" 1000 is "1.0 k", "%$.2d" 2536000 is -"2.53 M", etc. For byte values, use two $:s, like "%$$d" to turn -2536000 to "2.42 Mi". If you prefer JEDEC suffixes to SI ones, use three -$:s: "%$$$d" -> "2.42 M". To remove the space between the number and the -suffix, add "_" specifier: "%_$d" -> "2.53M". - -In addition to octal and hexadecimal conversions, you can print -integers in binary: "%b" for 256 would print 100. - -PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC): -=================================================================== -"%d" across all 32-bit ints (4.8x/4.0x faster than 32-/64-bit MSVC) -"%24d" across all 32-bit ints (4.5x/4.2x faster) -"%x" across all 32-bit ints (4.5x/3.8x faster) -"%08x" across all 32-bit ints (4.3x/3.8x faster) -"%f" across e-10 to e+10 floats (7.3x/6.0x faster) -"%e" across e-10 to e+10 floats (8.1x/6.0x faster) -"%g" across e-10 to e+10 floats (10.0x/7.1x faster) -"%f" for values near e-300 (7.9x/6.5x faster) -"%f" for values near e+300 (10.0x/9.1x faster) -"%e" for values near e-300 (10.1x/7.0x faster) -"%e" for values near e+300 (9.2x/6.0x faster) -"%.320f" for values near e-300 (12.6x/11.2x faster) -"%a" for random values (8.6x/4.3x faster) -"%I64d" for 64-bits with 32-bit values (4.8x/3.4x faster) -"%I64d" for 64-bits > 32-bit values (4.9x/5.5x faster) -"%s%s%s" for 64 char strings (7.1x/7.3x faster) -"...512 char string..." ( 35.0x/32.5x faster!) -*/ - -#if defined(__clang__) -#if defined(__has_feature) && defined(__has_attribute) -#if __has_feature(address_sanitizer) -#if __has_attribute(__no_sanitize__) -#define STBSP__ASAN __attribute__((__no_sanitize__("address"))) -#elif __has_attribute(__no_sanitize_address__) -#define STBSP__ASAN __attribute__((__no_sanitize_address__)) -#elif __has_attribute(__no_address_safety_analysis__) -#define STBSP__ASAN __attribute__((__no_address_safety_analysis__)) -#endif -#endif -#endif -#elif defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) -#if defined(__SANITIZE_ADDRESS__) && __SANITIZE_ADDRESS__ -#define STBSP__ASAN __attribute__((__no_sanitize_address__)) -#endif -#endif - -#ifndef STBSP__ASAN -#define STBSP__ASAN -#endif - -#ifdef STB_SPRINTF_STATIC -#define STBSP__PUBLICDEC static -#define STBSP__PUBLICDEF static STBSP__ASAN -#else -#ifdef __cplusplus -#define STBSP__PUBLICDEC extern "C" -#define STBSP__PUBLICDEF extern "C" STBSP__ASAN -#else -#define STBSP__PUBLICDEC extern -#define STBSP__PUBLICDEF STBSP__ASAN -#endif -#endif - -#if defined(__has_attribute) -#if __has_attribute(format) -#define STBSP__ATTRIBUTE_FORMAT(fmt,va) __attribute__((format(printf,fmt,va))) -#endif -#endif - -#ifndef STBSP__ATTRIBUTE_FORMAT -#define STBSP__ATTRIBUTE_FORMAT(fmt,va) -#endif - -#ifdef _MSC_VER -#define STBSP__NOTUSED(v) (void)(v) -#else -#define STBSP__NOTUSED(v) (void)sizeof(v) -#endif - -//#include // size_t, ptrdiff_t - -#ifndef STB_SPRINTF_MIN -#define STB_SPRINTF_MIN 512 // how many characters per callback -#endif -typedef char *STBSP_SPRINTFCB(const char *buf, void *user, int len); - -STBSP__PUBLICDEC int m4_vsprintf(char *buf, char const *fmt, va_list va); -STBSP__PUBLICDEC int m4_vsnprintf(char *buf, int count, char const *fmt, va_list va); -STBSP__PUBLICDEC int m4_sprintf(char *buf, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(2,3); -STBSP__PUBLICDEC int m4_snprintf(char *buf, int count, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(3,4); - -STBSP__PUBLICDEC int m4_vsprintfcb(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va); -STBSP__PUBLICDEC void m4_set_separators(char comma, char period); - -/* -** NOTE(allen): sprintf modifications notes -** -** Legend for specifier allocation: -** [ ] - specifier is free for use -** [#] - used by stb_sprintf default -** [$] - used by built-in custom printing logic -** -** Specifier allocation: -** a[#] - hex float -** A[#] - hex float -** b[#] - binary -** B[#] - binary -** c[#] - char -** C[ ] -** d[#] - integer -** D[ ] -** e[#] - float -** E[#] - float -** f[#] - float -** F[ ] -** g[#] - float -** G[#] - float -** h[#] - half width -** H[ ] -** i[#] - integer -** I[#] - size[Microsoft-Style] -** j[#] - size[size_t] -** J[ ] -** k[ ] -** K[ ] -** l[#] - size[long]/size[long long] -** L[ ] -** m[ ] -** M[ ] -** n[#] - write-bytes -** N[$] - indentation -** o[#] - octal -** O[ ] -** p[ ] -** P[ ] -** q[ ] -** Q[ ] -** r[ ] -** R[ ] -** s[#] - cstr -** S[$] - String8 -** t[#] - size[ptrdiff_t] -** T[ ] -** u[#] - unsigned integer -** U[ ] -** v[ ] -** V[ ] -** w[ ] -** W[ ] -** x[#] - hex -** X[#] - hex -** y[ ] -** Y[ ] -** z[#] - size[size_t] -** Z[ ] -** 0[#] - leading zeroes -** 1[ ] -** 2[ ] -** 3[ ] -** 4[ ] -** 5[ ] -** 6[ ] -** 7[ ] -** 8[ ] -** 9[ ] -** $[$] - memory size (modified from stb_sprintf.h) -** ?[ ] -** -*/ - -#endif /* MR4TH_BASE_H */ - -/* -** TODO: -** [ ] m4_printf plugins experiment -** -** [ ] unicode support -** [ ] high performance encode/decode factorization -** [ ] unicode string conversions should take string lists "Better unicode conversions here" -** [ ] math implementation replacements -** [ ] clib elimination option -** [x] manually implement memset,memcmp,memmove -** [x] basic C implementations -** [ ] high performance implementations (hand written assembly perhaps? -- or at least use vector intrinsics) -** [ ] necessary stubs for clib elimination -** [ ] Test out the usage process -** [ ] default (unity build standalone) -** [ ] standalone multi-unit -** [ ] core & plugin -** [ ] Write instructions -** [ ] Write examples -** -** [ ] Multi-threading primitives -** [ ] Thread-safe STREAM -*/ diff --git a/mr4th/mr4th_cmdln.c b/mr4th/mr4th_cmdln.c deleted file mode 100644 index 726c9c0..0000000 --- a/mr4th/mr4th_cmdln.c +++ /dev/null @@ -1,294 +0,0 @@ -//////////////////////////////// -// Functions: Command Line Parsing - -MR4TH_SYMBOL MR4TH_READ_ONLY -CMDLN_Params cmdln__params_nil = {0}; - -#define cmdln_params_nil (CMDLN_Params*)(&cmdln__params_nil) - -MR4TH_SYMBOL CMDLN* -cmdln_from_args(Arena *arena, String8List *args){ - CMDLN *cmdln = push_array(arena, CMDLN, 1); - cmdln->raw = str8_list_copy(arena, args); - - String8Node *node = cmdln->raw.first; - - // first string is 'program' - if (node != 0){ - cmdln->program = node->string; - node = node->next; - } - - // consume string nodes - B32 forced_input = 0; - for (;node != 0;){ - String8 string = str8_skip_chop_whitespace(node->string); - node = node->next; - - // check if argument is a flag - B32 is_flag = 0; - if (!forced_input){ - is_flag = (string.size != 0 && string.str[0] == '-'); - } - - // parse flag - if (is_flag){ - - // long flag - B32 is_long_flag = (string.size > 1 && string.str[1] == '-'); - if (is_long_flag){ - - // end 'normal' mode - B32 double_dash = (string.size == 2); - if (double_dash){ - forced_input = 1; - } - - // parse long flag - if (!double_dash){ - String8 flag_whole = str8_skip(string, 2); - - // parameter delimter - U64 delim = flag_whole.size; - for (U8 *ptr = flag_whole.str, *opl = flag_whole.str + flag_whole.size; - ptr < opl; ptr += 1){ - if (*ptr == '=' || *ptr == ':'){ - delim = (U64)(ptr - flag_whole.str); - break; - } - } - - // split flag at delimiter - String8 flag_name = str8_prefix(flag_whole, delim); - String8 flag_param = str8_skip(flag_whole, delim + 1); - - // if have a param delimiter at end - // then use the next argument as the flag_param - if (delim == flag_whole.size - 1){ - if (node != 0){ - flag_param = node->string; - node = node->next; - } - } - - // parse parameters - CMDLN_Params *params = cmdln_params_from_string(arena, flag_param); - - // store flag node - { - CMDLN_Node *cmdlnnode = push_array(arena, CMDLN_Node, 1); - SLLQueuePush(cmdln->first, cmdln->last, cmdlnnode); - cmdlnnode->string = flag_name; - cmdlnnode->params = params; - cmdln->flag_count += 1; - } - } - } - - // short flags - if (!is_long_flag){ - String8 short_flags = str8_skip(string, 1); - - U8 *flag = short_flags.str; - U8 *flagopl = short_flags.str + short_flags.size; - for (; flag < flagopl; flag += 1){ - U8 *flagptr = flag; - - // check for parameters - String8 flag_param = {0}; - if (flag + 1 < flagopl && - (flag[1] == '=' || flag[1] == ':')){ - flag_param = str8_range(flag + 2, flagopl); - if (flag_param.size == 0){ - if (node != 0){ - flag_param = node->string; - node = node->next; - } - } - - // kill the flag loop after finding parameters - flag = flagopl; - } - - // parse parameters - CMDLN_Params *params = cmdln_params_from_string(arena, flag_param); - - // store flag node - { - CMDLN_Node *cmdlnnode = push_array(arena, CMDLN_Node, 1); - SLLQueuePush(cmdln->first, cmdln->last, cmdlnnode); - cmdlnnode->string = str8(flagptr, 1); - cmdlnnode->params = params; - cmdln->flag_count += 1; - } - } - } - } - - // parse input - if (!is_flag){ - String8 input_string = string; - - // store input node - { - CMDLN_Node *cmdlnnode = push_array(arena, CMDLN_Node, 1); - SLLQueuePush(cmdln->first, cmdln->last, cmdlnnode); - cmdlnnode->string = input_string; - cmdln->input_count += 1; - } - } - } - - // pointer arrays - cmdln->inputs = push_array(arena, CMDLN_Node*, cmdln->input_count); - cmdln->flags = push_array(arena, CMDLN_Node*, cmdln->flag_count); - { - CMDLN_Node **inputptr = cmdln->inputs; - CMDLN_Node **flagptr = cmdln->flags; - for (CMDLN_Node *node = cmdln->first; - node != 0; - node = node->next){ - if (node->params == 0){ - *inputptr = node; - inputptr += 1; - } - else{ - *flagptr = node; - flagptr += 1; - } - } - } - - return(cmdln); -} - -MR4TH_SYMBOL CMDLN_Params* -cmdln_params_from_string(Arena *arena, String8 flag_param){ - CMDLN_Params *params = cmdln_params_nil; - if (flag_param.size > 0){ - params = push_array(arena, CMDLN_Params, 1); - params->raw = flag_param; - params->list = str8_split(arena, flag_param, (U8*)",", 1); - } - return(params); -} - -MR4TH_SYMBOL U64 -cmdln_input_count(CMDLN *cmdln){ - return(cmdln->input_count); -} - -MR4TH_SYMBOL String8 -cmdln_input_from_idx(CMDLN *cmdln, U64 idx){ - String8 result = {0}; - if (idx < cmdln->input_count){ - result = cmdln->inputs[idx]->string; - } - return(result); -} - -MR4TH_SYMBOL U64 -cmdln_flag_count(CMDLN *cmdln){ - return(cmdln->flag_count); -} - -MR4TH_SYMBOL CMDLN_Flag* -cmdln_flag_from_idx(CMDLN *cmdln, U64 idx){ - CMDLN_Flag *result = 0; - if (idx < cmdln->flag_count){ - result = cmdln->flags[idx]; - } - return(result); -} - -MR4TH_SYMBOL CMDLN_Params* -cmdln_get_params(CMDLN *cmdln, String8 flagstr, char abbrev){ - CMDLN_Params *result = 0; - for (CMDLN_Node *node = cmdln->first; - node != 0; - node = node->next){ - if (node->params != 0){ - if (str8_match(flagstr, node->string, 0) || - (node->string.size == 1 && node->string.str[0] == (U8)abbrev)){ - result = node->params; - break; - } - } - } - return(result); -} - -MR4TH_SYMBOL B32 -cmdln_has_flag(CMDLN *cmdln, String8 flagstr, char abbrev){ - CMDLN_Params *params = cmdln_get_params(cmdln, flagstr, abbrev); - B32 result = (params != 0); - return(result); -} - -MR4TH_SYMBOL String8 -cmdln_get_str8(CMDLN *cmdln, String8 flagstr, char abbrev){ - CMDLN_Params *params = cmdln_get_params(cmdln, flagstr, abbrev); - String8 result = {0}; - if (params != 0){ - result = params->raw; - } - return(result); -} - -MR4TH_SYMBOL S64 -cmdln_get_s64(CMDLN *cmdln, String8 flagstr, char abbrev){ - String8 str = cmdln_get_str8(cmdln, flagstr, abbrev); - S64 result = cmdln_s64_from_str8(str); - return(result); -} - -MR4TH_SYMBOL F64 -cmdln_get_f64(CMDLN *cmdln, String8 flagstr, char abbrev){ - String8 str = cmdln_get_str8(cmdln, flagstr, abbrev); - F64 result = cmdln_f64_from_str8(str); - return(result); -} - -MR4TH_SYMBOL S64 -cmdln_s64_from_str8(String8 valstr){ - S64 result = s64_from_str8_c_syntax(valstr); - return(result); -} - -MR4TH_SYMBOL F64 -cmdln_f64_from_str8(String8 valstr){ - F64 result = f64_from_str8(valstr); - return(result); -} - -MR4TH_SYMBOL void -cmdln_dump(Arena *arena, String8List *out, CMDLN *cmdln, U32 indent){ - // raw - str8_list_pushf(arena, out, "%Nraw:\n", indent); - for (String8Node *node = cmdln->raw.first; - node != 0; - node = node->next){ - str8_list_pushf(arena, out, "%N%S\n", indent + 1, node->string); - } - - // program - str8_list_pushf(arena, out, "%Nprogram: %S\n", indent, cmdln->program); - - // input nodes - str8_list_pushf(arena, out, "%Nnodes:\n", indent); - for (CMDLN_Node *cmdlnnode = cmdln->first; - cmdlnnode != 0; - cmdlnnode = cmdlnnode->next){ - if (cmdlnnode->params == 0){ - str8_list_pushf(arena, out, "%N[input] %S\n", indent + 1, cmdlnnode->string); - } - else{ - str8_list_pushf(arena, out, "%N[flag ] %S\n", indent + 1, cmdlnnode->string); - for (String8Node *node = cmdlnnode->params->list.first; - node != 0; - node = node->next){ - str8_list_pushf(arena, out, "%N[param] %S\n", indent + 2, node->string); - } - } - } -} diff --git a/mr4th/mr4th_cmdln.h b/mr4th/mr4th_cmdln.h deleted file mode 100644 index 686ae84..0000000 --- a/mr4th/mr4th_cmdln.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef MR4TH_CMDLN_H -#define MR4TH_CMDLN_H - -//////////////////////////////// -// Types: Command Line Parsing - -typedef struct CMDLN_Params{ - String8 raw; - String8List list; -} CMDLN_Params; - -typedef struct CMDLN_Node{ - struct CMDLN_Node *next; - String8 string; - CMDLN_Params *params; - // (params == 0 ) -> 'input' (not a flag) - // (params != 0 ) -> flag - // (params == nil) -> flag has no parameters -} CMDLN_Node; - -typedef CMDLN_Node CMDLN_Flag; - -typedef struct CMDLN{ - String8List raw; - String8 program; - CMDLN_Node *first; - CMDLN_Node *last; - U64 input_count; - U64 flag_count; - CMDLN_Node **inputs; - CMDLN_Node **flags; -} CMDLN; - -//////////////////////////////// -// Functions: Command Line Parsing - -MR4TH_SYMBOL CMDLN* cmdln_from_args(Arena *arena, String8List *args); -MR4TH_SYMBOL CMDLN_Params* cmdln_params_from_string(Arena *arena, String8 flag_param); - -MR4TH_SYMBOL U64 cmdln_input_count(CMDLN *cmdln); -MR4TH_SYMBOL String8 cmdln_input_from_idx(CMDLN *cmdln, U64 idx); - -MR4TH_SYMBOL U64 cmdln_flag_count(CMDLN *cmdln); -MR4TH_SYMBOL CMDLN_Flag* cmdln_flag_from_idx(CMDLN *cmdln, U64 idx); - -MR4TH_SYMBOL CMDLN_Params* cmdln_get_params(CMDLN *cmdln, String8 flagstr, char abbrev); -MR4TH_SYMBOL B32 cmdln_has_flag(CMDLN *cmdln, String8 flagstr, char abbrev); -MR4TH_SYMBOL String8 cmdln_get_str8(CMDLN *cmdln, String8 flagstr, char abbrev); -MR4TH_SYMBOL S64 cmdln_get_s64(CMDLN *cmdln, String8 flagstr, char abbrev); -MR4TH_SYMBOL F64 cmdln_get_f64(CMDLN *cmdln, String8 flagstr, char abbrev); - -MR4TH_SYMBOL S64 cmdln_s64_from_str8(String8 valstr); -MR4TH_SYMBOL F64 cmdln_f64_from_str8(String8 valstr); - -MR4TH_SYMBOL void cmdln_dump(Arena *arena, String8List *out, CMDLN *cmdln, U32 indent); - -/* TODO: -** [ ] fuzz -** [ ] built in parser diagnostics -** [ ] built in misuse feedback -** [ ] help structurer -*/ - -#endif //MR4TH_CMDLN_H diff --git a/mr4th/mr4th_elf.c b/mr4th/mr4th_elf.c deleted file mode 100644 index fa701cc..0000000 --- a/mr4th/mr4th_elf.c +++ /dev/null @@ -1,480 +0,0 @@ -//////////////////////////////// -// Functions: ELF - -// normalizing - -MR4TH_SYMBOL_STATIC U16 -elf_u16_decode(void *ptr, B32 flip){ - U16 result = 0; - if (flip){ - U8 *buf = (U8*)ptr; - result = buf[1] | (buf[0] << 8); - } - else{ - result = *(U16*)ptr; - } - return(result); -} - -MR4TH_SYMBOL_STATIC U32 -elf_u32_decode(void *ptr, B32 flip){ - U32 result = 0; - if (flip){ - U8 *buf = (U8*)ptr; - result = buf[3] | (buf[2] << 8) | (buf[1] << 16) | (buf[0] << 24); - } - else{ - result = *(U32*)ptr; - } - return(result); -} - -MR4TH_SYMBOL_STATIC U64 -elf_u64_decode(void *ptr, B32 flip){ - U64 result = 0; - if (flip){ - U8 *buf = (U8*)ptr; - result = ((((U64)buf[7]) << 0) | (((U64)buf[6]) << 8) | - (((U64)buf[5]) << 16) | (((U64)buf[4]) << 24) | - (((U64)buf[3]) << 32) | (((U64)buf[2]) << 40) | - (((U64)buf[1]) << 48) | (((U64)buf[0]) << 56)); - } - else{ - result = *(U64*)ptr; - } - return(result); -} - -MR4TH_SYMBOL_STATIC void -elf_header64_from_header32(ELF_Header64 *dst, ELF_Header32 *src, ELF_Encoding src_encoding){ - B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB); - B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN); - - MemoryCopyArray(dst->ident, src->ident); - dst->type = elf_u16_decode(&src->type, flip_order); - dst->machine = elf_u16_decode(&src->machine, flip_order); - dst->version = elf_u32_decode(&src->version, flip_order); - dst->entry = (U64)elf_u32_decode(&src->entry, flip_order); - dst->segment_table_foff = (U64)elf_u32_decode(&src->segment_table_foff, flip_order); - dst->section_table_foff = (U64)elf_u32_decode(&src->section_table_foff, flip_order); - dst->flags = elf_u32_decode(&src->flags, flip_order); - dst->header_size = elf_u16_decode(&src->header_size, flip_order); - dst->segment_size = elf_u16_decode(&src->segment_size, flip_order); - dst->segment_count = elf_u16_decode(&src->segment_count, flip_order); - dst->section_size = elf_u16_decode(&src->section_size, flip_order); - dst->section_count = elf_u16_decode(&src->section_count, flip_order); - dst->string_section_index = elf_u16_decode(&src->string_section_index, flip_order); -} - -MR4TH_SYMBOL_STATIC void -elf_header64_from_header64(ELF_Header64 *dst, ELF_Header64 *src, ELF_Encoding src_encoding){ - B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB); - B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN); - - if (!flip_order){ - MemoryCopyStruct(dst, src); - } - else{ - MemoryCopyArray(dst->ident, src->ident); - dst->type = elf_u16_decode(&src->type, 1); - dst->machine = elf_u16_decode(&src->machine, 1); - dst->version = elf_u32_decode(&src->version, 1); - dst->entry = elf_u32_decode(&src->entry, 1); - dst->segment_table_foff = elf_u32_decode(&src->segment_table_foff, 1); - dst->section_table_foff = elf_u32_decode(&src->section_table_foff, 1); - dst->flags = elf_u32_decode(&src->flags, 1); - dst->header_size = elf_u16_decode(&src->header_size, 1); - dst->segment_size = elf_u16_decode(&src->segment_size, 1); - dst->segment_count = elf_u16_decode(&src->segment_count, 1); - dst->section_size = elf_u16_decode(&src->section_size, 1); - dst->section_count = elf_u16_decode(&src->section_count, 1); - dst->string_section_index = elf_u16_decode(&src->string_section_index, 1); - } -} - -MR4TH_SYMBOL_STATIC void -elf_section64_from_section32(ELF_Section64 *dst, ELF_Section32 *src, ELF_Encoding src_encoding){ - B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB); - B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN); - - dst->name = elf_u32_decode(&src->name, flip_order); - dst->type = elf_u32_decode(&src->type, flip_order); - dst->flags = elf_u32_decode(&src->flags, flip_order); - dst->addr = elf_u32_decode(&src->addr, flip_order); - dst->offset = elf_u32_decode(&src->offset, flip_order); - dst->size = elf_u32_decode(&src->size, flip_order); - dst->link = elf_u32_decode(&src->link, flip_order); - dst->info = elf_u32_decode(&src->info, flip_order); - dst->addralign = elf_u32_decode(&src->addralign, flip_order); - dst->entsize = elf_u32_decode(&src->entsize, flip_order); -} - -MR4TH_SYMBOL_STATIC void -elf_section64_from_section64(ELF_Section64 *dst, ELF_Section64 *src, ELF_Encoding src_encoding){ - B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB); - B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN); - - if (!flip_order){ - MemoryCopyStruct(dst, src); - } - else{ - dst->name = elf_u32_decode(&src->name, 1); - dst->type = elf_u32_decode(&src->type, 1); - dst->flags = elf_u64_decode(&src->flags, 1); - dst->addr = elf_u64_decode(&src->addr, 1); - dst->offset = elf_u64_decode(&src->offset, 1); - dst->size = elf_u64_decode(&src->size, 1); - dst->link = elf_u32_decode(&src->link, 1); - dst->info = elf_u32_decode(&src->info, 1); - dst->addralign = elf_u64_decode(&src->addralign, 1); - dst->entsize = elf_u64_decode(&src->entsize, 1); - } -} - -MR4TH_SYMBOL_STATIC void -elf_segment64_from_segment32(ELF_Segment64 *dst, ELF_Segment32 *src, ELF_Encoding src_encoding){ - B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB); - B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN); - - dst->type = elf_u32_decode(&src->type, flip_order); - dst->offset = elf_u32_decode(&src->offset, flip_order); - dst->vaddr = elf_u32_decode(&src->vaddr, flip_order); - dst->paddr = elf_u32_decode(&src->paddr, flip_order); - dst->file_size = elf_u32_decode(&src->file_size, flip_order); - dst->memory_size = elf_u32_decode(&src->memory_size, flip_order); - dst->flags = elf_u32_decode(&src->flags, flip_order); - dst->align = elf_u32_decode(&src->align, flip_order); -} - -MR4TH_SYMBOL_STATIC void -elf_segment64_from_segment64(ELF_Segment64 *dst, ELF_Segment64 *src, ELF_Encoding src_encoding){ - B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB); - B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN); - - if (!flip_order){ - MemoryCopyStruct(dst, src); - } - else{ - dst->type = elf_u32_decode(&src->type, 1); - dst->flags = elf_u32_decode(&src->flags, 1); - dst->offset = elf_u64_decode(&src->offset, 1); - dst->vaddr = elf_u64_decode(&src->vaddr, 1); - dst->paddr = elf_u64_decode(&src->paddr, 1); - dst->file_size = elf_u64_decode(&src->file_size, 1); - dst->memory_size = elf_u64_decode(&src->memory_size, 1); - dst->align = elf_u64_decode(&src->align, 1); - } -} - -MR4TH_SYMBOL_STATIC void -elf_symbol64_from_symbol32(ELF_Symbol64 *dst, ELF_Symbol32 *src, ELF_Encoding src_encoding){ - B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB); - B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN); - - dst->name = elf_u32_decode(&src->name, flip_order); - dst->value = elf_u32_decode(&src->value, flip_order); - dst->size = elf_u32_decode(&src->size, flip_order); - dst->info = src->info; - dst->other = src->other; - dst->section_index = elf_u16_decode(&src->section_index, flip_order); -} - -MR4TH_SYMBOL_STATIC void -elf_symbol64_from_symbol64(ELF_Symbol64 *dst, ELF_Symbol64 *src, ELF_Encoding src_encoding){ - B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB); - B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN); - - if (!flip_order){ - MemoryCopyStruct(dst, src); - } - else{ - dst->name = elf_u32_decode(&src->name, 1); - dst->info = src->info; - dst->other = src->other; - dst->section_index = elf_u16_decode(&src->section_index, 1); - dst->value = elf_u64_decode(&src->value, 1); - dst->size = elf_u64_decode(&src->size, 1); - } -} - -MR4TH_SYMBOL_STATIC void -elf_reloca64_from_reloc32(ELF_RelocationAdd64 *dst, ELF_Relocation32 *src, ELF_Encoding src_encoding){ - B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB); - B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN); - dst->offset = elf_u32_decode(&src->offset, flip_order); - dst->info = elf_u32_decode(&src->info, flip_order); - dst->addend = 0; -} - -MR4TH_SYMBOL_STATIC void -elf_reloca64_from_reloc64(ELF_RelocationAdd64 *dst, ELF_Relocation64 *src, ELF_Encoding src_encoding){ - B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB); - B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN); - dst->offset = elf_u64_decode(&src->offset, flip_order); - dst->info = elf_u64_decode(&src->info, flip_order); - dst->addend = 0; -} - -MR4TH_SYMBOL_STATIC void -elf_reloca64_from_reloca32(ELF_RelocationAdd64 *dst, ELF_RelocationAdd32 *src, ELF_Encoding src_encoding){ - B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB); - B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN); - dst->offset = elf_u32_decode(&src->offset, flip_order); - dst->info = elf_u32_decode(&src->info, flip_order); - dst->addend = (S32)elf_u32_decode(&src->addend, flip_order); -} - -MR4TH_SYMBOL_STATIC void -elf_reloca64_from_reloca64(ELF_RelocationAdd64 *dst, ELF_RelocationAdd64 *src, ELF_Encoding src_encoding){ - B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB); - B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN); - dst->offset = elf_u64_decode(&src->offset, flip_order); - dst->info = elf_u64_decode(&src->info, flip_order); - dst->addend = (S64)elf_u64_decode(&src->addend, flip_order); -} - -// strings - -MR4TH_SYMBOL_STATIC String8 -elf_str8_from_identification_idx(ELF_IdentificationIdx idx){ - String8 result = str8_lit("ERROR"); - switch (idx){ -#define X(N,C) case C: result = str8_lit(#N); break; - ELF_IdentificationIdx_XList(X) -#undef X - } - return(result); -} - -MR4TH_SYMBOL_STATIC String8 -elf_str8_from_class(ELF_Class elf_class){ - String8 result = str8_lit("ERROR"); - switch (elf_class){ -#define X(N,C) case C: result = str8_lit(#N); break; - ELF_Class_XList(X) -#undef X - } - return(result); -} - -MR4TH_SYMBOL_STATIC String8 -elf_str8_from_encoding(ELF_Encoding elf_encoding){ - String8 result = str8_lit("ERROR"); - switch (elf_encoding){ -#define X(N,C) case C: result = str8_lit(#N); break; - ELF_Encoding_XList(X) -#undef X - } - return(result); -} - -MR4TH_SYMBOL_STATIC String8 -elf_str8_from_osabi(ELF_OsAbiExtension elf_osabi){ - String8 result = str8_lit("ERROR"); - switch (elf_osabi){ -#define X(N,C) case C: result = str8_lit(#N); break; - ELF_OsAbiExtension_XList(X) -#undef X - } - return(result); -} - -MR4TH_SYMBOL_STATIC String8 -elf_str8_from_file_type(ELF_FileType file_type){ - String8 result = str8_lit("ERROR"); - switch (file_type){ -#define X(N,C) case C: result = str8_lit(#N); break; - ELF_FileType_XList(X) -#undef X - } - return(result); -} - -MR4TH_SYMBOL_STATIC String8 -elf_str8_from_machine_type(ELF_FileType machine_type){ - String8 result = str8_lit("ERROR"); - switch (machine_type){ -#define X(N,C) case C: result = str8_lit(#N); break; - ELF_MachineType_XList(X) -#undef X - } - return(result); -} - -MR4TH_SYMBOL_STATIC String8 -elf_str8_from_section_type(ELF_SectionType section_type){ - String8 result = str8_lit("ERROR"); - - if (ELF_SectionType_LOOS <= section_type && - section_type <= ELF_SectionType_HIOS){ - result = str8_lit("OS-CUSTOM-TYPE"); - } - - else if (ELF_SectionType_LOPROC <= section_type && - section_type <= ELF_SectionType_HIPROC){ - result = str8_lit("PROC-CUSTOM-TYPE"); - } - - else if (ELF_SectionType_LOUSER <= section_type && - section_type <= ELF_SectionType_HIUSER){ - result = str8_lit("USER-CUSTOM-TYPE"); - } - - else{ - switch (section_type){ -#define X(N,C) case C: result = str8_lit(#N); break; - ELF_SectionType_XList(X) -#undef X - } - } - - return(result); -} - -MR4TH_SYMBOL_STATIC void -elf_str8list_from_section_flags(Arena *arena, String8List *out, U32 flags){ - U32 f = 1; - for (U32 i = 0; i < 20; i += 1){ - if ((flags & f) != 0){ - switch (f){ -#define X(N,C) case C: str8_list_push(arena, out, str8_lit(#N)); break; - ELF_SectionFlags_XList(X) -#undef X - } - } - f <<= 1; - } - if ((flags & ELF_SectionFlag_MASKOS) != 0){ - str8_list_pushf(arena, out, "OS-CUSTOM(%02x)", (flags >> 20)&0xFF); - } - if ((flags & ELF_SectionFlag_MASKPROC) != 0){ - str8_list_pushf(arena, out, "PROC-CUSTOM(%01x)", (flags >> 28)&0xF); - } -} - -MR4TH_SYMBOL_STATIC String8 -elf_str8_from_section_flags(Arena *arena, U32 flags){ - ArenaTemp scratch = arena_get_scratch(&arena, 1); - String8List list = {0}; - elf_str8list_from_section_flags(scratch.arena, &list, flags); - String8 result = str8_join_flags(arena, &list); - arena_release_scratch(&scratch); - return(result); -} - -MR4TH_SYMBOL_STATIC String8 -elf_str8_from_segment_type(ELF_SegmentType segment_type){ - String8 result = str8_lit("ERROR"); - - if (ELF_SegmentType_LOOS <= segment_type && - segment_type <= ELF_SegmentType_HIOS){ - result = str8_lit("OS-CUSTOM-TYPE"); - } - - else if (ELF_SegmentType_LOPROC <= segment_type && - segment_type <= ELF_SegmentType_HIPROC){ - result = str8_lit("PROC-CUSTOM-TYPE"); - } - - else{ - switch (segment_type){ -#define X(N,C) case C: result = str8_lit(#N); break; - ELF_SegmentType_XList(X) -#undef X - } - } - - return(result); -} - -MR4TH_SYMBOL_STATIC void -elf_str8list_from_segment_flags(Arena *arena, String8List *out, ELF_SegmentFlags flags){ - U32 f = 1; - for (U32 i = 0; i < 20; i += 1){ - if ((flags & f) != 0){ - switch (f){ -#define X(N,C) case C: str8_list_push(arena, out, str8_lit(#N)); break; - ELF_SegmentFlags_XList(X) -#undef X - } - } - f <<= 1; - } - if ((flags & ELF_SegmentFlag_MASKOS) != 0){ - str8_list_pushf(arena, out, "OS-CUSTOM(%02x)", (flags >> 20)&0xFF); - } - if ((flags & ELF_SegmentFlag_MASKPROC) != 0){ - str8_list_pushf(arena, out, "PROC-CUSTOM(%01x)", (flags >> 28)&0xF); - } -} - -MR4TH_SYMBOL_STATIC String8 -elf_str8_from_segment_flags(Arena *arena, ELF_SegmentFlags flags){ - ArenaTemp scratch = arena_get_scratch(&arena, 1); - String8List list = {0}; - elf_str8list_from_segment_flags(scratch.arena, &list, flags); - String8 result = str8_join_flags(arena, &list); - arena_release_scratch(&scratch); - return(result); -} - -MR4TH_SYMBOL_STATIC String8 -elf_str8_from_symbol_binding(ELF_SymbolBinding bind){ - String8 result = str8_lit("ERROR"); - - if (ELF_SymbolBinding_LOOS <= bind && - bind <= ELF_SymbolBinding_HIOS){ - result = str8_lit("OS-CUSTOM-TYPE"); - } - - else if (ELF_SymbolBinding_LOPROC <= bind && - bind <= ELF_SymbolBinding_HIPROC){ - result = str8_lit("PROC-CUSTOM-TYPE"); - } - - else{ - switch (bind){ -#define X(N,C) case C: result = str8_lit(#N); break; - ELF_SymbolBinding_XList(X) -#undef X - } - } - - return(result); -} - -MR4TH_SYMBOL_STATIC String8 -elf_str8_from_symbol_type(ELF_SymbolType type){ - String8 result = str8_lit("ERROR"); - - if (ELF_SymbolType_LOOS <= type && - type <= ELF_SymbolType_HIOS){ - result = str8_lit("OS-CUSTOM-TYPE"); - } - - else if (ELF_SymbolType_LOPROC <= type && - type <= ELF_SymbolType_HIPROC){ - result = str8_lit("PROC-CUSTOM-TYPE"); - } - - else{ - switch (type){ -#define X(N,C) case C: result = str8_lit(#N); break; - ELF_SymbolType_XList(X) -#undef X - } - } - - return(result); -} - -MR4TH_SYMBOL_STATIC String8 -elf_str8_from_symbol_vis(ELF_SymbolVis vis){ - String8 result = str8_lit("ERROR"); - switch (vis){ -#define X(N,C) case C: result = str8_lit(#N); break; - ELF_SymbolVis_XList(X) -#undef X - } - return(result); -} diff --git a/mr4th/mr4th_elf.h b/mr4th/mr4th_elf.h deleted file mode 100644 index c96e692..0000000 --- a/mr4th/mr4th_elf.h +++ /dev/null @@ -1,710 +0,0 @@ -#ifndef MR4TH_ELF_H -#define MR4TH_ELF_H - -/* -** ELF total layout summary: -** -** TODO -*/ - -//////////////////////////////// -// Types: ELF - -// identification - -#define ELF_NUM_IDENT 16 - -#define ELF_IdentificationIdx_XList(X)\ -X(MAG0, 0)\ -X(MAG1, 1)\ -X(MAG2, 2)\ -X(MAG3, 3)\ -X(CLASS, 4)\ -X(DATA, 5)\ -X(VERSION, 6)\ -X(OSABI, 7)\ -X(ABIVERSION, 8)\ -X(PAD0, 9)\ -X(PAD1, 10)\ -X(PAD2, 11)\ -X(PAD3, 12)\ -X(PAD4, 13)\ -X(PAD5, 14)\ -X(PAD6, 15) - -typedef enum ELF_IdentificationIdx{ -#define X(N,C) ELF_IdentificationIdx_##N = C, - ELF_IdentificationIdx_XList(X) -#undef X -} ELF_IdentificationIdx; - -#define ELF_Magic_Byte0 0x7F -#define ELF_Magic_Byte1 'E' -#define ELF_Magic_Byte2 'L' -#define ELF_Magic_Byte3 'F' - -// elf class - -#define ELF_Class_XList(X)\ -X(NONE, 0)\ -X(32, 1)\ -X(64, 2) - -typedef enum ELF_Class{ -#define X(N,C) ELF_Class_##N = C, - ELF_Class_XList(X) -#undef X -} ELF_Class; - -// elf encoding - -#define ELF_Encoding_XList(X)\ -X(NONE, 0)\ -X(2LSB, 1)\ -X(2MSB, 2) - -typedef enum ELF_Encoding{ -#define X(N,C) ELF_Encoding_##N = C, - ELF_Encoding_XList(X) -#undef X -} ELF_Encoding; - -// elf os/abi extension - -#define ELF_OsAbiExtension_XList(X)\ -X(NONE, 0)\ -X(HPUX, 1)\ -X(NETBSD, 2)\ -X(GNU, 3)\ -X(SOLARIS, 6)\ -X(AIX, 7)\ -X(IRIX, 8)\ -X(FREEBSD, 9)\ -X(TRU64, 10)\ -X(MODESTO, 11)\ -X(OPENBSD, 12)\ -X(OPENVMS, 13)\ -X(NSK, 14)\ -X(AROS, 15)\ -X(FENIXOS, 16)\ -X(CLOUDABI, 17)\ -X(OPENVOS, 18) - -typedef enum ELF_OsAbiExtension{ -#define X(N,C) ELF_OsAbiExtension_##N = C, - ELF_OsAbiExtension_XList(X) -#undef X -} ELF_OsAbiExtension; - -// file type - -#define ELF_FileType_XList(X)\ -X(NONE, 0)\ -X(REL, 1)\ -X(EXEC, 2)\ -X(DYN, 3)\ -X(CORE, 4)\ -X(LOOS, 0xfe00)\ -X(HIOS, 0xfeff)\ -X(LOPROC, 0xff00)\ -X(HIPROC, 0xffff) - -typedef U16 ELF_FileType; -enum{ -#define X(N,C) ELF_FileType_##N = C, - ELF_FileType_XList(X) -#undef X -}; - -// machine type - -#define ELF_MachineType_XList(X)\ -X(NONE, 0)\ -X(M32, 1)\ -X(SPARC, 2)\ -X(386, 3)\ -X(68K, 4)\ -X(88K, 5)\ -X(IAMCU, 6)\ -X(860, 7)\ -X(MIPS, 8)\ -X(S370, 9)\ -X(MIPS_RS3_LE, 10)\ -X(PARISC, 15)\ -X(VPP500, 17)\ -X(SPARC32PLUS, 18)\ -X(960, 19)\ -X(PPC, 20)\ -X(PPC64, 21)\ -X(S390, 22)\ -X(SPU, 23)\ -X(V800, 36)\ -X(FR20, 37)\ -X(RH32, 38)\ -X(RCE, 39)\ -X(ARM, 40)\ -X(ALPHA, 41)\ -X(SH, 42)\ -X(SPARCV9, 43)\ -X(TRICORE, 44)\ -X(ARC, 45)\ -X(H8_300, 300)\ -X(H8S, 48)\ -X(H8_500, 49)\ -X(IA_64, 50)\ -X(MIPS_X, 51)\ -X(COLDFIRE, 52)\ -X(68HC12, 53)\ -X(MMA, 54)\ -X(PCP, 55)\ -X(NCPU, 56)\ -X(NDR1, 57)\ -X(STARCORE, 58)\ -X(ME16, 59)\ -X(ST100, 60)\ -X(TINYJ, 61)\ -X(X86_64, 62)\ -X(PDSP, 63)\ -X(PDP10, 64)\ -X(PDP11, 65)\ -X(FX66, 66)\ -X(ST9PLUS, 67)\ -X(ST7, 68)\ -X(68HC16, 69)\ -X(68HC11, 70)\ -X(68HC08, 71)\ -X(68HC05, 72)\ -X(SVX, 73)\ -X(ST19, 74)\ -X(VAX, 75)\ -X(CRIS, 76)\ -X(JAVELIN, 77)\ -X(FIREPATH, 78)\ -X(ZSP, 79)\ -X(MMIX, 80)\ -X(HUANY, 81)\ -X(PRISM, 82)\ -X(AVR, 83)\ -X(FR30, 84)\ -X(D10V, 85)\ -X(D30V, 86)\ -X(V850, 87)\ -X(M32R, 88)\ -X(MN10300, 89)\ -X(MN10200, 90)\ -X(PJ, 91)\ -X(OPENRISC, 92)\ -X(ARC_COMPACT, 93)\ -X(XTENSA, 94)\ -X(VIDEOCORE, 95)\ -X(TMM_GPP, 96)\ -X(NS32K, 97)\ -X(TPC, 98)\ -X(SNP1K, 99)\ -X(ST200, 100)\ -X(IP2K, 101)\ -X(MAX, 102)\ -X(CR, 103)\ -X(F2MC16, 104)\ -X(MSP430, 105)\ -X(BLACKFIN, 106)\ -X(SE_C33, 107)\ -X(SEP, 108)\ -X(ARCA, 109)\ -X(UNICORE, 110)\ -X(EXCESS, 111)\ -X(DXP, 112)\ -X(ALTERA_NIOS2, 113)\ -X(CRX, 114)\ -X(XGATE, 115)\ -X(C166, 116)\ -X(M16C, 117)\ -X(DSPIC30F, 118)\ -X(CE, 119)\ -X(M32C, 120)\ -X(TSK3000, 131)\ -X(RS08, 132)\ -X(SHARC, 133)\ -X(ECOG2, 134)\ -X(SCORE7, 135)\ -X(DSP24, 136)\ -X(VIDEOCORE3, 137)\ -X(LATTICEMICO32, 138)\ -X(SE_C17, 139)\ -X(TI_C6000, 140)\ -X(TI_C2000, 141)\ -X(TI_C5500, 142)\ -X(TI_ARP32, 143)\ -X(TI_PRU, 144)\ -X(MMDSP_PLUS, 160)\ -X(CYPRESS_M8C, 161)\ -X(R32C, 162)\ -X(TRIMEDIA, 163)\ -X(QDSP6, 164)\ -X(8051, 165)\ -X(STXP7X, 166)\ -X(NDS32, 167)\ -X(ECOG1, 168)\ -X(MAXQ30, 169)\ -X(XIMO16, 170)\ -X(MANIK, 171)\ -X(CRAYNV2, 172)\ -X(RX, 173)\ -X(METAG, 174)\ -X(MCST_ELBRUS, 175)\ -X(ECOG16, 176)\ -X(CR16, 177)\ -X(ETPU, 178)\ -X(SLE9X, 179)\ -X(L10M, 180)\ -X(K10M, 181)\ -X(AARCH64, 183)\ -X(AVR32, 185)\ -X(STM8, 186)\ -X(TILE64, 187)\ -X(TILEPRO, 188)\ -X(MICROBLAZE, 189)\ -X(CUDA, 190)\ -X(TILEGX, 191)\ -X(CLOUDSHIELD, 192)\ -X(COREA_1ST, 193)\ -X(COREA_2ND, 194)\ -X(ARC_COMPACT2, 195)\ -X(OPEN8, 196)\ -X(RL78, 197)\ -X(VIDEOCORE5, 198)\ -X(78KOR, 199)\ -X(56800EX, 200)\ -X(BA1, 201)\ -X(BA2, 202)\ -X(XCORE, 203)\ -X(MCHP_PIC, 204)\ -X(INTEL205, 205)\ -X(INTEL206, 206)\ -X(INTEL207, 207)\ -X(INTEL208, 208)\ -X(INTEL209, 209)\ -X(KM32, 210)\ -X(KMX32, 211)\ -X(KMX16, 212)\ -X(KMX8, 213)\ -X(KVARC, 214)\ -X(CDP, 215)\ -X(COGE, 216)\ -X(COOL, 217)\ -X(NORC, 218)\ -X(CSR_KALIMBA, 219)\ -X(Z80, 220)\ -X(VISIUM, 221)\ -X(FT32, 222)\ -X(MOXIE, 223)\ -X(AMDGPU, 224)\ -X(RISCV, 243) - -typedef U16 ELF_MachineType; -enum{ -#define X(N,C) ELF_MachineType_##N = C, - ELF_MachineType_XList(X) -#undef X -}; - -// elf header - -typedef struct ELF_Header32{ - U8 ident[ELF_NUM_IDENT]; - ELF_FileType type; - ELF_MachineType machine; - U32 version; - U32 entry; - U32 segment_table_foff; - U32 section_table_foff; - U32 flags; - U16 header_size; - U16 segment_size; - U16 segment_count; - U16 section_size; - U16 section_count; - U16 string_section_index; -} ELF_Header32; - -typedef struct ELF_Header64{ - U8 ident[ELF_NUM_IDENT]; - ELF_FileType type; - ELF_MachineType machine; - U32 version; - U64 entry; - U64 segment_table_foff; - U64 section_table_foff; - U32 flags; - U16 header_size; - U16 segment_size; - U16 segment_count; - U16 section_size; - U16 section_count; - U16 string_section_index; -} ELF_Header64; - -// elf section type - -#define ELF_SectionType_XList(X)\ -X(NULL, 0)\ -X(PROGBITS, 1)\ -X(SYMTAB, 2)\ -X(STRTAB, 3)\ -X(RELA, 4)\ -X(HASH, 5)\ -X(DYNAMIC, 6)\ -X(NOTE, 7)\ -X(NOBITS, 8)\ -X(REL, 9)\ -X(SHLIB, 10)\ -X(DYNSYM, 11)\ -X(INIT_ARRAY, 14)\ -X(FINI_ARRAY, 15)\ -X(PREINIT_ARRAY, 16)\ -X(GROUP, 17)\ -X(SYMTAB_SHNDX, 18)\ -X(LOOS, 0x60000000)\ -X(HIOS, 0x6fffffff)\ -X(LOPROC, 0x70000000)\ -X(HIPROC, 0x7fffffff)\ -X(LOUSER, 0x80000000)\ -X(HIUSER, 0xffffffff) - -typedef U32 ELF_SectionType; -enum{ -#define X(N,C) ELF_SectionType_##N = C, - ELF_SectionType_XList(X) -#undef X -}; - -// elf section flags - -#define ELF_SectionFlags_XList(X)\ -X(WRITE, 0x1)\ -X(ALLOC, 0x2)\ -X(EXECINSTR, 0x4)\ -X(MERGE, 0x10)\ -X(STRINGS, 0x20)\ -X(INFO_LINK, 0x40)\ -X(LINK_ORDER, 0x80)\ -X(OS_NONCONFORMING, 0x100)\ -X(GROUP, 0x200)\ -X(TLS, 0x400)\ -X(COMPRESSED, 0x800)\ -X(MASKOS, 0x0ff00000)\ -X(MASKPROC, 0xf0000000) - -enum{ -#define X(N,C) ELF_SectionFlag_##N = C, - ELF_SectionFlags_XList(X) -#undef X -}; - -// elf section indexes - -#define ELF_SectionIndex_XList(X)\ -X(UNDEF, 0)\ -X(LORESERVE, 0xff00)\ -X(LOPROC, 0xff00)\ -X(HIPROC, 0xff1f)\ -X(LOOS, 0xff20)\ -X(HIOS, 0xff3f)\ -X(ABS, 0xfff1)\ -X(COMMON, 0xfff2)\ -X(XINDEX, 0xffff)\ -X(HIRESERVE, 0xffff) - -typedef enum ELF_SectionIndex{ -#define X(N,C) ELF_SectionIndex_##N = C, - ELF_SectionIndex_XList(X) -#undef X -} ELF_SectionIndex; - - -// elf section - -typedef struct ELF_Section32{ - U32 name; - ELF_SectionType type; - U32 flags; - U32 addr; - U32 offset; - U32 size; - U32 link; - U32 info; - U32 addralign; - U32 entsize; -} ELF_Section32; - -typedef struct ELF_Section64{ - U32 name; - ELF_SectionType type; - U64 flags; - U64 addr; - U64 offset; - U64 size; - U32 link; - U32 info; - U64 addralign; - U64 entsize; -} ELF_Section64; - -// elf compression type - -#define ELF_CompressionType_XList(X)\ -X(ZLIB, 1)\ -X(LOOS, 0x60000000)\ -X(HIOS, 0x6fffffff)\ -X(LOPROC, 0x70000000)\ -X(HIPROC, 0x7fffffff) - -typedef enum ELF_CompressionType{ -#define X(N,C) ELF_CompressionType_##N = C, - ELF_CompressionType_XList(X) -#undef X -} ELF_CompressionType; - -// elf compression header - -typedef struct ELF_CompressionHeader32{ - ELF_CompressionType type; - U32 size; - U32 addralign; -} ELF_CompressionHeader32; - -typedef struct ELF_CompressionHeader64{ - ELF_CompressionType type; - U32 reserved; - U64 size; - U64 addralign; -} ELF_CompressionHeader64; - -// elf section group flags - -#define ELF_SectionGroupFlags_XList(X)\ -X(COMDAT, 0x1)\ -X(MASKOS, 0x0ff00000)\ -X(MASKPROC, 0xf0000000) - -typedef U32 ELF_SectionGroupFlags; -enum{ -#define X(N,C) ELF_SectionGroupFlag_##N = C, - ELF_SectionGroupFlags_XList(X) -#undef X -}; - -// elf symbol - -typedef struct ELF_Symbol32{ - U32 name; - U32 value; - U32 size; - U8 info; - U8 other; - U16 section_index; -} ELF_Symbol32; - -typedef struct ELF_Symbol64{ - U32 name; - U8 info; - U8 other; - U16 section_index; - U64 value; - U64 size; -} ELF_Symbol64; - -#define ELF_Symbol_BindFromInfo(inf) ((inf)>>4) -#define ELF_Symbol_TypeFromInfo(inf) ((inf)&0xF) -#define ELF_Symbol_InfoFromBindType(bin,typ) (((bin)<<4)|((type)&0xF)) - -#define ELF_Symbol_VisFromOther(oth) ((oth)&0x3) -#define ELF_Symbol_OtherFromVis(vis) (((vis)&0x3)) - -// elf symbol binding - -#define ELF_SymbolBinding_XList(X)\ -X(LOCAL, 0)\ -X(GLOBAL, 1)\ -X(WEAK, 2)\ -X(LOOS, 10)\ -X(HIOS, 12)\ -X(LOPROC, 13)\ -X(HIPROC, 15) - -typedef enum ELF_SymbolBinding{ -#define X(N,C) ELF_SymbolBinding_##N = C, - ELF_SymbolBinding_XList(X) -#undef X -} ELF_SymbolBinding; - -// elf symbol types - -#define ELF_SymbolType_XList(X)\ -X(NOTYPE, 0)\ -X(OBJECT, 1)\ -X(FUNC, 2)\ -X(SECTION, 3)\ -X(FILE, 4)\ -X(COMMON, 5)\ -X(TLS, 6)\ -X(LOOS, 10)\ -X(HIOS, 12)\ -X(LOPROC, 13)\ -X(HIPROC, 15) - -typedef enum ELF_SymbolType{ -#define X(N,C) ELF_SymbolType_##N = C, - ELF_SymbolType_XList(X) -#undef X -} ELF_SymbolType; - -// elf symbol visibility - -#define ELF_SymbolVis_XList(X)\ -X(DEFAULT, 0)\ -X(INTERNAL, 1)\ -X(HIDDEN, 2)\ -X(PROTECTED, 3) - -typedef enum ELF_SymbolVis{ -#define X(N,C) ELF_SymbolVis_##N = C, - ELF_SymbolVis_XList(X) -#undef X -} ELF_SymbolVis; - -// elf relocations - -typedef struct ELF_Relocation32{ - U32 offset; - U32 info; -} ELF_Relocation32; - -typedef struct ELF_RelocationAdd32{ - U32 offset; - U32 info; - S32 addend; -} ELF_RelocationAdd32; - -typedef struct ELF_Relocation64{ - U64 offset; - U64 info; -} ELF_Relocation64; - -typedef struct ELF_RelocationAdd64{ - U64 offset; - U64 info; - S64 addend; -} ELF_RelocationAdd64; - -// elf segment type - -#define ELF_SegmentType_XList(X)\ -X(NULL, 0)\ -X(LOAD, 1)\ -X(DYNAMIC, 2)\ -X(INTERP, 3)\ -X(NOTE, 4)\ -X(SHLIB, 5)\ -X(PHDR, 6)\ -X(TLS, 7)\ -X(LOOS, 0x60000000)\ -X(HIOS, 0x6fffffff)\ -X(LOPROC, 0x70000000)\ -X(HIPROC, 0x7fffffff) - -typedef U32 ELF_SegmentType; -enum{ -#define X(N,C) ELF_SegmentType_##N = C, - ELF_SegmentType_XList(X) -#undef X -}; - -// elf segment flags - -#define ELF_SegmentFlags_XList(X)\ -X(X, 0x1)\ -X(W, 0x2)\ -X(R, 0x4)\ -X(MASKOS, 0x0ff00000)\ -X(MASKPROC, 0xf0000000)\ - -typedef U32 ELF_SegmentFlags; -enum{ -#define X(N,C) ELF_SegmentFlag_##N = C, - ELF_SegmentFlags_XList(X) -#undef X -}; - -// elf segment - -typedef struct ELF_Segment32{ - ELF_SegmentType type; - U32 offset; - U32 vaddr; - U32 paddr; - U32 file_size; - U32 memory_size; - ELF_SegmentFlags flags; - U32 align; -} ELF_Segment32; - -typedef struct ELF_Segment64{ - ELF_SegmentType type; - ELF_SegmentFlags flags; - U64 offset; - U64 vaddr; - U64 paddr; - U64 file_size; - U64 memory_size; - U64 align; -} ELF_Segment64; - -//////////////////////////////// -// Functions: ELF - -// normalizing - -MR4TH_SYMBOL_STATIC U16 elf_u16_decode(void *ptr, B32 flip); -MR4TH_SYMBOL_STATIC U32 elf_u32_decode(void *ptr, B32 flip); -MR4TH_SYMBOL_STATIC U64 elf_u64_decode(void *ptr, B32 flip); - -MR4TH_SYMBOL_STATIC void elf_header64_from_header32(ELF_Header64 *dst, ELF_Header32 *src, ELF_Encoding src_encoding); -MR4TH_SYMBOL_STATIC void elf_header64_from_header64(ELF_Header64 *dst, ELF_Header64 *src, ELF_Encoding src_encoding); - -MR4TH_SYMBOL_STATIC void elf_section64_from_section32(ELF_Section64 *dst, ELF_Section32 *src, ELF_Encoding src_encoding); -MR4TH_SYMBOL_STATIC void elf_section64_from_section64(ELF_Section64 *dst, ELF_Section64 *src, ELF_Encoding src_encoding); - -MR4TH_SYMBOL_STATIC void elf_segment64_from_segment32(ELF_Segment64 *dst, ELF_Segment32 *src, ELF_Encoding src_encoding); -MR4TH_SYMBOL_STATIC void elf_segment64_from_segment64(ELF_Segment64 *dst, ELF_Segment64 *src, ELF_Encoding src_encoding); - -MR4TH_SYMBOL_STATIC void elf_symbol64_from_symbol32(ELF_Symbol64 *dst, ELF_Symbol32 *src, ELF_Encoding src_encoding); -MR4TH_SYMBOL_STATIC void elf_symbol64_from_symbol64(ELF_Symbol64 *dst, ELF_Symbol64 *src, ELF_Encoding src_encoding); - -MR4TH_SYMBOL_STATIC void elf_reloca64_from_reloc32(ELF_RelocationAdd64 *dst, ELF_Relocation32 *src, ELF_Encoding src_encoding); -MR4TH_SYMBOL_STATIC void elf_reloca64_from_reloc64(ELF_RelocationAdd64 *dst, ELF_Relocation64 *src, ELF_Encoding src_encoding); -MR4TH_SYMBOL_STATIC void elf_reloca64_from_reloca32(ELF_RelocationAdd64 *dst, ELF_RelocationAdd32 *src, ELF_Encoding src_encoding); -MR4TH_SYMBOL_STATIC void elf_reloca64_from_reloca64(ELF_RelocationAdd64 *dst, ELF_RelocationAdd64 *src, ELF_Encoding src_encoding); - -// strings - -MR4TH_SYMBOL_STATIC String8 elf_str8_from_identification_idx(ELF_IdentificationIdx idx); -MR4TH_SYMBOL_STATIC String8 elf_str8_from_class(ELF_Class elf_class); -MR4TH_SYMBOL_STATIC String8 elf_str8_from_encoding(ELF_Encoding elf_encoding); -MR4TH_SYMBOL_STATIC String8 elf_str8_from_osabi(ELF_OsAbiExtension elf_osabi); -MR4TH_SYMBOL_STATIC String8 elf_str8_from_file_type(ELF_FileType file_type); -MR4TH_SYMBOL_STATIC String8 elf_str8_from_machine_type(ELF_FileType machine_type); - -MR4TH_SYMBOL_STATIC String8 elf_str8_from_section_type(ELF_SectionType section_type); -MR4TH_SYMBOL_STATIC void elf_str8list_from_section_flags(Arena *arena, String8List *out, U32 flags); -MR4TH_SYMBOL_STATIC String8 elf_str8_from_section_flags(Arena *arena, U32 flags); - -MR4TH_SYMBOL_STATIC String8 elf_str8_from_segment_type(ELF_SegmentType segment_type); -MR4TH_SYMBOL_STATIC void elf_str8list_from_segment_flags(Arena *arena, String8List *out, ELF_SegmentFlags flags); -MR4TH_SYMBOL_STATIC String8 elf_str8_from_segment_flags(Arena *arena, ELF_SegmentFlags flags); - -MR4TH_SYMBOL_STATIC String8 elf_str8_from_symbol_binding(ELF_SymbolBinding bind); -MR4TH_SYMBOL_STATIC String8 elf_str8_from_symbol_type(ELF_SymbolType type); -MR4TH_SYMBOL_STATIC String8 elf_str8_from_symbol_vis(ELF_SymbolVis vis); - -#endif //MR4TH_ELF_H diff --git a/mr4th/mr4th_elf.parse.c b/mr4th/mr4th_elf.parse.c deleted file mode 100644 index 8cc05f0..0000000 --- a/mr4th/mr4th_elf.parse.c +++ /dev/null @@ -1,422 +0,0 @@ -//////////////////////////////// -// Elf Parse Functions - -MR4TH_SYMBOL ELF_Parse* -elfp_begin(Arena *arena, String8 data){ - // magic check - B32 elf_magic = 0; - ELF_Class elf_class = ELF_Class_NONE; - ELF_Encoding elf_encoding = ELF_Encoding_NONE; - U32 elf_version = 0; - ELF_OsAbiExtension elf_ext = ELF_OsAbiExtension_NONE; - B32 good_headers = 0; - if (data.size >= ELF_NUM_IDENT){ - elf_class = data.str[ELF_IdentificationIdx_CLASS]; - elf_encoding = data.str[ELF_IdentificationIdx_DATA]; - elf_version = data.str[ELF_IdentificationIdx_VERSION]; - elf_ext = data.str[ELF_IdentificationIdx_OSABI]; - if (data.str[0] == ELF_Magic_Byte0 && - data.str[1] == ELF_Magic_Byte1 && - data.str[2] == ELF_Magic_Byte2 && - data.str[3] == ELF_Magic_Byte3 && - elf_version == 1 && - (elf_class == ELF_Class_32 || elf_class == ELF_Class_64) && - (elf_encoding == ELF_Encoding_2LSB || - elf_encoding == ELF_Encoding_2MSB)){ - good_headers = 1; - } - } - - // header - void *header = 0; - U64 section_table_foff = 0; - U16 section_count = 0; - U16 section_size = 0; - U64 segment_table_foff = 0; - U16 segment_count = 0; - U16 segment_size = 0; - U16 string_section_index = 0; - - if (good_headers){ - switch (elf_class){ - default:break; - - case ELF_Class_32: { - if (sizeof(ELF_Header32) <= data.size){ - header = data.str; - ELF_Header32 *h = (ELF_Header32*)header; - section_table_foff = h->section_table_foff; - section_count = h->section_count; - section_size = h->section_size; - segment_table_foff = h->segment_table_foff; - segment_count = h->segment_count; - segment_size = h->segment_size; - string_section_index = h->string_section_index; - } - }break; - case ELF_Class_64: { - if (sizeof(ELF_Header64) <= data.size){ - header = data.str; - ELF_Header64 *h = (ELF_Header64*)header; - section_table_foff = h->section_table_foff; - section_count = h->section_count; - section_size = h->section_size; - segment_table_foff = h->segment_table_foff; - segment_count = h->segment_count; - segment_size = h->segment_size; - string_section_index = h->string_section_index; - } - }break; - } - } - - // sections - void *sections = 0; - if (section_count > 0 && section_table_foff + section_count*section_size <= data.size){ - sections = data.str + section_table_foff; - } - - // segments - void *segments = 0; - if (segment_count > 0 && segment_table_foff + segment_count*segment_size <= data.size){ - segments = data.str + segment_table_foff; - } - - // string table - U8 *section_strtable_first = 0; - U8 *section_strtable_opl = 0; - { - U32 index = 0; - if (string_section_index != ELF_SectionIndex_UNDEF && - string_section_index != ELF_SectionIndex_XINDEX){ - index = string_section_index; - } - else if (string_section_index == ELF_SectionIndex_XINDEX){ - switch (elf_class){ - default:break; - case ELF_Class_32: index = ((ELF_Section32*)sections)->link; break; - case ELF_Class_64: index = ((ELF_Section64*)sections)->link; break; - } - } - if (index > 0){ - U64 offset = 0; - U64 size = 0; - switch (elf_class){ - default:break; - case ELF_Class_32: - { - offset = ((ELF_Section32*)sections)[index].offset; - size = ((ELF_Section32*)sections)[index].size; - }break; - case ELF_Class_64: - { - offset = ((ELF_Section64*)sections)[index].offset; - size = ((ELF_Section64*)sections)[index].size; - }break; - } - if (offset < data.size && offset + size < data.size){ - section_strtable_first = data.str + offset; - section_strtable_opl = data.str + offset + size; - } - } - } - - // find symtab & dynsym sections - void *symbols[ELFP_SYMBOL_TABLE_COUNT] = {0}; - U32 symbol_count[ELFP_SYMBOL_TABLE_COUNT] = {0}; - U8 *symbol_strtable_first[ELFP_SYMBOL_TABLE_COUNT] = {0}; - U8 *symbol_strtable_opl[ELFP_SYMBOL_TABLE_COUNT] = {0}; - if (sections != 0){ - for (U32 i = 0; i < section_count; i += 1){ - ELF_SectionType type = 0; - U64 foff = 0; - U64 opl = 0; - switch (elf_class){ - default:break; - case ELF_Class_32: { - ELF_Section32 *sec32 = (ELF_Section32*)sections + i; - type = sec32->type; - foff = sec32->offset; - opl = foff + sec32->size; - }break; - case ELF_Class_64: { - ELF_Section64 *sec64 = (ELF_Section64*)sections + i; - type = sec64->type; - foff = sec64->offset; - opl = foff + sec64->size; - }break; - } - U32 idx = ELFP_SYMBOL_TABLE_COUNT; - switch (type){ - case ELF_SectionType_SYMTAB: idx = ELFP_SYMBOL_TABLE_symtab; break; - case ELF_SectionType_DYNSYM: idx = ELFP_SYMBOL_TABLE_dynsym; break; - } - if (idx < ELFP_SYMBOL_TABLE_COUNT && - foff < data.size && opl < data.size){ - U32 link = 0; - //U32 info = 0; - U32 count = 0; - switch (elf_class){ - default:break; - case ELF_Class_32: { - ELF_Section32 *sec32 = (ELF_Section32*)sections + i; - link = sec32->link; - //info = sec32->info; - count = sec32->size/sizeof(ELF_Symbol32); - }break; - case ELF_Class_64: { - ELF_Section64 *sec64 = (ELF_Section64*)sections + i; - link = sec64->link; - //info = sec64->info; - count = sec64->size/sizeof(ELF_Symbol64); - }break; - } - symbols[idx] = data.str + foff; - symbol_count[idx] = count; - if (link < section_count){ - U64 strtable_off = 0; - U64 strtable_size = 0; - switch (elf_class){ - default:break; - case ELF_Class_32: { - ELF_Section32 *sec32 = (ELF_Section32*)sections + link; - strtable_off = sec32->offset; - strtable_size = sec32->size; - }break; - case ELF_Class_64: { - ELF_Section64 *sec64 = (ELF_Section64*)sections + link; - strtable_off = sec64->offset; - strtable_size = sec64->size; - }break; - } - if (strtable_off < data.size && - strtable_off + strtable_size < data.size){ - symbol_strtable_first[idx] = data.str + strtable_off; - symbol_strtable_opl[idx] = data.str + strtable_off + strtable_size; - } - } - } - } - } - - // fill result - ELF_Parse *elf = 0; - if (header != 0){ - elf = push_array(arena, ELF_Parse, 1); - elf->elf_class = elf_class; - elf->encoding = elf_encoding; - elf->section_count = section_count; - elf->segment_count = segment_count; - elf->header = header; - elf->size = data.size; - elf->sections = sections; - elf->segments = segments; - elf->section_strtable_first = section_strtable_first; - elf->section_strtable_opl = section_strtable_opl; - MemoryCopyArray(elf->symbols, symbols); - MemoryCopyArray(elf->symbol_count, symbol_count); - MemoryCopyArray(elf->symbol_strtable_first, symbol_strtable_first); - MemoryCopyArray(elf->symbol_strtable_opl, symbol_strtable_opl); - } - - return(elf); -} - -MR4TH_SYMBOL void -elfp_header_read(ELF_Parse *elf, ELF_Header64 *out){ - if (elf->header != 0){ - switch (elf->elf_class){ - default:break; - case ELF_Class_32: { - elf_header64_from_header32(out, (ELF_Header32*)elf->header, elf->encoding); - }break; - case ELF_Class_64: { - elf_header64_from_header64(out, (ELF_Header64*)elf->header, elf->encoding); - }break; - } - } -} - -MR4TH_SYMBOL U32 -elfp_section_count(ELF_Parse *elf){ - U32 result = elf->section_count; - return(result); -} - -MR4TH_SYMBOL void -elfp_section_read(ELF_Parse *elf, U32 idx, ELF_Section64 *out){ - if (elf->sections != 0 && idx < elf->section_count){ - switch (elf->elf_class){ - default:break; - case ELF_Class_32: { - elf_section64_from_section32(out, (ELF_Section32*)elf->sections + idx, elf->encoding); - }break; - case ELF_Class_64: { - elf_section64_from_section64(out, (ELF_Section64*)elf->sections + idx, elf->encoding); - }break; - } - } -} - -MR4TH_SYMBOL String8 -elfp_section_name(ELF_Parse *elf, U32 idx){ - String8 result = {0}; - if (elf->sections != 0 && idx < elf->section_count){ - U32 name = 0; - switch (elf->elf_class){ - default:break; - case ELF_Class_32: name = ((ELF_Section32*)elf->sections)[idx].name; break; - case ELF_Class_64: name = ((ELF_Section64*)elf->sections)[idx].name; break; - } - result = str8_cstring_capped(elf->section_strtable_first + name, - elf->section_strtable_opl); - } - return(result); -} - -MR4TH_SYMBOL U32 -elfp_segment_count(ELF_Parse *elf){ - U32 result = elf->segment_count; - return(result); -} - -MR4TH_SYMBOL void -elfp_segment_read(ELF_Parse *elf, U32 idx, ELF_Segment64 *out){ - if (elf->segments != 0 && idx < elf->segment_count){ - switch (elf->elf_class){ - default:break; - case ELF_Class_32: { - elf_segment64_from_segment32(out, (ELF_Segment32*)elf->segments + idx, elf->encoding); - }break; - case ELF_Class_64: { - elf_segment64_from_segment64(out, (ELF_Segment64*)elf->segments + idx, elf->encoding); - }break; - } - } -} - -MR4TH_SYMBOL U32 -elfp_symbol_count(ELF_Parse *elf, U32 table){ - U32 result = 0; - if (table < ELFP_SYMBOL_TABLE_COUNT){ - result = elf->symbol_count[table]; - } - return(result); -} - -MR4TH_SYMBOL void -elfp_symbol_read(ELF_Parse *elf, U32 table, U32 idx, ELF_Symbol64 *out){ - if (table < ELFP_SYMBOL_TABLE_COUNT){ - void *symbols = elf->symbols[table]; - switch (elf->elf_class){ - default:break; - case ELF_Class_32: { - elf_symbol64_from_symbol32(out, (ELF_Symbol32*)symbols + idx, elf->encoding); - }break; - case ELF_Class_64: { - elf_symbol64_from_symbol64(out, (ELF_Symbol64*)symbols + idx, elf->encoding); - }break; - } - } -} - -MR4TH_SYMBOL String8 -elfp_symbol_name(ELF_Parse *elf, U32 table, U32 idx){ - String8 result = {0}; - if (table < ELFP_SYMBOL_TABLE_COUNT){ - void *s = elf->symbols[table]; - U8 *string_table_first = elf->symbol_strtable_first[table]; - U8 *string_table_opl = elf->symbol_strtable_opl[table]; - U32 name = 0; - switch (elf->elf_class){ - default:break; - case ELF_Class_32: name = ((ELF_Symbol32*)s)[idx].name; break; - case ELF_Class_64: name = ((ELF_Symbol64*)s)[idx].name; break; - } - if (string_table_first != 0){ - result = str8_cstring_capped(string_table_first + name, - string_table_opl); - } - } - return(result); -} - -MR4TH_SYMBOL U32 -elfp_relocs_count(ELF_Parse *elf, U32 secidx){ - U32 result = 0; - if (elf->sections != 0 && secidx < elf->section_count){ - switch (elf->elf_class){ - default:break; - case ELF_Class_32: { - ELF_Section32 *sec32 = ((ELF_Section32*)elf->sections) + secidx; - switch (sec32->type){ - case ELF_SectionType_REL: - result = sec32->size/sizeof(ELF_Relocation32); break; - case ELF_SectionType_RELA: - result = sec32->size/sizeof(ELF_RelocationAdd32); break; - } - }break; - case ELF_Class_64: { - ELF_Section64 *sec64 = ((ELF_Section64*)elf->sections) + secidx; - switch (sec64->type){ - case ELF_SectionType_REL: - result = sec64->size/sizeof(ELF_Relocation64); break; - case ELF_SectionType_RELA: - result = sec64->size/sizeof(ELF_RelocationAdd64); break; - } - }break; - } - } - return(result); -} - -MR4TH_SYMBOL void -elfp_relocs_read(ELF_Parse *elf, U32 secidx, U32 relocidx, ELF_RelocationAdd64 *out){ - if (elf->sections != 0 && secidx < elf->section_count){ - switch (elf->elf_class){ - default:break; - case ELF_Class_32: { - ELF_Section32 *sec32 = ((ELF_Section32*)elf->sections) + secidx; - U64 opl = ClampTop(sec32->offset + sec32->size, elf->size); - U64 size = opl - sec32->offset; - switch (sec32->type){ - case ELF_SectionType_REL: { - ELF_Relocation32 *relocs = (ELF_Relocation32*)((U8*)elf->header + sec32->offset); - U32 count = sec32->size/sizeof(*relocs); - if (relocidx < count){ - elf_reloca64_from_reloc32(out, relocs + relocidx, elf->encoding); - } - }break; - case ELF_SectionType_RELA: { - ELF_RelocationAdd32 *relocs = (ELF_RelocationAdd32*)((U8*)elf->header + sec32->offset); - U32 count = sec32->size/sizeof(*relocs); - if (relocidx < count){ - elf_reloca64_from_reloca32(out, relocs + relocidx, elf->encoding); - } - }break; - } - }break; - case ELF_Class_64: { - ELF_Section64 *sec64 = ((ELF_Section64*)elf->sections) + secidx; - U64 opl = ClampTop(sec64->offset + sec64->size, elf->size); - U64 size = opl - sec64->offset; - switch (sec64->type){ - case ELF_SectionType_REL: { - ELF_Relocation64 *relocs = (ELF_Relocation64*)((U8*)elf->header + sec64->offset); - U32 count = sec64->size/sizeof(*relocs); - if (relocidx < count){ - elf_reloca64_from_reloc64(out, relocs + relocidx, elf->encoding); - } - }break; - case ELF_SectionType_RELA: { - ELF_RelocationAdd64 *relocs = (ELF_RelocationAdd64*)((U8*)elf->header + sec64->offset); - U32 count = sec64->size/sizeof(*relocs); - if (relocidx < count){ - elf_reloca64_from_reloca64(out, relocs + relocidx, elf->encoding); - } - }break; - } - }break; - } - } -} diff --git a/mr4th/mr4th_elf.parse.h b/mr4th/mr4th_elf.parse.h deleted file mode 100644 index 4a205d2..0000000 --- a/mr4th/mr4th_elf.parse.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef MR4TH_ELF_PARSE_H -#define MR4TH_ELF_PARSE_H - -//////////////////////////////// -// Elf Parse Types - -#define ELFP_SYMBOL_TABLE_symtab 0 -#define ELFP_SYMBOL_TABLE_dynsym 1 -#define ELFP_SYMBOL_TABLE_COUNT 2 - -typedef struct ELF_Parse{ - ELF_Class elf_class; - ELF_Encoding encoding; - U32 section_count; - U32 segment_count; - void *header; - U64 size; - void *sections; - void *segments; - U8 *section_strtable_first; - U8 *section_strtable_opl; - void *symbols[ELFP_SYMBOL_TABLE_COUNT]; - U32 symbol_count[ELFP_SYMBOL_TABLE_COUNT]; - U8 *symbol_strtable_first[ELFP_SYMBOL_TABLE_COUNT]; - U8 *symbol_strtable_opl[ELFP_SYMBOL_TABLE_COUNT]; -} ELF_Parse; - -//////////////////////////////// -// Elf Parse Functions - -MR4TH_SYMBOL ELF_Parse* elfp_begin(Arena *arena, String8 data); - -MR4TH_SYMBOL void elfp_header_read(ELF_Parse *elf, ELF_Header64 *out); - -MR4TH_SYMBOL U32 elfp_section_count(ELF_Parse *elf); -MR4TH_SYMBOL void elfp_section_read(ELF_Parse *elf, U32 idx, ELF_Section64 *out); -MR4TH_SYMBOL String8 elfp_section_name(ELF_Parse *elf, U32 idx); - -MR4TH_SYMBOL U32 elfp_segment_count(ELF_Parse *elf); -MR4TH_SYMBOL void elfp_segment_read(ELF_Parse *elf, U32 idx, ELF_Segment64 *out); - -MR4TH_SYMBOL U32 elfp_symbol_count(ELF_Parse *elf, U32 table); -MR4TH_SYMBOL void elfp_symbol_read(ELF_Parse *elf, U32 table, U32 idx, ELF_Symbol64 *out); -MR4TH_SYMBOL String8 elfp_symbol_name(ELF_Parse *elf, U32 table, U32 idx); - -MR4TH_SYMBOL U32 elfp_relocs_count(ELF_Parse *elf, U32 secidx); -MR4TH_SYMBOL void elfp_relocs_read(ELF_Parse *elf, U32 secidx, U32 relocidx, ELF_RelocationAdd64 *out); - -#endif //MR4TH_ELF_PARSE_H