home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume25
/
pdksh
/
part01
next >
Wrap
Text File
|
1991-11-12
|
56KB
|
2,636 lines
Newsgroups: comp.sources.misc
From: sjg@zen.void.oz.au (Simon J. Gerraty)
Subject: v25i047: pdksh - Public Domain Korn Shell, v4, Part01/09
Message-ID: <csm-v25i047=pdksh.210931@sparky.IMD.Sterling.COM>
X-Md4-Signature: 49a12c19b06e4666179b8736de09b441
Date: Wed, 13 Nov 1991 03:10:19 GMT
Approved: kent@sparky.imd.sterling.com
Submitted-by: sjg@zen.void.oz.au (Simon J. Gerraty)
Posting-number: Volume 25, Issue 47
Archive-name: pdksh/part01
Environment: UNIX
This is the latest version of the PD ksh (pdksh). It is not
intended to be the ultimate shell but rather a usable ksh work
alike. For those of us who have to work on multiple systems it
is nice to have the same user interface on all. Pdksh is not
100% compatible with the ksh. Having said that, I use it daily
beside a real ksh88 and find them virtually indistinguishable.
I only run this shell on sun's and only for interactive use. I
use it on sun4c, sun3 and sun386 systems. The makefiles are
probably set up for a sun386 :-).
I am releasing this version of the shell (with the kind
permission of the previous maintainers and major contributors) to
ensure that it is available from usenet archive sites. Of
course it remains in the Public Domain. Equally obviously
neither myself nor any other contributors make any claims of
suitability etc. Ie. NO WARRANTY!!!
HISTORY:
This shell was written by Eric Gisin. It is based on Charles
Forsyth's public domain V7 shell, which he later contributed to
Minix. John R MacMillan picked up Eric Gisin's version after
Eric moved on to other projects (see ReadMe.jrm).
Since then there have been many contributors to this shell.
Most have left their fingerprints within the source and various
ReadMe.xxx and Changes.xxx files reflect their input.
This version is basically that known as Eric Gisin's version 3.3
alpha which I obtained indirectly from John R MacMillan who is
the most recent maintainer. This version has much improved
emacs-mode command line editing (my main contribution) plus
enough extra emacs-mode features to make it difficult to
distinguish from ksh88. Bug fixes from various contributors are
the only other changes from John MacMillan's version.
I have upped the version number for this release to distinguish
it from the original 3.3 version. This version is much improved
despite the small number of new features.
Please see the README for additional information concerning pdksh.
Simon J. Gerraty
-----------------
#! /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 . etc sh sh/emacs.c sh/var.c std std/posix std/stdc
# Wrapped by kent@sparky on Tue Nov 12 20:44:31 1991
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 9)."'
if test -f 'README' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(3792 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X Public Domain Korn Shell
X Version 4.1
X
XPD KSH:
X
XThis is the latest version of the PD ksh (pdksh). It is not
Xintended to be the ultimate shell but rather a usable ksh work
Xalike. For those of us who have to work on multiple systems it
Xis nice to have the same user interface on all. Pdksh is not
X100% compatible with the ksh. Having said that, I use it daily
Xbeside a real ksh88 and find them virtually indistinguishable.
X
XI only run this shell on sun's and only for interactive use. I
Xuse it on sun4c, sun3 and sun386 systems. The makefiles are
Xprobably set up for a sun386 :-).
X
XI am releasing this version of the shell (with the kind
Xpermission of the previous maintainers and major contributors) to
Xensure that it is available from usenet archive sites. Of
Xcourse it remains in the Public Domain. Equally obviously
Xneither myself nor any other contributors make any claims of
Xsuitability etc. Ie. NO WARRANTY!!!
X
XHISTORY:
X
XThis shell was written by Eric Gisin. It is based on Charles
XForsyth's public domain V7 shell, which he later contributed to
XMinix. John R MacMillan picked up Eric Gisin's version after
XEric moved on to other projects (see ReadMe.jrm).
X
XSince then there have been many contributors to this shell.
XMost have left their fingerprints within the source and various
XReadMe.xxx and Changes.xxx files reflect their input.
X
XThis version is basically that known as Eric Gisin's version 3.3
Xalpha which I obtained indirectly from John R MacMillan who is
Xthe most recent maintainer. This version has much improved
Xemacs-mode command line editing (my main contribution) plus
Xenough extra emacs-mode features to make it difficult to
Xdistinguish from ksh88. Bug fixes from various contributors are
Xthe only other changes from John MacMillan's version.
X
XI have upped the version number for this release to distinguish
Xit from the original 3.3 version. This version is much improved
Xdespite the small number of new features.
X
XINSTALLATION:
X
XReadMe.jrm is John R MacMillan's README file and contains
Xinformation about the current source arrangement. Please read it.
X
XEric Gisin's original ReadMe file can be found in ./sh, it is
Xsomewhat out of date but retained for history's sake :-) Use
Xthe instructions in ReadMe.jrm.
X
XThe original instructions indicated that a POSIX compliant
Xenvironment and possibly an ANSI compiler are required. I have
Xused both gcc and native Sun compilers without problems.
XActually I use gcc on the sun386 and cc on the others.
XI do know that a friend's SysVr2 NS3210 system required some
Xserious modifications to get the shell running. If he ever
Xsends me the diffs I'll fix the source :-)
X
XENVIRONMENT:
X
XMy main interest in this shell is for Sun workstations. Every
Xother UNIX system I use comes with a real ksh. Being a strictly
XC-shell environment, some improved profile files are in order on
XSun's.
X
XThe etc directory contains a set of useful environment files.
XThese are the same files I use on several systems (many use a
Xreal ksh):
X./etc/profile
X./etc/sys_config.sh
X./etc/ksh.kshrc
X
XThe first one is obvious. The second, sys_config.sh is sourced
Xby /etc/profile and several other scripts. It is used to
Xdetermine the system type so that scripts like profile can be
Xused on multiple platforms.
XThe third one is also quite useful, add
X. /etc/ksh.kshrc
Xto user's ~/.kshrc to simplify alias management.
X
XBUGS:
X
XMany folk have contributed to this shell. There are surely
Xstill plenty of bugs to be found/fixed.
X
XFeel free to e-mail fixes to pdksh-bug@zen.void.oz.au
XPlease use context diffs (ie diff -c, get gnudiff if your
Xsystem's diff doesn't support -c).
XI will, if need be, release patches following the C-news style.
X
XI hope you find this shell as useful as I do...
X
XSimon J. Gerraty <sjg@zen.void.oz.au>
END_OF_FILE
if test 3792 -ne `wc -c <'README'`; then
echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test ! -d 'etc' ; then
echo shar: Creating directory \"'etc'\"
mkdir 'etc'
fi
if test ! -d 'sh' ; then
echo shar: Creating directory \"'sh'\"
mkdir 'sh'
fi
if test -f 'sh/emacs.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'sh/emacs.c'\"
else
echo shar: Extracting \"'sh/emacs.c'\" \(32990 characters\)
sed "s/^X//" >'sh/emacs.c' <<'END_OF_FILE'
X/*
X * 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 */
X
X#include "config.h"
X#ifdef EMACS
X
X#ifndef lint
Xstatic char *RCSid = "$Id: emacs.c,v 3.2 89/03/27 15:49:17 egisin Exp $";
Xstatic char *sccs_id = "@(#)emacs.c 1.5 91/11/09 15:35:13 (sjg)";
X#endif
X
X#include <stddef.h>
X#include <stdlib.h>
X#include <string.h>
X#include <stdio.h>
X#include <signal.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <dirent.h>
X#include <unistd.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 "table.h"
X#include "expand.h"
X#include "edit.h"
X
X#define PUSH_DELETE 1 /* push all deletes of >1 char */
X
Xstatic Area 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#ifndef S_ISDIR
X#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
X#endif
X
X#ifndef S_ISREG
X#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
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#define KNULL 4
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_ALLOC 2
X#define XF_NOBIND 4
X
X#define iscfs(c) (c == ' ' || c == '\t') /* Separator for completion */
X#define ismfs(c) (!(isalnum(c)|| c == '$')) /* Separator for motion */
X#define BEL 0x07
X#define CMASK 0x7F /* 7-bit ASCII character mask */
X
Xstatic int x_prefix1 = CTRL('['), x_prefix2 = CTRL('X');
Xstatic char **x_histp; /* history position */
Xstatic char **x_nextcmdp; /* for newline-and-next */
Xstatic char *xmp; /* mark pointer */
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 x_maxlen; /* to determine column width */
X
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_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();
Xstatic int x_set_mark(), x_kill_region(), x_xchg_point_mark();
Xstatic int x_nl_next_com(), x_eot_del();
Xstatic int x_copy_arg();
Xstatic int x_noop();
X#ifdef 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();
Xstatic int x_prev_histword(), x_set_arg(), x_fold_case();
X
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 {x_del_back, "delete-char-backward", 0, CTRL('H'), 0 },
X {x_eot_del, "eot-or-delete", 0, CTRL('D'), 0 },
X {x_del_bword, "delete-word-backward", 1, CTRL('H'), 0 },
X {x_mv_bword, "backward-word", 1, 'b', 0 },
X {x_del_line, "kill-line", 0, 0, 0 },
X {x_abort, "abort", 0, 0, 0 },
X {x_noop, "no-op", 0, 0, 0 },
X/* Do not move the above! */
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'), 0},
X {x_next_com, "down-history", 0, CTRL('N'), 0},
X {x_search_hist, "search-history", 0, CTRL('R'), 0},
X {x_beg_hist, "beginning-of-history", 1, '<', 0},
X {x_end_hist, "end-of-history", 1, '>', 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 defined(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", 1, 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 {x_nl_next_com, "newline-and-next", 0, CTRL('O'), 0 },
X {x_set_mark, "set-mark-command", 1, ' ', 0 },
X {x_kill_region, "kill-region", 0, CTRL('W'), 0 },
X {x_xchg_point_mark, "exchange-point-and-mark", 2, CTRL('X'), 0 },
X#if 0
X {x_copy_arg, "copy-last-arg", 1, '_', 0},
X#endif
X#ifdef 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 { 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#define xft_erase &x_ftab[3]
X#define xft_kill &x_ftab[7]
X#define xft_werase &x_ftab[5]
X#define xft_intr &x_ftab[8]
X#define xft_quit &x_ftab[9]
X
Xint
Xx_emacs(buf, len)
X char *buf;
X size_t len;
X{
X char c;
X int i;
X int (*func)();
X extern x_insert();
X
X xbp = xbuf = buf; xend = buf + len;
X xlp = xcp = xep = buf;
X *xcp = 0;
X xlp_valid = TRUE;
X xmp = NULL;
X x_curprefix = 0;
X macroptr = null;
X x_histp = histptr + 1;
X
X if (x_nextcmdp != NULL) {
X x_load_hist(x_nextcmdp);
X x_nextcmdp = NULL;
X }
X
X /* <sjg@sun0> this may not be correct */
X if ((i = atoi(strval(global("COLUMNS")))) > 0)
X x_cols = i;
X else
X x_cols = 80;
X x_col = promptlen(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 if ((c = x_getc()) < 0)
X return i;
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 case KNULL:
X break;
X case KEOL:
X i = xep - xbuf;
X x_last_command = 0;
X return i;
X case KINTR: /* special case for interrupt */
X errno = EINTR;
X return -1;
X }
X }
X}
X
Xstatic int
Xx_insert(c) {
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{
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 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 /*
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 xlp_valid = FALSE;
X x_lastcp();
X x_adj_ok = (xcp >= xlp);
X x_zots(cp);
X if (adj == x_adj_done) /* has x_adjust() been called? */
X {
X /* no */
X for (cp = xlp; cp > xcp; )
X x_bs(*--cp);
X }
X
X x_adj_ok = 1;
X return;
X}
X
Xstatic int
Xx_del_back(c) {
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 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 if (xmp != NULL) {
X if (xcp + nc > xmp)
X xmp = xcp;
X else if (xmp > xcp)
X xmp -= nc;
X }
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 xlp_valid = FALSE;
X for (cp = x_lastcp(); cp > xcp; )
X x_bs(*--cp);
X
X return;
X}
X
Xstatic int
Xx_del_bword(c) {
X x_delete(x_bword());
X return KSTD;
X}
X
Xstatic int
Xx_mv_bword(c) {
X (void)x_bword();
X return KSTD;
X}
X
Xstatic int
Xx_mv_fword(c) {
X x_goto(xcp + x_fword());
X return KSTD;
X}
X
Xstatic int
Xx_del_fword(c) {
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 && ismfs(cp[-1]))
X {
X cp--;
X nc++;
X }
X while (cp != xbuf && !ismfs(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 && !ismfs(*cp))
X {
X cp++;
X nc++;
X }
X while (cp != xep && ismfs(*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))
X {
X /* we are heading off screen */
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 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 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 x_lastcp();
X while (*str && str < xlp && 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
Xstatic int
Xx_mv_back(c) {
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 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 *cp;
X
X *xep = '\0';
X if ((c = x_getc()) < 0 ||
X /* we search forward, I don't know what Korn does */
X (cp = (xcp == xep) ? NULL : strchr(xcp+1, c)) == NULL &&
X (cp = strchr(xbuf, c)) == NULL) {
X x_putc(BEL);
X return KSTD;
X }
X x_goto(cp);
X return KSTD;
X}
X
Xstatic int
Xx_newline(c) {
X x_putc('\n');
X x_flush();
X *xep++ = '\n';
X return KEOL;
X}
X
Xstatic int
Xx_end_of_text(c) {
X#if 0
X x_store_hist();
X#endif
X return KEOL;
X}
X
Xstatic int x_beg_hist(c) {x_load_hist(history); return KSTD;}
X
Xstatic int x_end_hist(c) {x_load_hist(histptr); return KSTD;}
X
Xstatic int x_prev_com(c) {x_load_hist(x_histp-1); return KSTD;}
X
Xstatic int x_next_com(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 xlp_valid = FALSE;
X if (xep > x_lastcp())
X x_goto(xep);
X else
X x_redraw(oldsize);
X}
X
Xstatic int
Xx_nl_next_com(c)
Xint c;
X{
X x_nextcmdp = x_histp + 1;
X return (x_newline(c));
X}
X
Xstatic int
Xx_eot_del(c)
Xint c;
X{
X if (xep == xbuf)
X return (x_end_of_text(c));
X else
X return (x_del_char(c));
X}
X
Xstatic int x_search(), x_match();
X
X/* reverse incremental history search */
Xstatic int
Xx_search_hist(c)
X int c;
X{
X int offset = -1; /* offset of match in xbuf, else -1 */
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 ((c = x_getc()) < 0)
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 static char push[2];
X push[0] = c;
X macroptr = push; /* 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 i, j;
X
X *xep = 0;
X i = xep- xbuf;
X j = x_size_str(xbuf);
X xcp = xbuf;
X x_push(i);
X xlp = xbp = xep = xbuf;
X xlp_valid = TRUE;
X *xcp = 0;
X xmp = NULL;
X x_redraw(j);
X return KSTD;
X}
X
Xstatic int
Xx_mv_end(c) {
X x_goto(xep);
X return KSTD;
X}
X
Xstatic int
Xx_mv_begin(c) {
X x_goto(xbuf);
X return KSTD;
X}
X
Xstatic int
Xx_draw_line(c)
X{
X x_redraw(-1);
X return KSTD;
X
X}
X
Xvoid
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 = promptlen(prompt);
X }
X x_displen = x_cols - 2 - x_col;
X xlp_valid = FALSE;
X cp = x_lastcp();
X x_zots(xbp);
X if (xbp != xbuf || xep > xlp)
X limit = x_cols;
X if (limit >= 0)
X {
X if (xep > xlp)
X i = 0; /* we fill the line */
X else
X i = limit - (xlp - xbp);
X
X for (j = 0; j < i && x_col < (x_cols - 2); j++)
X x_putc(' ');
X i = ' ';
X if (xep > xlp) /* 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 for (cp = xlp; cp > xcp; )
X x_bs(*--cp);
X x_adj_ok = 1;
X _D_(x_flush();)
X return;
X}
X
Xstatic int
Xx_transpose(c) {
X char tmp;
X if (xcp == xbuf) {
X x_putc(BEL);
X return KSTD;
X } else if (xcp == xep) {
X if (xcp - xbuf == 1) {
X x_putc(BEL);
X return KSTD;
X }
X x_bs(xcp[-1]);
X x_bs(xcp[-2]);
X x_zotc(xcp[-1]);
X x_zotc(xcp[-2]);
X tmp = xcp[-1];
X xcp[-1] = xcp[-2];
X xcp[-2] = tmp;
X } else {
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 }
X return KSTD;
X}
X
Xstatic int
Xx_literal(c) {
X x_curprefix = -1;
X return KSTD;
X}
X
Xstatic int
Xx_meta1(c) {
X x_curprefix = 1;
X return KPREF;
X}
X
Xstatic int
Xx_meta2(c) {
X x_curprefix = 2;
X return KPREF;
X}
X
Xstatic int
Xx_kill(c) {
X int i;
X
X i = xep - xcp;
X xlp = xcp;
X xlp_valid = TRUE;
X x_push(i);
X x_delete(i);
X return KSTD;
X}
X
Xstatic void
Xx_push(nchars) {
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 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 xmp = xcp;
X x_ins(killstack[killtp]);
X return KSTD;
X}
X
Xstatic int
Xx_meta_yank(c) {
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 /* x_zotc(c); */
X xlp = xep = xcp = xbp = xbuf;
X xlp_valid = TRUE;
X *xcp = 0;
X return KINTR;
X}
X
Xstatic int
Xx_error(c) {
X x_putc(BEL);
X return KSTD;
X}
X
Xstatic int
Xx_stuffreset(c)
X{
X#ifdef TIOCSTI
X (void)x_stuff(c);
X return KINTR;
X#else
X x_zotc(c);
X xlp = xcp = xep = xbp = xbuf;
X xlp_valid = TRUE;
X *xcp = 0;
X x_redraw(-1);
X return KSTD;
X#endif
X}
X
Xstatic int
Xx_stuff(c)
X{
X#if 0 || defined TIOCSTI
X char ch = c;
X bool_t savmode = x_mode(FALSE);
X
X (void)ioctl(ttyfd, TIOCSTI, &ch);
X (void)x_mode(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_emacs()
X{
X register int i, j;
X struct x_ftab Const *fp;
X
X ainit(AEDIT);
X
X x_tab = (struct x_ftab ***) 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 = (char ***) 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
Xvoid
Xx_emacs_keys(erase, kill, werase, intr, quit)
X int erase, kill, werase, intr, quit;
X{
X x_tab[0][erase] = xft_erase;
X x_tab[0][kill] = xft_kill;
X x_tab[0][werase] = xft_werase;
X x_tab[0][intr] = xft_intr;
X x_tab[0][quit] = xft_quit;
X}
X
Xstatic int
Xx_set_mark(c) {
X xmp = xcp;
X return KSTD;
X}
X
Xstatic int
Xx_kill_region(c) {
X int rsize;
X char *xr;
X
X if (xmp == NULL) {
X x_putc(BEL);
X return KSTD;
X }
X if (xmp > xcp) {
X rsize = xmp - xcp;
X xr = xcp;
X } else {
X rsize = xcp - xmp;
X xr = xmp;
X }
X x_goto(xr);
X x_push(rsize);
X x_delete(rsize);
X xmp = xr;
X return KSTD;
X}
X
Xstatic int
Xx_xchg_point_mark(c) {
X char *tmp;
X
X if (xmp == NULL) {
X x_putc(BEL);
X return KSTD;
X }
X tmp = xmp;
X xmp = xcp;
X x_goto( tmp );
X return KSTD;
X}
X
X#if 0
Xstatic int
Xx_copy_arg(c) {
X char *last;
X if ((last = strval(local("_"))) && *last)
X x_ins(last);
X return KSTD;
X}
X#endif
X
Xstatic int
Xx_noop(c) {
X return KNULL;
X}
X
X#ifdef 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 loc += strlen(*record);
X tabstop += x_maxlen; /* next tab stop */
X afree((Void *)*record, ATEMP);
X }
X }
X
X afree((Void*)array, ATEMP);
X x_redraw(-1);
X}
X
Xstatic int
Xx_comp_comm(c) {
X compl_command(1);
X return KSTD;
X}
Xstatic int
Xx_list_comm(c) {
X compl_command(0);
X return KSTD;
X}
Xstatic int
Xx_complete(c) {
X compl_dec(1);
X return KSTD;
X}
Xstatic int
Xx_enumerate(c) {
X compl_dec(0);
X return KSTD;
X}
Xstatic int
Xx_comp_file(c) {
X compl_file(1);
X return KSTD;
X}
Xstatic int
Xx_list_file(c) {
X compl_file(0);
X return KSTD;
X}
X
Xstatic void
Xcompl_dec(type)
X{
X char *cp;
X cp = xcp;
X
X while (cp != xbuf && !iscfs(*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{
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 (iscfs(*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 && !iscfs(*xcp))
X x_zotc(*xcp++);
X else {
X x_maxlen = 0;
X XPinit(words, 16);
X }
X while (*xp && !iscfs(*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{
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 (iscfs(*xp)) {
X xp++;
X break;
X }
X }
X if (type)
X while (*xcp && !iscfs(*xcp))
X x_zotc(*xcp++);
X else {
X x_maxlen = 0;
X XPinit(words, 16);
X }
X while (*xp && !iscfs(*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 continue;
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
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 && iscfs(*rcp))
X rcp--;
X while (rcp > cp && !iscfs(*rcp))
X rcp--;
X if (iscfs(*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 && iscfs(*rcp))
X rcp++;
X while (x_arg-- > 1)
X {
X while (*rcp && !iscfs(*rcp))
X rcp++;
X while (*rcp && iscfs(*rcp))
X rcp++;
X }
X cp = rcp;
X while (*rcp && !iscfs(*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 && ismfs(*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 && !ismfs(*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/* NAME:
X * x_lastcp - last visible char
X *
X * SYNOPSIS:
X * x_lastcp()
X *
X * DESCRIPTION:
X * This function returns a pointer to that char in the
X * edit buffer that will be the last displayed on the
X * screen. The sequence:
X *
X * for (cp = x_lastcp(); cp > xcp; cp)
X * x_bs(*--cp);
X *
X * Will position the cursor correctly on the screen.
X *
X * RETURN VALUE:
X * cp or NULL
X */
X
Xchar *
Xx_lastcp()
X{
X register char *rcp;
X register int i;
X
X if (!xlp_valid)
X {
X for (i = 0, rcp = xbp; rcp < xep && i < x_displen; rcp++)
X i += x_size(*rcp);
X xlp = rcp;
X }
X xlp_valid = TRUE;
X return (xlp);
X}
X
X#endif /* EDIT */
X
END_OF_FILE
if test 32990 -ne `wc -c <'sh/emacs.c'`; then
echo shar: \"'sh/emacs.c'\" unpacked with wrong size!
fi
# end of 'sh/emacs.c'
fi
if test -f 'sh/var.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'sh/var.c'\"
else
echo shar: Extracting \"'sh/var.c'\" \(11520 characters\)
sed "s/^X//" >'sh/var.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char *RCSid = "$Id: var.c,v 3.2 89/03/27 15:52:21 egisin Exp $";
Xstatic char *sccs_id = "@(#)var.c 1.3 91/11/09 15:35:17 (sjg)";
X#endif
X
X#include <stddef.h>
X#include <string.h>
X#include <errno.h>
X#include <setjmp.h>
X#include <time.h>
X#include "sh.h"
X#include "table.h"
X#include "expand.h"
X
X/*
X * Variables
X *
X * WARNING: unreadable code, needs a rewrite
X *
X * if (flag&INTEGER), val.i contains integer value, and type contains base.
X * otherwise, (val.s + type) contains string value.
X * if (flag&EXPORT), val.s contains "name=value" for E-Z exporting.
X */
Xchar null [] = "";
Xstatic struct tbl vtemp;
Xstatic void getspec(), setspec();
Xstatic void export ARGS((struct tbl *, char *val));
Xstatic int special ARGS ((char *name));
X
X/*
X * create a new block for function calls and simple commands
X * assume caller has allocated and set up e.loc
X */
Xvoid
Xnewblock()
X{
X register struct block *l = e.loc;
X static char *empty[] = {""};
X
X ainit(&l->area);
X l->argc = 0;
X l->argv = empty;
X l->exit = l->error = NULL;
X tinit(&l->vars, &l->area);
X tinit(&l->funs, &l->area);
X}
X
X/*
X * pop a block handling special variables
X */
Xvoid
Xpopblock()
X{
X register struct block *l = e.loc;
X register struct tbl *vp, **vpp = l->vars.tbls;
X register int i;
X
X e.loc = l->next; /* pop block */
X for (i = l->vars.size; --i >= 0; )
X if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL))
X setspec(global(vp->name));
X afreeall(&l->area);
X}
X
X/*
X * Search for variable, if not found create globally.
X */
Xstruct tbl *
Xglobal(n)
X register char *n;
X{
X register struct block *l = e.loc;
X register struct tbl *vp;
X register int c;
X unsigned h = hash(n);
X
X c = n[0];
X if (digit(c)) {
X vp = &vtemp;
X lastarea = ATEMP;
X vp->flag = (DEFINED|RDONLY);
X vp->type = 0;
X *vp->name = c; /* should strncpy */
X for (c = 0; digit(*n) && c < 1000; n++)
X c = c*10 + *n-'0';
X if (c <= l->argc)
X setstr(vp, l->argv[c]);
X return vp;
X } else
X if (!letter(c)) {
X vp = &vtemp;
X lastarea = ATEMP;
X vp->flag = (DEFINED|RDONLY);
X vp->type = 0;
X *vp->name = c;
X if (n[1] != '\0')
X return vp;
X vp->flag |= ISSET|INTEGER;
X switch (c) {
X case '$':
X vp->val.i = kshpid;
X break;
X case '!':
X vp->val.i = async;
X break;
X case '?':
X vp->val.i = exstat;
X break;
X case '#':
X vp->val.i = l->argc;
X break;
X case '-':
X vp->flag &= ~ INTEGER;
X vp->val.s = getoptions();
X break;
X default:
X vp->flag &= ~(ISSET|INTEGER);
X }
X return vp;
X }
X for (l = e.loc; l != NULL; l = l->next) {
X vp = tsearch(&l->vars, n, h);
X lastarea = &l->area;
X if (vp != NULL)
X return vp;
X if (l->next == NULL)
X break;
X }
X vp = tenter(&l->vars, n, h);
X vp->flag |= DEFINED;
X if (special(n))
X vp->flag |= SPECIAL;
X return vp;
X}
X
X/*
X * Search for local variable, if not found create locally.
X */
Xstruct tbl *
Xlocal(n)
X register char *n;
X{
X register struct block *l = e.loc;
X register struct tbl *vp;
X unsigned h = hash(n);
X
X if (!letter(*n)) {
X vp = &vtemp;
X lastarea = ATEMP;
X vp->flag = (DEFINED|RDONLY);
X vp->type = 0;
X return vp;
X }
X vp = tenter(&l->vars, n, h);
X lastarea = &l->area;
X vp->flag |= DEFINED;
X if (special(n))
X vp->flag |= SPECIAL;
X return vp;
X}
X
X/* get variable string value */
Xchar *
Xstrval(vp)
X register struct tbl *vp;
X{
X register char *s;
X static char strbuf[40];
X
X if ((vp->flag&SPECIAL))
X getspec(vp);
X if (!(vp->flag&ISSET))
X return null; /* special to dollar() */
X if (!(vp->flag&INTEGER)) /* string source */
X s = vp->val.s + vp->type;
X else { /* integer source */
X register unsigned long n;
X register int base;
X
X s = strbuf + sizeof(strbuf);
X n = (vp->val.i < 0) ? -vp->val.i : vp->val.i;
X base = (vp->type == 0) ? 10 : vp->type;
X
X *--s = '\0';
X do {
X *--s = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[n%base];
X n /= base;
X } while (n != 0);
X /* todo: should we output base# ? */
X if (vp->val.i < 0)
X *--s = '-';
X }
X return s;
X}
X
X/* get variable integer value */
Xlong
Xintval(vp)
X register struct tbl *vp;
X{
X register struct tbl *vq;
X
X if ((vp->flag&SPECIAL))
X getspec(vp);
X if ((vp->flag&INTEGER))
X return vp->val.i;
X vq = &vtemp;
X vq->flag = (INTEGER);
X vq->type = 0;
X if (strint(vq, vp) == NULL)
X errorf("%s: bad number\n", vp->val.s);
X return vq->val.i;
X}
X
X/* set variable to string value */
Xvoid
Xsetstr(vq, s)
X register struct tbl *vq;
X char *s;
X{
X if (!(vq->flag&INTEGER)) { /* string dest */
X if ((vq->flag&ALLOC))
X afree((Void*)vq->val.s, lastarea);
X vq->flag &= ~ (ISSET|ALLOC);
X vq->type = 0;
X if ((vq->flag&EXPORT))
X export(vq, s);
X else
X vq->val.s = strsave(s, lastarea);
X vq->flag |= ALLOC;
X } else { /* integer dest */
X register struct tbl *vp = &vtemp;
X vp->flag = (DEFINED|ISSET);
X vp->type = 0;
X vp->val.s = s;
X if (strint(vq, vp) == NULL)
X errorf("%s: bad number\n", s);
X }
X vq->flag |= ISSET;
X if ((vq->flag&SPECIAL))
X setspec(vq);
X}
X
X/* convert variable to integer variable */
Xstruct tbl *
Xstrint(vq, vp)
X register struct tbl *vq, *vp;
X{
X register char *s = vp->val.s + vp->type;
X register int c;
X int base, neg = 0;
X
X vq->flag |= INTEGER;
X if (!(vp->flag&ISSET) || (s == NULL && !(vp->flag&INTEGER))) {
X vq->flag &= ~ ISSET;
X return NULL;
X }
X if ((vp->flag&INTEGER)) {
X vq->val.i = vp->val.i;
X return vq;
X }
X vq->val.i = 0;
X base = 10;
X for (c = *s++; c ; c = *s++)
X if (c == '-') {
X neg++;
X } else if (c == '#') {
X base = vq->type = vq->val.i;
X vq->val.i = 0;
X } else if (letnum(c)) {
X if ('0' <= c && c <= '9')
X c -= '0';
X else if ('a' <= c && c <= 'z') /* fuck EBCDIC */
X c -= 'a'-10;
X else if ('A' <= c && c <= 'Z')
X c -= 'A'-10;
X if (c < 0 || c >= base) {
X vq->flag &= ~ ISSET;
X return NULL;
X }
X vq->val.i = (vq->val.i*base) + c;
X } else
X break;
X if (neg)
X vq->val.i = -vq->val.i;
X if (vq->type < 2 || vq->type > 36)
X vq->type = 0; /* default base (10) */
X return vq;
X}
X
X/* set variable to integer */
Xvoid
Xsetint(vq, n)
X register struct tbl *vq;
X long n;
X{
X if (!(vq->flag&INTEGER)) {
X register struct tbl *vp = &vtemp;
X vp->flag = (ISSET|INTEGER);
X vp->type = 0;
X vp->val.i = n;
X setstr(vq, strval(vp)); /* ? */
X } else
X vq->val.i = n;
X vq->flag |= ISSET;
X if ((vq->flag&SPECIAL))
X setspec(vq);
X}
X
X/* set variable from enviroment */
Ximport(thing)
X char *thing;
X{
X register struct tbl *vp;
X register char *val;
X
X val = strchr(thing, '=');
X if (val == NULL)
X return 0;
X *val = '\0';
X vp = local(thing);
X *val++ = '=';
X vp->flag |= DEFINED|ISSET|EXPORT;
X vp->val.s = thing;
X vp->type = val - thing;
X if ((vp->flag&SPECIAL))
X setspec(vp);
X return 1;
X}
X
X/*
X * make vp->val.s be "name=value" for quick exporting.
X */
Xstatic void
Xexport(vp, val)
X register struct tbl *vp;
X char *val;
X{
X register char *cp, *xp;
X char *op = (vp->flag&ALLOC) ? vp->val.s : NULL;
X
X xp = (char*)alloc(strlen(vp->name) + strlen(val) + 2, lastarea);
X vp->flag |= ALLOC;
X vp->val.s = xp;
X for (cp = vp->name; (*xp = *cp++) != '\0'; xp++)
X ;
X *xp++ = '=';
X vp->type = xp - vp->val.s; /* offset to value */
X for (cp = val; (*xp++ = *cp++) != '\0'; )
X ;
X if (op != NULL)
X afree((Void*)op, lastarea);
X}
X
X/*
X * lookup variable (according to (set&LOCAL)),
X * set its attributes (INTEGER, RDONLY, EXPORT, TRACE),
X * and optionally set its value if an assignment.
X */
Xstruct tbl *
Xtypeset(var, set, clr)
X register char *var;
X int clr, set;
X{
X register struct tbl *vp;
X register char *val;
X
X /* check for valid variable name, search for value */
X val = var;
X if (!letter(*val))
X return NULL;
X for (val++; *val != '\0'; val++)
X if (*val == '=')
X break;
X else if (letnum(*val))
X ;
X else
X return NULL;
X if (*val == '=')
X *val = '\0';
X else
X val = NULL;
X vp = (set&LOCAL) ? local(var) : global(var);
X set &= ~ LOCAL;
X if (val != NULL)
X *val++ = '=';
X
X if (!(vp->flag&ISSET))
X vp->flag = vp->flag & ~clr | set;
X else
X if (!(vp->flag&INTEGER) && (set&INTEGER)) {
X /* string to integer */
X vtemp.flag = (ISSET);
X vtemp.type = 0;
X vtemp.val.s = vp->val.s + vp->type;
X if ((vp->flag&ALLOC))
X afree((Void*)vp->val.s, lastarea); /* dangerous, used later */
X vp->flag &= ~ ALLOC;
X vp->flag |= INTEGER;
X vp->type = 0;
X if (val == NULL && strint(vp, &vtemp) == NULL) {
X vp->flag &= ~ ISSET;
X errorf("%s: bad number\n", vtemp.val.s);
X }
X } else
X if ((clr&INTEGER) && (vp->flag&INTEGER)) {
X /* integer to string */
X vtemp.val.s = strval(vp);
X vp->flag &= ~ INTEGER;
X setstr(vp, vtemp.val.s);
X }
X
X vp->flag = vp->flag & ~clr | set;
X
X if (val != NULL) {
X if ((vp->flag&RDONLY))
X errorf("cannot set readonly %s\n", var);
X if ((vp->flag&INTEGER))
X /* setstr should be able to handle this */
X (void)evaluate(var);
X else
X setstr(vp, val);
X }
X
X if ((vp->flag&EXPORT) && !(vp->flag&INTEGER) && vp->type == 0)
X export(vp, (vp->flag&ISSET) ? vp->val.s : null);
X
X return vp;
X}
X
Xvoid
Xunset(vp)
X register struct tbl *vp;
X{
X if ((vp->flag&ALLOC))
X afree((Void*)vp->val.s, lastarea);
X vp->flag &= SPECIAL; /* Should ``unspecial'' some vars */
X}
X
Xint
Xisassign(s)
X register char *s;
X{
X if (!letter(*s))
X return (0);
X for (s++; *s != '='; s++)
X if (*s == 0 || !letnum(*s))
X return (0);
X return (1);
X}
X
X/*
X * Make the exported environment from the exported names in the dictionary.
X */
Xchar **
Xmakenv()
X{
X struct block *l = e.loc;
X XPtrV env;
X register struct tbl *vp, **vpp;
X register int i;
X
X XPinit(env, 64);
X for (l = e.loc; l != NULL; l = l->next)
X for (vpp = l->vars.tbls, i = l->vars.size; --i >= 0; )
X if ((vp = *vpp++) != NULL
X && (vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) {
X register struct block *l2;
X register struct tbl *vp2;
X unsigned h = hash(vp->name);
X
X lastarea = &l->area;
X
X /* unexport any redefined instances */
X for (l2 = l->next; l2 != NULL; l2 = l2->next) {
X vp2 = tsearch(&l2->vars, vp->name, h);
X if (vp2 != NULL)
X vp2->flag &= ~ EXPORT;
X }
X if ((vp->flag&INTEGER)) {
X /* integer to string */
X char *val;
X val = strval(vp);
X vp->flag &= ~ INTEGER;
X setstr(vp, val);
X }
X XPput(env, vp->val.s);
X }
X XPput(env, NULL);
X return (char **) XPclose(env);
X}
X
X/*
X * handle special variables with side effects - PATH, SECONDS.
X */
X
Xstatic int
Xspecial(name)
X register char * name;
X{
X if (strcmp("PATH", name) == 0)
X return V_PATH;
X if (strcmp("IFS", name) == 0)
X return V_IFS;
X if (strcmp("SECONDS", name) == 0)
X return V_SECONDS;
X if (strcmp("OPTIND", name) == 0)
X return V_OPTIND;
X if (strcmp("MAIL", name) == 0)
X return V_MAIL;
X if (strcmp("MAILPATH", name) == 0)
X return V_MAILPATH;
X if (strcmp("RANDOM", name) == 0)
X return V_RANDOM;
X return V_NONE;
X}
X
Xextern time_t time();
Xstatic time_t seconds; /* time SECONDS last set */
Xextern int rand();
Xextern void srand();
X
Xstatic void
Xgetspec(vp)
X register struct tbl *vp;
X{
X switch (special(vp->name)) {
X case V_SECONDS:
X vp->flag &= ~ SPECIAL;
X setint(vp, time((time_t *)0) - seconds);
X vp->flag |= SPECIAL;
X break;
X case V_RANDOM:
X vp->flag &= ~ SPECIAL;
X setint(vp, (rand() & 0x7fff));
X vp->flag |= SPECIAL;
X break;
X }
X}
X
Xstatic void
Xsetspec(vp)
X register struct tbl *vp;
X{
X extern void mbset(), mpset();
X
X switch (special(vp->name)) {
X case V_PATH:
X path = strval(vp);
X flushcom(1); /* clear tracked aliases */
X break;
X case V_IFS:
X setctypes(strval(vp), C_IFS);
X break;
X case V_SECONDS:
X seconds = time((time_t *)0);
X break;
X case V_OPTIND:
X if (intval(vp) == 1)
X resetopts();
X break;
X case V_MAIL:
X mbset(strval(vp));
X break;
X case V_MAILPATH:
X mpset(strval(vp));
X break;
X case V_RANDOM:
X vp->flag &= ~ SPECIAL;
X srand((unsigned int)intval(vp));
X vp->flag |= SPECIAL;
X break;
X }
X}
X
END_OF_FILE
if test 11520 -ne `wc -c <'sh/var.c'`; then
echo shar: \"'sh/var.c'\" unpacked with wrong size!
fi
# end of 'sh/var.c'
fi
if test ! -d 'std' ; then
echo shar: Creating directory \"'std'\"
mkdir 'std'
fi
if test ! -d 'std/posix' ; then
echo shar: Creating directory \"'std/posix'\"
mkdir 'std/posix'
fi
if test ! -d 'std/stdc' ; then
echo shar: Creating directory \"'std/stdc'\"
mkdir 'std/stdc'
fi
echo shar: End of archive 1 \(of 9\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 9 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still must unpack the following archives:
echo " " ${MISSING}
fi
exit 0
exit 0 # Just in case...
--
Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD UUCP: uunet!sparky!kent
Phone: (402) 291-8300 FAX: (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.