/*
* Copyright © 2023 Nick Bowler
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef CDECL99_INTCONV_H_
#define CDECL99_INTCONV_H_
#include
#include
#include
enum { INTCONV_OCTAL = 8, INTCONV_DECIMAL = 10, INTCONV_HEXADECIMAL = 16 };
/*
* Multiply *v by base, which must be one of the above enumeration constants,
* and add digit, updating *v with the result.
*
* If the result does not fit in uintmax_t, then 0 is returned. Otherwise,
* a non-zero result is returned.
*/
static inline bool intconv_shift(uintmax_t *v, unsigned base, unsigned digit)
{
uintmax_t old_v = *v;
if (old_v > (uintmax_t)-1 / base)
return false;
old_v *= base;
return (*v = old_v + digit) >= old_v;
}
/*
* Assuming d is a hexadecimal digit character (converted to unsigned char),
* return the corresponding value of that digit (between 0 and 15, inclusive).
*/
static inline unsigned char intconv_digit(unsigned char d)
{
if (d >= '0' && d <= '9') {
return d - '0';
} else {
#if ('A' & 7) == 1 && ('B' & 7) == 2 && ('C' & 7) == 3 \
&& ('a' & 7) == 1 && ('b' & 7) == 2 && ('c' & 7) == 3 \
&& ('D' & 7) == 4 && ('E' & 7) == 5 && ('F' & 7) == 6 \
&& ('d' & 7) == 4 && ('e' & 7) == 5 && ('f' & 7) == 6
/* EBCDIC or ASCII-like encoding */
return 9 + (d & 7);
#else
/* Something else */
static const char idx[] = "abcdef..ABCDEF";
return 10 + (((char *)memchr(idx, d, sizeof idx) - idx) & 7);
#endif
}
}
#endif