editline [Salz and Turner]

bash-4.2# cat editline.shar

#! /bin/sh

# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# Contents:  README MANIFEST Make.os9 Makefile complete.c editline.3
#   editline.c editline.h os9.h sysos9.c sysunix.c testit.c unix.h
# Wrapped by rsalz@sulphur on Tue Oct 26 15:38:27 1993
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo '          "shar: End of archive 1 (of 1)."'
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
  echo shar: Extracting \"'README'\" \(2358 characters\)
  sed "s/^X//" >'README' <<'END_OF_FILE'
X$Revision: 1.9 $
X
XThis is a line-editing library.  It can be linked into almost any
Xprogram to provide command-line editing and recall.
X
XIt is call-compatible with the FSF readline library, but it is a
Xfraction of the size (and offers fewer features).  It does not use
Xstandard I/O.  It is distributed under a "C News-like" copyright.
X
XConfiguration is done in the Makefile.  Type "make testit" to get
Xa small slow shell for testing.
X
XAn earlier version was distributed with Byron's rc.  Principal
Xchanges over that version include:
X Faster.
X Is eight-bit clean (thanks to brendan@cs.widener.edu)
X Written in K&R C, but ANSI compliant (gcc all warnings)
X Propagates EOF properly; rc trip test now passes
X Doesn't need or use or provide memmove.
X More robust
X Calling sequence changed to be compatible with readline.
X Test program, new manpage, better configuration
X More system-independant; includes Unix and OS-9 support.
X
XThis contains some changes since the posting to comp.sources.misc:
X  Bugfix for completion on absolute pathnames.
X  Better handling of M-n versus showing raw 8bit chars.
X  Better signal handling.
X  Now supports termios/termio/sgttyb ioctl's.
X  Add M-m command to toggle how 8bit data is displayed.
X
XThere is one known bug:
X  History-searching redraws the line wrong if the text
X  retrieved is shorter then the prompt.
X
XEnjoy,
X Rich $alz
X <rsalz@osf.org>
X
X Copyright 1992,1993 Simmule Turner and Rich Salz.  All rights reserved.
X
X This software is not subject to any license of the American Telephone
X and Telegraph Company or of the Regents of the University of California.
X
X Permission is granted to anyone to use this software for any purpose on
X any computer system, and to alter it and redistribute it freely, subject
X to the following restrictions:
X 1. The authors are not responsible for the consequences of use of this
X    software, no matter how awful, even if they arise from flaws in it.
X 2. The origin of this software must not be misrepresented, either by
X    explicit claim or by omission.  Since few users ever read sources,
X    credits must appear in the documentation.
X 3. Altered versions must be plainly marked as such, and must not be
X    misrepresented as being the original software.  Since few users
X    ever read sources, credits must appear in the documentation.
X 4. This notice may not be removed or altered.
END_OF_FILE
  if test 2358 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
  fi
  # end of 'README'
fi
if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MANIFEST'\"
else
  echo shar: Extracting \"'MANIFEST'\" \(772 characters\)
  sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X   File Name Archive # Description
X----------------------------------------------------------
XREADME                     1 Release notes and copyright
XMANIFEST                   1 This shipping list
XMake.os9                   1 OS-9 makefile
XMakefile                   1 Unix makefile
Xcomplete.c                 1 Filename completion routines
Xeditline.3                 1 Manual page for editline library
Xeditline.c                 1 Line-editing routines
Xeditline.h                 1 Internal library header file
Xos9.h                      1 OS-9-specific declarations
Xsysos9.c                   1 OS-9-specific routines
Xsysunix.c                  1 Unix-specific routines
Xtestit.c                   1 Test driver
Xunix.h                     1 Unix-specific declarations
END_OF_FILE
  if test 772 -ne `wc -c <'MANIFEST'`; then
    echo shar: \"'MANIFEST'\" unpacked with wrong size!
  fi
  # end of 'MANIFEST'
fi
if test -f 'Make.os9' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Make.os9'\"
else
  echo shar: Extracting \"'Make.os9'\" \(348 characters\)
  sed "s/^X//" >'Make.os9' <<'END_OF_FILE'
X##  $Revision: 1.2 $
X##
X##  OS-9 makefile for editline library.
X##
X
X.SUFFIXES:
X
XRFILES = editline.r complete.r sysos9.r
X
X%.r: %.c
X cc68 -r -Dstrchr=index -Dstrrchr=rindex -DNEED_STRDUP -DSYS_OS9 $*.c
X
Xtestit: testit.r editline.lib
X cc68 -f=testit testit.r -l=editline.lib
X
X$(RFILES): $(RFILES:%.r=%.c)
X
Xeditline.lib: $(RFILES)
X cat $(RFILES) >$@
END_OF_FILE
  if test 348 -ne `wc -c <'Make.os9'`; then
    echo shar: \"'Make.os9'\" unpacked with wrong size!
  fi
  # end of 'Make.os9'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
  echo shar: Extracting \"'Makefile'\" \(1904 characters\)
  sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X##  $Revision: 1.9 $
X##
X##  Unix makefile for editline library.
X##
X
X##  Set your options:
X## -DANSI_ARROWS ANSI arrows keys work like emacs.
X## -DHAVE_STDLIB Have <stdlib.h>.
X## -DHAVE_TCGETATTR Have tcgetattr(), tcsetattr().
X## -DHAVE_TERMIO Have "struct termio" and <termio.h>
X## (If neither of above two, we use <sgttyb.h> and BSD ioctl's)
X## -DHIDE Make static functions static (non debug).
X## -DHIST_SIZE=n History size.
X## -DNEED_STRDUP Don't have strdup().
X## -DUNIQUE_HISTORY Don't save command if same as last one.
X## -DUSE_DIRENT Use <dirent.h>, not <sys/dir.h>?
X## -DUSE_TERMCAP Use the termcap library for terminal size
X## see LDFLAGS, below, if you set this.
X## -DNEED_PERROR Don't have perror() (used in testit)
X## -DDO_SIGTSTP Send SIGTSTP on "suspend" key
XDEFS = -DANSI_ARROWS -DHAVE_TCGETATTR -DHIDE -DUSE_DIRENT -DSYS_UNIX
X
X##  Set your C compiler:
XWARN = -Wall -Wshadow -Wpointer-arith -Wcast-qual -Wwrite-strings \
X -Wunused -Wcomment -Wswitch
X#CC = gcc -ansi $(WARN)
X#CFLAGS = $(DEFS) -O -g
XCC = cc
XCFLAGS = $(DEFS) -g
X
X##  If you have -DUSE_TERMCAP, set this as appropriate:
X#LDFLAGS = -ltermlib
X#LDFLAGS = -ltermcap
X
X##  Set ranlib as appropriate:
XRANLIB = ranlib
X#RANLIB = echo
X
X##  End of configuration.
X
XSOURCES = editline.c complete.c sysunix.c
XOBJECTS = editline.o complete.o sysunix.o
X
Xall: libedit.a
X
Xtestit: testit.c libedit.a
X $(CC) $(CFLAGS) -o testit testit.c libedit.a $(LDFLAGS)
X
Xshar: FORCE
X makekit -m -s100k
X mv Part01 shar
XFORCE:
X
Xclean:
X rm -f *.[oa] testit foo core tags lint lint.all a.out Part01
X
Xlint: testit
X lint -a -b -u -x $(DEFS) $(SOURCES) testit.c >lint.all
X sed -e '/warning: function prototype not in scope/d' \
X -e '/warning: old style argument declaration/'d \
X -e '/mix of old and new style function declaration/'d \
X <lint.all >lint
X
Xlibedit.a: $(OBJECTS)
X @rm -f $@
X ar r $@ $(OBJECTS)
X $(RANLIB) $@
X
X$(OBJECTS): editline.h
END_OF_FILE
  if test 1904 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
  fi
  # end of 'Makefile'
fi
if test -f 'complete.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'complete.c'\"
else
  echo shar: Extracting \"'complete.c'\" \(4113 characters\)
  sed "s/^X//" >'complete.c' <<'END_OF_FILE'
