00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047 #include <sys/types.h>
00048 #include <sys/stat.h>
00049 #include <stdio.h>
00050 #include <dirent.h>
00051 #include <string.h>
00052 #include <pwd.h>
00053 #include <ctype.h>
00054 #include <stdlib.h>
00055 #include <unistd.h>
00056 #include <limits.h>
00057 #ifndef __FreeBSD__
00058 #include <alloca.h>
00059 #endif // __FreeBSD__
00060 #include "histedit.h"
00061
00062 #include "editline.h"
00063 #include "el.h"
00064 #include "compat.h"
00065 #include "TTermManip.h"
00066 #include "enhance.h"
00067
00068
00069 #define TAB '\r'
00070
00071
00072 #define GDB_411_HACK
00073
00074
00075
00076 const char* rl_library_version = "EditLine_t wrapper";
00077 const char* rl_readline_name = "";
00078 FILE* rl_instream = NULL;
00079 FILE* rl_outstream = NULL;
00080 int rl_point = 0;
00081 int rl_end = 0;
00082 char* rl_line_buffer = NULL;
00083
00084 int history_base = 1;
00085 int history_length = 0;
00086 int max_input_history = 0;
00087 char history_expansion_char = '!';
00088 char history_subst_char = '^';
00089 const char* history_no_expand_chars = " \t\n=(";
00090 Function* history_inhibit_expansion_function = NULL;
00091
00092 int rl_inhibit_completion = 0;
00093 int rl_attempted_completion_over = 0;
00094 const char* rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{(";
00095 char* rl_completer_word_break_characters = NULL;
00096 char* rl_completer_quote_characters = NULL;
00097 CPFunction* rl_completion_entry_function = NULL;
00098 CPPFunction* rl_attempted_completion_function = NULL;
00099 int tab_color = 5;
00100 El_tab_hook_t rl_tab_hook = NULL;
00101 El_in_key_hook_t rl_in_key_hook = NULL;
00102
00103
00104
00105
00106
00107
00108 int rl_completion_type = 0;
00109
00110
00111
00112
00113
00114 int rl_completion_query_items = 100;
00115
00116
00117
00118
00119
00120
00121 char* rl_special_prefixes = (char*) NULL;
00122
00123
00124
00125
00126
00127 int rl_completion_append_character = ' ';
00128
00129
00130
00131
00132 static int grl_complete_show_all = 0;
00133
00134 static HistoryFcns_t* gHistory = NULL;
00135 static EditLine_t* gEditLine = NULL;
00136 static int gel_rl_complete_cmdnum = 0;
00137
00138
00139 static unsigned char _el_rl_complete(EditLine_t*, int);
00140 static char* _get_prompt(EditLine_t*);
00141 static HIST_ENTRY* _move_history(int);
00142 static int _history_search_gen(const char*, int, int);
00143 #ifdef EL_HISTORY_EXPAND
00144 static int _history_expand_command(const char*, size_t, char**);
00145 static char* _rl_compat_sub(const char*, const char*,
00146 const char*, int);
00147 #endif
00148 static int rl_complete_internal(int);
00149 static int _rl_qsort_string_compare(const void*, const void*);
00150
00151
00152
00153
00154 static char* gel_rl_prompt = NULL;
00155
00156
00157 static char*
00158 _get_prompt(EditLine_t* ) {
00159 return gel_rl_prompt;
00160 }
00161
00162
00163
00164
00165
00166 static HIST_ENTRY*
00167 _move_history(int op) {
00168 HistEvent_t ev;
00169 static HIST_ENTRY rl_he;
00170
00171 if (history(gHistory, &ev, op) != 0) {
00172 return (HIST_ENTRY*) NULL;
00173 }
00174
00175 rl_he.line = ev.fStr;
00176 rl_he.data = "";
00177
00178 return &rl_he;
00179 }
00180
00181
00182 bool
00183 rl_isinitialized() {
00184 return gEditLine != NULL;
00185 }
00186
00187
00188
00189
00190
00191
00192
00193
00194 int
00195 rl_initialize(void) {
00196 HistEvent_t ev;
00197 const LineInfo_t* li;
00198 int i;
00199 int editmode = 1;
00200 struct termios t;
00201
00202 if (gEditLine != NULL) {
00203 el_end(gEditLine);
00204 }
00205
00206 if (gHistory != NULL) {
00207 history_end(gHistory);
00208 }
00209
00210 if (!rl_instream) {
00211 rl_instream = stdin;
00212 }
00213
00214 if (!rl_outstream) {
00215 rl_outstream = stdout;
00216 }
00217
00218
00219
00220
00221 if (tcgetattr(fileno(rl_instream), &t) != -1 && (t.c_lflag & ECHO) == 0) {
00222 editmode = 0;
00223 }
00224
00225 gEditLine = el_init(rl_readline_name, rl_instream, rl_outstream, stderr);
00226
00227 if (!editmode) {
00228 el_set(gEditLine, EL_EDITMODE, 0);
00229 }
00230
00231 gHistory = history_init();
00232
00233 if (!gEditLine || !gHistory) {
00234 return -1;
00235 }
00236
00237 history(gHistory, &ev, H_SETSIZE, INT_MAX);
00238 history_length = 0;
00239 max_input_history = INT_MAX;
00240 el_set(gEditLine, EL_HIST, history, gHistory);
00241
00242
00243 gel_rl_prompt = strdup("");
00244 el_set(gEditLine, EL_PROMPT, _get_prompt);
00245 el_set(gEditLine, EL_SIGNAL, 1);
00246
00247
00248
00249
00250
00251 char* editor = 0;
00252
00253 el_set(gEditLine, EL_EDITOR, editor ? editor : "emacs");
00254
00255
00256
00257
00258
00259 el_set(gEditLine, EL_ADDFN, "rl_complete",
00260 "ReadLine compatible completition function",
00261 _el_rl_complete);
00262 el_set(gEditLine, EL_BIND, "^I", "rl_complete", NULL);
00263
00264
00265 el_set(gEditLine, EL_BIND, "^R", "em-inc-search-prev", NULL);
00266 el_set(gEditLine, EL_BIND, "^S", "em-inc-search-next", NULL);
00267
00268
00269
00270
00271
00272
00273 for (i = EL_NUM_FCNS; i < gEditLine->fMap.fNFunc; i++) {
00274 if (gEditLine->fMap.fFunc[i] == _el_rl_complete) {
00275 gel_rl_complete_cmdnum = i;
00276 break;
00277 }
00278 }
00279
00280
00281
00282 el_source(gEditLine, NULL);
00283
00284
00285
00286
00287
00288 li = el_line(gEditLine);
00289
00290 rl_line_buffer = (char*) li->fBuffer;
00291 rl_point = rl_end = 0;
00292
00293 return 0;
00294 }
00295
00296
00297
00298
00299
00300
00301
00302
00303 void
00304 rl_cleanup_after_signal() {
00305 el_end(gEditLine);
00306 history_end(gHistory);
00307 }
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318 #include <iostream>
00319 char*
00320 readline(const char* prompt, bool newline) {
00321 HistEvent_t ev;
00322 int count;
00323 const char* ret;
00324
00325 if (gEditLine == NULL || gHistory == NULL) {
00326 rl_initialize();
00327 }
00328
00329
00330
00331 if (!prompt || !isatty(0) || !isatty(1)) {
00332 prompt = "";
00333 }
00334
00335 if (strcmp(gel_rl_prompt, prompt) != 0) {
00336 free(gel_rl_prompt);
00337 gel_rl_prompt = strdup(prompt);
00338 }
00339
00340
00341 if (newline) {
00342 tty_rawmode(gEditLine);
00343 ret = el_gets_newline(gEditLine, &count);
00344 } else {
00345 ret = el_gets(gEditLine, &count);
00346
00347 if (rl_in_key_hook && count > 0 && gEditLine->fLine.fLastChar > gEditLine->fLine.fBuffer) {
00348 char* key = gEditLine->fLine.fLastChar;
00349
00350 if (*key == '\a') {
00351 --key;
00352 }
00353 (*rl_in_key_hook)(*key);
00354 }
00355 }
00356
00357
00358
00359
00360
00361
00362 if (ret) {
00363 if (count <= 0) {
00364 ret = NULL;
00365 }
00366 }
00367
00368 history(gHistory, &ev, H_GETSIZE);
00369 history_length = ev.fNum;
00370
00371 if (ret && !strchr(ret, '\a') && ret[strlen(ret) - 1] == '\n') {
00372 tty_cookedmode(gEditLine);
00373 }
00374
00375 return (char*) ret;
00376 }
00377
00378
00379 void
00380 setColors(const char* colorTab, const char* colorTabComp, const char* colorBracket,
00381 const char* colorBadBracket, const char* colorPrompt) {
00382
00383 tab_color = term__atocolor(colorTabComp);
00384 prompt_setcolor(term__atocolor(colorPrompt));
00385
00386 setKeywordColors(term__atocolor(colorTab),
00387 term__atocolor(colorBracket),
00388 term__atocolor(colorBadBracket));
00389 }
00390
00391
00392 void
00393 termResize(void) {
00394 el_resize(gEditLine);
00395 }
00396
00397
00398 void
00399 setEcho(bool echo) {
00400 if (echo) {
00401 tty_noquotemode(gEditLine);
00402 } else {
00403 tty_quotemode(gEditLine);
00404 }
00405 }
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416 void
00417 using_history(void) {
00418 if (gHistory == NULL || gEditLine == NULL) {
00419 rl_initialize();
00420 }
00421 }
00422
00423
00424 #ifdef EL_HISTORY_EXPAND
00425
00426
00427
00428
00429
00430 static char*
00431 _rl_compat_sub(const char* str, const char* what, const char* with,
00432 int globally) {
00433 char* result;
00434 const char* temp, * newp;
00435 size_t len, add;
00436 int with_len, what_len;
00437 size_t size, i;
00438
00439 result = (char*) malloc((size = 16));
00440 temp = str;
00441 with_len = strlen(with);
00442 what_len = strlen(what);
00443 len = 0;
00444
00445 do {
00446 newp = strstr(temp, what);
00447
00448 if (newp) {
00449 i = newp - temp;
00450 add = i + with_len;
00451
00452 if (i + add + 1 >= size) {
00453 size += add + 1;
00454 result = (char*) realloc(result, size);
00455 }
00456 (void) strncpy(&result[len], temp, i);
00457 len += i;
00458 (void) strcpy(&result[len], with);
00459 len += with_len;
00460 temp = newp + what_len;
00461 } else {
00462 add = strlen(temp);
00463
00464 if (len + add + 1 >= size) {
00465 size += add + 1;
00466 result = (char*) realloc(result, size);
00467 }
00468 (void) strcpy(&result[len], temp);
00469 len += add;
00470 temp = NULL;
00471 }
00472 }
00473 while (temp && globally);
00474 result[len] = '\0';
00475
00476 return result;
00477 }
00478 #endif
00479
00480
00481 #ifdef EL_HISTORY_EXPAND
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493 static int
00494 _history_expand_command(const char* command, size_t cmdlen, char** result) {
00495 char** arr, * tempcmd, * line, * search = NULL, * cmd;
00496 const char* event_data = NULL;
00497 static char* from = NULL, * to = NULL;
00498 int start = -1, end = -1, max, i, idx;
00499 int gHistory_on = 0, t_on = 0, r_on = 0, gEditLine_on = 0, p_on = 0, g_on = 0;
00500 int event_num = 0, retval;
00501 size_t cmdsize;
00502
00503 *result = NULL;
00504
00505 cmd = (char*) alloca(cmdlen + 1);
00506 (void) strncpy(cmd, command, cmdlen);
00507 cmd[cmdlen] = 0;
00508
00509 idx = 1;
00510
00511
00512 if (cmd[idx] == history_expansion_char) {
00513 event_num = history_length;
00514 idx++;
00515 } else {
00516 int off, num;
00517 size_t len;
00518 off = idx;
00519
00520 while (cmd[off] && !strchr(":^$*-%", cmd[off]))
00521 off++;
00522 num = atoi(&cmd[idx]);
00523
00524 if (num != 0) {
00525 event_num = num;
00526
00527 if (num < 0) {
00528 event_num += history_length + 1;
00529 }
00530 } else {
00531 int prefix = 1, curr_num;
00532 HistEvent_t ev;
00533
00534 len = off - idx;
00535
00536 if (cmd[idx] == '?') {
00537 idx++, len--;
00538
00539 if (cmd[off - 1] == '?') {
00540 len--;
00541 } else if (cmd[off] != '\n' && cmd[off] != '\0') {
00542 return -1;
00543 }
00544 prefix = 0;
00545 }
00546 search = (char*) alloca(len + 1);
00547 (void) strncpy(search, &cmd[idx], len);
00548 search[len] = '\0';
00549
00550 if (history(gHistory, &ev, H_CURR) != 0) {
00551 return -1;
00552 }
00553 curr_num = ev.fNum;
00554
00555 if (prefix) {
00556 retval = history_search_prefix(search, -1);
00557 } else {
00558 retval = history_search(search, -1);
00559 }
00560
00561 if (retval == -1) {
00562 fprintf(rl_outstream, "%s: Event not found\n",
00563 search);
00564 return -1;
00565 }
00566
00567 if (history(gHistory, &ev, H_CURR) != 0) {
00568 return -1;
00569 }
00570 event_data = ev.fStr;
00571
00572
00573 history(gHistory, &ev, H_NEXT_EVENT, curr_num);
00574 }
00575 idx = off;
00576 }
00577
00578 if (!event_data && event_num >= 0) {
00579 HIST_ENTRY* rl_he;
00580 rl_he = history_get(event_num);
00581
00582 if (!rl_he) {
00583 return 0;
00584 }
00585 event_data = rl_he->line;
00586 } else {
00587 return -1;
00588 }
00589
00590 if (cmd[idx] != ':') {
00591 return -1;
00592 }
00593 cmd += idx + 1;
00594
00595
00596 if (*cmd == '^') {
00597 start = end = 1, cmd++;
00598 } else if (*cmd == '$') {
00599 start = end = -1, cmd++;
00600 } else if (*cmd == '*') {
00601 start = 1, end = -1, cmd++;
00602 } else if (isdigit((unsigned char) *cmd)) {
00603 const char* temp;
00604 int shifted = 0;
00605
00606 start = atoi(cmd);
00607 temp = cmd;
00608
00609 for ( ; isdigit((unsigned char) *cmd); cmd++) {
00610 }
00611
00612 if (temp != cmd) {
00613 shifted = 1;
00614 }
00615
00616 if (shifted && *cmd == '-') {
00617 if (!isdigit((unsigned char) *(cmd + 1))) {
00618 end = -2;
00619 } else {
00620 end = atoi(cmd + 1);
00621
00622 for ( ; isdigit((unsigned char) *cmd); cmd++) {
00623 }
00624 }
00625 } else if (shifted && *cmd == '*') {
00626 end = -1, cmd++;
00627 } else if (shifted) {
00628 end = start;
00629 }
00630 }
00631
00632 if (*cmd == ':') {
00633 cmd++;
00634 }
00635
00636 line = strdup(event_data);
00637
00638 for ( ; *cmd; cmd++) {
00639 if (*cmd == ':') {
00640 continue;
00641 } else if (*cmd == 'h') {
00642 gHistory_on = 1 | g_on, g_on = 0;
00643 } else if (*cmd == 't') {
00644 t_on = 1 | g_on, g_on = 0;
00645 } else if (*cmd == 'r') {
00646 r_on = 1 | g_on, g_on = 0;
00647 } else if (*cmd == 'e') {
00648 gEditLine_on = 1 | g_on, g_on = 0;
00649 } else if (*cmd == 'p') {
00650 p_on = 1 | g_on, g_on = 0;
00651 } else if (*cmd == 'g') {
00652 g_on = 2;
00653 } else if (*cmd == 's' || *cmd == '&') {
00654 char* what, * with, delim;
00655 size_t len, from_len;
00656 size_t size;
00657
00658 if (*cmd == '&' && (from == NULL || to == NULL)) {
00659 continue;
00660 } else if (*cmd == 's') {
00661 delim = *(++cmd), cmd++;
00662 size = 16;
00663 what = (char*) realloc(from, size);
00664 len = 0;
00665
00666 for ( ; *cmd && *cmd != delim; cmd++) {
00667 if (*cmd == '\\'
00668 && *(cmd + 1) == delim) {
00669 cmd++;
00670 }
00671
00672 if (len >= size) {
00673 what = (char*) realloc(what,
00674 (size <<= 1));
00675 }
00676 what[len++] = *cmd;
00677 }
00678 what[len] = '\0';
00679 from = what;
00680
00681 if (*what == '\0') {
00682 free(what);
00683
00684 if (search) {
00685 from = strdup(search);
00686 } else {
00687 from = NULL;
00688 free(line);
00689 return -1;
00690 }
00691 }
00692 cmd++;
00693
00694 if (!*cmd) {
00695 continue;
00696 }
00697
00698 size = 16;
00699 with = (char*) realloc(to, size);
00700 len = 0;
00701 from_len = strlen(from);
00702
00703 for ( ; *cmd && *cmd != delim; cmd++) {
00704 if (len + from_len + 1 >= size) {
00705 size += from_len + 1;
00706 with = (char*) realloc(with, size);
00707 }
00708
00709 if (*cmd == '&') {
00710
00711 (void) strcpy(&with[len], from);
00712 len += from_len;
00713 continue;
00714 }
00715
00716 if (*cmd == '\\'
00717 && (*(cmd + 1) == delim
00718 || *(cmd + 1) == '&')) {
00719 cmd++;
00720 }
00721 with[len++] = *cmd;
00722 }
00723 with[len] = '\0';
00724 to = with;
00725
00726 tempcmd = _rl_compat_sub(line, from, to,
00727 (g_on) ? 1 : 0);
00728 free(line);
00729 line = tempcmd;
00730 g_on = 0;
00731 }
00732 }
00733 }
00734
00735 arr = history_tokenize(line);
00736 free(line);
00737
00738 if (arr && *arr == NULL) {
00739 free(arr), arr = NULL;
00740 }
00741
00742 if (!arr) {
00743 return -1;
00744 }
00745
00746
00747 max = 0;
00748
00749 for (i = 0; arr[i]; i++) {
00750 max++;
00751 }
00752 max--;
00753
00754
00755 if (start < 0) {
00756 start = 1;
00757 }
00758
00759 if (end < 0) {
00760 end = max - ((end < -1) ? 1 : 0);
00761 }
00762
00763
00764 if (start > max || end > max || start > end) {
00765 free(arr);
00766 return -1;
00767 }
00768
00769 for (i = 0; i <= max; i++) {
00770 char* temp;
00771
00772 if (gHistory_on && (i == 1 || gHistory_on > 1) &&
00773 (temp = strrchr(arr[i], '/'))) {
00774 *(temp + 1) = '\0';
00775 }
00776
00777 if (t_on && (i == 1 || t_on > 1) &&
00778 (temp = strrchr(arr[i], '/'))) {
00779 (void) strcpy(arr[i], temp + 1);
00780 }
00781
00782 if (r_on && (i == 1 || r_on > 1) &&
00783 (temp = strrchr(arr[i], '.'))) {
00784 *temp = '\0';
00785 }
00786
00787 if (gEditLine_on && (i == 1 || gEditLine_on > 1) &&
00788 (temp = strrchr(arr[i], '.'))) {
00789 (void) strcpy(arr[i], temp);
00790 }
00791 }
00792
00793 cmdsize = 1, cmdlen = 0;
00794 tempcmd = (char*) malloc(cmdsize);
00795
00796 for (i = start; start <= i && i <= end; i++) {
00797 int arr_len;
00798
00799 arr_len = strlen(arr[i]);
00800
00801 if (cmdlen + arr_len + 1 >= cmdsize) {
00802 cmdsize += arr_len + 1;
00803 tempcmd = (char*) realloc(tempcmd, cmdsize);
00804 }
00805 (void) strcpy(&tempcmd[cmdlen], arr[i]);
00806 cmdlen += arr_len;
00807 tempcmd[cmdlen++] = ' ';
00808 }
00809
00810 while (cmdlen > 0 && isspace((unsigned char) tempcmd[cmdlen - 1]))
00811 cmdlen--;
00812 tempcmd[cmdlen] = '\0';
00813
00814 *result = tempcmd;
00815
00816 for (i = 0; i <= max; i++) {
00817 free(arr[i]);
00818 }
00819 free(arr), arr = (char**) NULL;
00820 return (p_on) ? 2 : 1;
00821 }
00822 #endif
00823
00824
00825
00826
00827 #ifdef EL_HISTORY_EXPAND
00828 int
00829 history_expand(char* str, char** output) {
00830 int i, retval = 0, idx;
00831 size_t size;
00832 char* temp, * result;
00833
00834 if (gHistory == NULL || gEditLine == NULL) {
00835 rl_initialize();
00836 }
00837
00838 *output = strdup(str);
00839
00840 if (str[0] == history_subst_char) {
00841
00842 temp = (char*) alloca(4 + strlen(str) + 1);
00843 temp[0] = temp[1] = history_expansion_char;
00844 temp[2] = ':';
00845 temp[3] = 's';
00846 (void) strcpy(temp + 4, str);
00847 str = temp;
00848 }
00849 #define ADD_STRING(what, len) \
00850 { \
00851 if (idx + len + 1 > size) { \
00852 result = (char*) realloc(result, (size += len + 1)); } \
00853 (void) strncpy(&result[idx], what, len); \
00854 idx += len; \
00855 result[idx] = '\0'; \
00856 }
00857
00858 result = NULL;
00859 size = idx = 0;
00860
00861 for (i = 0; str[i];) {
00862 int start, j, loop_again;
00863 size_t len;
00864
00865 loop_again = 1;
00866 start = j = i;
00867 loop:
00868
00869 for ( ; str[j]; j++) {
00870 if (str[j] == '\\' &&
00871 str[j + 1] == history_expansion_char) {
00872 (void) strcpy(&str[j], &str[j + 1]);
00873 continue;
00874 }
00875
00876 if (!loop_again) {
00877 if (str[j] == '?') {
00878 while (str[j] && str[++j] != '?')
00879 ;
00880
00881 if (str[j] == '?') {
00882 j++;
00883 }
00884 } else if (isspace((unsigned char) str[j])) {
00885 break;
00886 }
00887 }
00888
00889 if (str[j] == history_expansion_char
00890 && !strchr(history_no_expand_chars, str[j + 1])
00891 && (!history_inhibit_expansion_function ||
00892 (*history_inhibit_expansion_function)(str, j) == 0)) {
00893 break;
00894 }
00895 }
00896
00897 if (str[j] && str[j + 1] != '#' && loop_again) {
00898 i = j;
00899 j++;
00900
00901 if (str[j] == history_expansion_char) {
00902 j++;
00903 }
00904 loop_again = 0;
00905 goto loop;
00906 }
00907 len = i - start;
00908 temp = &str[start];
00909 ADD_STRING(temp, len);
00910
00911 if (str[i] == '\0' || str[i] != history_expansion_char
00912 || str[i + 1] == '#') {
00913 len = j - i;
00914 temp = &str[i];
00915 ADD_STRING(temp, len);
00916
00917 if (start == 0) {
00918 retval = 0;
00919 } else {
00920 retval = 1;
00921 }
00922 break;
00923 }
00924 retval = _history_expand_command(&str[i], (size_t) (j - i),
00925 &temp);
00926
00927 if (retval != -1) {
00928 len = strlen(temp);
00929 ADD_STRING(temp, len);
00930 }
00931 i = j;
00932 }
00933
00934 if (retval == 2) {
00935 add_history(temp);
00936 #ifdef GDB_411_HACK
00937
00938
00939
00940
00941 retval = -1;
00942 #endif
00943 }
00944 free(*output);
00945 *output = result;
00946
00947 return retval;
00948 }
00949 #endif
00950
00951
00952
00953
00954 char**
00955 history_tokenize(const char* str) {
00956 int size = 1, result_idx = 0, i, start;
00957 size_t len;
00958 char** result = NULL, * temp, delim = '\0';
00959
00960 for (i = 0; str[i]; i++) {
00961 while (isspace((unsigned char) str[i]))
00962 i++;
00963 start = i;
00964
00965 for ( ; str[i]; i++) {
00966 if (str[i] == '\\') {
00967 if (str[i + 1] != '\0') {
00968 i++;
00969 }
00970 } else if (str[i] == delim) {
00971 delim = '\0';
00972 } else if (!delim &&
00973 (isspace((unsigned char) str[i]) ||
00974 strchr("()<>;&|$", str[i]))) {
00975 break;
00976 } else if (!delim && strchr("'`\"", str[i])) {
00977 delim = str[i];
00978 }
00979 }
00980
00981 if (result_idx + 2 >= size) {
00982 size <<= 1;
00983 result = (char**) realloc(result, size * sizeof(char*));
00984 }
00985 len = i - start;
00986 temp = (char*) malloc(len + 1);
00987 (void) strncpy(temp, &str[start], len);
00988 temp[len] = '\0';
00989 result[result_idx++] = temp;
00990 result[result_idx] = NULL;
00991 }
00992
00993 return result;
00994 }
00995
00996
00997
00998
00999
01000 void
01001 stifle_history(int max) {
01002 HistEvent_t ev;
01003
01004 if (gHistory == NULL || gEditLine == NULL) {
01005 rl_initialize();
01006 }
01007
01008 if (history(gHistory, &ev, H_SETSIZE, max) == 0) {
01009 max_input_history = max;
01010 }
01011 }
01012
01013
01014
01015
01016
01017 int
01018 unstifle_history(void) {
01019 HistEvent_t ev;
01020 int omax;
01021
01022 history(gHistory, &ev, H_SETSIZE, INT_MAX);
01023 omax = max_input_history;
01024 max_input_history = INT_MAX;
01025 return omax;
01026 }
01027
01028
01029 int
01030 history_is_stifled(void) {
01031
01032 return max_input_history != INT_MAX;
01033 }
01034
01035
01036
01037
01038
01039 int
01040 read_history(const char* filename) {
01041 HistEvent_t ev;
01042
01043 if (gHistory == NULL || gEditLine == NULL) {
01044 rl_initialize();
01045 }
01046 return history(gHistory, &ev, H_LOAD, filename);
01047 }
01048
01049
01050
01051
01052
01053 int
01054 write_history(const char* filename) {
01055 HistEvent_t ev;
01056
01057 if (gHistory == NULL || gEditLine == NULL) {
01058 rl_initialize();
01059 }
01060 return history(gHistory, &ev, H_SAVE, filename);
01061 }
01062
01063
01064
01065
01066
01067
01068
01069 HIST_ENTRY*
01070 history_get(int num) {
01071 static HIST_ENTRY she;
01072 HistEvent_t ev;
01073 int i = 1, curr_num;
01074
01075 if (gHistory == NULL || gEditLine == NULL) {
01076 rl_initialize();
01077 }
01078
01079
01080 if (history(gHistory, &ev, H_CURR) != 0) {
01081 return NULL;
01082 }
01083 curr_num = ev.fNum;
01084
01085 if (history(gHistory, &ev, H_LAST) != 0) {
01086 return NULL;
01087 }
01088
01089 while (i < num && history(gHistory, &ev, H_PREV) == 0)
01090 i++;
01091
01092 if (i != num) {
01093 return NULL;
01094
01095 }
01096 she.line = ev.fStr;
01097 she.data = NULL;
01098
01099
01100 (void) history(gHistory, &ev, H_FIRST);
01101 (void) history(gHistory, &ev, H_NEXT_EVENT, curr_num);
01102
01103 return &she;
01104 }
01105
01106
01107
01108
01109
01110 int
01111 add_history(char* line) {
01112 HistEvent_t ev;
01113
01114 if (gHistory == NULL || gEditLine == NULL) {
01115 rl_initialize();
01116 }
01117
01118 size_t len = strlen(line);
01119 char oldlast = line[len - 1];
01120
01121 if (oldlast == '\n') {
01122
01123 line[len - 1] = 0;
01124 }
01125
01126 if (line[0]) {
01127
01128 (void) history(gHistory, &ev, H_ENTER, line);
01129
01130 if (history(gHistory, &ev, H_GETSIZE) == 0) {
01131 history_length = ev.fNum;
01132 }
01133 }
01134 line[len - 1] = oldlast;
01135
01136 return !(history_length > 0);
01137 }
01138
01139
01140
01141
01142
01143 void
01144 clear_history(void) {
01145 HistEvent_t ev;
01146
01147 history(gHistory, &ev, H_CLEAR);
01148 }
01149
01150
01151
01152
01153
01154 int
01155 where_history(void) {
01156 HistEvent_t ev;
01157 int curr_num, off;
01158
01159 if (history(gHistory, &ev, H_CURR) != 0) {
01160 return 0;
01161 }
01162 curr_num = ev.fNum;
01163
01164 history(gHistory, &ev, H_FIRST);
01165 off = 1;
01166
01167 while (ev.fNum != curr_num && history(gHistory, &ev, H_NEXT) == 0)
01168 off++;
01169
01170 return off;
01171 }
01172
01173
01174
01175
01176
01177 HIST_ENTRY*
01178 current_history(void) {
01179 return _move_history(H_CURR);
01180 }
01181
01182
01183
01184
01185
01186 int
01187 history_total_bytes(void) {
01188 HistEvent_t ev;
01189 int curr_num, size;
01190
01191 if (history(gHistory, &ev, H_CURR) != 0) {
01192 return -1;
01193 }
01194 curr_num = ev.fNum;
01195
01196 history(gHistory, &ev, H_FIRST);
01197 size = 0;
01198
01199 do {
01200 size += strlen(ev.fStr);
01201 }
01202 while (history(gHistory, &ev, H_NEXT) == 0);
01203
01204
01205 history(gHistory, &ev, H_PREV_EVENT, curr_num);
01206
01207 return size;
01208 }
01209
01210
01211
01212
01213
01214 int
01215 history_set_pos(int pos) {
01216 HistEvent_t ev;
01217 int off, curr_num;
01218
01219 if (pos > history_length || pos < 0) {
01220 return -1;
01221 }
01222
01223 history(gHistory, &ev, H_CURR);
01224 curr_num = ev.fNum;
01225 history(gHistory, &ev, H_FIRST);
01226 off = 0;
01227
01228 while (off < pos && history(gHistory, &ev, H_NEXT) == 0)
01229 off++;
01230
01231 if (off != pos) {
01232 history(gHistory, &ev, H_FIRST);
01233 history(gHistory, &ev, H_NEXT_EVENT, curr_num);
01234 return -1;
01235 }
01236 return 0;
01237 }
01238
01239
01240
01241
01242
01243 HIST_ENTRY*
01244 previous_history(void) {
01245 return _move_history(H_PREV);
01246 }
01247
01248
01249
01250
01251
01252 HIST_ENTRY*
01253 next_history(void) {
01254 return _move_history(H_NEXT);
01255 }
01256
01257
01258
01259
01260
01261 static int
01262 _history_search_gen(const char* str, int direction, int pos) {
01263 HistEvent_t ev;
01264 const char* strp;
01265 int curr_num;
01266
01267 if (history(gHistory, &ev, H_CURR) != 0) {
01268 return -1;
01269 }
01270 curr_num = ev.fNum;
01271
01272 for ( ; ;) {
01273 strp = strstr(ev.fStr, str);
01274
01275 if (strp && (pos < 0 || &ev.fStr[pos] == strp)) {
01276 return (int) (strp - ev.fStr);
01277 }
01278
01279 if (history(gHistory, &ev, direction < 0 ? H_PREV : H_NEXT) != 0) {
01280 break;
01281 }
01282 }
01283
01284 history(gHistory, &ev, direction < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num);
01285
01286 return -1;
01287 }
01288
01289
01290
01291
01292
01293 int
01294 history_search(const char* str, int direction) {
01295 return _history_search_gen(str, direction, -1);
01296 }
01297
01298
01299
01300
01301
01302 int
01303 history_search_prefix(const char* str, int direction) {
01304 return _history_search_gen(str, direction, 0);
01305 }
01306
01307
01308
01309
01310
01311
01312
01313 int
01314 history_search_pos(const char* str, int , int pos) {
01315 HistEvent_t ev;
01316 int curr_num, off;
01317
01318 off = (pos > 0) ? pos : -pos;
01319 pos = (pos > 0) ? 1 : -1;
01320
01321 if (history(gHistory, &ev, H_CURR) != 0) {
01322 return -1;
01323 }
01324 curr_num = ev.fNum;
01325
01326 if (history_set_pos(off) != 0 || history(gHistory, &ev, H_CURR) != 0) {
01327 return -1;
01328 }
01329
01330 for ( ; ;) {
01331 if (strstr(ev.fStr, str)) {
01332 return off;
01333 }
01334
01335 if (history(gHistory, &ev, (pos < 0) ? H_PREV : H_NEXT) != 0) {
01336 break;
01337 }
01338 }
01339
01340
01341 history(gHistory, &ev, (pos < 0) ? H_NEXT_EVENT : H_PREV_EVENT, curr_num);
01342
01343 return -1;
01344 }
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357 char*
01358 tilde_expand(char* txt) {
01359 struct passwd* pass;
01360 char* temp;
01361 size_t len = 0;
01362
01363 if (txt[0] != '~') {
01364 return strdup(txt);
01365 }
01366
01367 temp = strchr(txt + 1, '/');
01368
01369 if (temp == NULL) {
01370 temp = strdup(txt + 1);
01371 } else {
01372 len = temp - txt + 1;
01373 temp = (char*) malloc(len);
01374 (void) strncpy(temp, txt + 1, len - 2);
01375 temp[len - 2] = '\0';
01376 }
01377 pass = getpwnam(temp);
01378 free(temp);
01379
01380 if (pass == NULL) {
01381 return strdup(txt);
01382 }
01383
01384
01385
01386 txt += len;
01387
01388 temp = (char*) malloc(strlen(pass->pw_dir) + 1 + strlen(txt) + 1);
01389 (void) sprintf(temp, "%s/%s", pass->pw_dir, txt);
01390
01391 return temp;
01392 }
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402 char*
01403 filename_completion_function(const char* text, int state) {
01404 static DIR* dir = NULL;
01405 static char* filename = NULL, * dirname = NULL;
01406 static size_t filename_len = 0;
01407 struct dirent* entry;
01408 char* temp;
01409 size_t len;
01410
01411 if (state == 0 || dir == NULL) {
01412 if (dir != NULL) {
01413 closedir(dir);
01414 dir = NULL;
01415 }
01416 temp = strrchr((char*)text, '/');
01417
01418 if (temp) {
01419 temp++;
01420 filename = (char*) realloc(filename, strlen(temp) + 1);
01421 (void) strcpy(filename, temp);
01422 len = temp - text;
01423 dirname = (char*) realloc(dirname, len + 1);
01424 (void) strncpy(dirname, text, len);
01425 dirname[len] = '\0';
01426 } else {
01427 filename = strdup(text);
01428 dirname = NULL;
01429 }
01430
01431
01432 if (dirname && *dirname == '~') {
01433 temp = tilde_expand(dirname);
01434 dirname = (char*) realloc(dirname, strlen(temp) + 1);
01435 (void) strcpy(dirname, temp);
01436 free(temp);
01437 }
01438
01439 filename_len = strlen(filename);
01440
01441 if (filename_len == 0) {
01442 return NULL;
01443
01444 }
01445 dir = opendir(dirname ? dirname : ".");
01446
01447 if (!dir) {
01448 return NULL;
01449 }
01450 }
01451
01452
01453 while ((entry = readdir(dir)) != NULL) {
01454
01455
01456 if (entry->d_name[0] == filename[0]
01457 #if defined(__SVR4) || defined(__linux__) || defined(__CYGWIN__)
01458 && strlen(entry->d_name) >= filename_len
01459 #else
01460 && entry->d_namlen >= filename_len
01461 #endif
01462 && strncmp(entry->d_name, filename,
01463 filename_len) == 0) {
01464 break;
01465 }
01466 }
01467
01468 if (entry) {
01469 struct stat stbuf;
01470 #if defined(__SVR4) || defined(__linux__) || defined(__CYGWIN__)
01471 len = strlen(entry->d_name) +
01472 #else
01473 len = entry->d_namlen +
01474 #endif
01475 ((dirname) ? strlen(dirname) : 0) + 1 + 1;
01476 temp = (char*) malloc(len);
01477 (void) sprintf(temp, "%s%s",
01478 dirname ? dirname : "", entry->d_name);
01479
01480
01481 if (stat(temp, &stbuf) == 0 && S_ISDIR(stbuf.st_mode)) {
01482 strcat(temp, "/");
01483 }
01484 } else {
01485 temp = NULL;
01486 }
01487
01488 return temp;
01489 }
01490
01491
01492
01493
01494
01495
01496
01497
01498
01499 char*
01500 username_completion_function(const char* text, int state) {
01501 struct passwd* pwd;
01502
01503 if (text[0] == '\0') {
01504 return NULL;
01505 }
01506
01507 if (*text == '~') {
01508 text++;
01509 }
01510
01511 if (state == 0) {
01512 setpwent();
01513 }
01514
01515 while ((pwd = getpwent()) && text[0] == pwd->pw_name[0]
01516 && strcmp(text, pwd->pw_name) == 0)
01517 ;
01518
01519 if (pwd == NULL) {
01520 endpwent();
01521 return NULL;
01522 }
01523 return strdup(pwd->pw_name);
01524 }
01525
01526
01527
01528
01529
01530
01531 static unsigned char
01532 _el_rl_complete(EditLine_t* , int ch) {
01533 return (unsigned char) rl_complete(0, ch);
01534 }
01535
01536
01537
01538
01539
01540 char**
01541 completion_matches(const char* text, CPFunction* genfunc) {
01542 char** match_list = NULL, * retstr, * prevstr;
01543 size_t match_list_len, max_equal, which, i;
01544 size_t matches;
01545
01546 if (gHistory == NULL || gEditLine == NULL) {
01547 rl_initialize();
01548 }
01549
01550 matches = 0;
01551 match_list_len = 1;
01552
01553 while ((retstr = (*genfunc)(text, matches)) != NULL) {
01554 if (matches + 1 >= match_list_len) {
01555 match_list_len <<= 1;
01556 match_list = (char**) realloc(match_list,
01557 match_list_len * sizeof(char*));
01558 }
01559 match_list[++matches] = retstr;
01560 }
01561
01562 if (!match_list) {
01563 return (char**) NULL;
01564
01565 }
01566
01567 which = 2;
01568 prevstr = match_list[1];
01569 max_equal = strlen(prevstr);
01570
01571 for ( ; which <= matches; which++) {
01572 for (i = 0; i < max_equal &&
01573 prevstr[i] == match_list[which][i]; i++) {
01574 continue;
01575 }
01576 max_equal = i;
01577 }
01578
01579 retstr = (char*) malloc(max_equal + 1);
01580 (void) strncpy(retstr, match_list[1], max_equal);
01581 retstr[max_equal] = '\0';
01582 match_list[0] = retstr;
01583
01584
01585 if (matches + 1 >= match_list_len) {
01586 match_list = (char**) realloc(match_list,
01587 (match_list_len + 1) * sizeof(char*));
01588 }
01589 match_list[matches + 1] = (char*) NULL;
01590
01591 return match_list;
01592 }
01593
01594
01595
01596
01597
01598 static int
01599 _rl_qsort_string_compare(const void* i1, const void* i2) {
01600
01601 const char* s1 = ((const char**) i1)[0];
01602
01603 const char* s2 = ((const char**) i2)[0];
01604
01605 return strcasecmp(s1, s2);
01606 }
01607
01608
01609
01610
01611
01612
01613
01614 void
01615 rl_display_match_list(char** matches, int len, int max) {
01616 int i, idx, limit, count;
01617 int screenwidth = gEditLine->fTerm.fSize.fH;
01618
01619
01620
01621
01622
01623 limit = screenwidth / (max + 2);
01624
01625 if (limit == 0) {
01626 limit = 1;
01627 }
01628
01629
01630 count = len / limit;
01631
01632 if (count * limit < len) {
01633 count++;
01634 }
01635
01636
01637 qsort(&matches[1], (size_t) (len - 1), sizeof(char*),
01638 _rl_qsort_string_compare);
01639
01640 idx = 1;
01641
01642 for ( ; count > 0; count--) {
01643 for (i = 0; i < limit && matches[idx]; i++, idx++) {
01644 fprintf(gEditLine->fOutFile, "%-*s ", max, matches[idx]);
01645 }
01646 fprintf(gEditLine->fOutFile, "\n");
01647 }
01648 }
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662 static int
01663 rl_complete_internal(int what_to_do) {
01664 CPFunction* complet_func;
01665 const LineInfo_t* li;
01666 char* temp, ** matches;
01667 const char* ctemp;
01668 size_t len;
01669
01670 if (rl_tab_hook) {
01671 int cursorIdx = gEditLine->fLine.fCursor - gEditLine->fLine.fBuffer;
01672 char old = *gEditLine->fLine.fCursor;
01673 *gEditLine->fLine.fCursor = 0;
01674 term__setcolor(tab_color);
01675 int loc = rl_tab_hook(gEditLine->fLine.fBuffer, 0, &cursorIdx);
01676 term__resetcolor();
01677
01678 if (loc >= 0 || loc == -2 || cursorIdx != gEditLine->fLine.fCursor - gEditLine->fLine.fBuffer) {
01679 size_t lenbuf = strlen(gEditLine->fLine.fBuffer);
01680 gEditLine->fLine.fBuffer[lenbuf] = old;
01681 gEditLine->fLine.fBuffer[lenbuf + 1] = 0;
01682
01683 for (int i = gEditLine->fLine.fCursor - gEditLine->fLine.fBuffer; i < cursorIdx; ++i) {
01684 gEditLine->fLine.fBufColor[i] = -1;
01685 }
01686 gEditLine->fLine.fCursor = gEditLine->fLine.fBuffer + cursorIdx;
01687 gEditLine->fLine.fLastChar = gEditLine->fLine.fCursor;
01688
01689 if (loc == -2) {
01690
01691 re_clear_display(gEditLine);
01692 }
01693 re_refresh(gEditLine);
01694 } else {
01695 *gEditLine->fLine.fCursor = old;
01696 }
01697 return CC_NORM;
01698 }
01699
01700 rl_completion_type = what_to_do;
01701
01702 if (gHistory == NULL || gEditLine == NULL) {
01703 rl_initialize();
01704 }
01705
01706 complet_func = rl_completion_entry_function;
01707
01708 if (!complet_func) {
01709 complet_func = filename_completion_function;
01710 }
01711
01712
01713 li = el_line(gEditLine);
01714 ctemp = (const char*) li->fCursor;
01715
01716 while (ctemp > li->fBuffer
01717 && !strchr(rl_basic_word_break_characters, ctemp[-1])
01718 && (!rl_special_prefixes
01719 || !strchr(rl_special_prefixes, ctemp[-1])))
01720 ctemp--;
01721
01722 len = li->fCursor - ctemp;
01723 temp = (char*) alloca(len + 1);
01724 (void) strncpy(temp, ctemp, len);
01725 temp[len] = '\0';
01726
01727
01728
01729 rl_point = li->fCursor - li->fBuffer;
01730 rl_end = li->fLastChar - li->fBuffer;
01731
01732 if (!rl_attempted_completion_function) {
01733 matches = completion_matches(temp, complet_func);
01734 } else {
01735 int end = li->fCursor - li->fBuffer;
01736 matches = (*rl_attempted_completion_function)(temp, (int)
01737 (end - len), end);
01738 }
01739
01740 if (matches) {
01741 int i, retval = CC_REFRESH;
01742 int matches_num, maxlen, match_len, match_display = 1;
01743
01744
01745
01746
01747
01748 if (matches[0][0] != '\0') {
01749 el_deletestr(gEditLine, (int) len);
01750 el_insertstr(gEditLine, matches[0]);
01751 }
01752
01753 if (what_to_do == '?') {
01754 goto display_matches;
01755 }
01756
01757 if (matches[2] == NULL && strcmp(matches[0], matches[1]) == 0) {
01758
01759
01760
01761
01762
01763 size_t alen = strlen(matches[0]);
01764
01765 if ((complet_func != filename_completion_function
01766 || (alen > 0 && (matches[0])[alen - 1] != '/'))
01767 && rl_completion_append_character) {
01768 char buf[2];
01769 buf[0] = rl_completion_append_character;
01770 buf[1] = '\0';
01771 el_insertstr(gEditLine, buf);
01772 }
01773 } else if (what_to_do == '!') {
01774 display_matches:
01775
01776
01777
01778
01779
01780
01781 for (i = 1, maxlen = 0; matches[i]; i++) {
01782 match_len = strlen(matches[i]);
01783
01784 if (match_len > maxlen) {
01785 maxlen = match_len;
01786 }
01787 }
01788 matches_num = i - 1;
01789
01790
01791 fprintf(gEditLine->fOutFile, "\n");
01792
01793
01794
01795
01796
01797 if (matches_num > rl_completion_query_items) {
01798 fprintf(gEditLine->fOutFile,
01799 "Display all %d possibilities? (y or n) ",
01800 matches_num);
01801 fflush(gEditLine->fOutFile);
01802
01803 if (getc(stdin) != 'y') {
01804 match_display = 0;
01805 }
01806 fprintf(gEditLine->fOutFile, "\n");
01807 }
01808
01809 if (match_display) {
01810 rl_display_match_list(matches, matches_num,
01811 maxlen);
01812 }
01813 retval = CC_REDISPLAY;
01814 } else if (matches[0][0]) {
01815
01816
01817
01818
01819
01820 el_beep(gEditLine);
01821 } else {
01822
01823
01824 el_beep(gEditLine);
01825 retval = CC_NORM;
01826 }
01827
01828
01829 for (i = 0; matches[i]; i++) {
01830 free(matches[i]);
01831 }
01832 free(matches), matches = NULL;
01833
01834 return retval;
01835 }
01836 return CC_NORM;
01837 }
01838
01839
01840
01841
01842
01843 int
01844 rl_complete(int ignore, int invoking_key) {
01845 if (gHistory == NULL || gEditLine == NULL) {
01846 rl_initialize();
01847 }
01848
01849 if (rl_inhibit_completion) {
01850 rl_insert(ignore, invoking_key);
01851 return CC_REFRESH;
01852 } else if (gEditLine->fState.fLastCmd == gel_rl_complete_cmdnum) {
01853 return rl_complete_internal('?');
01854 } else if (grl_complete_show_all) {
01855 return rl_complete_internal('!');
01856 } else {
01857 return rl_complete_internal(TAB);
01858 }
01859 }
01860
01861
01862
01863
01864
01865
01866
01867
01868
01869 int
01870 rl_bind_key(int c, int func(int, int)) {
01871 int retval = -1;
01872
01873 if (gHistory == NULL || gEditLine == NULL) {
01874 rl_initialize();
01875 }
01876
01877 if (func == rl_insert) {
01878
01879 gEditLine->fMap.fKey[c] = ED_INSERT;
01880 retval = 0;
01881 }
01882 return retval;
01883 }
01884
01885
01886
01887
01888
01889
01890 int
01891 rl_read_key(void) {
01892 char fooarr[2 * sizeof(int)];
01893
01894 if (gEditLine == NULL || gHistory == NULL) {
01895 rl_initialize();
01896 }
01897
01898 return el_getc(gEditLine, fooarr);
01899 }
01900
01901
01902
01903
01904
01905
01906 void
01907 rl_reset_terminal(void) {
01908 if (gHistory == NULL || gEditLine == NULL) {
01909 rl_initialize();
01910 }
01911 el_reset(gEditLine);
01912 }
01913
01914
01915
01916
01917
01918 int
01919 rl_insert(int count, int c) {
01920 char arr[2];
01921
01922 if (gHistory == NULL || gEditLine == NULL) {
01923 rl_initialize();
01924 }
01925
01926
01927 arr[0] = c;
01928 arr[1] = '\0';
01929
01930 for ( ; count > 0; count--) {
01931 el_push(gEditLine, arr);
01932 }
01933
01934 return 0;
01935 }
01936
01937
01938 EditLine_t*
01939 el_readline_el() {
01940 if (NULL == gEditLine) {
01941 rl_initialize();
01942 }
01943 return gEditLine;
01944 }
01945
01946
01947 int
01948 rl_eof() {
01949 return el_eof(gEditLine);
01950 }