Rizin
unix-like reverse engineering framework and cli tools
dietline.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2007-2020 pancake <pancake@nopcode.org>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 /* dietline is a lightweight and portable library similar to GNU readline */
4 
5 #include <rz_cons.h>
6 #include <rz_core.h>
7 #include <string.h>
8 #include <stdlib.h>
9 
10 #if __WINDOWS__
11 #include <windows.h>
12 #define printf(...) rz_cons_win_printf(false, __VA_ARGS__)
13 #define USE_UTF8 1
14 static int rz_line_readchar_win(ut8 *s, int slen);
15 #else
16 #include <sys/ioctl.h>
17 #include <termios.h>
18 #include <signal.h>
19 #define USE_UTF8 1
20 #endif
21 
22 static char *rz_line_nullstr = "";
23 static const char word_break_characters[] = "\t\n ~`!@#$%^&*()-_=+[]{}\\|;:\"'<>,./";
24 
25 typedef enum {
29 
30 static inline bool is_word_break_char(char ch, bool mode) {
31  int i;
32  if (mode == MAJOR_BREAK) {
33  return ch == ' ';
34  }
35  for (i = 0; i < RZ_ARRAY_SIZE(word_break_characters); i++) {
36  if (ch == word_break_characters[i]) {
37  return true;
38  }
39  }
40  return false;
41 }
42 
43 /* https://www.gnu.org/software/bash/manual/html_node/Commands-For-Killing.html */
45  int i, len;
46  if (I.buffer.index <= 0) {
47  return;
48  }
49  for (i = I.buffer.index; i > 0 && is_word_break_char(I.buffer.data[i], mode); i--) {
50  /* Move the cursor index back until we hit a non-word-break-character */
51  }
52  for (; i > 0 && !is_word_break_char(I.buffer.data[i], mode); i--) {
53  /* Move the cursor index back until we hit a word-break-character */
54  }
55  if (i > 0) {
56  i++;
57  } else if (i < 0) {
58  i = 0;
59  }
60  if (I.buffer.index > I.buffer.length) {
61  I.buffer.length = I.buffer.index;
62  }
63  len = I.buffer.index - i;
64  free(I.clipboard);
65  I.clipboard = rz_str_ndup(I.buffer.data + i, len);
66  rz_line_clipboard_push(I.clipboard);
67  memmove(I.buffer.data + i, I.buffer.data + I.buffer.index,
68  I.buffer.length - I.buffer.index + 1);
69  I.buffer.length = strlen(I.buffer.data);
70  I.buffer.index = i;
71 }
72 
73 static void kill_word(BreakMode mode) {
74  int i, len;
75  for (i = I.buffer.index; i < I.buffer.length && is_word_break_char(I.buffer.data[i], mode); i++) {
76  /* Move the cursor index forward until we hit a non-word-break-character */
77  }
78  for (; i < I.buffer.length && !is_word_break_char(I.buffer.data[i], mode); i++) {
79  /* Move the cursor index forward until we hit a word-break-character */
80  }
81  len = i - I.buffer.index;
82  free(I.clipboard);
83  I.clipboard = rz_str_ndup(I.buffer.data + I.buffer.index, len);
84  rz_line_clipboard_push(I.clipboard);
85  memmove(I.buffer.data + I.buffer.index, I.buffer.data + i, I.buffer.length - i + 1);
86  I.buffer.length -= len;
87 }
88 
89 static void paste(bool *enable_yank_pop) {
90  if (I.clipboard) {
91  char *cursor = I.buffer.data + I.buffer.index;
92  int dist = (I.buffer.data + I.buffer.length) - cursor;
93  int len = strlen(I.clipboard);
94  I.buffer.length += len;
95  memmove(cursor + len, cursor, dist);
96  memcpy(cursor, I.clipboard, len);
97  I.buffer.index += len;
98  *enable_yank_pop = true;
99  }
100 }
101 
102 static void unix_word_rubout(void) {
103  int i, len;
104  if (I.buffer.index > 0) {
105  for (i = I.buffer.index - 1; i > 0 && I.buffer.data[i] == ' '; i--) {
106  /* Move cursor backwards until we hit a non-space character or EOL */
107  /* This removes any trailing spaces from the input */
108  }
109  for (; i > 0 && I.buffer.data[i] != ' '; i--) {
110  /* Move cursor backwards until we hit a space character or EOL */
111  /* This deletes everything back to the previous space character */
112  }
113  if (i > 0) {
114  i++;
115  } else if (i < 0) {
116  i = 0;
117  }
118  if (I.buffer.index > I.buffer.length) {
119  I.buffer.length = I.buffer.index;
120  }
121  len = I.buffer.index - i + 1;
122  free(I.clipboard);
123  I.clipboard = rz_str_ndup(I.buffer.data + i, len);
124  rz_line_clipboard_push(I.clipboard);
125  memmove(I.buffer.data + i,
126  I.buffer.data + I.buffer.index,
127  I.buffer.length - I.buffer.index + 1);
128  I.buffer.length = strlen(I.buffer.data);
129  I.buffer.index = i;
130  }
131 }
132 
133 static int inithist(void) {
134  ZERO_FILL(I.history);
135  if ((I.history.size + 1024) * sizeof(char *) < I.history.size) {
136  return false;
137  }
138  I.history.data = (char **)calloc((I.history.size + 1024), sizeof(char *));
139  if (!I.history.data) {
140  return false;
141  }
142  I.history.size = RZ_LINE_HISTSIZE;
143  return true;
144 }
145 
146 /* initialize history stuff */
148  ZERO_FILL(I.completion);
149  if (!inithist()) {
150  return false;
151  }
152  I.echo = true;
153  return true;
154 }
155 
156 #if USE_UTF8
157 /* read utf8 char into 's', return the length in bytes */
158 static int rz_line_readchar_utf8(ut8 *s, int slen) {
159 #if __WINDOWS__
160  return rz_line_readchar_win(s, slen);
161 #else
162  // TODO: add support for w32
163  ssize_t len, i;
164  if (slen < 1) {
165  return 0;
166  }
167  int ch = rz_cons_readchar();
168  if (ch == -1) {
169  return -1;
170  }
171  *s = ch;
172 #if 0
173  if ((t = read (0, s, 1)) != 1) {
174  return t;
175  }
176 #endif
177  *s = rz_cons_controlz(*s);
178  if (*s < 0x80) {
179  len = 1;
180  } else if ((s[0] & 0xe0) == 0xc0) {
181  len = 2;
182  } else if ((s[0] & 0xf0) == 0xe0) {
183  len = 3;
184  } else if ((s[0] & 0xf8) == 0xf0) {
185  len = 4;
186  } else {
187  return -1;
188  }
189  if (len > slen) {
190  return -1;
191  }
192  for (i = 1; i < len; i++) {
193  int ch = rz_cons_readchar();
194  if (ch != -1) {
195  s[i] = ch;
196  }
197  if ((s[i] & 0xc0) != 0x80) {
198  return -1;
199  }
200  }
201  return len;
202 #endif
203 }
204 #endif
205 
206 #if __WINDOWS__
207 static int rz_line_readchar_win(ut8 *s, int slen) { // this function handle the input in console mode
208  if (slen > 0 && rz_cons_readbuffer_readchar((char *)s)) {
209  if (s[0] == '\x1b' && rz_cons_readbuffer_readchar((char *)s + 1)) {
210  if (s[1] == '\x31' && rz_cons_readbuffer_readchar((char *)s + 2)) {
211  return 3;
212  }
213  return 2;
214  }
215  return 1;
216  }
217  INPUT_RECORD irInBuf = { 0 };
218  BOOL ret, bCtrl = FALSE;
219  DWORD mode, out;
220  char buf[5] = { 0 };
221  HANDLE h;
222  void *bed;
223 
224  h = GetStdHandle(STD_INPUT_HANDLE);
225  DWORD new_mode = I.vtmode == RZ_VIRT_TERM_MODE_COMPLETE ? ENABLE_VIRTUAL_TERMINAL_INPUT : 0;
226  GetConsoleMode(h, &mode);
227  SetConsoleMode(h, new_mode);
228  if (I.zerosep) {
229  bed = rz_cons_sleep_begin();
230  DWORD rsz = 0;
231  BOOL ret = ReadFile(h, s, 1, &rsz, NULL);
232  rz_cons_sleep_end(bed);
233  SetConsoleMode(h, mode);
234  if (!ret || rsz != 1) {
235  return 0;
236  }
237  return 1;
238  }
239 do_it_again:
240  bed = rz_cons_sleep_begin();
241  if (rz_cons_singleton()->term_xterm) {
242  ret = ReadFile(h, buf, 1, &out, NULL);
243  } else {
244  ret = ReadConsoleInputW(h, &irInBuf, 1, &out);
245  }
246  rz_cons_sleep_end(bed);
247  if (ret < 1) {
248  return 0;
249  }
250  if (irInBuf.EventType == KEY_EVENT) {
251  if (irInBuf.Event.KeyEvent.bKeyDown) {
252  if (irInBuf.Event.KeyEvent.uChar.UnicodeChar) {
253  char *tmp = rz_utf16_to_utf8_l(&irInBuf.Event.KeyEvent.uChar.UnicodeChar, 1);
254  if (!tmp) {
255  return 0;
256  }
257  strncpy_s(buf, sizeof(buf), tmp, strlen(tmp));
258  free(tmp);
259  } else {
260  int idx = 0;
261  buf[idx++] = 27;
262  buf[idx++] = '['; // Simulate escaping
263  bCtrl = irInBuf.Event.KeyEvent.dwControlKeyState & 8;
264  if (bCtrl) {
265  buf[idx++] = 0x31;
266  }
267  switch (irInBuf.Event.KeyEvent.wVirtualKeyCode) {
268  case VK_UP: buf[idx++] = 'A'; break;
269  case VK_DOWN: buf[idx++] = 'B'; break;
270  case VK_RIGHT: buf[idx++] = 'C'; break;
271  case VK_LEFT: buf[idx++] = 'D'; break;
272  case VK_PRIOR: buf[idx++] = '5'; break; // PAGE UP
273  case VK_NEXT: buf[idx++] = '6'; break; // PAGE DOWN
274  case VK_DELETE: buf[idx++] = '3'; break; // SUPR KEY
275  case VK_HOME: buf[idx++] = 'H'; break; // HOME KEY
276  case VK_END: buf[idx++] = 'F'; break; // END KEY
277  default: buf[0] = 0; break;
278  }
279  }
280  }
281  }
282  if (!buf[0]) {
283  goto do_it_again;
284  }
285  strncpy_s((char *)s, slen, buf, sizeof(buf));
286  SetConsoleMode(h, mode);
287  return strlen((char *)s);
288 }
289 
290 #endif
291 
293  line->cb_history_up = up;
294  line->cb_history_down = down;
295  line->offset_hist_index = 0;
296  line->file_hist_index = 0;
297  line->sdbshell_hist_iter = rz_list_head(line->sdbshell_hist);
298  return 1;
299 }
300 
301 static inline bool match_hist_line(char *hist_line, char *cur_line) {
302  // Starts with but not equal to
303  return rz_str_startswith(hist_line, cur_line) && strcmp(hist_line, cur_line);
304 }
305 
306 static void setup_hist_match(RzLine *line) {
307  if (line->history.do_setup_match) {
308  RZ_FREE(line->history.match);
309  if (*line->buffer.data) {
310  line->history.match = strdup(line->buffer.data);
311  }
312  }
313  line->history.do_setup_match = false;
314 }
315 
317  if (line->hist_up) {
318  return line->hist_up(line->user);
319  }
320  if (!line->history.data) {
321  inithist();
322  }
323  if (line->history.index > 0 && line->history.data) {
325  if (line->history.match) {
326  int i;
327  for (i = line->history.index - 1; i >= 0; i--) {
328  if (match_hist_line(line->history.data[i], line->history.match)) {
329  line->history.index = i;
330  break;
331  }
332  }
333  if (i < 0) {
334  return false;
335  }
336  } else {
337  line->history.index--;
338  }
339  strncpy(line->buffer.data, line->history.data[line->history.index], RZ_LINE_BUFSIZE - 1);
340  line->buffer.index = line->buffer.length = strlen(line->buffer.data);
341  return true;
342  }
343  return false;
344 }
345 
347  if (line->hist_down) {
348  return line->hist_down(line->user);
349  }
350  if (!line->history.data) {
351  inithist();
352  }
354  if (line->history.match) {
355  int i;
356  for (i = line->history.index + 1; i < line->history.top; i++) {
357  if (match_hist_line(line->history.data[i], line->history.match)) {
358  break;
359  }
360  }
361  line->history.index = i;
362  } else {
363  line->history.index++;
364  }
365  if (line->history.index >= line->history.top) {
366  line->history.index = line->history.top;
367  if (line->history.match) {
368  strncpy(line->buffer.data, line->history.match, RZ_LINE_BUFSIZE - 1);
369  } else {
370  line->buffer.data[0] = '\0';
371  }
372  line->buffer.index = line->buffer.length = strlen(line->buffer.data);
373  return false;
374  }
375  if (line->history.data && line->history.data[line->history.index]) {
376  strncpy(line->buffer.data, line->history.data[line->history.index], RZ_LINE_BUFSIZE - 1);
377  line->buffer.index = line->buffer.length = strlen(line->buffer.data);
378  }
379  return true;
380 }
381 
382 RZ_API int rz_line_hist_add(const char *line) {
383  if (!line || !*line) {
384  return false;
385  }
386  if (!I.history.data) {
387  inithist();
388  }
389  /* ignore dup */
390  if (I.history.top > 0) {
391  const char *data = I.history.data[I.history.top - 1];
392  if (data && !strcmp(line, data)) {
393  I.history.index = I.history.top;
394  return false;
395  }
396  }
397  if (I.history.top == I.history.size) {
398  int i;
399  free(I.history.data[0]);
400  for (i = 0; i <= I.history.size - 2; i++) {
401  I.history.data[i] = I.history.data[i + 1];
402  }
403  I.history.top--;
404  }
405  I.history.data[I.history.top++] = strdup(line);
406  I.history.index = I.history.top;
407  return true;
408 }
409 
410 static int rz_line_hist_up(void) {
411  if (!I.cb_history_up) {
413  }
414  return I.cb_history_up(&I);
415 }
416 
417 static int rz_line_hist_down(void) {
418  if (!I.cb_history_down) {
420  }
421  return I.cb_history_down(&I);
422 }
423 
424 RZ_API const char *rz_line_hist_get(int n) {
425  int i = 0;
426  if (!I.history.data) {
427  inithist();
428  }
429  n--;
430  if (I.history.data) {
431  for (i = 0; i < I.history.size && I.history.data[i]; i++) {
432  if (n == i) {
433  return I.history.data[i];
434  }
435  }
436  }
437  return NULL;
438 }
439 
441  int i = 0;
442  if (!I.history.data) {
443  inithist();
444  }
445  if (I.history.data) {
446  for (i = 0; i < I.history.size && I.history.data[i]; i++) {
447  // when you execute a command, you always move the history
448  // by 1 before actually printing it.
449  rz_cons_printf("%5d %s\n", i + 1, I.history.data[i]);
450  }
451  }
452  return i;
453 }
454 
456  int i;
457  if (I.history.data) {
458  for (i = 0; i < I.history.size; i++) {
459  RZ_FREE(I.history.data[i]);
460  }
461  }
462  RZ_FREE(I.history.data);
463  RZ_FREE(I.sdbshell_hist);
464  I.history.index = 0;
465 }
466 
475  rz_return_val_if_fail(path, false);
476 
477  FILE *fd;
478  char buf[RZ_LINE_BUFSIZE];
479  if (!(fd = rz_sys_fopen(path, "r"))) {
480  return false;
481  }
482  while (fgets(buf, sizeof(buf), fd) != NULL) {
485  }
486  fclose(fd);
487  return true;
488 }
489 
498  FILE *fd;
499  int i, ret = false;
500  if (RZ_STR_ISEMPTY(path)) {
501  return false;
502  }
503  char *p = (char *)rz_str_lastbut(path, RZ_SYS_DIR[0], NULL);
504  if (p) {
505  *p = 0;
506  if (!rz_sys_mkdirp(path)) {
507  RZ_LOG_ERROR("Could not save history into %s\n", path);
508  return false;
509  }
510  *p = RZ_SYS_DIR[0];
511  }
512  fd = rz_sys_fopen(path, "w");
513  if (fd != NULL) {
514  if (I.history.data) {
515  for (i = 0; i < I.history.index; i++) {
516  fputs(I.history.data[i], fd);
517  fputs("\n", fd);
518  }
519  fclose(fd);
520  ret = true;
521  } else {
522  fclose(fd);
523  }
524  }
525  return ret;
526 }
527 
528 RZ_API int rz_line_hist_chop(const char *file, int limit) {
529  /* TODO */
530  return 0;
531 }
532 
533 static void selection_widget_draw(void) {
534  RzCons *cons = rz_cons_singleton();
535  RzSelWidget *sel_widget = I.sel_widget;
536  int y, pos_y, pos_x = rz_str_ansi_len(I.prompt);
537  sel_widget->h = RZ_MIN(sel_widget->h, RZ_SELWIDGET_MAXH);
538  for (y = 0; y < sel_widget->options_len; y++) {
539  sel_widget->w = RZ_MAX(sel_widget->w, strlen(sel_widget->options[y]));
540  }
541  if (sel_widget->direction == RZ_SELWIDGET_DIR_UP) {
542  pos_y = cons->rows;
543  } else {
544  pos_y = rz_cons_get_cur_line();
545  if (pos_y + sel_widget->h > cons->rows) {
546  printf("%s\n", rz_str_pad('\n', sel_widget->h));
547  pos_y = cons->rows - sel_widget->h - 1;
548  }
549  }
550  sel_widget->w = RZ_MIN(sel_widget->w, RZ_SELWIDGET_MAXW);
551 
552  char *background_color = cons->context->color_mode ? cons->context->pal.widget_bg : Color_INVERT_RESET;
553  char *selected_color = cons->context->color_mode ? cons->context->pal.widget_sel : Color_INVERT;
554  bool scrollbar = sel_widget->options_len > RZ_SELWIDGET_MAXH;
555  int scrollbar_y = 0, scrollbar_l = 0;
556  if (scrollbar) {
557  scrollbar_y = (RZ_SELWIDGET_MAXH * (sel_widget->selection - sel_widget->scroll)) / sel_widget->options_len;
558  scrollbar_l = (RZ_SELWIDGET_MAXH * RZ_SELWIDGET_MAXH) / sel_widget->options_len;
559  }
560 
561  for (y = 0; y < sel_widget->h; y++) {
562  if (sel_widget->direction == RZ_SELWIDGET_DIR_UP) {
563  rz_cons_gotoxy(pos_x + 1, pos_y - y - 1);
564  } else {
565  rz_cons_gotoxy(pos_x + 1, pos_y + y + 1);
566  }
567  int scroll = RZ_MAX(0, sel_widget->selection - sel_widget->scroll);
568  const char *option = y < sel_widget->options_len ? sel_widget->options[y + scroll] : "";
569  rz_cons_printf("%s", sel_widget->selection == y + scroll ? selected_color : background_color);
570  rz_cons_printf("%-*.*s", sel_widget->w, sel_widget->w, option);
571  if (scrollbar && RZ_BETWEEN(scrollbar_y, y, scrollbar_y + scrollbar_l)) {
573  } else {
574  rz_cons_memcat(" ", 1);
575  }
576  }
577 
578  rz_cons_gotoxy(pos_x + I.buffer.length, pos_y);
580  rz_cons_flush();
581 }
582 
583 static void selection_widget_up(int steps) {
584  RzSelWidget *sel_widget = I.sel_widget;
585  if (sel_widget) {
586  if (sel_widget->direction == RZ_SELWIDGET_DIR_UP) {
587  int height = RZ_MIN(sel_widget->h, RZ_SELWIDGET_MAXH - 1);
588  sel_widget->selection = RZ_MIN(sel_widget->selection + steps, sel_widget->options_len - 1);
589  if (steps == 1) {
590  sel_widget->scroll = RZ_MIN(sel_widget->scroll + 1, RZ_SELWIDGET_MAXH - 1);
591  } else if (sel_widget->selection + (height - sel_widget->scroll) > sel_widget->options_len - 1) {
592  sel_widget->scroll = height - (sel_widget->options_len - 1 - sel_widget->selection);
593  }
594  } else {
595  sel_widget->selection = RZ_MAX(sel_widget->selection - steps, 0);
596  if (steps == 1) {
597  sel_widget->scroll = RZ_MAX(sel_widget->scroll - 1, 0);
598  } else if (sel_widget->selection - sel_widget->scroll <= 0) {
599  sel_widget->scroll = sel_widget->selection;
600  }
601  }
602  }
603 }
604 
605 static void selection_widget_down(int steps) {
606  RzSelWidget *sel_widget = I.sel_widget;
607  if (sel_widget) {
608  if (sel_widget->direction == RZ_SELWIDGET_DIR_UP) {
609  sel_widget->selection = RZ_MAX(sel_widget->selection - steps, 0);
610  if (steps == 1) {
611  sel_widget->scroll = RZ_MAX(sel_widget->scroll - 1, 0);
612  } else if (sel_widget->selection - sel_widget->scroll <= 0) {
613  sel_widget->scroll = sel_widget->selection;
614  }
615  } else {
616  int height = RZ_MIN(sel_widget->h, RZ_SELWIDGET_MAXH - 1);
617  sel_widget->selection = RZ_MIN(sel_widget->selection + steps, sel_widget->options_len - 1);
618  if (steps == 1) {
619  sel_widget->scroll = RZ_MIN(sel_widget->scroll + 1, RZ_SELWIDGET_MAXH - 1);
620  } else if (sel_widget->selection + (height - sel_widget->scroll) > sel_widget->options_len - 1) {
621  sel_widget->scroll = height - (sel_widget->options_len - 1 - sel_widget->selection);
622  }
623  }
624  }
625 }
626 
627 static void print_rline_task(void *_core) {
629  rz_cons_printf("%s%s%s", Color_RESET, I.prompt, I.buffer.data);
630  rz_cons_flush();
631 }
632 
633 static void selection_widget_erase(void) {
634  RzSelWidget *sel_widget = I.sel_widget;
635  if (sel_widget) {
636  sel_widget->options_len = 0;
637  sel_widget->selection = -1;
639  RZ_FREE(I.sel_widget);
640  RzCons *cons = rz_cons_singleton();
641  if (cons->event_resize && cons->event_data) {
642  cons->event_resize(cons->event_data);
643  RzCore *core = (RzCore *)(cons->user);
644  if (core) {
645  cons->cb_task_oneshot(&core->tasks, print_rline_task, core);
646  }
647  }
649  }
650 }
651 
652 static void selection_widget_select(void) {
653  RzSelWidget *sel_widget = I.sel_widget;
654  if (sel_widget && sel_widget->selection < sel_widget->options_len) {
655  char *sp = strchr(I.buffer.data, ' ');
656  if (sp) {
657  int delta = sp - I.buffer.data + 1;
658  I.buffer.length = RZ_MIN(delta + strlen(sel_widget->options[sel_widget->selection]), RZ_LINE_BUFSIZE - 1);
659  memcpy(I.buffer.data + delta, sel_widget->options[sel_widget->selection], strlen(sel_widget->options[sel_widget->selection]));
660  I.buffer.index = I.buffer.length;
661  return;
662  }
663  I.buffer.length = RZ_MIN(strlen(sel_widget->options[sel_widget->selection]), RZ_LINE_BUFSIZE - 1);
664  memcpy(I.buffer.data, sel_widget->options[sel_widget->selection], I.buffer.length);
665  I.buffer.data[I.buffer.length] = '\0';
666  I.buffer.index = I.buffer.length;
668  }
669 }
670 
671 static void selection_widget_update(void) {
672  int argc = rz_pvector_len(&I.completion.args);
673  const char **argv = (const char **)rz_pvector_data(&I.completion.args);
674  if (argc == 0 || (argc == 1 && I.buffer.length >= strlen(argv[0]))) {
676  return;
677  }
678  if (!I.sel_widget) {
679  RzSelWidget *sel_widget = RZ_NEW0(RzSelWidget);
680  I.sel_widget = sel_widget;
681  }
682  I.sel_widget->scroll = 0;
683  I.sel_widget->selection = 0;
684  I.sel_widget->options_len = argc;
685  I.sel_widget->options = argv;
686  I.sel_widget->h = RZ_MAX(I.sel_widget->h, I.sel_widget->options_len);
687 
688  if (I.prompt_type == RZ_LINE_PROMPT_DEFAULT) {
689  I.sel_widget->direction = RZ_SELWIDGET_DIR_DOWN;
690  } else {
691  I.sel_widget->direction = RZ_SELWIDGET_DIR_UP;
692  }
694  rz_cons_flush();
695  return;
696 }
697 
698 static bool is_valid_buffer_limits(RzLineBuffer *buf, size_t start, size_t end, size_t s_len) {
699  if (start > end || s_len < end - start) {
700  return false;
701  }
702  if (start > buf->length || start + s_len >= RZ_LINE_BUFSIZE - 1) {
703  return false;
704  }
705  if (end > buf->length || end + s_len >= RZ_LINE_BUFSIZE - 1) {
706  return false;
707  }
708  return true;
709 }
710 
711 static void replace_buffer_text(RzLineBuffer *buf, size_t start, size_t end, const char *s) {
712  size_t s_len = strlen(s);
713  if (!is_valid_buffer_limits(buf, start, end, s_len)) {
714  return;
715  }
716 
717  size_t diff = end - start;
718  // FIXME: escape s
719  memmove(buf->data + start + s_len, buf->data + end, buf->length - end);
720  memmove(buf->data + start, s, s_len);
721  buf->length += s_len - diff;
722  buf->index += s_len - diff;
723  buf->data[buf->length] = '\0';
724 }
725 
727  const char *ref = rz_pvector_at(options, 0);
728  size_t min_common_len = strlen(ref);
729  void **it;
730  bool first = true;
732  if (first) {
733  first = false;
734  continue;
735  }
736  char *s = *(char **)it;
737  size_t j;
738  for (j = 0; s[j] && ref[j] && s[j] == ref[j]; j++)
739  ;
740  if (j < min_common_len) {
741  min_common_len = j;
742  }
743  }
744  return rz_str_ndup(ref, min_common_len);
745 }
746 
747 static void print_options(int argc, const char **argv) {
748  int cols = (int)(rz_cons_get_size(NULL) * 0.82);
749  size_t i, len;
750  const int sep = 3;
751  int slen, col = 10;
752 
753  for (i = 0; i < argc && argv[i]; i++) {
754  int l = strlen(argv[i]);
755  if (sep + l > col) {
756  col = sep + l;
757  }
758  if (col > (cols >> 1)) {
759  col = (cols >> 1);
760  break;
761  }
762  }
763  for (len = i = 0; i < argc && argv[i]; i++) {
764  if (len + col > cols) {
765  rz_cons_printf("\n");
766  len = 0;
767  }
768  rz_cons_printf("%-*s ", col - sep, argv[i]);
769  slen = strlen(argv[i]);
770  len += (slen > col) ? (slen + sep) : (col + sep);
771  }
772  rz_cons_printf("\n");
773 }
774 
776  char *p;
777  const char **argv = NULL;
778  int argc = 0, i, j, plen;
779  bool opt = false;
780  RzCons *cons = rz_cons_singleton();
781 
782  if (I.ns_completion.run) {
783  RzLineNSCompletionResult *res = I.ns_completion.run(&I.buffer, I.prompt_type, I.ns_completion.run_user);
784  if (!res || rz_pvector_empty(&res->options)) {
785  // do nothing
786  } else if (rz_pvector_len(&res->options) == 1) {
787  // if there is just one option, just use it
788  bool is_at_end = I.buffer.length == I.buffer.index;
789  replace_buffer_text(&I.buffer, res->start, res->end, rz_pvector_at(&res->options, 0));
790  if (is_at_end && res->end_string) {
791  replace_buffer_text(&I.buffer, I.buffer.length, I.buffer.length, res->end_string);
792  }
793  } else {
794  // otherwise find maxcommonprefix, print it, and then print options
795  char *max_common_pfx = get_max_common_pfx(&res->options);
796  replace_buffer_text(&I.buffer, res->start, res->end, max_common_pfx);
797  free(max_common_pfx);
798 
799  rz_cons_printf("%s%s\n", I.prompt, I.buffer.data);
800  print_options(rz_pvector_len(&res->options), (const char **)rz_pvector_data(&res->options));
801  }
802 
804  return;
805  }
806 
807  /* prepare argc and argv */
808  if (I.completion.run) {
809  I.completion.opt = false;
810  I.completion.run(&I.completion, &I.buffer, I.prompt_type, I.completion.run_user);
811  argc = rz_pvector_len(&I.completion.args);
812  argv = (const char **)rz_pvector_data(&I.completion.args);
813  opt = I.completion.opt;
814  }
815  if (I.sel_widget && !I.sel_widget->complete_common) {
817  return;
818  }
819 
820  if (opt) {
821  p = (char *)rz_sub_str_lchr(I.buffer.data, 0, I.buffer.index, '=');
822  } else {
823  p = (char *)rz_sub_str_lchr(I.buffer.data, 0, I.buffer.index, ' ');
824  }
825  if (!p) {
826  p = (char *)rz_sub_str_lchr(I.buffer.data, 0, I.buffer.index, '@'); // HACK FOR r2
827  }
828  if (p) {
829  p++;
830  plen = sizeof(I.buffer.data) - (int)(size_t)(p - I.buffer.data);
831  } else {
832  p = I.buffer.data; // XXX: removes current buffer
833  plen = sizeof(I.buffer.data);
834  }
835  /* autocomplete */
836  if (argc == 1) {
837  const char *end_word = rz_sub_str_rchr(I.buffer.data,
838  I.buffer.index, strlen(I.buffer.data), ' ');
839  const char *t = end_word != NULL ? end_word : I.buffer.data + I.buffer.index;
840  int largv0 = strlen(argv[0] ? argv[0] : "");
841  size_t len_t = strlen(t);
842  p[largv0] = '\0';
843 
844  if ((p - I.buffer.data) + largv0 + 1 + len_t < plen) {
845  if (len_t > 0) {
846  int tt = largv0;
847  if (*t != ' ') {
848  p[tt++] = ' ';
849  }
850  memmove(p + tt, t, len_t);
851  }
852  memcpy(p, argv[0], largv0);
853 
854  if (p[largv0 - 1] != RZ_SYS_DIR[0]) {
855  p[largv0] = ' ';
856  if (!len_t) {
857  p[largv0 + 1] = '\0';
858  }
859  }
860  I.buffer.length = strlen(I.buffer.data);
861  I.buffer.index = I.buffer.length;
862  }
863  } else if (argc > 0) {
864  if (*p) {
865  // TODO: avoid overflow
866  const char *t = I.buffer.data + I.buffer.index;
867  const char *root = argv[0];
868  int min_common_len = strlen(root);
869  size_t len_t = strlen(t);
870 
871  // try to autocomplete argument
872  for (i = 0; i < argc; i++) {
873  j = 0;
874  if (!argv[i]) {
875  break;
876  }
877  while (argv[i][j] == root[j] && root[j] != '\0')
878  j++;
879  if (j < min_common_len) {
880  min_common_len = j;
881  }
882  root = argv[i];
883  }
884  if (len_t > 0) {
885  int tt = min_common_len;
886  memmove(p + tt, t, len_t);
887  p[tt + len_t] = '\0';
888  }
889  memmove(p, root, min_common_len);
890  if (!len_t) {
891  p[min_common_len] = '\0';
892  }
893  I.buffer.length = strlen(I.buffer.data);
894  I.buffer.index = (p - I.buffer.data) + min_common_len;
895  }
896  }
897 
898  if (I.prompt_type != RZ_LINE_PROMPT_DEFAULT || cons->show_autocomplete_widget) {
900  if (I.sel_widget) {
901  I.sel_widget->complete_common = false;
902  }
903  return;
904  }
905 
906  /* show options */
907  if (argc > 1 && I.echo) {
908  rz_cons_printf("%s%s\n", I.prompt, I.buffer.data);
909  print_options(argc, argv);
910  }
911 }
912 
913 RZ_API const char *rz_line_readline(void) {
914  return rz_line_readline_cb(NULL, NULL);
915 }
916 
917 static inline void rotate_kill_ring(bool *enable_yank_pop) {
918  if (!*enable_yank_pop) {
919  return;
920  }
921  I.buffer.index -= strlen(rz_list_get_n(I.kill_ring, I.kill_ring_ptr));
922  I.buffer.data[I.buffer.index] = 0;
923  I.kill_ring_ptr -= 1;
924  if (I.kill_ring_ptr < 0) {
925  I.kill_ring_ptr = I.kill_ring->length - 1;
926  }
927  I.clipboard = rz_list_get_n(I.kill_ring, I.kill_ring_ptr);
928  paste(enable_yank_pop);
929 }
930 
931 static inline void __delete_next_char(void) {
932  if (I.buffer.index < I.buffer.length) {
933  int len = rz_str_utf8_charsize(I.buffer.data + I.buffer.index);
934  memmove(I.buffer.data + I.buffer.index,
935  I.buffer.data + I.buffer.index + len,
936  strlen(I.buffer.data + I.buffer.index + 1) + 1);
937  I.buffer.length -= len;
938  }
939 }
940 
941 static inline void __delete_prev_char(void) {
942  if (I.buffer.index < I.buffer.length) {
943  if (I.buffer.index > 0) {
944  size_t len = rz_str_utf8_charsize_prev(I.buffer.data + I.buffer.index, I.buffer.index);
945  I.buffer.index -= len;
946  memmove(I.buffer.data + I.buffer.index,
947  I.buffer.data + I.buffer.index + len,
948  strlen(I.buffer.data + I.buffer.index));
949  I.buffer.length -= len;
950  }
951  } else {
952  I.buffer.length -= rz_str_utf8_charsize_last(I.buffer.data);
953  I.buffer.index = I.buffer.length;
954  if (I.buffer.length < 0) {
955  I.buffer.length = 0;
956  }
957  }
958  I.buffer.data[I.buffer.length] = '\0';
959  if (I.buffer.index < 0) {
960  I.buffer.index = 0;
961  }
962 }
963 
964 static inline void delete_till_end(void) {
965  I.buffer.data[I.buffer.index] = '\0';
966  I.buffer.length = I.buffer.index;
967  I.buffer.index = I.buffer.index > 0 ? I.buffer.index - 1 : 0;
968 }
969 
970 static void __print_prompt(void) {
971  RzCons *cons = rz_cons_singleton();
972  int columns = rz_cons_get_size(NULL) - 2;
973  int chars = strlen(I.buffer.data);
974  int len, i, cols = RZ_MAX(1, columns - rz_str_ansi_len(I.prompt) - 2);
975  if (cons->line->prompt_type == RZ_LINE_PROMPT_OFFSET) {
976  rz_cons_gotoxy(0, cons->rows);
977  rz_cons_flush();
978  }
980  if (cons->context->color_mode > 0) {
981  printf("\r%s%s", Color_RESET, I.prompt);
982  } else {
983  printf("\r%s", I.prompt);
984  }
985  fwrite(I.buffer.data, 1, RZ_MIN(cols, chars), stdout);
986  printf("\r%s", I.prompt);
987  if (I.buffer.index > cols) {
988  printf("< ");
989  i = I.buffer.index - cols;
990  if (i > sizeof(I.buffer.data)) {
991  i = sizeof(I.buffer.data) - 1;
992  }
993  } else {
994  i = 0;
995  }
996  len = I.buffer.index - i;
997  if (len > 0 && (i + len) <= I.buffer.length) {
998  fwrite(I.buffer.data + i, 1, len, stdout);
999  }
1000  fflush(stdout);
1001 }
1002 
1003 static inline void __move_cursor_right(void) {
1004  I.buffer.index = I.buffer.index < I.buffer.length
1005  ? I.buffer.index + rz_str_utf8_charsize(I.buffer.data + I.buffer.index)
1006  : I.buffer.length;
1007 }
1008 
1009 static inline void __move_cursor_left(void) {
1010  I.buffer.index = I.buffer.index
1011  ? I.buffer.index - rz_str_utf8_charsize_prev(I.buffer.data + I.buffer.index, I.buffer.index)
1012  : 0;
1013 }
1014 
1015 static inline void vi_cmd_b(void) {
1016  int i;
1017  for (i = I.buffer.index - 2; i >= 0; i--) {
1018  if ((is_word_break_char(I.buffer.data[i], MINOR_BREAK) && !is_word_break_char(I.buffer.data[i], MAJOR_BREAK)) || (is_word_break_char(I.buffer.data[i - 1], MINOR_BREAK) && !is_word_break_char(I.buffer.data[i], MINOR_BREAK))) {
1019  I.buffer.index = i;
1020  break;
1021  }
1022  }
1023  if (i < 0) {
1024  I.buffer.index = 0;
1025  }
1026 }
1027 
1028 static inline void vi_cmd_B(void) {
1029  int i;
1030  for (i = I.buffer.index - 2; i >= 0; i--) {
1031  if ((!is_word_break_char(I.buffer.data[i], MAJOR_BREAK) && is_word_break_char(I.buffer.data[i - 1], MAJOR_BREAK))) {
1032  I.buffer.index = i;
1033  break;
1034  }
1035  }
1036  if (i < 0) {
1037  I.buffer.index = 0;
1038  }
1039 }
1040 
1041 static inline void vi_cmd_W(void) {
1042  int i;
1043  for (i = I.buffer.index + 1; i < I.buffer.length; i++) {
1044  if ((!is_word_break_char(I.buffer.data[i], MAJOR_BREAK) && is_word_break_char(I.buffer.data[i - 1], MAJOR_BREAK))) {
1045  I.buffer.index = i;
1046  break;
1047  }
1048  }
1049  if (i >= I.buffer.length) {
1050  I.buffer.index = I.buffer.length - 1;
1051  }
1052 }
1053 
1054 static inline void vi_cmd_w(void) {
1055  int i;
1056  for (i = I.buffer.index + 1; i < I.buffer.length; i++) {
1057  if ((!is_word_break_char(I.buffer.data[i], MINOR_BREAK) && is_word_break_char(I.buffer.data[i - 1], MINOR_BREAK)) || (is_word_break_char(I.buffer.data[i], MINOR_BREAK) && !is_word_break_char(I.buffer.data[i], MAJOR_BREAK))) {
1058  I.buffer.index = i;
1059  break;
1060  }
1061  }
1062  if (i >= I.buffer.length) {
1063  I.buffer.index = I.buffer.length - 1;
1064  }
1065 }
1066 
1067 static inline void vi_cmd_E(void) {
1068  int i;
1069  for (i = I.buffer.index + 1; i < I.buffer.length; i++) {
1070  if ((!is_word_break_char(I.buffer.data[i], MAJOR_BREAK) && is_word_break_char(I.buffer.data[i + 1], MAJOR_BREAK))) {
1071  I.buffer.index = i;
1072  break;
1073  }
1074  }
1075  if (i >= I.buffer.length) {
1076  I.buffer.index = I.buffer.length - 1;
1077  }
1078 }
1079 
1080 static inline void vi_cmd_e(void) {
1081  int i;
1082  for (i = I.buffer.index + 1; i < I.buffer.length; i++) {
1083  if ((!is_word_break_char(I.buffer.data[i], MINOR_BREAK) && is_word_break_char(I.buffer.data[i + 1], MINOR_BREAK)) || (is_word_break_char(I.buffer.data[i], MINOR_BREAK) && !is_word_break_char(I.buffer.data[i], MAJOR_BREAK))) {
1084  I.buffer.index = i;
1085  break;
1086  }
1087  }
1088  if (i >= I.buffer.length) {
1089  I.buffer.index = I.buffer.length - 1;
1090  }
1091 }
1092 
1093 static void __update_prompt_color(void) {
1094  RzCons *cons = rz_cons_singleton();
1095  const char *BEGIN = "", *END = "";
1096  if (cons->context->color_mode) {
1097  if (I.prompt_mode) {
1098  switch (I.vi_mode) {
1099  case CONTROL_MODE:
1100  BEGIN = cons->context->pal.invalid;
1101  break;
1102  case INSERT_MODE:
1103  default:
1104  BEGIN = cons->context->pal.prompt;
1105  break;
1106  }
1107  } else {
1108  BEGIN = cons->context->pal.prompt;
1109  }
1110  END = cons->context->pal.reset;
1111  }
1112  char *prompt = rz_str_escape(I.prompt); // remote the color
1113  free(I.prompt);
1114  I.prompt = rz_str_newf("%s%s%s", BEGIN, prompt, END);
1115  free(prompt);
1116 }
1117 
1118 static void __vi_mode(bool *enable_yank_pop) {
1119  char ch;
1120  I.vi_mode = CONTROL_MODE;
1122  const char *gcomp_line = "";
1123  static int gcomp = 0;
1124  for (;;) {
1125  int rep = 0;
1126  if (I.echo) {
1127  __print_prompt();
1128  }
1129  if (I.vi_mode != CONTROL_MODE) { // exit if insert mode is selected
1131  break;
1132  }
1133  bool o_do_setup_match = I.history.do_setup_match;
1134  I.history.do_setup_match = true;
1135  ch = rz_cons_readchar();
1136  while (IS_DIGIT(ch)) { // handle commands like 3b
1137  if (ch == '0' && rep == 0) { // to handle the command 0
1138  break;
1139  }
1140  int tmp = ch - '0';
1141  rep = (rep * 10) + tmp;
1142  ch = rz_cons_readchar();
1143  }
1144  rep = rep > 0 ? rep : 1;
1145 
1146  switch (ch) {
1147  case 3:
1148  if (I.hud) {
1149  I.hud->activate = false;
1150  I.hud->current_entry_n = -1;
1151  }
1152  if (I.echo) {
1153  eprintf("^C\n");
1154  }
1155  I.buffer.index = I.buffer.length = 0;
1156  *I.buffer.data = '\0';
1157  gcomp = 0;
1158  return;
1159  case 'D':
1160  delete_till_end();
1161  break;
1162  case 'r': {
1163  char c = rz_cons_readchar();
1164  I.buffer.data[I.buffer.index] = c;
1165  } break;
1166  case 'x':
1167  while (rep--) {
1169  }
1170  break;
1171  case 'c':
1172  I.vi_mode = INSERT_MODE; // goto insert mode
1173  /* fall through */
1174  case 'd': {
1175  char c = rz_cons_readchar();
1176  while (rep--) {
1177  switch (c) {
1178  case 'i': {
1179  char t = rz_cons_readchar();
1180  if (t == 'w') { // diw
1183  } else if (t == 'W') { // diW
1186  }
1187  if (I.hud) {
1188  I.hud->vi = false;
1189  }
1190  } break;
1191  case 'W':
1193  break;
1194  case 'w':
1196  break;
1197  case 'B':
1199  break;
1200  case 'b':
1202  break;
1203  case 'h':
1205  break;
1206  case 'l':
1208  break;
1209  case '$':
1210  delete_till_end();
1211  break;
1212  case '^':
1213  case '0':
1214  strncpy(I.buffer.data, I.buffer.data + I.buffer.index, I.buffer.length);
1215  I.buffer.length -= I.buffer.index;
1216  I.buffer.index = 0;
1217  break;
1218  }
1219  __print_prompt();
1220  }
1221  } break;
1222  case 'I':
1223  if (I.hud) {
1224  I.hud->vi = false;
1225  }
1226  I.vi_mode = INSERT_MODE;
1227  /* fall through */
1228  case '^':
1229  case '0':
1230  if (gcomp) {
1231  strcpy(I.buffer.data, gcomp_line);
1232  I.buffer.length = strlen(I.buffer.data);
1233  I.buffer.index = 0;
1234  gcomp = false;
1235  }
1236  I.buffer.index = 0;
1237  break;
1238  case 'A':
1239  I.vi_mode = INSERT_MODE;
1240  /* fall through */
1241  case '$':
1242  if (gcomp) {
1243  strcpy(I.buffer.data, gcomp_line);
1244  I.buffer.index = strlen(I.buffer.data);
1245  I.buffer.length = I.buffer.index;
1246  gcomp = false;
1247  } else {
1248  I.buffer.index = I.buffer.length;
1249  }
1250  break;
1251  case 'p':
1252  while (rep--) {
1253  paste(enable_yank_pop);
1254  }
1255  break;
1256  case 'a':
1258  /* fall through */
1259  case 'i':
1260  I.vi_mode = INSERT_MODE;
1261  if (I.hud) {
1262  I.hud->vi = false;
1263  }
1264  break;
1265  case 'h':
1266  while (rep--) {
1268  }
1269  break;
1270  case 'l':
1271  while (rep--) {
1273  }
1274  break;
1275  case 'E':
1276  while (rep--) {
1277  vi_cmd_E();
1278  }
1279  break;
1280  case 'e':
1281  while (rep--) {
1282  vi_cmd_e();
1283  }
1284  break;
1285  case 'B':
1286  while (rep--) {
1287  vi_cmd_B();
1288  }
1289  break;
1290  case 'b':
1291  while (rep--) {
1292  vi_cmd_b();
1293  }
1294  break;
1295  case 'W':
1296  while (rep--) {
1297  vi_cmd_W();
1298  }
1299  break;
1300  case 'w':
1301  while (rep--) {
1302  vi_cmd_w();
1303  }
1304  break;
1305  default: // escape key
1306  ch = tolower(rz_cons_arrow_to_hjkl(ch));
1307  switch (ch) {
1308  case 'k': // up
1309  I.history.do_setup_match = o_do_setup_match;
1310  rz_line_hist_up();
1311  break;
1312  case 'j': // down
1313  I.history.do_setup_match = o_do_setup_match;
1315  break;
1316  case 'l': // right
1318  break;
1319  case 'h': // left
1321  break;
1322  }
1323  break;
1324  }
1325  if (I.hud) {
1326  return;
1327  }
1328  }
1329 }
1330 
1331 RZ_API const char *rz_line_readline_cb(RzLineReadCallback cb, void *user) {
1332  int rows;
1333  const char *gcomp_line = "";
1334  static int gcomp_idx = 0;
1335  static bool yank_flag = 0;
1336  static int gcomp = 0;
1337  static int gcomp_is_rev = true;
1338  char buf[10];
1339 #if USE_UTF8
1340  int utflen;
1341 #endif
1342  int ch = 0, key, i = 0; /* grep completion */
1343  char *tmp_ed_cmd, prev = 0;
1344  int prev_buflen = -1;
1345  bool enable_yank_pop = false;
1346 
1347  RzCons *cons = rz_cons_singleton();
1348 
1349  if (!I.hud || (I.hud && !I.hud->activate)) {
1350  I.buffer.index = I.buffer.length = 0;
1351  I.buffer.data[0] = '\0';
1352  if (I.hud) {
1353  I.hud->activate = true;
1354  }
1355  }
1356  int mouse_status = cons->mouse;
1357  if (I.hud && I.hud->vi) {
1358  __vi_mode(&enable_yank_pop);
1359  goto _end;
1360  }
1361  if (I.contents) {
1362  memmove(I.buffer.data, I.contents,
1363  RZ_MIN(strlen(I.contents) + 1, RZ_LINE_BUFSIZE - 1));
1364  I.buffer.data[RZ_LINE_BUFSIZE - 1] = '\0';
1365  I.buffer.index = I.buffer.length = strlen(I.contents);
1366  }
1367  if (I.disable) {
1368  if (!fgets(I.buffer.data, RZ_LINE_BUFSIZE, stdin)) {
1369  return NULL;
1370  }
1371  return (*I.buffer.data) ? I.buffer.data : rz_line_nullstr;
1372  }
1373 
1374  memset(&buf, 0, sizeof buf);
1375  rz_cons_set_raw(1);
1376 
1377  if (I.echo) {
1378  __print_prompt();
1379  }
1381  rz_cons_enable_mouse(I.hud);
1382  for (;;) {
1383  yank_flag = 0;
1384  if (rz_cons_is_breaked()) {
1385  break;
1386  }
1387  I.buffer.data[I.buffer.length] = '\0';
1388  if (cb) {
1389  int cbret = cb(user, I.buffer.data);
1390  if (cbret == 0) {
1391  I.buffer.data[0] = 0;
1392  I.buffer.length = 0;
1393  }
1394  }
1395 #if USE_UTF8
1396  utflen = rz_line_readchar_utf8((ut8 *)buf, sizeof(buf));
1397  if (utflen < 1) {
1399  return NULL;
1400  }
1401  buf[utflen] = 0;
1402 #else
1403 #if __WINDOWS__
1404  {
1405  int len = rz_line_readchar_win((ut8 *)buf, sizeof(buf));
1406  if (len < 1) {
1408  return NULL;
1409  }
1410  buf[len] = 0;
1411  }
1412 #else
1413  ch = rz_cons_readchar();
1414  if (ch == -1) {
1416  return NULL;
1417  }
1418  buf[0] = ch;
1419 #endif
1420 #endif
1421  bool o_do_setup_match = I.history.do_setup_match;
1422  I.history.do_setup_match = true;
1423  if (I.echo) {
1424  rz_cons_clear_line(0);
1425  }
1426  (void)rz_cons_get_size(&rows);
1427  switch (*buf) {
1428  case 0: // control-space
1429  /* ignore atm */
1430  break;
1431  case 1: // ^A
1432  if (gcomp) {
1433  strcpy(I.buffer.data, gcomp_line);
1434  I.buffer.length = strlen(I.buffer.data);
1435  I.buffer.index = 0;
1436  gcomp = false;
1437  }
1438  I.buffer.index = 0;
1439  break;
1440  case 2: // ^b // emacs left
1442  break;
1443  case 5: // ^E
1444  if (gcomp) {
1445  strcpy(I.buffer.data, gcomp_line);
1446  I.buffer.index = strlen(I.buffer.data);
1447  I.buffer.length = I.buffer.index;
1448  gcomp = false;
1449  } else if (prev == 24) { // ^X = 0x18
1450  I.buffer.data[I.buffer.length] = 0; // probably unnecessary
1451  tmp_ed_cmd = I.cb_editor(I.user, I.buffer.data);
1452  if (tmp_ed_cmd) {
1453  /* copied from yank (case 25) */
1454  I.buffer.length = strlen(tmp_ed_cmd);
1455  if (I.buffer.length < RZ_LINE_BUFSIZE) {
1456  I.buffer.index = I.buffer.length;
1457  strncpy(I.buffer.data, tmp_ed_cmd, RZ_LINE_BUFSIZE - 1);
1458  I.buffer.data[RZ_LINE_BUFSIZE - 1] = '\0';
1459  } else {
1460  I.buffer.length -= strlen(tmp_ed_cmd);
1461  }
1462  free(tmp_ed_cmd);
1463  }
1464  } else {
1465  I.buffer.index = I.buffer.length;
1466  }
1467  break;
1468  case 3: // ^C
1469  if (I.hud) {
1470  I.hud->activate = false;
1471  I.hud->current_entry_n = -1;
1472  }
1473  if (I.echo) {
1474  eprintf("^C\n");
1475  }
1476  I.buffer.index = I.buffer.length = 0;
1477  *I.buffer.data = '\0';
1478  gcomp = 0;
1479  goto _end;
1480  case 4: // ^D
1481  if (!I.buffer.data[0]) { /* eof */
1482  if (I.echo) {
1483  __print_prompt();
1484  printf("\n");
1485  }
1486  rz_cons_set_raw(false);
1488  return NULL;
1489  }
1490  if (I.buffer.index < I.buffer.length) {
1492  }
1493  break;
1494  case 11: // ^K
1495  I.buffer.data[I.buffer.index] = '\0';
1496  I.buffer.length = I.buffer.index;
1497  break;
1498  case 6: // ^f // emacs right
1500  break;
1501  case 12: // ^L -- right
1503  if (I.echo) {
1504  eprintf("\x1b[2J\x1b[0;0H");
1505  }
1506  fflush(stdout);
1507  break;
1508  case 18: // ^R -- reverse-search
1509  if (gcomp) {
1510  gcomp_idx++;
1511  }
1512  gcomp_is_rev = true;
1513  gcomp = 1;
1514  break;
1515  case 19: // ^S -- forward-search
1516  if (gcomp) {
1517  if (gcomp_idx > 0) {
1518  gcomp_idx--;
1519  }
1520  gcomp_is_rev = false;
1521  } else {
1523  }
1524  break;
1525  case 21: // ^U - cut
1526  free(I.clipboard);
1527  I.clipboard = strdup(I.buffer.data);
1528  rz_line_clipboard_push(I.clipboard);
1529  I.buffer.data[0] = '\0';
1530  I.buffer.length = 0;
1531  I.buffer.index = 0;
1532  break;
1533 #if __WINDOWS__
1534  case 22: // ^V - Paste from windows clipboard
1535  {
1536  HANDLE hClipBoard;
1537  PTCHAR clipText;
1538  if (OpenClipboard(NULL)) {
1539  hClipBoard = GetClipboardData(CF_UNICODETEXT);
1540  if (hClipBoard) {
1541  clipText = GlobalLock(hClipBoard);
1542  if (clipText) {
1543  char *txt = rz_utf16_to_utf8(clipText);
1544  if (!txt) {
1545  RZ_LOG_ERROR("Failed to allocate memory\n");
1546  break;
1547  }
1548  int len = strlen(txt);
1549  I.buffer.length += len;
1550  if (I.buffer.length < RZ_LINE_BUFSIZE) {
1551  I.buffer.index = I.buffer.length;
1552  strcat(I.buffer.data, txt);
1553  } else {
1554  I.buffer.length -= len;
1555  }
1556  free(txt);
1557  }
1558  GlobalUnlock(hClipBoard);
1559  }
1560  CloseClipboard();
1561  }
1562  } break;
1563 #endif
1564  case 23: // ^W ^w unix-word-rubout
1565  unix_word_rubout();
1566  break;
1567  case 24: // ^X
1568  if (I.buffer.index > 0) {
1569  strncpy(I.buffer.data, I.buffer.data + I.buffer.index, I.buffer.length);
1570  I.buffer.length -= I.buffer.index;
1571  I.buffer.index = 0;
1572  }
1573  break;
1574  case 25: // ^Y - paste
1575  paste(&enable_yank_pop);
1576  yank_flag = 1;
1577  break;
1578  case 29: // ^^ - rotate kill ring
1579  rotate_kill_ring(&enable_yank_pop);
1580  yank_flag = enable_yank_pop ? 1 : 0;
1581  break;
1582  case 20: // ^t Kill from point to the end of the current word,
1584  break;
1585  case 15: // ^o kill backward
1587  break;
1588  case 14: // ^n
1589  if (I.hud) {
1590  if (I.hud->top_entry_n + 1 < I.hud->current_entry_n) {
1591  I.hud->top_entry_n++;
1592  }
1593  } else if (I.sel_widget) {
1596  } else if (gcomp) {
1597  if (gcomp_idx > 0) {
1598  gcomp_idx--;
1599  }
1600  } else {
1601  I.history.do_setup_match = o_do_setup_match;
1603  }
1604  break;
1605  case 16: // ^p
1606  if (I.hud) {
1607  if (I.hud->top_entry_n >= 0) {
1608  I.hud->top_entry_n--;
1609  }
1610  } else if (I.sel_widget) {
1613  } else if (gcomp) {
1614  gcomp_idx++;
1615  } else {
1616  I.history.do_setup_match = o_do_setup_match;
1617  rz_line_hist_up();
1618  }
1619  break;
1620  case 27: // esc-5b-41-00-00 alt/meta key
1621 #if __WINDOWS__
1622  if (I.vtmode != RZ_VIRT_TERM_MODE_COMPLETE) {
1623  memmove(buf, buf + 1, strlen(buf));
1624  if (!buf[0]) {
1625  buf[0] = -1;
1626  }
1627  } else {
1628 #endif
1629  buf[0] = rz_cons_readchar_timeout(50);
1630 #if __WINDOWS__
1631  }
1632 #endif
1633  switch (buf[0]) {
1634  case 127: // alt+bkspace
1636  break;
1637  case 27: // escape key, goto vi mode
1638  if (I.enable_vi_mode) {
1639  if (I.hud) {
1640  I.hud->vi = true;
1641  }
1642  __vi_mode(&enable_yank_pop);
1643  };
1644  if (I.sel_widget) {
1646  }
1647  break;
1648  case 1: // begin
1649  I.buffer.index = 0;
1650  break;
1651  case 5: // end
1652  I.buffer.index = I.buffer.length;
1653  break;
1654  case 'B':
1655  case 'b':
1656  for (i = I.buffer.index - 2; i >= 0; i--) {
1657  if (is_word_break_char(I.buffer.data[i], MINOR_BREAK) && !is_word_break_char(I.buffer.data[i + 1], MINOR_BREAK)) {
1658  I.buffer.index = i + 1;
1659  break;
1660  }
1661  }
1662  if (i < 0) {
1663  I.buffer.index = 0;
1664  }
1665  break;
1666  case 'D':
1667  case 'd':
1669  break;
1670  case 'F':
1671  case 'f':
1672  // next word
1673  for (i = I.buffer.index + 1; i < I.buffer.length; i++) {
1674  if (!is_word_break_char(I.buffer.data[i], MINOR_BREAK) && is_word_break_char(I.buffer.data[i - 1], MINOR_BREAK)) {
1675  I.buffer.index = i;
1676  break;
1677  }
1678  }
1679  if (i >= I.buffer.length) {
1680  I.buffer.index = I.buffer.length;
1681  }
1682  break;
1683  default:
1684  if (I.vtmode == RZ_VIRT_TERM_MODE_COMPLETE) {
1685  buf[1] = rz_cons_readchar_timeout(50);
1686  if (buf[1] == -1) { // alt+e
1688  __print_prompt();
1689  continue;
1690  }
1691  }
1692  if (buf[0] == 0x5b) { // [
1693  switch (buf[1]) {
1694  case '3': // supr
1696  if (I.vtmode == RZ_VIRT_TERM_MODE_COMPLETE) {
1697  buf[1] = rz_cons_readchar();
1698  if (buf[1] == -1) {
1700  return NULL;
1701  }
1702  }
1703  break;
1704  case '5': // pag up
1705  if (I.vtmode == RZ_VIRT_TERM_MODE_COMPLETE) {
1706  buf[1] = rz_cons_readchar();
1707  }
1708  if (I.hud) {
1709  I.hud->top_entry_n -= (rows - 1);
1710  if (I.hud->top_entry_n < 0) {
1711  I.hud->top_entry_n = 0;
1712  }
1713  }
1714  if (I.sel_widget) {
1715  selection_widget_up(RZ_MIN(I.sel_widget->h, RZ_SELWIDGET_MAXH));
1717  }
1718  break;
1719  case '6': // pag down
1720  if (I.vtmode == RZ_VIRT_TERM_MODE_COMPLETE) {
1721  buf[1] = rz_cons_readchar();
1722  }
1723  if (I.hud) {
1724  I.hud->top_entry_n += (rows - 1);
1725  if (I.hud->top_entry_n >= I.hud->current_entry_n) {
1726  I.hud->top_entry_n = I.hud->current_entry_n - 1;
1727  }
1728  }
1729  if (I.sel_widget) {
1732  }
1733  break;
1734  case '9': // handle mouse wheel
1735  key = rz_cons_readchar();
1736  cons->mouse_event = 1;
1737  if (key == '6') { // up
1738  if (I.hud && I.hud->top_entry_n + 1 < I.hud->current_entry_n) {
1739  I.hud->top_entry_n--;
1740  }
1741  } else if (key == '7') { // down
1742  if (I.hud && I.hud->top_entry_n >= 0) {
1743  I.hud->top_entry_n++;
1744  }
1745  }
1746  while (rz_cons_readchar() != 'M') {
1747  }
1748  break;
1749  /* arrows */
1750  case 'A': // up arrow
1751  if (I.hud) {
1752  if (I.hud->top_entry_n > 0) {
1753  I.hud->top_entry_n--;
1754  }
1755  } else if (I.sel_widget) {
1758  } else if (gcomp) {
1759  gcomp_idx++;
1760  } else {
1761  I.history.do_setup_match = o_do_setup_match;
1762  if (rz_line_hist_up() == -1) {
1764  return NULL;
1765  }
1766  }
1767  break;
1768  case 'B': // down arrow
1769  if (I.hud) {
1770  if (I.hud->top_entry_n + 1 < I.hud->current_entry_n) {
1771  I.hud->top_entry_n++;
1772  }
1773  } else if (I.sel_widget) {
1776  } else if (gcomp) {
1777  if (gcomp_idx > 0) {
1778  gcomp_idx--;
1779  }
1780  } else {
1781  I.history.do_setup_match = o_do_setup_match;
1782  if (rz_line_hist_down() == -1) {
1784  return NULL;
1785  }
1786  }
1787  break;
1788  case 'C': // right arrow
1790  break;
1791  case 'D': // left arrow
1793  break;
1794  case 0x31: // control + arrow
1795  if (I.vtmode == RZ_VIRT_TERM_MODE_COMPLETE) {
1796  ch = rz_cons_readchar();
1797  if (ch == 0x7e) { // HOME in screen/tmux
1798  // corresponding END is 0x34 below (the 0x7e is ignored there)
1799  I.buffer.index = 0;
1800  break;
1801  }
1802  rz_cons_readchar();
1803  ch = rz_cons_readchar();
1804  }
1805 #if __WINDOWS__
1806  else {
1807  ch = buf[2];
1808  }
1809 #endif
1810  int fkey = ch - '0';
1811  switch (ch) {
1812  case 0x41:
1813  // first
1814  I.buffer.index = 0;
1815  break;
1816  case 0x44:
1817  // previous word
1818  for (i = I.buffer.index; i > 0; i--) {
1819  if (I.buffer.data[i] == ' ') {
1820  I.buffer.index = i - 1;
1821  break;
1822  }
1823  }
1824  if (I.buffer.data[i] != ' ') {
1825  I.buffer.index = 0;
1826  }
1827  break;
1828  case 0x42:
1829  // end
1830  I.buffer.index = I.buffer.length;
1831  break;
1832  case 0x43:
1833  // next word
1834  for (i = I.buffer.index; i < I.buffer.length; i++) {
1835  if (I.buffer.data[i] == ' ') {
1836  I.buffer.index = i + 1;
1837  break;
1838  }
1839  }
1840  if (I.buffer.data[i] != ' ') {
1841  I.buffer.index = I.buffer.length;
1842  }
1843  break;
1844  default:
1845  if (I.vtmode == RZ_VIRT_TERM_MODE_COMPLETE) {
1846  if (I.cb_fkey) {
1847  I.cb_fkey(I.user, fkey);
1848  }
1849  }
1850  break;
1851  }
1852  rz_cons_set_raw(1);
1853  break;
1854  case 0x37: // HOME xrvt-unicode
1855  rz_cons_readchar();
1856  /* fall through */
1857  case 0x48: // HOME
1858  if (I.sel_widget) {
1859  selection_widget_up(I.sel_widget->options_len - 1);
1861  break;
1862  }
1863  I.buffer.index = 0;
1864  break;
1865  case 0x34: // END
1866  case 0x38: // END xrvt-unicode
1867  rz_cons_readchar();
1868  /* fall through */
1869  case 0x46: // END
1870  if (I.sel_widget) {
1871  selection_widget_down(I.sel_widget->options_len - 1);
1873  break;
1874  }
1875  I.buffer.index = I.buffer.length;
1876  break;
1877  }
1878  }
1879  }
1880  break;
1881  case 8:
1882  case 127:
1883  if (I.hud && (I.buffer.index == 0)) {
1884  I.hud->activate = false;
1885  I.hud->current_entry_n = -1;
1886  }
1888  break;
1889  case 9: // TAB tab
1890  if (I.sel_widget) {
1892  I.sel_widget->complete_common = true;
1894  }
1895  if (I.hud) {
1896  if (I.hud->top_entry_n + 1 < I.hud->current_entry_n) {
1897  I.hud->top_entry_n++;
1898  } else {
1899  I.hud->top_entry_n = 0;
1900  }
1901  } else {
1903  rz_cons_flush();
1904  }
1905  break;
1906  case 10: // ^J -- ignore
1907  case 13: // enter
1908  if (I.hud) {
1909  I.hud->activate = false;
1910  break;
1911  }
1912  if (I.sel_widget) {
1914  break;
1915  }
1916  if (gcomp && I.buffer.length > 0) {
1917  strncpy(I.buffer.data, gcomp_line, RZ_LINE_BUFSIZE - 1);
1918  I.buffer.data[RZ_LINE_BUFSIZE - 1] = '\0';
1919  I.buffer.length = strlen(gcomp_line);
1920  }
1921  gcomp_idx = gcomp = 0;
1922  goto _end;
1923  default:
1924  if (gcomp) {
1925  gcomp++;
1926  }
1927  {
1928 #if USE_UTF8
1929  int size = utflen;
1930 #else
1931  int size = 1;
1932 #endif
1933  if (I.buffer.length + size >= RZ_LINE_BUFSIZE) {
1934  break;
1935  }
1936  }
1937  if (I.buffer.index < I.buffer.length) {
1938 #if USE_UTF8
1939  if ((I.buffer.length + utflen) < sizeof(I.buffer.data)) {
1940  I.buffer.length += utflen;
1941  for (i = I.buffer.length; i > I.buffer.index; i--) {
1942  I.buffer.data[i] = I.buffer.data[i - utflen];
1943  }
1944  memcpy(I.buffer.data + I.buffer.index, buf, utflen);
1945  }
1946 #else
1947  for (i = ++I.buffer.length; i > I.buffer.index; i--) {
1948  I.buffer.data[i] = I.buffer.data[i - 1];
1949  }
1950  I.buffer.data[I.buffer.index] = buf[0];
1951 #endif
1952  } else {
1953 #if USE_UTF8
1954  if ((I.buffer.length + utflen) < sizeof(I.buffer.data)) {
1955  memcpy(I.buffer.data + I.buffer.length, buf, utflen);
1956  I.buffer.length += utflen;
1957  }
1958  I.buffer.data[I.buffer.length] = '\0';
1959 #else
1960  I.buffer.data[I.buffer.length] = buf[0];
1961  I.buffer.length++;
1962  if (I.buffer.length > (RZ_LINE_BUFSIZE - 1)) {
1963  I.buffer.length--;
1964  }
1965  I.buffer.data[I.buffer.length] = '\0';
1966 #endif
1967  }
1968 #if USE_UTF8
1969  if ((I.buffer.index + utflen) <= I.buffer.length) {
1970  I.buffer.index += utflen;
1971  }
1972 #else
1973  if (I.buffer.index < I.buffer.length) {
1974  I.buffer.index++;
1975  }
1976 #endif
1977  break;
1978  }
1979  if (I.sel_widget && I.buffer.length != prev_buflen) {
1980  prev_buflen = I.buffer.length;
1982  rz_cons_flush();
1983  }
1984  prev = buf[0];
1985  if (I.echo) {
1986  if (gcomp) {
1987  gcomp_line = "";
1988  int counter = 0;
1989  if (I.history.data != NULL) {
1990  for (i = I.history.size - 1; i >= 0; i--) {
1991  if (!I.history.data[i]) {
1992  continue;
1993  }
1994  if (strstr(I.history.data[i], I.buffer.data)) {
1995  gcomp_line = I.history.data[i];
1996  if (++counter > gcomp_idx) {
1997  break;
1998  }
1999  }
2000  if (i == 0) {
2001  if (gcomp_is_rev) {
2002  gcomp_idx--;
2003  }
2004  }
2005  }
2006  }
2007  const char *prompt = gcomp_is_rev ? "reverse-i-search" : "forward-i-search";
2008  printf("\r (%s (%s)): %s\r", prompt, I.buffer.data, gcomp_line);
2009  } else {
2010  __print_prompt();
2011  }
2012  fflush(stdout);
2013  }
2014  enable_yank_pop = yank_flag ? 1 : 0;
2015  if (I.hud) {
2016  goto _end;
2017  }
2018  }
2019 _end:
2021  rz_cons_set_raw(0);
2022  rz_cons_enable_mouse(mouse_status);
2023  if (I.echo) {
2024  printf("\r%s%s\n", I.prompt, I.buffer.data);
2025  fflush(stdout);
2026  }
2027 
2028  RZ_FREE(I.sel_widget);
2029 
2030  // should be here or not?
2031  if (!memcmp(I.buffer.data, "!history", 8)) {
2032  // if (I.buffer.data[0]=='!' && I.buffer.data[1]=='\0') {
2034  return rz_line_nullstr;
2035  }
2036  return I.buffer.data[0] != '\0' ? I.buffer.data : rz_line_nullstr;
2037 }
size_t len
Definition: 6502dis.c:15
lzma_index ** i
Definition: index.h:629
#define I(x)
Definition: arc.h:164
const lzma_allocator const uint8_t size_t uint8_t * out
Definition: block.h:528
static RzCore * _core
Definition: cmd_debug.c:1622
RZ_API void rz_cons_set_raw(bool is_raw)
Definition: cons.c:1617
RZ_API int rz_cons_get_size(int *rows)
Definition: cons.c:1446
RZ_API int rz_cons_memcat(const char *str, int len)
Definition: cons.c:1224
RZ_API bool rz_cons_enable_mouse(const bool enable)
Definition: cons.c:500
RZ_API RzCons * rz_cons_singleton(void)
Definition: cons.c:300
RZ_API void rz_cons_clear_line(int std_err)
Definition: cons.c:756
RZ_API void * rz_cons_sleep_begin(void)
Definition: cons.c:443
RZ_API void rz_cons_break_pop(void)
Definition: cons.c:361
RZ_API void rz_cons_break_push(RzConsBreak cb, void *user)
Definition: cons.c:357
RZ_API int rz_cons_printf(const char *format,...)
Definition: cons.c:1202
RZ_API int rz_cons_get_cur_line(void)
Definition: cons.c:387
RZ_API void rz_cons_flush(void)
Definition: cons.c:959
RZ_API bool rz_cons_is_breaked(void)
Definition: cons.c:373
RZ_API void rz_cons_sleep_end(void *user)
Definition: cons.c:450
RZ_API void rz_cons_gotoxy(int x, int y)
Definition: cons.c:724
#define RZ_API
#define NULL
Definition: cris-opc.c:27
_Use_decl_annotations_ int __cdecl printf(const char *const _Format,...)
Definition: cs_driver.c:93
static static fork const void static count static fd const char const char static newpath const char static path const char path
Definition: sflib.h:35
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len static semflg const void static shmflg const struct timespec struct timespec static rem const char static group const void start
Definition: sflib.h:133
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len key
Definition: sflib.h:118
RZ_API int rz_line_dietline_init(void)
Definition: dietline.c:147
static void selection_widget_select(void)
Definition: dietline.c:652
RZ_API int rz_line_hist_cmd_down(RzLine *line)
Definition: dietline.c:346
RZ_API const char * rz_line_readline(void)
Definition: dietline.c:913
RZ_API int rz_line_hist_cmd_up(RzLine *line)
Definition: dietline.c:316
static void kill_word(BreakMode mode)
Definition: dietline.c:73
static void __move_cursor_left(void)
Definition: dietline.c:1009
static void selection_widget_down(int steps)
Definition: dietline.c:605
static void backward_kill_word(BreakMode mode)
Definition: dietline.c:44
static void selection_widget_erase(void)
Definition: dietline.c:633
RZ_API int rz_line_hist_list(void)
Definition: dietline.c:440
static char * rz_line_nullstr
Definition: dietline.c:22
static void delete_till_end(void)
Definition: dietline.c:964
static void print_rline_task(void *_core)
Definition: dietline.c:627
static void vi_cmd_w(void)
Definition: dietline.c:1054
static void __delete_next_char(void)
Definition: dietline.c:931
static void __move_cursor_right(void)
Definition: dietline.c:1003
static void selection_widget_update(void)
Definition: dietline.c:671
static bool is_valid_buffer_limits(RzLineBuffer *buf, size_t start, size_t end, size_t s_len)
Definition: dietline.c:698
RZ_API void rz_line_autocomplete(void)
Definition: dietline.c:775
static void print_options(int argc, const char **argv)
Definition: dietline.c:747
static void vi_cmd_E(void)
Definition: dietline.c:1067
static void __update_prompt_color(void)
Definition: dietline.c:1093
RZ_API void rz_line_hist_free(void)
Definition: dietline.c:455
static int rz_line_hist_down(void)
Definition: dietline.c:417
static void paste(bool *enable_yank_pop)
Definition: dietline.c:89
static void unix_word_rubout(void)
Definition: dietline.c:102
RZ_API int rz_line_hist_chop(const char *file, int limit)
Definition: dietline.c:528
static char * get_max_common_pfx(RzPVector *options)
Definition: dietline.c:726
static const char word_break_characters[]
Definition: dietline.c:23
static void __delete_prev_char(void)
Definition: dietline.c:941
static void vi_cmd_B(void)
Definition: dietline.c:1028
static void selection_widget_draw(void)
Definition: dietline.c:533
RZ_API int rz_line_hist_load(RZ_NONNULL const char *path)
Load the history of commands from path.
Definition: dietline.c:474
static void vi_cmd_W(void)
Definition: dietline.c:1041
static int rz_line_hist_up(void)
Definition: dietline.c:410
static int inithist(void)
Definition: dietline.c:133
static void __vi_mode(bool *enable_yank_pop)
Definition: dietline.c:1118
RZ_API const char * rz_line_readline_cb(RzLineReadCallback cb, void *user)
Definition: dietline.c:1331
static bool is_word_break_char(char ch, bool mode)
Definition: dietline.c:30
static void vi_cmd_b(void)
Definition: dietline.c:1015
RZ_API int rz_line_set_hist_callback(RzLine *line, RzLineHistoryUpCb up, RzLineHistoryDownCb down)
Definition: dietline.c:292
static void selection_widget_up(int steps)
Definition: dietline.c:583
BreakMode
Definition: dietline.c:25
@ MAJOR_BREAK
Definition: dietline.c:27
@ MINOR_BREAK
Definition: dietline.c:26
RZ_API const char * rz_line_hist_get(int n)
Definition: dietline.c:424
static void __print_prompt(void)
Definition: dietline.c:970
static bool match_hist_line(char *hist_line, char *cur_line)
Definition: dietline.c:301
static int rz_line_readchar_utf8(ut8 *s, int slen)
Definition: dietline.c:158
static void rotate_kill_ring(bool *enable_yank_pop)
Definition: dietline.c:917
RZ_API int rz_line_hist_add(const char *line)
Definition: dietline.c:382
RZ_API int rz_line_hist_save(RZ_NONNULL const char *path)
Save the history of commands executed until now to file path.
Definition: dietline.c:497
static void vi_cmd_e(void)
Definition: dietline.c:1080
static void replace_buffer_text(RzLineBuffer *buf, size_t start, size_t end, const char *s)
Definition: dietline.c:711
static void setup_hist_match(RzLine *line)
Definition: dietline.c:306
int root
Definition: enough.c:226
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
RZ_API int rz_cons_controlz(int ch)
Definition: input.c:14
RZ_API bool rz_cons_readbuffer_readchar(char *ch)
Definition: input.c:609
RZ_API int rz_cons_arrow_to_hjkl(int ch)
Definition: input.c:78
RZ_API int rz_cons_readchar_timeout(ut32 usec)
Definition: input.c:560
RZ_API int rz_cons_readchar(void)
Definition: input.c:619
voidpf void uLong size
Definition: ioapi.h:138
const char int mode
Definition: ioapi.h:137
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
return memset(p, 0, total)
void * p
Definition: libc.cpp:67
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
RZ_API RZ_BORROW void * rz_list_get_n(RZ_NONNULL const RzList *list, ut32 n)
Returns the N-th element of the list.
Definition: list.c:574
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
RZ_API void rz_line_clipboard_push(const char *str)
Definition: line.c:50
RZ_API void rz_line_ns_completion_result_free(RzLineNSCompletionResult *res)
Definition: line.c:144
static static fork const void static count static fd const char const char static newpath char char argv
Definition: sflib.h:40
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
static const char struct stat static buf struct stat static buf static vhangup int options
Definition: sflib.h:145
static uint32_t const uint8_t uint32_t uint32_t limit
Definition: memcmplen.h:45
int n
Definition: mipsasm.c:19
#define FALSE
Definition: mybfd.h:102
string FILE
Definition: benchmark.py:21
line
Definition: setup.py:34
int idx
Definition: setup.py:197
#define eprintf(x, y...)
Definition: rlcc.c:7
static RzSocket * s
Definition: rtr.c:28
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
int(* RzLineHistoryUpCb)(RzLine *line)
Definition: rz_cons.h:1085
@ RZ_VIRT_TERM_MODE_COMPLETE
All the sequences goes through VT (Windows Terminal, mintty, all OSs)
Definition: rz_cons.h:451
#define RZ_SELWIDGET_DIR_UP
Definition: rz_cons.h:998
#define RZ_SELWIDGET_MAXW
Definition: rz_cons.h:997
#define RZ_SELWIDGET_DIR_DOWN
Definition: rz_cons.h:999
#define Color_RESET
Definition: rz_cons.h:617
#define Color_RESET_BG
Definition: rz_cons.h:619
@ CONTROL_MODE
Definition: rz_cons.h:780
@ INSERT_MODE
Definition: rz_cons.h:779
#define RZ_SELWIDGET_MAXH
Definition: rz_cons.h:996
#define Color_INVERT_RESET
Definition: rz_cons.h:607
@ RZ_LINE_PROMPT_DEFAULT
Definition: rz_cons.h:1037
@ RZ_LINE_PROMPT_OFFSET
Definition: rz_cons.h:1038
int(* RzLineHistoryDownCb)(RzLine *line)
Definition: rz_cons.h:1086
#define RZ_LINE_BUFSIZE
Definition: rz_cons.h:991
#define Color_INVERT
Definition: rz_cons.h:606
#define RZ_CONS_CLEAR_FROM_CURSOR_TO_END
Definition: rz_cons.h:595
#define RZ_LINE_HISTSIZE
Definition: rz_cons.h:992
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
RZ_API size_t rz_str_utf8_charsize_prev(const char *str, int prev_len)
Definition: str.c:2317
RZ_API size_t rz_str_utf8_charsize_last(const char *str)
Definition: str.c:2335
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API char * rz_str_ndup(RZ_NULLABLE const char *ptr, int len)
Create new copy of string ptr limited to size len.
Definition: str.c:1006
RZ_API RZ_OWN char * rz_str_escape(RZ_NONNULL const char *buf)
Definition: str.c:1550
RZ_API RZ_BORROW char * rz_str_trim_tail(RZ_NONNULL char *str)
Removes whitespace characters (space, tab, newline etc.) from the end of a string and replaces them w...
Definition: str_trim.c:125
RZ_API size_t rz_str_ansi_len(const char *str)
Definition: str.c:1945
#define RZ_STR_ISEMPTY(x)
Definition: rz_str.h:67
RZ_API const char * rz_sub_str_rchr(const char *str, int start, int end, char chr)
Definition: str.c:690
RZ_API bool rz_str_startswith(RZ_NONNULL const char *str, RZ_NONNULL const char *needle)
Checks if a string starts with a specifc sequence of characters (case sensitive)
Definition: str.c:3286
RZ_API const char * rz_str_pad(const char ch, int len)
Definition: str.c:3236
RZ_API const char * rz_sub_str_lchr(const char *str, int start, int end, char chr)
Definition: str.c:682
RZ_API size_t rz_str_utf8_charsize(const char *str)
Definition: str.c:2298
RZ_API const char * rz_str_lastbut(const char *s, char ch, const char *but)
Definition: str.c:2670
#define IS_DIGIT(x)
Definition: rz_str_util.h:11
RZ_API bool rz_sys_mkdirp(const char *dir)
Definition: sys.c:691
RZ_API FILE * rz_sys_fopen(const char *path, const char *mode)
Definition: sys.c:1815
#define RZ_SYS_DIR
Definition: rz_types.h:218
#define ZERO_FILL(x)
Definition: rz_types.h:281
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_NONNULL
Definition: rz_types.h:64
#define RZ_ARRAY_SIZE(x)
Definition: rz_types.h:300
#define RZ_FREE(x)
Definition: rz_types.h:369
#define RZ_MIN(x, y)
#define RZ_MAX(x, y)
#define RZ_BETWEEN(x, y, z)
static void ** rz_pvector_data(RzPVector *vec)
Definition: rz_vector.h:257
static size_t rz_pvector_len(const RzPVector *vec)
Definition: rz_vector.h:231
static bool rz_pvector_empty(RzPVector *vec)
Definition: rz_vector.h:246
static void * rz_pvector_at(const RzPVector *vec, size_t index)
Definition: rz_vector.h:236
#define rz_pvector_foreach(vec, it)
Definition: rz_vector.h:334
#define tolower(c)
Definition: safe-ctype.h:149
static int
Definition: sfsocketcall.h:114
int size_t
Definition: sftypes.h:40
int ssize_t
Definition: sftypes.h:39
#define c(i)
Definition: sha256.c:43
#define h(i)
Definition: sha256.c:48
Definition: gzappend.c:170
Definition: getopt.h:84
RzConsPrintablePalette pal
Definition: rz_cons.h:491
struct rz_line_t * line
Definition: rz_cons.h:553
bool show_autocomplete_widget
Definition: rz_cons.h:516
RzConsEvent event_resize
Definition: rz_cons.h:522
void * event_data
Definition: rz_cons.h:523
RzConsContext * context
Definition: rz_cons.h:502
RzConsQueueTaskOneshot cb_task_oneshot
Definition: rz_cons.h:531
int rows
Definition: rz_cons.h:508
void * user
Definition: rz_cons.h:534
int mouse_event
Definition: rz_cons.h:524
int mouse
Definition: rz_cons.h:551
RzCoreTaskScheduler tasks
Definition: rz_core.h:362
size_t start
First byte that was considered for autocompletion. Everything before this will be left intact.
Definition: rz_cons.h:1062
const char * end_string
String to place after the only option available is autocompleted. By default a space is used.
Definition: rz_cons.h:1064
size_t end
Last byte that was considered for autocompletion. Everything after this will be left intact.
Definition: rz_cons.h:1063
RzPVector options
Vector of options that can be used for autocompletion.
Definition: rz_cons.h:1060
RzLinePromptType prompt_type
Definition: rz_cons.h:1116
const char ** options
Definition: rz_cons.h:1002
int64_t counter
Definition: main.c:4
int height
Definition: main.c:10
static char * prompt(const char *str, const char *txt)
Definition: vmenus.c:30
static st64 delta
Definition: vmenus.c:2425
DWORD * HANDLE
DWORD
static const z80_opcode fd[]
Definition: z80_tab.h:997
static const char * cb[]
Definition: z80_tab.h:176
static int sp
Definition: z80asm.c:91
int read(izstream &zs, T *x, Items items)
Definition: zstream.h:115