home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume25
/
pdksh
/
part03
< prev
next >
Wrap
Text File
|
1991-11-12
|
56KB
|
2,751 lines
Newsgroups: comp.sources.misc
From: sjg@zen.void.oz.au (Simon J. Gerraty)
Subject: v25i049: pdksh - Public Domain Korn Shell, v4, Part03/09
Message-ID: <1991Nov13.031054.15849@sparky.imd.sterling.com>
X-Md4-Signature: 52c66eb39f12096edc2a8e55bd5d160e
Date: Wed, 13 Nov 1991 03:10:54 GMT
Approved: kent@sparky.imd.sterling.com
Submitted-by: sjg@zen.void.oz.au (Simon J. Gerraty)
Posting-number: Volume 25, Issue 49
Archive-name: pdksh/part03
Environment: UNIX
#! /bin/sh
# 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: etc/profile sh/exec.c sh/vi.c
# Wrapped by kent@sparky on Tue Nov 12 20:44:32 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 3 (of 9)."'
if test -f 'etc/profile' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'etc/profile'\"
else
echo shar: Extracting \"'etc/profile'\" \(5445 characters\)
sed "s/^X//" >'etc/profile' <<'END_OF_FILE'
X:
X# NAME:
X# profile - global initialization for sh,ksh
X#
X# DESCRIPTION:
X# This file is processed during login by /bin/sh
X# and /bin/ksh. It is used to setup the default user
X# environment. It is processed with root privs.
X#
X# SEE ALSO:
X# $HOME/.profile
X# /etc/ksh.kshrc
X#
X# AMENDED:
X# 91/11/08 23:02:21 (sjg)
X#
X# RELEASED:
X# 91/11/08 23:02:24 v2.7
X#
X# SCCSID:
X# @(#)profile 2.7 91/11/08 23:02:21 (sjg)
X#
X# @(#)Copyright (c) 1991 Simon J. Gerraty
X#
X# This file is provided in the hope that it will
X# be of use. There is absolutely NO WARRANTY.
X# Permission to copy, redistribute or otherwise
X# use this file is hereby granted provided that
X# the above copyright notice and this notice are
X# left intact.
X
Xcase "$_INIT_" in
X*env*) ;;
X*) # do these once
X _INIT_="$_INIT_"env
X export _INIT_
X # sys_config.sh should set ARCH,OS,C,N,HOSTNAME,uname
X # we use these in lots of scripts...
X [ -f /etc/sys_config.sh ] && . /etc/sys_config.sh
X
X # pick one of the following for the default umask
X # umask 002 # relaxed -rwxrwxr-x
X umask 022 # cautious -rwxr-xr-x
X # umask 027 # uptight -rwxr-x---
X # umask 077 # paranoid -rwx------
X # you can override the default umask
X # for specific groups later...
X
X if [ -d /local ]; then
X LOCAL=/local
X else
X LOCAL=/usr/local
X fi
X
X # set system specific things,
X # eg. set PATH,MANPATH
X # override default ulimit if desired.
X # defult ulmit is unlimited on SunOS
X # and 4Mb for most System V
X case $OS in
X SunOS)
X # On sun's /bin -> /usr/bin so leave it out!
X PATH=.:/usr/bin:/usr/ucb:/usr/5bin
X MANPATH=/usr/man
X defterm=vt220
X ;;
X SCO-UNIX)
X PATH=.:/bin:/usr/bin:/usr/lbin:/usr/dbin:/usr/ldbin
X MANPATH=/usr/man
X defterm=ansi
X ;;
X B.O.S.)
X PATH=.:/bin:/usr/bin
X if [ -d /usr/ucb ]; then
X PATH=$PATH:/usr/ucb
X fi
X MANPATH=/usr/catman
X defterm=vt220
X SRC_COMPAT=_SYSV
X export SRC_COMPAT
X ;;
X *)
X PATH=.:/bin:/usr/bin
X if [ -d /usr/ucb ]; then
X PATH=$PATH:/usr/ucb
X fi
X MANPATH=/usr/catman
X defterm=vt220
X ;;
X esac
X if [ -d ${LOCAL}/bin ]; then
X PATH=$PATH:${LOCAL}/bin
X fi
X if [ -d $HOME/bin -a "$HOME" != / ]; then
X PATH=$PATH:$HOME/bin
X fi
X if [ -d ${LOCAL}/man ]; then
X MANPATH=$MANPATH:${LOCAL}/man
X fi
X # make sure these are set at least once
X LOGNAME=${LOGNAME:-`logname`}
X USER=${USER:-$LOGNAME}
X
X # this is adapted from my whoami.sh
X # we expect id to produce output like:
X # uid=100(sjg) gid=10(staff) groups=10(staff),...
X S='('
X E=')'
X GROUP=`id | cut -d= -f3 | \
X sed -e "s;^[^${S}][^${S}]*${S}\([^${E}][^${E}]*\)${E}.*$;\1;"`
X
X # set some group specific defaults
X case "$GROUP" in
X staff) # staff deal with things that non-staff
X # have no business looking at
X umask 027
X ;;
X extern) # we put external accounts in group "extern"
X # give them as much privacy as we can...
X umask 077
X ulimit 16384 # 8Mb file limit
X TMOUT=600 # idle timeout
X ;;
X esac
X
X unset S E GROUP
X export LOCAL TTY PATH LOGNAME USER
X
X TTY=`tty`
X if [ $? -ne 0 ]; then
X # This trick appears not to work under BOS 2.00.45
X # so be careful of su - user in boot scripts.
X TTY=none
X else
X TTY=`basename $TTY`
X ORGANIZATION=""
X COPYRIGHT="Copyright (c) `date +19%y` $ORGANIZATION"
X export ORGANIZATION COPYRIGHT
X
X # set up some env variables
X MAIL=/usr/spool/mail/$USER
X MAILPATH=/usr/spool/mail/$USER:/etc/motd
X EMACSDIR=${LOCAL}/lib/emacs
X PAGER=${PAGER:-more}
X export MAIL EMACSDIR MANPATH MAILPATH PAGER
X
X EDITOR=emacs
X
X PROMPT="<$LOGNAME@$HOSTNAME>$ "
X PUBDIR=/usr/spool/uucppublic
X export PUBDIR
X [ -f /etc/profile.TeX ] && . /etc/profile.TeX
X fi
X
X # test (and setup if we are Korn shell)
X if [ "$RANDOM" != "$RANDOM" ]; then
X # we are Korn shell
X SHELL=/bin/ksh
X ENV=${HOME%/}/.kshrc
X PROMPT="<$LOGNAME@$HOSTNAME:!>$ "
X export HISTSIZE HISTFILE ENV
X CDPATH=.:$HOME
X if [ "$TMOUT" ]; then
X typeset -r TMOUT
X fi
X else
X SHELL=/bin/sh
X fi
X PS1=$PROMPT
X export SHELL PS1 EDITOR PATH PROMPT HOSTNAME CDPATH
X
X;;
Xesac
X
X# login time initialization
Xcase "$_INIT_" in
X*log*) ;;
X*) _INIT_="$_INIT_"log
X
X if [ $TTY != none -a "$0" != "-su" -a "$LOGNAME" = "`logname`" -a ! -f ~/.hushlogin ]
X then
X case $TERM in
X network|unknown|dialup|"")
X echo $N "Enter terminal type [$defterm]: $C" 1>&2
X read tmpterm
X TERM=${tmpterm:-$defterm}
X ;;
X esac
X # welcome first time users
X [ -r ${LOCAL}/etc/1stlogin.ann -a ! -f $HOME/... ] && \
X . ${LOCAL}/etc/1stlogin.ann
X # not all of the following are appropriate at all sites
X # Sun's don't need to cat /etc/motd for instance
X case "$OS" in
X SunOS) ;;
X SCO-UNIX)
X [ -s /etc/motd ] && cat /etc/motd
X [ -x /usr/bin/mail -a -s "$MAIL" ] &&
X echo "You have mail."
X [ -x /usr/bin/news ] && /usr/bin/news -n
X ;;
X *)
X [ -s /etc/motd ] && cat /etc/motd
X if [ -x /usr/bin/mailx ]; then
X if mailx -e; then
X echo "You have mail."
X # show the the headers, this might
X # be better done in .profile so they
X # can override it.
X# mailx -H
X fi
X fi
X [ -x /usr/bin/news ] && /usr/bin/news -n
X ;;
X esac
X [ -x /usr/games/fortune ] && /usr/games/fortune -a
X # remind folk who turned on reply.pl to turn it off.
X if [ -f $HOME/.forward ]; then
X echo "Your mail is being forwarded to:"
X cat $HOME/.forward
X if [ -f $HOME/.recording ]; then
X echo "Perhaps you should run \"reply.pl off\""
X fi
X fi
X fi
X unset tmpterm defterm C N
X TERM=${TERM:-unknown}
X export TERM TTY
X;;
Xesac
X# Handle X-terminals if necessary
X[ -f /etc/profile.X11 ] && . /etc/profile.X11
END_OF_FILE
if test 5445 -ne `wc -c <'etc/profile'`; then
echo shar: \"'etc/profile'\" unpacked with wrong size!
fi
# end of 'etc/profile'
fi
if test -f 'sh/exec.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'sh/exec.c'\"
else
echo shar: Extracting \"'sh/exec.c'\" \(14925 characters\)
sed "s/^X//" >'sh/exec.c' <<'END_OF_FILE'
X/*
X * execute command tree
X */
X
X#ifndef lint
Xstatic char *RCSid = "$Id: exec.c,v 3.4 89/03/27 15:50:10 egisin Exp $";
Xstatic char *sccs_id = "@(#)exec.c 1.3 91/11/09 15:35:22 (sjg)";
X#endif
X
X#include <stddef.h>
X#include <stdio.h>
X#include <string.h>
X#include <errno.h>
X#include <signal.h>
X#include <setjmp.h>
X#include <unistd.h>
X#include <fcntl.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "sh.h"
X#include "lex.h"
X#include "tree.h"
X#include "table.h"
X
Xstatic int comexec ARGS((struct op *t, char **vp, char **ap, int flags));
Xstatic void iosetup ARGS((struct ioword *iop));
Xstatic void echo ARGS((char **, char **));
Xstatic int herein ARGS((char *name, int sub));
X#ifdef SHARPBANG
Xstatic void scriptexec ARGS((struct op *t, char **ap));
X#endif
X
X/*
X * execute command tree
X */
Xint
Xexecute(t, flags)
X register struct op *t;
X Volatile int flags; /* if XEXEC don't fork */
X{
X int i;
X int Volatile rv = 0;
X int pv[2];
X register char **ap;
X char *s, *cp;
X struct ioword **iowp;
X
X if (t == NULL)
X return 0;
X
X if ((flags&XFORK) && !(flags&XEXEC) && t->type != TPIPE)
X return exchild(t, flags); /* run in sub-process */
X
X newenv(E_EXEC);
X if (trap)
X runtraps();
X
X if (t->ioact != NULL || t->type == TPIPE) {
X e.savefd = (short*) alloc(sizeofN(short, NUFILE), ATEMP);
X for (i = 0; i < NUFILE; i++)
X e.savefd[i] = 0; /* not redirected */
X /* mark fd 0/1 in-use if pipeline */
X if (flags&XPIPEI)
X e.savefd[0] = -1;
X if (flags&XPIPEO)
X e.savefd[1] = -1;
X }
X
X /* do redirection, to be restored in quitenv() */
X if (t->ioact != NULL)
X for (iowp = t->ioact; *iowp != NULL; iowp++)
X iosetup(*iowp);
X
X switch(t->type) {
X case TCOM:
X e.type = E_TCOM;
X rv = comexec(t, eval(t->vars, DOTILDE),
X eval(t->args, DOBLANK|DOGLOB|DOTILDE), flags);
X break;
X
X case TPAREN:
X exstat = rv = execute(t->left, flags|XFORK);
X break;
X
X case TPIPE:
X flags |= XFORK;
X flags &= ~XEXEC;
X e.savefd[0] = savefd(0);
X e.savefd[1] = savefd(1);
X flags |= XPIPEO;
X (void) dup2(e.savefd[0], 0); /* stdin of first */
X while (t->type == TPIPE) {
X openpipe(pv);
X (void) dup2(pv[1], 1); /* stdout of curr */
X exchild(t->left, flags);
X (void) dup2(pv[0], 0); /* stdin of next */
X closepipe(pv);
X flags |= XPIPEI;
X t = t->right;
X }
X flags &= ~ XPIPEO;
X (void) dup2(e.savefd[1], 1); /* stdout of last */
X exchild(t, flags);
X (void) dup2(e.savefd[0], 0); /* close pipe in */
X if (!(flags&XBGND))
X exstat = rv = waitlast();
X break;
X
X case TLIST:
X while (t->type == TLIST) {
X execute(t->left, 0);
X t = t->right;
X }
X rv = execute(t, 0);
X break;
X
X case TASYNC:
X rv = execute(t->left, flags|XBGND|XFORK);
X break;
X
X case TOR:
X case TAND:
X rv = execute(t->left, 0);
X if (t->right != NULL && (rv == 0) == (t->type == TAND))
X rv = execute(t->right, 0);
X break;
X
X case TFOR:
X e.type = E_LOOP;
X ap = (t->vars != NULL) ?
X eval(t->vars, DOBLANK|DOGLOB|DOTILDE) : e.loc->argv + 1;
X while ((i = setjmp(e.jbuf)))
X if (i == LBREAK)
X goto Break1;
X while (*ap != NULL) {
X setstr(global(t->str), *ap++);
X rv = execute(t->left, 0);
X }
X Break1:
X break;
X
X case TWHILE:
X case TUNTIL:
X e.type = E_LOOP;
X while ((i = setjmp(e.jbuf)))
X if (i == LBREAK)
X goto Break2;
X while ((execute(t->left, 0) == 0) == (t->type == TWHILE))
X rv = execute(t->right, 0);
X Break2:
X break;
X
X case TIF:
X case TELIF:
X if (t->right == NULL)
X break; /* should be error */
X rv = execute(t->left, 0) == 0 ?
X execute(t->right->left, 0) :
X execute(t->right->right, 0);
X break;
X
X case TCASE:
X cp = evalstr(t->str, 0);
X for (t = t->left; t != NULL && t->type == TPAT; t = t->right)
X for (ap = t->vars; *ap; ap++)
X if ((s = evalstr(*ap, DOPAT)) && gmatch(cp, s))
X goto Found;
X break;
X Found:
X rv = execute(t->left, 0);
X break;
X
X case TBRACE:
X rv = execute(t->left, 0);
X break;
X
X case TFUNCT:
X rv = define(t->str, t->left);
X break;
X
X case TTIME:
X rv = timex(t, flags);
X break;
X
X case TEXEC: /* an eval'd TCOM */
X s = t->args[0];
X ap = makenv();
X#ifdef _MINIX /* no F_SETFD close-on-exec */
X for (i = 10; i < 20; i++)
X close(i);
X#endif
X execve(t->str, t->args, ap);
X if (errno == ENOEXEC) {
X char *shell;
X#ifdef SHARPBANG
X scriptexec(t, ap);
X#else
X shell = strval(global("EXECSHELL"));
X if (shell && *shell) {
X if ((shell = search(shell,path,1)) == NULL)
X shell = SHELL;
X } else {
X shell = SHELL;
X }
X *t->args-- = t->str;
X *t->args = shell;
X execve(t->args[0], t->args, ap);
X errorf("No shell\n");
X#endif /* SHARPBANG */
X }
X errorf("%s: %s\n", s, strerror(errno));
X }
X
X quitenv(); /* restores IO */
X if (e.interactive) { /* flush stdout, shlout */
X fflush(shf[1]);
X fflush(shf[2]);
X }
X if ((flags&XEXEC))
X exit(rv); /* exit child */
X return rv;
X}
X
X/*
X * execute simple command
X */
X
Xstatic int
Xcomexec(t, vp, ap, flags)
X struct op *t;
X register char **ap, **vp;
X int flags;
X{
X int i;
X int rv = 0;
X register char *cp;
X register char **lastp;
X register struct tbl *tp = NULL;
X register struct block *l;
X static struct op texec = {TEXEC};
X extern int c_exec(), c_builtin();
X
X if (flag[FXTRACE])
X echo(vp, ap);
X
X /* snag the last argument for $_ */
X if ((lastp = ap) && *lastp) {
X while (*++lastp)
X ;
X setstr(typeset("_",LOCAL,0),*--lastp);
X }
X
X /* create new variable/function block */
X l = (struct block*) alloc(sizeof(struct block), ATEMP);
X l->next = e.loc; e.loc = l;
X newblock();
X
X Doexec:
X if ((cp = *ap) == NULL)
X cp = ":";
X tp = findcom(cp, flag[FHASHALL]);
X
X switch (tp->type) {
X case CSHELL: /* shell built-in */
X while (tp->val.f == c_builtin) {
X if ((cp = *++ap) == NULL)
X break;
X tp = tsearch(&builtins, cp, hash(cp));
X if (tp == NULL)
X errorf("%s: not builtin\n", cp);
X }
X if (tp->val.f == c_exec) {
X if (*++ap == NULL) {
X e.savefd = NULL; /* don't restore redirection */
X break;
X }
X flags |= XEXEC;
X goto Doexec;
X }
X if ((tp->flag&TRACE))
X e.loc = l->next; /* no local block */
X i = (tp->flag&TRACE) ? 0 : LOCAL;
X while (*vp != NULL)
X (void) typeset(*vp++, i, 0);
X rv = (*tp->val.f)(ap);
X break;
X
X case CFUNC: /* function call */
X if (!(tp->flag&ISSET))
X errorf("%s: undefined function\n", cp);
X l->argv = ap;
X for (i = 0; *ap++ != NULL; i++)
X ;
X l->argc = i - 1;
X resetopts();
X while (*vp != NULL)
X (void) typeset(*vp++, LOCAL, 0);
X e.type = E_FUNC;
X if (setjmp(e.jbuf))
X rv = exstat; /* return # */
X else
X rv = execute(tp->val.t, 0);
X break;
X
X case CEXEC: /* executable command */
X if (!(tp->flag&ISSET)) {
X /*
X * mlj addition:
X *
X * If you specify a full path to a file
X * (or type the name of a file in .) which
X * doesn't have execute priv's, it used to
X * just say "not found". Kind of annoying,
X * particularly if you just wrote a script
X * but forgot to say chmod 755 script.
X *
X * This should probably be done in eaccess(),
X * but it works here (at least I haven't noticed
X * changing errno here breaking something
X * else).
X *
X * So, we assume that if the file exists, it
X * doesn't have execute privs; else, it really
X * is not found.
X */
X if (access(cp, 0) < 0)
X shellf("%s: not found\n", cp);
X else
X shellf("%s: cannot execute\n", cp);
X rv = 1;
X break;
X }
X
X /* set $_ to program's full path */
X setstr(typeset("_", LOCAL|EXPORT, 0), tp->val.s);
X while (*vp != NULL)
X (void) typeset(*vp++, LOCAL|EXPORT, 0);
X
X if ((flags&XEXEC)) {
X j_exit();
X if (flag[FMONITOR] || !(flags&XBGND)) {
X signal(SIGINT, SIG_DFL);
X signal(SIGQUIT, SIG_DFL);
X }
X }
X
X /* to fork we set up a TEXEC node and call execute */
X texec.left = t; /* for tprint */
X texec.str = tp->val.s;
X texec.args = ap;
X rv = exchild(&texec, flags);
X break;
X }
X if (rv != 0 && flag[FERREXIT])
X leave(rv);
X return (exstat = rv);
X}
X
X#ifdef SHARPBANG
Xstatic void
Xscriptexec(tp, ap)
X register struct op *tp;
X register char **ap;
X{
X char line[LINE];
X register char *cp;
X register int fd, n;
X char *shell;
X
X shell = strval(global("EXECSHELL"));
X if (shell && *shell) {
X if ((shell = search(shell,path,1)) == NULL)
X shell = SHELL;
X } else {
X shell = SHELL;
X }
X
X *tp->args-- = tp->str;
X line[0] = '\0';
X if ((fd = open(tp->str,0)) >= 0) {
X if ((n = read(fd, line, LINE - 1)) > 0)
X line[n] = '\0';
X (void) close(fd);
X }
X if (line[0] == '#' && line[1] == '!') {
X cp = &line[2];
X while (*cp && (*cp == ' ' || *cp == '\t'))
X cp++;
X if (*cp && *cp != '\n') {
X *tp->args = cp;
X while (*cp && *cp != '\n' && *cp != ' ' && *cp != '\t')
X cp++;
X if (*cp && *cp != '\n') {
X *cp++ = '\0';
X while (*cp && (*cp == ' ' || *cp == '\t'))
X cp++;
X if (*cp && *cp != '\n') {
X tp->args--;
X tp->args[0] = tp->args[1];
X tp->args[1] = cp;
X while (*cp && *cp != '\n' &&
X *cp != ' ' && *cp != '\t')
X cp++;
X }
X }
X *cp = '\0';
X } else
X *tp->args = shell;
X } else
X *tp->args = shell;
X
X (void) execve(tp->args[0], tp->args, ap);
X errorf( "No shell\n" );
X}
X#endif /* SHARPBANG */
X
Xint
Xshcomexec(wp)
X register char **wp;
X{
X register struct tbl *tp;
X
X tp = tsearch(&builtins, *wp, hash(*wp));
X if (tp == NULL)
X errorf("%s: shcomexec botch\n", *wp);
X return (*tp->val.f)(wp);
X}
X
X/*
X * define function
X */
Xint
Xdefine(name, t)
X char *name;
X struct op *t;
X{
X register struct block *l;
X register struct tbl *tp;
X
X for (l = e.loc; l != NULL; l = l->next) {
X lastarea = &l->area;
X tp = tsearch(&l->funs, name, hash(name));
X if (tp != NULL && (tp->flag&DEFINED))
X break;
X if (l->next == NULL) {
X tp = tenter(&l->funs, name, hash(name));
X tp->flag = DEFINED|FUNCT;
X tp->type = CFUNC;
X }
X }
X
X if ((tp->flag&ALLOC))
X tfree(tp->val.t, lastarea);
X tp->flag &= ~(ISSET|ALLOC);
X
X if (t == NULL) { /* undefine */
X tdelete(tp);
X return 0;
X }
X
X tp->val.t = tcopy(t, lastarea);
X tp->flag |= (ISSET|ALLOC);
X
X return 0;
X}
X
X/*
X * add builtin
X */
Xbuiltin(name, func)
X char *name;
X int (*func)();
X{
X register struct tbl *tp;
X int flag = DEFINED;
X
X if (*name == '=') { /* sets keyword variables */
X name++;
X flag |= TRACE; /* command does variable assignment */
X }
X
X tp = tenter(&builtins, name, hash(name));
X tp->flag |= flag;
X tp->type = CSHELL;
X tp->val.f = func;
X}
X
X/*
X * find command
X * either function, hashed command, or built-in (in that order)
X */
Xstruct tbl *
Xfindcom(name, insert)
X char *name;
X int insert; /* insert if not found */
X{
X register struct block *l = e.loc;
X unsigned int h = hash(name);
X register struct tbl *tp = NULL;
X static struct tbl temp;
X
X if (strchr(name, '/') != NULL) {
X tp = &temp;
X tp->type = CEXEC;
X tp->flag = 0; /* make ~ISSET */
X goto Search;
X }
X for (l = e.loc; l != NULL; l = l->next) {
X tp = tsearch(&l->funs, name, h);
X if (tp != NULL && (tp->flag&DEFINED))
X break;
X }
X if (tp == NULL) {
X tp = tsearch(&commands, name, h);
X if (tp != NULL && eaccess(tp->val.s,1) != 0) {
X if (tp->flag&ALLOC)
X afree(tp->val.s, commands.areap);
X tp->type = CEXEC;
X tp->flag = DEFINED;
X }
X }
X if (tp == NULL)
X tp = tsearch(&builtins, name, h);
X if (tp == NULL) {
X tp = tenter(&commands, name, h);
X tp->type = CEXEC;
X tp->flag = DEFINED;
X }
X Search:
X if (tp->type == CEXEC && !(tp->flag&ISSET)) {
X if (!insert) {
X tp = &temp;
X tp->type = CEXEC;
X tp->flag = 0; /* make ~ISSET */
X }
X name = search(name, path, 1);
X if (name != NULL) {
X tp->val.s = strsave(name,
X (tp == &temp) ? ATEMP : APERM);
X tp->flag |= ISSET|ALLOC;
X }
X }
X return tp;
X}
X
X/*
X * flush executable commands with relative paths
X */
Xflushcom(all)
X int all; /* just relative or all */
X{
X register struct tbl *tp;
X
X for (twalk(&commands); (tp = tnext()) != NULL; )
X if ((tp->flag&ISSET) && (all || tp->val.s[0] != '/')) {
X if ((tp->flag&ALLOC))
X afree(tp->val.s, commands.areap);
X tp->flag = DEFINED; /* make ~ISSET */
X }
X}
X
X/*
X * search for command with PATH
X */
Xchar *
Xsearch(name, path, mode)
X char *name, *path;
X int mode; /* 0: readable; 1: executable */
X{
X register int i;
X register char *sp, *tp;
X struct stat buf;
X
X if (strchr(name, '/'))
X return (eaccess(name, mode) == 0) ? name : NULL;
X
X sp = path;
X while (sp != NULL) {
X tp = line;
X for (; *sp != '\0'; tp++)
X if ((*tp = *sp++) == ':') {
X --sp;
X break;
X }
X if (tp != line)
X *tp++ = '/';
X for (i = 0; (*tp++ = name[i++]) != '\0';)
X ;
X i = eaccess(line, mode);
X if (i == 0 && (mode != 1 || stat(line,&buf) == 0 &&
X (buf.st_mode & S_IFMT) == S_IFREG))
X return line;
X /* what should we do about EACCES? */
X if (*sp++ == '\0')
X sp = NULL;
X }
X return NULL;
X}
X
X/*
X * set up redirection, saving old fd's in e.savefd
X */
Xstatic void
Xiosetup(iop)
X register struct ioword *iop;
X{
X register int u = -1;
X char *cp = iop->name;
X extern long lseek();
X
X if (iop->unit == 0 || iop->unit == 1 || iop->unit == 2)
X e.interactive = 0;
X#if 0
X if (e.savefd[iop->unit] != 0)
X errorf("file descriptor %d already redirected\n", iop->unit);
X#endif
X e.savefd[iop->unit] = savefd(iop->unit);
X
X if ((iop->flag&IOTYPE) != IOHERE)
X cp = evalstr(cp, DOTILDE);
X
X switch (iop->flag&IOTYPE) {
X case IOREAD:
X u = open(cp, 0);
X break;
X
X case IOCAT:
X if ((u = open(cp, 1)) >= 0) {
X (void) lseek(u, (long)0, 2);
X break;
X }
X /* FALLTHROUGH */
X case IOWRITE:
X u = creat(cp, 0666);
X break;
X
X case IORDWR:
X u = open(cp, 2);
X break;
X
X case IOHERE:
X u = herein(cp, iop->flag&IOEVAL);
X /* cp may have wrong name */
X break;
X
X case IODUP:
X if (*cp == '-')
X close(u = iop->unit);
X else
X if (digit(*cp))
X u = *cp - '0';
X else
X errorf("%s: illegal >& argument\n", cp);
X break;
X }
X if (u < 0)
X errorf("%s: cannot %s\n", cp,
X (iop->flag&IOTYPE) == IOWRITE ? "create" : "open");
X if (u != iop->unit) {
X (void) dup2(u, iop->unit);
X if (iop->flag != IODUP)
X close(u);
X }
X
X fopenshf(iop->unit);
X}
X
X/*
X * open here document temp file.
X * if unquoted here, expand here temp file into second temp file.
X */
Xstatic int
Xherein(hname, sub)
X char *hname;
X int sub;
X{
X int fd;
X FILE * Volatile f = NULL;
X
X f = fopen(hname, "r");
X if (f == NULL)
X return -1;
X setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
X
X if (sub) {
X char *cp;
X struct source *s;
X struct temp *h;
X
X newenv(E_ERRH);
X if (setjmp(e.jbuf)) {
X if (f != NULL)
X fclose(f);
X quitenv();
X return -1; /* todo: error()? */
X }
X
X /* set up yylex input from here file */
X s = pushs(SFILE);
X s->u.file = f;
X source = s;
X if (yylex(ONEWORD) != LWORD)
X errorf("exec:herein error\n");
X cp = evalstr(yylval.cp, 0);
X
X /* write expanded input to another temp file */
X h = maketemp(ATEMP);
X h->next = e.temps; e.temps = h;
X if (h == NULL)
X error();
X f = fopen(h->name, "w+");
X if (f == NULL)
X error();
X setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
X fputs(cp, f);
X rewind(f);
X
X quitenv();
X }
X fd = dup(fileno(f));
X fclose(f);
X return fd;
X}
X
Xstatic void
Xecho(vp, ap)
X register char **vp, **ap;
X{
X shellf("+");
X while (*vp != NULL)
X shellf(" %s", *vp++);
X while (*ap != NULL)
X shellf(" %s", *ap++);
X shellf("\n");
X}
X
END_OF_FILE
if test 14925 -ne `wc -c <'sh/exec.c'`; then
echo shar: \"'sh/exec.c'\" unpacked with wrong size!
fi
# end of 'sh/exec.c'
fi
if test -f 'sh/vi.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'sh/vi.c'\"
else
echo shar: Extracting \"'sh/vi.c'\" \(30485 characters\)
sed "s/^X//" >'sh/vi.c' <<'END_OF_FILE'
X/*
X * vi command editing
X * written by John Rochester (initially for nsh)
X * bludgeoned to fit PD ksh by Larry Bouzane and Eric Gisin
X * Further hacked (bugfixes and tweaks) by Mike Jetzer
X */
X
X#include "config.h"
X#ifdef VI
X
X#ifndef lint
Xstatic char *RCSid = "$Id: vi.c,v 3.1 89/01/28 15:29:20 egisin Exp $";
Xstatic char *sccs_id = "@(#)vi.c 1.3 91/11/09 15:35:09 (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 <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 CMDLEN 256
X#define Ctrl(c) (c&0x1f)
X#define bcopy(src, dst, len) memmove(dst, src, len)
Xextern int histN();
X
Xstatic int nextstate();
Xstatic int vi_insert();
Xstatic int vi_cmd();
Xstatic int domove();
Xstatic int redo_insert();
Xstatic yank_range();
Xstatic int bracktype();
Xstatic edit_prompt();
Xstatic edit_reset();
Xstatic int putbuf();
Xstatic stripblanks();
Xstatic del_range();
Xstatic int findch();
Xstatic int forwword();
Xstatic int backword();
Xstatic int endword();
Xstatic int Forwword();
Xstatic int Backword();
Xstatic int Endword();
Xstatic int grabhist();
Xstatic int grabsearch();
Xstatic redraw_line();
Xstatic refresh();
Xstatic int outofwin();
Xstatic rewindow();
Xstatic int newcol();
Xstatic display();
Xstatic ed_mov_opt();
X
X#define C_ 0x1
X#define M_ 0x2
X#define E_ 0x4
X#define X_ 0x8
X#define U_ 0x10
X#define B_ 0x20
X#define O_ 0x40
X#define S_ 0x80
X
X#define isbad(c) (classify[c]&B_)
X#define iscmd(c) (classify[c]&(M_|E_|C_|U_))
X#define ismove(c) (classify[c]&M_)
X#define isextend(c) (classify[c]&E_)
X#define islong(c) (classify[c]&X_)
X#define ismeta(c) (classify[c]&O_)
X#define isundoable(c) (!(classify[c]&U_))
X#define issrch(c) (classify[c]&S_)
X
Xchar classify[128] = {
X B_, 0, 0, 0, 0, 0, O_, 0,
X#if 1 /* Mike B. changes */
X C_|M_, 0, O_, 0, O_, O_, O_, 0,
X#else
X C_, 0, O_, 0, O_, O_, O_, 0,
X#endif
X O_, 0, C_|U_, 0, 0, 0, 0, 0,
X 0, 0, O_, 0, 0, 0, 0, 0,
X#if 1 /* Mike B. changes */
X C_|M_, 0, 0, C_, M_, C_, 0, 0,
X#else
X C_, 0, 0, C_, M_, C_, 0, 0,
X#endif
X 0, 0, C_, C_, M_, C_, 0, C_|S_,
X M_, 0, 0, 0, 0, 0, 0, 0,
X 0, 0, 0, M_, 0, 0, 0, C_|S_,
X 0, C_, M_, C_, C_, M_, M_|X_, C_,
X 0, C_, 0, 0, 0, 0, C_, 0,
X C_, 0, C_, C_, M_|X_, 0, 0, M_,
X C_, C_, 0, 0, 0, 0, M_, C_,
X 0, C_, M_, E_, E_, M_, M_|X_, 0,
X M_, C_, C_, C_, M_, 0, C_, 0,
X C_, 0, C_, C_, M_|X_, C_|U_, 0, M_,
X C_, E_, 0, 0, 0, 0, C_, 0
X};
X
X#define MAXVICMD 3
X#define SRCHLEN 40
X
X#define INSERT 1
X#define REPLACE 2
X
X#define VNORMAL 0
X#define VARG1 1
X#define VEXTCMD 2
X#define VARG2 3
X#define VXCH 4
X#define VFAIL 5
X#define VCMD 6
X#define VREDO 7
X#define VLIT 8
X#define VSEARCH 9
X#define VREPLACE1CHAR 10
X
Xstruct edstate {
X int winleft;
X char *cbuf;
X int cbufsize;
X int linelen;
X int cursor;
X};
X
Xstatic char undocbuf[CMDLEN];
X
Xstatic struct edstate ebuf;
Xstatic struct edstate undobuf = { 0, undocbuf, CMDLEN, 0, 0 };
X
Xstatic struct edstate *es; /* current editor state */
Xstatic struct edstate *undo;
X
Xstatic char ibuf[CMDLEN]; /* input buffer */
Xstatic int inslen; /* length of input buffer */
Xstatic int srchlen; /* length of current search pattern */
Xstatic char ybuf[CMDLEN]; /* yank buffer */
Xstatic int yanklen; /* length of yank buffer */
Xstatic int fsavecmd = ' '; /* last find command */
Xstatic int fsavech; /* character to find */
Xstatic char lastcmd[MAXVICMD]; /* last non-move command */
Xstatic int lastac; /* argcnt for lastcmd */
Xstatic int lastsearch = ' '; /* last search command */
Xstatic char srchpat[SRCHLEN]; /* last search pattern */
Xstatic int insert; /* non-zero in insert mode */
Xstatic int hnum; /* position in history */
Xstatic int hlast; /* 1 past last position in history */
Xstatic int modified; /* buffer has been "modified" */
Xstatic int state;
X
X#if 0
Xvi_init()
X{
X es = (struct edstate *) malloc((unsigned) sizeof(struct edstate));
X fsavecmd = ' ';
X lastsearch = ' ';
X}
X
Xedit_init()
X{
X wbuf[0] = malloc((unsigned) (x_cols - 3));
X wbuf[1] = malloc((unsigned) (x_cols - 3));
X}
X#endif
X
Xvoid
Xvi_reset(buf, len)
X char *buf;
X int len;
X{
X state = VNORMAL;
X hnum = hlast = histnum(-1) + 1;
X insert = INSERT;
X yanklen = 0;
X inslen = 0;
X lastcmd[0] = 'a';
X lastac = 1;
X modified = 1;
X edit_reset(buf, len);
X}
X
Xint
Xvi_hook(ch)
X int ch;
X{
X static char curcmd[MAXVICMD];
X static char locpat[SRCHLEN];
X static int cmdlen;
X static int argc1, argc2;
X int i;
X
X if (state != VSEARCH && (ch == '\r' || ch == '\n')) {
X x_putc('\r');
X x_putc('\n');
X x_flush();
X return 1;
X }
X
X switch (state) {
X
X case VREPLACE1CHAR:
X curcmd[cmdlen++] = ch;
X state = VCMD;
X break;
X
X case VNORMAL:
X if (insert != 0) {
X if (ch == Ctrl('v')) {
X state = VLIT;
X ch = '^';
X }
X if (vi_insert(ch) != 0) {
X x_putc(Ctrl('g'));
X state = VNORMAL;
X } else {
X if (state == VLIT) {
X es->cursor--;
X refresh(0);
X } else
X refresh(insert != 0);
X }
X } else {
X cmdlen = 0;
X argc1 = 0;
X if (ch >= '1' && ch <= '9') {
X argc1 = ch - '0';
X state = VARG1;
X } else {
X curcmd[cmdlen++] = ch;
X state = nextstate(ch);
X if (state == VSEARCH) {
X save_cbuf();
X es->cursor = 0;
X es->linelen = 0;
X if (ch == '/') {
X if (putbuf("/", 1, 0) != 0) {
X return -1;
X }
X } else if (putbuf("?", 1, 0) != 0)
X return -1;
X refresh(0);
X }
X }
X }
X break;
X
X case VLIT:
X if (isbad(ch)) {
X del_range(es->cursor, es->cursor + 1);
X x_putc(Ctrl('g'));
X } else
X es->cbuf[es->cursor++] = ch;
X refresh(1);
X state = VNORMAL;
X break;
X
X case VARG1:
X if (isdigit(ch))
X argc1 = argc1 * 10 + ch - '0';
X else {
X curcmd[cmdlen++] = ch;
X state = nextstate(ch);
X }
X break;
X
X case VEXTCMD:
X argc2 = 0;
X if (ch >= '1' && ch <= '9') {
X argc2 = ch - '0';
X state = VARG2;
X return 0;
X } else {
X curcmd[cmdlen++] = ch;
X if (ch == curcmd[0])
X state = VCMD;
X else if (ismove(ch))
X state = nextstate(ch);
X else
X state = VFAIL;
X }
X break;
X
X case VARG2:
X if (isdigit(ch))
X argc2 = argc2 * 10 + ch - '0';
X else {
X if (argc1 == 0)
X argc1 = argc2;
X else
X argc1 *= argc2;
X curcmd[cmdlen++] = ch;
X if (ch == curcmd[0])
X state = VCMD;
X else if (ismove(ch))
X state = nextstate(ch);
X else
X state = VFAIL;
X }
X break;
X
X case VXCH:
X if (ch == Ctrl('['))
X state = VNORMAL;
X else {
X curcmd[cmdlen++] = ch;
X state = VCMD;
X }
X break;
X
X case VSEARCH:
X switch (ch) {
X
X /* case Ctrl('['): */
X case '\r':
X case '\n':
X locpat[srchlen] = '\0';
X (void) strcpy(srchpat, locpat);
X /* redraw_line(); */
X state = VCMD;
X break;
X
X case 0x7f:
X if (srchlen == 0) {
X restore_cbuf();
X state = VNORMAL;
X } else {
X srchlen--;
X if (locpat[srchlen] < ' ' ||
X locpat[srchlen] == 0x7f) {
X es->linelen--;
X }
X es->linelen--;
X es->cursor = es->linelen;
X refresh(0);
X return 0;
X }
X refresh(0);
X break;
X
X case Ctrl('u'):
X srchlen = 0;
X es->linelen = 1;
X es->cursor = 1;
X refresh(0);
X return 0;
X
X default:
X if (srchlen == SRCHLEN - 1)
X x_putc(Ctrl('g'));
X else {
X locpat[srchlen++] = ch;
X if (ch < ' ' || ch == 0x7f) {
X es->cbuf[es->linelen++] = '^';
X es->cbuf[es->linelen++] = ch ^ '@';
X } else
X es->cbuf[es->linelen++] = ch;
X es->cursor = es->linelen;
X refresh(0);
X }
X return 0;
X break;
X }
X break;
X }
X switch (state) {
X
X case VCMD:
X state = VNORMAL;
X switch (vi_cmd(argc1, curcmd)) {
X case -1:
X x_putc(Ctrl('g'));
X break;
X case 0:
X if (insert != 0)
X inslen = 0;
X refresh(insert != 0);
X break;
X case 1:
X refresh(0);
X x_putc('\r');
X x_putc('\n');
X x_flush();
X return 1;
X }
X break;
X
X case VREDO:
X state = VNORMAL;
X if (argc1 != 0)
X lastac = argc1;
X switch (vi_cmd(lastac, lastcmd) != 0) {
X case -1:
X x_putc(Ctrl('g'));
X refresh(0);
X break;
X case 0:
X if (insert != 0) {
X if (lastcmd[0] == 's' || lastcmd[0] == 'c' ||
X lastcmd[0] == 'C') {
X if (redo_insert(1) != 0)
X x_putc(Ctrl('g'));
X } else {
X if (redo_insert(lastac) != 0)
X x_putc(Ctrl('g'));
X }
X }
X refresh(0);
X break;
X case 1:
X refresh(0);
X x_putc('\r');
X x_putc('\n');
X x_flush();
X return 1;
X }
X break;
X
X case VFAIL:
X state = VNORMAL;
X x_putc(Ctrl('g'));
X break;
X }
X return 0;
X}
X
Xstatic int
Xnextstate(ch)
X int ch;
X{
X /*
X * probably could have been done more elegantly than
X * by creating a new state, but it works
X */
X if (ch == 'r')
X return VREPLACE1CHAR;
X else if (isextend(ch))
X return VEXTCMD;
X else if (issrch(ch))
X return VSEARCH;
X else if (islong(ch))
X return VXCH;
X else if (ch == '.')
X return VREDO;
X else if (iscmd(ch))
X return VCMD;
X else
X return VFAIL;
X}
X
Xstatic int
Xvi_insert(ch)
X int ch;
X{
X int tcursor;
X
X switch (ch) {
X
X case '\0':
X return -1;
X
X case Ctrl('['):
X if (lastcmd[0] == 's' || lastcmd[0] == 'c' ||
X lastcmd[0] == 'C')
X return redo_insert(0);
X else
X return redo_insert(lastac - 1);
X
X case 0x7f: /* delete */
X /* tmp fix */
X /* general fix is to get stty erase char and use that
X */
X case Ctrl('H'): /* delete */
X if (es->cursor != 0) {
X if (inslen > 0)
X inslen--;
X es->cursor--;
X if (insert != REPLACE) {
X bcopy(&es->cbuf[es->cursor+1],
X &es->cbuf[es->cursor],
X es->linelen - es->cursor);
X es->linelen--;
X }
X }
X break;
X
X case Ctrl('U'):
X if (es->cursor != 0) {
X inslen = 0;
X bcopy(&es->cbuf[es->cursor], es->cbuf,
X es->linelen - es->cursor);
X es->linelen -= es->cursor;
X es->cursor = 0;
X }
X break;
X
X case Ctrl('W'):
X if (es->cursor != 0) {
X tcursor = backword(1);
X bcopy(&es->cbuf[es->cursor], &es->cbuf[tcursor],
X es->linelen - es->cursor);
X es->linelen -= es->cursor - tcursor;
X if (inslen < es->cursor - tcursor)
X inslen = 0;
X else
X inslen -= es->cursor - tcursor;
X es->cursor = tcursor;
X }
X break;
X
X default:
X if (es->linelen == es->cbufsize - 1)
X return -1;
X ibuf[inslen++] = ch;
X if (insert == INSERT) {
X bcopy(&es->cbuf[es->cursor], &es->cbuf[es->cursor+1],
X es->linelen - es->cursor);
X es->linelen++;
X }
X es->cbuf[es->cursor++] = ch;
X if (insert == REPLACE && es->cursor > es->linelen)
X es->linelen++;
X }
X return 0;
X}
X
Xstatic int
Xvi_cmd(argcnt, cmd)
X int argcnt;
X char *cmd;
X{
X int ncursor;
X int cur, c1, c2, c3 = 0;
X char pos[10];
X struct edstate *t;
X
X
X if (argcnt == 0) {
X if (*cmd == 'G')
X argcnt = hlast + 1;
X else if (*cmd != '_')
X argcnt = 1;
X }
X
X if (ismove(*cmd)) {
X if ((cur = domove(argcnt, cmd, 0)) >= 0) {
X if (cur == es->linelen && cur != 0)
X cur--;
X es->cursor = cur;
X } else
X return -1;
X } else {
X if (isundoable(*cmd)) {
X undo->winleft = es->winleft;
X bcopy(es->cbuf, undo->cbuf, es->linelen);
X undo->linelen = es->linelen;
X undo->cursor = es->cursor;
X lastac = argcnt;
X bcopy(cmd, lastcmd, MAXVICMD);
X }
X switch (*cmd) {
X
X case Ctrl('r'):
X redraw_line();
X break;
X
X case 'a':
X modified = 1;
X if (es->linelen != 0)
X es->cursor++;
X insert = INSERT;
X break;
X
X case 'A':
X modified = 1;
X del_range(0, 0);
X es->cursor = es->linelen;
X insert = INSERT;
X break;
X
X case 'c':
X case 'd':
X case 'y':
X if (*cmd == cmd[1]) {
X c1 = 0;
X c2 = es->linelen;
X } else if (!ismove(cmd[1]))
X return -1;
X else {
X if ((ncursor = domove(argcnt, &cmd[1], 1)) < 0)
X return -1;
X if (*cmd == 'c' &&
X (cmd[1]=='w' || cmd[1]=='W') &&
X !isspace(es->cbuf[es->cursor])) {
X while (isspace(es->cbuf[--ncursor]))
X ;
X ncursor++;
X }
X if (ncursor > es->cursor) {
X c1 = es->cursor;
X c2 = ncursor;
X } else {
X c1 = ncursor;
X c2 = es->cursor;
X }
X }
X if (*cmd != 'c' && c1 != c2)
X yank_range(c1, c2);
X if (*cmd != 'y') {
X del_range(c1, c2);
X es->cursor = c1;
X }
X if (*cmd == 'c') {
X modified = 1;
X insert = INSERT;
X }
X break;
X
X case 'p':
X modified = 1;
X if (es->linelen != 0)
X es->cursor++;
X while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0)
X ;
X if (es->cursor != 0)
X es->cursor--;
X if (argcnt != 0)
X return -1;
X break;
X
X case 'P':
X modified = 1;
X while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0)
X ;
X if (es->cursor != 0)
X es->cursor--;
X if (argcnt != 0)
X return -1;
X break;
X
X case 'C':
X modified = 1;
X del_range(es->cursor, es->linelen);
X insert = INSERT;
X break;
X
X case 'D':
X yank_range(es->cursor, es->linelen);
X del_range(es->cursor, es->linelen);
X if (es->cursor != 0)
X es->cursor--;
X break;
X
X case 'G':
X if (grabhist(modified, argcnt - 1) < 0)
X return -1;
X else {
X modified = 0;
X hnum = argcnt - 1;
X }
X break;
X
X case 'i':
X modified = 1;
X insert = INSERT;
X break;
X
X case 'I':
X modified = 1;
X es->cursor = 0;
X insert = INSERT;
X break;
X
X case '+':
X case 'j':
X if (grabhist(modified, hnum + argcnt) < 0)
X return -1;
X else {
X modified = 0;
X hnum += argcnt;
X }
X break;
X
X case '-':
X case 'k':
X if (grabhist(modified, hnum - argcnt) < 0)
X return -1;
X else {
X modified = 0;
X hnum -= argcnt;
X }
X break;
X
X case 'r':
X if (es->linelen == 0)
X return -1;
X modified = 1;
X es->cbuf[es->cursor] = cmd[1];
X break;
X
X case 'R':
X modified = 1;
X insert = REPLACE;
X break;
X
X case 's':
X if (es->linelen == 0)
X return -1;
X modified = 1;
X if (es->cursor + argcnt > es->linelen)
X argcnt = es->linelen - es->cursor;
X del_range(es->cursor, es->cursor + argcnt);
X insert = INSERT;
X break;
X
X case 'x':
X if (es->linelen == 0)
X return -1;
X modified = 1;
X if (es->cursor + argcnt > es->linelen)
X argcnt = es->linelen - es->cursor;
X yank_range(es->cursor, es->cursor + argcnt);
X del_range(es->cursor, es->cursor + argcnt);
X break;
X
X case 'X':
X if (es->cursor > 0) {
X modified = 1;
X if (es->cursor < argcnt)
X argcnt = es->cursor;
X yank_range(es->cursor - argcnt, es->cursor);
X del_range(es->cursor - argcnt, es->cursor);
X es->cursor -= argcnt;
X } else
X return -1;
X break;
X
X case 'u':
X t = es;
X es = undo;
X undo = t;
X break;
X
X case '?':
X hnum = -1;
X /* ahhhhhh... */
X case '/':
X c3 = 1;
X srchlen = 0;
X lastsearch = *cmd;
X /* fall through */
X case 'n':
X case 'N':
X if (lastsearch == ' ')
X return -1;
X if (lastsearch == '?')
X c1 = 1;
X else
X c1 = 0;
X if (*cmd == 'N')
X c1 = !c1;
X if ((c2 = grabsearch(modified, hnum,
X c1, srchpat)) < 0) {
X if (c3) {
X restore_cbuf();
X refresh(0);
X }
X return -1;
X } else {
X modified = 0;
X hnum = c2;
X }
X break;
X case '_': {
X int space;
X char *p, *sp;
X
X (void) histnum(-1);
X p = *histpos();
X#define issp(c) (isspace((c)) || (c) == '\n')
X if (argcnt) {
X while (*p && issp(*p))
X p++;
X while (*p && --argcnt) {
X while (*p && !issp(*p))
X p++;
X while (*p && issp(*p))
X p++;
X }
X if (!*p)
X return -1;
X sp = p;
X } else {
X sp = p;
X space = 0;
X while (*p) {
X if (issp(*p))
X space = 1;
X else if (space) {
X space = 0;
X sp = p;
X }
X p++;
X }
X p = sp;
X }
X modified = 1;
X if (es->linelen != 0)
X es->cursor++;
X while (*p && !issp(*p)) {
X argcnt++;
X p++;
X }
X if (putbuf(" ", 1, 0) != 0)
X argcnt = -1;
X else if (putbuf(sp, argcnt, 0) != 0)
X argcnt = -1;
X if (argcnt < 0) {
X if (es->cursor != 0)
X es->cursor--;
X return -1;
X }
X insert = INSERT;
X }
X break;
X
X case '~': {
X char *p;
X
X if (es->linelen == 0)
X return -1;
X p = &es->cbuf[es->cursor];
X if (islower(*p)) {
X modified = 1;
X *p = toupper(*p);
X } else if (isupper(*p)) {
X modified = 1;
X *p = tolower(*p);
X }
X if (es->cursor < es->linelen - 1)
X es->cursor++;
X }
X break;
X
X case '#':
X es->cursor = 0;
X if (putbuf("#", 1, 0) != 0)
X return -1;
X return 1;
X
X case '*': {
X int rval = 0;
X int start, end;
X char *toglob = undo->cbuf;
X char **ap;
X char **ap2;
X char **globstr();
X
X if (isspace(es->cbuf[es->cursor]))
X return -1;
X start = es->cursor;
X while (start > -1 && !isspace(es->cbuf[start]))
X start--;
X start++;
X end = es->cursor;
X while (end < es->linelen && !isspace(es->cbuf[end]))
X end++;
X /* use undo buffer to build word up in */
X bcopy(&es->cbuf[start], toglob, end-start);
X if (*toglob != '~' && toglob[end-start-1] != '*') {
X toglob[end-start] = '*';
X toglob[end-start+1] = '\0';
X } else
X toglob[end-start] = '\0';
X ap = globstr(toglob);
X ap2 = ap;
X if (strcmp(ap[0], toglob) == 0 && ap[1] == (char *) 0)
X rval = -1;
X /* restore undo buffer that we used temporarily */
X bcopy(es->cbuf, toglob, es->linelen);
X if (rval < 0)
X return rval;
X del_range(start, end);
X es->cursor = start;
X while (1) {
X if (putbuf(*ap, strlen(*ap), 0) != 0) {
X rval = -1;
X break;
X }
X if (*++ap == (char *) 0)
X break;
X if (putbuf(" ", 1, 0) != 0) {
X rval = -1;
X break;
X }
X }
X#if 0
X /*
X * this is definitely wrong
X */
X for (ap = ap2; *ap; ap++)
X free(*ap);
X
X free(ap2);
X#endif
X
X modified = 1;
X insert = INSERT;
X refresh(0);
X if (rval != 0)
X return rval;
X }
X break;
X }
X if (insert == 0 && es->cursor != 0 && es->cursor >= es->linelen)
X es->cursor--;
X }
X return 0;
X}
X
Xstatic int
Xdomove(argcnt, cmd, sub)
X int argcnt;
X char *cmd;
X int sub;
X{
X int bcount, i = 0, t; /* = 0 kludge for gcc -W */
X int ncursor = 0; /* = 0 kludge for gcc -W */
X
X switch (*cmd) {
X
X case 'b':
X if (!sub && es->cursor == 0)
X return -1;
X ncursor = backword(argcnt);
X break;
X
X case 'B':
X if (!sub && es->cursor == 0)
X return -1;
X ncursor = Backword(argcnt);
X break;
X
X case 'e':
X if (!sub && es->cursor + 1 >= es->linelen)
X return -1;
X ncursor = endword(argcnt);
X if (sub)
X ncursor++;
X break;
X
X case 'E':
X if (!sub && es->cursor + 1 >= es->linelen)
X return -1;
X ncursor = Endword(argcnt);
X if (sub)
X ncursor++;
X break;
X
X case 'f':
X case 'F':
X case 't':
X case 'T':
X fsavecmd = *cmd;
X fsavech = cmd[1];
X /* drop through */
X
X case ',':
X case ';':
X if (fsavecmd == ' ')
X return -1;
X i = fsavecmd == 'f' || fsavecmd == 'F';
X t = fsavecmd > 'a';
X if (*cmd == ',')
X t = !t;
X if ((ncursor = findch(fsavech, argcnt, t, i)) < 0)
X return -1;
X if (sub && t)
X ncursor++;
X break;
X
X case 'h':
X /* tmp fix */
X case Ctrl('H'):
X if (!sub && es->cursor == 0)
X return -1;
X ncursor = es->cursor - argcnt;
X if (ncursor < 0)
X ncursor = 0;
X break;
X
X case ' ':
X case 'l':
X if (!sub && es->cursor + 1 >= es->linelen)
X return -1;
X if (es->linelen != 0) {
X ncursor = es->cursor + argcnt;
X if (ncursor >= es->linelen)
X ncursor = es->linelen - 1;
X }
X break;
X
X case 'w':
X if (!sub && es->cursor + 1 >= es->linelen)
X return -1;
X ncursor = forwword(argcnt);
X break;
X
X case 'W':
X if (!sub && es->cursor + 1 >= es->linelen)
X return -1;
X ncursor = Forwword(argcnt);
X break;
X
X case '0':
X ncursor = 0;
X break;
X
X case '^':
X ncursor = 0;
X while (ncursor < es->linelen - 1 && isspace(es->cbuf[ncursor]))
X ncursor++;
X break;
X
X case '$':
X if (es->linelen != 0)
X ncursor = es->linelen;
X else
X ncursor = 0;
X break;
X
X case '%':
X ncursor = es->cursor;
X while (ncursor < es->linelen &&
X (i = bracktype(es->cbuf[ncursor])) == 0)
X ncursor++;
X if (ncursor == es->linelen)
X return -1;
X bcount = 1;
X do {
X if (i > 0) {
X if (++ncursor >= es->linelen)
X return -1;
X } else {
X if (--ncursor < 0)
X return -1;
X }
X t = bracktype(es->cbuf[ncursor]);
X if (t == i)
X bcount++;
X else if (t == -i)
X bcount--;
X } while (bcount != 0);
X if (sub)
X ncursor++;
X break;
X
X default:
X return -1;
X }
X return ncursor;
X}
X
Xstatic int
Xredo_insert(count)
X int count;
X{
X while (count-- > 0)
X if (putbuf(ibuf, inslen, insert==REPLACE) != 0)
X return -1;
X if (es->cursor > 0)
X es->cursor--;
X insert = 0;
X return 0;
X}
X
Xstatic
Xyank_range(a, b)
X int a, b;
X{
X yanklen = b - a;
X if (yanklen != 0)
X bcopy(&es->cbuf[a], ybuf, yanklen);
X}
X
Xstatic int
Xbracktype(ch)
X int ch;
X{
X switch (ch) {
X
X case '(':
X return 1;
X
X case '[':
X return 2;
X
X case '{':
X return 3;
X
X case ')':
X return -1;
X
X case ']':
X return -2;
X
X case '}':
X return -3;
X
X default:
X return 0;
X }
X}
X
X/*
X * Non user interface editor routines below here
X */
X
Xstatic int cur_col; /* current column on line */
Xstatic int pwidth; /* width of prompt */
Xstatic int winwidth; /* width of window */
X/*static char *wbuf[2]; /* window buffers */
Xstatic char wbuf[2][80-3]; /* window buffers */ /* TODO */
Xstatic int win; /* window buffer in use */
Xstatic char morec; /* more character at right of window */
Xstatic int lastref; /* argument to last refresh() */
Xstatic char holdbuf[CMDLEN]; /* place to hold last edit buffer */
Xstatic int holdlen; /* length of holdbuf */
X
Xsave_cbuf()
X{
X bcopy(es->cbuf, holdbuf, es->linelen);
X holdlen = es->linelen;
X holdbuf[holdlen] = '\0';
X}
X
Xrestore_cbuf()
X{
X es->cursor = 0;
X es->linelen = holdlen;
X bcopy(holdbuf, es->cbuf, holdlen);
X}
X
Xstatic
Xedit_reset(buf, len)
X char *buf;
X int len;
X{
X es = &ebuf;
X es->cbuf = buf;
X es->cbufsize = len;
X undo = &undobuf;
X undo->cbufsize = len;
X
X es->linelen = undo->linelen = 0;
X es->cursor = undo->cursor = 0;
X es->winleft = undo->winleft = 0;
X
X cur_col = pwidth = promptlen(prompt);
X winwidth = x_cols - pwidth - 3;
X x_putc('\r');
X x_flush();
X pprompt(prompt);
X /* docap(CLR_EOL, 0); */
X win = 0;
X morec = ' ';
X lastref = 1;
X}
X
Xstatic int
Xputbuf(buf, len, repl)
X char *buf;
X int len;
X int repl;
X{
X if (len == 0)
X return 0;
X if (repl) {
X if (es->cursor + len >= es->cbufsize - 1)
X return -1;
X if (es->cursor + len > es->linelen)
X es->linelen = es->cursor + len;
X } else {
X if (es->linelen + len >= es->cbufsize - 1)
X return -1;
X bcopy(&es->cbuf[es->cursor], &es->cbuf[es->cursor + len],
X es->linelen - es->cursor);
X es->linelen += len;
X }
X bcopy(buf, &es->cbuf[es->cursor], len);
X es->cursor += len;
X return 0;
X}
X
Xstatic
Xstripblanks()
X{
X int ncursor;
X
X ncursor = 0;
X while (ncursor < es->linelen && isspace(es->cbuf[ncursor]))
X ncursor++;
X del_range(0, ncursor);
X}
X
Xstatic
Xdel_range(a, b)
X int a, b;
X{
X if (es->linelen != b)
X bcopy(&es->cbuf[b], &es->cbuf[a], es->linelen - b);
X es->linelen -= b - a;
X}
X
Xstatic int
Xfindch(ch, cnt, forw, incl)
X int ch;
X int forw;
X int incl;
X{
X int ncursor;
X
X if (es->linelen == 0)
X return -1;
X ncursor = es->cursor;
X while (cnt--) {
X do {
X if (forw) {
X if (++ncursor == es->linelen)
X return -1;
X } else {
X if (--ncursor < 0)
X return -1;
X }
X } while (es->cbuf[ncursor] != ch);
X }
X if (!incl) {
X if (forw)
X ncursor--;
X else
X ncursor++;
X }
X return ncursor;
X}
X
X#define Isalnum(x) (isalnum(x) || (x == '_'))
Xstatic int
Xforwword(argcnt)
X int argcnt;
X{
X int ncursor;
X
X ncursor = es->cursor;
X while (ncursor < es->linelen && argcnt--) {
X if (Isalnum(es->cbuf[ncursor]))
X while (Isalnum(es->cbuf[ncursor]) &&
X ++ncursor < es->linelen)
X ;
X else if (!isspace(es->cbuf[ncursor]))
X while (!Isalnum(es->cbuf[ncursor]) &&
X !isspace(es->cbuf[ncursor]) &&
X ++ncursor < es->linelen)
X ;
X while (isspace(es->cbuf[ncursor]) && ++ncursor < es->linelen)
X ;
X }
X return ncursor;
X}
X
Xstatic int
Xbackword(argcnt)
X int argcnt;
X{
X int ncursor;
X
X ncursor = es->cursor;
X while (ncursor > 0 && argcnt--) {
X while (--ncursor > 0 && isspace(es->cbuf[ncursor]))
X ;
X if (ncursor > 0) {
X if (Isalnum(es->cbuf[ncursor]))
X while (--ncursor >= 0 &&
X Isalnum(es->cbuf[ncursor]))
X ;
X else
X while (--ncursor >= 0 &&
X !Isalnum(es->cbuf[ncursor]) &&
X !isspace(es->cbuf[ncursor]))
X ;
X ncursor++;
X }
X }
X return ncursor;
X}
X
Xstatic int
Xendword(argcnt)
X int argcnt;
X{
X int ncursor;
X
X ncursor = es->cursor;
X while (ncursor < es->linelen && argcnt--) {
X while (++ncursor < es->linelen - 1 &&
X isspace(es->cbuf[ncursor]))
X ;
X if (ncursor < es->linelen - 1) {
X if (Isalnum(es->cbuf[ncursor]))
X while (++ncursor < es->linelen &&
X Isalnum(es->cbuf[ncursor]))
X ;
X else
X while (++ncursor < es->linelen &&
X !Isalnum(es->cbuf[ncursor]) &&
X !isspace(es->cbuf[ncursor]))
X ;
X ncursor--;
X }
X }
X return ncursor;
X}
X
Xstatic int
XForwword(argcnt)
X int argcnt;
X{
X int ncursor;
X
X ncursor = es->cursor;
X while (ncursor < es->linelen && argcnt--) {
X while (!isspace(es->cbuf[ncursor]) && ++ncursor < es->linelen)
X ;
X while (isspace(es->cbuf[ncursor]) && ++ncursor < es->linelen)
X ;
X }
X return ncursor;
X}
X
Xstatic int
XBackword(argcnt)
X int argcnt;
X{
X int ncursor;
X
X ncursor = es->cursor;
X while (ncursor > 0 && argcnt--) {
X while (--ncursor >= 0 && isspace(es->cbuf[ncursor]))
X ;
X while (ncursor >= 0 && !isspace(es->cbuf[ncursor]))
X ncursor--;
X ncursor++;
X }
X return ncursor;
X}
X
Xstatic int
XEndword(argcnt)
X int argcnt;
X{
X int ncursor;
X
X ncursor = es->cursor;
X while (ncursor < es->linelen - 1 && argcnt--) {
X while (++ncursor < es->linelen - 1 &&
X isspace(es->cbuf[ncursor]))
X ;
X if (ncursor < es->linelen - 1) {
X while (++ncursor < es->linelen &&
X !isspace(es->cbuf[ncursor]))
X ;
X ncursor--;
X }
X }
X return ncursor;
X}
X
Xstatic int
Xgrabhist(save, n)
X int save;
X int n;
X{
X char *hptr;
X char pos[10];
X
X if (n < 0 || n > hlast)
X return -1;
X if (n == hlast) {
X restore_cbuf();
X return 0;
X }
X (void) histnum(n);
X if ((hptr = *histpos()) == NULL) {
X shellf("grabhist: bad history array\n");
X return -1;
X }
X if (save)
X save_cbuf();
X es->linelen = strlen(hptr);
X bcopy(hptr, es->cbuf, es->linelen);
X es->cursor = 0;
X return 0;
X}
X
Xstatic int
Xgrabsearch(save, start, fwd, pat)
X int save, start, fwd;
X char *pat;
X{
X char *hptr;
X
X if ((start == 0 && fwd == 0) || (start >= hlast - 1 && fwd == 1))
X return -1;
X if ((hptr = findhist(start, fwd, pat)) == NULL) {
X /* if (start != 0 && fwd && match(holdbuf, pat) >= 0) { */
X if (start != 0 && fwd && strcmp(holdbuf, pat) >= 0) {
X restore_cbuf();
X return 0;
X } else
X return -1;
X } else if (hptr == (char *)-1) {
X return -1;
X }
X if (save)
X save_cbuf();
X es->linelen = strlen(hptr);
X bcopy(hptr, es->cbuf, es->linelen);
X es->cursor = 0;
X return histN();
X}
X
Xstatic
Xredraw_line()
X{
X x_putc('\r');
X x_putc('\n');
X x_flush();
X pprompt(prompt);
X cur_col = 2;
X morec = ' ';
X}
X
Xstatic
Xrefresh(leftside)
X int leftside;
X{
X if (leftside < 0)
X leftside = lastref;
X else
X lastref = leftside;
X if (outofwin())
X rewindow();
X display(wbuf[1 - win], wbuf[win], leftside);
X win = 1 - win;
X}
X
Xstatic int
Xoutofwin()
X{
X int cur, col;
X
X if (es->cursor < es->winleft)
X return 1;
X col = 0;
X cur = es->winleft;
X while (cur < es->cursor)
X col = newcol(es->cbuf[cur++], col);
X if (col > winwidth)
X return 1;
X return 0;
X}
X
Xstatic
Xrewindow()
X{
X register int tcur, tcol;
X int holdcur1, holdcol1;
X int holdcur2, holdcol2;
X
X holdcur1 = holdcur2 = tcur = 0;
X holdcol1 = holdcol2 = tcol = 0;
X while (tcur < es->cursor) {
X if (tcol - holdcol2 > winwidth / 2) {
X holdcur1 = holdcur2;
X holdcol1 = holdcol2;
X holdcur2 = tcur;
X holdcol2 = tcol;
X }
X tcol = newcol(es->cbuf[tcur++], tcol);
X }
X while (tcol - holdcol1 > winwidth / 2)
X holdcol1 = newcol(es->cbuf[holdcur1++], holdcol1);
X es->winleft = holdcur1;
X}
X
Xstatic int
Xnewcol(ch, col)
X int ch, col;
X{
X if (ch < ' ' || ch == 0x7f) {
X if (ch == '\t')
X return (col | 7) + 1;
X else
X return col + 2;
X } else
X return col + 1;
X}
X
Xstatic
Xdisplay(wb1, wb2, leftside)
X char *wb1, *wb2;
X int leftside;
X{
X char *twb1, *twb2, mc;
X int cur, col, cnt;
X int ncol = 0; /* set to 0 kludge for gcc -W */
X int moreright;
X
X col = 0;
X cur = es->winleft;
X moreright = 0;
X twb1 = wb1;
X while (col < winwidth && cur < es->linelen) {
X if (cur == es->cursor && leftside)
X ncol = col + pwidth;
X if (es->cbuf[cur] < ' ' || es->cbuf[cur] == 0x7f) {
X if (es->cbuf[cur] == '\t') {
X do {
X *twb1++ = ' ';
X } while (++col < winwidth && (col & 7) != 0);
X } else {
X *twb1++ = '^';
X if (++col < winwidth) {
X *twb1++ = es->cbuf[cur] ^ '@';
X col++;
X }
X }
X } else {
X *twb1++ = es->cbuf[cur];
X col++;
X }
X if (cur == es->cursor && !leftside)
X ncol = col + pwidth - 1;
X cur++;
X }
X if (cur == es->cursor)
X ncol = col + pwidth;
X if (col < winwidth) {
X while (col < winwidth) {
X *twb1++ = ' ';
X col++;
X }
X } else
X moreright++;
X *twb1 = ' ';
X
X col = pwidth;
X cnt = winwidth;
X twb1 = wb1;
X twb2 = wb2;
X while (cnt--) {
X if (*twb1 != *twb2) {
X if (cur_col != col)
X ed_mov_opt(col, wb1);
X x_putc(*twb1);
X cur_col++;
X }
X twb1++;
X twb2++;
X col++;
X }
X if (es->winleft > 0 && moreright)
X mc = '+';
X else if (es->winleft > 0)
X mc = '<';
X else if (moreright)
X mc = '>';
X else
X mc = ' ';
X if (mc != morec) {
X ed_mov_opt(x_cols - 2, wb1);
X x_putc(mc);
X cur_col++;
X morec = mc;
X }
X#if 0
X /*
X * Hack to fix teh ^r redraw problem, but it redraws way too much.
X * Probably unacceptable at low baudrates. Someone please fix this
X */
X else
X {
X ed_mov_opt(x_cols - 2, wb1);
X }
X#endif
X if (cur_col != ncol)
X ed_mov_opt(ncol, wb1);
X}
X
Xstatic
Xed_mov_opt(col, wb)
X int col;
X char *wb;
X{
X if (col < cur_col) {
X if (col + 1 < cur_col - col) {
X x_putc('\r');
X x_flush();
X pprompt(prompt);
X cur_col = pwidth;
X while (cur_col++ < col)
X x_putc(*wb++);
X } else {
X while (cur_col-- > col)
X x_putc('\b');
X }
X } else {
X wb = &wb[cur_col - pwidth];
X while (cur_col++ < col)
X x_putc(*wb++);
X }
X cur_col = col;
X}
X
Xint
Xx_vi(buf, len)
X char *buf;
X size_t len;
X{
X int c;
X
X vi_reset(buf, len > CMDLEN ? CMDLEN : len);
X x_flush();
X while ((c = getch()) != -1) {
X if (vi_hook(c))
X break;
X x_flush();
X }
X
X if (c == -1)
X return -1;
X
X if (es->cbuf != buf) {
X bcopy(es->cbuf, buf, es->linelen);
X buf[es->linelen] = '\n';
X } else
X es->cbuf[es->linelen] = '\n';
X
X es->linelen++;
X return es->linelen;
X}
X
Xgetch()
X{
X char buf;
X
X if (read(ttyfd, &buf, 1) != 1)
X return -1;
X if ((buf & 0x7f) == Ctrl('c')) {
X /*
X * If you hit ctrl-c, the buffer was left in a
X * strange state; the next command typed was
X * mucked up. Doing all of this is probably
X * overkill, but it works most of the time.
X */
X memset(es->cbuf, 0, CMDLEN);
X es->winleft = 0;
X es->cbufsize = 0;
X es->linelen = 0;
X es->cursor = 0;
X
X memset(undo->cbuf, 0, CMDLEN);
X undo->winleft = 0;
X undo->cbufsize = 0;
X undo->linelen = 0;
X undo->cursor = 0;
X x_mode(FALSE);
X trapsig(SIGINT);
X } else if ((buf & 0x7f) == Ctrl('d'))
X return -1;
X return buf & 0x7f;
X}
X
X
Xchar **globstr(stuff)
Xchar *stuff;
X {
X char *vecp[2];
X
X vecp[0] = stuff;
X vecp[1] = NULL;
X return(eval(vecp, DOBLANK|DOGLOB|DOTILDE));
X }
X#endif /* ifdef VI */
END_OF_FILE
if test 30485 -ne `wc -c <'sh/vi.c'`; then
echo shar: \"'sh/vi.c'\" unpacked with wrong size!
fi
# end of 'sh/vi.c'
fi
echo shar: End of archive 3 \(of 9\).
cp /dev/null ark3isdone
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.