%% options copyright owner = Dirk Krause copyright year = 2014-xxxx license = bsd %% header /** @file dk3maidd.h Retrieve numbers from decimal dkChar strings. */ #include #include #if DK3_HAVE_SYS_TYPES_H #include #endif #if DK3_HAVE_STDINT #include #endif #if DK3_HAVE_INTTYPES_H #include #endif #if DK3_HAVE_LIMITS_H #include #endif #if DK3_HAVE_MATH_H #include #endif #if DK3_HAVE_FLOAT_H #include #endif #include #ifdef __cplusplus extern "C" { #endif /** Convert string to dk3_um_t. @param rp Pointer to result variable. @param src Source text to convert. @param ec Pointer to error code variable, may be NULL. Set to DK3_ERROR_INVALID_ARGS if rp and/or src is NULL, DK3_ERROR_SYNTAX if unacceptable characters found, DK3_ERROR_MATH_OVERFLOW on numeric overflow. @return 1 on success, 0 on error (see ec). If trailing garbage is found after the number, the function returns 1 and sets the error code variable to DK3_ERROR_SYNTAX. */ int dk3ma_um_from_string(dk3_um_t *rp, dkChar const *src, int *ec); /** Convert string to dk3_im_t. @param rp Pointer to result variable. @param src Source text to convert. @param ec Pointer to error code variable, may be NULL. Set to DK3_ERROR_INVALID_ARGS if rp and/or src is NULL, DK3_ERROR_SYNTAX if unacceptable characters found, DK3_ERROR_MATH_OVERFLOW on numeric overflow. @return 1 on success, 0 on error (see ec). If trailing garbage is found after the number, the function returns 1 and sets the error code variable to DK3_ERROR_SYNTAX. */ int dk3ma_im_from_string(dk3_im_t *rp, dkChar const *src, int *ec); /** Convert string to short. @param rp Pointer to result variable. @param src Source text to convert. @param ec Pointer to error code variable, may be NULL. Set to DK3_ERROR_INVALID_ARGS if rp and/or src is NULL, DK3_ERROR_SYNTAX if unacceptable characters found, DK3_ERROR_MATH_OVERFLOW on numeric overflow. @return 1 on success, 0 on error (see ec). If trailing garbage is found after the number, the function returns 1 and sets the error code variable to DK3_ERROR_SYNTAX. */ int dk3ma_s_from_string(short *rp, dkChar const *src, int *ec); /** Convert string to unsigned short. @param rp Pointer to result variable. @param src Source text to convert. @param ec Pointer to error code variable, may be NULL. Set to DK3_ERROR_INVALID_ARGS if rp and/or src is NULL, DK3_ERROR_SYNTAX if unacceptable characters found, DK3_ERROR_MATH_OVERFLOW on numeric overflow. @return 1 on success, 0 on error (see ec). If trailing garbage is found after the number, the function returns 1 and sets the error code variable to DK3_ERROR_SYNTAX. */ int dk3ma_us_from_string(unsigned short *rp, dkChar const *src, int *ec); /** Convert string to int. @param rp Pointer to result variable. @param src Source text to convert. @param ec Pointer to error code variable, may be NULL. Set to DK3_ERROR_INVALID_ARGS if rp and/or src is NULL, DK3_ERROR_SYNTAX if unacceptable characters found, DK3_ERROR_MATH_OVERFLOW on numeric overflow. @return 1 on success, 0 on error (see ec). If trailing garbage is found after the number, the function returns 1 and sets the error code variable to DK3_ERROR_SYNTAX. */ int dk3ma_i_from_string(int *rp, dkChar const *src, int *ec); /** Convert string to unsigned. @param rp Pointer to result variable. @param src Source text to convert. @param ec Pointer to error code variable, may be NULL. Set to DK3_ERROR_INVALID_ARGS if rp and/or src is NULL, DK3_ERROR_SYNTAX if unacceptable characters found, DK3_ERROR_MATH_OVERFLOW on numeric overflow. @return 1 on success, 0 on error (see ec). If trailing garbage is found after the number, the function returns 1 and sets the error code variable to DK3_ERROR_SYNTAX. */ int dk3ma_ui_from_string(unsigned *rp, dkChar const *src, int *ec); /** Convert string to long. @param rp Pointer to result variable. @param src Source text to convert. @param ec Pointer to error code variable, may be NULL. Set to DK3_ERROR_INVALID_ARGS if rp and/or src is NULL, DK3_ERROR_SYNTAX if unacceptable characters found, DK3_ERROR_MATH_OVERFLOW on numeric overflow. @return 1 on success, 0 on error (see ec). If trailing garbage is found after the number, the function returns 1 and sets the error code variable to DK3_ERROR_SYNTAX. */ int dk3ma_l_from_string(long *rp, dkChar const *src, int *ec); /** Convert string to unsigned long. @param rp Pointer to result variable. @param src Source text to convert. @param ec Pointer to error code variable, may be NULL. Set to DK3_ERROR_INVALID_ARGS if rp and/or src is NULL, DK3_ERROR_SYNTAX if unacceptable characters found, DK3_ERROR_MATH_OVERFLOW on numeric overflow. @return 1 on success, 0 on error (see ec). If trailing garbage is found after the number, the function returns 1 and sets the error code variable to DK3_ERROR_SYNTAX. */ int dk3ma_ul_from_string(unsigned long *rp, dkChar const *src, int *ec); #if DK3_HAVE_LONG_LONG /** Convert string to long long. @param rp Pointer to result variable. @param src Source text to convert. @param ec Pointer to error code variable, may be NULL. Set to DK3_ERROR_INVALID_ARGS if rp and/or src is NULL, DK3_ERROR_SYNTAX if unacceptable characters found, DK3_ERROR_MATH_OVERFLOW on numeric overflow. @return 1 on success, 0 on error (see ec). If trailing garbage is found after the number, the function returns 1 and sets the error code variable to DK3_ERROR_SYNTAX. */ int dk3ma_ll_from_string(long long *rp, dkChar const *src, int *ec); /** Convert string to unsigned long long. @param rp Pointer to result variable. @param src Source text to convert. @param ec Pointer to error code variable, may be NULL. Set to DK3_ERROR_INVALID_ARGS if rp and/or src is NULL, DK3_ERROR_SYNTAX if unacceptable characters found, DK3_ERROR_MATH_OVERFLOW on numeric overflow. @return 1 on success, 0 on error (see ec). If trailing garbage is found after the number, the function returns 1 and sets the error code variable to DK3_ERROR_SYNTAX. */ int dk3ma_ull_from_string(unsigned long long *rp, dkChar const *src, int *ec); #endif #if DK3_HAVE_INTMAX_T /** Convert string to intmax_t. @param rp Pointer to result variable. @param src Source text to convert. @param ec Pointer to error code variable, may be NULL. Set to DK3_ERROR_INVALID_ARGS if rp and/or src is NULL, DK3_ERROR_SYNTAX if unacceptable characters found, DK3_ERROR_MATH_OVERFLOW on numeric overflow. @return 1 on success, 0 on error (see ec). If trailing garbage is found after the number, the function returns 1 and sets the error code variable to DK3_ERROR_SYNTAX. */ int dk3ma_intmax_t_from_string(intmax_t *rp, dkChar const *src, int *ec); /** Convert string to uintmax_t. @param rp Pointer to result variable. @param src Source text to convert. @param ec Pointer to error code variable, may be NULL. Set to DK3_ERROR_INVALID_ARGS if rp and/or src is NULL, DK3_ERROR_SYNTAX if unacceptable characters found, DK3_ERROR_MATH_OVERFLOW on numeric overflow. @return 1 on success, 0 on error (see ec). If trailing garbage is found after the number, the function returns 1 and sets the error code variable to DK3_ERROR_SYNTAX. */ int dk3ma_uintmax_t_from_string(uintmax_t *rp, dkChar const *src, int *ec); #endif #ifdef __cplusplus } #endif %% module #include "dk3ma.h" $!trace-include /** Constant numeric values. */ static dk3_um_t const dk3maidd_um_array[] = { #if DK3_HAVE_LONG_LONG /* 0 */ (dk3_um_t)10ULL, /* 1 */ (dk3_um_t)1ULL, /* 2 */ (dk3_um_t)2ULL, /* 3 */ (dk3_um_t)3ULL, /* 4 */ (dk3_um_t)4ULL, /* 5 */ (dk3_um_t)5ULL, /* 6 */ (dk3_um_t)6ULL, /* 7 */ (dk3_um_t)7ULL, /* 8 */ (dk3_um_t)8ULL, /* 9 */ (dk3_um_t)9ULL, /* 10 */ (dk3_um_t)10ULL, /* 11 */ (dk3_um_t)11ULL, /* 12 */ (dk3_um_t)12ULL, /* 13 */ (dk3_um_t)13ULL, /* 14 */ (dk3_um_t)14ULL, /* 15 */ (dk3_um_t)15ULL, /* 16 */ (dk3_um_t)16ULL #else /* 0 */ (dk3_um_t)10UL, /* 1 */ (dk3_um_t)1UL, /* 2 */ (dk3_um_t)2UL, /* 3 */ (dk3_um_t)3UL, /* 4 */ (dk3_um_t)4UL, /* 5 */ (dk3_um_t)5UL, /* 6 */ (dk3_um_t)6UL, /* 7 */ (dk3_um_t)7UL, /* 8 */ (dk3_um_t)8UL, /* 9 */ (dk3_um_t)9UL, /* 10 */ (dk3_um_t)10UL, /* 11 */ (dk3_um_t)11UL, /* 12 */ (dk3_um_t)12UL, /* 13 */ (dk3_um_t)13UL, /* 14 */ (dk3_um_t)14UL, /* 15 */ (dk3_um_t)15UL, /* 16 */ (dk3_um_t)16UL #endif }; #if DK3_CHAR_SIZE > 1 /** Find start of text in string. @param str String to search for text. @return Pointer to start of text on success, NULL on error. */ static dkChar const * dk3maidd_str_start(dkChar const *str) { dkChar const *back = NULL; if (NULL != str) { back = str; while((dkT(' ') == *back) || (dkT('\t') == *back)) { back++; } switch(*back) { case dkT('\0'): case dkT('\n'): case dkT('\r'): { back = NULL; } break; } } return back; } #endif int dk3ma_um_from_string(dk3_um_t *rp, dkChar const *src, int *ec) { #if DK3_CHAR_SIZE > 1 dkChar const *ptr = NULL; /* Current char to process */ dk3_um_t val = DK3_UM_0; /* Value found */ dk3_um_t op = DK3_UM_0; /* Operand to add */ int mec = 0; /* Math error code */ int back = 0; /* Function result */ int found = 0; /* Flag: Digits found */ int cc = 1; /* Flag: Can continue */ int action = 0; /* Action to take */ $? "+ dk3ma_um_from_string \"%!ds\"", TR_STR(src) if ((NULL != rp) && (NULL != src)) { ptr = dk3maidd_str_start(src); if (NULL != ptr) { while (0 != cc) { action = 0; switch(*(ptr++)) { case dkT('\0'): { /* End of string */ cc = 0; if (0 != found) { back = 1; } else { if (NULL != ec) { *ec = DK3_ERROR_SYNTAX; } } } break; case dkT('0'): { found = 1; action = 1; op = DK3_UM_0; } break; case dkT('1'): { found = 1; action = 1; op = dk3maidd_um_array[1]; } break; case dkT('2'): { found = 1; action = 1; op = dk3maidd_um_array[2]; } break; case dkT('3'): { found = 1; action = 1; op = dk3maidd_um_array[3]; } break; case dkT('4'): { found = 1; action = 1; op = dk3maidd_um_array[4]; } break; case dkT('5'): { found = 1; action = 1; op = dk3maidd_um_array[5]; } break; case dkT('6'): { found = 1; action = 1; op = dk3maidd_um_array[6]; } break; case dkT('7'): { found = 1; action = 1; op = dk3maidd_um_array[7]; } break; case dkT('8'): { found = 1; action = 1; op = dk3maidd_um_array[8]; } break; case dkT('9'): { found = 1; action = 1; op = dk3maidd_um_array[9]; } break; default: { /* Non-digit */ cc = 0; if (0 != found) { back = 1; } if (NULL != ec) { *ec = DK3_ERROR_SYNTAX; } } break; } if (0 != cc) { switch(action) { case 1: { val = dk3ma_um_add_ok( dk3ma_um_mul_ok(val, dk3maidd_um_array[0], &mec), op, &mec ); $? ". mec = %d", mec if (0 != mec) { $? "! mec != 0" cc = 0; val = DK3_UM_MAX; if (NULL != ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } break; } } $? ". mec = %d", mec } } else { if (NULL != ec) { *ec = DK3_ERROR_SYNTAX; } } *rp = val; #if DK3_ON_WINDOWS $? ". value = %I64u", val #else #if DK3_HAVE_INTMAX_T $? ". value = %ju", val #else #if DK3_HAVE_LONG_LONG $? ". value = %llu", val #else $? ". value = %lu", val #endif #endif #endif } else { if (NULL != ec) { *ec = DK3_ERROR_INVALID_ARGS; } } $? "- dk3ma_um_from_string %d", back return back; #else return (dk3ma_um_from_c8_string(rp, src, ec)); #endif } int dk3ma_im_from_string(dk3_im_t *rp, dkChar const *src, int *ec) { #if DK3_CHAR_SIZE > 1 dkChar const *ptr = NULL; /* Start of text */ dk3_um_t umv = DK3_UM_0; /* Temporary value */ dk3_im_t val = DK3_IM_0; /* Conversion result */ int back = 0; /* Function result */ if ((NULL != rp) && (NULL != src)) { ptr = dk3maidd_str_start(src); if (NULL != ptr) { if (dkT('-') == *ptr) { ptr++; if (0 != dk3ma_um_from_string(&umv, ptr, ec)) { if ((dk3_um_t)DK3_IM_MAX >= umv) { val = (dk3_im_t)umv; val = DK3_IM_0 - val; back = 1; } else { val = DK3_IM_MIN; #if VERSION_BEFORE_20140924 if ((dk3_um_t)(DK3_IM_MAX + (dk3_im_t)1L) == umv) #else /* 2014-09-24: Fixed warning about integer overflow in constant. */ if (((dk3_um_t)(DK3_IM_MAX) + (dk3_um_t)1UL) == umv) #endif { back = 1; } else { if (NULL != ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } } else { val = (dk3_im_t)umv; } } else { if (0 != dk3ma_um_from_string(&umv, ptr, ec)) { if ((dk3_um_t)DK3_IM_MAX >= umv) { val = (dk3_im_t)umv; back = 1; } else { val = DK3_IM_MAX; if (NULL != ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } else { val = (dk3_im_t)umv; } } } else { if (NULL != ec) { *ec = DK3_ERROR_SYNTAX; } } *rp = val; } else { if (NULL != ec) { *ec = DK3_ERROR_INVALID_ARGS; } } return back; #else return (dk3ma_im_from_c8_string(rp, src, ec)); #endif } int dk3ma_us_from_string(unsigned short *rp, dkChar const *src, int *ec) { #if DK3_CHAR_SIZE > 1 dk3_um_t val = DK3_UM_0; int back = 0; if ((NULL != rp) && (NULL != src)) { if (0 != dk3ma_um_from_string(&val, src, ec)) { if ((dk3_um_t)DK3_US_MAX >= val) { *rp = (unsigned short)val; back = 1; } else { *rp = DK3_US_MAX; if (NULL != ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } else { *rp = (unsigned short)val; } } else { if (NULL != ec) { *ec = DK3_ERROR_INVALID_ARGS; } } return back; #else return (dk3ma_us_from_c8_string(rp, src, ec)); #endif } int dk3ma_s_from_string(short *rp, dkChar const *src, int *ec) { #if DK3_CHAR_SIZE > 1 dk3_im_t val = DK3_IM_0; int back = 0; if ((NULL != rp) && (NULL != src)) { if (0 != dk3ma_im_from_string(&val, src, ec)) { if (((dk3_im_t)DK3_S_MIN <= val) && ((dk3_im_t)DK3_S_MAX >= val)) { *rp = (short)val; back = 1; } else { if (DK3_IM_0 > val) { *rp = DK3_S_MIN; } else { *rp = DK3_S_MAX; } if (NULL != ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } else { *rp = (short)val; } } else { if (NULL != ec) { *ec = DK3_ERROR_INVALID_ARGS; } } return back; #else return (dk3ma_s_from_c8_string(rp, src, ec)); #endif } int dk3ma_ui_from_string(unsigned *rp, dkChar const *src, int *ec) { #if DK3_CHAR_SIZE > 1 dk3_um_t val = DK3_UM_0; int back = 0; if ((NULL != rp) && (NULL != src)) { if (0 != dk3ma_um_from_string(&val, src, ec)) { if ((dk3_um_t)DK3_U_MAX >= val) { *rp = (unsigned)val; back = 1; } else { *rp = DK3_U_MAX; if (NULL != ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } else { *rp = (unsigned)val; } } else { if (NULL != ec) { *ec = DK3_ERROR_INVALID_ARGS; } } return back; #else return (dk3ma_ui_from_c8_string(rp, src, ec)); #endif } int dk3ma_i_from_string(int *rp, dkChar const *src, int *ec) { #if DK3_CHAR_SIZE > 1 dk3_im_t val = DK3_IM_0; int back = 0; if ((NULL != rp) && (NULL != src)) { if (0 != dk3ma_im_from_string(&val, src, ec)) { if (((dk3_im_t)DK3_I_MIN <= val) && ((dk3_im_t)DK3_I_MAX >= val)) { *rp = (int)val; back = 1; } else { if (DK3_IM_0 > val) { *rp = DK3_I_MIN; } else { *rp = DK3_I_MAX; } if (NULL != ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } else { *rp = (int)val; } } else { if (NULL != ec) { *ec = DK3_ERROR_INVALID_ARGS; } } return back; #else return (dk3ma_i_from_c8_string(rp, src, ec)); #endif } int dk3ma_ul_from_string(unsigned long *rp, dkChar const *src, int *ec) { #if DK3_CHAR_SIZE > 1 dk3_um_t val = DK3_UM_0; int back = 0; if ((NULL != rp) && (NULL != src)) { if (0 != dk3ma_um_from_string(&val, src, ec)) { if ((dk3_um_t)DK3_UL_MAX >= val) { *rp = (unsigned long)val; back = 1; } else { *rp = DK3_UL_MAX; if (NULL != ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } else { *rp = (unsigned long)val; } } else { if (NULL != ec) { *ec = DK3_ERROR_INVALID_ARGS; } } return back; #else return (dk3ma_ul_from_c8_string(rp, src, ec)); #endif } int dk3ma_l_from_string(long *rp, dkChar const *src, int *ec) { #if DK3_CHAR_SIZE > 1 dk3_im_t val = DK3_IM_0; int back = 0; if ((NULL != rp) && (NULL != src)) { if (0 != dk3ma_im_from_string(&val, src, ec)) { if (((dk3_im_t)DK3_L_MIN <= val) && ((dk3_im_t)DK3_L_MAX >= val)) { *rp = (long)val; back = 1; } else { if (DK3_IM_0 > val) { *rp = DK3_L_MIN; } else { *rp = DK3_L_MAX; } if (NULL != ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } else { *rp = (long)val; } } else { if (NULL != ec) { *ec = DK3_ERROR_INVALID_ARGS; } } return back; #else return (dk3ma_l_from_c8_string(rp, src, ec)); #endif } #if DK3_HAVE_LONG_LONG int dk3ma_ull_from_string(unsigned long long *rp, dkChar const *src, int *ec) { #if DK3_CHAR_SIZE > 1 dk3_um_t val = DK3_UM_0; int back = 0; if ((NULL != rp) && (NULL != src)) { if (0 != dk3ma_um_from_string(&val, src, ec)) { if ((dk3_um_t)DK3_ULL_MAX >= val) { *rp = (unsigned long long)val; back = 1; } else { *rp = DK3_ULL_MAX; if (NULL != ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } else { *rp = (unsigned long long)val; } } else { if (NULL != ec) { *ec = DK3_ERROR_INVALID_ARGS; } } return back; #else return (dk3ma_ull_from_c8_string(rp, src, ec)); #endif } int dk3ma_ll_from_string(long long *rp, dkChar const *src, int *ec) { #if DK3_CHAR_SIZE > 1 dk3_im_t val = DK3_IM_0; int back = 0; if ((NULL != rp) && (NULL != src)) { if (0 != dk3ma_im_from_string(&val, src, ec)) { if (((dk3_im_t)DK3_LL_MIN <= val) && ((dk3_im_t)DK3_LL_MAX >= val)) { *rp = (long long)val; back = 1; } else { if (DK3_IM_0 > val) { *rp = DK3_LL_MIN; } else { *rp = DK3_LL_MAX; } if (NULL != ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } else { *rp = (long long)val; } } else { if (NULL != ec) { *ec = DK3_ERROR_INVALID_ARGS; } } return back; #else return (dk3ma_ll_from_c8_string(rp, src, ec)); #endif } #endif #if DK3_HAVE_INTMAX_T int dk3ma_uintmax_t_from_string(uintmax_t *rp, dkChar const *src, int *ec) { #if DK3_CHAR_SIZE > 1 dk3_um_t val = DK3_UM_0; int back = 0; if ((NULL != rp) && (NULL != src)) { if (0 != dk3ma_um_from_string(&val, src, ec)) { *rp = (uintmax_t)val; back = 1; } else { *rp = (uintmax_t)val; } } else { if (NULL != ec) { *ec = DK3_ERROR_INVALID_ARGS; } } return back; #else return (dk3ma_uintmax_t_from_c8_string(rp, src, ec)); #endif } int dk3ma_intmax_t_from_string(intmax_t *rp, dkChar const *src, int *ec) { #if DK3_CHAR_SIZE > 1 dk3_im_t val = DK3_IM_0; int back = 0; if ((NULL != rp) && (NULL != src)) { if (0 != dk3ma_im_from_string(&val, src, ec)) { *rp = (intmax_t)val; back = 1; } else { *rp = (intmax_t)val; } } else { if (NULL != ec) { *ec = DK3_ERROR_INVALID_ARGS; } } return back; #else return (dk3ma_intmax_t_from_c8_string(rp, src, ec)); #endif } #endif