@@ -37,27 +37,18 @@ #include #include #include #define sz(x) ( sizeof (x) / sizeof (x) [0] ) + enum /* constants */ { null = 0, - - /* ascii address space */ - numspace = (0x39 - 0x30) + 1, /* 10 */ - alphaspace = (0x5a - 0x41) + 1, /* 26 */ - smallalphaspace = (0x7a - 0x61) + 1, /* 26 */ - - /* base representations */ - imaxbase = numspace + alphaspace, /* 36 */ - maxbase = imaxbase + smallalphaspace /* 62 */ }; typedef unsigned long long word; typedef _Bool bool; enum { false = 0, true = 1 }; -typedef struct pair { uint8_t val; const char* str; } pair; #define error_list \ e(domain, "bad argument passed for domain") \ e(find, "could not find key in table") \ @@ -72,17 +63,14 @@ error_list # undef e } bad; -bad tblget(size_t stacksz, const pair* haystack, const char* needle, uint8_t* val) { - for (size_t i = 0; i base) return bad_domain; - - val *= base; - val += v; - } - - *ret = val; - return ok; -} - -bad atoi(word base, const char* s, word* ret) { - /* s must be a null-terminated ASCII numeral string */ - if (base > maxbase) return bad_base; - - /* override the default base if it's a basèd literal */ - if (s[0] == '@' || base == 0) return asctoi(s + (s[0]=='@'),ret); - else if (s[0] == '0' && s[1] == 'x') base = 16, s += 2; - else if (s[0] == '0' && s[1] == 'd') base = 10, s += 2; - else if (s[0] == '0' && s[1] == 'b') base = 2, s += 2; - else if (s[0] == '0' && s[1] == 't') base = 3, s += 2; - else if (s[0] == '0') base = 8, s += 1; - - bool insens = (base <= imaxbase); - word val = 0; - - for (;*s!=null;++s) { - uint8_t v = *s; - if(v >= 0x30 && v <= 0x39) v -= 0x30; else { - if(v >= 0x61 && v <= 0x7a) { - if (insens) v -= 0x20; else { - v = numspace + alphaspace + (v - 0x61); - goto checkval; - } - } - if(v >= 0x41 && v <= 0x5a) v = numspace + (v - 0x41); - else return bad_domain; - } - checkval: if (v >= base) return bad_domain; - - val *= base; - val += v; - } - - *ret = val; - return ok; -} - -/* needed for efficiency's sake, but really sucky - - * this table needs to be kept in sync with the - * itoa algorithm by hand. unfortunately, given C's - * abject lack of metaprogramming, we have to do this - * by hand. */ -const char baseref[] = /* numerals[10] */ "0123456789" - /* bigalpha[26] */ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - /* smallalpha[26] */ "abcdefghijklmnopqrstuvwxyz"; -_Static_assert (sizeof baseref - 1 == maxbase); - -bad itoasc(word val, const char* buf_start, char* buf_end, char** newbuf) { - char* ptr = buf_end; - - *ptr-- = 0; - while(val > 0) { - if (ptr < buf_start) return bad_overflow; - word rem = val % 128; - val /= 128; - *ptr-- = (char)rem; - } - - if (newbuf != null) *newbuf = ptr + 1; - return ok; -} - -bool lowercase = false; -bad itoa(word base, word val, const char* buf_start, - char* buf_end, char** newbuf) { - - char* ptr = buf_end; - - if (base > maxbase) return bad_base; - if (base == 0) return itoasc(val, buf_start, buf_end, newbuf); - - *ptr-- = 0; - if (val == 0) *ptr-- = '0'; - else while(val > 0) { - if (ptr < buf_start) return bad_overflow; - word rem = val % base; - val /= base; - char out = baseref[rem]; - if (lowercase && base <= imaxbase) - if (out >= 'A' && out <= 'Z') - out += ('a' - 'A'); - *ptr-- = out; - } - - if (newbuf != null) *newbuf = ptr + 1; - return ok; -} +/* import the conversion utilities */ +typedef bad iaia_error_type; +typedef word iaia_word_type; +enum /* iaia synonyms */ { + iaia_e_ok = ok, + iaia_e_domain = bad_domain, + iaia_e_base = bad_base, + iaia_e_overflow = bad_overflow, +}; +#include "clib/iaia.c" bad run(const int argc, const char** argv) { # ifndef _POSIX_IO /* fuck your buffering, it only ever makes @@ -263,8 +158,9 @@ bool raw = false; bool prefix = false; + bool lowercase = false; for (const char** arg = argv + 1; *arg != null; ++arg) { uint8_t tblval; if (*arg[0] == '%') { ++ *arg; goto number; } else @@ -342,9 +238,9 @@ for (const char** s = in_vals; *s != null; ++s) { word val; bad e = atoi(base[set_in], *s, &val); if (e == ok) { - bad e = itoa(base[set_out], val, buf, ptr, &ptr); + bad e = itoa(base[set_out], val, buf, ptr, &ptr, lowercase); if (prefix) { if (pfxstr != null) { print(pfxstrlen, pfxstr); } else if (base[set_out] < sz(prefixes)) {