util  Check-in [42ea2c7296]

Overview
Comment:add mkpw
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 42ea2c7296fcf7fbdfb520435719ffece5a2b9d6db8baf6affc8e0521c1d84a6
User & Date: lexi on 2019-07-19 11:34:42
Other Links: manifest | tags
Context
2019-07-19
11:47
switch from syscall to getrandom check-in: 6b3b3fa87f user: lexi tags: trunk
11:34
add mkpw check-in: 42ea2c7296 user: lexi tags: trunk
06:37
fix dumb bugs check-in: e3d4aa2fb2 user: lexi tags: trunk
Changes

Added clib/iaia.c version [b9f828e90b].



































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/* [ʞ] iaia.c
 *  ~ lexi hale <lexi@hale.su>
 *  # include "iaia.c"
 *  # define _IAIA_FN_{ATOI,ITOA,ASCTOI,ITOASC}
 *  : typedef iaia_word_type,
 *            iaia_error_type
 *  : enum iaia_e_domain,
 *         iaia_e_base,
 *         iaia_e_overflow
 *  ? arbitrary-base integer conversion functions
 */

#ifndef _IAIA_FN_ATOI
#	define _IAIA_FN_ATOI atoi
#endif
#ifndef _IAIA_FN_ITOA
#	define _IAIA_FN_ITOA itoa
#endif
#ifndef _IAIA_FN_ASCTOI
#	define _IAIA_FN_ASCTOI asctoi
#endif
#ifndef _IAIA_FN_ITOASC
#	define _IAIA_FN_ITOASC itoasc
#endif

enum /* constants */ {

	/* 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 */
};

/* -- string to integer converters -- */

iaia_error_type _IAIA_FN_ASCTOI(const char* s, iaia_word_type* ret) {
	iaia_word_type val = 0;
	enum { base = 128 };

	for (;*s!=null;++s) {
		uint8_t v = *s;
		if (v > base) return iaia_e_domain;

		val *= base;
		val += v;
	}

	*ret = val;
	return ok;
}

iaia_error_type _IAIA_FN_ATOI(iaia_word_type base, const char* s, iaia_word_type* ret) {
	/* s must be a null-terminated ASCII numeral string */
	if (base > maxbase) return iaia_e_base;

	/* override the default base if it's a basèd literal */
	if (s[0] == '@' || base == 0) return _IAIA_FN_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);
	iaia_word_type 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 iaia_e_domain;
		}
		checkval: if (v >= base) return iaia_e_domain;

		val *= base;
		val += v;
	}

	*ret = val;
	return iaia_e_ok;
}


/* -- integer to string converters -- */

/* 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 iaia_ref_table[] = /* numerals[10] */ "0123456789"
	/* bigalpha[26] */ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	/* smallalpha[26] */ "abcdefghijklmnopqrstuvwxyz";
_Static_assert (sizeof iaia_ref_table - 1 == maxbase);

iaia_error_type _IAIA_FN_ITOASC(iaia_word_type val, const char* buf_start, char* buf_end, char** newbuf) {
	char* ptr = buf_end;

	*ptr-- = 0;
	while(val > 0) {
		if (ptr < buf_start) return iaia_e_overflow;
		iaia_word_type rem = val % 128;
		val /= 128;
		*ptr-- = (char)rem;
	}

	if (newbuf != null) *newbuf = ptr + 1;
	return ok;
}

iaia_error_type _IAIA_FN_ITOA(iaia_word_type base, iaia_word_type val, const char* buf_start,
		char* buf_end, char** newbuf, bool lowercase) {

	char* ptr = buf_end;

	if (base > maxbase) return iaia_e_base;
	if (base == 0) return _IAIA_FN_ITOASC(val, buf_start, buf_end, newbuf);

	*ptr-- = 0;
	if (val == 0) *ptr-- = '0';
	else while(val > 0) {
		if (ptr < buf_start) return iaia_e_overflow;
		iaia_word_type rem = val % base;
		val /= base;
		char out = iaia_ref_table[rem];
		if (lowercase && base <= imaxbase)
			if (out >= 'A' && out <= 'Z')
				out += ('a' - 'A');
		*ptr-- = out;
	}

	if (newbuf != null) *newbuf = ptr + 1;
	return iaia_e_ok;
}

