diff --git a/Makefile b/Makefile index 57378f0..74cd1bf 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -NCRON_C_SRCS = $(sort xmalloc.c nk/io.c nk/pspawn.c) +NCRON_C_SRCS = $(sort xmalloc.c strconv.c nk/io.c nk/pspawn.c) NCRON_CXX_SRCS = $(sort ncron.cpp sched.cpp crontab.cpp) NCRON_OBJS = $(NCRON_C_SRCS:.c=.o) $(NCRON_CXX_SRCS:.cpp=.o) NCRON_DEP = $(NCRON_C_SRCS:.c=.d) $(NCRON_CXX_SRCS:.cpp=.d) diff --git a/crontab.cpp b/crontab.cpp index 26b87fb..b355127 100644 --- a/crontab.cpp +++ b/crontab.cpp @@ -7,10 +7,11 @@ #include #include #include -#include +#include extern "C" { #include "nk/log.h" #include "xmalloc.h" +#include "strconv.h" } #include "ncron.hpp" #include "sched.hpp" @@ -140,14 +141,12 @@ struct hstm { } }; -#define MARKED_HST() hst.st, (p > hst.st ? static_cast(p - hst.st) : 0) +#line 178 "crontab.rl" -#line 179 "crontab.rl" - -#line 148 "crontab.cpp" +#line 147 "crontab.cpp" static const signed char _history_m_actions[] = { 0, 1, 0, 1, 1, 1, 2, 1, 3, 1, 4, 0 @@ -212,7 +211,7 @@ static const int history_m_error = 0; static const int history_m_en_main = 1; -#line 181 "crontab.rl" +#line 180 "crontab.rl" static int do_parse_history(hstm &hst, const char *p, size_t plen) @@ -221,15 +220,15 @@ static int do_parse_history(hstm &hst, const char *p, size_t plen) const char *eof = pe; -#line 219 "crontab.cpp" +#line 218 "crontab.cpp" { hst.cs = (int)history_m_start; } -#line 188 "crontab.rl" +#line 187 "crontab.rl" -#line 224 "crontab.cpp" +#line 223 "crontab.cpp" { unsigned int _trans = 0; const char * _keys; @@ -273,66 +272,66 @@ static int do_parse_history(hstm &hst, const char *p, size_t plen) { case 0: { { -#line 148 "crontab.rl" +#line 147 "crontab.rl" hst.st = p; } -#line 270 "crontab.cpp" +#line 269 "crontab.cpp" break; } case 1: { { -#line 149 "crontab.rl" +#line 148 "crontab.rl" - if (!nk::from_string(MARKED_HST(), &hst.h.lasttime)) { + if (!strconv_to_i64(hst.st, p, &hst.h.lasttime)) { hst.parse_error = true; {p += 1; goto _out; } } } -#line 283 "crontab.cpp" +#line 282 "crontab.cpp" break; } case 2: { { -#line 155 "crontab.rl" +#line 154 "crontab.rl" - if (!nk::from_string(MARKED_HST(), &hst.h.numruns)) { + if (!strconv_to_u32(hst.st, p, &hst.h.numruns)) { hst.parse_error = true; {p += 1; goto _out; } } } -#line 296 "crontab.cpp" +#line 295 "crontab.cpp" break; } case 3: { { -#line 161 "crontab.rl" +#line 160 "crontab.rl" - if (!nk::from_string(MARKED_HST(), &hst.h.exectime)) { + if (!strconv_to_i64(hst.st, p, &hst.h.exectime)) { hst.parse_error = true; {p += 1; goto _out; } } } -#line 309 "crontab.cpp" +#line 308 "crontab.cpp" break; } case 4: { { -#line 167 "crontab.rl" +#line 166 "crontab.rl" - if (!nk::from_string(MARKED_HST(), &hst.id)) { + if (!strconv_to_i32(hst.st, p, &hst.id)) { hst.parse_error = true; {p += 1; goto _out; } } } -#line 322 "crontab.cpp" +#line 321 "crontab.cpp" break; } @@ -356,7 +355,7 @@ static int do_parse_history(hstm &hst, const char *p, size_t plen) _out: {} } -#line 189 "crontab.rl" +#line 188 "crontab.rl" if (hst.parse_error) return -1; @@ -502,11 +501,11 @@ struct Pckm { }; -#line 377 "crontab.rl" +#line 376 "crontab.rl" -#line 492 "crontab.cpp" +#line 491 "crontab.cpp" static const signed char _parse_cmd_key_m_actions[] = { 0, 1, 0, 1, 1, 1, 2, 2, 0, 2, 2, 1, 0, 2, 1, 2, @@ -575,7 +574,7 @@ static const int parse_cmd_key_m_error = 0; static const int parse_cmd_key_m_en_main = 1; -#line 379 "crontab.rl" +#line 378 "crontab.rl" static void parse_command_key(ParseCfgState &ncs) @@ -592,15 +591,15 @@ static void parse_command_key(ParseCfgState &ncs) } -#line 575 "crontab.cpp" +#line 574 "crontab.cpp" { pckm.cs = (int)parse_cmd_key_m_start; } -#line 394 "crontab.rl" +#line 393 "crontab.rl" -#line 580 "crontab.cpp" +#line 579 "crontab.cpp" { unsigned int _trans = 0; const char * _keys; @@ -644,16 +643,16 @@ static void parse_command_key(ParseCfgState &ncs) { case 0: { { -#line 337 "crontab.rl" +#line 336 "crontab.rl" pckm.st = p; } -#line 626 "crontab.cpp" +#line 625 "crontab.cpp" break; } case 1: { { -#line 338 "crontab.rl" +#line 337 "crontab.rl" size_t l = p > pckm.st ? static_cast(p - pckm.st) : 0; if (l) { @@ -679,13 +678,13 @@ static void parse_command_key(ParseCfgState &ncs) } } -#line 657 "crontab.cpp" +#line 656 "crontab.cpp" break; } case 2: { { -#line 362 "crontab.rl" +#line 361 "crontab.rl" size_t l = p > pckm.st ? static_cast(p - pckm.st) : 0; if (l) { @@ -696,7 +695,7 @@ static void parse_command_key(ParseCfgState &ncs) } } -#line 673 "crontab.cpp" +#line 672 "crontab.cpp" break; } @@ -720,7 +719,7 @@ static void parse_command_key(ParseCfgState &ncs) _out: {} } -#line 395 "crontab.rl" +#line 394 "crontab.rl" if (pckm.cs == parse_cmd_key_m_error) { @@ -737,8 +736,7 @@ static void parse_command_key(ParseCfgState &ncs) static void parse_time_unit(const ParseCfgState &ncs, const char *p, unsigned unit, unsigned *dest) { unsigned t; - auto offs = p > (ncs.time_st + 1) ? static_cast(p - ncs.time_st - 1) : 0; - if (!nk::from_string(ncs.time_st, offs, &t)) { + if (!strconv_to_u32(ncs.time_st, p - 1, &t)) { log_line("Invalid time unit at line %zu", ncs.linenum); exit(EXIT_FAILURE); } @@ -747,18 +745,18 @@ static void parse_time_unit(const ParseCfgState &ncs, const char *p, unsigned un static void parse_int_value(const char *p, const char *start, size_t linenum, int *dest) { - if (!nk::from_string(start, p > start ? static_cast(p - start) : 0, dest)) { + if (!strconv_to_i32(start, p, dest)) { log_line("Invalid integer value at line %zu", linenum); exit(EXIT_FAILURE); } } -#line 534 "crontab.rl" +#line 532 "crontab.rl" -#line 731 "crontab.cpp" +#line 729 "crontab.cpp" static const signed char _ncrontab_actions[] = { 0, 1, 0, 1, 1, 1, 2, 1, 3, 1, 4, 1, 5, 1, 6, 1, @@ -996,7 +994,7 @@ static const int ncrontab_error = 0; static const int ncrontab_en_main = 1; -#line 536 "crontab.rl" +#line 534 "crontab.rl" static int do_parse_config(ParseCfgState &ncs, const char *p, size_t plen) @@ -1005,15 +1003,15 @@ static int do_parse_config(ParseCfgState &ncs, const char *p, size_t plen) const char *eof = pe; -#line 975 "crontab.cpp" +#line 973 "crontab.cpp" { ncs.cs = (int)ncrontab_start; } -#line 543 "crontab.rl" +#line 541 "crontab.rl" -#line 980 "crontab.cpp" +#line 978 "crontab.cpp" { unsigned int _trans = 0; const char * _keys; @@ -1057,135 +1055,135 @@ static int do_parse_config(ParseCfgState &ncs, const char *p, size_t plen) { case 0: { { -#line 434 "crontab.rl" +#line 432 "crontab.rl" ncs.time_st = p; ncs.v_time = 0; } -#line 1026 "crontab.cpp" +#line 1024 "crontab.cpp" break; } case 1: { { -#line 435 "crontab.rl" +#line 433 "crontab.rl" parse_time_unit(ncs, p, 1, &ncs.v_time); } -#line 1034 "crontab.cpp" +#line 1032 "crontab.cpp" break; } case 2: { { -#line 436 "crontab.rl" +#line 434 "crontab.rl" parse_time_unit(ncs, p, 60, &ncs.v_time); } -#line 1042 "crontab.cpp" +#line 1040 "crontab.cpp" break; } case 3: { { -#line 437 "crontab.rl" +#line 435 "crontab.rl" parse_time_unit(ncs, p, 3600, &ncs.v_time); } -#line 1050 "crontab.cpp" +#line 1048 "crontab.cpp" break; } case 4: { { -#line 438 "crontab.rl" +#line 436 "crontab.rl" parse_time_unit(ncs, p, 86400, &ncs.v_time); } -#line 1058 "crontab.cpp" +#line 1056 "crontab.cpp" break; } case 5: { { -#line 439 "crontab.rl" +#line 437 "crontab.rl" parse_time_unit(ncs, p, 604800, &ncs.v_time); } -#line 1066 "crontab.cpp" +#line 1064 "crontab.cpp" break; } case 6: { { -#line 441 "crontab.rl" +#line 439 "crontab.rl" ncs.intv_st = p; ncs.v_int1 = ncs.v_int2 = 0; ncs.intv2_exist = false; } -#line 1078 "crontab.cpp" +#line 1076 "crontab.cpp" break; } case 7: { { -#line 446 "crontab.rl" +#line 444 "crontab.rl" parse_int_value(p, ncs.intv_st, ncs.linenum, &ncs.v_int1); } -#line 1086 "crontab.cpp" +#line 1084 "crontab.cpp" break; } case 8: { { -#line 447 "crontab.rl" +#line 445 "crontab.rl" ncs.intv2_st = p; } -#line 1094 "crontab.cpp" +#line 1092 "crontab.cpp" break; } case 9: { { -#line 448 "crontab.rl" +#line 446 "crontab.rl" parse_int_value(p, ncs.intv2_st, ncs.linenum, &ncs.v_int2); ncs.intv2_exist = true; } -#line 1102 "crontab.cpp" +#line 1100 "crontab.cpp" break; } case 10: { { -#line 449 "crontab.rl" +#line 447 "crontab.rl" using std::swap; swap(ncs.v_int1, ncs.v_int3); swap(ncs.v_int2, ncs.v_int4); } -#line 1114 "crontab.cpp" +#line 1112 "crontab.cpp" break; } case 11: { { -#line 454 "crontab.rl" +#line 452 "crontab.rl" ncs.v_int3 = -1; ncs.v_int4 = -1; } -#line 1125 "crontab.cpp" +#line 1123 "crontab.cpp" break; } case 12: { { -#line 459 "crontab.rl" +#line 457 "crontab.rl" ncs.strv_st = p; ncs.v_strlen = 0; } -#line 1133 "crontab.cpp" +#line 1131 "crontab.cpp" break; } case 13: { { -#line 460 "crontab.rl" +#line 458 "crontab.rl" ncs.v_strlen = p > ncs.strv_st ? static_cast(p - ncs.strv_st) : 0; if (ncs.v_strlen >= sizeof ncs.v_str) { @@ -1196,22 +1194,22 @@ static int do_parse_config(ParseCfgState &ncs, const char *p, size_t plen) ncs.v_str[ncs.v_strlen] = 0; } -#line 1149 "crontab.cpp" +#line 1147 "crontab.cpp" break; } case 14: { { -#line 483 "crontab.rl" +#line 481 "crontab.rl" ncs.ce->journal_ = true; } -#line 1157 "crontab.cpp" +#line 1155 "crontab.cpp" break; } case 15: { { -#line 486 "crontab.rl" +#line 484 "crontab.rl" ncs.ce->runat_ = true; ncs.ce->exectime_ = ncs.v_int1; @@ -1219,100 +1217,100 @@ static int do_parse_config(ParseCfgState &ncs, const char *p, size_t plen) ncs.ce->journal_ = true; } -#line 1170 "crontab.cpp" +#line 1168 "crontab.cpp" break; } case 16: { { -#line 492 "crontab.rl" +#line 490 "crontab.rl" if (!ncs.ce->runat_) ncs.ce->maxruns_ = ncs.v_int1 > 0 ? static_cast(ncs.v_int1) : 0; } -#line 1181 "crontab.cpp" +#line 1179 "crontab.cpp" break; } case 17: { { -#line 500 "crontab.rl" +#line 498 "crontab.rl" ncs.ce->interval_ = ncs.v_time; } -#line 1189 "crontab.cpp" +#line 1187 "crontab.cpp" break; } case 18: { { -#line 509 "crontab.rl" +#line 507 "crontab.rl" add_cst_mon(ncs); } -#line 1197 "crontab.cpp" +#line 1195 "crontab.cpp" break; } case 19: { { -#line 510 "crontab.rl" +#line 508 "crontab.rl" add_cst_mday(ncs); } -#line 1205 "crontab.cpp" +#line 1203 "crontab.cpp" break; } case 20: { { -#line 511 "crontab.rl" +#line 509 "crontab.rl" add_cst_wday(ncs); } -#line 1213 "crontab.cpp" +#line 1211 "crontab.cpp" break; } case 21: { { -#line 512 "crontab.rl" +#line 510 "crontab.rl" add_cst_time(ncs); } -#line 1221 "crontab.cpp" +#line 1219 "crontab.cpp" break; } case 22: { { -#line 519 "crontab.rl" +#line 517 "crontab.rl" parse_command_key(ncs); } -#line 1229 "crontab.cpp" +#line 1227 "crontab.cpp" break; } case 23: { { -#line 526 "crontab.rl" +#line 524 "crontab.rl" ncs.jobid_st = p; } -#line 1237 "crontab.cpp" +#line 1235 "crontab.cpp" break; } case 24: { { -#line 527 "crontab.rl" +#line 525 "crontab.rl" parse_int_value(p, ncs.jobid_st, ncs.linenum, &ncs.ce->id_); } -#line 1245 "crontab.cpp" +#line 1243 "crontab.cpp" break; } case 25: { { -#line 528 "crontab.rl" +#line 526 "crontab.rl" ncs.finish_ce(); ncs.create_ce(); } -#line 1253 "crontab.cpp" +#line 1251 "crontab.cpp" break; } @@ -1336,7 +1334,7 @@ static int do_parse_config(ParseCfgState &ncs, const char *p, size_t plen) _out: {} } -#line 544 "crontab.rl" +#line 542 "crontab.rl" if (ncs.cs == ncrontab_error) diff --git a/crontab.rl b/crontab.rl index dc52005..b7d6a5c 100644 --- a/crontab.rl +++ b/crontab.rl @@ -6,10 +6,11 @@ #include #include #include -#include +#include extern "C" { #include "nk/log.h" #include "xmalloc.h" +#include "strconv.h" } #include "ncron.hpp" #include "sched.hpp" @@ -139,33 +140,31 @@ struct hstm { } }; -#define MARKED_HST() hst.st, (p > hst.st ? static_cast(p - hst.st) : 0) - %%{ machine history_m; access hst.; action St { hst.st = p; } action LastTimeEn { - if (!nk::from_string(MARKED_HST(), &hst.h.lasttime)) { + if (!strconv_to_i64(hst.st, p, &hst.h.lasttime)) { hst.parse_error = true; fbreak; } } action NumRunsEn { - if (!nk::from_string(MARKED_HST(), &hst.h.numruns)) { + if (!strconv_to_u32(hst.st, p, &hst.h.numruns)) { hst.parse_error = true; fbreak; } } action ExecTimeEn { - if (!nk::from_string(MARKED_HST(), &hst.h.exectime)) { + if (!strconv_to_i64(hst.st, p, &hst.h.exectime)) { hst.parse_error = true; fbreak; } } action IdEn { - if (!nk::from_string(MARKED_HST(), &hst.id)) { + if (!strconv_to_i32(hst.st, p, &hst.id)) { hst.parse_error = true; fbreak; } @@ -408,8 +407,7 @@ static void parse_command_key(ParseCfgState &ncs) static void parse_time_unit(const ParseCfgState &ncs, const char *p, unsigned unit, unsigned *dest) { unsigned t; - auto offs = p > (ncs.time_st + 1) ? static_cast(p - ncs.time_st - 1) : 0; - if (!nk::from_string(ncs.time_st, offs, &t)) { + if (!strconv_to_u32(ncs.time_st, p - 1, &t)) { log_line("Invalid time unit at line %zu", ncs.linenum); exit(EXIT_FAILURE); } @@ -418,7 +416,7 @@ static void parse_time_unit(const ParseCfgState &ncs, const char *p, unsigned un static void parse_int_value(const char *p, const char *start, size_t linenum, int *dest) { - if (!nk::from_string(start, p > start ? static_cast(p - start) : 0, dest)) { + if (!strconv_to_i32(start, p, dest)) { log_line("Invalid integer value at line %zu", linenum); exit(EXIT_FAILURE); } diff --git a/ncron.cpp b/ncron.cpp index c6ed08e..e513fe5 100644 --- a/ncron.cpp +++ b/ncron.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MIT #include #include +#include #include #include @@ -19,11 +20,11 @@ #include #endif -#include extern "C" { #include "nk/log.h" #include "nk/io.h" #include "xmalloc.h" +#include "strconv.h" } #include "ncron.hpp" #include "sched.hpp" @@ -310,7 +311,7 @@ static void process_options(int ac, char *av[]) switch (c) { case 'h': usage(); exit(EXIT_SUCCESS); break; case 'v': print_version(); exit(EXIT_SUCCESS); break; - case 's': if (!nk::from_string(optarg, &g_initial_sleep)) { + case 's': if (!strconv_to_u32(optarg, optarg + strlen(optarg), &g_initial_sleep)) { log_line("invalid sleep '%s' specified", optarg); exit(EXIT_FAILURE); } diff --git a/nk/from_string.hpp b/nk/from_string.hpp deleted file mode 100644 index 615e73c..0000000 --- a/nk/from_string.hpp +++ /dev/null @@ -1,283 +0,0 @@ -#ifndef NKLIB_FROM_STRING_HPP_ -#define NKLIB_FROM_STRING_HPP_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace nk { - namespace detail { - template - [[nodiscard]] constexpr bool str_to_signed_integer(const char *s, T *result) - { - using ut = typename std::make_unsigned::type; - constexpr auto maxut = static_cast::type>(std::numeric_limits::max()); - ut ret(0), digit(0); - const bool neg = (*s == '-'); - if (neg) ++s; - if (!(s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))) { - do { - if (*s < '0' || *s > '9') - return false; - if (ret > maxut / 10) { - ret = std::numeric_limits::max(); - break; - } - digit = static_cast(*s) - '0'; - ret = ret * 10u + digit; - } while (*++s); - } else { - s += 2; - do { - if (*s >= '0' && *s <= '9') - digit = static_cast(*s) - '0'; - else if (*s >= 'A' && *s <= 'F') - digit = static_cast(*s) - 'A' + ut{ 10 }; - else if (*s >= 'a' && *s <= 'f') - digit = static_cast(*s) - 'a' + ut{ 10 }; - else - return false; - if (ret > maxut / 16) { - ret = std::numeric_limits::max(); - break; - } - ret = ret * 16u + digit; - } while (*++s); - } - if (ret > maxut + neg) - return false; // out of range - *result = neg ? -static_cast(ret) : static_cast(ret); - return true; - } - template - [[nodiscard]] constexpr bool str_to_signed_integer(const char *s, size_t c, T *result) - { - using ut = typename std::make_unsigned::type; - constexpr auto maxut = static_cast::type>(std::numeric_limits::max()); - ut ret(0), digit(0); - if (c == 0) - return false; - const ut neg = (*s == '-'); - if (neg) ++s, c--; - if (c == 0) - return false; - if (!(c > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))) { - do { - if (*s < '0' || *s > '9') - return false; - if (ret > maxut / 10) { - ret = std::numeric_limits::max(); - break; - } - digit = static_cast(*s) - '0'; - ret = ret * 10u + digit; - } while (++s, --c); - } else { - s += 2; c -= 2; - do { - if (*s >= '0' && *s <= '9') - digit = static_cast(*s) - '0'; - else if (*s >= 'A' && *s <= 'F') - digit = static_cast(*s) - 'A' + ut{ 10 }; - else if (*s >= 'a' && *s <= 'f') - digit = static_cast(*s) - 'a' + ut{ 10 }; - else - return false; - if (ret > maxut / 16) { - ret = std::numeric_limits::max(); - break; - } - ret = ret * 16u + digit; - } while (++s, --c); - } - if (ret > maxut + neg) - return false; // out of range - *result = neg ? -static_cast(ret) : static_cast(ret); - return true; - } - template - [[nodiscard]] constexpr bool str_to_unsigned_integer(const char *s, T *result) - { - T ret(0), digit(0); - const bool neg = (*s == '-'); - if (neg) - return false; // out of range - if (!(s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))) { - do { - if (*s < '0' || *s > '9') - return false; - if (ret > std::numeric_limits::max() / 10) - return false; // out of range - digit = static_cast(*s) - '0'; - ret = ret * 10u + digit; - } while (*++s); - } else { - s += 2; - do { - if (*s >= '0' && *s <= '9') - digit = static_cast(*s) - '0'; - else if (*s >= 'A' && *s <= 'F') - digit = static_cast(*s) - 'A' + T{ 10 }; - else if (*s >= 'a' && *s <= 'f') - digit = static_cast(*s) - 'a' + T{ 10 }; - else - return false; - if (ret > std::numeric_limits::max() / 16) - return false; // out of range - ret = ret * 16u + digit; - } while (*++s); - } - *result = ret; - return true; - } - template - [[nodiscard]] constexpr bool str_to_unsigned_integer(const char *s, size_t c, T *result) - { - T ret(0), digit(0); - if (c == 0) - return false; - const bool neg = (*s == '-'); - if (neg) - return false; // out of range - if (!(c > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))) { - do { - if (*s < '0' || *s > '9') - return false; - if (ret > std::numeric_limits::max() / 10) - return false; // out of range - digit = static_cast(*s) - '0'; - ret = ret * 10u + digit; - } while (++s, --c); - } else { - s += 2; c -= 2; - do { - if (*s >= '0' && *s <= '9') - digit = static_cast(*s) - '0'; - else if (*s >= 'A' && *s <= 'F') - digit = static_cast(*s) - 'A' + T{ 10 }; - else if (*s >= 'a' && *s <= 'f') - digit = static_cast(*s) - 'a' + T{ 10 }; - else - return false; - if (ret > std::numeric_limits::max() / 16) - return false; // out of range - ret = ret * 16u + digit; - } while (++s, --c); - } - *result = ret; - return true; - } - - [[nodiscard]] static inline bool str_to_double(const char *s, size_t c, double *result) - { - double v; - const auto ret = std::from_chars(s, s + c, v); - if (ret.ec == std::errc{}) { - *result = v; - return true; - } - return false; - } - [[nodiscard]] static inline bool str_to_float(const char *s, size_t c, float *result) - { - float v; - const auto ret = std::from_chars(s, s + c, v); - if (ret.ec == std::errc{}) { - *result = v; - return true; - } - return false; - } - [[nodiscard]] static inline bool str_to_long_double(const char *s, size_t c, long double *result) - { - long double v; - const auto ret = std::from_chars(s, s + c, v); - if (ret.ec == std::errc{}) { - *result = v; - return true; - } - return false; - } - [[nodiscard]] static inline bool str_to_double(const char *s, double *result) - { - return str_to_double(s, strlen(s), result); - } - [[nodiscard]] static inline bool str_to_float(const char *s, float *result) - { - return str_to_float(s, strlen(s), result); - } - [[nodiscard]] static inline bool str_to_long_double(const char *s, long double *result) - { - return str_to_long_double(s, strlen(s), result); - } - - template - [[nodiscard]] bool do_from_string(const char *s, T *result) - { - static_assert(std::is_integral_v || std::is_floating_point_v, "T must be integer or floating point type"); - if constexpr (std::is_integral_v) { - if constexpr (std::is_signed_v) { - return detail::str_to_signed_integer(s, result); - } else { - return detail::str_to_unsigned_integer(s, result); - } - } else if constexpr (std::is_floating_point_v) { - if constexpr (std::is_same_v::type, double>) { - return str_to_double(s, result); - } else if constexpr (std::is_same_v::type, float>) { - return str_to_float(s, result); - } else if constexpr (std::is_same_v::type, long double>) { - return str_to_long_double(s, result); - } - } - } - template - [[nodiscard]] bool do_from_string(const char *s, size_t c, T *result) - { - static_assert(std::is_integral_v || std::is_floating_point_v, "T must be integer or floating point type"); - if constexpr (std::is_integral_v) { - if constexpr (std::is_signed_v) { - return detail::str_to_signed_integer(s, c, result); - } else { - return detail::str_to_unsigned_integer(s, c, result); - } - } else if constexpr (std::is_floating_point_v) { - if constexpr (std::is_same_v::type, double>) { - return str_to_double(s, c, result); - } else if constexpr (std::is_same_v::type, float>) { - return str_to_float(s, c, result); - } else if constexpr (std::is_same_v::type, long double>) { - return str_to_long_double(s, c, result); - } - } - } - } - - template - [[nodiscard]] bool from_string(const char *s, T *result) - { - return detail::do_from_string(s, result); - } - template - [[nodiscard]] bool from_string(const char *s, size_t c, T *result) - { - return detail::do_from_string(s, c, result); - } - template - [[nodiscard]] bool from_string(const std::string &s, T *result) - { - return detail::do_from_string(s.data(), s.size(), result); - } - template - [[nodiscard]] bool from_string(std::string_view s, T *result) - { - return detail::do_from_string(s.data(), s.size(), result); - } -} -#endif diff --git a/strconv.c b/strconv.c new file mode 100644 index 0000000..494bc35 --- /dev/null +++ b/strconv.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include "strconv.h" + +bool strconv_to_u32(const char *str, const char *strend, uint32_t *val) +{ + char *endptr; + unsigned long r = strtoul(str, (char **)&endptr, 10); + if (r == ULONG_MAX && errno == ERANGE) + return false; + if (*str != '\0' && *endptr == *strend) { + *val = r; + return true; + } + return false; +} + +bool strconv_to_u64(const char *str, const char *strend, uint64_t *val) +{ + char *endptr; + unsigned long long r = strtoull(str, &endptr, 10); + if (r == ULLONG_MAX && errno == ERANGE) + return false; + if (*str != '\0' && *endptr == *strend) { + *val = r; + return true; + } + return false; +} + +bool strconv_to_i32(const char *str, const char *strend, int32_t *val) +{ + char *endptr; + long r = strtol(str, &endptr, 10); + if ((r == LONG_MAX || r == LONG_MIN) && errno == ERANGE) + return false; + if (*str != '\0' && *endptr == *strend) { + *val = r; + return true; + } + return false; +} + +bool strconv_to_i64(const char *str, const char *strend, int64_t *val) +{ + char *endptr; + long long r = strtoll(str, &endptr, 10); + if ((r == LLONG_MAX || r == LLONG_MIN) && errno == ERANGE) + return false; + if (*str != '\0' && *endptr == *strend) { + *val = r; + return true; + } + return false; +} diff --git a/strconv.h b/strconv.h new file mode 100644 index 0000000..e178ac3 --- /dev/null +++ b/strconv.h @@ -0,0 +1,11 @@ +#ifndef NCRON_STRCONV_H_ +#define NCRON_STRCONV_H_ +#include +#include + +bool strconv_to_u32(const char *str, const char *strend, uint32_t *val); +bool strconv_to_u64(const char *str, const char *strend, uint64_t *val); +bool strconv_to_i32(const char *str, const char *strend, int32_t *val); +bool strconv_to_i64(const char *str, const char *strend, int64_t *val); + +#endif