From c3a551ee61a30fd413fc278a9a90a7dd33923676 Mon Sep 17 00:00:00 2001 From: Julian Barathieu Date: Sat, 7 Dec 2019 17:54:48 +0100 Subject: [PATCH] strtol --- kaleid/kernel/sh/shcmds.c | 12 +--- kaleid/kernel/sh/testcmds.c | 22 ++---- kaleid/libc/atoi.c | 6 ++ kaleid/libc/strtol.c | 129 +++++++++++++++++++++++++++++++++--- 4 files changed, 132 insertions(+), 37 deletions(-) diff --git a/kaleid/kernel/sh/shcmds.c b/kaleid/kernel/sh/shcmds.c index 3edec9a..0507e59 100644 --- a/kaleid/kernel/sh/shcmds.c +++ b/kaleid/kernel/sh/shcmds.c @@ -35,16 +35,6 @@ error_t CmdTest(int argc, char **argv, char *cmdline); error_t CmdMemUsage(int argc, char **argv, char *cmdline); -static inline int ShAtoi(char* str) -{ - int res = 0; - - for (int i = 0; str[i] != 0; ++i) - res = res * 10 + str[i] - '0'; - - return res; -} - error_t CmdBeep(int argc, char **argv, char *cmdline) { IoDoBeep(); @@ -144,7 +134,7 @@ error_t CmdQuit(int argc, char **argv, char *cmdline) error_t CmdSleep(int argc, char **argv, char *cmdline) { - int delay = ShAtoi(argv[1]); + int delay = atoi(argv[1]); KeSleep(delay); return EOK; diff --git a/kaleid/kernel/sh/testcmds.c b/kaleid/kernel/sh/testcmds.c index 4b395c9..50661fc 100644 --- a/kaleid/kernel/sh/testcmds.c +++ b/kaleid/kernel/sh/testcmds.c @@ -34,16 +34,6 @@ static Command_t testcmdtable[]; -static inline int ShAtoi(char* str) -{ - int res = 0; - - for (int i = 0; str[i] != 0; ++i) - res = res * 10 + str[i] - '0'; - - return res; -} - error_t CmdTest(int argc, char **argv, char *cmdline) { ExecuteCommand(cmdline+5, testcmdtable); @@ -68,8 +58,8 @@ error_t CmdArgs(int argc, char **argv, char *cmdline) error_t CmdDumpATASect(int argc, char **argv, char *cmdline) { char sector[512] = {0}; - int sectNumber = ShAtoi(argv[1]); - int nb = 1; //ShAtoi(argv[2]); + int sectNumber = atoi(argv[1]); + int nb = 1; //atoi(argv[2]); int x = 0; int step = 16; @@ -108,8 +98,8 @@ error_t CmdDumpATASect(int argc, char **argv, char *cmdline) error_t CmdFloatDiv(int argc, char **argv, char *cmdline) { - double a = (double)ShAtoi(argv[1]); - double b = (double)ShAtoi(argv[2]); + double a = (double)atoi(argv[1]); + double b = (double)atoi(argv[2]); double number = a / b; double number_ent = (double)(ulong)number; @@ -152,7 +142,7 @@ error_t CmdHelpTest(int argc, char **argv, char *cmdline) error_t CmdPF(int argc, char **argv, char *cmdline) { - char *address = (void*)(ulong)ShAtoi(argv[1]); + char *address = (void*)(ulong)atoi(argv[1]); KernLog("Provoking Page Fault at %#x\n", address); @@ -192,7 +182,7 @@ error_t CmdStackUnderflow(int argc, char **argv, char *cmdline) error_t CmdTimerTest(int argc, char **argv, char *cmdline) { - int delay = ShAtoi(argv[1]); + int delay = atoi(argv[1]); Timer_t *timer = KeSetTimer(delay); diff --git a/kaleid/libc/atoi.c b/kaleid/libc/atoi.c index 79b19ff..f2e32c3 100644 --- a/kaleid/libc/atoi.c +++ b/kaleid/libc/atoi.c @@ -24,6 +24,12 @@ #include +// +// int atoi(const char *str) +// +// Equivalent to strtol(str, NULL, 0) +// + // String to integer // Do not change errno #define _ATOI_IMPL(_Name, _Type, _Func) \ diff --git a/kaleid/libc/strtol.c b/kaleid/libc/strtol.c index c98782e..fd465c4 100644 --- a/kaleid/libc/strtol.c +++ b/kaleid/libc/strtol.c @@ -25,18 +25,127 @@ #include long strtol(const char *str, char **endp, int base) { - (void)str; - (void)endp; - (void)base; - seterrno(ENOSYS); - return 0; + char c; + ulong n; + bool neg = 0; + const char *save, *start = str; + + // Ignore leading spaces + do { + c = *str++; + } while (isspace(c)); + + // Accept any +/-'s, whatever the base + // In particular we accept things like "-0xF" + if (c == '+') + c = *str++; + else if (c == '-') { + c = *str++; + neg = 1; + } + + // Accept 0/0b/0B/0x/0X and guess base if needed + if (c == '0') { + c = *str++; + if ((base == 0 || base == 16) && (c == 'x' || c == 'X')) { + c = *str++; + base = 16; + } + else if ((base == 0 || base == 2) && (c == 'b' || c == 'B')) { + c = *str++; + base = 2; + } + + else if (base == 0) + base = 8; + } + + // base==0 but no leading '0' - assume it's decimal + if (base == 0) + base = 10; + + // + // Extract the number from the string + // We do not check whether the number actually fits + // That's why our accumulator 'n' needs to be unsigned, otherwise + // containing a number too large would cause a signed overflow and UB + // + save = str; + for (n = 0;; c = *str) { + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + + if (c >= base) + break; + else { + str++; + n = (n * base) + c; + } + } + + // Save where we stopped in *endp (optional) + // If 'str' is still '== save', no digit were consummed + if (endp != NULL) + *endp = (char *)(str == save ? start : str); + + return neg ? -(long)n : (long)n; } + +// +// Made from the code above by removing "neg" +// ulong strtoul(const char *str, char **endp, int base) { - (void)str; - (void)endp; - (void)base; - seterrno(ENOSYS); - return 0; + char c; + ulong n; + const char *save, *start = str; + + do { + c = *str++; + } while (isspace(c)); + + if (c == '0') { + c = *str++; + if ((base == 0 || base == 16) && (c == 'x' || c == 'X')) { + c = *str++; + base = 16; + } + else if ((base == 0 || base == 2) && (c == 'b' || c == 'B')) { + c = *str++; + base = 2; + } + + else if (base == 0) + base = 8; + } + + if (base == 0) + base = 10; + + save = str; + for (n = 0;; c = *str) { + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + + if (c >= base) + break; + else { + str++; + n = (n * base) + c; + } + } + + if (endp != NULL) + *endp = (char *)(str == save ? start : str); + + return n; }