Added clib/tbl.c version [92768be859].

































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* [ʞ] tbl.c
 *  ~ lexi hale <lexi@hale.su>
 *  ? simple table-scanning function to make
 *    parsing easier */

struct tblrow { tbl_word_type val; const char* str; };

tbl_error_type tblget(size_t stacksz, const struct tblrow* haystack, const char* needle, tbl_word_type* val) {
	for (size_t i = 0; i<stacksz; ++i) {
		if (strcmp(haystack[i].str, needle) == ok) {
			*val = haystack[i].val;
			return tbl_ok;
		}
	}
	return tbl_error;
}

Added mkpw.c version [a0f03f1e22].





























































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
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
/* [ʞ] mkpw.c - make password
 *  ~ lexi hale <lexi@hale.su>
 *  © AGPLv3
 *  $ cc -O4 mkpw.c -omkpw [-D_CLIPBOARD]
 *    - D_CLIPBOARD enables mkpw to automatically
 *      copy new passwords to the clipboard. it
 *      does this by attempting to execute a sequence
 *      of binaries, and then writing the password
 *      to STDIN of the binary that succeeds.
 *  ? generates passwords
 *  → mkpw is unlikely to be portable to non-POSIX
 *    systems, but should run fine on Linux as well
 *    as BSDs with getrandom() support.
 */

#include <unistd.h>
#include <sys/random.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#define sz(a) ( sizeof (a) / sizeof (a) [0] )
#define say(x) (write(2, (x), sizeof (x)))

#ifdef _CLIPBOARD
#	include <sys/types.h>
#	include <pwd.h>
#	include <stdlib.h>
#	define _cl_opt o('n',nocopy,copy = false)
#else
#	define _cl_opt
#endif
 
#define options \
	o('l',lower,mode = lower) \
	o('m',mix,mode = mix) \
	o('u',upper,mode = upper)\
	_cl_opt

enum /* constants */ {
	null = 0, true = 1, false = 0
};

typedef enum bad {
	ok = 0,
	fail = 1,
	bad_user,
	bad_option,
	bad_syntax,
	bad_usage = 64, /* fleabsd idiom */
} bad;

typedef _Bool bool;
typedef unsigned long long iaia_word_type;
typedef bad iaia_error_type;
enum /* iaia errors */ {
	iaia_e_ok = ok,
	iaia_e_base = fail,
	iaia_e_domain = fail,
	iaia_e_overflow = fail,
};
#define _IAIA_FN_ATOI katoi
#include "clib/iaia.c"

typedef enum {
	tbl_ok = ok, tbl_error = fail
} tbl_error_type;
typedef unsigned char tbl_word_type;
#include "clib/tbl.c"

enum args {
#define o(short, long, code) arg_##long,
	options
#undef o
};

struct tblrow argtbl[] = {
#define o(short, long, code) {arg_##long, #long},
	options
#undef o
};

#define str_ucase "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define str_lcase "abcdefghijklmnopqrstuvwxyz"
#define str_num "0123456789" 
const char* reftbl = str_num str_ucase str_lcase;
const char* reftbl_lcase = str_num str_lcase;

