PageRenderTime 233ms CodeModel.GetById 80ms app.highlight 110ms RepoModel.GetById 31ms app.codeStats 1ms

/js/lib/Socket.IO-node/support/expresso/deps/jscoverage/js/editline/editline.c

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