X/*  $Revision: 1.4 $
X**
X**  History and file completion functions for editline library.
X*/
X#include "editline.h"
X
X
X#if defined(NEED_STRDUP)
X/*
X**  Return an allocated copy of a string.
X*/
Xchar *
Xstrdup(p)
X    char *p;
X{
X    char *new;
X
X    if ((new = NEW(char, strlen(p) + 1)) != NULL)
X (void)strcpy(new, p);
X    return new;
X}
X#endif /* defined(NEED_STRDUP) */
X
X/*
X**  strcmp-like sorting predicate for qsort.
X*/
XSTATIC int
Xcompare(p1, p2)
X    CONST void *p1;
X    CONST void *p2;
X{
X    CONST char **v1;
X    CONST char **v2;
X
X    v1 = (CONST char **)p1;
X    v2 = (CONST char **)p2;
X    return strcmp(*v1, *v2);
X}
X
X/*
X**  Fill in *avp with an array of names that match file, up to its length.
X**  Ignore . and .. .
X*/
XSTATIC int
XFindMatches(dir, file, avp)
X    char *dir;
X    char *file;
X    char ***avp;
X{
X    char **av;
X    char **new;
X    char *p;
X    DIR *dp;
X    DIRENTRY *ep;
X    SIZE_T ac;
X    SIZE_T len;
X
X    if ((dp = opendir(dir)) == NULL)
X return 0;
X
X    av = NULL;
X    ac = 0;
X    len = strlen(file);
X    while ((ep = readdir(dp)) != NULL) {
X p = ep->d_name;
X if (p[0] == '.' && (p[1] == '\0' || (p[1] == '.' && p[2] == '\0')))
X    continue;
X if (len && strncmp(p, file, len) != 0)
X    continue;
X
X if ((ac % MEM_INC) == 0) {
X    if ((new = NEW(char*, ac + MEM_INC)) == NULL)
X break;
X    if (ac) {
X COPYFROMTO(new, av, ac * sizeof (char **));
X DISPOSE(av);
X    }
X    *avp = av = new;
X }
X
X if ((av[ac] = strdup(p)) == NULL) {
X    if (ac == 0)
X DISPOSE(av);
X    break;
X }
X ac++;
X    }
X
X    /* Clean up and return. */
X    (void)closedir(dp);
X    if (ac)
X qsort(av, ac, sizeof (char **), compare);
X    return ac;
X}
X
X/*
X**  Split a pathname into allocated directory and trailing filename parts.
X*/
XSTATIC int
XSplitPath(path, dirpart, filepart)
X    char *path;
X    char **dirpart;
X    char **filepart;
X{
X    static char DOT[] = ".";
X    char *dpart;
X    char *fpart;
X
X    if ((fpart = strrchr(path, '/')) == NULL) {
X if ((dpart = strdup(DOT)) == NULL)
X    return -1;
X if ((fpart = strdup(path)) == NULL) {
X    DISPOSE(dpart);
X    return -1;
X }
X    }
X    else {
X if ((dpart = strdup(path)) == NULL)
X    return -1;
X dpart[fpart - path + 1] = '\0';
X if ((fpart = strdup(++fpart)) == NULL) {
X    DISPOSE(dpart);
X    return -1;
X }
X    }
X    *dirpart = dpart;
X    *filepart = fpart;
X    return 0;
X}
X
X/*
X**  Attempt to complete the pathname, returning an allocated copy.
X**  Fill in *unique if we completed it, or set it to 0 if ambiguous.
X*/
Xchar *
Xrl_complete(pathname, unique)
X    char *pathname;
X    int *unique;
X{
X    char **av;
X    char *dir;
X    char *file;
X    char *new;
X    char *p;
X    SIZE_T ac;
X    SIZE_T end;
X    SIZE_T i;
X    SIZE_T j;
X    SIZE_T len;
X
X    if (SplitPath(pathname, &dir, &file) < 0)
X return NULL;
X    if ((ac = FindMatches(dir, file, &av)) == 0) {
X DISPOSE(dir);
X DISPOSE(file);
X return NULL;
X    }
X
X    p = NULL;
X    len = strlen(file);
X    if (ac == 1) {
X /* Exactly one match -- finish it off. */
X *unique = 1;
X j = strlen(av[0]) - len + 2;
X if ((p = NEW(char, j + 1)) != NULL) {
X    COPYFROMTO(p, av[0] + len, j);
X    if ((new = NEW(char, strlen(dir) + strlen(av[0]) + 2)) != NULL) {
X (void)strcpy(new, dir);
X (void)strcat(new, "/");
X (void)strcat(new, av[0]);
X rl_add_slash(new, p);
X DISPOSE(new);
X    }
X }
X    }
X    else {
X *unique = 0;
X if (len) {
X    /* Find largest matching substring. */
X    for (i = len, end = strlen(av[0]); i < end; i++)
X for (j = 1; j < ac; j++)
X    if (av[0][i] != av[j][i])
X goto breakout;
X  breakout:
X    if (i > len) {
X j = i - len + 1;
X if ((p = NEW(char, j)) != NULL) {
X    COPYFROMTO(p, av[0] + len, j);
X    p[j - 1] = '\0';
X }
X    }
X }
X    }
X
X    /* Clean up and return. */
X    DISPOSE(dir);
X    DISPOSE(file);
X    for (i = 0; i < ac; i++)
X DISPOSE(av[i]);
X    DISPOSE(av);
X    return p;
X}
X
X/*
X**  Return all possible completions.
X*/
Xint
Xrl_list_possib(pathname, avp)
X    char *pathname;
X    char ***avp;
X{
X    char *dir;
X    char *file;
X    int ac;
X
X    if (SplitPath(pathname, &dir, &file) < 0)
X return 0;
X    ac = FindMatches(dir, file, avp);
X    DISPOSE(dir);
X    DISPOSE(file);
X    return ac;
X}
END_OF_FILE
  if test 4113 -ne `wc -c <'complete.c'`; then
    echo shar: \"'complete.c'\" unpacked with wrong size!
  fi
  # end of 'complete.c'
fi
if test -f 'editline.3' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'editline.3'\"
else
  echo shar: Extracting \"'editline.3'\" \(5321 characters\)
  sed "s/^X//" >'editline.3' <<'END_OF_FILE'
