/* cvt.c - converting integers to and from strings * **************************************************************** * Copyright (C) 1998, 2000 Thomas Lord * * See the file "COPYING" for further information about * the copyright and warranty status of this work. */ #include "hackerlab/os/errno.h" #include "hackerlab/char/char-class.h" #include "hackerlab/char/str.h" #include "hackerlab/fmt/cvt.h" /************************************************************************ *(h1 "Converting Integers to and from Strings" * :include ("hackerlab/fmt/cvt.h")) * * The functions in this chapter convert between integer types and * strings. */ /*(menu) */ /************************************************************************ *(h2 "Converting Integers to Strings") * */ /*(c cvt_ulong_to_decimal) * size_t cvt_ulong_to_decimal (t_uchar * nbuf, unsigned long n); * * Convert `n' to a 0-terminated decimal number. * * Return the number of digits in the output. */ size_t cvt_ulong_to_decimal (t_uchar * nbuf, unsigned long n) { size_t x; size_t y; size_t used; if (!n) { nbuf[0] = '0'; nbuf[1] = 0; return 1; } x = 0; while (n) { nbuf[x] = '0' + n % 10; n /= 10; x += 1; } nbuf[x] = 0; y = 0; used = x--; while (x > y) { int c; c = nbuf[x]; nbuf[x] = nbuf[y]; nbuf[y] = c; --x; ++y; } return used; } /*(c cvt_ulong_to_decimal_n) * int cvt_ulong_to_decimal_n (t_uchar * nbuf, * size_t buflen, * unsigned long n, * size_t * needed); * * Convert `n' to a 0-terminated decimal number written to `nbuf' with * has the size of `buflen'. Stores the size which would be needed by * the conversion in `*needed' if it is not null (even on failure). * * Return 0 on success and -1 if the buffer is too small. */ int cvt_ulong_to_decimal_n (t_uchar * nbuf, size_t buflen, unsigned long n, size_t * needed) { size_t used; t_uchar tmp[sizeof (unsigned long)*2 + (sizeof (unsigned long) + 1)/2 + 1]; used = cvt_ulong_to_decimal (tmp, n); if (needed) *needed = used; if (used >= buflen) return -1; (void) str_cpy (nbuf, tmp); return 0; } /*(c cvt_long_to_decimal) * void cvt_long_to_decimal (t_uchar * nbuf, long n); * * Convert `n' to a 0-terminated decimal number. * * Return the number of digits in the output. */ size_t cvt_long_to_decimal (t_uchar * nbuf, long n) { if (n < 0) { nbuf[0] = '-'; return 1 + cvt_ulong_to_decimal (nbuf + 1, -n); } else return cvt_ulong_to_decimal (nbuf, n); } /*(c cvt_long_to_decimal_n) * int cvt_long_to_decimal_n (t_uchar * nbuf, * size_t buflen, * unsigned long n, * size_t * needed); * * Convert `n' to a 0-terminated decimal number written to `nbuf' with * has the size of `buflen'. Stores the size which would be needed by * the conversion in `*needed' if it is not null (even on failure). * * Return 0 on success and -1 if the buffer is too small. */ int cvt_long_to_decimal_n (t_uchar * nbuf, size_t buflen, long n, size_t * needed) { size_t used; t_uchar tmp[sizeof (unsigned long)*2 + (sizeof (unsigned long) + 1)/2 + 2]; if (n < 0) { tmp[0] = '-'; used = 1 + cvt_ulong_to_decimal (tmp + 1, -n); } else used = cvt_ulong_to_decimal (tmp, n); if (needed) *needed = used; if (used >= buflen) return -1; (void) str_cpy (nbuf, tmp); return 0; } /*(c cvt_ulong_to_octal) * size_t cvt_ulong_to_octal (t_uchar * nbuf, unsigned long n); * * Convert `n' to a 0-terminated octal number. */ size_t cvt_ulong_to_octal (t_uchar * nbuf, unsigned long n) { size_t x; size_t y; size_t used; if (!n) { nbuf[0] = '0'; nbuf[1] = 0; return 1; } x = 0; while (n) { nbuf[x] = '0' + n % 8; n /= 8; x += 1; } nbuf[x] = 0; y = 0; used = x--; while (x > y) { int c; c = nbuf[x]; nbuf[x] = nbuf[y]; nbuf[y] = c; --x; ++y; } return used; } /*(c cvt_ulong_to_octal_n) * int cvt_ulong_to_octal_n (t_uchar * nbuf, * size_t buflen, * unsigned long n, * size_t * needed); * * Convert `n' to a 0-terminated octal number written to `nbuf' with * has the size of `buflen'. Stores the size which would be needed by * the conversion in `*needed' if it is not null (even on failure). * * Return 0 on success and -1 if the buffer is too small */ int cvt_ulong_to_octal_n (t_uchar * nbuf, size_t buflen, unsigned long n, size_t * needed) { size_t used; t_uchar tmp[(sizeof (unsigned long)*8 + 2)/3 + 1]; used = cvt_ulong_to_octal (tmp, n); if (needed) *needed = used; if (used >= buflen) return -1; (void) str_cpy (nbuf, tmp); return 0; } /*(c cvt_long_to_octal) * void cvt_long_to_octal (t_uchar * nbuf, long n); * * Convert `n' to a 0-terminated octal number. * * Return the number of digits in the output. */ size_t cvt_long_to_octal (t_uchar * nbuf, long n) { if (n < 0) { nbuf[0] = '-'; return 1 + cvt_ulong_to_octal (nbuf + 1, -n); } else return cvt_ulong_to_octal (nbuf, n); } /*(c cvt_long_to_octal_n) * int cvt_long_to_octal_n (t_uchar * nbuf, * size_t buflen, * unsigned long n, * size_t * needed); * * Convert `n' to a 0-terminated octal number written to `nbuf' with * has the size of `buflen'. Stores the size which would be needed by * the conversion in `*needed' if it is not null (even on failure). * * Return 0 on success and -1 if the buffer is too small. */ int cvt_long_to_octal_n (t_uchar * nbuf, size_t buflen, long n, size_t * needed) { size_t used; t_uchar tmp[(sizeof (unsigned long)*8 + 2)/3 + 2]; if (n < 0) { tmp[0] = '-'; used = 1 + cvt_ulong_to_octal (tmp + 1, -n); } else used = cvt_ulong_to_octal (tmp, n); if (needed) *needed = used; if (used >= buflen) return -1; (void) str_cpy (nbuf, tmp); return 0; } /*(c cvt_ulong_to_HEX) * size_t cvt_ulong_to_HEX (t_uchar * nbuf, unsigned long n); * * Convert `n' to a 0-terminated hexadecimal number using upper-case * hex digits "A..F". * * Return the number of digits in the output. */ size_t cvt_ulong_to_HEX (t_uchar * nbuf, unsigned long n) { static const t_uchar * HEX = "0123456789ABCDEF"; size_t x; size_t y; size_t needed; if (!n) { nbuf[0] = '0'; nbuf[1] = 0; return 1; } x = 0; while (n) { nbuf[x] = HEX[n % 16]; n /= 16; x += 1; } nbuf[x] = 0; y = 0; needed = x--; while (x > y) { int c; c = nbuf[x]; nbuf[x] = nbuf[y]; nbuf[y] = c; --x; ++y; } return needed; } /*(c cvt_ulong_to_HEX_n) * int cvt_ulong_to_HEX_n (t_uchar * nbuf, * size_t buflen, * unsigned long n, * size_t * needed); * * Convert `n' to a 0-terminated octal number hexadecimal number using * upper-case written to `nbuf' with has the size of `buflen'. hex * digits "A..F". Stores the size which would be needed by the * conversion in `*needed' if it is not null (even on failure). * * Return 0 on success and -1 if the buffer is too small. */ int cvt_ulong_to_HEX_n (t_uchar * nbuf, size_t buflen, unsigned long n, size_t * needed) { size_t used; t_uchar tmp[sizeof (unsigned long)*2 + 1]; used = cvt_ulong_to_HEX (tmp, n); if (needed) *needed = used; if (used >= buflen) return -1; (void) str_cpy (nbuf, tmp); return 0; } /*(c cvt_long_to_HEX) * size_t cvt_long_to_HEX (t_uchar * nbuf, long n); * * Convert `n' to a 0-terminated hexadecimal number using upper-case * hex digits "A..F". * * Return the number of digits in the output. */ size_t cvt_long_to_HEX (t_uchar * nbuf, long n) { if (n < 0) { nbuf[0] = '-'; return 1 + cvt_ulong_to_HEX (nbuf + 1, -n); } else return cvt_ulong_to_HEX (nbuf, n); } /*(c cvt_long_to_HEX_n) * int cvt_long_to_HEX_n (t_uchar * nbuf, * size_t buflen, * unsigned long n, * size_t * needed); * * Convert `n' to a 0-terminated octal number hexadecimal number using * upper-case written to `nbuf' with has the size of `buflen'. hex * digits "A..F". Stores the size which would be needed by the * conversion in `*needed' if it is not null (even on failure). * * Return 0 on success and -1 if the buffer is too small. */ int cvt_long_to_HEX_n (t_uchar * nbuf, size_t buflen, long n, size_t * needed) { size_t used; t_uchar tmp[sizeof (unsigned long)*2 + 2]; if (n < 0) { tmp[0] = '-'; used = 1 + cvt_ulong_to_HEX (tmp + 1, -n); } else used = cvt_ulong_to_HEX (tmp, n); if (needed) *needed = used; if (used >= buflen) return -1; (void) str_cpy (nbuf, tmp); return 0; } /*(c cvt_ulong_to_hex) * void cvt_ulong_to_hex (t_uchar * nbuf, unsigned long n); * * Convert `n' to a 0-terminated hexadecimal number using lower-case * hex digits "a..f". * * Return the number of digits in the output. */ size_t cvt_ulong_to_hex (t_uchar * nbuf, unsigned long n) { static const t_uchar * hex = "0123456789abcdef"; size_t x; size_t y; size_t needed; if (!n) { nbuf[0] = '0'; nbuf[1] = 0; return 1; } x = 0; while (n) { nbuf[x] = hex[n % 16]; n /= 16; x += 1; } nbuf[x] = 0; y = 0; needed = x--; while (x > y) { int c; c = nbuf[x]; nbuf[x] = nbuf[y]; nbuf[y] = c; --x; ++y; } return needed; } /*(c cvt_ulong_to_hex_n) * int cvt_ulong_to_hex_n (t_uchar * nbuf, * size_t buflen, * unsigned long n, * size_t * needed); * * Convert `n' to a 0-terminated octal number hexadecimal number using * lower-case written to `nbuf' with has the size of `buflen'. hex * digits "a..f". Stores the size which would be needed by the * conversion in `*needed' if it is not null (even on failure). * * Return 0 on success and -1 if the buffer is too small. */ int cvt_ulong_to_hex_n (t_uchar * nbuf, size_t buflen, unsigned long n, size_t * needed) { size_t used; t_uchar tmp[sizeof (unsigned long)*2 + 1]; used = cvt_ulong_to_hex (tmp, n); if (needed) *needed = used; if (used >= buflen) return -1; (void) str_cpy (nbuf, tmp); return 0; } /*(c cvt_long_to_hex) * size_t cvt_long_to_hex (t_uchar * nbuf, long n); * * Convert `n' to a 0-terminated hexadecimal number using upper-case * hex digits "A..F". * * Return the number of digits in the output. */ size_t cvt_long_to_hex (t_uchar * nbuf, long n) { if (n < 0) { nbuf[0] = '-'; return 1 + cvt_ulong_to_hex (nbuf + 1, -n); } else return cvt_ulong_to_hex (nbuf, n); } /*(c cvt_long_to_hex_n) * int cvt_long_to_hex_n (t_uchar * nbuf, * size_t buflen, * unsigned long n, * size_t * needed); * * Convert `n' to a 0-terminated octal number hexadecimal number using * lower-case written to `nbuf' with has the size of `buflen'. hex * digits "a..f". Stores the size which would be needed by the * conversion in `*needed' if it is not null (even on failure). * * Return 0 on success and -1 if the buffer is too small. */ int cvt_long_to_hex_n (t_uchar * nbuf, size_t buflen, long n, size_t * needed) { size_t used; t_uchar tmp[sizeof (unsigned long)*2 + 2]; if (n < 0) { tmp[0] = '-'; used = 1 + cvt_ulong_to_hex (tmp + 1, -n); } else used = cvt_ulong_to_hex (tmp, n); if (needed) *needed = used; if (used >= buflen) return -1; (void) str_cpy (nbuf, tmp); return 0; } /************************************************************************ *(h2 "Converting Decimal Strings to Integers") * */ /*(c cvt_decimal_to_ulong) * int cvt_decimal_to_ulong (int * errn, * unsigned long * answerp, * const t_uchar * text, * size_t len); * * Convert the decimal number `text' to an unsigned long integer. * * Return 0 upon success, -1 on error. * * On error, `*errn' may be: * * ERANGE the decimal number will not fit in an `unsigned long'. * EINVAL `text' is not a valid number. */ int cvt_decimal_to_ulong (int * errn, unsigned long * answerp, const t_uchar * text, size_t len) { size_t consumed; unsigned long answer; if (cvt_scan_decimal_to_ulong (errn, &answer, &consumed, text, len) == -1) return -1; if (consumed != len) { if (errn) *errn = EINVAL; return -1; } *answerp = answer; return 0; } /*(c cvt_scan_decimal_to_ulong) * int cvt_scan_decimal_to_ulong (int * errn, * unsigned long * answerp, * size_t * consumed, * const t_uchar * text, * size_t len); * * Convert a decimal begining at `text' to an unsigned long integer. * Pass the actual characters parsed back in `*consumed' if `consumed' is not null. * * Return 0 upon success, -1 on error. * * On error, `*errn' may be: * * ERANGE the decimal number will not fit in an `unsigned long'. * EINVAL `text' can not be parsed as a valid number. */ int cvt_scan_decimal_to_ulong (int * errn, unsigned long * answerp, size_t * consumed, const t_uchar * text, size_t len) { unsigned long answer; size_t initial_len; initial_len = len; answer = 0; if (len == 0) goto einval; if (len && (*text == '+')) { ++text; --len; } if (!char_is_digit (*text)) { einval: if (errn) *errn = EINVAL; return -1; } while (len && char_is_digit (*text)) { int digit; unsigned long next; digit = *text - '0'; next = answer * 10 + digit; if (answer && (next <= answer)) { if (errn) *errn = ERANGE; return -1; } answer = next; ++text; --len; } *answerp = answer; if (consumed) *consumed = initial_len - len; return 0; } /*(c cvt_decimal_to_uint) * int cvt_decimal_to_uint (int * errn, * unsigned int * answerp, * const t_uchar * text, * size_t len); * * Convert the decimal number `text' to an unsigned integer. * * Return 0 upon success, -1 on error. * * On error, `*errn' may be: * * ERANGE the decimal number will not fit in an `unsigned int'. * EINVAL `text' is not a valid number. */ int cvt_decimal_to_uint (int * errn, unsigned int * answerp, const t_uchar * text, size_t len) { size_t consumed; unsigned int answer; if( cvt_scan_decimal_to_uint (errn, &answer, &consumed, text, len) == -1) return -1; if (consumed != len) { if (errn) *errn = EINVAL; return -1; } *answerp = answer; return 0; } /*(c cvt_scan_decimal_to_uint) * int cvt_scan_decimal_to_uint (int * errn, * unsigned int * answerp, * size_t * consumed, * const t_uchar * text, * size_t len); * * Convert a decimal begining at `text' to an unsigned integer. * Pass the actual characters parsed back in `*consumed' if `consumed' is not null. * * Return 0 upon success, -1 on error. * * On error, `*errn' may be: * * ERANGE the decimal number will not fit in an `unsigned long'. * EINVAL `text' can not be parsed as a valid number. */ int cvt_scan_decimal_to_uint (int * errn, unsigned int * answerp, size_t * consumed, const t_uchar * text, size_t len) { unsigned int answer; size_t initial_len; initial_len = len; answer = 0; if (len == 0) goto einval; if (len && (*text == '+')) { ++text; --len; } if (!char_is_digit (*text)) { einval: if (errn) *errn = EINVAL; return -1; } while (len && char_is_digit (*text)) { int digit; unsigned int next; digit = *text - '0'; next = answer * 10 + digit; if (answer && (next <= answer)) { if (errn) *errn = ERANGE; return -1; } answer = next; ++text; --len; } *answerp = answer; if (consumed) *consumed = initial_len - len; return 0; } /*(c cvt_decimal_to_long) * int cvt_decimal_to_long (int * errn, * long * answerp, * const t_uchar * text, * size_t len); * * Convert the decimal number `text' to a long integer. * * Return 0 upon success, -1 on error. * * On error, `*errn' may be: * * ERANGE the decimal number will not fit in a `long'. * EINVAL `text' is not a valid number. */ int cvt_decimal_to_long (int * errn, long * answerp, const t_uchar * text, size_t len) { long answer; size_t consumed; if( cvt_scan_decimal_to_long (errn, &answer, &consumed, text, len) == -1) return -1; if (consumed != len) { if (errn) *errn = EINVAL; return -1; } *answerp = answer; return 0; } /*(c cvt_scan_decimal_to_long) * int cvt_scan_decimal_to_long (int * errn, * long * answerp, * size_t * consumed, * const t_uchar * text, * size_t len); * * Convert a decimal begining at `text' to a long integer. * Pass the actual characters parsed back in `*consumed' if `consumed' is not null. * * Return 0 upon success, -1 on error. * * On error, `*errn' may be: * * ERANGE the decimal number will not fit in an `unsigned long'. * EINVAL `text' can not be parsed as a valid number. */ int cvt_scan_decimal_to_long (int * errn, long * answerp, size_t * consumed, const t_uchar * text, size_t len) { long answer; int sign; size_t initial_len; initial_len = len; answer = 0; if (len == 0) goto einval; if (len && (*text == '-')) { sign = -1; ++text; --len; } else { sign = 1; if (len && (*text == '+')) { ++text; --len; } } if (!char_is_digit (*text)) { einval: if (errn) *errn = EINVAL; return -1; } while (len && char_is_digit (*text)) { int digit; long next; digit = *text - '0'; next = answer * 10 + sign * digit; if (answer && ((sign > 0) ? (next <= answer) : (answer <= next))) { if (errn) *errn = ERANGE; return -1; } answer = next; ++text; --len; } *answerp = answer; if (consumed) *consumed = initial_len - len; return 0; } /*(c cvt_decimal_to_int) * int cvt_decimal_to_int (int * errn, * int * answerp, * const t_uchar * text, * size_t len); * * Convert the decimal number `text' to an integer. * * Return 0 upon success, -1 on error. * * On error, `*errn' may be: * * ERANGE the decimal number will not fit in an `int'. * EINVAL `text' is not a valid number. */ int cvt_decimal_to_int (int * errn, int * answerp, const t_uchar * text, size_t len) { size_t consumed; int answer; if( cvt_scan_decimal_to_int (errn, &answer, &consumed, text, len) == -1) return -1; if (consumed != len) { if (errn) *errn = EINVAL; return -1; } *answerp = answer; return 0; } /*(c cvt_scan_decimal_to_int) * int cvt_scan_decimal_to_int (int * errn, * int * answerp, * size_t * consumed, * const t_uchar * text, * size_t len); * * Convert a decimal begining at `text' to an integer. * Pass the actual characters parsed back in `*consumed' if `consumed' is not null. * * Return 0 upon success, -1 on error. * * On error, `*errn' may be: * * ERANGE the decimal number will not fit in an `unsigned long'. * EINVAL `text' can not be parsed as a valid number. */ int cvt_scan_decimal_to_int (int * errn, int * answerp, size_t * consumed, const t_uchar * text, size_t len) { int answer; int sign; size_t initial_len; initial_len = len; answer = 0; if (len == 0) goto einval; if (len && (*text == '-')) { sign = -1; ++text; --len; } else { sign = 1; if (len && (*text == '+')) { ++text; --len; } } if (!char_is_digit (*text)) { einval: if (errn) if (errn) *errn = EINVAL; return -1; } while (len && char_is_digit (*text)) { int digit; int next; digit = *text - '0'; next = answer * 10 + sign * digit; if (answer && ((sign > 0) ? (next <= answer) : (answer <= next))) { if (errn) *errn = ERANGE; return -1; } answer = next; ++text; --len; } *answerp = answer; if (consumed) *consumed = initial_len - len; return 0; } /************************************************************************ *(h2 "Converting Hexadecimal Strings to Integers") * */ /*(c cvt_hex_to_ulong) * int cvt_hex_to_ulong (int * errn, * unsigned long * answerp, * const t_uchar * text, * size_t len); * * Convert the hexadecimal number `text' to an unsigned long integer. * * Return 0 upon success, -1 on error. * * On error, `*errn' may be: * * ERANGE the hexadecimal number will not fit in an `unsigned long'. * EINVAL `text' is not a valid hexadecimal number. */ int cvt_hex_to_ulong (int * errn, unsigned long * answerp, const t_uchar * text, size_t len) { size_t consumed; unsigned long answer; if( cvt_scan_hex_to_ulong (errn, &answer, &consumed, text, len) == -1) return -1; if (consumed != len) { if (errn) *errn = EINVAL; return -1; } *answerp = answer; return 0; } /*(c cvt_scan_hex_to_ulong) * int cvt_scan_hex_to_ulong (int * errn, * unsigned long * answerp, * size_t * consumed, * const t_uchar * text, * size_t len); * * Convert a hexadecimal begining at `text' to an unsigned long integer. * Pass the actual characters parsed back in `*consumed' if `consumed' is not null. * * Return 0 upon success, -1 on error. * * On error, `*errn' may be: * * ERANGE the decimal number will not fit in an `unsigned long'. * EINVAL `text' can not be parsed as a valid number. */ int cvt_scan_hex_to_ulong (int * errn, unsigned long * answerp, size_t * consumed, const t_uchar * text, size_t len) { unsigned long answer; size_t initial_len; initial_len = len; answer = 0; if (len == 0) goto einval; if (len && (*text == '+')) { ++text; --len; } if (!char_is_xdigit (*text)) { einval: if (errn) *errn = EINVAL; return -1; } while (len && char_is_xdigit (*text)) { int digit; unsigned long next; digit = char_digit_value (*text); next = answer * 16 + digit; if (answer && (next <= answer)) { if (errn) *errn = ERANGE; return -1; } answer = next; ++text; --len; } *answerp = answer; if (consumed) *consumed = initial_len - len; return 0; } /*(c cvt_hex_to_uint) * int cvt_hex_to_uint (int * errn, * unsigned int * answerp, * const t_uchar * text, * size_t len); * * Convert the hexadecimal number `text' to an unsigned integer. * * Return 0 upon success, -1 on error. * * On error, `*errn' may be: * * ERANGE the hexadecimal number will not fit in an `unsigned int'. * EINVAL `text' is not a valid hexadecimal number. */ int cvt_hex_to_uint (int * errn, unsigned int * answerp, const t_uchar * text, size_t len) { size_t consumed; unsigned int answer; if( cvt_scan_hex_to_uint (errn, &answer, &consumed, text, len) == -1) return -1; if (consumed != len) { if (errn) *errn = EINVAL; return -1; } *answerp = answer; return 0; } /*(c cvt_scan_hex_to_uint) * int cvt_scan_hex_to_uint (int * errn, * unsigned int * answerp, * size_t * consumed, * const t_uchar * text, * size_t len); * * Convert a hexadecimal begining at `text' to an unsigned integer. * Pass the actual characters parsed back in `*consumed' if `consumed' is not null. * * Return 0 upon success, -1 on error. * * On error, `*errn' may be: * * ERANGE the decimal number will not fit in an `unsigned long'. * EINVAL `text' can not be parsed as a valid number. */ int cvt_scan_hex_to_uint (int * errn, unsigned int * answerp, size_t * consumed, const t_uchar * text, size_t len) { unsigned int answer; size_t initial_len; initial_len = len; answer = 0; if (len == 0) goto einval; if (len && (*text == '+')) { ++text; --len; } if (!char_is_xdigit (*text)) { einval: if (errn) *errn = EINVAL; return -1; } while (len && char_is_xdigit (*text)) { int digit; unsigned int next; digit = char_digit_value (*text); next = answer * 16 + digit; if (answer && (next <= answer)) { if (errn) *errn = ERANGE; return -1; } answer = next; ++text; --len; } *answerp = answer; if (consumed) *consumed = initial_len - len; return 0; } /*(c cvt_hex_to_long) * int cvt_hex_to_long (int * errn, * long * answerp, * const t_uchar * text, * size_t len); * * Convert the hexadecimal number `text' to a long integer. * * Return 0 upon success, -1 on error. * * On error, `*errn' may be: * * ERANGE the hexadecimal number will not fit in a `long'. * EINVAL `text' is not a valid hexadecimal number. */ int cvt_hex_to_long (int * errn, long * answerp, const t_uchar * text, size_t len) { long answer; size_t consumed; if( cvt_scan_hex_to_long (errn, &answer, &consumed, text, len) == -1) return -1; if (consumed != len) { if (errn) *errn = EINVAL; return -1; } *answerp = answer; return 0; } /*(c cvt_scan_hex_to_long) * int cvt_scan_hex_to_long (int * errn, * long * answerp, * size_t * consumed, * const t_uchar * text, * size_t len); * * Convert a hexadecimal begining at `text' to a long integer. * Pass the actual characters parsed back in `*consumed' if `consumed' is not null. * * Return 0 upon success, -1 on error. * * On error, `*errn' may be: * * ERANGE the decimal number will not fit in an `unsigned long'. * EINVAL `text' can not be parsed as a valid number. */ int cvt_scan_hex_to_long (int * errn, long * answerp, size_t * consumed, const t_uchar * text, size_t len) { long answer; int sign; size_t initial_len; initial_len = len; answer = 0; if (len == 0) goto einval; if (len && (*text == '-')) { sign = -1; ++text; --len; } else { sign = 1; if (len && (*text == '+')) { ++text; --len; } } if (!char_is_xdigit (*text)) { einval: if (errn) *errn = EINVAL; return -1; } while (len && char_is_xdigit (*text)) { int digit; long next; digit = char_digit_value (*text); next = answer * 16 + sign * digit; if (answer && ((sign > 0) ? (next <= answer) : (answer <= next))) { if (errn) *errn = ERANGE; return -1; } answer = next; ++text; --len; } *answerp = answer; if (consumed) *consumed = initial_len - len; return 0; } /*(c cvt_hex_to_int) * int cvt_hex_to_int (int * errn, * int * answerp, * const t_uchar * text, * size_t len); * * Convert the hexadecimal number `text' to an integer. * * Return 0 upon success, -1 on error. * * On error, `*errn' may be: * * ERANGE the hexadecimal number will not fit in an `int'. * EINVAL `text' is not a valid hexadecimal number. */ int cvt_hex_to_int (int * errn, int * answerp, const t_uchar * text, size_t len) { size_t consumed; int answer; if( cvt_scan_hex_to_int (errn, &answer, &consumed, text, len) == -1) return -1; if (consumed != len) { if (errn) *errn = EINVAL; return -1; } *answerp = answer; return 0; } /*(c cvt_scan_hex_to_int) * int cvt_scan_hex_to_int (int * errn, * int * answerp, * size_t * consumed, * const t_uchar * text, * size_t len); * * Convert a hexadecimal begining at `text' to an integer. * Pass the actual characters parsed back in `*consumed' if `consumed' is not null. * * Return 0 upon success, -1 on error. * * On error, `*errn' may be: * * ERANGE the decimal number will not fit in an `unsigned long'. * EINVAL `text' can not be parsed as a valid number. */ int cvt_scan_hex_to_int (int * errn, int * answerp, size_t * consumed, const t_uchar * text, size_t len) { int answer; int sign; size_t initial_len; initial_len = len; answer = 0; if (len == 0) goto einval; if (len && (*text == '-')) { sign = -1; ++text; --len; } else { sign = 1; if (len && (*text == '+')) { ++text; --len; } } if (!char_is_xdigit (*text)) { einval: if (errn) *errn = EINVAL; return -1; } while (len && char_is_xdigit (*text)) { int digit; int next; digit = char_digit_value (*text); next = answer * 16 + sign * digit; if (answer && ((sign > 0) ? (next <= answer) : (answer <= next))) { if (errn) *errn = ERANGE; return -1; } answer = next; ++text; --len; } *answerp = answer; if (consumed) *consumed = initial_len - len; return 0; } /************************************************************************ *(h2 "Converting Octal Strings to Integers") * */ /*(c cvt_octal_to_ulong) * int cvt_octal_to_ulong (int * errn, * unsigned long * answerp, * const t_uchar * text, * size_t len); * * Convert the octal number `text' to an unsigned long integer. * * Return 0 upon success, -1 on error. * * On error, `*errn' may be: * * ERANGE the octal number will not fit in an `unsigned long'. * EINVAL `text' is not a valid octal number. */ int cvt_octal_to_ulong (int * errn, unsigned long * answerp, const t_uchar * text, size_t len) { size_t consumed; unsigned long answer; if( cvt_scan_octal_to_ulong (errn, &answer, &consumed, text, len) == -1) return -1; if (consumed != len) { if (errn) *errn = EINVAL; return -1; } *answerp = answer; return 0; } /*(c cvt_scan_octal_to_ulong) * int cvt_scan_octal_to_ulong (int * errn, * unsigned long * answerp, * size_t * consumed, * const t_uchar * text, * size_t len); * * Convert a octal begining at `text' to an unsigned long integer. * Pass the actual characters parsed back in `*consumed' if `consumed' is not null. * * Return 0 upon success, -1 on error. * * On error, `*errn' may be: * * ERANGE the decimal number will not fit in an `unsigned long'. * EINVAL `text' can not be parsed as a valid number. */ int cvt_scan_octal_to_ulong (int * errn, unsigned long * answerp, size_t * consumed, const t_uchar * text, size_t len) { unsigned long answer; size_t initial_len; initial_len = len; answer = 0; if (len == 0) goto einval; if (len && (*text == '+')) { ++text; --len; } if (!char_is_odigit (*text)) { einval: if (errn) *errn = EINVAL; return -1; } while (len && char_is_odigit (*text)) { int digit; unsigned long next; digit = *text - '0'; next = answer * 8 + digit; if (answer && (next <= answer)) { if (errn) *errn = ERANGE; return -1; } answer = next; ++text; --len; } *answerp = answer; if (consumed) *consumed = initial_len - len; return 0; } /*(c cvt_octal_to_uint) * int cvt_octal_to_uint (int * errn, * unsigned int * answerp, * const t_uchar * text, * size_t len); * * Convert the octal number `text' to an unsigned integer. * * Return 0 upon success, -1 on error. * * On error, `*errn' may be: * * ERANGE the octal number will not fit in an `unsigned int'. * EINVAL `text' is not a valid octal number. */ int cvt_octal_to_uint (int * errn, unsigned int * answerp, const t_uchar * text, size_t len) { size_t consumed; unsigned int answer; if( cvt_scan_octal_to_uint (errn, &answer, &consumed, text, len) == -1) return -1; if (consumed != len) { if (errn) *errn = EINVAL; return -1; } *answerp = answer; return 0; } /*(c cvt_scan_octal_to_uint) * int cvt_scan_octal_to_uint (int * errn, * unsigned int * answerp, * size_t * consumed, * const t_uchar * text, * size_t len); * * Convert a octal begining at `text' to an unsigned integer. * Pass the actual characters parsed back in `*consumed' if `consumed' is not null. * * Return 0 upon success, -1 on error. * * On error, `*errn' may be: * * ERANGE the decimal number will not fit in an `unsigned long'. * EINVAL `text' can not be parsed as a valid number. */ int cvt_scan_octal_to_uint (int * errn, unsigned int * answerp, size_t * consumed, const t_uchar * text, size_t len) { unsigned int answer; size_t initial_len; initial_len = len; answer = 0; if (len == 0) goto einval; if (len && (*text == '+')) { ++text; --len; } if (!char_is_odigit (*text)) { einval: if (errn) *errn = EINVAL; return -1; } while (len && char_is_odigit (*text)) { int digit; unsigned int next; digit = *text - '0'; next = answer * 8 + digit; if (answer && (next <= answer)) { if (errn) *errn = ERANGE; return -1; } answer = next; ++text; --len; } *answerp = answer; if (consumed) *consumed = initial_len - len; return 0; } /*(c cvt_octal_to_long) * int cvt_octal_to_long (int * errn, * long * answerp, * const t_uchar * text, * size_t len); * * Convert the octal number `text' to a long integer. * * Return 0 upon success, -1 on error. * * On error, `*errn' may be: * * ERANGE the octal number will not fit in a `long'. * EINVAL `text' is not a valid octal number. */ int cvt_octal_to_long (int * errn, long * answerp, const t_uchar * text, size_t len) { long answer; size_t consumed; if( cvt_scan_octal_to_long (errn, &answer, &consumed, text, len) == -1) return -1; if (consumed != len) { if (errn) *errn = EINVAL; return -1; } *answerp = answer; return 0; } /*(c cvt_scan_octal_to_long) * int cvt_scan_octal_to_long (int * errn, * long * answerp, * size_t * consumed, * const t_uchar * text, * size_t len); * * Convert a octal begining at `text' to a long integer. * Pass the actual characters parsed back in `*consumed' if `consumed' is not null. * * Return 0 upon success, -1 on error. * * On error, `*errn' may be: * * ERANGE the decimal number will not fit in an `unsigned long'. * EINVAL `text' can not be parsed as a valid number. */ int cvt_scan_octal_to_long (int * errn, long * answerp, size_t * consumed, const t_uchar * text, size_t len) { long answer; int sign; size_t initial_len; initial_len = len; answer = 0; if (len == 0) goto einval; if (len && (*text == '-')) { sign = -1; ++text; --len; } else { sign = 1; if (len && (*text == '+')) { ++text; --len; } } if (!char_is_odigit (*text)) { einval: if (errn) *errn = EINVAL; return -1; } while (len && char_is_odigit (*text)) { int digit; long next; digit = *text - '0'; next = answer * 8 + sign * digit; if (answer && ((sign > 0) ? (next <= answer) : (answer <= next))) { if (errn) *errn = ERANGE; return -1; } answer = next; ++text; --len; } *answerp = answer; if (consumed) *consumed = initial_len - len; return 0; } /*(c cvt_octal_to_int) * int cvt_octal_to_int (int * errn, * int * answerp, * const t_uchar * text, * size_t len); * * Convert the octal number `text' to an integer. * * Return 0 upon success, -1 on error. * * On error, `*errn' may be: * * ERANGE the octal number will not fit in an `int'. * EINVAL `text' is not a valid octal number. */ int cvt_octal_to_int (int * errn, int * answerp, const t_uchar * text, size_t len) { size_t consumed; int answer; if( cvt_scan_octal_to_int (errn, &answer, &consumed, text, len) == -1) return -1; if (consumed != len) { if (errn) *errn = EINVAL; return -1; } *answerp = answer; return 0; } /*(c cvt_scan_octal_to_int) * int cvt_scan_octal_to_int (int * errn, * int * answerp, * size_t * consumed, * const t_uchar * text, * size_t len); * * Convert a octal begining at `text' to an integer. * Pass the actual characters parsed back in `*consumed' if `consumed' is not null. * * Return 0 upon success, -1 on error. * * On error, `*errn' may be: * * ERANGE the decimal number will not fit in an `unsigned long'. * EINVAL `text' can not be parsed as a valid number. */ int cvt_scan_octal_to_int (int * errn, int * answerp, size_t * consumed, const t_uchar * text, size_t len) { int answer; int sign; size_t initial_len; initial_len = len; answer = 0; if (len == 0) goto einval; if (len && (*text == '-')) { sign = -1; ++text; --len; } else { sign = 1; if (len && (*text == '+')) { ++text; --len; } } if (!char_is_odigit (*text)) { einval: if (errn) *errn = EINVAL; return -1; } while (len && char_is_odigit (*text)) { int digit; int next; digit = *text - '0'; next = answer * 8 + sign * digit; if (answer && ((sign > 0) ? (next <= answer) : (answer <= next))) { if (errn) *errn = ERANGE; return -1; } answer = next; ++text; --len; } *answerp = answer; if (consumed) *consumed = initial_len - len; return 0; }