/* 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;
}
syntax highlighted by Code2HTML, v. 0.9.1