X.\" $Revision: 1.3 $
X.TH EDITLINE 3
X.SH NAME
Xeditline \- command-line editing library with history
X.SH SYNOPSIS
X.nf
X.B "char *"
X.B "readline(prompt)"
X.B "     char *prompt;"
X
X.B "void"
X.B "add_history(line)"
X.B "    char *line;"
X.fi
X.SH DESCRIPTION
X.I Editline
Xis a library that provides an line-editing interface with text recall.
XIt is intended to be compatible with the
X.I readline
Xlibrary provided by the Free Software Foundation, but much smaller.
XThe bulk of this manual page describes the user interface.
X.PP
XThe
X.I readline
Xroutine returns a line of text with the trailing newline removed.
XThe data is returned in a buffer allocated with
X.IR malloc (3),
Xso the space should be released with
X.IR free (3)
Xwhen the calling program is done with it.
XBefore accepting input from the user, the specified
X.I prompt
Xis displayed on the terminal.
X.PP
XThe
X.I add_history
Xroutine makes a copy of the specified
X.I line
Xand adds it to the internal history list.
X.SS "User Interface"
XA program that uses this library provides a simple emacs-like editing
Xinterface to its users.
XA line may be edited before it is sent to the calling program by typing either
Xcontrol characters or escape sequences.
XA control character, shown as a caret followed by a letter, is typed by
Xholding down the ``control'' key while the letter is typed.
XFor example, ``^A'' is a control-A.
XAn escape sequence is entered by typing the ``escape'' key followed by one or
Xmore characters.
XThe escape key is abbreviated as ``ESC.''
XNote that unlike control keys, case matters in escape sequences; ``ESC\ F''
Xis not the same as ``ESC\ f''.
X.PP
XAn editing command may be typed anywhere on the line, not just at the
Xbeginning.
XIn addition, a return may also be typed anywhere on the line, not just at
Xthe end.
X.PP
XMost editing commands may be given a repeat count,
X.IR n ,
Xwhere
X.I n
Xis a number.
XTo enter a repeat count, type the escape key, the number, and then
Xthe command to execute.
XFor example, ``ESC\ 4\ ^f'' moves forward four characters.
XIf a command may be given a repeat count then the text ``[n]'' is given at the
Xend of its description.
X.PP
XThe following control characters are accepted:
X.RS
X.nf
X.ta \w'ESC DEL  'u
X^A Move to the beginning of the line
X^B Move left (backwards) [n]
X^D Delete character [n]
X^E Move to end of line
X^F Move right (forwards) [n]
X^G Ring the bell
X^H Delete character before cursor (backspace key) [n]
X^I Complete filename (tab key); see below
X^J Done with line (return key)
X^K Kill to end of line (or column [n])
X^L Redisplay line
X^M Done with line (alternate return key)
X^N Get next line from history [n]
X^P Get previous line from history [n]
X^R Search backward (forward if [n]) through history for text;
X\& must start line if text begins with an uparrow
X^T Transpose characters
X^V Insert next character, even if it is an edit command
X^W Wipe to the mark
X^X^X Exchange current location and mark
X^Y Yank back last killed text
X^[ Start an escape sequence (escape key)
X^]c Move forward to next character ``c''
X^? Delete character before cursor (delete key) [n]
X.fi
X.RE
X.PP
XThe following escape sequences are provided.
X.RS
X.nf
X.ta \w'ESC DEL  'u
XESC\ ^H Delete previous word (backspace key) [n]
XESC\ DEL Delete previous word (delete key) [n]
XESC\ SP Set the mark (space key); see ^X^X and ^Y above
XESC\ \. Get the last (or [n]'th) word from previous line
XESC\ \? Show possible completions; see below
XESC\ < Move to start of history
XESC\ > Move to end of history
XESC\ b Move backward a word [n]
XESC\ d Delete word under cursor [n]
XESC\ f Move forward a word [n]
XESC\ l Make word lowercase [n]
XESC\ m Toggle if 8bit chars display normally or with ``M\-'' prefix
XESC\ u Make word uppercase [n]
XESC\ y Yank back last killed text
XESC\ w Make area up to mark yankable
XESC\ nn Set repeat count to the number nn
XESC\ C Read from environment variable ``_C_'', where C is
X\& an uppercase letter
X.fi
X.RE
X.PP
XThe
X.I editline
Xlibrary has a small macro facility.
XIf you type the escape key followed by an uppercase letter,
X.IR C ,
Xthen the contents of the environment variable
X.I _C_
Xare read in as if you had typed them at the keyboard.
XFor example, if the variable
X.I _L_
Xcontains the following:
X.RS
X^A^Kecho '^V^[[H^V^[[2J'^M
X.RE
XThen typing ``ESC L'' will move to the beginning of the line, kill the
Xentire line, enter the echo command needed to clear the terminal (if your
Xterminal is like a VT-100), and send the line back to the shell.
X.PP
XThe
X.I editline
Xlibrary also does filename completion.
XSuppose the root directory has the following files in it:
X.RS
X.nf
X.ta \w'core   'u
Xbin vmunix
Xcore vmunix.old
X.fi
X.RE
XIf you type ``rm\ /v'' and then the tab key.
X.I Editline
Xwill then finish off as much of the name as possible by adding ``munix''.
XBecause the name is not unique, it will then beep.
XIf you type the escape key and a question mark, it will display the
Xtwo choices.
XIf you then type a period and a tab, the library will finish off the filename
Xfor you:
X.RS
X.nf
X.RI "rm /v[TAB]" munix .TAB old
X.fi
X.RE
XThe tab key is shown by ``[TAB]'' and the automatically-entered text
Xis shown in italics.
X.SH "BUGS AND LIMITATIONS"
XCannot handle lines more than 80 columns.
X.SH AUTHORS
XSimmule R. Turner <uunet.uu.net!capitol!sysgo!simmy>
Xand Rich $alz <rsalz@osf.org>.
XOriginal manual page by DaviD W. Sanderson <dws@ssec.wisc.edu>.
END_OF_FILE
  if test 5321 -ne `wc -c <'editline.3'`; then
    echo shar: \"'editline.3'\" unpacked with wrong size!
  fi
  # end of 'editline.3'
fi
if test -f 'editline.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'editline.c'\"
else
  echo shar: Extracting \"'editline.c'\" \(23405 characters\)
  sed "s/^X//" >'editline.c' <<'END_OF_FILE'
X/*  $Revision: 1.9 $
X**
X**  Main editing routines for editline library.
X*/
X#include "editline.h"
X#include <signal.h>
X#include <ctype.h>
X
X/*
X**  Manifest constants.
X*/
X#define SCREEN_WIDTH 80
X#define SCREEN_ROWS 24
X#define NO_ARG (-1)
X#define DEL 127
X#define CTL(x) ((x) & 0x1F)
X#define ISCTL(x) ((x) && (x) < ' ')
X#define UNCTL(x) ((x) + 64)
X#define META(x) ((x) | 0x80)
X#define ISMETA(x) ((x) & 0x80)
X#define UNMETA(x) ((x) & 0x7F)
X#if !defined(HIST_SIZE)
X#define HIST_SIZE 20
X#endif /* !defined(HIST_SIZE) */
X
Xtypedef CONST CHAR *STRING;
X
X/*
X**  Command status codes.
X*/
Xtypedef enum _STATUS {
X    CSdone, CSeof, CSmove, CSdispatch, CSstay, CSsignal
X} STATUS;
X
X/*
X**  The type of case-changing to perform.
X*/
Xtypedef enum _CASE {
X    TOupper, TOlower
X} CASE;
X
X/*
X**  Key to command mapping.
X*/
Xtypedef struct _KEYMAP {
X    CHAR Key;
X    STATUS (*Function)();
X} KEYMAP;
X
X/*
X**  Command history structure.
X*/
Xtypedef struct _HISTORY {
X    int Size;
X    int Pos;
X    CHAR *Lines[HIST_SIZE];
X} HISTORY;
X
X/*
X**  Globals.
X*/
Xint rl_eof;
Xint rl_erase;
Xint rl_intr;
Xint rl_kill;
Xint rl_quit;
X#if defined(DO_SIGTSTP)
Xint rl_susp;
X#endif /* defined(DO_SIGTSTP) */
X
XSTATIC CHAR NIL[] = "";
XSTATIC STRING Input = NIL;
XSTATIC CHAR *Line;
XSTATIC CONST char *Prompt;
XSTATIC CHAR *Yanked;
XSTATIC char *Screen;
XSTATIC char NEWLINE[]= CRLF;
XSTATIC HISTORY H;
XSTATIC int Repeat;
XSTATIC int End;
XSTATIC int Mark;
XSTATIC int OldPoint;
XSTATIC int Point;
XSTATIC int PushBack;
XSTATIC int Pushed;
XSTATIC int Signal;
XFORWARD KEYMAP Map[33];
XFORWARD KEYMAP MetaMap[17];
XSTATIC SIZE_T Length;
XSTATIC SIZE_T ScreenCount;
XSTATIC SIZE_T ScreenSize;
XSTATIC char *backspace;
XSTATIC int TTYwidth;
XSTATIC int TTYrows;
X
X/* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */
Xint rl_meta_chars = 1;
X
X/*
X**  Declarations.
X*/
XSTATIC CHAR *editinput();
Xextern int read();
Xextern int write();
X#if defined(USE_TERMCAP)
Xextern char *getenv();
Xextern char *tgetstr();
Xextern int tgetent();
Xextern int tgetnum();
X#endif /* defined(USE_TERMCAP) */
X
X/*
X**  TTY input/output functions.
X*/
X
XSTATIC void
XTTYflush()
X{
X    if (ScreenCount) {
X (void)write(1, Screen, ScreenCount);
X ScreenCount = 0;
X    }
X}
X
XSTATIC void
XTTYput(c)
X    CONST CHAR c;
X{
X    Screen[ScreenCount] = c;
X    if (++ScreenCount >= ScreenSize - 1) {
X ScreenSize += SCREEN_INC;
X RENEW(Screen, char, ScreenSize);
X    }
X}
X
XSTATIC void
XTTYputs(p)
X    STRING p;
X{
X    while (*p)
X TTYput(*p++);
X}
X
XSTATIC void
XTTYshow(c)
X    CHAR c;
X{
X    if (c == DEL) {
X TTYput('^');
X TTYput('?');
X    }
X    else if (ISCTL(c)) {
X TTYput('^');
X TTYput(UNCTL(c));
X    }
X    else if (rl_meta_chars && ISMETA(c)) {
X TTYput('M');
X TTYput('-');
X TTYput(UNMETA(c));
X    }
X    else
X TTYput(c);
X}
X
XSTATIC void
XTTYstring(p)
X    CHAR *p;
X{
X    while (*p)
X TTYshow(*p++);
X}
X
XSTATIC unsigned int
XTTYget()
X{
X    CHAR c;
X
X    TTYflush();
X    if (Pushed) {
X Pushed = 0;
X return PushBack;
X    }
X    if (*Input)
X return *Input++;
X    return read(0, &c, (SIZE_T)1) == 1 ? c : EOF;
X}
X
X#define TTYback() (backspace ? TTYputs((STRING)backspace) : TTYput('\b'))
X
XSTATIC void
XTTYbackn(n)
X    int n;
X{
X    while (--n >= 0)
X TTYback();
X}
X
XSTATIC void
XTTYinfo()
X{
X    static int init;
X#if defined(USE_TERMCAP)
X    char *term;
X    char buff[2048];
X    char *bp;
X    char *p;
X#endif /* defined(USE_TERMCAP) */
X#if defined(TIOCGWINSZ)
X    struct winsize W;
X#endif /* defined(TIOCGWINSZ) */
X
X    if (init) {
X#if defined(TIOCGWINSZ)
X /* Perhaps we got resized. */
X if (ioctl(0, TIOCGWINSZ, &W) >= 0
X && W.ws_col > 0 && W.ws_row > 0) {
X    TTYwidth = (int)W.ws_col;
X    TTYrows = (int)W.ws_row;
X }
X#endif /* defined(TIOCGWINSZ) */
X return;
X    }
X    init++;
X
X    TTYwidth = TTYrows = 0;
X#if defined(USE_TERMCAP)
X    bp = &buff[0];
X    if ((term = getenv("TERM")) == NULL)
X term = "dumb";
X    if (tgetent(buff, term) < 0) {
X       TTYwidth = SCREEN_WIDTH;
X       TTYrows = SCREEN_ROWS;
X       return;
X    }
X    p = tgetstr("le", &bp);
X    backspace = p ? strdup(p) : NULL;
X    TTYwidth = tgetnum("co");
X    TTYrows = tgetnum("li");
X#endif /* defined(USE_TERMCAP) */
X
X#if defined(TIOCGWINSZ)
X    if (ioctl(0, TIOCGWINSZ, &W) >= 0) {
X TTYwidth = (int)W.ws_col;
X TTYrows = (int)W.ws_row;
X    }
X#endif /* defined(TIOCGWINSZ) */
X
X    if (TTYwidth <= 0 || TTYrows <= 0) {
X TTYwidth = SCREEN_WIDTH;
X TTYrows = SCREEN_ROWS;
X    }
X}
X
X
X/*
X**  Print an array of words in columns.
X*/
XSTATIC void
Xcolumns(ac, av)
X    int ac;
X    CHAR **av;
X{
X    CHAR *p;
X    int i;
X    int j;
X    int k;
X    int len;
X    int skip;
X    int longest;
X    int cols;
X
X    /* Find longest name, determine column count from that. */
X    for (longest = 0, i = 0; i < ac; i++)
X if ((j = strlen((char *)av[i])) > longest)
X    longest = j;
X    cols = TTYwidth / (longest + 3);
X
X    TTYputs((STRING)NEWLINE);
X    for (skip = ac / cols + 1, i = 0; i < skip; i++) {
X for (j = i; j < ac; j += skip) {
X    for (p = av[j], len = strlen((char *)p), k = len; --k >= 0; p++)
X TTYput(*p);
X    if (j + skip < ac)
X while (++len < longest + 3)
X    TTYput(' ');
X }
X TTYputs((STRING)NEWLINE);
X    }
X}
X
XSTATIC void
Xreposition()
X{
X    int i;
X    CHAR *p;
X
X    TTYput('\r');
X    TTYputs((STRING)Prompt);
X    for (i = Point, p = Line; --i >= 0; p++)
X TTYshow(*p);
X}
X
XSTATIC void
Xleft(Change)
X    STATUS Change;
X{
X    TTYback();
X    if (Point) {
X if (ISCTL(Line[Point - 1]))
X    TTYback();
X        else if (rl_meta_chars && ISMETA(Line[Point - 1])) {
X    TTYback();
X    TTYback();
X }
X    }
X    if (Change == CSmove)
X Point--;
X}
X
XSTATIC void
Xright(Change)
X    STATUS Change;
X{
X    TTYshow(Line[Point]);
X    if (Change == CSmove)
X Point++;
X}
X
XSTATIC STATUS
Xring_bell()
X{
X    TTYput('\07');
X    TTYflush();
X    return CSstay;
X}
X
XSTATIC STATUS
Xdo_macro(c)
X    unsigned int c;
X{
X    CHAR name[4];
X
X    name[0] = '_';
X    name[1] = c;
X    name[2] = '_';
X    name[3] = '\0';
X
X    if ((Input = (CHAR *)getenv((char *)name)) == NULL) {
X Input = NIL;
X return ring_bell();
X    }
X    return CSstay;
X}
X
XSTATIC STATUS
Xdo_forward(move)
X    STATUS move;
X{
X    int i;
X    CHAR *p;
X
X    i = 0;
X    do {
X p = &Line[Point];
X for ( ; Point < End && (*p == ' ' || !isalnum(*p)); Point++, p++)
X    if (move == CSmove)
X right(CSstay);
X
X for (; Point < End && isalnum(*p); Point++, p++)
X    if (move == CSmove)
X right(CSstay);
X
X if (Point == End)
X    break;
X    } while (++i < Repeat);
X
X    return CSstay;
X}
X
XSTATIC STATUS
Xdo_case(type)
X    CASE type;
X{
X    int i;
X    int end;
X    int count;
X    CHAR *p;
X
X    (void)do_forward(CSstay);
X    if (OldPoint != Point) {
X if ((count = Point - OldPoint) < 0)
X    count = -count;
X Point = OldPoint;
X if ((end = Point + count) > End)
X    end = End;
X for (i = Point, p = &Line[i]; i < end; i++, p++) {
X    if (type == TOupper) {
X if (islower(*p))
X    *p = toupper(*p);
X    }
X    else if (isupper(*p))
X *p = tolower(*p);
X    right(CSmove);
X }
X    }
X    return CSstay;
X}
X
XSTATIC STATUS
Xcase_down_word()
X{
X    return do_case(TOlower);
X}
X
XSTATIC STATUS
Xcase_up_word()
X{
X    return do_case(TOupper);
X}
X
XSTATIC void
Xceol()
X{
X    int extras;
X    int i;
X    CHAR *p;
X
X    for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) {
X TTYput(' ');
X if (ISCTL(*p)) {
X    TTYput(' ');
X    extras++;
X }
X else if (rl_meta_chars && ISMETA(*p)) {
X    TTYput(' ');
X    TTYput(' ');
X    extras += 2;
X }
X    }
X
X    for (i += extras; i > Point; i--)
X TTYback();
X}
X
XSTATIC void
Xclear_line()
X{
X    Point = -strlen(Prompt);
X    TTYput('\r');
X    ceol();
X    Point = 0;
X    End = 0;
X    Line[0] = '\0';
X}
X
XSTATIC STATUS
Xinsert_string(p)
X    CHAR *p;
X{
X    SIZE_T len;
X    int i;
X    CHAR *new;
X    CHAR *q;
X
X    len = strlen((char *)p);
X    if (End + len >= Length) {
X if ((new = NEW(CHAR, Length + len + MEM_INC)) == NULL)
X    return CSstay;
X if (Length) {
X    COPYFROMTO(new, Line, Length);
X    DISPOSE(Line);
X }
X Line = new;
X Length += len + MEM_INC;
X    }
X
X    for (q = &Line[Point], i = End - Point; --i >= 0; )
X q[len + i] = q[i];
X    COPYFROMTO(&Line[Point], p, len);
X    End += len;
X    Line[End] = '\0';
X    TTYstring(&Line[Point]);
X    Point += len;
X
X    return Point == End ? CSstay : CSmove;
X}
X
XSTATIC STATUS
Xredisplay()
X{
X    TTYputs((STRING)NEWLINE);
X    TTYputs((STRING)Prompt);
X    TTYstring(Line);
X    return CSmove;
X}
X
XSTATIC STATUS
Xtoggle_meta_mode()
X{
X    rl_meta_chars = !rl_meta_chars;
X    return redisplay();
X}
X
X
XSTATIC CHAR *
Xnext_hist()
X{
X    return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];
X}
X
XSTATIC CHAR *
Xprev_hist()
X{
X    return H.Pos == 0 ? NULL : H.Lines[--H.Pos];
X}
X
XSTATIC STATUS
Xdo_insert_hist(p)
X    CHAR *p;
X{
X    if (p == NULL)
X return ring_bell();
X    Point = 0;
X    reposition();
X    ceol();
X    End = 0;
X    return insert_string(p);
X}
X
XSTATIC STATUS
Xdo_hist(move)
X    CHAR *(*move)();
X{
X    CHAR *p;
X    int i;
X
X    i = 0;
X    do {
X if ((p = (*move)()) == NULL)
X    return ring_bell();
X    } while (++i < Repeat);
X    return do_insert_hist(p);
X}
X
XSTATIC STATUS
Xh_next()
X{
X    return do_hist(next_hist);
X}
X
XSTATIC STATUS
Xh_prev()
X{
X    return do_hist(prev_hist);
X}
X
XSTATIC STATUS
Xh_first()
X{
X    return do_insert_hist(H.Lines[H.Pos = 0]);
X}
X
XSTATIC STATUS
Xh_last()
X{
X    return do_insert_hist(H.Lines[H.Pos = H.Size - 1]);
X}
X
X/*
X**  Return zero if pat appears as a substring in text.
X*/
XSTATIC int
Xsubstrcmp(text, pat, len)
X    char *text;
X    char *pat;
X    int len;
X{
X    CHAR c;
X
X    if ((c = *pat) == '\0')
X        return *text == '\0';
X    for ( ; *text; text++)
X        if (*text == c && strncmp(text, pat, len) == 0)
X            return 0;
X    return 1;
X}
X
XSTATIC CHAR *
Xsearch_hist(search, move)
X    CHAR *search;
X    CHAR *(*move)();
X{
X    static CHAR *old_search;
X    int len;
X    int pos;
X    int (*match)();
X    char *pat;
X
X    /* Save or get remembered search pattern. */
X    if (search && *search) {
X if (old_search)
X    DISPOSE(old_search);
X old_search = (CHAR *)strdup((char *)search);
X    }
X    else {
X if (old_search == NULL || *old_search == '\0')
X            return NULL;
X search = old_search;
X    }
X
X    /* Set up pattern-finder. */
X    if (*search == '^') {
X match = strncmp;
X pat = (char *)(search + 1);
X    }
X    else {
X match = substrcmp;
X pat = (char *)search;
X    }
X    len = strlen(pat);
X
X    for (pos = H.Pos; (*move)() != NULL; )
X if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0)
X            return H.Lines[H.Pos];
X    H.Pos = pos;
X    return NULL;
X}
X
XSTATIC STATUS
Xh_search()
X{
X    static int Searching;
X    CONST char *old_prompt;
X    CHAR *(*move)();
X    CHAR *p;
X
X    if (Searching)
X return ring_bell();
X    Searching = 1;
X
X    clear_line();
X    old_prompt = Prompt;
X    Prompt = "Search: ";
X    TTYputs((STRING)Prompt);
X    move = Repeat == NO_ARG ? prev_hist : next_hist;
X    p = editinput();
X    Prompt = old_prompt;
X    Searching = 0;
X    TTYputs((STRING)Prompt);
X    if (p == NULL && Signal > 0) {
X Signal = 0;
X clear_line();
X return redisplay();
X    }
X    p = search_hist(p, move);
X    clear_line();
X    if (p == NULL) {
X (void)ring_bell();
X return redisplay();
X    }
X    return do_insert_hist(p);
X}
X
XSTATIC STATUS
Xfd_char()
X{
X    int i;
X
X    i = 0;
X    do {
X if (Point >= End)
X    break;
X right(CSmove);
X    } while (++i < Repeat);
X    return CSstay;
X}
X
XSTATIC void
Xsave_yank(begin, i)
X    int begin;
X    int i;
X{
X    if (Yanked) {
X DISPOSE(Yanked);
X Yanked = NULL;
X    }
X
X    if (i < 1)
X return;
X
X    if ((Yanked = NEW(CHAR, (SIZE_T)i + 1)) != NULL) {
X COPYFROMTO(Yanked, &Line[begin], i);
X Yanked[i] = '\0';
X    }
X}
X
XSTATIC STATUS
Xdelete_string(count)
X    int count;
X{
X    int i;
X    CHAR *p;
X
X    if (count <= 0 || End == Point)
X return ring_bell();
X
X    if (count == 1 && Point == End - 1) {
X /* Optimize common case of delete at end of line. */
X End--;
X p = &Line[Point];
X i = 1;
X TTYput(' ');
X if (ISCTL(*p)) {
X    i = 2;
X    TTYput(' ');
X }
X else if (rl_meta_chars && ISMETA(*p)) {
X    i = 3;
X    TTYput(' ');
X    TTYput(' ');
X }
X TTYbackn(i);
X *p = '\0';
X return CSmove;
X    }
X    if (Point + count > End && (count = End - Point) <= 0)
X return CSstay;
X
X    if (count > 1)
X save_yank(Point, count);
X
X    for (p = &Line[Point], i = End - (Point + count) + 1; --i >= 0; p++)
X p[0] = p[count];
X    ceol();
X    End -= count;
X    TTYstring(&Line[Point]);
X    return CSmove;
X}
X
XSTATIC STATUS
Xbk_char()
X{
X    int i;
X
X    i = 0;
X    do {
X if (Point == 0)
X    break;
X left(CSmove);
X    } while (++i < Repeat);
X
X    return CSstay;
X}
X
XSTATIC STATUS
Xbk_del_char()
X{
X    int i;
X
X    i = 0;
X    do {
X if (Point == 0)
X    break;
X left(CSmove);
X    } while (++i < Repeat);
X
X    return delete_string(i);
X}
X
XSTATIC STATUS
Xkill_line()
X{
X    int i;
X
X    if (Repeat != NO_ARG) {
X if (Repeat < Point) {
X    i = Point;
X    Point = Repeat;
X    reposition();
X    (void)delete_string(i - Point);
X }
X else if (Repeat > Point) {
X    right(CSmove);
X    (void)delete_string(Repeat - Point - 1);
X }
X return CSmove;
X    }
X
X    save_yank(Point, End - Point);
X    Line[Point] = '\0';
X    ceol();
X    End = Point;
X    return CSstay;
X}
X
XSTATIC STATUS
Xinsert_char(c)
X    int c;
X{
X    STATUS s;
X    CHAR buff[2];
X    CHAR *p;
X    CHAR *q;
X    int i;
X
X    if (Repeat == NO_ARG || Repeat < 2) {
X buff[0] = c;
X buff[1] = '\0';
X return insert_string(buff);
X    }
X
X    if ((p = NEW(CHAR, Repeat + 1)) == NULL)
X return CSstay;
X    for (i = Repeat, q = p; --i >= 0; )
X *q++ = c;
X    *q = '\0';
X    Repeat = 0;
X    s = insert_string(p);
X    DISPOSE(p);
X    return s;
X}
X
XSTATIC STATUS
Xmeta()
X{
X    unsigned int c;
X    KEYMAP *kp;
X
X    if ((c = TTYget()) == EOF)
X return CSeof;
X#if defined(ANSI_ARROWS)
X    /* Also include VT-100 arrows. */
X    if (c == '[' || c == 'O')
X switch ((int)(c = TTYget())) {
X default: return ring_bell();
X case EOF: return CSeof;
X case 'A': return h_prev();
X case 'B': return h_next();
X case 'C': return fd_char();
X case 'D': return bk_char();
X }
X#endif /* defined(ANSI_ARROWS) */
X
X    if (isdigit(c)) {
X for (Repeat = c - '0'; (c = TTYget()) != EOF && isdigit(c); )
X    Repeat = Repeat * 10 + c - '0';
X Pushed = 1;
X PushBack = c;
X return CSstay;
X    }
X
X    if (isupper(c))
X return do_macro(c);
X    for (OldPoint = Point, kp = MetaMap; kp->Function; kp++)
X if (kp->Key == c)
X    return (*kp->Function)();
X
X    return ring_bell();
X}
X
XSTATIC STATUS
Xemacs(c)
X    unsigned int c;
X{
X    STATUS s;
X    KEYMAP *kp;
X
X    if (rl_meta_chars && ISMETA(c)) {
X Pushed = 1;
X PushBack = UNMETA(c);
X return meta();
X    }
X    for (kp = Map; kp->Function; kp++)
X if (kp->Key == c)
X    break;
X    s = kp->Function ? (*kp->Function)() : insert_char((int)c);
X    if (!Pushed)
X /* No pushback means no repeat count; hacky, but true. */
X Repeat = NO_ARG;
X    return s;
X}
X
XSTATIC STATUS
XTTYspecial(c)
X    unsigned int c;
X{
X    if (ISMETA(c))
X return CSdispatch;
X
X    if (c == rl_erase || c == DEL)
X return bk_del_char();
X    if (c == rl_kill) {
X if (Point != 0) {
X    Point = 0;
X    reposition();
X }
X Repeat = NO_ARG;
X return kill_line();
X    }
X    if (c == rl_eof && Point == 0 && End == 0)
X return CSeof;
X    if (c == rl_intr) {
X Signal = SIGINT;
X return CSsignal;
X    }
X    if (c == rl_quit) {
X Signal = SIGQUIT;
X return CSeof;
X    }
X#if defined(DO_SIGTSTP)
X    if (c == rl_susp) {
X Signal = SIGTSTP;
X return CSsignal;
X    }
X#endif /* defined(DO_SIGTSTP) */
X
X    return CSdispatch;
X}
X
XSTATIC CHAR *
Xeditinput()
X{
X    unsigned int c;
X
X    Repeat = NO_ARG;
X    OldPoint = Point = Mark = End = 0;
X    Line[0] = '\0';
X
X    Signal = -1;
X    while ((c = TTYget()) != EOF)
X switch (TTYspecial(c)) {
X case CSdone:
X    return Line;
X case CSeof:
X    return NULL;
X case CSsignal:
X    return (CHAR *)"";
X case CSmove:
X    reposition();
X    break;
X case CSdispatch:
X    switch (emacs(c)) {
X    case CSdone:
X return Line;
X    case CSeof:
X return NULL;
X    case CSsignal:
X return (CHAR *)"";
X    case CSmove:
X reposition();
X break;
X    case CSdispatch:
X    case CSstay:
X break;
X    }
X    break;
X case CSstay:
X    break;
X }
X    return NULL;
X}
X
XSTATIC void
Xhist_add(p)
X    CHAR *p;
X{
X    int i;
X
X    if ((p = (CHAR *)strdup((char *)p)) == NULL)
X return;
X    if (H.Size < HIST_SIZE)
X H.Lines[H.Size++] = p;
X    else {
X DISPOSE(H.Lines[0]);
X for (i = 0; i < HIST_SIZE - 1; i++)
X    H.Lines[i] = H.Lines[i + 1];
X H.Lines[i] = p;
X    }
X    H.Pos = H.Size - 1;
X}
X
X/*
X**  For compatibility with FSF readline.
X*/
X/* ARGSUSED0 */
Xvoid
Xrl_reset_terminal(p)
X    char *p;
X{
X}
X
Xvoid
Xrl_initialize()
X{
X}
X
Xchar *
Xreadline(prompt)
X    CONST char *prompt;
X{
X    CHAR *line;
X    int s;
X
X    if (Line == NULL) {
X Length = MEM_INC;
X if ((Line = NEW(CHAR, Length)) == NULL)
X    return NULL;
X    }
X
X    TTYinfo();
X    rl_ttyset(0);
X    hist_add(NIL);
X    ScreenSize = SCREEN_INC;
X    Screen = NEW(char, ScreenSize);
X    Prompt = prompt ? prompt : (char *)NIL;
X    TTYputs((STRING)Prompt);
X    if ((line = editinput()) != NULL) {
X line = (CHAR *)strdup((char *)line);
X TTYputs((STRING)NEWLINE);
X TTYflush();
X    }
X    rl_ttyset(1);
X    DISPOSE(Screen);
X    DISPOSE(H.Lines[--H.Size]);
X    if (Signal > 0) {
X s = Signal;
X Signal = 0;
X (void)kill(getpid(), s);
X    }
X    return (char *)line;
X}
X
Xvoid
Xadd_history(p)
X    char *p;
X{
X    if (p == NULL || *p == '\0')
X return;
X
X#if defined(UNIQUE_HISTORY)
X    if (H.Size && strcmp(p, H.Lines[H.Size - 1]) == 0)
X        return;
X#endif /* defined(UNIQUE_HISTORY) */
X    hist_add((CHAR *)p);
X}
X
X
XSTATIC STATUS
Xbeg_line()
X{
X    if (Point) {
X Point = 0;
X return CSmove;
X    }
X    return CSstay;
X}
X
XSTATIC STATUS
Xdel_char()
X{
X    return delete_string(Repeat == NO_ARG ? 1 : Repeat);
X}
X
XSTATIC STATUS
Xend_line()
X{
X    if (Point != End) {
X Point = End;
X return CSmove;
X    }
X    return CSstay;
X}
X
X/*
X**  Move back to the beginning of the current word and return an
X**  allocated copy of it.
X*/
XSTATIC CHAR *
Xfind_word()
X{
X    static char SEPS[] = "#;&|^$=`'{}()<>\n\t ";
X    CHAR *p;
X    CHAR *new;
X    SIZE_T len;
X
X    for (p = &Line[Point]; p > Line && strchr(SEPS, (char)p[-1]) == NULL; p--)
X continue;
X    len = Point - (p - Line) + 1;
X    if ((new = NEW(CHAR, len)) == NULL)
X return NULL;
X    COPYFROMTO(new, p, len);
X    new[len - 1] = '\0';
X    return new;
X}
X
XSTATIC STATUS
Xc_complete()
X{
X    CHAR *p;
X    CHAR *word;
X    int unique;
X    STATUS s;
X
X    word = find_word();
X    p = (CHAR *)rl_complete((char *)word, &unique);
X    if (word)
X DISPOSE(word);
X    if (p && *p) {
X s = insert_string(p);
X if (!unique)
X    (void)ring_bell();
X DISPOSE(p);
X return s;
X    }
X    return ring_bell();
X}
X
XSTATIC STATUS
Xc_possible()
X{
X    CHAR **av;
X    CHAR *word;
X    int ac;
X
X    word = find_word();
X    ac = rl_list_possib((char *)word, (char ***)&av);
X    if (word)
X DISPOSE(word);
X    if (ac) {
X columns(ac, av);
X while (--ac >= 0)
X    DISPOSE(av[ac]);
X DISPOSE(av);
X return CSmove;
X    }
X    return ring_bell();
X}
X
XSTATIC STATUS
Xaccept_line()
X{
X    Line[End] = '\0';
X    return CSdone;
X}
X
XSTATIC STATUS
Xtranspose()
X{
X    CHAR c;
X
X    if (Point) {
X if (Point == End)
X    left(CSmove);
X c = Line[Point - 1];
X left(CSstay);
X Line[Point - 1] = Line[Point];
X TTYshow(Line[Point - 1]);
X Line[Point++] = c;
X TTYshow(c);
X    }
X    return CSstay;
X}
X
XSTATIC STATUS
Xquote()
X{
X    unsigned int c;
X
X    return (c = TTYget()) == EOF ? CSeof : insert_char((int)c);
X}
X
XSTATIC STATUS
Xwipe()
X{
X    int i;
X
X    if (Mark > End)
X return ring_bell();
X
X    if (Point > Mark) {
X i = Point;
X Point = Mark;
X Mark = i;
X reposition();
X    }
X
X    return delete_string(Mark - Point);
X}
X
XSTATIC STATUS
Xmk_set()
X{
X    Mark = Point;
X    return CSstay;
X}
X
XSTATIC STATUS
Xexchange()
X{
X    unsigned int c;
X
X    if ((c = TTYget()) != CTL('X'))
X return c == EOF ? CSeof : ring_bell();
X
X    if ((c = Mark) <= End) {
X Mark = Point;
X Point = c;
X return CSmove;
X    }
X    return CSstay;
X}
X
XSTATIC STATUS
Xyank()
X{
X    if (Yanked && *Yanked)
X return insert_string(Yanked);
X    return CSstay;
X}
X
XSTATIC STATUS
Xcopy_region()
X{
X    if (Mark > End)
X return ring_bell();
X
X    if (Point > Mark)
X save_yank(Mark, Point - Mark);
X    else
X save_yank(Point, Mark - Point);
X
X    return CSstay;
X}
X
XSTATIC STATUS
Xmove_to_char()
X{
X    unsigned int c;
X    int i;
X    CHAR *p;
X
X    if ((c = TTYget()) == EOF)
X return CSeof;
X    for (i = Point + 1, p = &Line[i]; i < End; i++, p++)
X if (*p == c) {
X    Point = i;
X    return CSmove;
X }
X    return CSstay;
X}
X
XSTATIC STATUS
Xfd_word()
X{
X    return do_forward(CSmove);
X}
X
XSTATIC STATUS
Xfd_kill_word()
X{
X    int i;
X
X    (void)do_forward(CSstay);
X    if (OldPoint != Point) {
X i = Point - OldPoint;
X Point = OldPoint;
X return delete_string(i);
X    }
X    return CSstay;
X}
X
XSTATIC STATUS
Xbk_word()
X{
X    int i;
X    CHAR *p;
X
X    i = 0;
X    do {
X for (p = &Line[Point]; p > Line && !isalnum(p[-1]); p--)
X    left(CSmove);
X
X for (; p > Line && p[-1] != ' ' && isalnum(p[-1]); p--)
X    left(CSmove);
X
X if (Point == 0)
X    break;
X    } while (++i < Repeat);
X
X    return CSstay;
X}
X
XSTATIC STATUS
Xbk_kill_word()
X{
X    (void)bk_word();
X    if (OldPoint != Point)
X return delete_string(OldPoint - Point);
X    return CSstay;
X}
X
XSTATIC int
Xargify(line, avp)
X    CHAR *line;
X    CHAR ***avp;
X{
X    CHAR *c;
X    CHAR **p;
X    CHAR **new;
X    int ac;
X    int i;
X
X    i = MEM_INC;
X    if ((*avp = p = NEW(CHAR*, i))== NULL)
X return 0;
X
X    for (c = line; isspace(*c); c++)
X continue;
X    if (*c == '\n' || *c == '\0')
X return 0;
X
X    for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) {
X if (isspace(*c)) {
X    *c++ = '\0';
X    if (*c && *c != '\n') {
X if (ac + 1 == i) {
X    new = NEW(CHAR*, i + MEM_INC);
X    if (new == NULL) {
X p[ac] = NULL;
X return ac;
X    }
X    COPYFROMTO(new, p, i * sizeof (char **));
X    i += MEM_INC;
X    DISPOSE(p);
X    *avp = p = new;
X }
X p[ac++] = c;
X    }
X }
X else
X    c++;
X    }
X    *c = '\0';
X    p[ac] = NULL;
X    return ac;
X}
X
XSTATIC STATUS
Xlast_argument()
X{
X    CHAR **av;
X    CHAR *p;
X    STATUS s;
X    int ac;
X
X    if (H.Size == 1 || (p = H.Lines[H.Size - 2]) == NULL)
X return ring_bell();
X
X    if ((p = (CHAR *)strdup((char *)p)) == NULL)
X return CSstay;
X    ac = argify(p, &av);
X
X    if (Repeat != NO_ARG)
X s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell();
X    else
X s = ac ? insert_string(av[ac - 1]) : CSstay;
X
X    if (ac)
X DISPOSE(av);
X    DISPOSE(p);
X    return s;
X}
X
XSTATIC KEYMAP Map[33] = {
X    { CTL('@'), ring_bell },
X    { CTL('A'), beg_line },
X    { CTL('B'), bk_char },
X    { CTL('D'), del_char },
X    { CTL('E'), end_line },
X    { CTL('F'), fd_char },
X    { CTL('G'), ring_bell },
X    { CTL('H'), bk_del_char },
X    { CTL('I'), c_complete },
X    { CTL('J'), accept_line },
X    { CTL('K'), kill_line },
X    { CTL('L'), redisplay },
X    { CTL('M'), accept_line },
X    { CTL('N'), h_next },
X    { CTL('O'), ring_bell },
X    { CTL('P'), h_prev },
X    { CTL('Q'), ring_bell },
X    { CTL('R'), h_search },
X    { CTL('S'), ring_bell },
X    { CTL('T'), transpose },
X    { CTL('U'), ring_bell },
X    { CTL('V'), quote },
X    { CTL('W'), wipe },
X    { CTL('X'), exchange },
X    { CTL('Y'), yank },
X    { CTL('Z'), ring_bell },
X    { CTL('['), meta },
X    { CTL(']'), move_to_char },
X    { CTL('^'), ring_bell },
X    { CTL('_'), ring_bell },
X    { 0, NULL }
X};
X
XSTATIC KEYMAP MetaMap[17]= {
X    { CTL('H'), bk_kill_word },
X    { DEL, bk_kill_word },
X    { ' ', mk_set },
X    { '.', last_argument },
X    { '<', h_first },
X    { '>', h_last },
X    { '?', c_possible },
X    { 'b', bk_word },
X    { 'd', fd_kill_word },
X    { 'f', fd_word },
X    { 'l', case_down_word },
X    { 'm', toggle_meta_mode},
X    { 'u', case_up_word },
X    { 'y', yank },
X    { 'w', copy_region },
X    { 0, NULL }
X};
END_OF_FILE
  if test 23405 -ne `wc -c <'editline.c'`; then
    echo shar: \"'editline.c'\" unpacked with wrong size!
  fi
  # end of 'editline.c'
