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