00001
00002
00003
00004
00005 #include "editline.h"
00006 #include <signal.h>
00007 #include <ctype.h>
00008
00009
00010
00011
00012 #define SCREEN_WIDTH 80
00013 #define SCREEN_ROWS 24
00014 #define NO_ARG (-1)
00015 #define DEL 127
00016 #define CTL(x) ((x) & 0x1F)
00017 #define ISCTL(x) ((x) && (x) < ' ')
00018 #define UNCTL(x) ((x) + 64)
00019 #define META(x) ((x) | 0x80)
00020 #define ISMETA(x) ((x) & 0x80)
00021 #define UNMETA(x) ((x) & 0x7F)
00022 #if !defined(HIST_SIZE)
00023 #define HIST_SIZE 20
00024 #endif
00025
00026
00027
00028
00029 typedef enum _STATUS {
00030 CSdone, CSeof, CSmove, CSdispatch, CSstay, CSsignal
00031 } STATUS;
00032
00033
00034
00035
00036 typedef enum _CASE {
00037 TOupper, TOlower
00038 } CASE;
00039
00040
00041
00042
00043 typedef struct _KEYMAP {
00044 CHAR Key;
00045 STATUS (*Function)();
00046 } KEYMAP;
00047
00048
00049
00050
00051 typedef struct _HISTORY {
00052 int Size;
00053 int Pos;
00054 CHAR *Lines[HIST_SIZE];
00055 } HISTORY;
00056
00057
00058
00059
00060 int rl_eof;
00061 int rl_erase;
00062 int rl_intr;
00063 int rl_kill;
00064 int rl_quit;
00065
00066 STATIC CHAR NIL[] = "";
00067 STATIC CONST CHAR *Input = NIL;
00068 STATIC CHAR *Line;
00069 STATIC CONST char *Prompt;
00070 STATIC CHAR *Yanked;
00071 STATIC char *Screen;
00072 STATIC char NEWLINE[]= CRLF;
00073 STATIC HISTORY H;
00074 STATIC int Repeat;
00075 STATIC int End;
00076 STATIC int Mark;
00077 STATIC int OldPoint;
00078 STATIC int Point;
00079 STATIC int PushBack;
00080 STATIC int Pushed;
00081 STATIC int Signal;
00082 FORWARD KEYMAP Map[33];
00083 FORWARD KEYMAP MetaMap[17];
00084 STATIC SIZE_T Length;
00085 STATIC SIZE_T ScreenCount;
00086 STATIC SIZE_T ScreenSize;
00087 STATIC char *backspace;
00088 STATIC int TTYwidth;
00089 STATIC int TTYrows;
00090
00091
00092 int rl_meta_chars = 0;
00093
00094
00095
00096
00097 STATIC CHAR *editinput();
00098 extern int read();
00099 extern int write();
00100 #if defined(USE_TERMCAP)
00101 extern char *getenv();
00102 extern char *tgetstr();
00103 extern int tgetent();
00104 #endif
00105
00106
00107
00108
00109
00110 STATIC void
00111 TTYflush()
00112 {
00113 if (ScreenCount) {
00114 (void)write(1, Screen, ScreenCount);
00115 ScreenCount = 0;
00116 }
00117 }
00118
00119 STATIC void
00120 TTYput(c)
00121 CHAR c;
00122 {
00123 Screen[ScreenCount] = c;
00124 if (++ScreenCount >= ScreenSize - 1) {
00125 ScreenSize += SCREEN_INC;
00126 RENEW(Screen, char, ScreenSize);
00127 }
00128 }
00129
00130 STATIC void
00131 TTYputs(p)
00132 CHAR *p;
00133 {
00134 while (*p)
00135 TTYput(*p++);
00136 }
00137
00138 STATIC void
00139 TTYshow(c)
00140 CHAR c;
00141 {
00142 if (c == DEL) {
00143 TTYput('^');
00144 TTYput('?');
00145 }
00146 else if (ISCTL(c)) {
00147 TTYput('^');
00148 TTYput(UNCTL(c));
00149 }
00150 else if (rl_meta_chars && ISMETA(c)) {
00151 TTYput('M');
00152 TTYput('-');
00153 TTYput(UNMETA(c));
00154 }
00155 else
00156 TTYput(c);
00157 }
00158
00159 STATIC void
00160 TTYstring(p)
00161 CHAR *p;
00162 {
00163 while (*p)
00164 TTYshow(*p++);
00165 }
00166
00167 STATIC unsigned int
00168 TTYget()
00169 {
00170 CHAR c;
00171
00172 TTYflush();
00173 if (Pushed) {
00174 Pushed = 0;
00175 return PushBack;
00176 }
00177 if (*Input)
00178 return *Input++;
00179 return read(0, &c, (SIZE_T)1) == 1 ? c : EOF;
00180 }
00181
00182 #define TTYback() (backspace ? TTYputs((CHAR *)backspace) : TTYput('\b'))
00183
00184 STATIC void
00185 TTYbackn(n)
00186 int n;
00187 {
00188 while (--n >= 0)
00189 TTYback();
00190 }
00191
00192 STATIC void
00193 TTYinfo()
00194 {
00195 static int init;
00196 #if defined(USE_TERMCAP)
00197 char *term;
00198 char buff[2048];
00199 char *bp;
00200 #endif
00201 #if defined(TIOCGWINSZ)
00202 struct winsize W;
00203 #endif
00204
00205 if (init) {
00206 #if defined(TIOCGWINSZ)
00207
00208 if (ioctl(0, TIOCGWINSZ, &W) >= 0
00209 && W.ws_col > 0 && W.ws_row > 0) {
00210 TTYwidth = (int)W.ws_col;
00211 TTYrows = (int)W.ws_row;
00212 }
00213 #endif
00214 return;
00215 }
00216 init++;
00217
00218 TTYwidth = TTYrows = 0;
00219 #if defined(USE_TERMCAP)
00220 bp = &buff[0];
00221 if ((term = getenv("TERM")) == NULL)
00222 term = "dumb";
00223 if (tgetent(buff, term) < 0) {
00224 TTYwidth = SCREEN_WIDTH;
00225 TTYrows = SCREEN_ROWS;
00226 return;
00227 }
00228 if ((backspace = tgetstr("le", &bp)) != NULL)
00229 backspace = strdup(backspace);
00230 TTYwidth = tgetnum("co");
00231 TTYrows = tgetnum("li");
00232 #endif
00233
00234 #if defined(TIOCGWINSZ)
00235 if (ioctl(0, TIOCGWINSZ, &W) >= 0) {
00236 TTYwidth = (int)W.ws_col;
00237 TTYrows = (int)W.ws_row;
00238 }
00239 #endif
00240
00241 if (TTYwidth <= 0 || TTYrows <= 0) {
00242 TTYwidth = SCREEN_WIDTH;
00243 TTYrows = SCREEN_ROWS;
00244 }
00245 }
00246
00247
00248
00249
00250
00251 STATIC void
00252 columns(ac, av)
00253 int ac;
00254 CHAR **av;
00255 {
00256 CHAR *p;
00257 int i;
00258 int j;
00259 int k;
00260 int len;
00261 int skip;
00262 int longest;
00263 int cols;
00264
00265
00266 for (longest = 0, i = 0; i < ac; i++)
00267 if ((j = strlen((char *)av[i])) > longest)
00268 longest = j;
00269 cols = TTYwidth / (longest + 3);
00270
00271 TTYputs((CHAR *)NEWLINE);
00272 for (skip = ac / cols + 1, i = 0; i < skip; i++) {
00273 for (j = i; j < ac; j += skip) {
00274 for (p = av[j], len = strlen((char *)p), k = len; --k >= 0; p++)
00275 TTYput(*p);
00276 if (j + skip < ac)
00277 while (++len < longest + 3)
00278 TTYput(' ');
00279 }
00280 TTYputs((CHAR *)NEWLINE);
00281 }
00282 }
00283
00284 STATIC void
00285 reposition()
00286 {
00287 int i;
00288 CHAR *p;
00289
00290 TTYput('\r');
00291 TTYputs((CONST CHAR *)Prompt);
00292 for (i = Point, p = Line; --i >= 0; p++)
00293 TTYshow(*p);
00294 }
00295
00296 STATIC void
00297 left(Change)
00298 STATUS Change;
00299 {
00300 TTYback();
00301 if (Point) {
00302 if (ISCTL(Line[Point - 1]))
00303 TTYback();
00304 else if (rl_meta_chars && ISMETA(Line[Point - 1])) {
00305 TTYback();
00306 TTYback();
00307 }
00308 }
00309 if (Change == CSmove)
00310 Point--;
00311 }
00312
00313 STATIC void
00314 right(Change)
00315 STATUS Change;
00316 {
00317 TTYshow(Line[Point]);
00318 if (Change == CSmove)
00319 Point++;
00320 }
00321
00322 STATIC STATUS
00323 ring_bell()
00324 {
00325 TTYput('\07');
00326 TTYflush();
00327 return CSstay;
00328 }
00329
00330 STATIC STATUS
00331 do_macro(c)
00332 unsigned int c;
00333 {
00334 CHAR name[4];
00335
00336 name[0] = '_';
00337 name[1] = c;
00338 name[2] = '_';
00339 name[3] = '\0';
00340
00341 if ((Input = (CHAR *)getenv((char *)name)) == NULL) {
00342 Input = NIL;
00343 return ring_bell();
00344 }
00345 return CSstay;
00346 }
00347
00348 STATIC STATUS
00349 do_forward(move)
00350 STATUS move;
00351 {
00352 int i;
00353 CHAR *p;
00354
00355 i = 0;
00356 do {
00357 p = &Line[Point];
00358 for ( ; Point < End && (*p == ' ' || !isalnum(*p)); Point++, p++)
00359 if (move == CSmove)
00360 right(CSstay);
00361
00362 for (; Point < End && isalnum(*p); Point++, p++)
00363 if (move == CSmove)
00364 right(CSstay);
00365
00366 if (Point == End)
00367 break;
00368 } while (++i < Repeat);
00369
00370 return CSstay;
00371 }
00372
00373 STATIC STATUS
00374 do_case(type)
00375 CASE type;
00376 {
00377 int i;
00378 int end;
00379 int count;
00380 CHAR *p;
00381
00382 (void)do_forward(CSstay);
00383 if (OldPoint != Point) {
00384 if ((count = Point - OldPoint) < 0)
00385 count = -count;
00386 Point = OldPoint;
00387 if ((end = Point + count) > End)
00388 end = End;
00389 for (i = Point, p = &Line[i]; i < end; i++, p++) {
00390 if (type == TOupper) {
00391 if (islower(*p))
00392 *p = toupper(*p);
00393 }
00394 else if (isupper(*p))
00395 *p = tolower(*p);
00396 right(CSmove);
00397 }
00398 }
00399 return CSstay;
00400 }
00401
00402 STATIC STATUS
00403 case_down_word()
00404 {
00405 return do_case(TOlower);
00406 }
00407
00408 STATIC STATUS
00409 case_up_word()
00410 {
00411 return do_case(TOupper);
00412 }
00413
00414 STATIC void
00415 ceol()
00416 {
00417 int extras;
00418 int i;
00419 CHAR *p;
00420
00421 for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) {
00422 TTYput(' ');
00423 if (ISCTL(*p)) {
00424 TTYput(' ');
00425 extras++;
00426 }
00427 else if (rl_meta_chars && ISMETA(*p)) {
00428 TTYput(' ');
00429 TTYput(' ');
00430 extras += 2;
00431 }
00432 }
00433
00434 for (i += extras; i > Point; i--)
00435 TTYback();
00436 }
00437
00438 STATIC void
00439 clear_line()
00440 {
00441 Point = -strlen(Prompt);
00442 TTYput('\r');
00443 ceol();
00444 Point = 0;
00445 End = 0;
00446 Line[0] = '\0';
00447 }
00448
00449 STATIC STATUS
00450 insert_string(p)
00451 CHAR *p;
00452 {
00453 SIZE_T len;
00454 int i;
00455 CHAR *new;
00456 CHAR *q;
00457
00458 len = strlen((char *)p);
00459 if (End + len >= Length) {
00460 if ((new = NEW(CHAR, Length + len + MEM_INC)) == NULL)
00461 return CSstay;
00462 if (Length) {
00463 COPYFROMTO(new, Line, Length);
00464 DISPOSE(Line);
00465 }
00466 Line = new;
00467 Length += len + MEM_INC;
00468 }
00469
00470 for (q = &Line[Point], i = End - Point; --i >= 0; )
00471 q[len + i] = q[i];
00472 COPYFROMTO(&Line[Point], p, len);
00473 End += len;
00474 Line[End] = '\0';
00475 TTYstring(&Line[Point]);
00476 Point += len;
00477
00478 return Point == End ? CSstay : CSmove;
00479 }
00480
00481 STATIC STATUS
00482 redisplay()
00483 {
00484 TTYputs((CONST CHAR *)NEWLINE);
00485 TTYputs((CONST CHAR *)Prompt);
00486 TTYstring(Line);
00487 return CSmove;
00488 }
00489
00490 STATIC STATUS
00491 toggle_meta_mode()
00492 {
00493 rl_meta_chars = ! rl_meta_chars;
00494 return redisplay();
00495 }
00496
00497
00498 STATIC CHAR *
00499 next_hist()
00500 {
00501 return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];
00502 }
00503
00504 STATIC CHAR *
00505 prev_hist()
00506 {
00507 return H.Pos == 0 ? NULL : H.Lines[--H.Pos];
00508 }
00509
00510 STATIC STATUS
00511 do_insert_hist(p)
00512 CHAR *p;
00513 {
00514 if (p == NULL)
00515 return ring_bell();
00516 Point = 0;
00517 reposition();
00518 ceol();
00519 End = 0;
00520 return insert_string(p);
00521 }
00522
00523 STATIC STATUS
00524 do_hist(move)
00525 CHAR *(*move)();
00526 {
00527 CHAR *p;
00528 int i;
00529
00530 i = 0;
00531 do {
00532 if ((p = (*move)()) == NULL)
00533 return ring_bell();
00534 } while (++i < Repeat);
00535 return do_insert_hist(p);
00536 }
00537
00538 STATIC STATUS
00539 h_next()
00540 {
00541 return do_hist(next_hist);
00542 }
00543
00544 STATIC STATUS
00545 h_prev()
00546 {
00547 return do_hist(prev_hist);
00548 }
00549
00550 STATIC STATUS
00551 h_first()
00552 {
00553 return do_insert_hist(H.Lines[H.Pos = 0]);
00554 }
00555
00556 STATIC STATUS
00557 h_last()
00558 {
00559 return do_insert_hist(H.Lines[H.Pos = H.Size - 1]);
00560 }
00561
00562
00563
00564
00565 STATIC int
00566 substrcmp(text, pat, len)
00567 char *text;
00568 char *pat;
00569 int len;
00570 {
00571 char c;
00572
00573 if ((c = *pat) == '\0')
00574 return *text == '\0';
00575 for ( ; *text; text++)
00576 if (*text == c && strncmp(text, pat, len) == 0)
00577 return 0;
00578 return 1;
00579 }
00580
00581 STATIC CHAR *
00582 search_hist(search, move)
00583 CHAR *search;
00584 CHAR *(*move)();
00585 {
00586 static CHAR *old_search;
00587 int len;
00588 int pos;
00589 int (*match)();
00590 char *pat;
00591
00592
00593 if (search && *search) {
00594 if (old_search)
00595 DISPOSE(old_search);
00596 old_search = (CHAR *)strdup((char *)search);
00597 }
00598 else {
00599 if (old_search == NULL || *old_search == '\0')
00600 return NULL;
00601 search = old_search;
00602 }
00603
00604
00605 if (*search == '^') {
00606 match = strncmp;
00607 pat = (char *)(search + 1);
00608 }
00609 else {
00610 match = substrcmp;
00611 pat = (char *)search;
00612 }
00613 len = strlen(pat);
00614
00615 for (pos = H.Pos; (*move)() != NULL; )
00616 if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0)
00617 return H.Lines[H.Pos];
00618 H.Pos = pos;
00619 return NULL;
00620 }
00621
00622 STATIC STATUS
00623 h_search()
00624 {
00625 static int Searching;
00626 CONST char *old_prompt;
00627 CHAR *(*move)();
00628 CHAR *p;
00629
00630 if (Searching)
00631 return ring_bell();
00632 Searching = 1;
00633
00634 clear_line();
00635 old_prompt = Prompt;
00636 Prompt = "Search: ";
00637 TTYputs((CONST CHAR *)Prompt);
00638 move = Repeat == NO_ARG ? prev_hist : next_hist;
00639 p = editinput();
00640 Prompt = old_prompt;
00641 Searching = 0;
00642 TTYputs((CONST CHAR *)Prompt);
00643 if (p == NULL && Signal > 0) {
00644 Signal = 0;
00645 clear_line();
00646 return redisplay();
00647 }
00648 p = search_hist(p, move);
00649 clear_line();
00650 if (p == NULL) {
00651 (void)ring_bell();
00652 return redisplay();
00653 }
00654 return do_insert_hist(p);
00655 }
00656
00657 STATIC STATUS
00658 fd_char()
00659 {
00660 int i;
00661
00662 i = 0;
00663 do {
00664 if (Point >= End)
00665 break;
00666 right(CSmove);
00667 } while (++i < Repeat);
00668 return CSstay;
00669 }
00670
00671 STATIC void
00672 save_yank(begin, i)
00673 int begin;
00674 int i;
00675 {
00676 if (Yanked) {
00677 DISPOSE(Yanked);
00678 Yanked = NULL;
00679 }
00680
00681 if (i < 1)
00682 return;
00683
00684 if ((Yanked = NEW(CHAR, (SIZE_T)i + 1)) != NULL) {
00685 COPYFROMTO(Yanked, &Line[begin], i);
00686 Yanked[i] = '\0';
00687 }
00688 }
00689
00690 STATIC STATUS
00691 delete_string(count)
00692 int count;
00693 {
00694 int i;
00695 CHAR *p;
00696
00697 if (count <= 0 || End == Point)
00698 return ring_bell();
00699
00700 if (count == 1 && Point == End - 1) {
00701
00702 End--;
00703 p = &Line[Point];
00704 i = 1;
00705 TTYput(' ');
00706 if (ISCTL(*p)) {
00707 i = 2;
00708 TTYput(' ');
00709 }
00710 else if (rl_meta_chars && ISMETA(*p)) {
00711 i = 3;
00712 TTYput(' ');
00713 TTYput(' ');
00714 }
00715 TTYbackn(i);
00716 *p = '\0';
00717 return CSmove;
00718 }
00719 if (Point + count > End && (count = End - Point) <= 0)
00720 return CSstay;
00721
00722 if (count > 1)
00723 save_yank(Point, count);
00724
00725 for (p = &Line[Point], i = End - (Point + count) + 1; --i >= 0; p++)
00726 p[0] = p[count];
00727 ceol();
00728 End -= count;
00729 TTYstring(&Line[Point]);
00730 return CSmove;
00731 }
00732
00733 STATIC STATUS
00734 bk_char()
00735 {
00736 int i;
00737
00738 i = 0;
00739 do {
00740 if (Point == 0)
00741 break;
00742 left(CSmove);
00743 } while (++i < Repeat);
00744
00745 return CSstay;
00746 }
00747
00748 STATIC STATUS
00749 bk_del_char()
00750 {
00751 int i;
00752
00753 i = 0;
00754 do {
00755 if (Point == 0)
00756 break;
00757 left(CSmove);
00758 } while (++i < Repeat);
00759
00760 return delete_string(i);
00761 }
00762
00763 STATIC STATUS
00764 kill_line()
00765 {
00766 int i;
00767
00768 if (Repeat != NO_ARG) {
00769 if (Repeat < Point) {
00770 i = Point;
00771 Point = Repeat;
00772 reposition();
00773 (void)delete_string(i - Point);
00774 }
00775 else if (Repeat > Point) {
00776 right(CSmove);
00777 (void)delete_string(Repeat - Point - 1);
00778 }
00779 return CSmove;
00780 }
00781
00782 save_yank(Point, End - Point);
00783 Line[Point] = '\0';
00784 ceol();
00785 End = Point;
00786 return CSstay;
00787 }
00788
00789 STATIC STATUS
00790 insert_char(c)
00791 int c;
00792 {
00793 STATUS s;
00794 CHAR buff[2];
00795 CHAR *p;
00796 CHAR *q;
00797 int i;
00798
00799 if (Repeat == NO_ARG || Repeat < 2) {
00800 buff[0] = c;
00801 buff[1] = '\0';
00802 return insert_string(buff);
00803 }
00804
00805 if ((p = NEW(CHAR, Repeat + 1)) == NULL)
00806 return CSstay;
00807 for (i = Repeat, q = p; --i >= 0; )
00808 *q++ = c;
00809 *q = '\0';
00810 Repeat = 0;
00811 s = insert_string(p);
00812 DISPOSE(p);
00813 return s;
00814 }
00815
00816 STATIC STATUS
00817 meta()
00818 {
00819 unsigned int c;
00820 KEYMAP *kp;
00821
00822 if ((c = TTYget()) == EOF)
00823 return CSeof;
00824 #if defined(ANSI_ARROWS)
00825
00826 if (c == '[' || c == 'O')
00827 switch (c = TTYget()) {
00828 default: return ring_bell();
00829 case EOF: return CSeof;
00830 case 'A': return h_prev();
00831 case 'B': return h_next();
00832 case 'C': return fd_char();
00833 case 'D': return bk_char();
00834 }
00835 #endif
00836
00837 if (isdigit(c)) {
00838 for (Repeat = c - '0'; (c = TTYget()) != EOF && isdigit(c); )
00839 Repeat = Repeat * 10 + c - '0';
00840 Pushed = 1;
00841 PushBack = c;
00842 return CSstay;
00843 }
00844
00845 if (isupper(c))
00846 return do_macro(c);
00847 for (kp = MetaMap; kp->Function; kp++)
00848 if (kp->Key == c)
00849 return (*kp->Function)();
00850
00851 return ring_bell();
00852 }
00853
00854 STATIC STATUS
00855 emacs(c)
00856 unsigned int c;
00857 {
00858 STATUS s;
00859 KEYMAP *kp;
00860
00861 OldPoint = Point;
00862 if (rl_meta_chars && ISMETA(c)) {
00863 Pushed = 1;
00864 PushBack = UNMETA(c);
00865 return meta();
00866 }
00867 for (kp = Map; kp->Function; kp++)
00868 if (kp->Key == c)
00869 break;
00870 s = kp->Function ? (*kp->Function)() : insert_char((int)c);
00871 if (!Pushed)
00872
00873 Repeat = NO_ARG;
00874 return s;
00875 }
00876
00877 STATIC STATUS
00878 TTYspecial(c)
00879 unsigned int c;
00880 {
00881 if (ISMETA(c))
00882 return CSdispatch;
00883
00884 if (c == rl_erase || c == DEL)
00885 return bk_del_char();
00886 if (c == rl_kill) {
00887 if (Point != 0) {
00888 Point = 0;
00889 reposition();
00890 }
00891 Repeat = NO_ARG;
00892 return kill_line();
00893 }
00894 if (c == rl_eof && Point == 0 && End == 0)
00895 return CSeof;
00896 if (c == rl_intr) {
00897 Signal = SIGINT;
00898 return CSsignal;
00899 }
00900 if (c == rl_quit) {
00901 Signal = SIGQUIT;
00902 return CSeof;
00903 }
00904
00905 return CSdispatch;
00906 }
00907
00908 STATIC CHAR *
00909 editinput()
00910 {
00911 unsigned int c;
00912
00913 Repeat = NO_ARG;
00914 OldPoint = Point = Mark = End = 0;
00915 Line[0] = '\0';
00916
00917 Signal = -1;
00918 while ((c = TTYget()) != EOF)
00919 switch (TTYspecial(c)) {
00920 case CSdone:
00921 return Line;
00922 case CSeof:
00923 return NULL;
00924 case CSsignal:
00925 return (CHAR *)"";
00926 case CSmove:
00927 reposition();
00928 break;
00929 case CSdispatch:
00930 switch (emacs(c)) {
00931 case CSdone:
00932 return Line;
00933 case CSeof:
00934 return NULL;
00935 case CSsignal:
00936 return (CHAR *)"";
00937 case CSmove:
00938 reposition();
00939 break;
00940 case CSdispatch:
00941 case CSstay:
00942 break;
00943 }
00944 break;
00945 case CSstay:
00946 break;
00947 }
00948 return NULL;
00949 }
00950
00951 STATIC void
00952 hist_add(p)
00953 CHAR *p;
00954 {
00955 int i;
00956
00957 if ((p = (CHAR *)strdup((char *)p)) == NULL)
00958 return;
00959 if (H.Size < HIST_SIZE)
00960 H.Lines[H.Size++] = p;
00961 else {
00962 DISPOSE(H.Lines[0]);
00963 for (i = 0; i < HIST_SIZE - 1; i++)
00964 H.Lines[i] = H.Lines[i + 1];
00965 H.Lines[i] = p;
00966 }
00967 H.Pos = H.Size - 1;
00968 }
00969
00970
00971
00972
00973
00974 void
00975 rl_reset_terminal(p)
00976 char *p;
00977 {
00978 }
00979
00980 void
00981 rl_initialize()
00982 {
00983 }
00984
00985 char *
00986 readline(prompt)
00987 CONST char *prompt;
00988 {
00989 CHAR *line;
00990 int s;
00991
00992 if (Line == NULL) {
00993 Length = MEM_INC;
00994 if ((Line = NEW(CHAR, Length)) == NULL)
00995 return NULL;
00996 }
00997
00998 TTYinfo();
00999 rl_ttyset(0);
01000 hist_add(NIL);
01001 ScreenSize = SCREEN_INC;
01002 Screen = NEW(char, ScreenSize);
01003 Prompt = prompt ? prompt : (char *)NIL;
01004 TTYputs((CONST CHAR *)Prompt);
01005 if ((line = editinput()) != NULL) {
01006 line = (CHAR *)strdup((char *)line);
01007 TTYputs((CHAR *)NEWLINE);
01008 TTYflush();
01009 }
01010 rl_ttyset(1);
01011 DISPOSE(Screen);
01012 DISPOSE(H.Lines[--H.Size]);
01013
01014 if (line != NULL && *line != '\0'
01015 #if defined(UNIQUE_HISTORY)
01016 && !(H.Pos && strcmp((char *) line, (char *) H.Lines[H.Pos - 1]) == 0)
01017 #endif
01018 && !(H.Size && strcmp((char *) line, (char *) H.Lines[H.Size - 1]) == 0)
01019 ) {
01020 hist_add(line);
01021 }
01022
01023 if (Signal > 0) {
01024 s = Signal;
01025 Signal = 0;
01026 (void)kill(getpid(), s);
01027 }
01028 return (char *)line;
01029 }
01030
01031 void
01032 add_history(p)
01033 char *p;
01034 {
01035 #ifdef obsolete
01036 if (p == NULL || *p == '\0')
01037 return;
01038
01039 #if defined(UNIQUE_HISTORY)
01040 if (H.Pos && strcmp(p, (char *) H.Lines[H.Pos - 1]) == 0)
01041 return;
01042 #endif
01043 if (H.Size && strcmp(p, (char *) H.Lines[H.Size - 1]) == 0)
01044 return;
01045 hist_add((CHAR *)p);
01046 #endif
01047 }
01048
01049
01050 STATIC STATUS
01051 beg_line()
01052 {
01053 if (Point) {
01054 Point = 0;
01055 return CSmove;
01056 }
01057 return CSstay;
01058 }
01059
01060 STATIC STATUS
01061 del_char()
01062 {
01063 return delete_string(Repeat == NO_ARG ? 1 : Repeat);
01064 }
01065
01066 STATIC STATUS
01067 end_line()
01068 {
01069 if (Point != End) {
01070 Point = End;
01071 return CSmove;
01072 }
01073 return CSstay;
01074 }
01075
01076 STATIC char SEPS[] = "\"#$&'()*:;<=>?[\\]^`{|}~\n\t ";
01077
01078
01079
01080
01081
01082 STATIC CHAR *
01083 find_word()
01084 {
01085 CHAR *p, *q;
01086 CHAR *new;
01087 SIZE_T len;
01088
01089 p = &Line[Point];
01090 while (p > Line) {
01091 p--;
01092 if (p > Line && p[-1] == '\\') {
01093 p--;
01094 } else {
01095 if (strchr(SEPS, (char) *p) != NULL) {
01096 p++;
01097 break;
01098 }
01099 }
01100 }
01101 len = Point - (p - Line) + 1;
01102 if ((new = NEW(CHAR, len)) == NULL)
01103 return NULL;
01104 q = new;
01105 while (p < &Line[Point]) {
01106 if (*p == '\\') {
01107 if (++p == &Line[Point]) break;
01108 }
01109 *q++ = *p++;
01110 }
01111 *q = '\0';
01112 return new;
01113 }
01114
01115 STATIC STATUS
01116 c_possible()
01117 {
01118 CHAR **av;
01119 CHAR *word;
01120 int ac;
01121
01122 word = find_word();
01123 ac = rl_list_possib((char *)word, (char ***)&av);
01124 if (word)
01125 DISPOSE(word);
01126 if (ac) {
01127 columns(ac, av);
01128 while (--ac >= 0)
01129 DISPOSE(av[ac]);
01130 DISPOSE(av);
01131 return CSmove;
01132 }
01133 return ring_bell();
01134 }
01135
01136 STATIC STATUS
01137 c_complete()
01138 {
01139 CHAR *p, *q;
01140 CHAR *word, *new;
01141 SIZE_T len;
01142 int unique;
01143 STATUS s;
01144
01145 word = find_word();
01146 p = (CHAR *)rl_complete((char *)word, &unique);
01147 if (word)
01148 DISPOSE(word);
01149 if (p) {
01150 len = strlen((char *)p);
01151 word = p;
01152 new = q = NEW(CHAR, 2 * len + 1);
01153 while (*p) {
01154 if ((*p < ' ' || strchr(SEPS, (char) *p) != NULL)
01155 && (!unique || p[1] != 0)) {
01156 *q++ = '\\';
01157 }
01158 *q++ = *p++;
01159 }
01160 *q = '\0';
01161 DISPOSE(word);
01162 if (len > 0) {
01163 s = insert_string(new);
01164 #if ANNOYING_NOISE
01165 if (!unique)
01166 (void)ring_bell();
01167 #endif
01168 }
01169 DISPOSE(new);
01170 if (len > 0) return s;
01171 }
01172 return c_possible();
01173 }
01174
01175 STATIC STATUS
01176 accept_line()
01177 {
01178 Line[End] = '\0';
01179 return CSdone;
01180 }
01181
01182 STATIC STATUS
01183 transpose()
01184 {
01185 CHAR c;
01186
01187 if (Point) {
01188 if (Point == End)
01189 left(CSmove);
01190 c = Line[Point - 1];
01191 left(CSstay);
01192 Line[Point - 1] = Line[Point];
01193 TTYshow(Line[Point - 1]);
01194 Line[Point++] = c;
01195 TTYshow(c);
01196 }
01197 return CSstay;
01198 }
01199
01200 STATIC STATUS
01201 quote()
01202 {
01203 unsigned int c;
01204
01205 return (c = TTYget()) == EOF ? CSeof : insert_char((int)c);
01206 }
01207
01208 STATIC STATUS
01209 wipe()
01210 {
01211 int i;
01212
01213 if (Mark > End)
01214 return ring_bell();
01215
01216 if (Point > Mark) {
01217 i = Point;
01218 Point = Mark;
01219 Mark = i;
01220 reposition();
01221 }
01222
01223 return delete_string(Mark - Point);
01224 }
01225
01226 STATIC STATUS
01227 mk_set()
01228 {
01229 Mark = Point;
01230 return CSstay;
01231 }
01232
01233 STATIC STATUS
01234 exchange()
01235 {
01236 unsigned int c;
01237
01238 if ((c = TTYget()) != CTL('X'))
01239 return c == EOF ? CSeof : ring_bell();
01240
01241 if ((c = Mark) <= End) {
01242 Mark = Point;
01243 Point = c;
01244 return CSmove;
01245 }
01246 return CSstay;
01247 }
01248
01249 STATIC STATUS
01250 yank()
01251 {
01252 if (Yanked && *Yanked)
01253 return insert_string(Yanked);
01254 return CSstay;
01255 }
01256
01257 STATIC STATUS
01258 copy_region()
01259 {
01260 if (Mark > End)
01261 return ring_bell();
01262
01263 if (Point > Mark)
01264 save_yank(Mark, Point - Mark);
01265 else
01266 save_yank(Point, Mark - Point);
01267
01268 return CSstay;
01269 }
01270
01271 STATIC STATUS
01272 move_to_char()
01273 {
01274 unsigned int c;
01275 int i;
01276 CHAR *p;
01277
01278 if ((c = TTYget()) == EOF)
01279 return CSeof;
01280 for (i = Point + 1, p = &Line[i]; i < End; i++, p++)
01281 if (*p == c) {
01282 Point = i;
01283 return CSmove;
01284 }
01285 return CSstay;
01286 }
01287
01288 STATIC STATUS
01289 fd_word()
01290 {
01291 return do_forward(CSmove);
01292 }
01293
01294 STATIC STATUS
01295 fd_kill_word()
01296 {
01297 int i;
01298
01299 (void)do_forward(CSstay);
01300 if (OldPoint != Point) {
01301 i = Point - OldPoint;
01302 Point = OldPoint;
01303 return delete_string(i);
01304 }
01305 return CSstay;
01306 }
01307
01308 STATIC STATUS
01309 bk_word()
01310 {
01311 int i;
01312 CHAR *p;
01313
01314 i = 0;
01315 do {
01316 for (p = &Line[Point]; p > Line && !isalnum(p[-1]); p--)
01317 left(CSmove);
01318
01319 for (; p > Line && p[-1] != ' ' && isalnum(p[-1]); p--)
01320 left(CSmove);
01321
01322 if (Point == 0)
01323 break;
01324 } while (++i < Repeat);
01325
01326 return CSstay;
01327 }
01328
01329 STATIC STATUS
01330 bk_kill_word()
01331 {
01332 (void)bk_word();
01333 if (OldPoint != Point)
01334 return delete_string(OldPoint - Point);
01335 return CSstay;
01336 }
01337
01338 STATIC int
01339 argify(line, avp)
01340 CHAR *line;
01341 CHAR ***avp;
01342 {
01343 CHAR *c;
01344 CHAR **p;
01345 CHAR **new;
01346 int ac;
01347 int i;
01348
01349 i = MEM_INC;
01350 if ((*avp = p = NEW(CHAR*, i))== NULL)
01351 return 0;
01352
01353 for (c = line; isspace(*c); c++)
01354 continue;
01355 if (*c == '\n' || *c == '\0')
01356 return 0;
01357
01358 for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) {
01359 if (isspace(*c)) {
01360 *c++ = '\0';
01361 if (*c && *c != '\n') {
01362 if (ac + 1 == i) {
01363 new = NEW(CHAR*, i + MEM_INC);
01364 if (new == NULL) {
01365 p[ac] = NULL;
01366 return ac;
01367 }
01368 COPYFROMTO(new, p, i * sizeof (char **));
01369 i += MEM_INC;
01370 DISPOSE(p);
01371 *avp = p = new;
01372 }
01373 p[ac++] = c;
01374 }
01375 }
01376 else
01377 c++;
01378 }
01379 *c = '\0';
01380 p[ac] = NULL;
01381 return ac;
01382 }
01383
01384 STATIC STATUS
01385 last_argument()
01386 {
01387 CHAR **av;
01388 CHAR *p;
01389 STATUS s;
01390 int ac;
01391
01392 if (H.Size == 1 || (p = H.Lines[H.Size - 2]) == NULL)
01393 return ring_bell();
01394
01395 if ((p = (CHAR *)strdup((char *)p)) == NULL)
01396 return CSstay;
01397 ac = argify(p, &av);
01398
01399 if (Repeat != NO_ARG)
01400 s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell();
01401 else
01402 s = ac ? insert_string(av[ac - 1]) : CSstay;
01403
01404 if (ac)
01405 DISPOSE(av);
01406 DISPOSE(p);
01407 return s;
01408 }
01409
01410 STATIC KEYMAP Map[33] = {
01411 { CTL('@'), mk_set },
01412 { CTL('A'), beg_line },
01413 { CTL('B'), bk_char },
01414 { CTL('D'), del_char },
01415 { CTL('E'), end_line },
01416 { CTL('F'), fd_char },
01417 { CTL('G'), ring_bell },
01418 { CTL('H'), bk_del_char },
01419 { CTL('I'), c_complete },
01420 { CTL('J'), accept_line },
01421 { CTL('K'), kill_line },
01422 { CTL('L'), redisplay },
01423 { CTL('M'), accept_line },
01424 { CTL('N'), h_next },
01425 { CTL('O'), ring_bell },
01426 { CTL('P'), h_prev },
01427 { CTL('Q'), ring_bell },
01428 { CTL('R'), h_search },
01429 { CTL('S'), ring_bell },
01430 { CTL('T'), transpose },
01431 { CTL('U'), ring_bell },
01432 { CTL('V'), quote },
01433 { CTL('W'), bk_kill_word },
01434 { CTL('X'), exchange },
01435 { CTL('Y'), yank },
01436 { CTL('Z'), end_line },
01437 { CTL('['), meta },
01438 { CTL(']'), move_to_char },
01439 { CTL('^'), ring_bell },
01440 { CTL('_'), ring_bell },
01441 { 0, NULL }
01442 };
01443
01444 STATIC KEYMAP MetaMap[17]= {
01445 { CTL('H'), wipe },
01446 { DEL, wipe },
01447 { ' ', mk_set },
01448 { '.', last_argument },
01449 { '<', h_first },
01450 { '>', h_last },
01451 { '?', c_possible },
01452 { 'b', bk_word },
01453 { 'd', fd_kill_word },
01454 { 'f', fd_word },
01455 { 'l', case_down_word },
01456 { 'm', toggle_meta_mode },
01457 { 'u', case_up_word },
01458 { 'y', yank },
01459 { 'w', copy_region },
01460 { 0, NULL }
01461 };
01462
01463
01464
01465