/* * Copyright © 2023-2024 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 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 cdecl_uintmax, then 0 is returned. Otherwise, * a non-zero result is returned. */ static inline bool intconv_shift(cdecl_uintmax *v, unsigned base, unsigned digit) { cdecl_uintmax old_v = *v; if (old_v > (cdecl_uintmax)-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