MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

add robust argument parsing for TTY control functions

+134 -49
+29 -2
include/tty_ctrl.h
··· 5 5 #include <stddef.h> 6 6 #include <stdio.h> 7 7 8 - bool tty_ctrl_write_fd(int fd, const char *data, size_t len); 9 - bool tty_ctrl_write_stream(FILE *stream, const char *data, size_t len, bool flush); 8 + #include "types.h" 9 + 10 + ant_value_t tty_ctrl_bool_result(ant_t *js, bool ok); 10 11 11 12 const char *tty_ctrl_clear_line_seq(int dir, size_t *len_out); 12 13 const char *tty_ctrl_clear_screen_down_seq(size_t *len_out); 13 14 15 + int tty_ctrl_normalize_clear_line_dir(int dir); 16 + int tty_ctrl_normalize_coord(int value); 17 + 18 + bool tty_ctrl_parse_int_value(ant_value_t value, int *out); 19 + bool tty_ctrl_write_fd(int fd, const char *data, size_t len); 20 + bool tty_ctrl_write_stream(FILE *stream, const char *data, size_t len, bool flush); 21 + 22 + bool tty_ctrl_parse_clear_line_dir(ant_value_t *args, int nargs, int dir_index, int *dir_out); 14 23 bool tty_ctrl_build_cursor_to(char *buf, size_t buf_size, int x, bool has_y, int y, size_t *len_out); 15 24 bool tty_ctrl_build_move_cursor_axis(char *buf, size_t buf_size, int delta, bool horizontal, size_t *len_out); 25 + 26 + typedef struct { 27 + int x; 28 + bool has_y; 29 + int y; 30 + } tty_ctrl_cursor_to_args_t; 31 + 32 + bool tty_ctrl_parse_cursor_to_args( 33 + ant_value_t *args, int nargs, 34 + int x_index, int y_index, 35 + tty_ctrl_cursor_to_args_t *out 36 + ); 37 + 38 + bool tty_ctrl_parse_move_cursor_args( 39 + ant_value_t *args, int nargs, 40 + int dx_index, int dy_index, 41 + int *dx, int *dy 42 + ); 16 43 17 44 #endif
+16 -24
src/modules/readline.c
··· 1193 1193 } 1194 1194 1195 1195 static ant_value_t rl_clear_line(ant_t *js, ant_value_t *args, int nargs) { 1196 - (void)js; 1197 - if (nargs < 2) return js_false; 1198 - int dir = (int)js_getnum(args[1]); 1196 + int dir = 0; 1197 + if (!tty_ctrl_parse_clear_line_dir(args, nargs, 1, &dir)) return js_false; 1199 1198 1200 1199 size_t seq_len = 0; 1201 1200 const char *seq = tty_ctrl_clear_line_seq(dir, &seq_len); 1202 - return js_bool(tty_ctrl_write_stream(stdout, seq, seq_len, true)); 1201 + return tty_ctrl_bool_result(js, tty_ctrl_write_stream(stdout, seq, seq_len, true)); 1203 1202 } 1204 1203 1205 1204 static ant_value_t rl_clear_screen_down(ant_t *js, ant_value_t *args, int nargs) { 1206 - (void)js; (void)args; (void)nargs; 1207 - 1208 1205 size_t seq_len = 0; 1209 1206 const char *seq = tty_ctrl_clear_screen_down_seq(&seq_len); 1210 - return js_bool(tty_ctrl_write_stream(stdout, seq, seq_len, true)); 1207 + return tty_ctrl_bool_result(js, tty_ctrl_write_stream(stdout, seq, seq_len, true)); 1211 1208 } 1212 1209 1213 1210 static ant_value_t rl_cursor_to(ant_t *js, ant_value_t *args, int nargs) { 1214 - (void)js; 1215 - if (nargs < 2) return js_false; 1216 - int x = (int)js_getnum(args[1]); 1211 + tty_ctrl_cursor_to_args_t parsed; 1212 + if (!tty_ctrl_parse_cursor_to_args(args, nargs, 1, 2, &parsed)) return js_false; 1217 1213 1218 1214 char seq[64]; 1219 1215 size_t seq_len = 0; 1220 - bool ok = false; 1221 - if (nargs >= 3 && vtype(args[2]) == T_NUM) { 1222 - int y = (int)js_getnum(args[2]); 1223 - ok = tty_ctrl_build_cursor_to(seq, sizeof(seq), x, true, y, &seq_len); 1224 - } else { 1225 - ok = tty_ctrl_build_cursor_to(seq, sizeof(seq), x, false, 0, &seq_len); 1226 - } 1216 + bool ok = tty_ctrl_build_cursor_to( 1217 + seq, sizeof(seq), 1218 + parsed.x, parsed.has_y, parsed.y, 1219 + &seq_len 1220 + ); 1227 1221 if (!ok) return js_false; 1228 1222 1229 - return js_bool(tty_ctrl_write_stream(stdout, seq, seq_len, true)); 1223 + return tty_ctrl_bool_result(js, tty_ctrl_write_stream(stdout, seq, seq_len, true)); 1230 1224 } 1231 1225 1232 1226 static ant_value_t rl_move_cursor(ant_t *js, ant_value_t *args, int nargs) { 1233 - (void)js; 1234 - if (nargs < 3) return js_false; 1235 - 1236 - int dx = (int)js_getnum(args[1]); 1237 - int dy = (int)js_getnum(args[2]); 1227 + int dx = 0; 1228 + int dy = 0; 1229 + if (!tty_ctrl_parse_move_cursor_args(args, nargs, 1, 2, &dx, &dy)) return js_false; 1238 1230 1239 1231 bool ok = true; 1240 1232 if (dx != 0) { ··· 1252 1244 } 1253 1245 1254 1246 if (!ok) return js_false; 1255 - return js_bool(fflush(stdout) == 0); 1247 + return tty_ctrl_bool_result(js, fflush(stdout) == 0); 1256 1248 } 1257 1249 1258 1250 static ant_value_t rl_emit_keypress_events(ant_t *js, ant_value_t *args, int nargs) {
+9 -22
src/modules/tty.c
··· 1 1 #include <compat.h> // IWYU pragma: keep 2 2 3 - #include <limits.h> 4 3 #include <stdbool.h> 5 4 #include <stdio.h> 6 5 #include <stdlib.h> ··· 43 42 return t == T_FUNC || t == T_CFUNC; 44 43 } 45 44 46 - static bool parse_int(ant_value_t value, int *out) { 47 - if (vtype(value) != T_NUM) return false; 48 - double d = js_getnum(value); 49 - if (!isfinite(d)) return false; 50 - if (d < (double)INT_MIN || d > (double)INT_MAX) return false; 51 - int i = (int)d; 52 - if ((double)i != d) return false; 53 - *out = i; 54 - return true; 55 - } 56 - 57 45 static bool parse_fd(ant_value_t value, int *fd_out) { 58 46 int fd = 0; 59 - if (!parse_int(value, &fd)) return false; 47 + if (!tty_ctrl_parse_int_value(value, &fd)) return false; 60 48 if (fd < 0) return false; 61 49 *fd_out = fd; 62 50 return true; ··· 413 401 ant_value_t this_obj = js_getthis(js); 414 402 415 403 int dir = 0; 416 - if (nargs > 0 && vtype(args[0]) != T_UNDEF && !parse_int(args[0], &dir)) { 404 + if (!tty_ctrl_parse_clear_line_dir(args, nargs, 0, &dir)) { 417 405 return js_mkerr_typed(js, JS_ERR_TYPE, "clearLine(dir) requires a numeric dir"); 418 406 } 419 407 ··· 442 430 443 431 static ant_value_t tty_write_stream_cursor_to(ant_t *js, ant_value_t *args, int nargs) { 444 432 ant_value_t this_obj = js_getthis(js); 445 - if (nargs < 1 || !parse_int(args[0], &(int){0})) { 433 + int x = 0; 434 + if (nargs < 1 || !tty_ctrl_parse_int_value(args[0], &x)) { 446 435 return js_mkerr_typed(js, JS_ERR_TYPE, "cursorTo(x[, y][, callback]) requires numeric x"); 447 436 } 448 437 449 - int x = 0; 450 - (void)parse_int(args[0], &x); 451 - if (x < 0) x = 0; 438 + x = tty_ctrl_normalize_coord(x); 452 439 453 440 bool has_y = false; 454 441 int y = 0; ··· 459 446 cb = args[1]; 460 447 } else if (vtype(args[1]) == T_UNDEF) { 461 448 // no-op 462 - } else if (parse_int(args[1], &y)) { 449 + } else if (tty_ctrl_parse_int_value(args[1], &y)) { 463 450 has_y = true; 464 - if (y < 0) y = 0; 451 + y = tty_ctrl_normalize_coord(y); 465 452 if (nargs > 2 && is_callable(args[2])) cb = args[2]; 466 453 } else { 467 454 return js_mkerr_typed(js, JS_ERR_TYPE, "cursorTo y must be a number when provided"); ··· 487 474 488 475 int dx = 0; 489 476 int dy = 0; 490 - if (!parse_int(args[0], &dx) || !parse_int(args[1], &dy)) { 477 + if (!tty_ctrl_parse_move_cursor_args(args, nargs, 0, 1, &dx, &dy)) { 491 478 return js_mkerr_typed(js, JS_ERR_TYPE, "moveCursor(dx, dy[, callback]) requires numeric dx and dy"); 492 479 } 493 480 ··· 534 521 if (nargs > 0) { 535 522 if (vtype(args[0]) == T_NUM) { 536 523 int parsed_count = 16; 537 - if (!parse_int(args[0], &parsed_count)) { 524 + if (!tty_ctrl_parse_int_value(args[0], &parsed_count)) { 538 525 return js_mkerr_typed(js, JS_ERR_TYPE, "hasColors(count[, env]) count must be an integer"); 539 526 } 540 527 count = parsed_count;
+80 -1
src/tty_ctrl.c
··· 1 1 #include <compat.h> // IWYU pragma: keep 2 - #include "tty_ctrl.h" 3 2 4 3 #include <errno.h> 4 + #include <limits.h> 5 + #include <math.h> 5 6 #include <stdio.h> 6 7 #include <string.h> 7 8 ··· 12 13 #include <unistd.h> 13 14 #define ANT_WRITE_FD write 14 15 #endif 16 + 17 + #include "tty_ctrl.h" 18 + #include "internal.h" 15 19 16 20 bool tty_ctrl_write_fd(int fd, const char *data, size_t len) { 17 21 if (fd < 0 || !data) return false; ··· 46 50 return true; 47 51 } 48 52 53 + bool tty_ctrl_parse_int_value(ant_value_t value, int *out) { 54 + if (vtype(value) != T_NUM) return false; 55 + double d = js_getnum(value); 56 + if (!isfinite(d)) return false; 57 + if (d < (double)INT_MIN || d > (double)INT_MAX) return false; 58 + int i = (int)d; 59 + if ((double)i != d) return false; 60 + *out = i; 61 + return true; 62 + } 63 + 64 + int tty_ctrl_normalize_clear_line_dir(int dir) { 65 + if (dir < 0) return -1; 66 + if (dir > 0) return 1; 67 + return 0; 68 + } 69 + 70 + int tty_ctrl_normalize_coord(int value) { 71 + return value < 0 ? 0 : value; 72 + } 73 + 74 + bool tty_ctrl_parse_clear_line_dir(ant_value_t *args, int nargs, int dir_index, int *dir_out) { 75 + int dir = 0; 76 + if (nargs > dir_index && vtype(args[dir_index]) != T_UNDEF) { 77 + if (!tty_ctrl_parse_int_value(args[dir_index], &dir)) return false; 78 + } 79 + *dir_out = tty_ctrl_normalize_clear_line_dir(dir); 80 + return true; 81 + } 82 + 83 + bool tty_ctrl_parse_cursor_to_args( 84 + ant_value_t *args, 85 + int nargs, 86 + int x_index, 87 + int y_index, 88 + tty_ctrl_cursor_to_args_t *out 89 + ) { 90 + if (!out || nargs <= x_index) return false; 91 + 92 + int x = 0; 93 + if (!tty_ctrl_parse_int_value(args[x_index], &x)) return false; 94 + out->x = tty_ctrl_normalize_coord(x); 95 + out->has_y = false; 96 + out->y = 0; 97 + 98 + if (nargs > y_index && vtype(args[y_index]) != T_UNDEF) { 99 + int y = 0; 100 + if (!tty_ctrl_parse_int_value(args[y_index], &y)) return false; 101 + out->has_y = true; 102 + out->y = tty_ctrl_normalize_coord(y); 103 + } 104 + 105 + return true; 106 + } 107 + 108 + bool tty_ctrl_parse_move_cursor_args( 109 + ant_value_t *args, 110 + int nargs, 111 + int dx_index, 112 + int dy_index, 113 + int *dx, 114 + int *dy 115 + ) { 116 + if (!dx || !dy) return false; 117 + if (nargs <= dy_index) return false; 118 + if (!tty_ctrl_parse_int_value(args[dx_index], dx)) return false; 119 + if (!tty_ctrl_parse_int_value(args[dy_index], dy)) return false; 120 + return true; 121 + } 122 + 49 123 const char *tty_ctrl_clear_line_seq(int dir, size_t *len_out) { 124 + dir = tty_ctrl_normalize_clear_line_dir(dir); 50 125 const char *seq = "\033[2K\r"; 51 126 if (dir < 0) seq = "\033[1K"; 52 127 else if (dir > 0) seq = "\033[0K"; ··· 92 167 if (len_out) *len_out = (size_t)n; 93 168 return true; 94 169 } 170 + 171 + ant_value_t tty_ctrl_bool_result(ant_t *js, bool ok) { 172 + return js_bool(ok); 173 + }