sjg@zen.void.oz.au (Simon J. Gerraty) (04/25/91)
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@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@zen.void.oz.au> X or <sjg@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@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@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@zen.void.oz.au> #include <disclaimer> /* imagine something _very_ witty here */