#ifdef _CLIPBOARD
char* const* cbd_cmds[] = {
	/* NOTE: these commands must be specified in order of
	 * most- to least-specific. more than one utility may
	 * be present on a given system, so we need to make sure
	 * the right one is called. */
	(char* const[]){"termux-clipboard-set", null},
	(char* const[]){"xsel", "-bi", null},
	/* TODO: allow command to be specified by env var */
	null
};
#endif
int main(int argc, const char** argv) {
	if (argc == 0) return -1;
	if (argc == 1) { 
		size_t namelen = strlen(argv[0]);
		say("\x1b[1musage:\x1b[m ");
		write(2, argv[0], namelen);
		say(" [-lmu"
#		ifdef _CLIPBOARD		
			"n"
#		endif
		"] [--lower] [--mix] [--upper]"
#		ifdef _CLIPBOARD		
			" [--nocopy]"
#		endif
		" <length> [<quantity>]");
		return bad_usage;
	}

	enum { upper, mix, lower } mode = lower;
	unsigned long long len, q = 1;
	bool gotlen = false;
	bool gotq = false;

#	ifdef _CLIPBOARD
		bool copy = true;
#	endif
	for (const char** arg = argv; *arg != null; ++arg) {
		if ((*arg)[0] == '-') {
			if ((*arg)[1] == '-') { /* long opt */
				unsigned char a;
				if (tblget(sz(argtbl), argtbl, *arg + 2, &a) == ok) switch (a) {
#					define o(short, long, code) case arg_##long:code;break;
						options
#					undef o
				} else {
					return bad_option;
				}
			} else { /* short opt */
				for(const char* ptr = (*arg) + 1; *ptr != 0; ++ptr) {
					switch(*ptr) {
#						define o(short, long, code) case short:code;break;
 		   					options
#						undef o
						default: return bad_option;
					}
				}
			}
		} else {
			if (gotq) return bad_syntax;
			else if (gotlen) {
				if (katoi(10, *arg, &q) == ok) {
					gotq = true;
				}
			} else if(katoi(10, *arg, &len) == ok) {
				gotlen = true;
			}
		}
	}
	if (!gotlen) return bad_syntax;
#	ifdef _CLIPBOARD
	if (geteuid() == 0 && copy) {
		/* on a sane system, what we'd do is hike up the process
		 * tree til we found a non-root user. alas, this is UNIX. */
		const char* realuser = getenv("SUDO_USER");
		if (realuser == null) realuser = "nobody";

		say("\x1b[1;33mwarning:\x1b[m you are running \x1b[4m");
			size_t namelen = strlen(argv[0]);
			write(2,argv[0],namelen);
		say("\x1b[24m as \x1b[1mroot\x1b[m! dropping to \x1b[1m");
			write(2,realuser,strlen(realuser));
			setenv("USER", realuser, true);
		say("\x1b[m to prevent malicious behavior\n");

		struct passwd* nobody = getpwnam(realuser);
		if (nobody == null) {
			say("\x1b[1;31mfatal:\x1b[m could not get UID to drop privileges; bailing");
			return bad_user;
		} else {
			setenv("HOME", nobody -> pw_dir, true);
			setenv("SHELL", "/dev/null", true);
			setuid(nobody -> pw_uid);
		}

	}
#	endif
	
	const unsigned char chars = (sizeof str_num - 1) +
		((mode == upper) ? (sizeof str_ucase - 1) :
		((mode == lower) ? (sizeof str_lcase - 1) :
			((sizeof str_ucase - 1) + (sizeof str_lcase - 1))));
	const char* tbl = (mode == upper) ? reftbl :
			((mode == lower) ? reftbl_lcase : reftbl);

	char buf[len+1];
	/* *buf = 0; */

	unsigned char noise[len];
	for (size_t i = 0; i<q; ++i) {
		unsigned char* cur = noise;
		getrandom(noise, len, 0);

		for(char* ptr = buf; ptr < buf + len; ++ptr, ++cur) {
			*ptr = tbl[*cur % chars]; /* such a waste of entropy… :( */
		}

		buf[len] = '\n';
		write(1, buf, len + 1);
	}

#	ifdef _CLIPBOARD
		if (copy) {
			char* const clipboard_env = getenv("mkpw_clipboard_setter");
			char* const clipboard_env_arg = getenv("mkpw_clipboard_setter_arg");
			// FIXME: allow multiple args
			int fds[2];
			if (pipe(fds) != 0) return 63;
			if (!fork()) {
				close(fds[1]);
				dup2(fds[0], 0);
				if (clipboard_env != null) {
					execvp(clipboard_env, (char* const[]){
							clipboard_env, clipboard_env_arg, null});
					return -1;
				} else for(char* const** cmd = cbd_cmds; *cmd != null; ++cmd) {
					execvp((*cmd)[0], *cmd);
				}
				return -1; /* exec failed */
			} else {
				close(fds[0]);
				write(fds[1], buf, len);
				write(fds[1], "\n", 1);
				close(fds[1]);
			}
		}
#	endif
	
	return ok;
}

Modified ord.c from [1556b70bdd] to [4cd517ba89].

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);
				}