1 /* Copyright 2019
2  * Ramon Fried <ramon.fried@gmail.com>
3  */
4 
5 #include <ctype.h>
6 #include <inttypes.h>
7 #include "bitwise.h"
8 
9 /* IEC Standard */
10 #define KiB (1ULL << 10)
11 #define MiB (1ULL << 20)
12 #define GiB (1ULL << 30)
13 #define TiB (1ULL << 40)
14 #define PiB (1ULL << 50)
15 
16 /* SI Standard */
17 #define kB (1000ULL)
18 #define MB (1000 * kB)
19 #define GB (1000 * MB)
20 #define TB (1000 * GB)
21 #define PB (1000 * TB)
22 
23 int g_has_color = 1;
24 int g_width = 0;
25 bool g_input_avail;
26 int g_input;
27 
28 #define RED   "\x1B[31m"
29 #define GREEN   "\x1B[32m"
30 #define YEL   "\x1B[33m"
31 #define BLUE   "\x1B[34m"
32 #define MAGENTA   "\x1B[35m"
33 #define CYAN   "\x1B[36m"
34 #define WHITE   "\x1B[37m"
35 #define RESET "\x1B[0m"
36 #define NOTHING ""
37 
38 char *color_green = NOTHING;
39 char *color_red = NOTHING;
40 char *color_blue = NOTHING;
41 char *color_magenta = NOTHING;
42 char *color_cyan = NOTHING;
43 char *color_white = NOTHING;
44 char *color_reset = NOTHING;
45 
init_colors(void)46 void init_colors(void)
47 {
48 	if (g_has_color) {
49 		color_green = GREEN;
50 		color_red = RED;
51 		color_blue = BLUE;
52 		color_magenta = MAGENTA;
53 		color_cyan = CYAN;
54 		color_white = WHITE;
55 		color_reset = RESET;
56 	} else {
57 		color_green = NOTHING;
58 		color_red = NOTHING;
59 		color_blue = NOTHING;
60 		color_magenta = NOTHING;
61 		color_cyan = NOTHING;
62 		color_white = NOTHING;
63 		color_reset = NOTHING;
64 	}
65 }
66 
init_terminal(void)67 void init_terminal(void)
68 {
69 	initscr();
70 	if (has_colors() == FALSE)
71 		g_has_color = 0;
72 	else {
73 		start_color();
74 		init_colors();
75 	}
76 	cbreak();
77 	noecho();
78 	nonl();
79 	intrflush(NULL, FALSE);
80 	keypad(stdscr, TRUE);
81 	curs_set(2);
82 }
83 
deinit_terminal(void)84 void deinit_terminal(void)
85 {
86 	endwin();
87 }
88 
die(const char * fmt,...)89 void die(const char *fmt, ...)
90 {
91 	va_list args;
92 	va_start(args, fmt);
93 
94 	deinit_terminal();
95 	/* See interactive.c for reasoning */
96 	/* deinit_readline(); */
97 	vfprintf(stderr, fmt, args);
98 	va_end(args);
99 	exit(EXIT_FAILURE);
100 }
101 
validate_input(int ch,int base)102 int validate_input(int ch, int base)
103 {
104 	switch (base) {
105 	case 2:
106 		if (ch == '0' || ch == '1')
107 			return 0;
108 		break;
109 	case 8:
110 		if (ch >= '0' && ch <= '7')
111 			return 0;
112 		break;
113 	case 16:
114 		if ((ch >= '0' && ch <= '9') ||
115 		    (ch >= 'A' && ch <= 'F') ||
116 		    (ch >= 'a' && ch <= 'f'))
117 			return 0;
118 		break;
119 	case 10:
120 		if (isdigit(ch))
121 			return 0;
122 		break;
123 	default:
124 		break;
125 	}
126 
127 	return 1;
128 }
129 
binary_scanf(const char * buf,uint64_t * val)130 int binary_scanf(const char *buf, uint64_t *val)
131 {
132 	uint64_t value = 0;
133 
134 	/* Skip the leading 0 */
135 	if (buf[0] == '0') {
136 		buf++;
137 	}
138 
139 	/* Skip the leading b */
140 	buf++;
141 
142 	while (*buf) {
143 		switch (*buf) {
144 
145 		case '0':
146 			value <<= 1;
147 			break;
148 		case '1':
149 			value <<= 1;
150 			value++;
151 			break;
152 		default:
153 			return 0;
154 		}
155 		buf++;
156 	}
157 
158 	*val = value;
159 
160 	return 1;
161 }
162 
base_scanf(const char * buf,int base,uint64_t * value)163 int base_scanf(const char *buf, int base, uint64_t *value)
164 {
165 	int ret = 0;
166 
167 	switch (base) {
168 	case 10:
169 		ret = sscanf(buf, "%" PRIu64, value);
170 		break;
171 	case 16:
172 		ret = sscanf(buf, "%" PRIX64, value);
173 		break;
174 	case 8:
175 		ret = sscanf(buf, "%" PRIo64, value);
176 		break;
177 	case 2:
178 		ret = binary_scanf(buf, value);
179 		break;
180 	default:
181 		fprintf(stderr, "Unknown base\n");
182 		break;
183 	}
184 
185 	if (ret == EOF || !ret) {
186 		LOG("Couldn't parse number: %s\n", buf);
187 		return 1;
188 	}
189 
190 	return 0;
191 }
192 
ip_scanf(const char * input,uint64_t * val)193 int ip_scanf(const char *input, uint64_t *val)
194 {
195 	union {
196 		uint8_t ip[4];
197 		uint32_t ip32;
198 	} ip;
199 	if (sscanf(input, "%hhu.%hhu.%hhu.%hhu",
200 		   &ip.ip[0], &ip.ip[1], &ip.ip[2], &ip.ip[3]) != 4) {
201 		fprintf(stderr, "Failed parsing IPv4 address\n");
202 		return 1;
203 	}
204 
205 	*val = ip.ip32;
206 	return 0;
207 }
208 
parse_input(const char * input,uint64_t * val)209 int parse_input(const char *input, uint64_t *val)
210 {
211 	int base;
212 
213 	if (strchr(input, '.'))
214 		return ip_scanf(input, val);
215 	if (tolower(input[0]) == 'b')
216 		base = 2;
217 	else if (input[0] == '0')
218 		if (tolower(input[1] == 'b'))
219 			base = 2;
220 		else if (input[1] == 'x' || input[1] == 'X')
221 			base = 16;
222 		else
223 			base = 8;
224 	else
225 		base = 10;
226 
227 	return base_scanf(input, base, val);
228 }
229 
lltostr(uint64_t val,char * buf,int base)230 int lltostr(uint64_t val, char *buf, int base)
231 {
232 	int rc;
233 
234 	switch (base) {
235 	case 10:
236 		rc = sprintf(buf, "%" PRIu64, val);
237 		break;
238 	case 16:
239 		rc = sprintf(buf, "%" PRIx64, val);
240 		break;
241 	case 8:
242 		rc = sprintf(buf, "%" PRIo64, val);
243 		break;
244 	case 2:
245 	default:
246 		sprintf(buf, "Not implemeted");
247 		return -1;
248 	}
249 
250 	if (rc < 0)
251 		LOG("sprintf failed with error: %d\n", rc);
252 
253 	return rc;
254 }
255 
sprintf_type(uint64_t val,char * buf,output_type type)256 int sprintf_type(uint64_t val, char *buf, output_type type)
257 {
258 	int i;
259 	int pos = 0;
260 
261 	switch (type) {
262 	case CMD_OUTPUT_DECIMAL:
263 		sprintf(buf, "Decimal: %" PRIu64, val);
264 		break;
265 	case CMD_OUTPUT_HEXADECIMAL:
266 		sprintf(buf, "Hexadecimal: 0x%" PRIx64, val);
267 		break;
268 	case CMD_OUTPUT_OCTAL:
269 		sprintf(buf, "Octal: 0%" PRIo64, val);
270 		break;
271 	case CMD_OUTPUT_BINARY:
272 		pos = sprintf(buf, "Binary: ");
273 		for (i = g_width; i > 0; i--) {
274 			if ((i % 8 == 0) && (i != g_width)) {
275 				buf[pos] = '|';
276 				buf[pos + 1] = ' ';
277 				pos += 2;
278 			}
279 			if (val & BIT(i - 1)) {
280 				buf[pos] = '1';
281 			}
282 			else {
283 				buf[pos] = '0';
284 			}
285 			buf[pos + 1] = ' ';
286 			pos += 2;
287 		}
288 		buf[pos-1] = '\0';
289 		break;
290 
291 	default:
292 		break;
293 	}
294 
295 	return 0;
296 }
297 
sprintf_size(uint64_t val,char * buf,bool si)298 int sprintf_size(uint64_t val, char *buf, bool si)
299 {
300 	int ret;
301 	double f_val = val;
302 
303 	if (si) {
304 		if (val >= PB)
305 			ret = sprintf(buf, "%.2lf PB", f_val / PB);
306 		else if (val >= TB)
307 			ret = sprintf(buf, "%.2lf TB", f_val / TB);
308 		else if (val >= GB)
309 			ret = sprintf(buf, "%.2lf GB", f_val / GB);
310 		else if (val >= MB)
311 			ret = sprintf(buf, "%.2lf MB", f_val / MB);
312 		else if (val >= kB)
313 			ret = sprintf(buf, "%.2lf Kb", f_val / kB);
314 		else
315 			ret = sprintf(buf, "%" PRIu64, val);
316 	} else {
317 		if (val >= PiB)
318 			ret = sprintf(buf, "%.2lf PiB", f_val / PiB);
319 		else if (val >= TiB)
320 			ret = sprintf(buf, "%.2lf TiB", f_val / TiB);
321 		else if (val >= GiB)
322 			ret = sprintf(buf, "%.2lf GiB", f_val / GiB);
323 		else if (val >= MiB)
324 			ret = sprintf(buf, "%.2lf MiB", f_val / MiB);
325 		else if (val >= KiB)
326 			ret = sprintf(buf, "%.2lf KiB", f_val / KiB);
327 		else
328 			ret = sprintf(buf, "%" PRIu64, val);
329 	}
330 
331 	return ret;
332 }
333 
set_width_by_val(uint64_t val)334 void set_width_by_val(uint64_t val)
335 {
336 	if (val & 0xFFFFFFFF00000000)
337 		g_width = 64;
338 	else if (val & 0xFFFF0000)
339 		g_width = 32;
340 	else if (val & 0xFF00)
341 		g_width = 16;
342 	else if (val & 0xFF)
343 		g_width = 8;
344 	else
345 		g_width = 32;
346 }
347 
set_width(char width)348 int set_width(char width)
349 {
350 	if (tolower(width) == 'b')
351 		g_width = 8;
352 	else if (tolower(width) == 'w')
353 		g_width = 16;
354 	else if (tolower(width) == 'l')
355 		g_width = 32;
356 	else if (tolower(width) == 'd')
357 		g_width = 64;
358 	else
359 		return 1;
360 
361 	return 0;
362 }
363