diff --git a/code/globalincs/flagset.h b/code/globalincs/flagset.h index db3fa11d2c..e3635a054d 100644 --- a/code/globalincs/flagset.h +++ b/code/globalincs/flagset.h @@ -201,9 +201,17 @@ class flagset { bool any_set() const { return values.any(); } bool none_set() const { return values.none(); } - void from_u64(std::uint64_t num) { values = (unsigned long) num; } + void from_u64(std::uint64_t num) + { + static_assert(SIZE <= 64, "from_u64 can only be used with flagsets of up to 64 flags"); + values = std::bitset(num); + } - std::uint64_t to_u64() const { return (std::uint64_t) values.to_ulong(); } + std::uint64_t to_u64() const + { + static_assert(SIZE <= 64, "to_u64 can only be used with flagsets of up to 64 flags"); + return static_cast(values.to_ullong()); + } size_t hash() const { return std::hash>()(values); } }; diff --git a/code/graphics/opengl/gropenglopenxr.cpp b/code/graphics/opengl/gropenglopenxr.cpp index 570755484d..7e2eae204e 100644 --- a/code/graphics/opengl/gropenglopenxr.cpp +++ b/code/graphics/opengl/gropenglopenxr.cpp @@ -62,7 +62,7 @@ bool gr_opengl_openxr_test_capabilities() { } if (requirements.minApiVersionSupported > XR_MAKE_VERSION(GLVersion.major, GLVersion.minor, 0)) { - mprintf(("System doesn't meet OpenXR graphics requirements (min %" PRIu64 ", available %" PRIu64 ")!\n", requirements.minApiVersionSupported, static_cast(XR_MAKE_VERSION(GLVersion.major, GLVersion.minor, 0)))); + mprintf(("System doesn't meet OpenXR graphics requirements (min " UINT64_T_ARG ", available " UINT64_T_ARG ")!\n", requirements.minApiVersionSupported, static_cast(XR_MAKE_VERSION(GLVersion.major, GLVersion.minor, 0)))); return false; } diff --git a/code/graphics/vulkan/VulkanRendererSetup.cpp b/code/graphics/vulkan/VulkanRendererSetup.cpp index 90ebc51b56..1d1a2533c6 100644 --- a/code/graphics/vulkan/VulkanRendererSetup.cpp +++ b/code/graphics/vulkan/VulkanRendererSetup.cpp @@ -208,7 +208,7 @@ bool compareDevices(const PhysicalDeviceValues& left, const PhysicalDeviceValues void printPhysicalDevice(const PhysicalDeviceValues& values) { - mprintf((" Found %s (%d) of type %s. API version %d.%d.%d, Driver version %d.%d.%d. Scored as %" PRIu64 "\n", + mprintf((" Found %s (%d) of type %s. API version %d.%d.%d, Driver version %d.%d.%d. Scored as " UINT64_T_ARG "\n", values.properties.deviceName.data(), values.properties.deviceID, to_string(values.properties.deviceType).c_str(), diff --git a/code/missioneditor/missionsave.cpp b/code/missioneditor/missionsave.cpp index 68ade7cdf7..dd698120f3 100644 --- a/code/missioneditor/missionsave.cpp +++ b/code/missioneditor/missionsave.cpp @@ -2566,7 +2566,7 @@ int Fred_mission_save::save_mission_info() fout("\n+Flags:"); } - fout(" %" PRIu64, The_mission.flags.to_u64()); + fout(" " UINT64_T_ARG, The_mission.flags.to_u64()); // maybe write out Nebula values if (The_mission.flags[Mission::Mission_Flags::Fullneb]) { diff --git a/code/parse/parselo.cpp b/code/parse/parselo.cpp index e6cc5f048e..4a761ab3bc 100644 --- a/code/parse/parselo.cpp +++ b/code/parse/parselo.cpp @@ -2989,6 +2989,79 @@ int stuff_long(long *l, bool optional) return retval; } +// Stuff an unsigned 64-bit value pointed at by Mp. +// Advances past integer characters. +int stuff_uint64(std::uint64_t *l, bool optional) +{ + char *str_start = Mp; + + // since strtoull ignores white space anyway, might as well make it explicit + ignore_white_space(); + + // this is a bit cumbersome + size_t span; + if (*Mp == '+') + { + span = strspn(Mp + 1, "0123456789"); + + // account for the sign symbol, but not if it's the only valid character + if (span > 0) + ++span; + } + else + span = strspn(Mp, "0123456789"); + + // don't call strtoull unless we found digits, because it will happily parse + // (and wrap around) a negative number + std::uint64_t result = (span > 0) ? strtoull(Mp, nullptr, 10) : 0; + bool success = false, comma = false; + int retval = 0; + + // no number found? + if (span == 0) + { + if (!optional) + error_display(1, "Expected unsigned integer, found [%.32s].\n", next_tokens()); + } + else + { + *l = result; + success = true; + } + + if (success) + Mp += span; + + // if an unexpected character is part of the number, warn about it + if (success && unexpected_numeric_char(*Mp)) + { + error_display(0, "Expected unsigned integer, found [%.32s].\n", next_tokens(true)); + // Rather than back up to str_start, do what retail did and continue + // merrily parsing along at the next character. (Optional numbers + // will still back up to str_start - c.f. a few lines down.) + if (optional) + success = false; + } + + if (check_first_non_grayspace_char(Mp, ',', &Mp)) + comma = true; + + if (optional && !success) + Mp = str_start; + + if (success) + { + retval = 2; + diag_printf("Stuffed uint64: " UINT64_T_ARG "\n", *l); + } + else if (optional) + retval = comma ? 1 : 0; + else + skip_token(); + + return retval; +} + int stuff_float_optional(float *f) { return stuff_float(f, true); diff --git a/code/parse/parselo.h b/code/parse/parselo.h index b501ff4e2c..1844924f65 100644 --- a/code/parse/parselo.h +++ b/code/parse/parselo.h @@ -164,6 +164,7 @@ extern bool check_first_non_grayspace_char(const char *str, char ch_to_look_for, extern int stuff_float(float *f, bool optional = false); extern int stuff_int(int *i, bool optional = false); extern int stuff_long(long *l, bool optional = false); +extern int stuff_uint64(std::uint64_t *l, bool optional = false); extern void stuff_ubyte(ubyte *i); extern int stuff_int_optional(int *i); extern int stuff_float_optional(float *f); @@ -246,17 +247,14 @@ void parse_string_flag_list_special(Flagset& dest, const special_flag_def_list_n } template -void stuff_flagset(T *dest) { - long l = 0; - stuff_long(&l); +void stuff_flagset(T *dest) +{ + std::uint64_t val = 0; + stuff_uint64(&val); - if (l < 0) { - error_display(0, "Expected flagset value but got negative value %lu!\n", l); - l = 0; - } - dest->from_u64((std::uint64_t) l); + dest->from_u64(val); - diag_printf("Stuffed flagset: %" PRIu64 "\n", dest->to_u64()); + diag_printf("Stuffed flagset: " UINT64_T_ARG "\n", dest->to_u64()); } extern size_t stuff_int_list(int *ilp, size_t max_ints, ParseLookupType lookup_type = ParseLookupType::RAW_INTEGER_TYPE, bool warn_on_lookup_failure = true); diff --git a/freespace2/freespace.cpp b/freespace2/freespace.cpp index c4e1e53c5d..5ae02aa50d 100644 --- a/freespace2/freespace.cpp +++ b/freespace2/freespace.cpp @@ -2383,15 +2383,15 @@ void game_show_framerate() MEMORYSTATUSEX mem_stats; mem_stats.dwLength = sizeof(mem_stats); if (GlobalMemoryStatusEx(&mem_stats)) { - sprintf(mem_buffer, "Physical Free: %" PRIu64 " / %" PRIu64 " Meg", mem_stats.ullAvailPhys / 1024 / 1024, mem_stats.ullTotalPhys / 1024 / 1024); + sprintf(mem_buffer, "Physical Free: " UINT64_T_ARG " / " UINT64_T_ARG " Meg", mem_stats.ullAvailPhys / 1024 / 1024, mem_stats.ullTotalPhys / 1024 / 1024); gr_string(sx, sy, mem_buffer.c_str(), GR_RESIZE_NONE); sy += line_height; - sprintf(mem_buffer, "Pagefile Free: %" PRIu64 " / %" PRIu64 " Meg", mem_stats.ullAvailPageFile / 1024 / 1024, mem_stats.ullTotalPageFile / 1024 / 1024); + sprintf(mem_buffer, "Pagefile Free: " UINT64_T_ARG " / " UINT64_T_ARG " Meg", mem_stats.ullAvailPageFile / 1024 / 1024, mem_stats.ullTotalPageFile / 1024 / 1024); gr_string(sx, sy, mem_buffer.c_str(), GR_RESIZE_NONE); sy += line_height; - sprintf(mem_buffer, "Virtual Free: %" PRIu64 " / %" PRIu64 " Meg", mem_stats.ullAvailVirtual / 1024 / 1024, mem_stats.ullTotalVirtual / 1024 / 1024); + sprintf(mem_buffer, "Virtual Free: " UINT64_T_ARG " / " UINT64_T_ARG " Meg", mem_stats.ullAvailVirtual / 1024 / 1024, mem_stats.ullTotalVirtual / 1024 / 1024); gr_string(sx, sy, mem_buffer.c_str(), GR_RESIZE_NONE); } }