Skip to content

Commit

Permalink
Add a platform-independent implementation of box_strtoui64
Browse files Browse the repository at this point in the history
Replaces strtoull(), which doesn't exist on older Windows compilers (MSVC <
12), and in any case doesn't necessarily return a uint64_t, so this is a better
interface.
  • Loading branch information
qris committed Jul 23, 2017
1 parent 0458cd3 commit 5da656c
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 5 deletions.
36 changes: 34 additions & 2 deletions lib/win32/emu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@

#include "emu.h"

#include <assert.h>
#include <string.h> // for strlen()

#include <iomanip>
#include <sstream>

#ifdef WIN32

#include <assert.h>
#include <fcntl.h>
#include <process.h>
#include <windows.h>
Expand All @@ -15,7 +20,6 @@

#include <string>
#include <list>
#include <sstream>

// message resource definitions for syslog()
#include "messages.h"
Expand Down Expand Up @@ -2036,3 +2040,31 @@ bool ConvertTime_tToFileTime(const time_t from, FILETIME *pTo)

#endif // WIN32

// MSVC < 12 (2013) does not have strtoull(), and _strtoi64 is signed only (truncates all values
// greater than 1<<63 to _I64_MAX, so we roll our own using std::istringstream
// <http://stackoverflow.com/questions/1070497/c-convert-hex-string-to-signed-integer>
uint64_t box_strtoui64(const char *nptr, const char **endptr, int base)
{
std::istringstream iss((std::string(nptr)));
uint64_t result;

assert(base == 0 || base == 8 || base == 10 || base == 16);
iss >> std::setbase(base);
iss >> result;

if(endptr != NULL)
{
if(iss.eof())
{
*endptr = nptr + strlen(nptr);
}
else
{
assert(iss.tellg() >= 0);
*endptr = nptr + iss.tellg();
}
}

return result;
}

18 changes: 15 additions & 3 deletions lib/win32/emu.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

#include "emu_winver.h"

#include <stdint.h> // for uint64_t
#include <stdlib.h> // for strtoull()

#if ! defined EMU_INCLUDE
#define EMU_INCLUDE

#ifdef WIN32
#define EMU_STRUCT_STAT struct emu_stat
#define EMU_STAT emu_stat
Expand All @@ -14,8 +20,7 @@
#define EMU_LSTAT ::lstat
#endif

#if ! defined EMU_INCLUDE && defined WIN32
#define EMU_INCLUDE
#ifdef WIN32

// Need feature detection macros below
#if defined BOX_CMAKE
Expand Down Expand Up @@ -450,4 +455,11 @@ int console_read(char* pBuffer, size_t BufferSize);
#pragma warning(disable:4996) // POSIX name for this item is deprecated
#endif // _MSC_VER

#endif // !EMU_INCLUDE && WIN32
#endif // WIN32

// MSVC < 12 (2013) does not have strtoull(), and _strtoi64 is signed only (truncates all values
// greater than 1<<63 to _I64_MAX, so we roll our own using std::istringstream
// <http://stackoverflow.com/questions/1070497/c-convert-hex-string-to-signed-integer>
uint64_t box_strtoui64(const char *nptr, const char **endptr, int base);

#endif // !EMU_INCLUDE
11 changes: 11 additions & 0 deletions test/common/testcommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -920,5 +920,16 @@ int test(int argc, const char *argv[])
}
}

// Test that box_strtoui64 works properly
TEST_EQUAL(1234567890123456, box_strtoui64("1234567890123456", NULL, 10));
TEST_EQUAL(0x1234567890123456, box_strtoui64("1234567890123456", NULL, 16));
TEST_EQUAL(0xd9385a13c3842ba0, box_strtoui64("d9385a13c3842ba0", NULL, 16));
const char *input = "12a34";
const char *endptr;
TEST_EQUAL(12, box_strtoui64(input, &endptr, 10));
TEST_EQUAL(input + 2, endptr);
TEST_EQUAL(0x12a34, box_strtoui64(input, &endptr, 16));
TEST_EQUAL(input + 5, endptr);

return 0;
}

0 comments on commit 5da656c

Please sign in to comment.