/* radare - LGPL - Copyright 2007-2016 - pancake */ /* dietline is a lightweight and portable library similar to GNU readline */ #include #include #include #include #if __WINDOWS__ && !__CYGWIN__ #include #define USE_UTF8 0 #else #include #include #include #define USE_UTF8 1 #endif static char *r_line_nullstr = ""; #define ONLY_VALID_CHARS 1 #if ONLY_VALID_CHARS static inline int is_valid_char (unsigned char ch) { if (ch>=32 && ch<=127) return true; switch (ch) { //case 0: // wat case 1: // ^a case 2: // ^b -> emacs left case 4: // ^d case 5: // ^e case 6: // ^f -> emacs right case 8: // backspace case 9: // tab case 10: // newline case 13: // carriage return case 23: // ^w case 27: // arrow return true; } return false; } #endif static int inithist() { ZERO_FILL (I.history); if ((I.history.size + 1024) * sizeof(char *) < I.history.size) return false; I.history.data = (char **)calloc ((I.history.size + 1024), sizeof(char *)); if (!I.history.data) return false; I.history.size = R_LINE_HISTSIZE; return true; } /* initialize history stuff */ R_API int r_line_dietline_init() { ZERO_FILL (I.completion); if (!inithist ()) return false; I.echo = true; return true; } #if USE_UTF8 /* read utf8 char into 's', return the length in bytes */ static int r_line_readchar_utf8(unsigned char *s, int slen) { // TODO: add support for w32 int ret, len; for (len = 0; len+20) break; } len++; s[len] = 0; return len; } #endif #if __WINDOWS__ && !__CYGWIN__ static int r_line_readchar_win(int * vch) { // this function handle the input in console mode INPUT_RECORD irInBuf[128]; BOOL ret, bCtrl = FALSE; DWORD mode, out; ut8 buf[2]; HANDLE h; int i; if (I.zerosep) { *vch = 0; buf[0] = 0; read (0, buf, 1); return buf[0]; } *buf = '\0'; do_it_again: h = GetStdHandle (STD_INPUT_HANDLE); GetConsoleMode (h, &mode); SetConsoleMode (h, 0); // RAW *vch = 0; ret = ReadConsoleInput (h, irInBuf, 128, &out); if (ret<1) { return 0; } for (i = 0; i < out; i++) { if (irInBuf[i].EventType!=KEY_EVENT) continue; if (!irInBuf[i].Event.KeyEvent.bKeyDown) continue; *buf = irInBuf[i].Event.KeyEvent.uChar.AsciiChar; bCtrl = irInBuf[i].Event.KeyEvent.dwControlKeyState & 8; if (irInBuf[i].Event.KeyEvent.uChar.AsciiChar) { continue; } switch (irInBuf[i].Event.KeyEvent.wVirtualKeyCode) { case VK_DOWN: *vch = bCtrl? 140: 40; break; case VK_UP: *vch = bCtrl? 138: 38; break; case VK_RIGHT: *vch = bCtrl? 139: 39; break; case VK_LEFT: *vch = bCtrl? 137:37; break; case 46: *vch = bCtrl? 146: 46; break; // SUPR KEY case VK_PRIOR: *vch = bCtrl? 136:36; break; // HOME KEY case VK_NEXT: *vch = bCtrl? 135: 35; break; // END KEY default: *vch = *buf = 0; break; } } SetConsoleMode (h, mode); if (buf[0]==0 && *vch==0) goto do_it_again; return buf[0]; } #endif static int r_line_readchar() { ut8 buf[2]; *buf = '\0'; #if __WINDOWS__ && !__CYGWIN__ #if 1 // new implementation for read input at windows by skuater. If something fail set this to 0 int dummy=0; return r_line_readchar_win(&dummy); #endif BOOL ret; DWORD mode, out; HANDLE h; #else int ret; #endif do_it_again: #if __WINDOWS__ && !__CYGWIN__ h = GetStdHandle (STD_INPUT_HANDLE); GetConsoleMode (h, &mode); SetConsoleMode (h, 0); // RAW ret = ReadConsole (h, buf, 1, &out, NULL); // wine hack-around if (!ret && read (0, buf, 1) != 1) return -1; SetConsoleMode (h, mode); #else do { buf[0] = 0; ret = read (0, buf, 1); buf[0] = r_cons_controlz (buf[0]); // VTE HOME/END support if (buf[0]==79) { if (read (0, buf, 1) != 1) return -1; if (buf[0]==70) { return 5; } else if (buf[0]==72) { return 1; } return 0; } if (ret == -1) return 0; // read no char if (!buf[0] || ret == 0) return -1; // eof // TODO: add support for other invalid chars if (*buf==0xc2 || *buf==0xc3) { read (0, buf+1, 1); *buf = '\0'; } } while (*buf == '\0'); #endif #if ONLY_VALID_CHARS if (!is_valid_char (buf[0])) goto do_it_again; #endif return buf[0]; } R_API int r_line_hist_add(const char *line) { if (!I.history.data) inithist (); if (I.history.top >= I.history.size) I.history.top = I.history.index = 0; // workaround /* ignore dup */ if (I.history.index > 0) { const char *data = I.history.data[I.history.index - 1]; if (data && !strcmp (line, data)) return false; } if (line && *line) { // && I.history.index < I.history.size) { I.history.data[I.history.top++] = strdup (line); I.history.index = I.history.top; return true; } return false; } static int r_line_hist_up() { if (I.hist_up) return I.hist_up (I.user); if (!I.history.data) inithist (); if (I.history.index>0) { strncpy (I.buffer.data, I.history.data[--I.history.index], R_LINE_BUFSIZE-1); I.buffer.index = I.buffer.length = strlen (I.buffer.data); return true; } return false; } static int r_line_hist_down() { if (I.hist_down) return I.hist_down (I.user); I.buffer.index = 0; if (!I.history.data) inithist (); if (I.history.index.history or so */ R_API int r_line_hist_load(const char *file) { FILE *fd; char buf[R_LINE_BUFSIZE], *path = r_str_home (file); if (path == NULL) return false; if (!(fd = fopen (path, "r"))) { free (path); return false; } while (fgets (buf, sizeof (buf), fd) != NULL) { buf[strlen (buf)-1] = 0; r_line_hist_add (buf); } fclose (fd); free (path); return true; } R_API int r_line_hist_save(const char *file) { FILE *fd; int i, ret = false; char *p, *path = r_str_home (file); if (path != NULL) { p = (char*)r_str_lastbut (path, R_SYS_DIR[0], NULL); // TODO: use fs if (p) { *p = 0; r_sys_mkdirp (path); *p = R_SYS_DIR[0]; } fd = fopen (path, "w"); if (fd != NULL) { if (I.history.data) { for (i=0; i 0) { int tt = largv0; if (*t != ' ') p[tt++] = ' '; memmove (p + tt, t, len_t); } memcpy (p, argv[0], largv0); p[largv0] = ' '; if (len_t == 0) p[largv0 + 1] = '\0'; I.buffer.length = strlen (I.buffer.data); I.buffer.index = (p - I.buffer.data) + largv0 + 1; } } else if (argc > 0) { if (*p) { // TODO: avoid overflow const char *t = I.buffer.data + I.buffer.index; const char *root = argv[0]; int min_common_len = strlen(root); size_t len_t = strlen (t); // try to autocomplete argument for (i = 0; i < argc; i++) { j = 0; if (!argv[i]) break; while (argv[i][j] == root[j] && root[j] != '\0') j++; if (j < min_common_len) { min_common_len = j; } root = argv[i]; } if (len_t > 0) { int tt = min_common_len; memmove (p + tt, t, len_t); p[tt + len_t] = '\0'; } memmove (p, root, min_common_len); if (len_t == 0) p[min_common_len] = '\0'; I.buffer.length = strlen (I.buffer.data); I.buffer.index = (p - I.buffer.data) + min_common_len; } } /* show options */ if (opt > 1 && I.echo) { const int sep = 3; int slen, col = 10; printf ("%s%s\n", I.prompt, I.buffer.data); for (i = 0; i < argc && argv[i]; i++) { int l = strlen (argv[i]); if (sep + l > col) { col = sep + l; } if (col > (cols >> 1)) { col = (cols >> 1); break; } } for (len = i = 0; i < argc && argv[i]; i++) { if (len + col > cols) { printf ("\n"); len = 0; } printf ("%-*s ", col - sep, argv[i]); slen = strlen (argv[i]); len += (slen > col) ? (slen + sep) : (col + sep); } printf ("\n"); } fflush (stdout); } R_API const char *r_line_readline() { return r_line_readline_cb (NULL, NULL); } #if __WINDOWS__ && !__CYGWIN__ R_API const char *r_line_readline_cb_win(RLineReadCallback cb, void *user) { int columns = r_cons_get_size (NULL)-2; const char *gcomp_line = ""; static int gcomp_idx = 0; static int gcomp = 0; signed char buf[10]; int ch, i=0; /* grep completion */ int vch=0; char *tmp_ed_cmd, prev = 0; HANDLE hClipBoard; char *clipText; I.buffer.index = I.buffer.length = 0; I.buffer.data[0] = '\0'; if (I.contents) { memmove (I.buffer.data, I.contents, R_MIN (strlen (I.contents)+1, R_LINE_BUFSIZE-1)); I.buffer.data[R_LINE_BUFSIZE-1] = '\0'; I.buffer.index = I.buffer.length = strlen (I.contents); } if (I.disable) { if (!fgets (I.buffer.data, R_LINE_BUFSIZE-1, stdin)) return NULL; I.buffer.data[strlen (I.buffer.data)] = '\0'; return (*I.buffer.data)? I.buffer.data : r_line_nullstr; } memset (&buf, 0, sizeof buf); r_cons_set_raw (1); if (I.echo) { r_cons_clear_line (0); printf ("\x1b[0K\r%s%s", I.prompt, I.buffer.data); fflush (stdout); } r_cons_singleton()->breaked = false; for (;;) { #if 0 if (I.echo) { printf(" ("); for(i=1;i= columns) break; printf("%s ", argv[i]); } } printf(")"); fflush(stdout); } #endif I.buffer.data[I.buffer.length]='\0'; if (cb && !cb (user, I.buffer.data)) { I.buffer.data[0] = 0; I.buffer.length = 0; } ch = r_line_readchar_win (&vch); //eprintf("des ch=%c(%d) vch=%d\n",ch,vch); if (ch == -1) return NULL; buf[0] = ch; if (I.echo) r_cons_clear_line (0); columns = r_cons_get_size (NULL)-2; if (columns<1) columns = 40; if (I.echo) printf ("\r%*c\r", columns, ' '); if (I.echo) printf ("\r\x1b[2K\r"); //%*c\r", columns, ' '); /* process special at vch codes first*/ switch (vch) { case 37: // left arrow I.buffer.index = I.buffer.index? I.buffer.index-1: 0; break; case 38: // up arrow if (gcomp) gcomp_idx++; else if (r_line_hist_up ()==-1) return NULL; break; case 39: // right arrow I.buffer.index = I.buffer.index0) gcomp_idx--; } else if (r_line_hist_down ()==-1) return NULL; break; /* ctrl+arrows */ case 137:// ctrl+left arrow // previous word for (i=I.buffer.index; i>0; i--) { if (I.buffer.data[i] == ' ') { I.buffer.index = i-1; break; } } if (I.buffer.data[i] != ' ') I.buffer.index = 0; break; case 138:// ctrl+up arrow //first I.buffer.index = 0; break; case 139:// ctrl+right arrow // next word for (i=I.buffer.index; ibreaked = true; goto _end; case 4: // ^D if (!I.buffer.data[0]) { /* eof */ if (I.echo) printf ("^D\n"); r_cons_set_raw (false); return NULL; } if (I.buffer.index0) { for (i=I.buffer.index-1; i>0&&I.buffer.data[i]==' '; i--); for (; i&&I.buffer.data[i]!=' '; i--); if (!i) for (; i>0&&I.buffer.data[i]==' '; i--); if (i>0) i++; else if (i<0) i=0; if (I.buffer.index>I.buffer.length) I.buffer.length = I.buffer.index; memmove (I.buffer.data+i, I.buffer.data+I.buffer.index, I.buffer.length-I.buffer.index+1); I.buffer.length = strlen (I.buffer.data); I.buffer.index = i; } break; case 24: // ^X -- do nothing but store in prev = *buf break; case 25: // ^Y - paste if (I.clipboard != NULL) { I.buffer.length += strlen(I.clipboard); // TODO: support endless strings if (I.buffer.length < R_LINE_BUFSIZE) { I.buffer.index = I.buffer.length; strcat (I.buffer.data, I.clipboard); } else I.buffer.length -= strlen (I.clipboard); } break; case 14: // ^n if (gcomp) { if (gcomp_idx>0) gcomp_idx--; } else r_line_hist_down (); break; case 16: // ^p if (gcomp) { gcomp_idx++; } else r_line_hist_up (); break; case 8: case 127: if (I.buffer.index < I.buffer.length) { if (I.buffer.index>0) { int len = 0; // TODO: WIP len = 1; I.buffer.index--; memmove (I.buffer.data+I.buffer.index, I.buffer.data+I.buffer.index+len, strlen (I.buffer.data+I.buffer.index)); I.buffer.length -= len; I.buffer.data[I.buffer.length] = 0; } } else { // OK I.buffer.index = --I.buffer.length; if (I.buffer.length<0) I.buffer.length=0; I.buffer.data[I.buffer.length]='\0'; } if (I.buffer.index<0) I.buffer.index = 0; break; /* tab */ case 9: // tab r_line_autocomplete (); break; /* enter */ case 13: if (gcomp && I.buffer.length>0) { strncpy (I.buffer.data, gcomp_line, R_LINE_BUFSIZE-1); I.buffer.data[R_LINE_BUFSIZE-1] = '\0'; I.buffer.length = strlen (gcomp_line); } gcomp_idx = gcomp = 0; goto _end; #if 0 // force command fit for(i=1;iI.buffer.index; i--) I.buffer.data[i] = I.buffer.data[i-1]; I.buffer.data[I.buffer.index] = buf[0]; } else { I.buffer.data[I.buffer.length]=buf[0]; I.buffer.length++; if (I.buffer.length>(R_LINE_BUFSIZE-1)) I.buffer.length--; I.buffer.data[I.buffer.length]='\0'; } I.buffer.index++; break; } prev = buf[0]; if (I.echo) { if (gcomp) { gcomp_line = ""; //if (I.buffer.length == 0) // gcomp = 0; if (I.history.data != NULL) for (i=0; icols) { printf ("< "); i = I.buffer.index-cols; if (i>sizeof (I.buffer.data)) { i = sizeof (I.buffer.data)-1; } } else i = 0; len = I.buffer.index-i; if (len>0 && (i+len)<=I.buffer.length) fwrite (I.buffer.data+i, 1, len, stdout); } fflush (stdout); } } _end: r_cons_set_raw (0); if (I.echo) { printf ("\r%s%s\n", I.prompt, I.buffer.data); fflush (stdout); } // should be here or not? if (!memcmp (I.buffer.data, "!history", 8)) { //if (I.buffer.data[0]=='!' && I.buffer.data[1]=='\0') { r_line_hist_list (); return r_line_nullstr; } return I.buffer.data[0] != '\0'? I.buffer.data : r_line_nullstr; } #endif R_API const char *r_line_readline_cb(RLineReadCallback cb, void *user) { #if __WINDOWS__ && !__CYGWIN__ #if 1 // new implementation for read input at windows by skuater. If something fail set this to 0 return r_line_readline_cb_win(cb,user); #endif #endif int columns = r_cons_get_size (NULL)-2; const char *gcomp_line = ""; static int gcomp_idx = 0; static int gcomp = 0; signed char buf[10]; #if USE_UTF8 int utflen; #endif int ch, i=0; /* grep completion */ char *tmp_ed_cmd, prev = 0; I.buffer.index = I.buffer.length = 0; I.buffer.data[0] = '\0'; if (I.contents) { memmove (I.buffer.data, I.contents, R_MIN (strlen (I.contents)+1, R_LINE_BUFSIZE-1)); I.buffer.data[R_LINE_BUFSIZE-1] = '\0'; I.buffer.index = I.buffer.length = strlen (I.contents); } if (I.disable) { if (!fgets (I.buffer.data, R_LINE_BUFSIZE-1, stdin)) return NULL; I.buffer.data[strlen (I.buffer.data)] = '\0'; return (*I.buffer.data)? I.buffer.data : r_line_nullstr; } memset (&buf, 0, sizeof buf); r_cons_set_raw (1); if (I.echo) { r_cons_clear_line (0); printf ("\x1b[0K\r%s%s", I.prompt, I.buffer.data); fflush (stdout); } r_cons_singleton()->breaked = false; for (;;) { I.buffer.data[I.buffer.length] = '\0'; if (cb && !cb (user, I.buffer.data)) { I.buffer.data[0] = 0; I.buffer.length = 0; } #if USE_UTF8 utflen = r_line_readchar_utf8 ( (ut8*)buf, sizeof (buf)); if (utflen <1) { return NULL; } buf[utflen] = 0; #else ch = r_line_readchar (); if (ch == -1) return NULL; buf[0] = ch; #endif if (I.echo) { r_cons_clear_line (0); } if (columns < 1) { columns = 40; } #if __WINDOWS__ && !__CYGWIN__ if (I.echo) { printf ("\r%*c\r", columns, ' '); } #else if (I.echo) { printf ("\r\x1b[2K\r"); //%*c\r", columns, ' '); } #endif switch (*buf) { case 0: // control-space /* ignore atm */ break; case 1: // ^A I.buffer.index = 0; break; case 2: // ^b // emacs left #if USE_UTF8 { char *s = I.buffer.data+I.buffer.index-1; utflen = 1; while (s>I.buffer.data && (*s & 0xc0) == 0x80) { utflen++; s--; } } I.buffer.index = I.buffer.index? I.buffer.index-utflen: 0; #else I.buffer.index = I.buffer.index? I.buffer.index-1: 0; #endif break; case 5: // ^E if (prev == 24) { // ^X = 0x18 I.buffer.data[I.buffer.length] = 0; // probably unnecessary tmp_ed_cmd = I.editor_cb (I.user, I.buffer.data); if (tmp_ed_cmd) { /* copied from yank (case 25) */ I.buffer.length = strlen (tmp_ed_cmd); if (I.buffer.length < R_LINE_BUFSIZE) { I.buffer.index = I.buffer.length; strncpy (I.buffer.data, tmp_ed_cmd, R_LINE_BUFSIZE-1); I.buffer.data[R_LINE_BUFSIZE-1] = '\0'; } else I.buffer.length -= strlen (tmp_ed_cmd); free (tmp_ed_cmd); } } else I.buffer.index = I.buffer.length; break; case 3: // ^C if (I.echo) eprintf ("^C\n"); I.buffer.index = I.buffer.length = 0; *I.buffer.data = '\0'; r_cons_singleton()->breaked = true; goto _end; case 4: // ^D if (!I.buffer.data[0]) { /* eof */ if (I.echo) printf ("^D\n"); r_cons_set_raw (false); return NULL; } if (I.buffer.index0) { char *s; do { I.buffer.index--; s = I.buffer.data+I.buffer.index; } while ((*s & 0xc0) == 0x80); } #else I.buffer.index = I.buffer.index? I.buffer.index-1: 0; #endif } break; case 21: // ^U - cut free (I.clipboard); I.clipboard = strdup (I.buffer.data); I.buffer.data[0] = '\0'; I.buffer.length = 0; I.buffer.index = 0; break; case 23: // ^W ^w if (I.buffer.index>0) { for (i=I.buffer.index-1; i>0&&I.buffer.data[i]==' '; i--); for (; i&&I.buffer.data[i]!=' '; i--); if (!i) for (; i>0&&I.buffer.data[i]==' '; i--); if (i>0) i++; else if (i<0) i=0; if (I.buffer.index>I.buffer.length) I.buffer.length = I.buffer.index; memmove (I.buffer.data+i, I.buffer.data+I.buffer.index, I.buffer.length-I.buffer.index+1); I.buffer.length = strlen (I.buffer.data); I.buffer.index = i; } break; case 24: // ^X -- do nothing but store in prev = *buf break; case 25: // ^Y - paste if (I.clipboard != NULL) { I.buffer.length += strlen(I.clipboard); // TODO: support endless strings if (I.buffer.length < R_LINE_BUFSIZE) { I.buffer.index = I.buffer.length; strcat (I.buffer.data, I.clipboard); } else I.buffer.length -= strlen (I.clipboard); } break; case 14: // ^n if (gcomp) { if (gcomp_idx>0) gcomp_idx--; } else r_line_hist_down (); break; case 16: // ^p if (gcomp) { gcomp_idx++; } else r_line_hist_up (); break; case 27: //esc-5b-41-00-00 buf[0] = r_line_readchar(); switch (buf[0]) { case -1: return NULL; case 1: // begin I.buffer.index = 0; break; case 5: // end I.buffer.index = I.buffer.length; break; case 'B': case 'b': // previous word for (i = I.buffer.index - 2; i >= 0; i--) { if (I.buffer.data[i] == ' ' && I.buffer.data[i + 1] != ' ') { I.buffer.index = i + 1; break; } } if (i < 0) I.buffer.index = 0; break; case 'F': case 'f': // next word for (i = I.buffer.index + 1; i < I.buffer.length; i++) { if (I.buffer.data[i] != ' ' && I.buffer.data[i - 1] == ' ') { I.buffer.index = i; break; } } if (i >= I.buffer.length) I.buffer.index = I.buffer.length; break; default: buf[1] = r_line_readchar(); if (buf[1] == -1) return NULL; if (buf[0]==0x5b) { // [ switch (buf[1]) { case 0x33: // supr if (I.buffer.index0) gcomp_idx--; } else if (r_line_hist_down ()==-1) return NULL; break; case 0x43: // C --> right arrow #if USE_UTF8 { char *s = I.buffer.data+I.buffer.index+1; utflen = 1; while ((*s & 0xc0) == 0x80) { utflen++; s++; } I.buffer.index = I.buffer.index left arrow #if USE_UTF8 { char *s = I.buffer.data+I.buffer.index-1; utflen = 1; while (s>I.buffer.data && (*s & 0xc0) == 0x80) { utflen++; s--; } } I.buffer.index = I.buffer.index? I.buffer.index-utflen: 0; #else I.buffer.index = I.buffer.index? I.buffer.index-1: 0; #endif break; case 0x31: // control + arrow ch = r_cons_readchar (); if (ch == 0x7e) { // HOME in screen/tmux // corresponding END is 0x34 below (the 0x7e is ignored there) I.buffer.index = 0; break; } r_cons_readchar (); ch = r_cons_readchar (); switch (ch) { case 0x41: //first I.buffer.index = 0; break; case 0x44: // previous word for (i=I.buffer.index; i>0; i--) { if (I.buffer.data[i] == ' ') { I.buffer.index = i-1; break; } } if (I.buffer.data[i] != ' ') I.buffer.index = 0; break; case 0x42: //end I.buffer.index = I.buffer.length; break; case 0x43: // next word for (i=I.buffer.index; i 0) { int len = 0; // TODO: WIP #if USE_UTF8 char *s; do { I.buffer.index--; s = I.buffer.data + I.buffer.index; len++; } while ((*s & 0xc0) == 0x80); #else len = 1; I.buffer.index--; #endif memmove (I.buffer.data + I.buffer.index, I.buffer.data + I.buffer.index + len, strlen (I.buffer.data + I.buffer.index)); I.buffer.length -= len; I.buffer.data[I.buffer.length] = 0; } } else { // OK #if USE_UTF8 char *s; // utf8 backward size do { I.buffer.length--; s = I.buffer.data+I.buffer.length; i++; } while ((*s & 0xc0) == 0x80); I.buffer.index = I.buffer.length; #else I.buffer.index = --I.buffer.length; #endif if (I.buffer.length < 0) I.buffer.length = 0; I.buffer.data[I.buffer.length] = '\0'; } if (I.buffer.index < 0) { I.buffer.index = 0; } break; case 9: // tab r_line_autocomplete (); break; case 13: if (gcomp && I.buffer.length>0) { strncpy (I.buffer.data, gcomp_line, R_LINE_BUFSIZE-1); I.buffer.data[R_LINE_BUFSIZE-1] = '\0'; I.buffer.length = strlen (gcomp_line); } gcomp_idx = gcomp = 0; goto _end; default: if (gcomp) gcomp++; if (I.buffer.index I.buffer.index; i--) { I.buffer.data[i] = I.buffer.data[i - utflen]; } memcpy (I.buffer.data + I.buffer.index, buf, utflen); } #else for (i = ++I.buffer.length; i > I.buffer.index; i--) { I.buffer.data[i] = I.buffer.data[i - 1]; } I.buffer.data[I.buffer.index] = buf[0]; #endif } else { #if USE_UTF8 if ((I.buffer.length + utflen) < sizeof (I.buffer.data)) { memcpy (I.buffer.data + I.buffer.length, buf, utflen); I.buffer.length += utflen; } I.buffer.data[I.buffer.length] = '\0'; #else I.buffer.data[I.buffer.length] = buf[0]; I.buffer.length++; if (I.buffer.length > (R_LINE_BUFSIZE - 1)) { I.buffer.length--; } I.buffer.data[I.buffer.length] = '\0'; #endif } #if USE_UTF8 I.buffer.index += utflen; #else I.buffer.index++; #endif break; } prev = buf[0]; if (I.echo) { if (gcomp) { gcomp_line = ""; if (I.history.data != NULL) for (i=0; icols) { printf ("< "); i = I.buffer.index-cols; if (i>sizeof (I.buffer.data)) { i = sizeof (I.buffer.data)-1; } } else i = 0; len = I.buffer.index-i; if (len>0 && (i+len)<=I.buffer.length) fwrite (I.buffer.data+i, 1, len, stdout); } fflush (stdout); } } _end: r_cons_set_raw (0); if (I.echo) { printf ("\r%s%s\n", I.prompt, I.buffer.data); fflush (stdout); } // should be here or not? if (!memcmp (I.buffer.data, "!history", 8)) { //if (I.buffer.data[0]=='!' && I.buffer.data[1]=='\0') { r_line_hist_list (); return r_line_nullstr; } return I.buffer.data[0] != '\0'? I.buffer.data : r_line_nullstr; }