diff --git a/ChangeLog b/ChangeLog index 98c3f77e..d4e06437 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,7 @@ 2022-01-23 Alex Kotov * include/kernaux/assert.h: Require semicolon after macros - * include/kernaux/libc.h: Add funcs "isdigit", "isspace" + * include/kernaux/libc.h: Add funcs "atoi", "isdigit", "isspace" 2022-01-22 Alex Kotov diff --git a/README.md b/README.md index 3433203f..df8bf4ce 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,7 @@ stable options. * `--with-libc` - provides the replacement for some standard C functions. Useful in freestanding environment, where no libc is present. You can also separately include or exclude components: + * `--with[out]-libc-atoi` * `--with[out]-libc-isdigit` * `--with[out]-libc-isspace` * `--with[out]-libc-memset` diff --git a/configure.ac b/configure.ac index 4970ac11..4ac98338 100644 --- a/configure.ac +++ b/configure.ac @@ -35,6 +35,7 @@ AC_ARG_WITH( [units], AS_HELP_STRING([--without-units], [without m dnl Packages (disabled by default) AC_ARG_WITH( [libc], AS_HELP_STRING([--with-libc], [with libc replacement])) +AC_ARG_WITH( [libc-atoi], AS_HELP_STRING([--with-libc-atoi], [with atoi replacement])) AC_ARG_WITH( [libc-isdigit], AS_HELP_STRING([--with-libc-isdigit], [with isdigit replacement])) AC_ARG_WITH( [libc-isspace], AS_HELP_STRING([--with-libc-isspace], [with isspace replacement])) AC_ARG_WITH( [libc-memset], AS_HELP_STRING([--with-libc-memset], [with memset replacement])) @@ -61,6 +62,7 @@ AS_IF([test "$with_all" = no], do_without_all) AC_DEFUN([do_with_libc], [ +if test -z "$with_libc_atoi"; then with_libc_atoi=yes; fi if test -z "$with_libc_isdigit"; then with_libc_isdigit=yes; fi if test -z "$with_libc_isspace"; then with_libc_isspace=yes; fi if test -z "$with_libc_memset"; then with_libc_memset=yes; fi @@ -104,6 +106,7 @@ AM_CONDITIONAL([WITH_PRINTF], [test "$with_printf" != no]) AM_CONDITIONAL([WITH_UNITS], [test "$with_units" != no]) dnl Packages (disabled by default) +AM_CONDITIONAL([WITH_LIBC_ATOI], [test "$with_libc_atoi" = yes]) AM_CONDITIONAL([WITH_LIBC_ISDIGIT], [test "$with_libc_isdigit" = yes]) AM_CONDITIONAL([WITH_LIBC_ISSPACE], [test "$with_libc_isspace" = yes]) AM_CONDITIONAL([WITH_LIBC_MEMSET], [test "$with_libc_memset" = yes]) @@ -138,6 +141,7 @@ AS_IF([test "$with_printf" != no], [AC_DEFINE([WITH_PRINTF], [1] AS_IF([test "$with_units", != no], [AC_DEFINE([WITH_UNITS], [1], [with measurement units utils])]) dnl Packages (disabled by default) +AS_IF([test "$with_libc_atoi" = yes], [AC_DEFINE([WITH_LIBC_ATOI], [1], [with atoi replacement])]) AS_IF([test "$with_libc_isdigit" = yes], [AC_DEFINE([WITH_LIBC_ISDIGIT], [1], [with isdigit replacement])]) AS_IF([test "$with_libc_isspace" = yes], [AC_DEFINE([WITH_LIBC_ISSPACE], [1], [with isspace replacement])]) AS_IF([test "$with_libc_memset" = yes], [AC_DEFINE([WITH_LIBC_MEMSET], [1], [with memset replacement])]) diff --git a/include/kernaux/libc.h b/include/kernaux/libc.h index 69471f59..d9c55002 100644 --- a/include/kernaux/libc.h +++ b/include/kernaux/libc.h @@ -11,6 +11,9 @@ extern "C" { int isdigit(int c); int isspace(int c); +// +int atoi(const char *str); + // void *memset(void *s, int c, size_t n); char *strcpy(char *dest, const char *src); diff --git a/src/libc.c b/src/libc.c index 3dc58894..0f28b822 100644 --- a/src/libc.c +++ b/src/libc.c @@ -4,6 +4,23 @@ #include +#include + +#ifdef WITH_LIBC_ATOI +int atoi(const char *str) +{ + while (isspace(*str)) ++str; + bool is_negative = false; + switch (*str) { + case '-': is_negative = true; + case '+': ++str; + } + int result = 0; + while (isdigit(*str)) result = 10 * result - (*str++ - '0'); + return is_negative ? result : -result; +} +#endif // WITH_LIBC_ATOI + #ifdef WITH_LIBC_ISDIGIT int isdigit(const int c) { diff --git a/src/printf.c b/src/printf.c index 1278a41c..e55d1d41 100644 --- a/src/printf.c +++ b/src/printf.c @@ -444,11 +444,9 @@ void _out_fct(char character, void* buffer, size_t idx, size_t maxlen) // internal ASCII string to unsigned int conversion unsigned int _atoi(const char** str) { - unsigned int i = 0u; - while (isdigit(**str)) { - i = i * 10u + (unsigned int)(*((*str)++) - '0'); - } - return i; + const int result = atoi(*str); + while (isdigit(**str)) (*str)++; + return result; } // output the specified string in reverse, taking care of any zero-padding