]> git.draconx.ca Git - cdecl99.git/blob - src/intconv.h
Release 1.3.
[cdecl99.git] / src / intconv.h
1 /*
2  * Copyright © 2023-2024 Nick Bowler
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16  */
17
18 #ifndef CDECL99_INTCONV_H_
19 #define CDECL99_INTCONV_H_
20
21 #include <string.h>
22 #include <stdbool.h>
23
24 enum { INTCONV_OCTAL = 8, INTCONV_DECIMAL = 10, INTCONV_HEXADECIMAL = 16 };
25
26 /*
27  * Multiply *v by base, which must be one of the above enumeration constants,
28  * and add digit, updating *v with the result.
29  *
30  * If the result does not fit in cdecl_uintmax, then 0 is returned.  Otherwise,
31  * a non-zero result is returned.
32  */
33 static inline bool intconv_shift(cdecl_uintmax *v, unsigned base, unsigned digit)
34 {
35         cdecl_uintmax old_v = *v;
36
37         if (old_v > (cdecl_uintmax)-1 / base)
38                 return false;
39         old_v *= base;
40
41         return (*v = old_v + digit) >= old_v;
42 }
43
44 /*
45  * Assuming d is a hexadecimal digit character (converted to unsigned char),
46  * return the corresponding value of that digit (between 0 and 15, inclusive).
47  */
48 static inline unsigned char intconv_digit(unsigned char d)
49 {
50         if (d >= '0' && d <= '9') {
51                 return d - '0';
52         } else {
53 #if ('A' & 7) == 1 && ('B' & 7) == 2 && ('C' & 7) == 3 \
54  && ('a' & 7) == 1 && ('b' & 7) == 2 && ('c' & 7) == 3 \
55  && ('D' & 7) == 4 && ('E' & 7) == 5 && ('F' & 7) == 6 \
56  && ('d' & 7) == 4 && ('e' & 7) == 5 && ('f' & 7) == 6
57                 /* EBCDIC or ASCII-like encoding */
58                 return 9 + (d & 7);
59 #else
60                 /* Something else */
61                 static const char idx[] = "abcdef..ABCDEF";
62                 return 10 + (((char *)memchr(idx, d, sizeof idx) - idx) & 7);
63 #endif
64         }
65 }
66
67 #endif