fi
if test -f 'editline.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'editline.h'\"
else
  echo shar: Extracting \"'editline.h'\" \(1699 characters\)
  sed "s/^X//" >'editline.h' <<'END_OF_FILE'
X/*  $Revision: 1.4 $
X**
X**  Internal header file for editline library.
X*/
X#include <stdio.h>
X#if defined(HAVE_STDLIB)
X#include <stdlib.h>
X#include <string.h>
X#endif /* defined(HAVE_STDLIB) */
X#if defined(SYS_UNIX)
X#include "unix.h"
X#endif /* defined(SYS_UNIX) */
X#if defined(SYS_OS9)
X#include "os9.h"
X#endif /* defined(SYS_OS9) */
X
X#if !defined(SIZE_T)
X#define SIZE_T unsigned int
X#endif /* !defined(SIZE_T) */
X
Xtypedef unsigned char CHAR;
X
X#if defined(HIDE)
X#define STATIC static
X#else
X#define STATIC /* NULL */
X#endif /* !defined(HIDE) */
X
X#if !defined(CONST)
X#if defined(__STDC__)
X#define CONST const
X#else
X#define CONST
X#endif /* defined(__STDC__) */
X#endif /* !defined(CONST) */
X
X
X#define MEM_INC 64
X#define SCREEN_INC 256
X
X#define DISPOSE(p) free((char *)(p))
X#define NEW(T, c) \
X ((T *)malloc((unsigned int)(sizeof (T) * (c))))
X#define RENEW(p, T, c) \
X (p = (T *)realloc((char *)(p), (unsigned int)(sizeof (T) * (c))))
X#define COPYFROMTO(new, p, len) \
X (void)memcpy((char *)(new), (char *)(p), (int)(len))
X
X
X/*
X**  Variables and routines internal to this package.
X*/
Xextern int rl_eof;
Xextern int rl_erase;
Xextern int rl_intr;
Xextern int rl_kill;
Xextern int rl_quit;
X#if defined(DO_SIGTSTP)
Xextern int rl_susp;
X#endif /* defined(DO_SIGTSTP) */
Xextern char *rl_complete();
Xextern int rl_list_possib();
Xextern void rl_ttyset();
Xextern void rl_add_slash();
X
X#if !defined(HAVE_STDLIB)
Xextern char *getenv();
Xextern char *malloc();
Xextern char *realloc();
Xextern char *memcpy();
Xextern char *strcat();
Xextern char *strchr();
Xextern char *strrchr();
Xextern char *strcpy();
Xextern char *strdup();
Xextern int strcmp();
Xextern int strlen();
Xextern int strncmp();
X#endif /* !defined(HAVE_STDLIB) */
END_OF_FILE
  if test 1699 -ne `wc -c <'editline.h'`; then
    echo shar: \"'editline.h'\" unpacked with wrong size!
  fi
  # end of 'editline.h'
