From 416c81bb8a7e5b2eb51cad0693527a9819ae6abf Mon Sep 17 00:00:00 2001 From: Matthew Kilgore Date: Tue, 13 Feb 2024 01:39:33 -0500 Subject: [PATCH] move hex/oct/bin functions to separate file --- internal/c/libqb.cpp | 275 -------------------------- internal/c/libqb/build.mk | 1 + internal/c/libqb/include/hexoctbin.h | 12 ++ internal/c/libqb/src/hexoctbin.cpp | 285 +++++++++++++++++++++++++++ internal/c/qbx.cpp | 7 +- 5 files changed, 299 insertions(+), 281 deletions(-) create mode 100644 internal/c/libqb/include/hexoctbin.h create mode 100644 internal/c/libqb/src/hexoctbin.cpp diff --git a/internal/c/libqb.cpp b/internal/c/libqb.cpp index 09a041727..44b01cead 100644 --- a/internal/c/libqb.cpp +++ b/internal/c/libqb.cpp @@ -17632,281 +17632,6 @@ wait: return; } -qbs *func__bin(int64 value, int32 neg_bits) { - - static int32 i, i2, i3, neg; - static int64 value2; - static qbs *str; - - str = qbs_new(64, 1); - - // negative? - if ((value >> 63) & 1) - neg = 1; - else - neg = 0; - - // calc. most significant bit - i2 = 0; - value2 = value; - if (neg) { - for (i = 1; i <= 64; i++) { - if (!(value2 & 1)) - i2 = i; - value2 >>= 1; - } - if (i2 >= neg_bits) { - // doesn't fit in neg_bits, so expand to next 16/32/64 boundary - i3 = 64; - if (i2 < 32) - i3 = 32; - if (i2 < 16) - i3 = 16; - i2 = i3; - } else - i2 = neg_bits; - } else { - for (i = 1; i <= 64; i++) { - if (value2 & 1) - i2 = i; - value2 >>= 1; - } - } - - if (!i2) { - str->chr[0] = 48; - str->len = 1; - return str; - } //"0" - - // calc. number of characters required in i3 - i3 = i2; // equal for BIN$ because one bit = one char - - // build string - str->len = i3; - i3--; - for (i = 1; i <= i2; i++) { - str->chr[i3--] = (value & 1) + 48; - value >>= 1; - } - - return str; -} - -// note: QBASIC doesn't have a BIN$ function -// QB64 uses 32 bin digits for SINGLE/DOUBLE/FLOAT but if this range is exceeded -// it uses up to 64 bin digits before generating an "OVERFLOW" error -// performs overflow check before calling func__bin -qbs *func__bin_float(long double value) { - static qbs *str; - static int64 ivalue; - static int64 uivalue; - // ref: uint64 0-18446744073709551615 - // int64 \969223372036854775808 to 9223372036854775807 - if ((value >= 9.223372036854776E18) || (value <= -9.223372036854776E18)) { - // note: ideally, the following line would be used, however, qbr_longdouble_to_uint64 just does the same as qbr - // if ((value>=1.844674407370956E19)||(value<=-9.223372036854776E18)){ - str = qbs_new(0, 1); - error(6); // Overflow - return str; - } - if (value >= 0) { - uivalue = qbr_longdouble_to_uint64(value); - ivalue = uivalue; - } else { - ivalue = qbr(value); - } - return func__bin(ivalue, 32); -} - -qbs *func_oct(int64 value, int32 neg_bits) { - - static int32 i, i2, i3, x, x2, neg; - static int64 value2; - static qbs *str; - - str = qbs_new(22, 1); - - // negative? - if ((value >> 63) & 1) - neg = 1; - else - neg = 0; - - // calc. most significant bit - i2 = 0; - value2 = value; - if (neg) { - for (i = 1; i <= 64; i++) { - if (!(value2 & 1)) - i2 = i; - value2 >>= 1; - } - if (i2 >= neg_bits) { - // doesn't fit in neg_bits, so expand to next 16/32/64 boundary - i3 = 64; - if (i2 < 32) - i3 = 32; - if (i2 < 16) - i3 = 16; - i2 = i3; - } else - i2 = neg_bits; - } else { - for (i = 1; i <= 64; i++) { - if (value2 & 1) - i2 = i; - value2 >>= 1; - } - } - - if (!i2) { - str->chr[0] = 48; - str->len = 1; - return str; - } //"0" - - // calc. number of characters required in i3 - i3 = i2 / 3; - if ((i3 * 3) != i2) - i3++; - - // build string - str->len = i3; - i3--; - x = 0; - x2 = 0; - for (i = 1; i <= i2; i++) { - if (value & 1) - x2 |= (1 << x); - value >>= 1; - x++; - if (x == 3) { - str->chr[i3--] = x2 + 48; - x2 = 0; - x = 0; - } - } - if (x) - str->chr[i3] = x2 + 48; - - return str; -} - -// note: QBASIC uses 11 oct digits for SINGLE/DOUBLE or generates "OVERFLOW" if this range is exceeded -// QB64 uses 11 oct digits for SINGLE/DOUBLE/FLOAT but if this range is exceeded -// it uses up to 22 oct digits before generating an "OVERFLOW" error -// performs overflow check before calling func_oct -qbs *func_oct_float(long double value) { - static qbs *str; - static int64 ivalue; - static int64 uivalue; - // ref: uint64 0-18446744073709551615 - // int64 \969223372036854775808 to 9223372036854775807 - if ((value >= 9.223372036854776E18) || (value <= -9.223372036854776E18)) { - // note: ideally, the following line would be used, however, qbr_longdouble_to_uint64 just does the same as qbr - // if ((value>=1.844674407370956E19)||(value<=-9.223372036854776E18)){ - str = qbs_new(0, 1); - error(6); // Overflow - return str; - } - if (value >= 0) { - uivalue = qbr_longdouble_to_uint64(value); - ivalue = uivalue; - } else { - ivalue = qbr(value); - } - return func_oct(ivalue, 32); -} - -qbs *func_hex(int64 value, int32 neg_size) { - // note: negative int64 values can be treated as positive uint64 values (and vise versa) - - static int32 i, i2, i3, x, neg; - static int64 value2; - static qbs *str; - - str = qbs_new(16, 1); - - value2 = value; - i2 = 0; - i3 = 0; - for (i = 1; i <= 16; i++) { - if (value2 & 15) - i2 = i; // most significant digit of positive value - if ((value2 & 15) != 15) { - i3 = i; // most significant digit of negative value - if ((((value2 & 8) == 0) && (i != 16))) - i3++; // for a negative number to fit into 4/8 characters, its top bit must be on - } - x = value2 & 15; - if (x > 9) - x += 55; - else - x += 48; - str->chr[16 - i] = x; - value2 >>= 4; - } - if (!i2) { - str->chr[0] = 48; - str->len = 1; - return str; - } //"0" - - // negative? - if ((value >> 63) & 1) - neg = 1; - else - neg = 0; - - // change i2 from sig-digits to string-output-digits - if (neg) { - if (i3 <= neg_size) { - i2 = neg_size; // extend to minimum character size - } else { - // didn't fit in recommended size, expand to either 4, 8 or 16 appropriately - i2 = 16; - if (i3 <= 8) - i2 = 8; - if (i3 <= 4) - i2 = 4; - } - } // neg - - // adjust string to the left to remove unnecessary characters - if (i2 != 16) { - memmove(str->chr, str->chr + (16 - i2), i2); - str->len = i2; - } - - return str; -} - -// note: QBASIC uses 8 hex digits for SINGLE/DOUBLE or generates "OVERFLOW" if this range is exceeded -// QB64 uses 8 hex digits for SINGLE/DOUBLE/FLOAT but if this range is exceeded -// it uses up to 16 hex digits before generating an "OVERFLOW" error -// performs overflow check before calling func_hex -qbs *func_hex_float(long double value) { - static qbs *str; - static int64 ivalue; - static int64 uivalue; - // ref: uint64 0-18446744073709551615 - // int64 \969223372036854775808 to 9223372036854775807 - if ((value >= 9.223372036854776E18) || (value <= -9.223372036854776E18)) { - // note: ideally, the following line would be used, however, qbr_longdouble_to_uint64 just does the same as qbr - // if ((value>=1.844674407370956E19)||(value<=-9.223372036854776E18)){ - str = qbs_new(0, 1); - error(6); // Overflow - return str; - } - if (value >= 0) { - uivalue = qbr_longdouble_to_uint64(value); - ivalue = uivalue; - } else { - ivalue = qbr(value); - } - return func_hex(ivalue, 8); -} ptrszint func_lbound(ptrszint *array, int32 index, int32 num_indexes) { if ((index < 1) || (index > num_indexes) || ((array[2] & 1) == 0)) { diff --git a/internal/c/libqb/build.mk b/internal/c/libqb/build.mk index 294a61f02..fa27b7535 100644 --- a/internal/c/libqb/build.mk +++ b/internal/c/libqb/build.mk @@ -11,6 +11,7 @@ libqb-objs-y += $(PATH_LIBQB)/src/datetime.o libqb-objs-y += $(PATH_LIBQB)/src/error_handle.o libqb-objs-y += $(PATH_LIBQB)/src/gfs.o libqb-objs-y += $(PATH_LIBQB)/src/qblist.o +libqb-objs-y += $(PATH_LIBQB)/src/hexoctbin.o libqb-objs-y += $(PATH_LIBQB)/src/mem.o libqb-objs-y += $(PATH_LIBQB)/src/math.o libqb-objs-y += $(PATH_LIBQB)/src/rounding.o diff --git a/internal/c/libqb/include/hexoctbin.h b/internal/c/libqb/include/hexoctbin.h new file mode 100644 index 000000000..1f9e66da4 --- /dev/null +++ b/internal/c/libqb/include/hexoctbin.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +#include "qbs.h" + +qbs *func__bin(int64_t value, int32_t neg_bits); +qbs *func__bin_float(long double value); +qbs *func_oct(int64_t value, int32_t neg_bits); +qbs *func_oct_float(long double value); +qbs *func_hex(int64_t value, int32_t neg_size); +qbs *func_hex_float(long double value); diff --git a/internal/c/libqb/src/hexoctbin.cpp b/internal/c/libqb/src/hexoctbin.cpp new file mode 100644 index 000000000..89547cd89 --- /dev/null +++ b/internal/c/libqb/src/hexoctbin.cpp @@ -0,0 +1,285 @@ + +#include "libqb-common.h" + +#include +#include +#include + +#include "rounding.h" +#include "qbs.h" +#include "hexoctbin.h" + +qbs *func__bin(int64_t value, int32_t neg_bits) { + static int32_t i, i2, i3, neg; + static int64_t value2; + static qbs *str; + + str = qbs_new(64, 1); + + // negative? + if ((value >> 63) & 1) + neg = 1; + else + neg = 0; + + // calc. most significant bit + i2 = 0; + value2 = value; + if (neg) { + for (i = 1; i <= 64; i++) { + if (!(value2 & 1)) + i2 = i; + value2 >>= 1; + } + if (i2 >= neg_bits) { + // doesn't fit in neg_bits, so expand to next 16/32/64 boundary + i3 = 64; + if (i2 < 32) + i3 = 32; + if (i2 < 16) + i3 = 16; + i2 = i3; + } else + i2 = neg_bits; + } else { + for (i = 1; i <= 64; i++) { + if (value2 & 1) + i2 = i; + value2 >>= 1; + } + } + + if (!i2) { + str->chr[0] = 48; + str->len = 1; + return str; + } //"0" + + // calc. number of characters required in i3 + i3 = i2; // equal for BIN$ because one bit = one char + + // build string + str->len = i3; + i3--; + for (i = 1; i <= i2; i++) { + str->chr[i3--] = (value & 1) + 48; + value >>= 1; + } + + return str; +} + +// note: QBASIC doesn't have a BIN$ function +// QB64 uses 32 bin digits for SINGLE/DOUBLE/FLOAT but if this range is exceeded +// it uses up to 64 bin digits before generating an "OVERFLOW" error +// performs overflow check before calling func__bin +qbs *func__bin_float(long double value) { + static qbs *str; + static int64_t ivalue; + static int64_t uivalue; + // ref: uint64 0-18446744073709551615 + // int64 \969223372036854775808 to 9223372036854775807 + if ((value >= 9.223372036854776E18) || (value <= -9.223372036854776E18)) { + // note: ideally, the following line would be used, however, qbr_longdouble_to_uint64 just does the same as qbr + // if ((value>=1.844674407370956E19)||(value<=-9.223372036854776E18)){ + str = qbs_new(0, 1); + error(6); // Overflow + return str; + } + if (value >= 0) { + uivalue = qbr_longdouble_to_uint64(value); + ivalue = uivalue; + } else { + ivalue = qbr(value); + } + return func__bin(ivalue, 32); +} + +qbs *func_oct(int64_t value, int32_t neg_bits) { + + static int32_t i, i2, i3, x, x2, neg; + static int64_t value2; + static qbs *str; + + str = qbs_new(22, 1); + + // negative? + if ((value >> 63) & 1) + neg = 1; + else + neg = 0; + + // calc. most significant bit + i2 = 0; + value2 = value; + if (neg) { + for (i = 1; i <= 64; i++) { + if (!(value2 & 1)) + i2 = i; + value2 >>= 1; + } + if (i2 >= neg_bits) { + // doesn't fit in neg_bits, so expand to next 16/32/64 boundary + i3 = 64; + if (i2 < 32) + i3 = 32; + if (i2 < 16) + i3 = 16; + i2 = i3; + } else + i2 = neg_bits; + } else { + for (i = 1; i <= 64; i++) { + if (value2 & 1) + i2 = i; + value2 >>= 1; + } + } + + if (!i2) { + str->chr[0] = 48; + str->len = 1; + return str; + } //"0" + + // calc. number of characters required in i3 + i3 = i2 / 3; + if ((i3 * 3) != i2) + i3++; + + // build string + str->len = i3; + i3--; + x = 0; + x2 = 0; + for (i = 1; i <= i2; i++) { + if (value & 1) + x2 |= (1 << x); + value >>= 1; + x++; + if (x == 3) { + str->chr[i3--] = x2 + 48; + x2 = 0; + x = 0; + } + } + if (x) + str->chr[i3] = x2 + 48; + + return str; +} + +// note: QBASIC uses 11 oct digits for SINGLE/DOUBLE or generates "OVERFLOW" if this range is exceeded +// QB64 uses 11 oct digits for SINGLE/DOUBLE/FLOAT but if this range is exceeded +// it uses up to 22 oct digits before generating an "OVERFLOW" error +// performs overflow check before calling func_oct +qbs *func_oct_float(long double value) { + static qbs *str; + static int64_t ivalue; + static int64_t uivalue; + // ref: uint64 0-18446744073709551615 + // int64 \969223372036854775808 to 9223372036854775807 + if ((value >= 9.223372036854776E18) || (value <= -9.223372036854776E18)) { + // note: ideally, the following line would be used, however, qbr_longdouble_to_uint64 just does the same as qbr + // if ((value>=1.844674407370956E19)||(value<=-9.223372036854776E18)){ + str = qbs_new(0, 1); + error(6); // Overflow + return str; + } + if (value >= 0) { + uivalue = qbr_longdouble_to_uint64(value); + ivalue = uivalue; + } else { + ivalue = qbr(value); + } + return func_oct(ivalue, 32); +} + +qbs *func_hex(int64_t value, int32_t neg_size) { + // note: negative int64 values can be treated as positive uint64 values (and vise versa) + + static int32_t i, i2, i3, x, neg; + static int64_t value2; + static qbs *str; + + str = qbs_new(16, 1); + + value2 = value; + i2 = 0; + i3 = 0; + for (i = 1; i <= 16; i++) { + if (value2 & 15) + i2 = i; // most significant digit of positive value + if ((value2 & 15) != 15) { + i3 = i; // most significant digit of negative value + if ((((value2 & 8) == 0) && (i != 16))) + i3++; // for a negative number to fit into 4/8 characters, its top bit must be on + } + x = value2 & 15; + if (x > 9) + x += 55; + else + x += 48; + str->chr[16 - i] = x; + value2 >>= 4; + } + if (!i2) { + str->chr[0] = 48; + str->len = 1; + return str; + } //"0" + + // negative? + if ((value >> 63) & 1) + neg = 1; + else + neg = 0; + + // change i2 from sig-digits to string-output-digits + if (neg) { + if (i3 <= neg_size) { + i2 = neg_size; // extend to minimum character size + } else { + // didn't fit in recommended size, expand to either 4, 8 or 16 appropriately + i2 = 16; + if (i3 <= 8) + i2 = 8; + if (i3 <= 4) + i2 = 4; + } + } // neg + + // adjust string to the left to remove unnecessary characters + if (i2 != 16) { + memmove(str->chr, str->chr + (16 - i2), i2); + str->len = i2; + } + + return str; +} + +// note: QBASIC uses 8 hex digits for SINGLE/DOUBLE or generates "OVERFLOW" if this range is exceeded +// QB64 uses 8 hex digits for SINGLE/DOUBLE/FLOAT but if this range is exceeded +// it uses up to 16 hex digits before generating an "OVERFLOW" error +// performs overflow check before calling func_hex +qbs *func_hex_float(long double value) { + static qbs *str; + static int64_t ivalue; + static int64_t uivalue; + // ref: uint64 0-18446744073709551615 + // int64 \969223372036854775808 to 9223372036854775807 + if ((value >= 9.223372036854776E18) || (value <= -9.223372036854776E18)) { + // note: ideally, the following line would be used, however, qbr_longdouble_to_uint64 just does the same as qbr + // if ((value>=1.844674407370956E19)||(value<=-9.223372036854776E18)){ + str = qbs_new(0, 1); + error(6); // Overflow + return str; + } + if (value >= 0) { + uivalue = qbr_longdouble_to_uint64(value); + ivalue = uivalue; + } else { + ivalue = qbr(value); + } + return func_hex(ivalue, 8); +} diff --git a/internal/c/qbx.cpp b/internal/c/qbx.cpp index a7265145c..207d91660 100755 --- a/internal/c/qbx.cpp +++ b/internal/c/qbx.cpp @@ -12,6 +12,7 @@ #include "filesystem.h" #include "font.h" #include "gui.h" +#include "hexoctbin.h" #include "image.h" #include "qbmath.h" #include "qbs.h" @@ -352,12 +353,6 @@ extern void sub_graphics_put(float x1f, float y1f, void *element, int32 option, extern int32 func_csrlin(); extern int32 func_pos(int32 ignore); extern void sub_sleep(int32 seconds, int32 passed); -extern qbs *func__bin(int64 value, int32 neg_bits); -extern qbs *func__bin_float(long double value); -extern qbs *func_oct(int64 value, int32 neg_bits); -extern qbs *func_oct_float(long double value); -extern qbs *func_hex(int64 value, int32 neg_size); -extern qbs *func_hex_float(long double value); extern ptrszint func_lbound(ptrszint *array, int32 index, int32 num_indexes); extern ptrszint func_ubound(ptrszint *array, int32 index, int32 num_indexes);