+/*
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef CDECL99_INTCONV_H_
+#define CDECL99_INTCONV_H_
+
+#include <string.h>
+#include <stdbool.h>
+#include <inttypes.h>
+
+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