fi
if test -f 'os9.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'os9.h'\"
else
  echo shar: Extracting \"'os9.h'\" \(174 characters\)
  sed "s/^X//" >'os9.h' <<'END_OF_FILE'
X/*  $Revision: 1.1 $
X**
X**  Editline system header file for OS-9 (on 68k).
X*/
X
X#define CRLF "\r\l"
X#define FORWARD extern
X
X#include <dir.h>
Xtypedef struct direct DIRENTRY;
END_OF_FILE
  if test 174 -ne `wc -c <'os9.h'`; then
    echo shar: \"'os9.h'\" unpacked with wrong size!
  fi
  # end of 'os9.h'
fi
if test -f 'sysos9.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'sysos9.c'\"
else
  echo shar: Extracting \"'sysos9.c'\" \(1120 characters\)
  sed "s/^X//" >'sysos9.c' <<'END_OF_FILE'
X/*  $Revision: 1.1 $
X**
X**  OS-9 system-dependant routines for editline library.
X*/
X#include "editline.h"
X#include <sgstat.h>
X#include <modes.h>
X
X
Xvoid
Xrl_ttyset(Reset)
X    int Reset;
X{
X    static struct sgbuf old;
X    struct sgbuf new;
X
X
X    if (Reset == 0) {
X        _gs_opt(0, &old);
X        _gs_opt(0, &new);
X        new.sg_backsp = 0; new.sg_delete = 0; new.sg_echo = 0;
X        new.sg_alf = 0; new.sg_nulls = 0; new.sg_pause = 0;
X        new.sg_page = 0; new.sg_bspch = 0; new.sg_dlnch = 0;
X        new.sg_eorch = 0; new.sg_eofch = 0; new.sg_rlnch = 0;
X        new.sg_dulnch = 0; new.sg_psch = 0; new.sg_kbich = 0;
X        new.sg_kbach = 0; new.sg_bsech = 0; new.sg_bellch = 0;
X        new.sg_xon = 0; new.sg_xoff = 0; new.sg_tabcr = 0;
X        new.sg_tabsiz = 0;
X        _ss_opt(0, &new);
X        rl_erase = old.sg_bspch;
X        rl_kill = old.sg_dlnch;
X        rl_eof = old.sg_eofch;
X        rl_intr = old.sg_kbich;
X        rl_quit = -1;
X    }
X    else
X        _ss_opt(0, &old);
X}
X
Xvoid
Xrl_add_slash(path, p)
X    char *path;
X    char *p;
X{
X    (void)strcat(p, access(path, S_IREAD | S_IFDIR) ? " " : "/");
X}
END_OF_FILE
  if test 1120 -ne `wc -c <'sysos9.c'`; then
    echo shar: \"'sysos9.c'\" unpacked with wrong size!
  fi
  # end of 'sysos9.c'
