js/src/editline/editline.c

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 /*
     7  * Copyright 1992,1993 Simmule Turner and Rich Salz.  All rights reserved.
     8  *
     9  * This software is not subject to any license of the American Telephone
    10  * and Telegraph Company or of the Regents of the University of California.
    11  *
    12  * Permission is granted to anyone to use this software for any purpose on
    13  * any computer system, and to alter it and redistribute it freely, subject
    14  * to the following restrictions:
    15  * 1. The authors are not responsible for the consequences of use of this
    16  *    software, no matter how awful, even if they arise from flaws in it.
    17  * 2. The origin of this software must not be misrepresented, either by
    18  *    explicit claim or by omission.  Since few users ever read sources,
    19  *    credits must appear in the documentation.
    20  * 3. Altered versions must be plainly marked as such, and must not be
    21  *    misrepresented as being the original software.  Since few users
    22  *    ever read sources, credits must appear in the documentation.
    23  * 4. This notice may not be removed or altered.
    24  */
    27 /*
    28 **  Main editing routines for editline library.
    29 */
    30 #include "editline.h"
    31 #include <signal.h>
    32 #include <ctype.h>
    33 #include <unistd.h>
    35 /*
    36 **  Manifest constants.
    37 */
    38 #define SCREEN_WIDTH	80
    39 #define SCREEN_ROWS	24
    40 #define NO_ARG		(-1)
    41 #define DEL		127
    42 #define CTL(x)		((x) & 0x1F)
    43 #define ISCTL(x)	((x) && (x) < ' ')
    44 #define UNCTL(x)	((x) + 64)
    45 #define META(x)		((x) | 0x80)
    46 #define ISMETA(x)	((x) & 0x80)
    47 #define UNMETA(x)	((x) & 0x7F)
    48 #if	!defined(HIST_SIZE)
    49 #define HIST_SIZE	20
    50 #endif	/* !defined(HIST_SIZE) */
    52 /*
    53 **  Command status codes.
    54 */
    55 typedef enum _STATUS {
    56     CSdone, CSeof, CSmove, CSdispatch, CSstay, CSsignal
    57 } STATUS;
    59 /*
    60 **  The type of case-changing to perform.
    61 */
    62 typedef enum _CASE {
    63     TOupper, TOlower
    64 } CASE;
    66 /*
    67 **  Key to command mapping.
    68 */
    69 typedef struct _KEYMAP {
    70     CHAR	Key;
    71     STATUS	(*Function)();
    72 } KEYMAP;
    74 /*
    75 **  Command history structure.
    76 */
    77 typedef struct _HISTORY {
    78     int		Size;
    79     int		Pos;
    80     CHAR	*Lines[HIST_SIZE];
    81 } HISTORY;
    83 /*
    84 **  Globals.
    85 */
    86 unsigned	rl_eof;
    87 unsigned	rl_erase;
    88 unsigned	rl_intr;
    89 unsigned	rl_kill;
    90 unsigned	rl_quit;
    92 STATIC CHAR		NIL[] = "";
    93 STATIC CONST CHAR	*Input = NIL;
    94 STATIC CHAR		*Line;
    95 STATIC CONST char	*Prompt;
    96 STATIC CHAR		*Yanked;
    97 STATIC char		*Screen;
    98 STATIC CONST char	NEWLINE[]= CRLF;
    99 STATIC HISTORY		H;
   100 STATIC int		Repeat;
   101 STATIC int		End;
   102 STATIC int		Mark;
   103 STATIC int		OldPoint;
   104 STATIC int		Point;
   105 STATIC int		PushBack;
   106 STATIC int		Pushed;
   107 STATIC int		Signal;
   108 FORWARD CONST KEYMAP	Map[32];
   109 FORWARD CONST KEYMAP	MetaMap[16];
   110 STATIC SIZE_T		Length;
   111 STATIC SIZE_T		ScreenCount;
   112 STATIC SIZE_T		ScreenSize;
   113 STATIC char		*backspace;
   114 STATIC int		TTYwidth;
   115 STATIC int		TTYrows;
   117 /* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */
   118 int		rl_meta_chars = 0;
   120 /*
   121 **  Declarations.
   122 */
   123 STATIC CHAR	*editinput();
   124 #if	defined(USE_TERMCAP)
   125 #include <stdlib.h>
   126 #include <curses.h>
   127 #include <term.h>
   128 #endif	/* defined(USE_TERMCAP) */
   130 /*
   131 **  TTY input/output functions.
   132 */
   134 STATIC void
   135 TTYflush()
   136 {
   137     if (ScreenCount) {
   138         /* Dummy assignment avoids GCC warning on
   139          * "attribute warn_unused_result" */
   140 	ssize_t dummy = write(1, Screen, ScreenCount);
   141         (void)dummy;
   142 	ScreenCount = 0;
   143     }
   144 }
   146 STATIC void
   147 TTYput(c)
   148     CHAR	c;
   149 {
   150     Screen[ScreenCount] = c;
   151     if (++ScreenCount >= ScreenSize - 1) {
   152 	ScreenSize += SCREEN_INC;
   153 	RENEW(Screen, char, ScreenSize);
   154     }
   155 }
   157 STATIC void
   158 TTYputs(p)
   159     CONST CHAR	*p;
   160 {
   161     while (*p)
   162 	TTYput(*p++);
   163 }
   165 STATIC void
   166 TTYshow(c)
   167     CHAR	c;
   168 {
   169     if (c == DEL) {
   170 	TTYput('^');
   171 	TTYput('?');
   172     }
   173     else if (ISCTL(c)) {
   174 	TTYput('^');
   175 	TTYput(UNCTL(c));
   176     }
   177     else if (rl_meta_chars && ISMETA(c)) {
   178 	TTYput('M');
   179 	TTYput('-');
   180 	TTYput(UNMETA(c));
   181     }
   182     else
   183 	TTYput(c);
   184 }
   186 STATIC void
   187 TTYstring(p)
   188     CHAR	*p;
   189 {
   190     while (*p)
   191 	TTYshow(*p++);
   192 }
   194 STATIC unsigned int
   195 TTYget()
   196 {
   197     CHAR	c;
   199     TTYflush();
   200     if (Pushed) {
   201 	Pushed = 0;
   202 	return PushBack;
   203     }
   204     if (*Input)
   205 	return *Input++;
   206     return read(0, &c, (SIZE_T)1) == 1 ? c : EOF;
   207 }
   209 #define TTYback()	(backspace ? TTYputs((CHAR *)backspace) : TTYput('\b'))
   211 STATIC void
   212 TTYbackn(n)
   213     int		n;
   214 {
   215     while (--n >= 0)
   216 	TTYback();
   217 }
   219 STATIC void
   220 TTYinfo()
   221 {
   222     static int		init;
   223 #if	defined(USE_TERMCAP)
   224     char		*term;
   225     char		buff[2048];
   226     char		*bp, *p;
   227 #endif	/* defined(USE_TERMCAP) */
   228 #if	defined(TIOCGWINSZ)
   229     struct winsize	W;
   230 #endif	/* defined(TIOCGWINSZ) */
   232     if (init) {
   233 #if	defined(TIOCGWINSZ)
   234 	/* Perhaps we got resized. */
   235 	if (ioctl(0, TIOCGWINSZ, &W) >= 0
   236 	 && W.ws_col > 0 && W.ws_row > 0) {
   237 	    TTYwidth = (int)W.ws_col;
   238 	    TTYrows = (int)W.ws_row;
   239 	}
   240 #endif	/* defined(TIOCGWINSZ) */
   241 	return;
   242     }
   243     init++;
   245     TTYwidth = TTYrows = 0;
   246 #if	defined(USE_TERMCAP)
   247     bp = &buff[0];
   248     if ((term = getenv("TERM")) == NULL)
   249 	term = "dumb";
   250     if (tgetent(buff, term) < 0) {
   251        TTYwidth = SCREEN_WIDTH;
   252        TTYrows = SCREEN_ROWS;
   253        return;
   254     }
   255     p = tgetstr("le", &bp);
   256     backspace = p ? strdup(p) : NULL;
   257     TTYwidth = tgetnum("co");
   258     TTYrows = tgetnum("li");
   259 #endif	/* defined(USE_TERMCAP) */
   261 #if	defined(TIOCGWINSZ)
   262     if (ioctl(0, TIOCGWINSZ, &W) >= 0) {
   263 	TTYwidth = (int)W.ws_col;
   264 	TTYrows = (int)W.ws_row;
   265     }
   266 #endif	/* defined(TIOCGWINSZ) */
   268     if (TTYwidth <= 0 || TTYrows <= 0) {
   269 	TTYwidth = SCREEN_WIDTH;
   270 	TTYrows = SCREEN_ROWS;
   271     }
   272 }
   275 STATIC void
   276 reposition()
   277 {
   278     int		i;
   279     CHAR	*p;
   281     TTYput('\r');
   282     TTYputs((CONST CHAR *)Prompt);
   283     for (i = Point, p = Line; --i >= 0; p++)
   284 	TTYshow(*p);
   285 }
   287 STATIC void
   288 left(Change)
   289     STATUS	Change;
   290 {
   291     TTYback();
   292     if (Point) {
   293 	if (ISCTL(Line[Point - 1]))
   294 	    TTYback();
   295         else if (rl_meta_chars && ISMETA(Line[Point - 1])) {
   296 	    TTYback();
   297 	    TTYback();
   298 	}
   299     }
   300     if (Change == CSmove)
   301 	Point--;
   302 }
   304 STATIC void
   305 right(Change)
   306     STATUS	Change;
   307 {
   308     TTYshow(Line[Point]);
   309     if (Change == CSmove)
   310 	Point++;
   311 }
   313 STATIC STATUS
   314 ring_bell()
   315 {
   316     TTYput('\07');
   317     TTYflush();
   318     return CSstay;
   319 }
   321 STATIC STATUS
   322 do_macro(c)
   323     unsigned int	c;
   324 {
   325     CHAR		name[4];
   327     name[0] = '_';
   328     name[1] = c;
   329     name[2] = '_';
   330     name[3] = '\0';
   332     if ((Input = (CHAR *)getenv((char *)name)) == NULL) {
   333 	Input = NIL;
   334 	return ring_bell();
   335     }
   336     return CSstay;
   337 }
   339 STATIC STATUS
   340 do_forward(move)
   341     STATUS	move;
   342 {
   343     int		i;
   344     CHAR	*p;
   346     i = 0;
   347     do {
   348 	p = &Line[Point];
   349 	for ( ; Point < End && (*p == ' ' || !isalnum(*p)); Point++, p++)
   350 	    if (move == CSmove)
   351 		right(CSstay);
   353 	for (; Point < End && isalnum(*p); Point++, p++)
   354 	    if (move == CSmove)
   355 		right(CSstay);
   357 	if (Point == End)
   358 	    break;
   359     } while (++i < Repeat);
   361     return CSstay;
   362 }
   364 STATIC STATUS
   365 do_case(type)
   366     CASE	type;
   367 {
   368     int		i;
   369     int		end;
   370     int		count;
   371     CHAR	*p;
   373     (void)do_forward(CSstay);
   374     if (OldPoint != Point) {
   375 	if ((count = Point - OldPoint) < 0)
   376 	    count = -count;
   377 	Point = OldPoint;
   378 	if ((end = Point + count) > End)
   379 	    end = End;
   380 	for (i = Point, p = &Line[i]; i < end; i++, p++) {
   381 	    if (type == TOupper) {
   382 		if (islower(*p))
   383 		    *p = toupper(*p);
   384 	    }
   385 	    else if (isupper(*p))
   386 		*p = tolower(*p);
   387 	    right(CSmove);
   388 	}
   389     }
   390     return CSstay;
   391 }
   393 STATIC STATUS
   394 case_down_word()
   395 {
   396     return do_case(TOlower);
   397 }
   399 STATIC STATUS
   400 case_up_word()
   401 {
   402     return do_case(TOupper);
   403 }
   405 STATIC void
   406 ceol()
   407 {
   408     int		extras;
   409     int		i;
   410     CHAR	*p;
   412     for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) {
   413 	TTYput(' ');
   414 	if (ISCTL(*p)) {
   415 	    TTYput(' ');
   416 	    extras++;
   417 	}
   418 	else if (rl_meta_chars && ISMETA(*p)) {
   419 	    TTYput(' ');
   420 	    TTYput(' ');
   421 	    extras += 2;
   422 	}
   423     }
   425     for (i += extras; i > Point; i--)
   426 	TTYback();
   427 }
   429 STATIC void
   430 clear_line()
   431 {
   432     Point = -strlen(Prompt);
   433     TTYput('\r');
   434     ceol();
   435     Point = 0;
   436     End = 0;
   437     Line[0] = '\0';
   438 }
   440 STATIC STATUS
   441 insert_string(p)
   442     CHAR	*p;
   443 {
   444     SIZE_T	len;
   445     int		i;
   446     CHAR	*new;
   447     CHAR	*q;
   449     len = strlen((char *)p);
   450     if (End + len >= Length) {
   451 	if ((new = NEW(CHAR, Length + len + MEM_INC)) == NULL)
   452 	    return CSstay;
   453 	if (Length) {
   454 	    COPYFROMTO(new, Line, Length);
   455 	    DISPOSE(Line);
   456 	}
   457 	Line = new;
   458 	Length += len + MEM_INC;
   459     }
   461     for (q = &Line[Point], i = End - Point; --i >= 0; )
   462 	q[len + i] = q[i];
   463     COPYFROMTO(&Line[Point], p, len);
   464     End += len;
   465     Line[End] = '\0';
   466     TTYstring(&Line[Point]);
   467     Point += len;
   469     return Point == End ? CSstay : CSmove;
   470 }
   472 STATIC STATUS
   473 redisplay()
   474 {
   475     TTYputs((CONST CHAR *)NEWLINE);
   476     TTYputs((CONST CHAR *)Prompt);
   477     TTYstring(Line);
   478     return CSmove;
   479 }
   481 STATIC STATUS
   482 toggle_meta_mode()
   483 {
   484     rl_meta_chars = ! rl_meta_chars;
   485     return redisplay();
   486 }
   489 STATIC CHAR *
   490 next_hist()
   491 {
   492     return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];
   493 }
   495 STATIC CHAR *
   496 prev_hist()
   497 {
   498     return H.Pos == 0 ? NULL : H.Lines[--H.Pos];
   499 }
   501 STATIC STATUS
   502 do_insert_hist(p)
   503     CHAR	*p;
   504 {
   505     if (p == NULL)
   506 	return ring_bell();
   507     Point = 0;
   508     reposition();
   509     ceol();
   510     End = 0;
   511     return insert_string(p);
   512 }
   514 STATIC STATUS
   515 do_hist(move)
   516     CHAR	*(*move)();
   517 {
   518     CHAR	*p;
   519     int		i;
   521     i = 0;
   522     do {
   523 	if ((p = (*move)()) == NULL)
   524 	    return ring_bell();
   525     } while (++i < Repeat);
   526     return do_insert_hist(p);
   527 }
   529 STATIC STATUS
   530 h_next()
   531 {
   532     return do_hist(next_hist);
   533 }
   535 STATIC STATUS
   536 h_prev()
   537 {
   538     return do_hist(prev_hist);
   539 }
   541 STATIC STATUS
   542 h_first()
   543 {
   544     return do_insert_hist(H.Lines[H.Pos = 0]);
   545 }
   547 STATIC STATUS
   548 h_last()
   549 {
   550     return do_insert_hist(H.Lines[H.Pos = H.Size - 1]);
   551 }
   553 /*
   554 **  Return zero if pat appears as a substring in text.
   555 */
   556 STATIC int
   557 substrcmp(text, pat, len)
   558     char	*text;
   559     char	*pat;
   560     int		len;
   561 {
   562     char	c;
   564     if ((c = *pat) == '\0')
   565         return *text == '\0';
   566     for ( ; *text; text++)
   567         if (*text == c && strncmp(text, pat, len) == 0)
   568             return 0;
   569     return 1;
   570 }
   572 STATIC CHAR *
   573 search_hist(search, move)
   574     CHAR	*search;
   575     CHAR	*(*move)();
   576 {
   577     static CHAR	*old_search;
   578     int		len;
   579     int		pos;
   580     int		(*match)();
   581     char	*pat;
   583     /* Save or get remembered search pattern. */
   584     if (search && *search) {
   585 	if (old_search)
   586 	    DISPOSE(old_search);
   587 	old_search = (CHAR *)strdup((char *)search);
   588     }
   589     else {
   590 	if (old_search == NULL || *old_search == '\0')
   591             return NULL;
   592 	search = old_search;
   593     }
   595     /* Set up pattern-finder. */
   596     if (*search == '^') {
   597 	match = strncmp;
   598 	pat = (char *)(search + 1);
   599     }
   600     else {
   601 	match = substrcmp;
   602 	pat = (char *)search;
   603     }
   604     len = strlen(pat);
   606     for (pos = H.Pos; (*move)() != NULL; )
   607 	if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0)
   608             return H.Lines[H.Pos];
   609     H.Pos = pos;
   610     return NULL;
   611 }
   613 STATIC STATUS
   614 h_search()
   615 {
   616     static int	Searching;
   617     CONST char	*old_prompt;
   618     CHAR	*(*move)();
   619     CHAR	*p;
   621     if (Searching)
   622 	return ring_bell();
   623     Searching = 1;
   625     clear_line();
   626     old_prompt = Prompt;
   627     Prompt = "Search: ";
   628     TTYputs((CONST CHAR *)Prompt);
   629     move = Repeat == NO_ARG ? prev_hist : next_hist;
   630     p = editinput();
   631     Prompt = old_prompt;
   632     Searching = 0;
   633     TTYputs((CONST CHAR *)Prompt);
   634     if (p == NULL && Signal > 0) {
   635 	Signal = 0;
   636 	clear_line();
   637 	return redisplay();
   638     }
   639     p = search_hist(p, move);
   640     clear_line();
   641     if (p == NULL) {
   642 	(void)ring_bell();
   643 	return redisplay();
   644     }
   645     return do_insert_hist(p);
   646 }
   648 STATIC STATUS
   649 fd_char()
   650 {
   651     int		i;
   653     i = 0;
   654     do {
   655 	if (Point >= End)
   656 	    break;
   657 	right(CSmove);
   658     } while (++i < Repeat);
   659     return CSstay;
   660 }
   662 STATIC void
   663 save_yank(begin, i)
   664     int		begin;
   665     int		i;
   666 {
   667     if (Yanked) {
   668 	DISPOSE(Yanked);
   669 	Yanked = NULL;
   670     }
   672     if (i < 1)
   673 	return;
   675     if ((Yanked = NEW(CHAR, (SIZE_T)i + 1)) != NULL) {
   676 	COPYFROMTO(Yanked, &Line[begin], i);
   677 	Yanked[i] = '\0';
   678     }
   679 }
   681 STATIC STATUS
   682 delete_string(count)
   683     int		count;
   684 {
   685     int		i;
   686     CHAR	*p;
   688     if (count <= 0 || End == Point)
   689 	return ring_bell();
   691     if (count == 1 && Point == End - 1) {
   692 	/* Optimize common case of delete at end of line. */
   693 	End--;
   694 	p = &Line[Point];
   695 	i = 1;
   696 	TTYput(' ');
   697 	if (ISCTL(*p)) {
   698 	    i = 2;
   699 	    TTYput(' ');
   700 	}
   701 	else if (rl_meta_chars && ISMETA(*p)) {
   702 	    i = 3;
   703 	    TTYput(' ');
   704 	    TTYput(' ');
   705 	}
   706 	TTYbackn(i);
   707 	*p = '\0';
   708 	return CSmove;
   709     }
   710     if (Point + count > End && (count = End - Point) <= 0)
   711 	return CSstay;
   713     if (count > 1)
   714 	save_yank(Point, count);
   716     for (p = &Line[Point], i = End - (Point + count) + 1; --i >= 0; p++)
   717 	p[0] = p[count];
   718     ceol();
   719     End -= count;
   720     TTYstring(&Line[Point]);
   721     return CSmove;
   722 }
   724 STATIC STATUS
   725 bk_char()
   726 {
   727     int		i;
   729     i = 0;
   730     do {
   731 	if (Point == 0)
   732 	    break;
   733 	left(CSmove);
   734     } while (++i < Repeat);
   736     return CSstay;
   737 }
   739 STATIC STATUS
   740 bk_del_char()
   741 {
   742     int		i;
   744     i = 0;
   745     do {
   746 	if (Point == 0)
   747 	    break;
   748 	left(CSmove);
   749     } while (++i < Repeat);
   751     return delete_string(i);
   752 }
   754 STATIC STATUS
   755 kill_line()
   756 {
   757     int		i;
   759     if (Repeat != NO_ARG) {
   760 	if (Repeat < Point) {
   761 	    i = Point;
   762 	    Point = Repeat;
   763 	    reposition();
   764 	    (void)delete_string(i - Point);
   765 	}
   766 	else if (Repeat > Point) {
   767 	    right(CSmove);
   768 	    (void)delete_string(Repeat - Point - 1);
   769 	}
   770 	return CSmove;
   771     }
   773     save_yank(Point, End - Point);
   774     Line[Point] = '\0';
   775     ceol();
   776     End = Point;
   777     return CSstay;
   778 }
   780 STATIC STATUS
   781 insert_char(c)
   782     int		c;
   783 {
   784     STATUS	s;
   785     CHAR	buff[2];
   786     CHAR	*p;
   787     CHAR	*q;
   788     int		i;
   790     if (Repeat == NO_ARG || Repeat < 2) {
   791 	buff[0] = c;
   792 	buff[1] = '\0';
   793 	return insert_string(buff);
   794     }
   796     if ((p = NEW(CHAR, Repeat + 1)) == NULL)
   797 	return CSstay;
   798     for (i = Repeat, q = p; --i >= 0; )
   799 	*q++ = c;
   800     *q = '\0';
   801     Repeat = 0;
   802     s = insert_string(p);
   803     DISPOSE(p);
   804     return s;
   805 }
   807 STATIC STATUS
   808 meta()
   809 {
   810     unsigned int	c;
   811     CONST KEYMAP	*kp;
   813     if ((int)(c = TTYget()) == EOF)
   814 	return CSeof;
   815 #if	defined(ANSI_ARROWS)
   816     /* Also include VT-100 arrows. */
   817     if (c == '[' || c == 'O')
   818 	switch (c = TTYget()) {
   819 	default:	return ring_bell();
   820 	case EOF:	return CSeof;
   821 	case 'A':	return h_prev();
   822 	case 'B':	return h_next();
   823 	case 'C':	return fd_char();
   824 	case 'D':	return bk_char();
   825 	}
   826 #endif	/* defined(ANSI_ARROWS) */
   828     if (isdigit(c)) {
   829 	for (Repeat = c - '0'; (int)(c = TTYget()) != EOF && isdigit(c); )
   830 	    Repeat = Repeat * 10 + c - '0';
   831 	Pushed = 1;
   832 	PushBack = c;
   833 	return CSstay;
   834     }
   836     if (isupper(c))
   837 	return do_macro(c);
   838     for (OldPoint = Point, kp = MetaMap; kp->Function; kp++)
   839 	if (kp->Key == c)
   840 	    return (*kp->Function)();
   842     return ring_bell();
   843 }
   845 STATIC STATUS
   846 emacs(c)
   847     unsigned int	c;
   848 {
   849     STATUS		s;
   850     const KEYMAP	*kp;
   852     if (rl_meta_chars && ISMETA(c)) {
   853 	Pushed = 1;
   854 	PushBack = UNMETA(c);
   855 	return meta();
   856     }
   857     for (kp = Map; kp->Function; kp++)
   858 	if (kp->Key == c)
   859 	    break;
   860     s = kp->Function ? (*kp->Function)() : insert_char((int)c);
   861     if (!Pushed)
   862 	/* No pushback means no repeat count; hacky, but true. */
   863 	Repeat = NO_ARG;
   864     return s;
   865 }
   867 STATIC STATUS
   868 TTYspecial(c)
   869     unsigned int	c;
   870 {
   871     if (ISMETA(c))
   872 	return CSdispatch;
   874     if (c == rl_erase || (int)c == DEL)
   875 	return bk_del_char();
   876     if (c == rl_kill) {
   877 	if (Point != 0) {
   878 	    Point = 0;
   879 	    reposition();
   880 	}
   881 	Repeat = NO_ARG;
   882 	return kill_line();
   883     }
   884     if (c == rl_eof && Point == 0 && End == 0)
   885 	return CSeof;
   886     if (c == rl_intr) {
   887 	Signal = SIGINT;
   888 	return CSsignal;
   889     }
   890     if (c == rl_quit) {
   891 	Signal = SIGQUIT;
   892 	return CSeof;
   893     }
   895     return CSdispatch;
   896 }
   898 STATIC CHAR *
   899 editinput()
   900 {
   901     unsigned int	c;
   903     Repeat = NO_ARG;
   904     OldPoint = Point = Mark = End = 0;
   905     Line[0] = '\0';
   907     Signal = -1;
   908     while ((int)(c = TTYget()) != EOF)
   909 	switch (TTYspecial(c)) {
   910 	case CSdone:
   911 	    return Line;
   912 	case CSeof:
   913 	    return NULL;
   914 	case CSsignal:
   915 	    return (CHAR *)"";
   916 	case CSmove:
   917 	    reposition();
   918 	    break;
   919 	case CSdispatch:
   920 	    switch (emacs(c)) {
   921 	    case CSdone:
   922 		return Line;
   923 	    case CSeof:
   924 		return NULL;
   925 	    case CSsignal:
   926 		return (CHAR *)"";
   927 	    case CSmove:
   928 		reposition();
   929 		break;
   930 	    case CSdispatch:
   931 	    case CSstay:
   932 		break;
   933 	    }
   934 	    break;
   935 	case CSstay:
   936 	    break;
   937 	}
   938     if (strlen((char *)Line))
   939         return Line;
   940     free(Line);
   941     return NULL;
   942 }
   944 STATIC void
   945 hist_add(p)
   946     CHAR	*p;
   947 {
   948     int		i;
   950     if ((p = (CHAR *)strdup((char *)p)) == NULL)
   951 	return;
   952     if (H.Size < HIST_SIZE)
   953 	H.Lines[H.Size++] = p;
   954     else {
   955 	DISPOSE(H.Lines[0]);
   956 	for (i = 0; i < HIST_SIZE - 1; i++)
   957 	    H.Lines[i] = H.Lines[i + 1];
   958 	H.Lines[i] = p;
   959     }
   960     H.Pos = H.Size - 1;
   961 }
   963 /*
   964 **  For compatibility with FSF readline.
   965 */
   966 /* ARGSUSED0 */
   967 void
   968 rl_reset_terminal(p)
   969     char	*p;
   970 {
   971     (void)p;
   972 }
   974 void
   975 rl_initialize()
   976 {
   977 }
   979 char *
   980 readline(prompt)
   981     CONST char	*prompt;
   982 {
   983     CHAR	*line;
   984     int		s;
   986     if (Line == NULL) {
   987 	Length = MEM_INC;
   988 	if ((Line = NEW(CHAR, Length)) == NULL)
   989 	    return NULL;
   990     }
   992     TTYinfo();
   993     rl_ttyset(0);
   994     hist_add(NIL);
   995     ScreenSize = SCREEN_INC;
   996     Screen = NEW(char, ScreenSize);
   997     Prompt = prompt ? prompt : (char *)NIL;
   998     TTYputs((CONST CHAR *)Prompt);
   999     if ((line = editinput()) != NULL) {
  1000 	line = (CHAR *)strdup((char *)line);
  1001 	TTYputs((CONST CHAR *)NEWLINE);
  1002 	TTYflush();
  1004     rl_ttyset(1);
  1005     DISPOSE(Screen);
  1006     DISPOSE(H.Lines[--H.Size]);
  1007     if (Signal > 0) {
  1008 	s = Signal;
  1009 	Signal = 0;
  1010 	(void)kill(getpid(), s);
  1012     return (char *)line;
  1015 void
  1016 add_history(p)
  1017     char	*p;
  1019     if (p == NULL || *p == '\0')
  1020 	return;
  1022 #if	defined(UNIQUE_HISTORY)
  1023     if (H.Size && strcmp(p, (char *)H.Lines[H.Size - 1]) == 0)
  1024         return;
  1025 #endif	/* defined(UNIQUE_HISTORY) */
  1026     hist_add((CHAR *)p);
  1030 STATIC STATUS
  1031 beg_line()
  1033     if (Point) {
  1034 	Point = 0;
  1035 	return CSmove;
  1037     return CSstay;
  1040 STATIC STATUS
  1041 del_char()
  1043     return delete_string(Repeat == NO_ARG ? 1 : Repeat);
  1046 STATIC STATUS
  1047 end_line()
  1049     if (Point != End) {
  1050 	Point = End;
  1051 	return CSmove;
  1053     return CSstay;
  1056 STATIC STATUS
  1057 accept_line()
  1059     Line[End] = '\0';
  1060     return CSdone;
  1063 STATIC STATUS
  1064 transpose()
  1066     CHAR	c;
  1068     if (Point) {
  1069 	if (Point == End)
  1070 	    left(CSmove);
  1071 	c = Line[Point - 1];
  1072 	left(CSstay);
  1073 	Line[Point - 1] = Line[Point];
  1074 	TTYshow(Line[Point - 1]);
  1075 	Line[Point++] = c;
  1076 	TTYshow(c);
  1078     return CSstay;
  1081 STATIC STATUS
  1082 quote()
  1084     unsigned int	c;
  1086     return (int)(c = TTYget()) == EOF ? CSeof : insert_char((int)c);
  1089 STATIC STATUS
  1090 wipe()
  1092     int		i;
  1094     if (Mark > End)
  1095 	return ring_bell();
  1097     if (Point > Mark) {
  1098 	i = Point;
  1099 	Point = Mark;
  1100 	Mark = i;
  1101 	reposition();
  1104     return delete_string(Mark - Point);
  1107 STATIC STATUS
  1108 mk_set()
  1110     Mark = Point;
  1111     return CSstay;
  1114 STATIC STATUS
  1115 exchange()
  1117     unsigned int	c;
  1119     if ((c = TTYget()) != CTL('X'))
  1120 	return (int)c == EOF ? CSeof : ring_bell();
  1122     if ((int)(c = Mark) <= End) {
  1123 	Mark = Point;
  1124 	Point = c;
  1125 	return CSmove;
  1127     return CSstay;
  1130 STATIC STATUS
  1131 yank()
  1133     if (Yanked && *Yanked)
  1134 	return insert_string(Yanked);
  1135     return CSstay;
  1138 STATIC STATUS
  1139 copy_region()
  1141     if (Mark > End)
  1142 	return ring_bell();
  1144     if (Point > Mark)
  1145 	save_yank(Mark, Point - Mark);
  1146     else
  1147 	save_yank(Point, Mark - Point);
  1149     return CSstay;
  1152 STATIC STATUS
  1153 move_to_char()
  1155     unsigned int	c;
  1156     int			i;
  1157     CHAR		*p;
  1159     if ((int)(c = TTYget()) == EOF)
  1160 	return CSeof;
  1161     for (i = Point + 1, p = &Line[i]; i < End; i++, p++)
  1162 	if (*p == c) {
  1163 	    Point = i;
  1164 	    return CSmove;
  1166     return CSstay;
  1169 STATIC STATUS
  1170 fd_word()
  1172     return do_forward(CSmove);
  1175 STATIC STATUS
  1176 fd_kill_word()
  1178     int		i;
  1180     (void)do_forward(CSstay);
  1181     if (OldPoint != Point) {
  1182 	i = Point - OldPoint;
  1183 	Point = OldPoint;
  1184 	return delete_string(i);
  1186     return CSstay;
  1189 STATIC STATUS
  1190 bk_word()
  1192     int		i;
  1193     CHAR	*p;
  1195     i = 0;
  1196     do {
  1197 	for (p = &Line[Point]; p > Line && !isalnum(p[-1]); p--)
  1198 	    left(CSmove);
  1200 	for (; p > Line && p[-1] != ' ' && isalnum(p[-1]); p--)
  1201 	    left(CSmove);
  1203 	if (Point == 0)
  1204 	    break;
  1205     } while (++i < Repeat);
  1207     return CSstay;
  1210 STATIC STATUS
  1211 bk_kill_word()
  1213     (void)bk_word();
  1214     if (OldPoint != Point)
  1215 	return delete_string(OldPoint - Point);
  1216     return CSstay;
  1219 STATIC int
  1220 argify(line, avp)
  1221     CHAR	*line;
  1222     CHAR	***avp;
  1224     CHAR	*c;
  1225     CHAR	**p;
  1226     CHAR	**new;
  1227     int		ac;
  1228     int		i;
  1230     i = MEM_INC;
  1231     if ((*avp = p = NEW(CHAR*, i))== NULL)
  1232 	 return 0;
  1234     for (c = line; isspace(*c); c++)
  1235 	continue;
  1236     if (*c == '\n' || *c == '\0')
  1237 	return 0;
  1239     for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) {
  1240 	if (isspace(*c)) {
  1241 	    *c++ = '\0';
  1242 	    if (*c && *c != '\n') {
  1243 		if (ac + 1 == i) {
  1244 		    new = NEW(CHAR*, i + MEM_INC);
  1245 		    if (new == NULL) {
  1246 			p[ac] = NULL;
  1247 			return ac;
  1249 		    COPYFROMTO(new, p, i * sizeof (char **));
  1250 		    i += MEM_INC;
  1251 		    DISPOSE(p);
  1252 		    *avp = p = new;
  1254 		p[ac++] = c;
  1257 	else
  1258 	    c++;
  1260     *c = '\0';
  1261     p[ac] = NULL;
  1262     return ac;
  1265 STATIC STATUS
  1266 last_argument()
  1268     CHAR	**av;
  1269     CHAR	*p;
  1270     STATUS	s;
  1271     int		ac;
  1273     if (H.Size == 1 || (p = H.Lines[H.Size - 2]) == NULL)
  1274 	return ring_bell();
  1276     if ((p = (CHAR *)strdup((char *)p)) == NULL)
  1277 	return CSstay;
  1278     ac = argify(p, &av);
  1280     if (Repeat != NO_ARG)
  1281 	s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell();
  1282     else
  1283 	s = ac ? insert_string(av[ac - 1]) : CSstay;
  1285     if (ac)
  1286 	DISPOSE(av);
  1287     DISPOSE(p);
  1288     return s;
  1291 STATIC CONST KEYMAP Map[32] = {
  1292     {	CTL('@'),	ring_bell	},
  1293     {	CTL('A'),	beg_line	},
  1294     {	CTL('B'),	bk_char		},
  1295     {	CTL('D'),	del_char	},
  1296     {	CTL('E'),	end_line	},
  1297     {	CTL('F'),	fd_char		},
  1298     {	CTL('G'),	ring_bell	},
  1299     {	CTL('H'),	bk_del_char	},
  1300     {	CTL('J'),	accept_line	},
  1301     {	CTL('K'),	kill_line	},
  1302     {	CTL('L'),	redisplay	},
  1303     {	CTL('M'),	accept_line	},
  1304     {	CTL('N'),	h_next		},
  1305     {	CTL('O'),	ring_bell	},
  1306     {	CTL('P'),	h_prev		},
  1307     {	CTL('Q'),	ring_bell	},
  1308     {	CTL('R'),	h_search	},
  1309     {	CTL('S'),	ring_bell	},
  1310     {	CTL('T'),	transpose	},
  1311     {	CTL('U'),	ring_bell	},
  1312     {	CTL('V'),	quote		},
  1313     {	CTL('W'),	wipe		},
  1314     {	CTL('X'),	exchange	},
  1315     {	CTL('Y'),	yank		},
  1316     {	CTL('Z'),	ring_bell	},
  1317     {	CTL('['),	meta		},
  1318     {	CTL(']'),	move_to_char	},
  1319     {	CTL('^'),	ring_bell	},
  1320     {	CTL('_'),	ring_bell	},
  1321     {	0,		NULL		}
  1322 };
  1324 STATIC CONST KEYMAP MetaMap[16]= {
  1325     {	CTL('H'),	bk_kill_word	},
  1326     {	DEL,		bk_kill_word	},
  1327     {	' ',		mk_set		},
  1328     {	'.',		last_argument	},
  1329     {	'<',		h_first		},
  1330     {	'>',		h_last		},
  1331     {	'b',		bk_word		},
  1332     {	'd',		fd_kill_word	},
  1333     {	'f',		fd_word		},
  1334     {	'l',		case_down_word	},
  1335     {	'm',		toggle_meta_mode },
  1336     {	'u',		case_up_word	},
  1337     {	'y',		yank		},
  1338     {	'w',		copy_region	},
  1339     {	0,		NULL		}
  1340 };

mercurial