editline.c

Go to the documentation of this file.
00001 /*  $Revision: 1.1.1.1 $
00002 **
00003 **  Main editing routines for editline library.
00004 */
00005 #include "editline.h"
00006 #include <signal.h>
00007 #include <ctype.h>
00008 
00009 /*
00010 **  Manifest constants.
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  /* !defined(HIST_SIZE) */
00025 
00026 /*
00027 **  Command status codes.
00028 */
00029 typedef enum _STATUS {
00030     CSdone, CSeof, CSmove, CSdispatch, CSstay, CSsignal
00031 } STATUS;
00032 
00033 /*
00034 **  The type of case-changing to perform.
00035 */
00036 typedef enum _CASE {
00037     TOupper, TOlower
00038 } CASE;
00039 
00040 /*
00041 **  Key to command mapping.
00042 */
00043 typedef struct _KEYMAP {
00044     CHAR        Key;
00045     STATUS      (*Function)();
00046 } KEYMAP;
00047 
00048 /*
00049 **  Command history structure.
00050 */
00051 typedef struct _HISTORY {
00052     int         Size;
00053     int         Pos;
00054     CHAR        *Lines[HIST_SIZE];
00055 } HISTORY;
00056 
00057 /*
00058 **  Globals.
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 /* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */
00092 int             rl_meta_chars = 0;
00093 
00094 /*
00095 **  Declarations.
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  /* defined(USE_TERMCAP) */
00105 
00106 /*
00107 **  TTY input/output functions.
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  /* defined(USE_TERMCAP) */
00201 #if     defined(TIOCGWINSZ)
00202     struct winsize      W;
00203 #endif  /* defined(TIOCGWINSZ) */
00204 
00205     if (init) {
00206 #if     defined(TIOCGWINSZ)
00207         /* Perhaps we got resized. */
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  /* defined(TIOCGWINSZ) */
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  /* defined(USE_TERMCAP) */
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  /* defined(TIOCGWINSZ) */
00240 
00241     if (TTYwidth <= 0 || TTYrows <= 0) {
00242         TTYwidth = SCREEN_WIDTH;
00243         TTYrows = SCREEN_ROWS;
00244     }
00245 }
00246 
00247 
00248 /*
00249 **  Print an array of words in columns.
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     /* Find longest name, determine column count from that. */
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 **  Return zero if pat appears as a substring in text.
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     /* Save or get remembered search pattern. */
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     /* Set up pattern-finder. */
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         /* Optimize common case of delete at end of line. */
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     /* Also include VT-100 arrows. */
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  /* defined(ANSI_ARROWS) */
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         /* No pushback means no repeat count; hacky, but true. */
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 **  For compatibility with FSF readline.
00972 */
00973 /* ARGSUSED0 */
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  /* defined(UNIQUE_HISTORY) */
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         /* Made part of readline(). -- kjb */
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  /* defined(UNIQUE_HISTORY) */
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 **  Move back to the beginning of the current word and return an
01080 **  allocated copy of it.
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  * $PchId: editline.c,v 1.4 1996/02/22 21:16:56 philip Exp $
01465  */

Generated on Fri Apr 14 22:57:26 2006 for minix by  doxygen 1.4.6