fi
if test -f 'sysunix.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'sysunix.c'\"
else
  echo shar: Extracting \"'sysunix.c'\" \(2744 characters\)
  sed "s/^X//" >'sysunix.c' <<'END_OF_FILE'
X/*  $Revision: 1.5 $
X**
X**  Unix system-dependant routines for editline library.
X*/
X#include "editline.h"
X
X#if defined(HAVE_TCGETATTR)
X#include <termios.h>
X
Xvoid
Xrl_ttyset(Reset)
X    int Reset;
X{
X    static struct termios old;
X    struct termios new;
X
X    if (Reset == 0) {
X (void)tcgetattr(0, &old);
X rl_erase = old.c_cc[VERASE];
X rl_kill = old.c_cc[VKILL];
X rl_eof = old.c_cc[VEOF];
X rl_intr = old.c_cc[VINTR];
X rl_quit = old.c_cc[VQUIT];
X#if defined(DO_SIGTSTP)
X rl_susp = old.c_cc[VSUSP];
X#endif /* defined(DO_SIGTSTP) */
X
X new = old;
X new.c_lflag &= ~(ECHO | ICANON | ISIG);
X new.c_iflag &= ~(ISTRIP | INPCK);
X new.c_cc[VMIN] = 1;
X new.c_cc[VTIME] = 0;
X (void)tcsetattr(0, TCSADRAIN, &new);
X    }
X    else
X (void)tcsetattr(0, TCSADRAIN, &old);
X}
X
X#else
X#if defined(HAVE_TERMIO)
X#include <termio.h>
X
Xvoid
Xrl_ttyset(Reset)
X    int Reset;
X{
X    static struct termio old;
X    struct termio new;
X
X    if (Reset == 0) {
X (void)ioctl(0, TCGETA, &old);
X rl_erase = old.c_cc[VERASE];
X rl_kill = old.c_cc[VKILL];
X rl_eof = old.c_cc[VEOF];
X rl_intr = old.c_cc[VINTR];
X rl_quit = old.c_cc[VQUIT];
X#if defined(DO_SIGTSTP)
X rl_susp = old.c_cc[VSUSP];
X#endif /* defined(DO_SIGTSTP) */
X
X new = old;
X new.c_lflag &= ~(ECHO | ICANON | ISIG);
X new.c_iflag &= ~(ISTRIP | INPCK);
X new.c_cc[VMIN] = 1;
X new.c_cc[VTIME] = 0;
X (void)ioctl(0, TCSETAW, &new);
X    }
X    else
X (void)ioctl(0, TCSETAW, &old);
X}
X
X#else
X#include <sgtty.h>
X
Xvoid
Xrl_ttyset(Reset)
X    int Reset;
X{
X    static struct sgttyb old_sgttyb;
X    static struct tchars old_tchars;
X    struct sgttyb new_sgttyb;
X    struct tchars new_tchars;
X#if defined(DO_SIGTSTP)
X    struct ltchars old_ltchars;
X#endif /* defined(DO_SIGTSTP) */
X
X    if (Reset == 0) {
X (void)ioctl(0, TIOCGETP, &old_sgttyb);
X rl_erase = old_sgttyb.sg_erase;
X rl_kill = old_sgttyb.sg_kill;
X
X (void)ioctl(0, TIOCGETC, &old_tchars);
X rl_eof = old_tchars.t_eofc;
X rl_intr = old_tchars.t_intrc;
X rl_quit = old_tchars.t_quitc;
X
X#if defined(DO_SIGTSTP)
X (void)ioctl(0, TIOCGLTC, &old_ltchars);
X rl_susp = old_ltchars.t_suspc;
X#endif /* defined(DO_SIGTSTP) */
X
X new_sgttyb = old_sgttyb;
X new_sgttyb.sg_flags &= ~ECHO;
X new_sgttyb.sg_flags |= RAW;
X#if defined(PASS8)
X new_sgttyb.sg_flags |= PASS8;
X#endif /* defined(PASS8) */
X (void)ioctl(0, TIOCSETP, &new_sgttyb);
X
X new_tchars = old_tchars;
X new_tchars.t_intrc = -1;
X new_tchars.t_quitc = -1;
X (void)ioctl(0, TIOCSETC, &new_tchars);
X    }
X    else {
X (void)ioctl(0, TIOCSETP, &old_sgttyb);
X (void)ioctl(0, TIOCSETC, &old_tchars);
X    }
X}
X#endif /* defined(HAVE_TERMIO) */
X#endif /* defined(HAVE_TCGETATTR) */
X
Xvoid
Xrl_add_slash(path, p)
X    char *path;
X    char *p;
X{
X    struct stat Sb;
X
X    if (stat(path, &Sb) >= 0)
X (void)strcat(p, S_ISDIR(Sb.st_mode) ? "/" : " ");
X}
END_OF_FILE
  if test 2744 -ne `wc -c <'sysunix.c'`; then
    echo shar: \"'sysunix.c'\" unpacked with wrong size!
  fi
  # end of 'sysunix.c'
