34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
..
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
...
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
...
260
261
262
263
264
265
266
267
268
269
270
271
272
273
...
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
|
# define forlibc(x) x
#endif
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <limits.h>
#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") \
e(syntax, "invalid syntax") \
e(base, "that base is out of range") \
e(overflow, "a memory overflow has occurred") \
................................................................................
typedef enum bad {
ok = 0, fail = 1,
# define e(name, desc) bad_##name,
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<stacksz; ++i) {
if (strcmp(haystack[i].str, needle) == ok) {
*val = haystack[i].val;
return ok;
}
}
return bad_find;
}
enum argument {
arg_to, arg_set, arg_base,
arg_asc,
arg_bin, arg_trn, arg_oct, arg_dec,
................................................................................
{switch_prefix, "-p"}, {switch_prefix, "--prefix"},
{switch_lowercase, "-l"}, {switch_lowercase, "--lowercase"},
{param_prefix, "-m"}, {param_prefix, "--manual-prefix"},
{arg_ebcdic, "ebcdic"},
};
bad asctoi(const char* s, word* ret) {
word val = 0;
enum { base = 128 };
for (;*s!=null;++s) {
uint8_t v = *s;
if (v > 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;
}
bad run(const int argc, const char** argv) {
# ifndef _POSIX_IO
/* fuck your buffering, it only ever makes
* things worse */
setvbuf(stdout,null,_IONBF);
# endif
................................................................................
const char** invalp = in_vals;
const char* pfxstr;
forposix(size_t pfxstrlen);
bool raw = false;
bool prefix = false;
for (const char** arg = argv + 1; *arg != null; ++arg) {
uint8_t tblval;
if (*arg[0] == '%') { ++ *arg; goto number; } else
if (!raw && (tblget(sz(argtbl),argtbl, *arg, &tblval) == ok)) {
enum argument symbol = (enum argument) tblval;
switch (symbol) {
................................................................................
char* ptr = (buf + bufmax) - 1;
forposix(char* lastptr = ptr);
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);
if (prefix) {
if (pfxstr != null) { print(pfxstrlen, pfxstr); }
else if (base[set_out] < sz(prefixes)) {
print((size_t)prefixes[base[set_out]][0],
prefixes[base[set_out]] + 1);
}
|
>
<
<
<
<
<
<
<
<
<
<
|
|
|
|
|
|
<
<
<
|
|
|
<
>
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
>
>
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
>
>
|
|
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
..
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
...
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
...
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
...
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
|
# define forlibc(x) x
#endif
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <limits.h>
#define sz(x) ( sizeof (x) / sizeof (x) [0] )
enum /* constants */ {
null = 0,
};
typedef unsigned long long word;
typedef _Bool bool;
enum { false = 0, true = 1 };
#define error_list \
e(domain, "bad argument passed for domain") \
e(find, "could not find key in table") \
e(syntax, "invalid syntax") \
e(base, "that base is out of range") \
e(overflow, "a memory overflow has occurred") \
................................................................................
typedef enum bad {
ok = 0, fail = 1,
# define e(name, desc) bad_##name,
error_list
# undef e
} bad;
typedef enum {
tbl_ok = ok, tbl_error = bad_find
} tbl_error_type;
typedef unsigned char tbl_word_type;
#include "clib/tbl.c"
typedef struct tblrow pair;
enum argument {
arg_to, arg_set, arg_base,
arg_asc,
arg_bin, arg_trn, arg_oct, arg_dec,
................................................................................
{switch_prefix, "-p"}, {switch_prefix, "--prefix"},
{switch_lowercase, "-l"}, {switch_lowercase, "--lowercase"},
{param_prefix, "-m"}, {param_prefix, "--manual-prefix"},
{arg_ebcdic, "ebcdic"},
};
/* 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
* things worse */
setvbuf(stdout,null,_IONBF);
# endif
................................................................................
const char** invalp = in_vals;
const char* pfxstr;
forposix(size_t pfxstrlen);
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
if (!raw && (tblget(sz(argtbl),argtbl, *arg, &tblval) == ok)) {
enum argument symbol = (enum argument) tblval;
switch (symbol) {
................................................................................
char* ptr = (buf + bufmax) - 1;
forposix(char* lastptr = ptr);
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, lowercase);
if (prefix) {
if (pfxstr != null) { print(pfxstrlen, pfxstr); }
else if (base[set_out] < sz(prefixes)) {
print((size_t)prefixes[base[set_out]][0],
prefixes[base[set_out]] + 1);
}
|