PD KSH 3.2 alpha - update-1/2
Simon J. Gerraty
sjg at zen.void.oz.au
Thu Apr 25 18:21:33 AEST 1991
As promissed here are my updates to the PD KSH, to compile
it on a Sun, fix a few bugs and add a few features. The README
file is just below...
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of shell archive."
# Contents: README src/edit.c
# Wrapped by sjg at zen on Thu Apr 25 18:06:08 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f README -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"README\"
else
echo shar: Extracting \"README\" \(1824 characters\)
sed "s/^X//" >README <<'END_OF_README'
XPD KSH 3.2 alpha Update README
X
XThis is the README file for my patches to the PD KSH (posted to
Xalt.sources in Dec 90). The update consists of two shell
Xarchives.
X
XArchive 1 contents:
XREADME # this file
Xsrc/edit.c # new edit.c
X
XArchive 2 contents:
Xsrc/ChangeLog # change log :-)
Xstdc/ChangeLog # ditto
Xsun386i.diffs # sun 386i related diffs
Xbugs.diffs # bug fixes and new features
X
XThe new edit.c adds several features to the PD KSH.
XThe ability to edit lines longer than the screen width.
XThis is done in a manner comaptible with the real ksh.
X
XNew features:
XM-[0-9] Esc followed by a digit 0-9 sets an argument
X that applies to the following command.
XM-.
XM-_ Retrieves the last (or n'th if preceded by arg)
X word from previous command line.
XM-u Upcase-word
XM-l Downcase-word
XM-c Capitalize-word
X
XAll word related functions now pay attention to the arg set by
XM-[0-9].
XThe editor's behaviour now agrees with the description in the
Xreal man page. That is; the editor treats only a sequence of
Xdigits and alpha chars as a word. Thus '/','.' etc are all word
Xseparators as one might expect. Under certain circumstances
Xsuch as file name completion and retrieving words from previous
Xcommands the original word separators ' ' and '\t' are used.
X
XI use this shell all day on my workstation at work where I also
Xuse the real ksh on another system. With the new edit.c it is
Xvery difficult to pick the difference between the real and PD
Xkorn-shell.
X
XThe important features still missing are support for:
X
X$HISTFILE
X$HISTSIZE
X$MAILPATH
X$CDPATH
X[[]]
X
XPlus there are still bugs in some of the variable expansion code
X${var%%*.c} doesn't work for instance.
XHopefully one day some one will address these.
XIf you do, please send a copy to:
X
XSimon J. Gerraty <sjg at zen.void.oz.au>
X or <sjg at melb.bull.oz.au>
X
X
X
END_OF_README
if test 1824 -ne `wc -c <README`; then
echo shar: \"README\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/edit.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"src/edit.c\"
else
echo shar: Extracting \"src/edit.c\" \(36696 characters\)
sed "s/^X//" >src/edit.c <<'END_OF_src/edit.c'
X/*
X * EDIT.C -- Emacs-like command line editing and history
X *
X * created by Ron Natalie at BRL
X * modified by Doug Kingston, Doug Gwyn, and Lou Salkind
X * adapted to PD ksh by Eric Gisin
X * Modified Feb 1991 by Simon Gerraty, to handle editing lines
X * longer than $COLUMNS, in a manner similar to the real KSH.
X *
X */
X
X#if EDIT
X#ifndef lint
Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/edit.c,v 3.2 88/12/14 20:11:44 egisin Exp $";
Xstatic char *sccsid = "@(#)edit.c 1.10 91/04/25 15:39:13 (sjg)";
X#endif
X
X#include <stddef.h>
X#include <stdlib.h>
X#include <string.h>
X#include <stdio.h>
X#include <unistd.h>
X#include <signal.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <dirent.h>
X#include <fcntl.h>
X#include <ctype.h>
X#include <errno.h>
X#include <setjmp.h>
X#include "sh.h"
X#include "lex.h"
X#include "tree.h" /* DOTILDE */
X#include "tty.h"
X#include "table.h"
X#include "expand.h"
X
X#define PUSH_DELETE 1 /* push all deletes of >1 char */
X
XArea aedit;
X#define AEDIT &aedit /* area for kill ring and macro defns */
X
X#undef CTRL /* _BSD brain damage */
X#define CTRL(x) ((x) == '?' ? 0x7F : (x) & 0x1F) /* ASCII */
X#define UNCTRL(x) ((x) == 0x7F ? '?' : (x) | 0x40) /* ASCII */
X
X#if ! defined S_ISDIR
X#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
X#endif
X
X#if ! defined S_ISREG
X#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
X#endif
X
X#if defined _CRAY2
Xextern unsigned sleep();
X#endif
X
X/* values returned by keyboard functions */
X#define KSTD 0
X#define KPREF 1 /* ^[, ^X */
X#define KEOL 2 /* ^M, ^J */
X#define KINTR 3 /* ^G, ^C */
X
Xstruct x_ftab {
X int (*xf_func)();
X char *xf_name;
X char xf_db_tab;
X char xf_db_char;
X short xf_flags;
X};
X
X#define XF_NINPUT 1
X#define XF_ALLOC 2
X#define XF_NOBIND 4
X
X
X/*
X * "the editor's idea of a word is a string containing only
X * letters digits and underscores"
X */
X#define isfs(c) ((int) strchr(" \t!@#$%^&*()-=+|{}[]:;\"'~`<,>.?/", c))
X/*
X * this is the original fs test,
X * it is still useful in come cases.
X */
X#define ISFS(c) (c == ' ' || c == '\t')
X
X#define BEL 0x07
X#define CMASK 0x7F /* 7-bit ASCII character mask */
X
Xtypedef int bool_t;
X#define FALSE 0
X#define TRUE 1
X
Xstatic bool_t x_mode = FALSE;
Xstatic int x_prefix1 = CTRL('['), x_prefix2 = CTRL('X');
Xstatic char **x_histp; /* history position */
Xstatic char *xbuf; /* beg input buffer */
Xstatic char *xend; /* end input buffer */
Xstatic char *xcp;
Xstatic char *xep;
Xstatic char *xbp; /* start of visible portion of input buffer */
Xstatic int x_adj_ok = 1;
X/*
X * we use x_adj_done so that functions can tell
X * whether x_adjust() has been called while they are active.
X */
Xstatic int x_adj_done = 0;
X
Xstatic int (*x_last_command)();
X/*static struct x_ftab *x_tab[3][128];*/
Xstatic struct x_ftab Const *(*x_tab)[128] = NULL; /* key definition */
Xstatic char *(*x_atab)[128] = NULL; /* macro definitions */
X#define KILLSIZE 20
Xstatic char *killstack[KILLSIZE];
Xstatic int killsp, killtp;
Xstatic int x_curprefix;
Xstatic char *macroptr;
Xstatic int first_time = 1;
Xstatic int x_maxlen; /* to determine column width */
Xstatic int x_cols = 80; /* todo: $COLUMNS */
Xstatic int x_col = 0;
Xstatic int x_displen;
Xstatic int x_arg; /* general purpose arg */
X
Xstatic void x_flush(), x_putc(), x_puts();
Xstatic void x_goto(), x_bs(), x_delete(), x_ins(), x_mapin();
Xstatic int x_fword(), x_bword(), x_size(), x_size_str();
Xstatic void x_zotc(), x_zots(), x_push(), x_redraw(), x_load_hist();
Xstatic void compl_command(), compl_dec(), compl_file();
Xstatic int x_insert(), x_ins_string(), x_del_back();
Xstatic int x_del_char(), x_del_bword(), x_mv_bword(), x_mv_fword();
Xstatic int x_del_fword(), x_mv_back(), x_mv_forw(), x_search_char();
Xstatic int x_newline(), x_end_of_text(), x_abort(), x_error();
Xstatic int x_beg_hist(), x_end_hist(), x_prev_com(), x_next_com();
Xstatic int x_search_hist(), x_del_line(), x_mv_end(), x_mv_begin();
Xstatic int x_draw_line(), x_transpose(), x_meta1(), x_meta2();
Xstatic int x_kill(), x_yank(), x_meta_yank(), x_literal();
Xstatic int x_stuffreset(), x_stuff(), x_complete(), x_enumerate();
X#if SILLY
Xstatic int x_game_of_life();
X#endif
Xstatic int x_comp_file(), x_comp_comm();
Xstatic int x_list_file(), x_list_comm();
Xstatic int strmatch();
X#ifdef DEBUG
Xstatic int x_debug_info();
X#endif
Xstatic int x_prev_histword();
Xstatic int x_set_arg();
Xstatic int x_fold_case();
X
Xstatic struct x_ftab Const x_ftab[] = {
X {x_insert, "auto-insert", 0, 0, 0 },
X {x_error, "error", 0, 0, 0 },
X {x_ins_string, "macro-string", 0, 0, XF_NOBIND|XF_ALLOC},
X/* Do not move the above! */
X {x_del_back, "delete-char-backward", 0, CTRL('H'), 0 },
X {x_del_char, "delete-char-forward", 0, CTRL('D'), 0 },
X {x_del_bword, "delete-word-backward", 0, CTRL('W'), 0 },
X {x_mv_bword, "backward-word", 1, 'b', 0 },
X {x_mv_fword, "forward-word", 1, 'f', 0 },
X {x_del_fword, "delete-word-forward", 1, 'd', 0 },
X {x_mv_back, "backward-char", 0, CTRL('B'), 0 },
X {x_mv_forw, "forward-char", 0, CTRL('F'), 0 },
X {x_search_char, "search-character", 0, CTRL(']'), 0 },
X {x_newline, "newline", 0, CTRL('M'), 0 },
X {x_newline, "newline", 0, CTRL('J'), 0 },
X {x_end_of_text, "eot", 0, CTRL('_'), 0 },
X {x_abort, "abort", 0, CTRL('G'), 0 },
X {x_prev_com, "up-history", 0, CTRL('P'), XF_NINPUT},
X {x_next_com, "down-history", 0, CTRL('N'), XF_NINPUT},
X {x_search_hist, "search-history", 0, CTRL('R'), XF_NINPUT},
X {x_beg_hist, "beginning-of-history", 1, '<', XF_NINPUT},
X {x_end_hist, "end-of-history", 1, '>', XF_NINPUT},
X {x_del_line, "kill-line", 0, CTRL('U'), 0 },
X {x_mv_end, "end-of-line", 0, CTRL('E'), 0 },
X {x_mv_begin, "beginning-of-line", 0, CTRL('A'), 0 },
X {x_draw_line, "redraw", 0, CTRL('L'), 0 },
X {x_meta1, "prefix-1", 0, CTRL('['), 0 },
X {x_meta2, "prefix-2", 0, CTRL('X'), 0 },
X {x_kill, "kill-to-eol", 0, CTRL('K'), 0 },
X {x_yank, "yank", 0, CTRL('Y'), 0 },
X {x_meta_yank, "yank-pop", 1, 'y', 0 },
X {x_literal, "quote", 0, CTRL('^'), 0 },
X {x_stuffreset, "stuff-reset", 0, 0, 0 },
X#if BRL && defined(TIOCSTI)
X {x_stuff, "stuff", 0, CTRL('T'), 0 },
X {x_transpose, "transpose-chars", 0, 0, 0 },
X#else
X {x_stuff, "stuff", 0, 0, 0 },
X {x_transpose, "transpose-chars", 0, CTRL('T'), 0 },
X#endif
X {x_complete, "complete", 1, CTRL('['), 0 },
X {x_enumerate, "list", 1, '?', 0 },
X {x_comp_file, "complete-file", 2, CTRL('X'), 0 },
X {x_comp_comm, "complete-command", 2, CTRL('['), 0 },
X {x_list_file, "list-file", 0, 0, 0 },
X {x_list_comm, "list-command", 2, '?', 0 },
X#if SILLY
X {x_game_of_life, "play-game-of-life", 0, 0, 0 },
X#endif
X#ifdef DEBUG
X {x_debug_info, "debug-info", 1, CTRL('H'), 0 },
X#endif
X {x_prev_histword, "prev-hist-word", 1, '.', 0 },
X {x_prev_histword, "prev-hist-word", 1, '_', 0 },
X {x_set_arg, "", 1, '0', 0 },
X {x_set_arg, "", 1, '1', 0 },
X {x_set_arg, "", 1, '2', 0 },
X {x_set_arg, "", 1, '3', 0 },
X {x_set_arg, "", 1, '4', 0 },
X {x_set_arg, "", 1, '5', 0 },
X {x_set_arg, "", 1, '6', 0 },
X {x_set_arg, "", 1, '7', 0 },
X {x_set_arg, "", 1, '8', 0 },
X {x_set_arg, "", 1, '9', 0 },
X {x_fold_case, "upcase-word", 1, 'U', 0 },
X {x_fold_case, "downcase-word", 1, 'L', 0 },
X {x_fold_case, "capitalize-word", 1, 'C', 0 },
X {x_fold_case, "upcase-word", 1, 'u', 0 },
X {x_fold_case, "downcase-word", 1, 'l', 0 },
X {x_fold_case, "capitalize-word", 1, 'c', 0 },
X
X { 0 }
X};
X
X#define xft_insert &x_ftab[0]
X#define xft_error &x_ftab[1]
X#define xft_ins_string &x_ftab[2]
X
Xint
Xx_read(fd, buf, len)
X int fd; /* not used */
X char *buf;
X size_t len;
X{
X char c;
X int i;
X int (*func)();
X extern x_insert();
X
X (void)set_xmode(TRUE);
X xbuf = buf; xend = buf + len;
X xbp = xcp = xep = buf;
X *xcp = 0;
X x_curprefix = 0;
X macroptr = null;
X x_histp = histptr + 1;
X
X /* <sjg at sun0> this may not be correct */
X if ((i = atoi(strval(global("COLUMNS")))) > 0)
X x_cols = i;
X x_col = strlen(prompt);
X x_adj_ok = 1;
X x_displen = x_cols - 2 - x_col;
X x_adj_done = 0;
X
X while (1) {
X x_flush();
X if (*macroptr) {
X c = *macroptr++;
X if (*macroptr == 0)
X macroptr = null;
X }
X else {
X i = read(ttyfd, &c, 1);
X if (i != 1)
X goto Exit;
X }
X
X if (x_curprefix == -1)
X func = x_insert;
X else
X func = x_tab[x_curprefix][c&CMASK]->xf_func;
X if (func == NULL)
X func = x_error;
X i = c | (x_curprefix << 8);
X x_curprefix = 0;
X switch (i = (*func)(i)) {
X case KSTD:
X x_last_command = func;
X case KPREF:
X break;
X case KEOL:
X i = xep - xbuf;
X x_last_command = 0;
X /* XXX -- doesn't get them all */
X if (strncmp(xbuf, "stty", 4) == 0)
X first_time = 1;
X goto Exit;
X case KINTR: /* special case for interrupt */
X i = -1;
X errno = EINTR;
X goto Exit;
X }
X }
X Exit:
X (void)set_xmode(FALSE);
X if (i < 0 && errno == EINTR)
X trapsig(SIGINT);
X return i;
X}
X
Xstatic int
Xx_insert(c)
X int c;
X{
X char str[2];
X
X /*
X * Should allow tab and control chars.
X */
X if (c == 0) {
X x_putc(BEL);
X return KSTD;
X }
X str[0] = c;
X str[1] = 0;
X x_ins(str);
X return KSTD;
X}
X
Xstatic int
Xx_ins_string(c)
X int c;
X{
X if (*macroptr) {
X x_putc(BEL);
X return KSTD;
X }
X macroptr = x_atab[c>>8][c & CMASK];
X return KSTD;
X}
X
Xstatic void
Xx_ins(cp)
X char *cp;
X{
X int count, i;
X register int adj = x_adj_done;
X
X x_adj_ok = (xcp == xep);
X count = strlen(cp);
X if (xep+count >= xend) {
X x_putc(BEL);
X return;
X }
X
X if (xcp != xep)
X memmove(xcp+count, xcp, xep - xcp + 1);
X else
X xcp[count] = 0;
X memmove(xcp, cp, count);
X#if 1
X /*
X * x_zots() may result in a call to x_adjust()
X * we want xcp to reflect the new position.
X */
X cp = xcp;
X xcp += count;
X xep += count;
X x_zots(cp);
X#else
X x_zots(xcp);
X xcp += count;
X xep += count;
X#endif
X if (adj == x_adj_done) /* has x_adjust() been called? */
X {
X if ((cp = xbp + x_displen) > xep)
X cp = xep;
X i = cp - xcp;
X while (i-- > 0)
X x_bs(*--cp);
X }
X x_adj_ok = 1;
X return;
X}
X
Xstatic int
Xx_del_back(c)
X int c;
X{
X if (xcp == xbuf) {
X x_putc(BEL);
X return KSTD;
X }
X x_goto(xcp - 1);
X x_delete(1);
X return KSTD;
X}
X
Xstatic int
Xx_del_char(c)
X int c;
X{
X if (xcp == xep) {
X x_putc(BEL);
X return KSTD;
X }
X x_delete(1);
X return KSTD;
X}
X
Xstatic void
Xx_delete(nc)
X int nc;
X{
X int i,j;
X char *cp;
X
X if (nc == 0)
X return;
X#ifdef PUSH_DELETE
X /*
X * This lets us yank a word we have deleted.
X */
X if (nc > 1)
X x_push(nc);
X#endif
X xep -= nc;
X cp = xcp;
X j = 0;
X i = nc;
X while (i--) {
X j += x_size(*cp++);
X }
X memmove(xcp, xcp+nc, xep - xcp + 1); /* Copies the null */
X x_adj_ok = 0; /* don't redraw */
X x_zots(xcp);
X /*
X * if we are already filling the line,
X * there is no need to ' ','\b'.
X * But if we must, make sure we do the minimum.
X */
X if ((i = x_cols - 2 - x_col) > 0)
X {
X j = (j < i) ? j : i;
X i = j;
X while (i--)
X x_putc(' ');
X i = j;
X while (i--)
X x_putc('\b');
X }
X /*x_goto(xcp);*/
X x_adj_ok = 1;
X if ((cp = xbp + x_displen) > xep)
X cp = xep;
X i = cp - xcp;
X while (i-- > 0)
X x_bs(*--cp);
X return;
X}
X
Xstatic int
Xx_del_bword(c)
X int c;
X{
X x_delete(x_bword());
X return KSTD;
X}
X
Xstatic int
Xx_mv_bword(c)
X int c;
X{
X (void)x_bword();
X return KSTD;
X}
X
Xstatic int
Xx_mv_fword(c)
X int c;
X{
X x_goto(xcp + x_fword());
X return KSTD;
X}
X
Xstatic int
Xx_del_fword(c)
X int c;
X{
X x_delete(x_fword());
X return KSTD;
X}
X
Xstatic int
Xx_bword() {
X int nc = 0;
X register char *cp = xcp;
X
X if (cp == xbuf) {
X x_putc(BEL);
X return 0;
X }
X if (x_last_command != x_set_arg)
X x_arg = 1;
X while (x_arg--)
X {
X while (cp != xbuf && isfs(cp[-1]))
X {
X cp--;
X nc++;
X }
X while (cp != xbuf && !isfs(cp[-1]))
X {
X cp--;
X nc++;
X }
X }
X x_goto(cp);
X return nc;
X}
X
Xstatic int
Xx_fword() {
X int nc = 0;
X register char *cp = xcp;
X
X if (cp == xep) {
X x_putc(BEL);
X return 0;
X }
X if (x_last_command != x_set_arg)
X x_arg = 1;
X while (x_arg--)
X {
X while (cp != xep && !isfs(*cp))
X {
X cp++;
X nc++;
X }
X while (cp != xep && isfs(*cp))
X {
X cp++;
X nc++;
X }
X }
X return nc;
X}
X
Xstatic void
Xx_goto(cp)
X register char *cp;
X{
X if (cp < xbp || cp >= (xbp + x_displen)) /* off screen */
X {
X xcp = cp;
X x_adjust();
X }
X else
X {
X if (cp < xcp) /* move back */
X {
X while (cp < xcp)
X x_bs(*--xcp);
X }
X else
X {
X if (cp > xcp) /* move forward */
X {
X while (cp > xcp)
X x_zotc(*xcp++);
X }
X }
X }
X}
X
Xstatic void
Xx_bs(c)
X int c;
X{
X register i;
X i = x_size(c);
X while (i--)
X x_putc('\b');
X}
X
Xstatic int
Xx_size_str(cp)
X register char *cp;
X{
X register size = 0;
X while (*cp)
X size += x_size(*cp++);
X return size;
X}
X
Xstatic int
Xx_size(c)
X int c;
X{
X if (c=='\t')
X return 4; /* Kludge, tabs are always four spaces. */
X if (c < ' ' || c == 0x7F) /* ASCII control char */
X return 2;
X return 1;
X}
X
Xstatic void
Xx_zots(str)
X register char *str;
X{
X register int adj = x_adj_done;
X
X while (*str && x_col < (x_cols - 2) && adj == x_adj_done)
X x_zotc(*str++);
X}
X
Xstatic void
Xx_zotc(c)
X int c;
X{
X if (c == '\t') {
X /* Kludge, tabs are always four spaces. */
X x_puts(" ");
X } else if (c < ' ' || c == 0x7F) { /* ASCII */
X x_putc('^');
X x_putc(UNCTRL(c));
X } else
X x_putc(c);
X}
X
X/* tty output */
X
Xstatic void
Xx_flush()
X{
X fflush(stdout);
X}
X
X/* NAME:
X * x_adjust - redraw the line adjusting starting point etc.
X *
X * DESCRIPTION:
X * This function is called when we have exceeded the bounds
X * of the edit window. It increments x_adj_done so that
X * functions like x_ins and x_delete know that we have been
X * called and can skip the x_bs() stuff which has already
X * been done by x_redraw.
X *
X * RETURN VALUE:
X * None
X */
X
Xx_adjust()
X{
X x_adj_done++; /* flag the fact that we were called. */
X /*
X * we had a promblem if the prompt length > x_cols / 2
X */
X if ((xbp = xcp - (x_displen / 2)) < xbuf)
X xbp = xbuf;
X
X x_redraw(x_cols);
X x_flush();
X}
X
Xstatic void
Xx_putc(c)
X int c;
X{
X if (c == '\r' || c == '\n')
X x_col = 0;
X if (x_col < x_cols)
X {
X putc(c, stdout);
X switch(c)
X {
X case BEL:
X break;
X case '\r':
X case '\n':
X break;
X case '\b':
X x_col--;
X break;
X default:
X x_col++;
X break;
X }
X }
X if (x_adj_ok && (x_col < 0 || x_col >= (x_cols - 2)))
X {
X x_adjust();
X }
X}
X
X#ifdef DEBUG
Xstatic int
Xx_debug_info()
X{
X x_flush();
X printf("\nksh debug:\n");
X printf("\tx_col == %d,\t\tx_cols == %d,\tx_displen == %d\n",
X x_col, x_cols, x_displen);
X printf("\txcp == 0x%lx,\txep == 0x%lx\n", (long) xcp, (long) xep);
X printf("\txbp == 0x%lx,\txbuf == 0x%lx\n", (long) xbp, (long) xbuf);
X printf("\n");
X x_redraw(-1);
X return KSTD;
X}
X#endif
X
Xstatic void
Xx_puts(s)
X register char *s;
X{
X register int adj = x_adj_done;
X
X while (*s && adj == x_adj_done)
X x_putc(*s++);
X}
X
Xstatic int
Xx_mv_back(c)
X int c;
X{
X if (xcp == xbuf) {
X x_putc(BEL);
X return KSTD;
X }
X x_goto(xcp-1);
X return KSTD;
X}
X
Xstatic int
Xx_mv_forw(c)
X int c;
X{
X if (xcp == xep) {
X x_putc(BEL);
X return KSTD;
X }
X x_goto(xcp+1);
X return KSTD;
X}
X
Xstatic int
Xx_search_char(c)
X int c;
X{
X char ci, *cp;
X
X *xep = '\0';
X if (read(ttyfd, &ci, 1) != 1 ||
X /* we search forward, I don't know what Korn does */
X (cp = (xcp == xep) ? NULL : strchr(xcp+1, ci)) == NULL &&
X (cp = strchr(xbuf, ci)) == NULL) {
X x_putc(BEL);
X return KSTD;
X }
X x_goto(cp);
X return KSTD;
X}
X
Xstatic int
Xx_newline(c)
X int c;
X{
X x_putc('\n');
X x_flush();
X *xep++ = '\n';
X return KEOL;
X}
X
Xstatic int
Xx_end_of_text(c)
X int c;
X{
X#if 0
X x_store_hist();
X#endif
X return KEOL;
X}
X
Xstatic int x_beg_hist(c) int c; {x_load_hist(history); return KSTD;}
X
Xstatic int x_end_hist(c) int c; {x_load_hist(histptr); return KSTD;}
X
Xstatic int x_prev_com(c) int c; {x_load_hist(x_histp-1); return KSTD;}
X
Xstatic int x_next_com(c) int c; {x_load_hist(x_histp+1); return KSTD;}
X
Xstatic void
Xx_load_hist(hp)
X register char **hp;
X{
X int oldsize;
X
X if (hp < history || hp > histptr) {
X x_putc(BEL);
X return;
X }
X x_histp = hp;
X oldsize = x_size_str(xbuf);
X (void)strcpy(xbuf, *hp);
X xbp = xbuf;
X xep = xcp = xbuf + strlen(*hp);
X if (xep - xbuf >= x_displen)
X x_goto(xep);
X else
X x_redraw(oldsize);
X}
X
Xstatic int x_search(), x_match();
X
X/* reverse incremental history search */
Xstatic int
Xx_search_hist(ci)
X int ci;
X{
X int offset = -1; /* offset of match in xbuf, else -1 */
X static char c[2]; /* input buffer */
X char pat [256+1]; /* pattern buffer */
X register char *p = pat;
X int (*func)();
X
X *p = 0;
X while (1) {
X if (offset < 0) {
X x_puts("\nI-search: ");
X x_zots(pat);
X }
X x_flush();
X if (read(ttyfd, c, 1) < 1)
X return KSTD;
X func = x_tab[0][*c&CMASK]->xf_func;
X if (*c == CTRL('['))
X break;
X else if (func == x_search_hist)
X offset = x_search(pat, offset);
X else if (func == x_del_back)
X continue; /* todo */
X else if (func == x_insert) {
X /* add char to pattern */
X *p++ = *c, *p = 0;
X if (offset >= 0) {
X /* already have partial match */
X offset = x_match(xbuf, pat);
X if (offset >= 0) {
X x_goto(xbuf + offset + (p - pat) - (*pat == '^'));
X continue;
X }
X }
X offset = x_search(pat, offset);
X } else { /* other command */
X macroptr = c; /* push command */
X break;
X }
X }
X if (offset < 0)
X x_redraw(-1);
X return KSTD;
X}
X
X/* search backward from current line */
Xstatic int
Xx_search(pat, offset)
X char *pat;
X int offset;
X{
X register char **hp;
X int i;
X
X for (hp = x_histp; --hp >= history; ) {
X i = x_match(*hp, pat);
X if (i >= 0) {
X if (offset < 0)
X x_putc('\n');
X x_load_hist(hp);
X x_goto(xbuf + i + strlen(pat) - (*pat == '^'));
X return i;
X }
X }
X x_putc(BEL);
X x_histp = histptr;
X return -1;
X}
X
X/* return position of first match of pattern in string, else -1 */
Xstatic int
Xx_match(str, pat)
X char *str, *pat;
X{
X if (*pat == '^') {
X return (strncmp(str, pat+1, strlen(pat+1)) == 0) ? 0 : -1;
X } else {
X char *q = strstr(str, pat);
X return (q == NULL) ? -1 : q - str;
X }
X}
X
Xstatic int
Xx_del_line(c)
X int c;
X{
X int i, j;
X
X *xep = 0;
X i = xep - xbuf;
X j = x_size_str(xbuf);
X xcp = xbuf;
X x_push(i);
X xep = xbp = xbuf;
X *xcp = 0;
X x_redraw(j);
X return KSTD;
X}
X
Xstatic int
Xx_mv_end(c)
X int c;
X{
X x_goto(xep);
X return KSTD;
X}
X
Xstatic int
Xx_mv_begin(c)
X int c;
X{
X x_goto(xbuf);
X return KSTD;
X}
X
Xstatic int
Xx_draw_line(c)
X int c;
X{
X x_redraw(-1);
X return KSTD;
X
X}
X
Xstatic void
Xx_redraw(limit)
X int limit;
X{
X int i, j;
X char *cp;
X
X x_adj_ok = 0;
X if (limit == -1)
X x_putc('\n');
X else
X x_putc('\r');
X x_flush();
X if (xbp == xbuf)
X {
X pprompt(prompt);
X x_col = strlen(prompt);
X }
X x_displen = x_cols - 2 - x_col;
X x_zots(xbp);
X#if 0 /* <sjg at zen> */
X if (limit >= 0) {
X i = limit - x_size_str(xbp);
X j = 0;
X while (j < i && x_col < (x_cols - 2)) {
X x_putc(' ');
X j++;
X }
X while (j--)
X x_putc('\b');
X }
X#else
X if (xep - xbuf >= x_displen || xbp != xbuf)
X limit = x_cols;
X if (limit >= 0)
X {
X i = limit - x_size_str(xbp);
X for (j = 0; j < i && x_col < (x_cols - 2);j++)
X x_putc(' ');
X i = ' ';
X if (xep - xbp >= x_displen) /* more off screen */
X {
X if (xbp > xbuf)
X i = '*';
X else
X i = '>';
X }
X else
X if (xbp > xbuf)
X i = '<';
X x_putc(i);
X j++;
X while (j--)
X x_putc('\b');
X }
X#endif
X if ((cp = xbp + x_displen) > xep)
X cp = xep;
X i = cp - xcp;
X
X while (i-- > 0)
X x_bs(*--cp);
X x_adj_ok = 1;
X return;
X}
X
Xstatic int
Xx_transpose(c)
X int c;
X{
X char tmp;
X if (xcp == xbuf || xcp == xep) {
X x_putc(BEL);
X return KSTD;
X }
X x_bs(xcp[-1]);
X x_zotc(xcp[0]);
X x_zotc(xcp[-1]);
X tmp = xcp[-1];
X xcp[-1] = xcp[0];
X xcp[0] = tmp;
X x_bs(xcp[0]);
X return KSTD;
X}
X
Xstatic int
Xx_literal(c)
X int c;
X{
X x_curprefix = -1;
X return KSTD;
X}
X
Xstatic int
Xx_meta1(c)
X int c;
X{
X x_curprefix = 1;
X return KPREF;
X}
X
Xstatic int
Xx_meta2(c)
X int c;
X{
X x_curprefix = 2;
X return KPREF;
X}
X
Xstatic int
Xx_kill(c)
X int c;
X{
X int i;
X
X i = xep - xcp;
X#ifndef PUSH_DELETE
X /*
X * 91-04-25 <sjg>
X * We make x_delete do the push,
X * that way we can yank after del-word etc.
X */
X x_push(i);
X#endif
X x_delete(i);
X return KSTD;
X}
X
Xstatic void
Xx_push(nchars)
X int nchars;
X{
X char *cp;
X cp = alloc((size_t)(nchars+1), AEDIT);
X memmove(cp, xcp, nchars);
X cp[nchars] = 0;
X if (killstack[killsp])
X afree((Void *)killstack[killsp], AEDIT);
X killstack[killsp] = cp;
X killsp = (killsp + 1) % KILLSIZE;
X}
X
Xstatic int
Xx_yank(c)
X int c;
X{
X if (killsp == 0)
X killtp = KILLSIZE;
X else
X killtp = killsp;
X killtp --;
X if (killstack[killtp] == 0) {
X x_puts("\nnothing to yank");
X x_redraw(-1);
X return KSTD;
X }
X x_ins(killstack[killtp]);
X return KSTD;
X}
X
Xstatic int
Xx_meta_yank(c)
X int c;
X{
X int len;
X if (x_last_command != x_yank && x_last_command != x_meta_yank) {
X x_puts("\nyank something first");
X x_redraw(-1);
X return KSTD;
X }
X len = strlen(killstack[killtp]);
X x_goto(xcp - len);
X x_delete(len);
X do {
X if (killtp == 0)
X killtp = KILLSIZE - 1;
X else
X killtp--;
X } while (killstack[killtp] == 0);
X x_ins(killstack[killtp]);
X return KSTD;
X}
X
Xstatic int
Xx_abort(c)
X int c;
X{
X /* x_zotc(c); */
X return KINTR;
X}
X
Xstatic int
Xx_error(c)
X int c;
X{
X x_putc(BEL);
X return KSTD;
X}
X
X#if _BSD
X#if defined TIOCGATC
Xstatic struct ttychars lchars, lcharsorig;
X#else
Xstatic struct tchars tchars, tcharsorig;
Xstatic struct ltchars ltchars, ltcharsorig;
X#endif
X#endif
X
X#if _BSD
Xbool_t
Xset_xmode(onoff)
Xbool_t onoff;
X{
X bool_t prev;
Xtypedef struct sgttyb Sgttyb;
X static Sgttyb cb;
X static Sgttyb orig;
X
X if (x_mode == onoff) return x_mode;
X prev = x_mode;
X x_mode = onoff;
X if (onoff) {
X if (first_time) {
X (void)ioctl(0, TIOCGETP, &cb);
X orig = cb;
X cb.sg_flags &= ~ECHO;
X cb.sg_flags |= CBREAK;
X#if defined TIOCGATC
X (void)ioctl(0, TIOCGATC, &lcharsorig);
X lchars = lcharsorig;
X lchars.tc_suspc = -1;
X lchars.tc_dsuspc = -1;
X lchars.tc_lnextc = -1;
X lchars.tc_statc = -1;
X lchars.tc_intrc = -1;
X lchars.tc_quitc = -1;
X lchars.tc_rprntc = -1;
X#else
X (void)ioctl(0, TIOCGETC, &tcharsorig);
X (void)ioctl(0, TIOCGLTC, <charsorig);
X tchars = tcharsorig;
X ltchars = ltcharsorig;
X ltchars.t_suspc = -1;
X ltchars.t_dsuspc = -1;
X ltchars.t_lnextc = -1;
X tchars.t_intrc = -1;
X tchars.t_quitc = -1;
X ltchars.t_rprntc = -1;
X#endif
X first_time = 0;
X }
X (void)ioctl(0, TIOCSETN, &cb);
X#if defined TIOCGATC
X (void)ioctl(0, TIOCSATC, &lchars);
X#else
X (void)ioctl(0, TIOCSETC, &tchars);
X (void)ioctl(0, TIOCSLTC, <chars);
X#endif
X }
X else {
X (void)ioctl(0, TIOCSETN, &orig);
X#if defined TIOCGATC
X (void)ioctl(0, TIOCSATC, &lcharsorig);
X#else
X (void)ioctl(0, TIOCSETC, &tcharsorig);
X (void)ioctl(0, TIOCSLTC, <charsorig);
X#endif
X }
X return prev;
X}
X
X#else /* !_BSD */
X
Xbool_t
Xset_xmode(onoff)
Xbool_t onoff;
X{
X bool_t prev;
X static struct termio cb, orig;
X
X if (x_mode == onoff) return x_mode;
X prev = x_mode;
X x_mode = onoff;
X
X if (onoff) {
X if (first_time) {
X (void)ioctl(0, TCGETA, &cb);
X orig = cb;
X#if defined _CRAY2 /* brain-damaged terminal handler */
X cb.c_lflag &= ~(ICANON|ECHO);
X /* rely on print routine to map '\n' to CR,LF */
X#else
X cb.c_iflag &= ~(INLCR|ICRNL);
X#if _BSD_SYSV /* need to force CBREAK instead of RAW (need CRMOD on output) */
X cb.c_lflag &= ~(ICANON|ECHO);
X#else
X cb.c_lflag &= ~(ISIG|ICANON|ECHO);
X#endif
X cb.c_cc[VTIME] = 0;
X cb.c_cc[VMIN] = 1;
X#endif /* _CRAY2 */
X first_time = 0;
X }
X#if ! defined TCSETAW /* e.g. Cray-2 */
X /* first wait for output to drain */
X#if defined TCSBRK
X (void)ioctl(0, TCSBRK, 1);
X#else /* the following kludge is minimally intrusive, but sometimes fails */
X (void)sleep((unsigned)1); /* fake it */
X#endif
X#endif
X#if _BSD_SYSV || !defined(TCSETAW)
X/* _BSD_SYSV needs to force TIOCSETN instead of TIOCSETP (preserve type-ahead) */
X (void)ioctl(0, TCSETA, &cb);
X#else
X (void)ioctl(0, TCSETAW, &cb);
X#endif
X }
X else {
X#if ! defined TCSETAW /* e.g. Cray-2 */
X /* first wait for output to drain */
X#if defined TCSBRK
X (void)ioctl(0, TCSBRK, 1);
X#else
X/* doesn't seem to be necessary when leaving xmode */
X/* (void)sleep((unsigned)1); /* fake it */
X#endif
X#endif
X#if _BSD_SYSV || !defined(TCSETAW)
X/* _BSD_SYSV needs to force TIOCSETN instead of TIOCSETP (preserve type-ahead) */
X (void)ioctl(0, TCSETA, &orig);
X#else
X (void)ioctl(0, TCSETAW, &orig);
X#endif
X }
X return prev;
X}
X#endif /* _BSD */
X
Xstatic int
Xx_stuffreset(c)
X int c;
X{
X#if defined TIOCSTI
X (void)x_stuff(c);
X return KINTR;
X#else
X x_zotc(c);
X xcp = xep = xbp = xbuf;
X *xcp = 0;
X x_redraw(-1);
X return KSTD;
X#endif
X}
X
Xstatic int
Xx_stuff(c)
X int c;
X{
X#if defined TIOCSTI
X char ch = c;
X bool_t savmode = set_xmode(FALSE);
X
X (void)ioctl(0, TIOCSTI, &ch);
X (void)set_xmode(savmode);
X x_redraw(-1);
X#endif
X return KSTD;
X}
X
Xstatic void
Xx_mapin(cp)
X char *cp;
X{
X char *op;
X
X op = cp;
X while (*cp) {
X /* XXX -- should handle \^ escape? */
X if (*cp == '^') {
X cp++;
X if (*cp >= '?') /* includes '?'; ASCII */
X *op++ = CTRL(*cp);
X else {
X *op++ = '^';
X cp--;
X }
X } else
X *op++ = *cp;
X cp++;
X }
X *op = 0;
X}
X
Xstatic char *
Xx_mapout(c)
X int c;
X{
X static char buf[8];
X register char *p = buf;
X
X if (c < ' ' || c == 0x7F) { /* ASCII */
X *p++ = '^';
X *p++ = (c == 0x7F) ? '?' : (c | 0x40);
X } else
X *p++ = c;
X *p = 0;
X return buf;
X}
X
Xstatic void
Xx_print(prefix, key)
X int prefix, key;
X{
X if (prefix == 1)
X shellf("%s", x_mapout(x_prefix1));
X if (prefix == 2)
X shellf("%s", x_mapout(x_prefix2));
X shellf("%s = ", x_mapout(key));
X if (x_tab[prefix][key]->xf_func != x_ins_string)
X shellf("%s\n", x_tab[prefix][key]->xf_name);
X else
X shellf("'%s'\n", x_atab[prefix][key]);
X}
X
Xvoid
Xx_bind(a1, a2, macro)
X char *a1, *a2;
X int macro; /* bind -m */
X{
X struct x_ftab Const *fp;
X int prefix, key;
X char *sp = NULL;
X
X if (x_tab == NULL)
X errorf("cannot bind, not a tty\n");
X
X if (a1 == NULL) {
X for (prefix = 0; prefix < 3; prefix++)
X for (key = 0; key < 0x80; key++) {
X fp = x_tab[prefix][key];
X if (fp == NULL ||
X fp->xf_func == x_insert || fp->xf_func == x_error)
X continue;
X x_print(prefix, key);
X }
X return;
X }
X
X x_mapin(a1);
X prefix = key = 0;
X for (;; a1++) {
X key = *a1;
X if (x_tab[prefix][key]->xf_func == x_meta1)
X prefix = 1;
X else
X if (x_tab[prefix][key]->xf_func == x_meta2)
X prefix = 2;
X else
X break;
X }
X
X if (a2 == NULL) {
X x_print(prefix, key);
X return;
X }
X
X if (*a2 == 0)
X fp = xft_insert;
X else if (!macro) {
X for (fp = x_ftab; fp->xf_func; fp++)
X if (strcmp(fp->xf_name, a2) == 0)
X break;
X if (fp->xf_func == NULL || (fp->xf_flags & XF_NOBIND))
X errorf("%s: no such function\n", a2);
X if (fp->xf_func == x_meta1)
X x_prefix1 = key;
X if (fp->xf_func == x_meta2)
X x_prefix2 = key;
X } else {
X fp = xft_ins_string;
X x_mapin(a2);
X sp = strsave(a2, AEDIT);
X }
X
X if ((x_tab[prefix][key]->xf_flags & XF_ALLOC) && x_atab[prefix][key])
X afree((Void *)x_atab[prefix][key], AEDIT);
X x_tab[prefix][key] = fp;
X x_atab[prefix][key] = sp;
X}
X
Xvoid
Xx_init()
X{
X register int i, j;
X struct x_ftab Const *fp;
X
X ainit(AEDIT);
X
X x_tab = alloc(sizeofN(*x_tab, 3), AEDIT);
X for (j = 0; j < 128; j++)
X x_tab[0][j] = xft_insert;
X for (i = 1; i < 3; i++)
X for (j = 0; j < 128; j++)
X x_tab[i][j] = xft_error;
X for (fp = x_ftab; fp->xf_func; fp++)
X if (fp->xf_db_char || fp->xf_db_tab)
X x_tab[fp->xf_db_tab][fp->xf_db_char] = fp;
X
X x_atab = alloc(sizeofN(*x_atab, 3), AEDIT);
X for (i = 1; i < 3; i++)
X for (j = 0; j < 128; j++)
X x_atab[i][j] = NULL;
X}
X
X#if SILLY
Xstatic int
Xx_game_of_life(c) {
X char newbuf [256+1];
X register char *ip, *op;
X int i, len;
X
X i = xep - xbuf;
X *xep = 0;
X len = x_size_str(xbuf);
X xcp = xbp = xbuf;
X memmove(newbuf+1, xbuf, i);
X newbuf[0] = 'A';
X newbuf[i] = 'A';
X for (ip = newbuf+1, op = xbuf; --i >= 0; ip++, op++) {
X /* Empty space */
X if (*ip < '@' || *ip == '_' || *ip == 0x7F) {
X /* Two adults, make whoopee */
X if (ip[-1] < '_' && ip[1] < '_') {
X /* Make kid look like parents. */
X *op = '`' + ((ip[-1] + ip[1])/2)%32;
X if (*op == 0x7F) /* Birth defect */
X *op = '`';
X }
X else
X *op = ' '; /* nothing happens */
X continue;
X }
X /* Child */
X if (*ip > '`') {
X /* All alone, dies */
X if (ip[-1] == ' ' && ip[1] == ' ')
X *op = ' ';
X else /* Gets older */
X *op = *ip-'`'+'@';
X continue;
X }
X /* Adult */
X /* Overcrowded, dies */
X if (ip[-1] >= '@' && ip[1] >= '@') {
X *op = ' ';
X continue;
X }
X *op = *ip;
X }
X *op = 0;
X x_redraw(len);
X return KSTD;
X}
X#endif
X
X/*
X * File/command name completion routines
X */
X
X/* type: 0 for list, 1 for completion */
X
Xstatic XPtrV words;
X
Xstatic void
Xadd_stash(dirnam, name)
X char *dirnam; /* directory name, if file */
X char *name;
X{
X char *cp;
X register int type = 0; /* '*' if executable, '/' if directory, else 0 */
X register int len = strlen(name);
X
X /* determine file type */
X if (dirnam) {
X struct stat statb;
X char *buf = alloc((size_t)(strlen(dirnam)+len+2), ATEMP);
X
X if (strcmp(dirnam, ".") == 0)
X *buf = '\0';
X else if (strcmp(dirnam, "/") == 0)
X (void)strcpy(buf, "/");
X else
X (void)strcat(strcpy(buf, dirnam), "/");
X (void)strcat(buf, name);
X if (stat(buf, &statb)==0)
X if (S_ISDIR(statb.st_mode))
X type = '/';
X else if (S_ISREG(statb.st_mode) && access(buf, 01)==0)
X type = '*';
X if (type)
X ++len;
X afree((Void *)buf, ATEMP);
X }
X
X if (len > x_maxlen)
X x_maxlen = len;
X
X /* stash name for later sorting */
X cp = alloc((size_t)(len+1), ATEMP);
X (void)strcpy(cp = alloc((size_t)(len+1), ATEMP), name);
X if (dirnam && type) { /* append file type indicator */
X cp[len-1] = type;
X cp[len] = '\0';
X }
X XPput(words, cp);
X}
X
Xstatic void
Xlist_stash()
X{
X register char **array, **record;
X int items = 0, tabstop, loc, nrows, jump, offset;
X
X items = XPsize(words);
X array = (char**) XPptrv(words);
X if (items == 0)
X return;
X qsortp(XPptrv(words), (size_t)XPsize(words), xstrcmp);
X
X /* print names */
X x_maxlen = (x_maxlen/8 + 1) * 8; /* column width */
X nrows = (items-1) / (x_cols/x_maxlen) + 1;
X for (offset = 0; offset < nrows; ++offset) {
X tabstop = loc = 0;
X x_putc('\n');
X for (jump = 0; offset+jump < items; jump += nrows) {
X if (jump)
X while (loc < tabstop) {
X x_putc('\t');
X loc = (loc/8 + 1) * 8;
X }
X record = array + (offset + jump);
X x_puts(*record);
X afree((Void *)*record, ATEMP);
X loc += strlen(*record);
X tabstop += x_maxlen; /* next tab stop */
X }
X }
X
X afree((Void*)array, ATEMP);
X x_redraw(-1);
X}
X
Xstatic int
Xx_comp_comm(c)
X int c;
X{
X compl_command(1);
X return KSTD;
X}
Xstatic int
Xx_list_comm(c)
X int c;
X{
X compl_command(0);
X return KSTD;
X}
Xstatic int
Xx_complete(c)
X int c;
X{
X compl_dec(1);
X return KSTD;
X}
Xstatic int
Xx_enumerate(c)
X int c;
X{
X compl_dec(0);
X return KSTD;
X}
Xstatic int
Xx_comp_file(c)
X int c;
X{
X compl_file(1);
X return KSTD;
X}
Xstatic int
Xx_list_file(c)
X int c;
X{
X compl_file(0);
X return KSTD;
X}
X
Xstatic void
Xcompl_dec(type)
X int type;
X{
X char *cp;
X cp = xcp;
X
X while (cp != xbuf && !ISFS(*cp))
X cp--;
X if (cp == xbuf && strchr(cp, '/') == NULL)
X compl_command(type);
X else
X compl_file(type);
X}
X
Xstatic void
Xcompl_file(type)
X int type;
X{
X char *str;
X register char *cp, *xp;
X char *lastp;
X char *dirnam;
X char buf [256+1];
X char bug [256+1];
X DIR *dirp;
X struct dirent *dp;
X long loc = -1;
X int len;
X int multi = 0;
X
X str = xcp;
X cp = buf;
X xp = str;
X while (xp != xbuf) {
X --xp;
X if (ISFS(*xp)) {
X xp++;
X break;
X }
X }
X if (digit(*xp) && (xp[1] == '<' || xp[1] == '>'))
X xp++;
X while (*xp == '<' || *xp == '>')
X xp++;
X if (type)
X while (*xcp && !ISFS(*xcp))
X x_zotc(*xcp++);
X else {
X x_maxlen = 0;
X XPinit(words, 16);
X }
X while (*xp && !ISFS(*xp))
X *cp++ = *xp++;
X
X *cp = 0;
X strcpy(buf, cp = substitute(buf, DOTILDE));
X afree((Void*)cp, ATEMP);
X lastp = strrchr(buf, '/');
X if (lastp)
X *lastp = 0;
X
X dirnam = (lastp == NULL) ? "." : (lastp == buf) ? "/" : buf;
X dirp = opendir(dirnam);
X if (dirp == NULL) {
X x_putc(BEL);
X return;
X }
X
X if (lastp == NULL)
X lastp = buf;
X else
X lastp++;
X len = strlen(lastp);
X
X while ((dp = readdir(dirp)) != NULL) {
X cp = dp->d_name;
X if (cp[0] == '.' &&
X (cp[1] == '\0' || cp[1] == '.' && cp[2] == '\0'))
X continue; /* always ignore . and .. */
X if (strncmp(lastp, cp, len) == 0)
X if (type) {
X if (loc == -1) {
X (void)strcpy(bug, cp);
X loc = strlen(cp);
X } else {
X multi = 1;
X loc = strmatch(bug, cp);
X bug[loc] = 0;
X }
X } else
X add_stash(dirnam, cp);
X }
X (void)closedir(dirp);
X
X if (type) {
X if (loc <= 0) {
X x_putc(BEL);
X return;
X }
X cp = bug + len;
X x_ins(cp);
X if (!multi) {
X struct stat statb;
X if (lastp == buf)
X buf[0] = 0;
X else if (lastp == buf + 1) {
X buf[1] = 0;
X buf[0] = '/';
X } else
X (void)strcat(buf, "/");
X (void)strcat(buf, bug);
X if (stat(buf, &statb) == 0 && S_ISDIR(statb.st_mode))
X x_ins("/");
X else
X x_ins(" ");
X }
X } else
X list_stash();
X}
X
Xstatic void
Xcompl_command(type)
X int type;
X{
X register struct tbl *tp;
X char *str;
X char buf [256+1];
X char bug [256+1];
X char *xp;
X char *cp;
X int len;
X int multi;
X int loc;
X
X str = xcp;
X cp = buf;
X xp = str;
X while (xp != xbuf) {
X --xp;
X if (ISFS(*xp)) {
X xp++;
X break;
X }
X }
X if (type)
X while (*xcp && !ISFS(*xcp))
X x_zotc(*xcp++);
X else {
X x_maxlen = 0;
X XPinit(words, 16);
X }
X while (*xp && !ISFS(*xp))
X *cp++ = *xp++;
X *cp = 0;
X
X len = strlen(buf);
X loc = -1;
X multi = 0;
X
X for (twalk(&commands); (tp = tnext()) != NULL; ) {
X int klen;
X
X if (!(tp->flag&ISSET))
X continue;
X klen = strlen(tp->name);
X if (klen < len)
X return;
X if (strncmp(buf, tp->name, len) ==0)
X if (type) {
X if (loc == -1) {
X (void)strcpy(bug, tp->name);
X loc = klen;
X } else {
X multi = 1;
X loc = strmatch(bug, tp->name);
X bug[loc] = 0;
X }
X } else
X add_stash((char *)0, tp->name);
X }
X
X if (type) {
X if (loc <= 0) {
X x_putc(BEL);
X return;
X }
X cp = bug + len;
X x_ins(cp);
X if (!multi)
X x_ins(" ");
X } else
X list_stash();
X}
X
Xstatic int
Xstrmatch(s1, s2)
X register char *s1, *s2;
X{
X register char *p;
X
X for (p = s1; *p == *s2++ && *p != 0; p++)
X ;
X return p - s1;
X}
X
X
X/* NAME:
X * x_set_arg - set an arg value for next function
X *
X * DESCRIPTION:
X * This is a simple implementation of M-[0-9].
X *
X * RETURN VALUE:
X * KSTD
X */
X
Xstatic int
Xx_set_arg(c)
X int c;
X{
X if ((x_arg = (c &= CMASK) - '0') < 0 || x_arg > 9)
X {
X x_arg = 1;
X x_putc(BEL);
X }
X return KSTD;
X}
X
X
X/* NAME:
X * x_prev_histword - recover word from prev command
X *
X * DESCRIPTION:
X * This function recovers the last word from the previous
X * command and inserts it into the current edit line. If a
X * numeric arg is supplied then the n'th word from the
X * start of the previous command is used.
X *
X * Bound to M-.
X *
X * RETURN VALUE:
X * KSTD
X */
X
Xstatic int
Xx_prev_histword()
X{
X register char *rcp;
X char *cp;
X char **hp;
X
X hp = x_histp-1;
X if (hp < history || hp > histptr)
X {
X x_putc(BEL);
X return;
X }
X cp = *hp;
X if (x_last_command != x_set_arg)
X {
X rcp = &cp[strlen(cp) - 1];
X /*
X * ignore white-space after the last word
X */
X while (rcp > cp && ISFS(*rcp))
X rcp--;
X while (rcp > cp && !ISFS(*rcp))
X rcp--;
X if (ISFS(*rcp))
X rcp++;
X x_ins(rcp);
X }
X else
X {
X int c;
X
X rcp = cp;
X /*
X * ignore white-space at start of line
X */
X while (*rcp && ISFS(*rcp))
X rcp++;
X while (x_arg-- > 1)
X {
X while (*rcp && !ISFS(*rcp))
X rcp++;
X while (*rcp && ISFS(*rcp))
X rcp++;
X }
X cp = rcp;
X while (*rcp && !ISFS(*rcp))
X rcp++;
X c = *rcp;
X *rcp = '\0';
X x_ins(cp);
X *rcp = c;
X }
X return KSTD;
X}
X
X/* NAME:
X * x_fold_case - convert word to UPPER/lower case
X *
X * DESCRIPTION:
X * This function is used to implement M-u,M-l and M-c
X * to upper case, lower case or Capitalize words.
X *
X * RETURN VALUE:
X * None
X */
X
Xstatic int
Xx_fold_case(c)
X int c;
X{
X register char *cp = xcp;
X
X if (cp == xep)
X {
X x_putc(BEL);
X return 0;
X }
X c &= 0137; /* strip prefixes and case */
X if (x_last_command != x_set_arg)
X x_arg = 1;
X while (x_arg--)
X {
X /*
X * fisrt skip over any white-space
X */
X while (cp != xep && isfs(*cp))
X {
X cp++;
X }
X /*
X * do the first char on its own since it may be
X * a different action than for the rest.
X */
X if (cp != xep)
X {
X if (c == 'L') /* M-l */
X {
X if (isupper(*cp))
X *cp = tolower(*cp);
X }
X else /* M-u or M-c */
X {
X if (islower(*cp))
X *cp = toupper(*cp);
X }
X cp++;
X }
X /*
X * now for the rest of the word
X */
X while (cp != xep && !isfs(*cp))
X {
X if (c == 'U') /* M-u */
X {
X if (islower(*cp))
X *cp = toupper(*cp);
X }
X else /* M-l or M-c */
X {
X if (isupper(*cp))
X *cp = tolower(*cp);
X }
X cp++;
X }
X }
X x_goto(cp);
X return 0;
X}
X
X#endif /* EDIT */
END_OF_src/edit.c
if test 36696 -ne `wc -c <src/edit.c`; then
echo shar: \"src/edit.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0
--
Simon J. Gerraty <sjg at zen.void.oz.au>
#include <disclaimer> /* imagine something _very_ witty here */
More information about the Alt.sources.patches
mailing list