fi
if test -f 'testit.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'testit.c'\"
else
  echo shar: Extracting \"'testit.c'\" \(1134 characters\)
  sed "s/^X//" >'testit.c' <<'END_OF_FILE'
X/*  $Revision: 1.4 $
X**
X**  A "micro-shell" to test editline library.
X**  If given any arguments, commands aren't executed.
X*/
X#include <stdio.h>
X#if defined(HAVE_STDLIB)
X#include <stdlib.h>
X#endif /* defined(HAVE_STDLIB) */
X
Xextern char *readline();
Xextern void add_history();
X
X#if !defined(HAVE_STDLIB)
Xextern int chdir();
Xextern int free();
Xextern int strncmp();
Xextern int system();
Xextern void exit();
Xextern char *getenv();
X#endif /* !defined(HAVE_STDLIB) */
X
X
X#if defined(NEED_PERROR)
Xvoid
Xperror(s)
X    char *s;
X{
X    extern int errno;
X
X    (voidf)printf(stderr, "%s: error %d\n", s, errno);
X}
X#endif /* defined(NEED_PERROR) */
X
X
X/* ARGSUSED1 */
Xint
Xmain(ac, av)
X    int ac;
X    char *av[];
X{
X    char *prompt;
X    char *p;
X    int doit;
X
X    doit = ac == 1;
X    if ((prompt = getenv("TESTPROMPT")) == NULL)
X prompt = "testit>  ";
X
X    while ((p = readline(prompt)) != NULL) {
X (void)printf("\t\t\t|%s|\n", p);
X if (doit)
X    if (strncmp(p, "cd ", 3) == 0) {
X if (chdir(&p[3]) < 0)
X    perror(&p[3]);
X    }
X    else if (system(p) != 0)
X perror(p);
X add_history(p);
X free(p);
X    }
X    exit(0);
X    /* NOTREACHED */
X}
END_OF_FILE
  if test 1134 -ne `wc -c <'testit.c'`; then
    echo shar: \"'testit.c'\" unpacked with wrong size!
  fi
  # end of 'testit.c'
fi
if test -f 'unix.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'unix.h'\"
else
  echo shar: Extracting \"'unix.h'\" \(432 characters\)
  sed "s/^X//" >'unix.h' <<'END_OF_FILE'
X/*  $Revision: 1.1 $
X**
X**  Editline system header file for Unix.
X*/
X
X#define CRLF "\r\n"
X#define FORWARD STATIC
X
X#include <sys/types.h>
X#include <sys/stat.h>
X
X#if defined(USE_DIRENT)
X#include <dirent.h>
Xtypedef struct dirent DIRENTRY;
X#else
X#include <sys/dir.h>
Xtypedef struct direct DIRENTRY;
X#endif /* defined(USE_DIRENT) */
X
X#if !defined(S_ISDIR)
X#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
X#endif /* !defined(S_ISDIR) */
END_OF_FILE
  if test 432 -ne `wc -c <'unix.h'`; then
    echo shar: \"'unix.h'\" unpacked with wrong size!
  fi
  # end of 'unix.h'
fi
echo shar: End of archive 1 \(of 1\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 ; do
    if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have the archive.
    rm -f ark[1-9]isdone
else
    echo You still must unpack the following archives:
    echo "        " ${MISSING}
fi
exit 0
bash-4.2#

bash-4.2# unshar editline.shar
/root/editline.shar:
If this archive is complete, you will see the following message:
          "shar: End of archive."
shar: Extracting "README" (2351 characters)
shar: Extracting "Makefile" (1954 characters)
shar: Extracting "editline.3" (5349 characters)
shar: Extracting "editline.h" (1622 characters)
shar: Extracting "unix.h" (432 characters)
shar: Extracting "editline.c" (23149 characters)
shar: Extracting "complete.c" (4113 characters)
shar: Extracting "sysunix.c" (2431 characters)
shar: Extracting "testit.c" (1134 characters)
shar: Extracting "Make.os9" (348 characters)
shar: Extracting "os9.h" (174 characters)
shar: Extracting "sysos9.c" (1120 characters)
shar: End of archive.
bash-4.2#