home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume25 / pdksh / part03 < prev    next >
Text File  |  1991-11-12  |  56KB  |  2,751 lines

  1. Newsgroups: comp.sources.misc
  2. From: sjg@zen.void.oz.au (Simon J. Gerraty)
  3. Subject:  v25i049:  pdksh - Public Domain Korn Shell, v4, Part03/09
  4. Message-ID: <1991Nov13.031054.15849@sparky.imd.sterling.com>
  5. X-Md4-Signature: 52c66eb39f12096edc2a8e55bd5d160e
  6. Date: Wed, 13 Nov 1991 03:10:54 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: sjg@zen.void.oz.au (Simon J. Gerraty)
  10. Posting-number: Volume 25, Issue 49
  11. Archive-name: pdksh/part03
  12. Environment: UNIX
  13.  
  14. #! /bin/sh
  15. # into a shell via "sh file" or similar.  To overwrite existing files,
  16. # type "sh file -c".
  17. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  18. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  19. # Contents:  etc/profile sh/exec.c sh/vi.c
  20. # Wrapped by kent@sparky on Tue Nov 12 20:44:32 1991
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. echo If this archive is complete, you will see the following message:
  23. echo '          "shar: End of archive 3 (of 9)."'
  24. if test -f 'etc/profile' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'etc/profile'\"
  26. else
  27.   echo shar: Extracting \"'etc/profile'\" \(5445 characters\)
  28.   sed "s/^X//" >'etc/profile' <<'END_OF_FILE'
  29. X:
  30. X# NAME:
  31. X#    profile - global initialization for sh,ksh
  32. X#
  33. X# DESCRIPTION:
  34. X#    This file is processed during login by /bin/sh
  35. X#    and /bin/ksh.  It is used to setup the default user
  36. X#    environment.  It is processed with root privs.
  37. X#
  38. X# SEE ALSO:
  39. X#    $HOME/.profile
  40. X#    /etc/ksh.kshrc
  41. X#
  42. X# AMENDED:
  43. X#    91/11/08 23:02:21 (sjg)
  44. X#
  45. X# RELEASED:
  46. X#    91/11/08 23:02:24 v2.7
  47. X#
  48. X# SCCSID:
  49. X#    @(#)profile 2.7 91/11/08 23:02:21 (sjg)
  50. X#
  51. X#    @(#)Copyright (c) 1991 Simon J. Gerraty
  52. X#
  53. X#    This file is provided in the hope that it will
  54. X#    be of use.  There is absolutely NO WARRANTY.
  55. X#    Permission to copy, redistribute or otherwise
  56. X#    use this file is hereby granted provided that 
  57. X#    the above copyright notice and this notice are
  58. X#    left intact. 
  59. X
  60. Xcase "$_INIT_" in
  61. X*env*) ;;
  62. X*)    # do these once
  63. X    _INIT_="$_INIT_"env
  64. X    export _INIT_
  65. X    # sys_config.sh should set ARCH,OS,C,N,HOSTNAME,uname
  66. X    # we use these in lots of scripts...
  67. X    [ -f /etc/sys_config.sh ] && . /etc/sys_config.sh
  68. X
  69. X    # pick one of the following for the default umask
  70. X    # umask 002    # relaxed    -rwxrwxr-x
  71. X    umask 022    # cautious    -rwxr-xr-x
  72. X    # umask 027    # uptight    -rwxr-x---
  73. X    # umask 077    # paranoid    -rwx------
  74. X    # you can override the default umask
  75. X    # for specific groups later...
  76. X
  77. X    if [ -d /local ]; then
  78. X        LOCAL=/local
  79. X    else
  80. X        LOCAL=/usr/local
  81. X    fi
  82. X
  83. X    # set system specific things,
  84. X    # eg. set PATH,MANPATH 
  85. X    # override default ulimit if desired.
  86. X    # defult ulmit is unlimited on SunOS
  87. X    # and 4Mb for most System V
  88. X    case $OS in
  89. X    SunOS)
  90. X        # On sun's /bin -> /usr/bin so leave it out!
  91. X        PATH=.:/usr/bin:/usr/ucb:/usr/5bin
  92. X        MANPATH=/usr/man
  93. X        defterm=vt220
  94. X        ;;
  95. X    SCO-UNIX)
  96. X        PATH=.:/bin:/usr/bin:/usr/lbin:/usr/dbin:/usr/ldbin
  97. X        MANPATH=/usr/man
  98. X        defterm=ansi
  99. X        ;;
  100. X    B.O.S.)
  101. X        PATH=.:/bin:/usr/bin
  102. X        if [ -d /usr/ucb ]; then
  103. X            PATH=$PATH:/usr/ucb
  104. X        fi
  105. X        MANPATH=/usr/catman
  106. X        defterm=vt220
  107. X        SRC_COMPAT=_SYSV
  108. X        export SRC_COMPAT
  109. X        ;;
  110. X    *)
  111. X        PATH=.:/bin:/usr/bin
  112. X        if [ -d /usr/ucb ]; then
  113. X            PATH=$PATH:/usr/ucb
  114. X        fi
  115. X        MANPATH=/usr/catman
  116. X        defterm=vt220
  117. X        ;;
  118. X    esac
  119. X    if [ -d ${LOCAL}/bin ]; then
  120. X        PATH=$PATH:${LOCAL}/bin
  121. X    fi
  122. X    if [ -d $HOME/bin -a "$HOME" != / ]; then
  123. X        PATH=$PATH:$HOME/bin
  124. X    fi
  125. X    if [ -d ${LOCAL}/man ]; then
  126. X        MANPATH=$MANPATH:${LOCAL}/man
  127. X    fi
  128. X    # make sure these are set at least once
  129. X    LOGNAME=${LOGNAME:-`logname`}
  130. X    USER=${USER:-$LOGNAME}
  131. X
  132. X    # this is adapted from my whoami.sh
  133. X    # we expect id to produce output like:
  134. X    # uid=100(sjg) gid=10(staff) groups=10(staff),...
  135. X    S='('
  136. X    E=')'
  137. X    GROUP=`id | cut -d= -f3 | \
  138. X        sed -e "s;^[^${S}][^${S}]*${S}\([^${E}][^${E}]*\)${E}.*$;\1;"`
  139. X
  140. X    # set some group specific defaults
  141. X    case "$GROUP" in
  142. X    staff)    # staff deal with things that non-staff 
  143. X        # have no business looking at
  144. X        umask 027
  145. X        ;;
  146. X    extern)    # we put external accounts in group "extern"
  147. X        # give them as much privacy as we can...
  148. X        umask 077
  149. X        ulimit 16384    # 8Mb file limit
  150. X        TMOUT=600    # idle timeout
  151. X        ;;
  152. X    esac
  153. X
  154. X    unset S E GROUP
  155. X    export LOCAL TTY PATH LOGNAME USER
  156. X
  157. X    TTY=`tty`
  158. X    if [ $? -ne 0 ]; then
  159. X        # This trick appears not to work under BOS 2.00.45
  160. X        # so be careful of su - user in boot scripts.
  161. X        TTY=none
  162. X    else
  163. X        TTY=`basename $TTY`
  164. X        ORGANIZATION=""
  165. X        COPYRIGHT="Copyright (c) `date +19%y` $ORGANIZATION"
  166. X        export ORGANIZATION COPYRIGHT
  167. X
  168. X        # set up some env variables
  169. X        MAIL=/usr/spool/mail/$USER
  170. X        MAILPATH=/usr/spool/mail/$USER:/etc/motd
  171. X        EMACSDIR=${LOCAL}/lib/emacs
  172. X        PAGER=${PAGER:-more}
  173. X        export MAIL EMACSDIR MANPATH MAILPATH PAGER
  174. X
  175. X        EDITOR=emacs
  176. X    
  177. X        PROMPT="<$LOGNAME@$HOSTNAME>$ "
  178. X        PUBDIR=/usr/spool/uucppublic
  179. X        export PUBDIR 
  180. X        [ -f /etc/profile.TeX ] && . /etc/profile.TeX
  181. X    fi
  182. X
  183. X    # test (and setup if we are Korn shell)
  184. X    if [ "$RANDOM" != "$RANDOM" ]; then
  185. X        # we are Korn shell
  186. X        SHELL=/bin/ksh
  187. X        ENV=${HOME%/}/.kshrc
  188. X        PROMPT="<$LOGNAME@$HOSTNAME:!>$ "
  189. X        export HISTSIZE HISTFILE ENV
  190. X        CDPATH=.:$HOME
  191. X        if [ "$TMOUT" ]; then
  192. X            typeset -r TMOUT
  193. X        fi
  194. X    else
  195. X        SHELL=/bin/sh
  196. X    fi
  197. X    PS1=$PROMPT
  198. X    export SHELL PS1 EDITOR PATH PROMPT HOSTNAME CDPATH
  199. X
  200. X;;
  201. Xesac
  202. X
  203. X# login time initialization
  204. Xcase "$_INIT_" in
  205. X*log*) ;;
  206. X*)    _INIT_="$_INIT_"log
  207. X
  208. X    if [ $TTY != none -a "$0" != "-su" -a "$LOGNAME" = "`logname`" -a ! -f ~/.hushlogin ]
  209. X    then
  210. X        case $TERM in
  211. X        network|unknown|dialup|"") 
  212. X            echo $N "Enter terminal type [$defterm]: $C" 1>&2
  213. X            read tmpterm
  214. X            TERM=${tmpterm:-$defterm}
  215. X            ;;
  216. X        esac
  217. X        # welcome first time users
  218. X        [ -r ${LOCAL}/etc/1stlogin.ann -a ! -f $HOME/... ] && \
  219. X            . ${LOCAL}/etc/1stlogin.ann
  220. X        # not all of the following are appropriate at all sites
  221. X        # Sun's don't need to cat /etc/motd for instance
  222. X        case "$OS" in
  223. X        SunOS)    ;;
  224. X        SCO-UNIX)    
  225. X            [ -s /etc/motd ] && cat /etc/motd
  226. X            [ -x /usr/bin/mail -a -s "$MAIL" ] && 
  227. X                echo "You have mail."
  228. X            [ -x /usr/bin/news ] && /usr/bin/news -n
  229. X            ;;
  230. X        *)
  231. X            [ -s /etc/motd ] && cat /etc/motd
  232. X            if [ -x /usr/bin/mailx ]; then
  233. X               if mailx -e; then
  234. X                echo "You have mail."
  235. X                # show the the headers, this might
  236. X                # be better done in .profile so they
  237. X                # can override it.
  238. X#                mailx -H
  239. X              fi
  240. X            fi
  241. X            [ -x /usr/bin/news ] && /usr/bin/news -n
  242. X            ;;
  243. X        esac
  244. X        [ -x /usr/games/fortune ] && /usr/games/fortune -a
  245. X        # remind folk who turned on reply.pl to turn it off.
  246. X        if [ -f $HOME/.forward ]; then
  247. X            echo "Your mail is being forwarded to:"
  248. X            cat $HOME/.forward
  249. X            if [ -f $HOME/.recording ]; then
  250. X                echo "Perhaps you should run \"reply.pl off\""
  251. X            fi
  252. X        fi
  253. X    fi
  254. X    unset tmpterm defterm C N
  255. X    TERM=${TERM:-unknown}
  256. X    export TERM TTY
  257. X;;
  258. Xesac
  259. X# Handle X-terminals if necessary
  260. X[ -f /etc/profile.X11 ] && . /etc/profile.X11
  261. END_OF_FILE
  262.   if test 5445 -ne `wc -c <'etc/profile'`; then
  263.     echo shar: \"'etc/profile'\" unpacked with wrong size!
  264.   fi
  265.   # end of 'etc/profile'
  266. fi
  267. if test -f 'sh/exec.c' -a "${1}" != "-c" ; then 
  268.   echo shar: Will not clobber existing file \"'sh/exec.c'\"
  269. else
  270.   echo shar: Extracting \"'sh/exec.c'\" \(14925 characters\)
  271.   sed "s/^X//" >'sh/exec.c' <<'END_OF_FILE'
  272. X/*
  273. X * execute command tree
  274. X */
  275. X
  276. X#ifndef lint
  277. Xstatic char *RCSid = "$Id: exec.c,v 3.4 89/03/27 15:50:10 egisin Exp $";
  278. Xstatic char *sccs_id = "@(#)exec.c    1.3 91/11/09 15:35:22 (sjg)";
  279. X#endif
  280. X
  281. X#include <stddef.h>
  282. X#include <stdio.h>
  283. X#include <string.h>
  284. X#include <errno.h>
  285. X#include <signal.h>
  286. X#include <setjmp.h>
  287. X#include <unistd.h>
  288. X#include <fcntl.h>
  289. X#include <sys/types.h>
  290. X#include <sys/stat.h>
  291. X#include "sh.h"
  292. X#include "lex.h"
  293. X#include "tree.h"
  294. X#include "table.h"
  295. X
  296. Xstatic    int    comexec ARGS((struct op *t, char **vp, char **ap, int flags));
  297. Xstatic    void    iosetup ARGS((struct ioword *iop));
  298. Xstatic    void    echo ARGS((char **, char **));
  299. Xstatic    int    herein ARGS((char *name, int sub));
  300. X#ifdef    SHARPBANG
  301. Xstatic    void    scriptexec ARGS((struct op *t, char **ap));
  302. X#endif
  303. X
  304. X/*
  305. X * execute command tree
  306. X */
  307. Xint
  308. Xexecute(t, flags)
  309. X    register struct op *t;
  310. X    Volatile int flags;    /* if XEXEC don't fork */
  311. X{
  312. X    int i;
  313. X    int Volatile rv = 0;
  314. X    int pv[2];
  315. X    register char **ap;
  316. X    char *s, *cp;
  317. X    struct ioword **iowp;
  318. X
  319. X    if (t == NULL)
  320. X        return 0;
  321. X
  322. X    if ((flags&XFORK) && !(flags&XEXEC) && t->type != TPIPE)
  323. X        return exchild(t, flags); /* run in sub-process */
  324. X
  325. X    newenv(E_EXEC);
  326. X    if (trap)
  327. X        runtraps();
  328. X    if (t->ioact != NULL || t->type == TPIPE) {
  329. X        e.savefd = (short*) alloc(sizeofN(short, NUFILE), ATEMP);
  330. X        for (i = 0; i < NUFILE; i++)
  331. X            e.savefd[i] = 0; /* not redirected */
  332. X        /* mark fd 0/1 in-use if pipeline */
  333. X        if (flags&XPIPEI)
  334. X            e.savefd[0] = -1;
  335. X        if (flags&XPIPEO)
  336. X            e.savefd[1] = -1;
  337. X    }
  338. X
  339. X    /* do redirection, to be restored in quitenv() */
  340. X    if (t->ioact != NULL)
  341. X        for (iowp = t->ioact; *iowp != NULL; iowp++)
  342. X            iosetup(*iowp);
  343. X
  344. X    switch(t->type) {
  345. X      case TCOM:
  346. X        e.type = E_TCOM;
  347. X        rv = comexec(t, eval(t->vars, DOTILDE),
  348. X                 eval(t->args, DOBLANK|DOGLOB|DOTILDE), flags);
  349. X        break;
  350. X
  351. X      case TPAREN:
  352. X        exstat = rv = execute(t->left, flags|XFORK);
  353. X        break;
  354. X
  355. X      case TPIPE:
  356. X        flags |= XFORK;
  357. X        flags &= ~XEXEC;
  358. X        e.savefd[0] = savefd(0);
  359. X        e.savefd[1] = savefd(1);
  360. X        flags |= XPIPEO;
  361. X        (void) dup2(e.savefd[0], 0); /* stdin of first */
  362. X        while (t->type == TPIPE) {
  363. X            openpipe(pv);
  364. X            (void) dup2(pv[1], 1);    /* stdout of curr */
  365. X            exchild(t->left, flags);
  366. X            (void) dup2(pv[0], 0);    /* stdin of next */
  367. X            closepipe(pv);
  368. X            flags |= XPIPEI;
  369. X            t = t->right;
  370. X        }
  371. X        flags &= ~ XPIPEO;
  372. X        (void) dup2(e.savefd[1], 1); /* stdout of last */
  373. X        exchild(t, flags);
  374. X        (void) dup2(e.savefd[0], 0); /* close pipe in */
  375. X        if (!(flags&XBGND))
  376. X            exstat = rv = waitlast();
  377. X        break;
  378. X
  379. X      case TLIST:
  380. X        while (t->type == TLIST) {
  381. X            execute(t->left, 0);
  382. X            t = t->right;
  383. X        }
  384. X        rv = execute(t, 0);
  385. X        break;
  386. X
  387. X      case TASYNC:
  388. X        rv = execute(t->left, flags|XBGND|XFORK);
  389. X        break;
  390. X
  391. X      case TOR:
  392. X      case TAND:
  393. X        rv = execute(t->left, 0);
  394. X        if (t->right != NULL && (rv == 0) == (t->type == TAND))
  395. X            rv = execute(t->right, 0);
  396. X        break;
  397. X
  398. X      case TFOR:
  399. X        e.type = E_LOOP;
  400. X        ap = (t->vars != NULL) ?
  401. X            eval(t->vars, DOBLANK|DOGLOB|DOTILDE) : e.loc->argv + 1;
  402. X        while ((i = setjmp(e.jbuf)))
  403. X            if (i == LBREAK)
  404. X                goto Break1;
  405. X        while (*ap != NULL) {
  406. X            setstr(global(t->str), *ap++);
  407. X            rv = execute(t->left, 0);
  408. X        }
  409. X      Break1:
  410. X        break;
  411. X
  412. X      case TWHILE:
  413. X      case TUNTIL:
  414. X        e.type = E_LOOP;
  415. X        while ((i = setjmp(e.jbuf)))
  416. X            if (i == LBREAK)
  417. X                goto Break2;
  418. X        while ((execute(t->left, 0) == 0) == (t->type == TWHILE))
  419. X            rv = execute(t->right, 0);
  420. X      Break2:
  421. X        break;
  422. X
  423. X      case TIF:
  424. X      case TELIF:
  425. X        if (t->right == NULL)
  426. X            break;    /* should be error */
  427. X        rv = execute(t->left, 0) == 0 ?
  428. X            execute(t->right->left, 0) :
  429. X            execute(t->right->right, 0);
  430. X        break;
  431. X
  432. X      case TCASE:
  433. X        cp = evalstr(t->str, 0);
  434. X        for (t = t->left; t != NULL && t->type == TPAT; t = t->right)
  435. X            for (ap = t->vars; *ap; ap++)
  436. X            if ((s = evalstr(*ap, DOPAT)) && gmatch(cp, s))
  437. X                goto Found;
  438. X        break;
  439. X      Found:
  440. X        rv = execute(t->left, 0);
  441. X        break;
  442. X
  443. X      case TBRACE:
  444. X        rv = execute(t->left, 0);
  445. X        break;
  446. X
  447. X      case TFUNCT:
  448. X        rv = define(t->str, t->left);
  449. X        break;
  450. X
  451. X      case TTIME:
  452. X        rv = timex(t, flags);
  453. X        break;
  454. X
  455. X      case TEXEC:        /* an eval'd TCOM */
  456. X        s = t->args[0];
  457. X        ap = makenv();
  458. X#ifdef _MINIX                /* no F_SETFD close-on-exec */
  459. X        for (i = 10; i < 20; i++)
  460. X            close(i);
  461. X#endif
  462. X        execve(t->str, t->args, ap);
  463. X        if (errno == ENOEXEC) {
  464. X            char *shell;
  465. X#ifdef    SHARPBANG
  466. X            scriptexec(t, ap);
  467. X#else
  468. X            shell = strval(global("EXECSHELL"));
  469. X            if (shell && *shell) {
  470. X                if ((shell = search(shell,path,1)) == NULL)
  471. X                    shell = SHELL;
  472. X            } else {
  473. X                shell = SHELL;
  474. X            }
  475. X            *t->args-- = t->str;
  476. X            *t->args = shell;
  477. X            execve(t->args[0], t->args, ap);
  478. X            errorf("No shell\n");
  479. X#endif    /* SHARPBANG */
  480. X        }
  481. X        errorf("%s: %s\n", s, strerror(errno));
  482. X    }
  483. X
  484. X    quitenv();        /* restores IO */
  485. X    if (e.interactive) {    /* flush stdout, shlout */
  486. X        fflush(shf[1]);
  487. X        fflush(shf[2]);
  488. X    }
  489. X    if ((flags&XEXEC))
  490. X        exit(rv);    /* exit child */
  491. X    return rv;
  492. X}
  493. X
  494. X/*
  495. X * execute simple command
  496. X */
  497. X
  498. Xstatic int
  499. Xcomexec(t, vp, ap, flags)
  500. X    struct op *t;
  501. X    register char **ap, **vp;
  502. X    int flags;
  503. X{
  504. X    int i;
  505. X    int rv = 0;
  506. X    register char *cp;
  507. X    register char **lastp;
  508. X    register struct tbl *tp = NULL;
  509. X    register struct block *l;
  510. X    static struct op texec = {TEXEC};
  511. X    extern int c_exec(), c_builtin();
  512. X
  513. X    if (flag[FXTRACE])
  514. X        echo(vp, ap);
  515. X
  516. X    /* snag the last argument for $_ */
  517. X    if ((lastp = ap) && *lastp) {
  518. X        while (*++lastp)
  519. X            ;
  520. X        setstr(typeset("_",LOCAL,0),*--lastp);
  521. X    }    
  522. X
  523. X    /* create new variable/function block */
  524. X    l = (struct block*) alloc(sizeof(struct block), ATEMP);
  525. X    l->next = e.loc; e.loc = l;
  526. X    newblock();
  527. X
  528. X Doexec:
  529. X    if ((cp = *ap) == NULL)
  530. X        cp = ":";
  531. X    tp = findcom(cp, flag[FHASHALL]);
  532. X
  533. X    switch (tp->type) {
  534. X      case CSHELL:            /* shell built-in */
  535. X        while (tp->val.f == c_builtin) {
  536. X            if ((cp = *++ap) == NULL)
  537. X                break;
  538. X            tp = tsearch(&builtins, cp, hash(cp));
  539. X            if (tp == NULL)
  540. X                errorf("%s: not builtin\n", cp);
  541. X        }
  542. X        if (tp->val.f == c_exec) {
  543. X            if (*++ap == NULL) {
  544. X                e.savefd = NULL; /* don't restore redirection */
  545. X                break;
  546. X            }
  547. X            flags |= XEXEC;
  548. X            goto Doexec;
  549. X        }
  550. X        if ((tp->flag&TRACE))
  551. X            e.loc = l->next; /* no local block */
  552. X        i = (tp->flag&TRACE) ? 0 : LOCAL;
  553. X        while (*vp != NULL)
  554. X            (void) typeset(*vp++, i, 0);
  555. X        rv = (*tp->val.f)(ap);
  556. X        break;
  557. X
  558. X    case CFUNC:            /* function call */
  559. X        if (!(tp->flag&ISSET))
  560. X            errorf("%s: undefined function\n", cp);
  561. X        l->argv = ap;
  562. X        for (i = 0; *ap++ != NULL; i++)
  563. X            ;
  564. X        l->argc = i - 1;
  565. X        resetopts();
  566. X        while (*vp != NULL)
  567. X            (void) typeset(*vp++, LOCAL, 0);
  568. X        e.type = E_FUNC;
  569. X        if (setjmp(e.jbuf))
  570. X            rv = exstat; /* return # */
  571. X        else
  572. X            rv = execute(tp->val.t, 0);
  573. X        break;
  574. X
  575. X    case CEXEC:        /* executable command */
  576. X        if (!(tp->flag&ISSET)) {
  577. X            /*
  578. X             * mlj addition:
  579. X             *
  580. X             * If you specify a full path to a file
  581. X             * (or type the name of a file in .) which
  582. X             * doesn't have execute priv's, it used to
  583. X             * just say "not found".  Kind of annoying,
  584. X             * particularly if you just wrote a script
  585. X             * but forgot to say chmod 755 script.
  586. X             *
  587. X             * This should probably be done in eaccess(),
  588. X             * but it works here (at least I haven't noticed
  589. X             * changing errno here breaking something
  590. X             * else).
  591. X             *
  592. X             * So, we assume that if the file exists, it
  593. X             * doesn't have execute privs; else, it really
  594. X             * is not found.
  595. X             */
  596. X            if (access(cp, 0) < 0)
  597. X                shellf("%s: not found\n", cp);
  598. X            else
  599. X                shellf("%s: cannot execute\n", cp);
  600. X            rv = 1;
  601. X            break;
  602. X        }
  603. X
  604. X        /* set $_ to program's full path */
  605. X        setstr(typeset("_", LOCAL|EXPORT, 0), tp->val.s);
  606. X        while (*vp != NULL)
  607. X            (void) typeset(*vp++, LOCAL|EXPORT, 0);
  608. X
  609. X        if ((flags&XEXEC)) {
  610. X            j_exit();
  611. X            if (flag[FMONITOR] || !(flags&XBGND)) {
  612. X                signal(SIGINT, SIG_DFL);
  613. X                signal(SIGQUIT, SIG_DFL);
  614. X            }
  615. X        }
  616. X
  617. X        /* to fork we set up a TEXEC node and call execute */
  618. X        texec.left = t;    /* for tprint */
  619. X        texec.str = tp->val.s;
  620. X        texec.args = ap;
  621. X        rv = exchild(&texec, flags);
  622. X        break;
  623. X    }
  624. X    if (rv != 0 && flag[FERREXIT])
  625. X        leave(rv);
  626. X    return (exstat = rv);
  627. X}
  628. X
  629. X#ifdef    SHARPBANG
  630. Xstatic void
  631. Xscriptexec(tp, ap)
  632. X    register struct op *tp;
  633. X    register char **ap;
  634. X{
  635. X    char line[LINE];
  636. X    register char *cp;
  637. X    register int fd, n;
  638. X    char *shell;
  639. X
  640. X    shell = strval(global("EXECSHELL"));
  641. X    if (shell && *shell) {
  642. X        if ((shell = search(shell,path,1)) == NULL)
  643. X            shell = SHELL;
  644. X    } else {
  645. X        shell = SHELL;
  646. X    }
  647. X
  648. X    *tp->args-- = tp->str;
  649. X    line[0] = '\0';
  650. X    if ((fd = open(tp->str,0)) >= 0) {
  651. X        if ((n = read(fd, line, LINE - 1)) > 0)
  652. X            line[n] = '\0';
  653. X        (void) close(fd);
  654. X    }
  655. X    if (line[0] == '#' && line[1] == '!') {
  656. X        cp = &line[2];
  657. X        while (*cp && (*cp == ' ' || *cp == '\t'))
  658. X            cp++;
  659. X        if (*cp && *cp != '\n') {
  660. X            *tp->args = cp;
  661. X            while (*cp && *cp != '\n' && *cp != ' ' && *cp != '\t')
  662. X                cp++;
  663. X            if (*cp && *cp != '\n') {
  664. X                *cp++ = '\0';
  665. X                while (*cp && (*cp == ' ' || *cp == '\t'))
  666. X                    cp++;
  667. X                if (*cp && *cp != '\n') {
  668. X                    tp->args--;
  669. X                    tp->args[0] = tp->args[1];
  670. X                    tp->args[1] = cp;
  671. X                    while (*cp && *cp != '\n' &&
  672. X                           *cp != ' ' && *cp != '\t')
  673. X                        cp++;
  674. X                }
  675. X            }
  676. X            *cp = '\0';
  677. X        } else
  678. X            *tp->args = shell;
  679. X    } else
  680. X        *tp->args = shell;
  681. X
  682. X    (void) execve(tp->args[0], tp->args, ap);
  683. X    errorf( "No shell\n" );
  684. X}
  685. X#endif    /* SHARPBANG */
  686. X
  687. Xint
  688. Xshcomexec(wp)
  689. X    register char **wp;
  690. X{
  691. X    register struct tbl *tp;
  692. X
  693. X    tp = tsearch(&builtins, *wp, hash(*wp));
  694. X    if (tp == NULL)
  695. X        errorf("%s: shcomexec botch\n", *wp);
  696. X    return (*tp->val.f)(wp);
  697. X}
  698. X
  699. X/*
  700. X * define function
  701. X */
  702. Xint
  703. Xdefine(name, t)
  704. X    char    *name;
  705. X    struct op *t;
  706. X{
  707. X    register struct block *l;
  708. X    register struct tbl *tp;
  709. X
  710. X    for (l = e.loc; l != NULL; l = l->next) {
  711. X        lastarea = &l->area;
  712. X        tp = tsearch(&l->funs, name, hash(name));
  713. X        if (tp != NULL && (tp->flag&DEFINED))
  714. X            break;
  715. X        if (l->next == NULL) {
  716. X            tp = tenter(&l->funs, name, hash(name));
  717. X            tp->flag = DEFINED|FUNCT;
  718. X            tp->type = CFUNC;
  719. X        }
  720. X    }
  721. X
  722. X    if ((tp->flag&ALLOC))
  723. X        tfree(tp->val.t, lastarea);
  724. X    tp->flag &= ~(ISSET|ALLOC);
  725. X
  726. X    if (t == NULL) {        /* undefine */
  727. X        tdelete(tp);
  728. X        return 0;
  729. X    }
  730. X
  731. X    tp->val.t = tcopy(t, lastarea);
  732. X    tp->flag |= (ISSET|ALLOC);
  733. X
  734. X    return 0;
  735. X}
  736. X
  737. X/*
  738. X * add builtin
  739. X */
  740. Xbuiltin(name, func)
  741. X    char *name;
  742. X    int (*func)();
  743. X{
  744. X    register struct tbl *tp;
  745. X    int flag = DEFINED;
  746. X
  747. X    if (*name == '=') {        /* sets keyword variables */
  748. X        name++;
  749. X        flag |= TRACE;    /* command does variable assignment */
  750. X    }
  751. X
  752. X    tp = tenter(&builtins, name, hash(name));
  753. X    tp->flag |= flag;
  754. X    tp->type = CSHELL;
  755. X    tp->val.f = func;
  756. X}
  757. X
  758. X/*
  759. X * find command
  760. X * either function, hashed command, or built-in (in that order)
  761. X */
  762. Xstruct tbl *
  763. Xfindcom(name, insert)
  764. X    char    *name;
  765. X    int    insert;            /* insert if not found */
  766. X{
  767. X    register struct block *l = e.loc;
  768. X    unsigned int h = hash(name);
  769. X    register struct    tbl *tp = NULL;
  770. X    static struct tbl temp;
  771. X
  772. X    if (strchr(name, '/') != NULL) {
  773. X        tp = &temp;
  774. X        tp->type = CEXEC;
  775. X        tp->flag = 0;    /* make ~ISSET */
  776. X        goto Search;
  777. X    }
  778. X    for (l = e.loc; l != NULL; l = l->next) {
  779. X        tp = tsearch(&l->funs, name, h);
  780. X        if (tp != NULL && (tp->flag&DEFINED))
  781. X            break;
  782. X    }
  783. X    if (tp == NULL) {
  784. X        tp = tsearch(&commands, name, h);
  785. X        if (tp != NULL && eaccess(tp->val.s,1) != 0) {
  786. X            if (tp->flag&ALLOC)
  787. X                afree(tp->val.s, commands.areap);
  788. X            tp->type = CEXEC;
  789. X            tp->flag = DEFINED;
  790. X        }
  791. X    }
  792. X    if (tp == NULL)
  793. X        tp = tsearch(&builtins, name, h);
  794. X    if (tp == NULL) {
  795. X        tp = tenter(&commands, name, h);
  796. X        tp->type = CEXEC;
  797. X        tp->flag = DEFINED;
  798. X    }
  799. X  Search:
  800. X    if (tp->type == CEXEC && !(tp->flag&ISSET)) {
  801. X        if (!insert) {
  802. X            tp = &temp;
  803. X            tp->type = CEXEC;
  804. X            tp->flag = 0;    /* make ~ISSET */
  805. X        }
  806. X        name = search(name, path, 1);
  807. X        if (name != NULL) {
  808. X            tp->val.s = strsave(name,
  809. X                        (tp == &temp) ? ATEMP : APERM);
  810. X            tp->flag |= ISSET|ALLOC;
  811. X        }
  812. X    }
  813. X    return tp;
  814. X}
  815. X
  816. X/*
  817. X * flush executable commands with relative paths
  818. X */
  819. Xflushcom(all)
  820. X    int all;        /* just relative or all */
  821. X{
  822. X    register struct tbl *tp;
  823. X
  824. X    for (twalk(&commands); (tp = tnext()) != NULL; )
  825. X        if ((tp->flag&ISSET) && (all || tp->val.s[0] != '/')) {
  826. X            if ((tp->flag&ALLOC))
  827. X                afree(tp->val.s, commands.areap);
  828. X            tp->flag = DEFINED; /* make ~ISSET */
  829. X        }
  830. X}
  831. X
  832. X/*
  833. X * search for command with PATH
  834. X */
  835. Xchar *
  836. Xsearch(name, path, mode)
  837. X    char *name, *path;
  838. X    int mode;        /* 0: readable; 1: executable */
  839. X{
  840. X    register int i;
  841. X    register char *sp, *tp;
  842. X    struct stat buf;
  843. X
  844. X    if (strchr(name, '/'))
  845. X        return (eaccess(name, mode) == 0) ? name : NULL;
  846. X
  847. X    sp = path;
  848. X    while (sp != NULL) {
  849. X        tp = line;
  850. X        for (; *sp != '\0'; tp++)
  851. X            if ((*tp = *sp++) == ':') {
  852. X                --sp;
  853. X                break;
  854. X            }
  855. X        if (tp != line)
  856. X            *tp++ = '/';
  857. X        for (i = 0; (*tp++ = name[i++]) != '\0';)
  858. X            ;
  859. X        i = eaccess(line, mode);
  860. X        if (i == 0 && (mode != 1 || stat(line,&buf) == 0 &&
  861. X            (buf.st_mode & S_IFMT) == S_IFREG))
  862. X            return line;
  863. X        /* what should we do about EACCES? */
  864. X        if (*sp++ == '\0')
  865. X            sp = NULL;
  866. X    }
  867. X    return NULL;
  868. X}
  869. X
  870. X/*
  871. X * set up redirection, saving old fd's in e.savefd
  872. X */
  873. Xstatic void
  874. Xiosetup(iop)
  875. X    register struct ioword *iop;
  876. X{
  877. X    register int u = -1;
  878. X    char *cp = iop->name;
  879. X    extern long lseek();
  880. X
  881. X    if (iop->unit == 0 || iop->unit == 1 || iop->unit == 2)
  882. X        e.interactive = 0;
  883. X#if 0
  884. X    if (e.savefd[iop->unit] != 0)
  885. X        errorf("file descriptor %d already redirected\n", iop->unit);
  886. X#endif
  887. X    e.savefd[iop->unit] = savefd(iop->unit);
  888. X
  889. X    if ((iop->flag&IOTYPE) != IOHERE)
  890. X        cp = evalstr(cp, DOTILDE);
  891. X
  892. X    switch (iop->flag&IOTYPE) {
  893. X      case IOREAD:
  894. X        u = open(cp, 0);
  895. X        break;
  896. X
  897. X      case IOCAT:
  898. X        if ((u = open(cp, 1)) >= 0) {
  899. X            (void) lseek(u, (long)0, 2);
  900. X            break;
  901. X        }
  902. X        /* FALLTHROUGH */
  903. X      case IOWRITE:
  904. X        u = creat(cp, 0666);
  905. X        break;
  906. X
  907. X      case IORDWR:
  908. X        u = open(cp, 2);
  909. X        break;
  910. X
  911. X      case IOHERE:
  912. X        u = herein(cp, iop->flag&IOEVAL);
  913. X        /* cp may have wrong name */
  914. X        break;
  915. X
  916. X      case IODUP:
  917. X        if (*cp == '-')
  918. X            close(u = iop->unit);
  919. X        else
  920. X        if (digit(*cp))
  921. X            u = *cp - '0';
  922. X        else
  923. X            errorf("%s: illegal >& argument\n", cp);
  924. X        break;
  925. X    }
  926. X    if (u < 0)
  927. X        errorf("%s: cannot %s\n", cp,
  928. X               (iop->flag&IOTYPE) == IOWRITE ? "create" : "open");
  929. X    if (u != iop->unit) {
  930. X        (void) dup2(u, iop->unit);
  931. X        if (iop->flag != IODUP)
  932. X            close(u);
  933. X    }
  934. X
  935. X    fopenshf(iop->unit);
  936. X}
  937. X
  938. X/*
  939. X * open here document temp file.
  940. X * if unquoted here, expand here temp file into second temp file.
  941. X */
  942. Xstatic int
  943. Xherein(hname, sub)
  944. X    char *hname;
  945. X    int sub;
  946. X{
  947. X    int fd;
  948. X    FILE * Volatile f = NULL;
  949. X
  950. X    f = fopen(hname, "r");
  951. X    if (f == NULL)
  952. X        return -1;
  953. X    setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
  954. X
  955. X    if (sub) {
  956. X        char *cp;
  957. X        struct source *s;
  958. X        struct temp *h;
  959. X
  960. X        newenv(E_ERRH);
  961. X        if (setjmp(e.jbuf)) {
  962. X            if (f != NULL)
  963. X                fclose(f);
  964. X            quitenv();
  965. X            return -1; /* todo: error()? */
  966. X        }
  967. X
  968. X        /* set up yylex input from here file */
  969. X        s = pushs(SFILE);
  970. X        s->u.file = f;
  971. X        source = s;
  972. X        if (yylex(ONEWORD) != LWORD)
  973. X            errorf("exec:herein error\n");
  974. X        cp = evalstr(yylval.cp, 0);
  975. X
  976. X        /* write expanded input to another temp file */
  977. X        h = maketemp(ATEMP);
  978. X        h->next = e.temps; e.temps = h;
  979. X        if (h == NULL)
  980. X            error();
  981. X        f = fopen(h->name, "w+");
  982. X        if (f == NULL)
  983. X            error();
  984. X        setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
  985. X        fputs(cp, f);
  986. X        rewind(f);
  987. X
  988. X        quitenv();
  989. X    }
  990. X    fd = dup(fileno(f));
  991. X    fclose(f);
  992. X    return fd;
  993. X}
  994. X
  995. Xstatic void
  996. Xecho(vp, ap)
  997. X    register char **vp, **ap;
  998. X{
  999. X    shellf("+");
  1000. X    while (*vp != NULL)
  1001. X        shellf(" %s", *vp++);
  1002. X    while (*ap != NULL)
  1003. X        shellf(" %s", *ap++);
  1004. X    shellf("\n");
  1005. X}
  1006. X
  1007. END_OF_FILE
  1008.   if test 14925 -ne `wc -c <'sh/exec.c'`; then
  1009.     echo shar: \"'sh/exec.c'\" unpacked with wrong size!
  1010.   fi
  1011.   # end of 'sh/exec.c'
  1012. fi
  1013. if test -f 'sh/vi.c' -a "${1}" != "-c" ; then 
  1014.   echo shar: Will not clobber existing file \"'sh/vi.c'\"
  1015. else
  1016.   echo shar: Extracting \"'sh/vi.c'\" \(30485 characters\)
  1017.   sed "s/^X//" >'sh/vi.c' <<'END_OF_FILE'
  1018. X/*
  1019. X *    vi command editing
  1020. X *    written by John Rochester (initially for nsh)
  1021. X *    bludgeoned to fit PD ksh by Larry Bouzane and Eric Gisin
  1022. X *    Further hacked (bugfixes and tweaks) by Mike Jetzer
  1023. X */
  1024. X
  1025. X#include "config.h"
  1026. X#ifdef VI
  1027. X
  1028. X#ifndef lint
  1029. Xstatic char *RCSid = "$Id: vi.c,v 3.1 89/01/28 15:29:20 egisin Exp $";
  1030. Xstatic char *sccs_id = "@(#)vi.c    1.3 91/11/09 15:35:09 (sjg)";
  1031. X#endif
  1032. X
  1033. X#include <stddef.h>
  1034. X#include <stdlib.h>
  1035. X#include <string.h>
  1036. X#include <stdio.h>
  1037. X#include <unistd.h>
  1038. X#include <signal.h>
  1039. X#include <fcntl.h>
  1040. X#include <ctype.h>
  1041. X#include <errno.h>
  1042. X#include <setjmp.h>
  1043. X#include "sh.h"
  1044. X#include "lex.h"
  1045. X#include "tree.h"        /* DOTILDE */
  1046. X#include "table.h"
  1047. X#include "expand.h"
  1048. X#include "edit.h"
  1049. X
  1050. X#define CMDLEN        256
  1051. X#define Ctrl(c)        (c&0x1f)
  1052. X#define    bcopy(src, dst, len)    memmove(dst, src, len)
  1053. Xextern    int    histN();
  1054. X
  1055. Xstatic int    nextstate();
  1056. Xstatic int    vi_insert();
  1057. Xstatic int    vi_cmd();
  1058. Xstatic int    domove();
  1059. Xstatic int    redo_insert();
  1060. Xstatic        yank_range();
  1061. Xstatic int    bracktype();
  1062. Xstatic        edit_prompt();
  1063. Xstatic        edit_reset();
  1064. Xstatic int    putbuf();
  1065. Xstatic        stripblanks();
  1066. Xstatic        del_range();
  1067. Xstatic int    findch();
  1068. Xstatic int    forwword();
  1069. Xstatic int    backword();
  1070. Xstatic int    endword();
  1071. Xstatic int    Forwword();
  1072. Xstatic int    Backword();
  1073. Xstatic int    Endword();
  1074. Xstatic int    grabhist();
  1075. Xstatic int    grabsearch();
  1076. Xstatic        redraw_line();
  1077. Xstatic        refresh();
  1078. Xstatic int    outofwin();
  1079. Xstatic        rewindow();
  1080. Xstatic int    newcol();
  1081. Xstatic        display();
  1082. Xstatic        ed_mov_opt();
  1083. X
  1084. X#define C_    0x1
  1085. X#define M_    0x2
  1086. X#define E_    0x4
  1087. X#define X_    0x8
  1088. X#define U_    0x10
  1089. X#define B_    0x20
  1090. X#define O_    0x40
  1091. X#define S_    0x80
  1092. X
  1093. X#define isbad(c)    (classify[c]&B_)
  1094. X#define iscmd(c)    (classify[c]&(M_|E_|C_|U_))
  1095. X#define ismove(c)    (classify[c]&M_)
  1096. X#define isextend(c)    (classify[c]&E_)
  1097. X#define islong(c)    (classify[c]&X_)
  1098. X#define ismeta(c)    (classify[c]&O_)
  1099. X#define isundoable(c)    (!(classify[c]&U_))
  1100. X#define issrch(c)    (classify[c]&S_)
  1101. X
  1102. Xchar    classify[128] = {
  1103. X    B_,    0,    0,    0,    0,    0,    O_,    0,
  1104. X#if 1    /* Mike B. changes */
  1105. X    C_|M_,    0,    O_,    0,    O_,    O_,    O_,    0,
  1106. X#else
  1107. X    C_,    0,    O_,    0,    O_,    O_,    O_,    0,
  1108. X#endif
  1109. X    O_,    0,    C_|U_,    0,    0,    0,    0,    0,
  1110. X    0,    0,    O_,    0,    0,    0,    0,    0,
  1111. X#if 1    /* Mike B. changes */
  1112. X    C_|M_,    0,    0,    C_,    M_,    C_,    0,    0,
  1113. X#else
  1114. X    C_,    0,    0,    C_,    M_,    C_,    0,    0,
  1115. X#endif
  1116. X    0,    0,    C_,    C_,    M_,    C_,    0,    C_|S_,
  1117. X    M_,    0,    0,    0,    0,    0,    0,    0,
  1118. X    0,    0,    0,    M_,    0,    0,    0,    C_|S_,
  1119. X    0,    C_,    M_,    C_,    C_,    M_,    M_|X_,    C_,
  1120. X    0,    C_,    0,    0,    0,    0,    C_,    0,
  1121. X    C_,    0,    C_,    C_,    M_|X_,    0,    0,    M_,
  1122. X    C_,    C_,    0,    0,    0,    0,    M_,    C_,
  1123. X    0,    C_,    M_,    E_,    E_,    M_,    M_|X_,    0,
  1124. X    M_,    C_,    C_,    C_,    M_,    0,    C_,    0,
  1125. X    C_,    0,    C_,    C_,    M_|X_,    C_|U_,    0,    M_,
  1126. X    C_,    E_,    0,    0,    0,    0,    C_,    0
  1127. X};
  1128. X
  1129. X#define MAXVICMD    3
  1130. X#define SRCHLEN        40
  1131. X
  1132. X#define INSERT        1
  1133. X#define REPLACE        2
  1134. X
  1135. X#define VNORMAL        0
  1136. X#define VARG1        1
  1137. X#define VEXTCMD        2
  1138. X#define VARG2        3
  1139. X#define VXCH        4
  1140. X#define VFAIL        5
  1141. X#define VCMD        6
  1142. X#define VREDO        7
  1143. X#define VLIT        8
  1144. X#define VSEARCH        9
  1145. X#define VREPLACE1CHAR    10
  1146. X
  1147. Xstruct edstate {
  1148. X    int    winleft;
  1149. X    char    *cbuf;
  1150. X    int    cbufsize;
  1151. X    int    linelen;
  1152. X    int    cursor;
  1153. X};
  1154. X
  1155. Xstatic char        undocbuf[CMDLEN];
  1156. X
  1157. Xstatic struct edstate    ebuf;
  1158. Xstatic struct edstate    undobuf = { 0, undocbuf, CMDLEN, 0, 0 };
  1159. X
  1160. Xstatic struct edstate    *es;            /* current editor state */
  1161. Xstatic struct edstate    *undo;
  1162. X
  1163. Xstatic char    ibuf[CMDLEN];        /* input buffer */
  1164. Xstatic int    inslen;            /* length of input buffer */
  1165. Xstatic int    srchlen;        /* length of current search pattern */
  1166. Xstatic char    ybuf[CMDLEN];        /* yank buffer */
  1167. Xstatic int    yanklen;        /* length of yank buffer */
  1168. Xstatic int    fsavecmd = ' ';        /* last find command */
  1169. Xstatic int    fsavech;        /* character to find */
  1170. Xstatic char    lastcmd[MAXVICMD];    /* last non-move command */
  1171. Xstatic int    lastac;            /* argcnt for lastcmd */
  1172. Xstatic int    lastsearch = ' ';    /* last search command */
  1173. Xstatic char    srchpat[SRCHLEN];    /* last search pattern */
  1174. Xstatic int    insert;            /* non-zero in insert mode */
  1175. Xstatic int    hnum;            /* position in history */
  1176. Xstatic int    hlast;            /* 1 past last position in history */
  1177. Xstatic int    modified;        /* buffer has been "modified" */
  1178. Xstatic int    state;
  1179. X
  1180. X#if 0
  1181. Xvi_init()
  1182. X{
  1183. X    es = (struct edstate *) malloc((unsigned) sizeof(struct edstate));
  1184. X    fsavecmd = ' ';
  1185. X    lastsearch = ' ';
  1186. X}
  1187. X
  1188. Xedit_init()
  1189. X{
  1190. X    wbuf[0] = malloc((unsigned) (x_cols - 3));
  1191. X    wbuf[1] = malloc((unsigned) (x_cols - 3));
  1192. X}
  1193. X#endif
  1194. X
  1195. Xvoid
  1196. Xvi_reset(buf, len)
  1197. X    char    *buf;
  1198. X    int    len;
  1199. X{
  1200. X    state = VNORMAL;
  1201. X    hnum = hlast = histnum(-1) + 1;
  1202. X    insert = INSERT;
  1203. X    yanklen = 0;
  1204. X    inslen = 0;
  1205. X    lastcmd[0] = 'a';
  1206. X    lastac = 1;
  1207. X    modified = 1;
  1208. X    edit_reset(buf, len);
  1209. X}
  1210. X
  1211. Xint
  1212. Xvi_hook(ch)
  1213. X    int        ch;
  1214. X{
  1215. X    static char    curcmd[MAXVICMD];
  1216. X    static char    locpat[SRCHLEN];
  1217. X    static int    cmdlen;
  1218. X    static int    argc1, argc2;
  1219. X    int        i;
  1220. X
  1221. X    if (state != VSEARCH && (ch == '\r' || ch == '\n')) {
  1222. X        x_putc('\r');
  1223. X        x_putc('\n');
  1224. X        x_flush();
  1225. X        return 1;
  1226. X    }
  1227. X
  1228. X    switch (state) {
  1229. X
  1230. X    case VREPLACE1CHAR:
  1231. X        curcmd[cmdlen++] = ch;
  1232. X        state = VCMD;
  1233. X        break;
  1234. X
  1235. X    case VNORMAL:
  1236. X        if (insert != 0) {
  1237. X            if (ch == Ctrl('v')) {
  1238. X                state = VLIT;
  1239. X                ch = '^';
  1240. X            }
  1241. X            if (vi_insert(ch) != 0) {
  1242. X                x_putc(Ctrl('g'));
  1243. X                state = VNORMAL;
  1244. X            } else {
  1245. X                if (state == VLIT) {
  1246. X                    es->cursor--;
  1247. X                    refresh(0);
  1248. X                } else
  1249. X                    refresh(insert != 0);
  1250. X            }
  1251. X        } else {
  1252. X            cmdlen = 0;
  1253. X            argc1 = 0;
  1254. X            if (ch >= '1' && ch <= '9') {
  1255. X                argc1 = ch - '0';
  1256. X                state = VARG1;
  1257. X            } else {
  1258. X                curcmd[cmdlen++] = ch;
  1259. X                state = nextstate(ch);
  1260. X                if (state == VSEARCH) {
  1261. X                    save_cbuf();
  1262. X                    es->cursor = 0;
  1263. X                    es->linelen = 0;
  1264. X                    if (ch == '/') {
  1265. X                        if (putbuf("/", 1, 0) != 0) {
  1266. X                            return -1;
  1267. X                        }
  1268. X                    } else if (putbuf("?", 1, 0) != 0) 
  1269. X                            return -1;
  1270. X                    refresh(0);
  1271. X                }
  1272. X            }
  1273. X        }
  1274. X        break;
  1275. X
  1276. X    case VLIT:
  1277. X        if (isbad(ch)) {
  1278. X            del_range(es->cursor, es->cursor + 1);
  1279. X            x_putc(Ctrl('g'));
  1280. X        } else
  1281. X            es->cbuf[es->cursor++] = ch;
  1282. X        refresh(1);
  1283. X        state = VNORMAL;
  1284. X        break;
  1285. X
  1286. X    case VARG1:
  1287. X        if (isdigit(ch))
  1288. X            argc1 = argc1 * 10 + ch - '0';
  1289. X        else {
  1290. X            curcmd[cmdlen++] = ch;
  1291. X            state = nextstate(ch);
  1292. X        }
  1293. X        break;
  1294. X
  1295. X    case VEXTCMD:
  1296. X        argc2 = 0;
  1297. X        if (ch >= '1' && ch <= '9') {
  1298. X            argc2 = ch - '0';
  1299. X            state = VARG2;
  1300. X            return 0;
  1301. X        } else {
  1302. X            curcmd[cmdlen++] = ch;
  1303. X            if (ch == curcmd[0])
  1304. X                state = VCMD;
  1305. X            else if (ismove(ch))
  1306. X                state = nextstate(ch);
  1307. X            else
  1308. X                state = VFAIL;
  1309. X        }
  1310. X        break;
  1311. X
  1312. X    case VARG2:
  1313. X        if (isdigit(ch))
  1314. X            argc2 = argc2 * 10 + ch - '0';
  1315. X        else {
  1316. X            if (argc1 == 0)
  1317. X                argc1 = argc2;
  1318. X            else
  1319. X                argc1 *= argc2;
  1320. X            curcmd[cmdlen++] = ch;
  1321. X            if (ch == curcmd[0])
  1322. X                state = VCMD;
  1323. X            else if (ismove(ch))
  1324. X                state = nextstate(ch);
  1325. X            else
  1326. X                state = VFAIL;
  1327. X        }
  1328. X        break;
  1329. X
  1330. X    case VXCH:
  1331. X        if (ch == Ctrl('['))
  1332. X            state = VNORMAL;
  1333. X        else {
  1334. X            curcmd[cmdlen++] = ch;
  1335. X            state = VCMD;
  1336. X        }
  1337. X        break;
  1338. X
  1339. X    case VSEARCH:
  1340. X        switch (ch) {
  1341. X
  1342. X        /* case Ctrl('['): */
  1343. X        case '\r':
  1344. X        case '\n':
  1345. X            locpat[srchlen] = '\0';
  1346. X            (void) strcpy(srchpat, locpat);
  1347. X            /* redraw_line(); */
  1348. X            state = VCMD;
  1349. X            break;
  1350. X
  1351. X        case 0x7f:
  1352. X            if (srchlen == 0) {
  1353. X                restore_cbuf();
  1354. X                state = VNORMAL;
  1355. X            } else {
  1356. X                srchlen--;
  1357. X                if (locpat[srchlen] < ' ' ||
  1358. X                        locpat[srchlen] == 0x7f) {
  1359. X                    es->linelen--;
  1360. X                }
  1361. X                es->linelen--;
  1362. X                es->cursor = es->linelen;
  1363. X                refresh(0);
  1364. X                return 0;
  1365. X            }
  1366. X            refresh(0);
  1367. X            break;
  1368. X
  1369. X        case Ctrl('u'):
  1370. X            srchlen = 0;
  1371. X            es->linelen = 1;
  1372. X            es->cursor = 1;
  1373. X            refresh(0);
  1374. X            return 0;
  1375. X
  1376. X        default:
  1377. X            if (srchlen == SRCHLEN - 1)
  1378. X                x_putc(Ctrl('g'));
  1379. X            else {
  1380. X                locpat[srchlen++] = ch;
  1381. X                if (ch < ' ' || ch == 0x7f) {
  1382. X                    es->cbuf[es->linelen++] = '^';
  1383. X                    es->cbuf[es->linelen++] = ch ^ '@';
  1384. X                } else
  1385. X                    es->cbuf[es->linelen++] = ch;
  1386. X                es->cursor = es->linelen;
  1387. X                refresh(0);
  1388. X            }
  1389. X            return 0;
  1390. X            break;
  1391. X        }
  1392. X        break;
  1393. X    }
  1394. X    switch (state) {
  1395. X
  1396. X    case VCMD:
  1397. X        state = VNORMAL;
  1398. X        switch (vi_cmd(argc1, curcmd)) {
  1399. X        case -1:
  1400. X            x_putc(Ctrl('g'));
  1401. X            break;
  1402. X        case 0:
  1403. X            if (insert != 0)
  1404. X                inslen = 0;
  1405. X            refresh(insert != 0);
  1406. X            break;
  1407. X        case 1:
  1408. X            refresh(0);
  1409. X            x_putc('\r');
  1410. X            x_putc('\n');
  1411. X            x_flush();
  1412. X            return 1;
  1413. X        }
  1414. X        break;
  1415. X
  1416. X    case VREDO:
  1417. X        state = VNORMAL;
  1418. X        if (argc1 != 0)
  1419. X            lastac = argc1;
  1420. X        switch (vi_cmd(lastac, lastcmd) != 0) {
  1421. X        case -1:
  1422. X            x_putc(Ctrl('g'));
  1423. X            refresh(0);
  1424. X            break;
  1425. X        case 0:
  1426. X            if (insert != 0) {
  1427. X                if (lastcmd[0] == 's' || lastcmd[0] == 'c' ||
  1428. X                        lastcmd[0] == 'C') {
  1429. X                    if (redo_insert(1) != 0)
  1430. X                        x_putc(Ctrl('g'));
  1431. X                } else {
  1432. X                    if (redo_insert(lastac) != 0)
  1433. X                        x_putc(Ctrl('g'));
  1434. X                }
  1435. X            }
  1436. X            refresh(0);
  1437. X            break;
  1438. X        case 1:
  1439. X            refresh(0);
  1440. X            x_putc('\r');
  1441. X            x_putc('\n');
  1442. X            x_flush();
  1443. X            return 1;
  1444. X        }
  1445. X        break;
  1446. X
  1447. X    case VFAIL:
  1448. X        state = VNORMAL;
  1449. X        x_putc(Ctrl('g'));
  1450. X        break;
  1451. X    }
  1452. X    return 0;
  1453. X}
  1454. X
  1455. Xstatic int
  1456. Xnextstate(ch)
  1457. X    int    ch;
  1458. X{
  1459. X    /*
  1460. X     * probably could have been done more elegantly than
  1461. X     * by creating a new state, but it works
  1462. X     */
  1463. X    if (ch == 'r')
  1464. X        return VREPLACE1CHAR;
  1465. X    else if (isextend(ch))
  1466. X        return VEXTCMD;
  1467. X    else if (issrch(ch))
  1468. X        return VSEARCH;
  1469. X    else if (islong(ch))
  1470. X        return VXCH;
  1471. X    else if (ch == '.')
  1472. X        return VREDO;
  1473. X    else if (iscmd(ch))
  1474. X        return VCMD;
  1475. X    else
  1476. X        return VFAIL;
  1477. X}
  1478. X
  1479. Xstatic int
  1480. Xvi_insert(ch)
  1481. X    int    ch;
  1482. X{
  1483. X    int    tcursor;
  1484. X
  1485. X    switch (ch) {
  1486. X
  1487. X    case '\0':
  1488. X        return -1;
  1489. X
  1490. X    case Ctrl('['):
  1491. X        if (lastcmd[0] == 's' || lastcmd[0] == 'c' ||
  1492. X                lastcmd[0] == 'C')
  1493. X            return redo_insert(0);
  1494. X        else
  1495. X            return redo_insert(lastac - 1);
  1496. X
  1497. X    case 0x7f:        /* delete */
  1498. X        /* tmp fix */
  1499. X        /* general fix is to get stty erase char and use that
  1500. X        */
  1501. X    case Ctrl('H'):        /* delete */
  1502. X        if (es->cursor != 0) {
  1503. X            if (inslen > 0)
  1504. X                inslen--;
  1505. X            es->cursor--;
  1506. X            if (insert != REPLACE) {
  1507. X                bcopy(&es->cbuf[es->cursor+1],
  1508. X                        &es->cbuf[es->cursor],
  1509. X                        es->linelen - es->cursor);
  1510. X                es->linelen--;
  1511. X            }
  1512. X        }
  1513. X        break;
  1514. X
  1515. X    case Ctrl('U'):
  1516. X        if (es->cursor != 0) {
  1517. X            inslen = 0;
  1518. X            bcopy(&es->cbuf[es->cursor], es->cbuf,
  1519. X                        es->linelen - es->cursor);
  1520. X            es->linelen -= es->cursor;
  1521. X            es->cursor = 0;
  1522. X        }
  1523. X        break;
  1524. X
  1525. X    case Ctrl('W'):
  1526. X        if (es->cursor != 0) {
  1527. X            tcursor = backword(1);
  1528. X            bcopy(&es->cbuf[es->cursor], &es->cbuf[tcursor],
  1529. X                        es->linelen - es->cursor);
  1530. X            es->linelen -= es->cursor - tcursor;
  1531. X            if (inslen < es->cursor - tcursor)
  1532. X                inslen = 0;
  1533. X            else
  1534. X                inslen -= es->cursor - tcursor;
  1535. X            es->cursor = tcursor;
  1536. X        }
  1537. X        break;
  1538. X
  1539. X    default:
  1540. X        if (es->linelen == es->cbufsize - 1)
  1541. X            return -1;
  1542. X        ibuf[inslen++] = ch;
  1543. X        if (insert == INSERT) {
  1544. X            bcopy(&es->cbuf[es->cursor], &es->cbuf[es->cursor+1],
  1545. X                    es->linelen - es->cursor);
  1546. X            es->linelen++;
  1547. X        }
  1548. X        es->cbuf[es->cursor++] = ch;
  1549. X        if (insert == REPLACE && es->cursor > es->linelen)
  1550. X            es->linelen++;
  1551. X    }
  1552. X    return 0;
  1553. X}
  1554. X
  1555. Xstatic int
  1556. Xvi_cmd(argcnt, cmd)
  1557. X    int        argcnt;
  1558. X    char        *cmd;
  1559. X{
  1560. X    int        ncursor;
  1561. X    int        cur, c1, c2, c3 = 0;
  1562. X    char        pos[10];
  1563. X    struct edstate    *t;
  1564. X
  1565. X
  1566. X    if (argcnt == 0) {
  1567. X        if (*cmd == 'G')
  1568. X            argcnt = hlast + 1;
  1569. X        else if (*cmd != '_')
  1570. X            argcnt = 1;
  1571. X    }
  1572. X
  1573. X    if (ismove(*cmd)) {
  1574. X        if ((cur = domove(argcnt, cmd, 0)) >= 0) {
  1575. X            if (cur == es->linelen && cur != 0)
  1576. X                cur--;
  1577. X            es->cursor = cur;
  1578. X        } else
  1579. X            return -1;
  1580. X    } else {
  1581. X        if (isundoable(*cmd)) {
  1582. X            undo->winleft = es->winleft;
  1583. X            bcopy(es->cbuf, undo->cbuf, es->linelen);
  1584. X            undo->linelen = es->linelen;
  1585. X            undo->cursor = es->cursor;
  1586. X            lastac = argcnt;
  1587. X            bcopy(cmd, lastcmd, MAXVICMD);
  1588. X        }
  1589. X        switch (*cmd) {
  1590. X
  1591. X        case Ctrl('r'):
  1592. X            redraw_line();
  1593. X            break;
  1594. X
  1595. X        case 'a':
  1596. X            modified = 1;
  1597. X            if (es->linelen != 0)
  1598. X                es->cursor++;
  1599. X            insert = INSERT;
  1600. X            break;
  1601. X
  1602. X        case 'A':
  1603. X            modified = 1;
  1604. X            del_range(0, 0);
  1605. X            es->cursor = es->linelen;
  1606. X            insert = INSERT;
  1607. X            break;
  1608. X
  1609. X        case 'c':
  1610. X        case 'd':
  1611. X        case 'y':
  1612. X            if (*cmd == cmd[1]) {
  1613. X                c1 = 0;
  1614. X                c2 = es->linelen;
  1615. X            } else if (!ismove(cmd[1]))
  1616. X                return -1;
  1617. X            else {
  1618. X                if ((ncursor = domove(argcnt, &cmd[1], 1)) < 0)
  1619. X                    return -1;
  1620. X                if (*cmd == 'c' &&
  1621. X                        (cmd[1]=='w' || cmd[1]=='W') &&
  1622. X                        !isspace(es->cbuf[es->cursor])) {
  1623. X                    while (isspace(es->cbuf[--ncursor]))
  1624. X                        ;
  1625. X                    ncursor++;
  1626. X                }
  1627. X                if (ncursor > es->cursor) {
  1628. X                    c1 = es->cursor;
  1629. X                    c2 = ncursor;
  1630. X                } else {
  1631. X                    c1 = ncursor;
  1632. X                    c2 = es->cursor;
  1633. X                }
  1634. X            }
  1635. X            if (*cmd != 'c' && c1 != c2)
  1636. X                yank_range(c1, c2);
  1637. X            if (*cmd != 'y') {
  1638. X                del_range(c1, c2);
  1639. X                es->cursor = c1;
  1640. X            }
  1641. X            if (*cmd == 'c') {
  1642. X                modified = 1;
  1643. X                insert = INSERT;
  1644. X            }
  1645. X            break;
  1646. X
  1647. X        case 'p':
  1648. X            modified = 1;
  1649. X            if (es->linelen != 0)
  1650. X                es->cursor++;
  1651. X            while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0)
  1652. X                ;
  1653. X            if (es->cursor != 0)
  1654. X                es->cursor--;
  1655. X            if (argcnt != 0)
  1656. X                return -1;
  1657. X            break;
  1658. X
  1659. X        case 'P':
  1660. X            modified = 1;
  1661. X            while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0)
  1662. X                ;
  1663. X            if (es->cursor != 0)
  1664. X                es->cursor--;
  1665. X            if (argcnt != 0)
  1666. X                return -1;
  1667. X            break;
  1668. X
  1669. X        case 'C':
  1670. X            modified = 1;
  1671. X            del_range(es->cursor, es->linelen);
  1672. X            insert = INSERT;
  1673. X            break;
  1674. X
  1675. X        case 'D':
  1676. X            yank_range(es->cursor, es->linelen);
  1677. X            del_range(es->cursor, es->linelen);
  1678. X            if (es->cursor != 0)
  1679. X                es->cursor--;
  1680. X            break;
  1681. X
  1682. X        case 'G':
  1683. X            if (grabhist(modified, argcnt - 1) < 0)
  1684. X                return -1;
  1685. X            else {
  1686. X                modified = 0;
  1687. X                hnum = argcnt - 1;
  1688. X            }
  1689. X            break;
  1690. X
  1691. X        case 'i':
  1692. X            modified = 1;
  1693. X            insert = INSERT;
  1694. X            break;
  1695. X
  1696. X        case 'I':
  1697. X            modified = 1;
  1698. X            es->cursor = 0;
  1699. X            insert = INSERT;
  1700. X            break;
  1701. X
  1702. X        case '+':
  1703. X        case 'j':
  1704. X            if (grabhist(modified, hnum + argcnt) < 0)
  1705. X                return -1;
  1706. X            else {
  1707. X                modified = 0;
  1708. X                hnum += argcnt;
  1709. X            }
  1710. X            break;
  1711. X
  1712. X        case '-':
  1713. X        case 'k':
  1714. X            if (grabhist(modified, hnum - argcnt) < 0)
  1715. X                return -1;
  1716. X            else {
  1717. X                modified = 0;
  1718. X                hnum -= argcnt;
  1719. X            }
  1720. X            break;
  1721. X
  1722. X        case 'r':
  1723. X            if (es->linelen == 0)
  1724. X                return -1;
  1725. X            modified = 1;
  1726. X            es->cbuf[es->cursor] = cmd[1];
  1727. X            break;
  1728. X
  1729. X        case 'R':
  1730. X            modified = 1;
  1731. X            insert = REPLACE;
  1732. X            break;
  1733. X
  1734. X        case 's':
  1735. X            if (es->linelen == 0)
  1736. X                return -1;
  1737. X            modified = 1;
  1738. X            if (es->cursor + argcnt > es->linelen)
  1739. X                argcnt = es->linelen - es->cursor;
  1740. X            del_range(es->cursor, es->cursor + argcnt);
  1741. X            insert = INSERT;
  1742. X            break;
  1743. X
  1744. X        case 'x':
  1745. X            if (es->linelen == 0)
  1746. X                return -1;
  1747. X            modified = 1;
  1748. X            if (es->cursor + argcnt > es->linelen)
  1749. X                argcnt = es->linelen - es->cursor;
  1750. X            yank_range(es->cursor, es->cursor + argcnt);
  1751. X            del_range(es->cursor, es->cursor + argcnt);
  1752. X            break;
  1753. X
  1754. X        case 'X':
  1755. X            if (es->cursor > 0) {
  1756. X                modified = 1;
  1757. X                if (es->cursor < argcnt)
  1758. X                    argcnt = es->cursor;
  1759. X                yank_range(es->cursor - argcnt, es->cursor);
  1760. X                del_range(es->cursor - argcnt, es->cursor);
  1761. X                es->cursor -= argcnt;
  1762. X            } else
  1763. X                return -1;
  1764. X            break;
  1765. X
  1766. X        case 'u':
  1767. X            t = es;
  1768. X            es = undo;
  1769. X            undo = t;
  1770. X            break;
  1771. X
  1772. X        case '?':
  1773. X            hnum = -1;
  1774. X            /* ahhhhhh... */
  1775. X        case '/':
  1776. X            c3 = 1;
  1777. X            srchlen = 0;
  1778. X            lastsearch = *cmd;
  1779. X            /* fall through */
  1780. X        case 'n':
  1781. X        case 'N':
  1782. X            if (lastsearch == ' ')
  1783. X                return -1;
  1784. X            if (lastsearch == '?')
  1785. X                c1 = 1; 
  1786. X            else
  1787. X                c1 = 0;
  1788. X            if (*cmd == 'N')
  1789. X                c1 = !c1;
  1790. X            if ((c2 = grabsearch(modified, hnum,
  1791. X                            c1, srchpat)) < 0) {
  1792. X                if (c3) {
  1793. X                    restore_cbuf();
  1794. X                    refresh(0);
  1795. X                }
  1796. X                return -1;
  1797. X            } else {
  1798. X                modified = 0;
  1799. X                hnum = c2;
  1800. X            }
  1801. X            break;
  1802. X        case '_': {
  1803. X            int    space;
  1804. X            char    *p, *sp;
  1805. X
  1806. X            (void) histnum(-1);
  1807. X            p = *histpos();
  1808. X#define issp(c)        (isspace((c)) || (c) == '\n')
  1809. X            if (argcnt) {
  1810. X                while (*p && issp(*p))
  1811. X                    p++;
  1812. X                while (*p && --argcnt) {
  1813. X                    while (*p && !issp(*p))
  1814. X                        p++;
  1815. X                    while (*p && issp(*p))
  1816. X                        p++;
  1817. X                }
  1818. X                if (!*p)
  1819. X                    return -1;
  1820. X                sp = p;
  1821. X            } else {
  1822. X                sp = p;
  1823. X                space = 0;
  1824. X                while (*p) {
  1825. X                    if (issp(*p))
  1826. X                        space = 1;
  1827. X                    else if (space) {
  1828. X                        space = 0;
  1829. X                        sp = p;
  1830. X                    }
  1831. X                    p++;
  1832. X                }
  1833. X                p = sp;
  1834. X            }
  1835. X            modified = 1;
  1836. X            if (es->linelen != 0)
  1837. X                es->cursor++;
  1838. X            while (*p && !issp(*p)) {
  1839. X                argcnt++;
  1840. X                p++;
  1841. X            }
  1842. X            if (putbuf(" ", 1, 0) != 0)
  1843. X                argcnt = -1;
  1844. X            else if (putbuf(sp, argcnt, 0) != 0)
  1845. X                argcnt = -1;
  1846. X            if (argcnt < 0) {
  1847. X                if (es->cursor != 0)
  1848. X                    es->cursor--;
  1849. X                return -1;
  1850. X            }
  1851. X            insert = INSERT;
  1852. X            }
  1853. X            break;
  1854. X
  1855. X        case '~': {
  1856. X            char    *p;
  1857. X
  1858. X            if (es->linelen == 0)
  1859. X                return -1;
  1860. X            p = &es->cbuf[es->cursor];
  1861. X            if (islower(*p)) {
  1862. X                modified = 1;
  1863. X                *p = toupper(*p);
  1864. X            } else if (isupper(*p)) {
  1865. X                modified = 1;
  1866. X                *p = tolower(*p);
  1867. X            }
  1868. X            if (es->cursor < es->linelen - 1)
  1869. X                es->cursor++;
  1870. X            }
  1871. X            break;
  1872. X
  1873. X        case '#':
  1874. X            es->cursor = 0;
  1875. X            if (putbuf("#", 1, 0) != 0)
  1876. X                return -1;
  1877. X            return 1;
  1878. X
  1879. X        case '*': {
  1880. X            int    rval = 0;
  1881. X            int    start, end;
  1882. X            char    *toglob = undo->cbuf;
  1883. X            char    **ap;
  1884. X            char    **ap2;
  1885. X            char    **globstr();
  1886. X
  1887. X            if (isspace(es->cbuf[es->cursor]))
  1888. X                return -1;
  1889. X            start = es->cursor;
  1890. X            while (start > -1 && !isspace(es->cbuf[start]))
  1891. X                start--;
  1892. X            start++;
  1893. X            end = es->cursor;
  1894. X            while (end < es->linelen && !isspace(es->cbuf[end]))
  1895. X                end++;
  1896. X            /* use undo buffer to build word up in */
  1897. X            bcopy(&es->cbuf[start], toglob, end-start);
  1898. X            if (*toglob != '~' && toglob[end-start-1] != '*') {
  1899. X                toglob[end-start] = '*';
  1900. X                toglob[end-start+1] = '\0';
  1901. X            } else
  1902. X                toglob[end-start] = '\0';
  1903. X            ap = globstr(toglob);
  1904. X            ap2 = ap;
  1905. X            if (strcmp(ap[0], toglob) == 0 && ap[1] == (char *) 0)
  1906. X                rval = -1;
  1907. X            /* restore undo buffer that we used temporarily */
  1908. X            bcopy(es->cbuf, toglob, es->linelen);
  1909. X            if (rval < 0)
  1910. X                return rval;
  1911. X            del_range(start, end);
  1912. X            es->cursor = start;
  1913. X            while (1) {
  1914. X                if (putbuf(*ap, strlen(*ap), 0) != 0) {
  1915. X                    rval = -1;
  1916. X                    break;
  1917. X                }
  1918. X                if (*++ap == (char *) 0)
  1919. X                    break;
  1920. X                if (putbuf(" ", 1, 0) != 0) {
  1921. X                    rval = -1;
  1922. X                    break;
  1923. X                }
  1924. X            }
  1925. X#if 0
  1926. X            /*
  1927. X             * this is definitely wrong
  1928. X             */
  1929. X            for (ap = ap2; *ap; ap++)
  1930. X                free(*ap);
  1931. X
  1932. X            free(ap2);
  1933. X#endif
  1934. X
  1935. X            modified = 1;
  1936. X            insert = INSERT;
  1937. X            refresh(0);
  1938. X            if (rval != 0)
  1939. X                return rval;
  1940. X            }
  1941. X            break;
  1942. X        }
  1943. X        if (insert == 0 && es->cursor != 0 && es->cursor >= es->linelen)
  1944. X            es->cursor--;
  1945. X    }
  1946. X    return 0;
  1947. X}
  1948. X
  1949. Xstatic int
  1950. Xdomove(argcnt, cmd, sub)
  1951. X    int    argcnt;
  1952. X    char    *cmd;
  1953. X    int    sub;
  1954. X{
  1955. X    int    bcount, i = 0, t;    /* = 0 kludge for gcc -W */
  1956. X    int    ncursor = 0;        /* = 0 kludge for gcc -W */
  1957. X
  1958. X    switch (*cmd) {
  1959. X
  1960. X    case 'b':
  1961. X        if (!sub && es->cursor == 0)
  1962. X            return -1;
  1963. X        ncursor = backword(argcnt);
  1964. X        break;
  1965. X
  1966. X    case 'B':
  1967. X        if (!sub && es->cursor == 0)
  1968. X            return -1;
  1969. X        ncursor = Backword(argcnt);
  1970. X        break;
  1971. X
  1972. X    case 'e':
  1973. X        if (!sub && es->cursor + 1 >= es->linelen)
  1974. X            return -1;
  1975. X        ncursor = endword(argcnt);
  1976. X        if (sub)
  1977. X            ncursor++;
  1978. X        break;
  1979. X
  1980. X    case 'E':
  1981. X        if (!sub && es->cursor + 1 >= es->linelen)
  1982. X            return -1;
  1983. X        ncursor = Endword(argcnt);
  1984. X        if (sub)
  1985. X            ncursor++;
  1986. X        break;
  1987. X
  1988. X    case 'f':
  1989. X    case 'F':
  1990. X    case 't':
  1991. X    case 'T':
  1992. X        fsavecmd = *cmd;
  1993. X        fsavech = cmd[1];
  1994. X        /* drop through */
  1995. X
  1996. X    case ',':
  1997. X    case ';':
  1998. X        if (fsavecmd == ' ')
  1999. X            return -1;
  2000. X        i = fsavecmd == 'f' || fsavecmd == 'F';
  2001. X        t = fsavecmd > 'a';
  2002. X        if (*cmd == ',')
  2003. X            t = !t;
  2004. X        if ((ncursor = findch(fsavech, argcnt, t, i)) < 0)
  2005. X            return -1;
  2006. X        if (sub && t)
  2007. X            ncursor++;
  2008. X        break;
  2009. X
  2010. X    case 'h':
  2011. X        /* tmp fix */
  2012. X    case Ctrl('H'):
  2013. X        if (!sub && es->cursor == 0)
  2014. X            return -1;
  2015. X        ncursor = es->cursor - argcnt;
  2016. X        if (ncursor < 0)
  2017. X            ncursor = 0;
  2018. X        break;
  2019. X
  2020. X    case ' ':
  2021. X    case 'l':
  2022. X        if (!sub && es->cursor + 1 >= es->linelen)
  2023. X            return -1;
  2024. X        if (es->linelen != 0) {
  2025. X            ncursor = es->cursor + argcnt;
  2026. X            if (ncursor >= es->linelen)
  2027. X                ncursor = es->linelen - 1;
  2028. X        }
  2029. X        break;
  2030. X
  2031. X    case 'w':
  2032. X        if (!sub && es->cursor + 1 >= es->linelen)
  2033. X            return -1;
  2034. X        ncursor = forwword(argcnt);
  2035. X        break;
  2036. X
  2037. X    case 'W':
  2038. X        if (!sub && es->cursor + 1 >= es->linelen)
  2039. X            return -1;
  2040. X        ncursor = Forwword(argcnt);
  2041. X        break;
  2042. X
  2043. X    case '0':
  2044. X        ncursor = 0;
  2045. X        break;
  2046. X
  2047. X    case '^':
  2048. X        ncursor = 0;
  2049. X        while (ncursor < es->linelen - 1 && isspace(es->cbuf[ncursor]))
  2050. X            ncursor++;
  2051. X        break;
  2052. X
  2053. X    case '$':
  2054. X        if (es->linelen != 0)
  2055. X            ncursor = es->linelen;
  2056. X        else
  2057. X            ncursor = 0;
  2058. X        break;
  2059. X
  2060. X    case '%':
  2061. X        ncursor = es->cursor;
  2062. X        while (ncursor < es->linelen &&
  2063. X                (i = bracktype(es->cbuf[ncursor])) == 0)
  2064. X            ncursor++;
  2065. X        if (ncursor == es->linelen)
  2066. X            return -1;
  2067. X        bcount = 1;
  2068. X        do {
  2069. X            if (i > 0) {
  2070. X                if (++ncursor >= es->linelen)
  2071. X                    return -1;
  2072. X            } else {
  2073. X                if (--ncursor < 0)
  2074. X                    return -1;
  2075. X            }
  2076. X            t = bracktype(es->cbuf[ncursor]);
  2077. X            if (t == i)
  2078. X                bcount++;
  2079. X            else if (t == -i)
  2080. X                bcount--;
  2081. X        } while (bcount != 0);
  2082. X        if (sub)
  2083. X            ncursor++;
  2084. X        break;
  2085. X
  2086. X    default:
  2087. X        return -1;
  2088. X    }
  2089. X    return ncursor;
  2090. X}
  2091. X
  2092. Xstatic int
  2093. Xredo_insert(count)
  2094. X    int    count;
  2095. X{
  2096. X    while (count-- > 0)
  2097. X        if (putbuf(ibuf, inslen, insert==REPLACE) != 0)
  2098. X            return -1;
  2099. X    if (es->cursor > 0)
  2100. X        es->cursor--;
  2101. X    insert = 0;
  2102. X    return 0;
  2103. X}
  2104. X
  2105. Xstatic
  2106. Xyank_range(a, b)
  2107. X    int    a, b;
  2108. X{
  2109. X    yanklen = b - a;
  2110. X    if (yanklen != 0)
  2111. X        bcopy(&es->cbuf[a], ybuf, yanklen);
  2112. X}
  2113. X
  2114. Xstatic int
  2115. Xbracktype(ch)
  2116. X    int    ch;
  2117. X{
  2118. X    switch (ch) {
  2119. X
  2120. X    case '(':
  2121. X        return 1;
  2122. X
  2123. X    case '[':
  2124. X        return 2;
  2125. X
  2126. X    case '{':
  2127. X        return 3;
  2128. X
  2129. X    case ')':
  2130. X        return -1;
  2131. X
  2132. X    case ']':
  2133. X        return -2;
  2134. X
  2135. X    case '}':
  2136. X        return -3;
  2137. X
  2138. X    default:
  2139. X        return 0;
  2140. X    }
  2141. X}
  2142. X
  2143. X/*
  2144. X *    Non user interface editor routines below here
  2145. X */
  2146. X
  2147. Xstatic int    cur_col;        /* current column on line */
  2148. Xstatic int    pwidth;            /* width of prompt */
  2149. Xstatic int    winwidth;        /* width of window */
  2150. X/*static char    *wbuf[2];        /* window buffers */
  2151. Xstatic char    wbuf[2][80-3];    /* window buffers */ /* TODO */
  2152. Xstatic int    win;            /* window buffer in use */
  2153. Xstatic char    morec;            /* more character at right of window */
  2154. Xstatic int    lastref;        /* argument to last refresh() */
  2155. Xstatic char    holdbuf[CMDLEN];    /* place to hold last edit buffer */
  2156. Xstatic int    holdlen;        /* length of holdbuf */
  2157. X
  2158. Xsave_cbuf()
  2159. X{
  2160. X    bcopy(es->cbuf, holdbuf, es->linelen);
  2161. X    holdlen = es->linelen;
  2162. X    holdbuf[holdlen] = '\0';
  2163. X}
  2164. X
  2165. Xrestore_cbuf()
  2166. X{
  2167. X    es->cursor = 0;
  2168. X    es->linelen = holdlen;
  2169. X    bcopy(holdbuf, es->cbuf, holdlen);
  2170. X}
  2171. X
  2172. Xstatic
  2173. Xedit_reset(buf, len)
  2174. X    char    *buf;
  2175. X    int    len;
  2176. X{
  2177. X    es = &ebuf;
  2178. X    es->cbuf = buf;
  2179. X    es->cbufsize = len;
  2180. X    undo = &undobuf;
  2181. X    undo->cbufsize = len;
  2182. X
  2183. X    es->linelen = undo->linelen = 0;
  2184. X    es->cursor = undo->cursor = 0;
  2185. X    es->winleft = undo->winleft = 0;
  2186. X
  2187. X    cur_col = pwidth = promptlen(prompt);
  2188. X    winwidth = x_cols - pwidth - 3;
  2189. X    x_putc('\r');
  2190. X    x_flush();
  2191. X    pprompt(prompt);
  2192. X    /* docap(CLR_EOL, 0); */
  2193. X    win = 0;
  2194. X    morec = ' ';
  2195. X    lastref = 1;
  2196. X}
  2197. X
  2198. Xstatic int
  2199. Xputbuf(buf, len, repl)
  2200. X    char    *buf;
  2201. X    int    len;
  2202. X    int    repl;
  2203. X{
  2204. X    if (len == 0)
  2205. X        return 0;
  2206. X    if (repl) {
  2207. X        if (es->cursor + len >= es->cbufsize - 1)
  2208. X            return -1;
  2209. X        if (es->cursor + len > es->linelen)
  2210. X            es->linelen = es->cursor + len;
  2211. X    } else {
  2212. X        if (es->linelen + len >= es->cbufsize - 1)
  2213. X            return -1;
  2214. X        bcopy(&es->cbuf[es->cursor], &es->cbuf[es->cursor + len],
  2215. X            es->linelen - es->cursor);
  2216. X        es->linelen += len;
  2217. X    }
  2218. X    bcopy(buf, &es->cbuf[es->cursor], len);
  2219. X    es->cursor += len;
  2220. X    return 0;
  2221. X}
  2222. X
  2223. Xstatic
  2224. Xstripblanks()
  2225. X{
  2226. X    int    ncursor;
  2227. X
  2228. X    ncursor = 0;
  2229. X    while (ncursor < es->linelen && isspace(es->cbuf[ncursor]))
  2230. X        ncursor++;
  2231. X    del_range(0, ncursor);
  2232. X}
  2233. X
  2234. Xstatic
  2235. Xdel_range(a, b)
  2236. X    int    a, b;
  2237. X{
  2238. X    if (es->linelen != b)
  2239. X        bcopy(&es->cbuf[b], &es->cbuf[a], es->linelen - b);
  2240. X    es->linelen -= b - a;
  2241. X}
  2242. X
  2243. Xstatic int
  2244. Xfindch(ch, cnt, forw, incl)
  2245. X    int    ch;
  2246. X    int    forw;
  2247. X    int    incl;
  2248. X{
  2249. X    int    ncursor;
  2250. X
  2251. X    if (es->linelen == 0)
  2252. X        return -1;
  2253. X    ncursor = es->cursor;
  2254. X    while (cnt--) {
  2255. X        do {
  2256. X            if (forw) {
  2257. X                if (++ncursor == es->linelen)
  2258. X                    return -1;
  2259. X            } else {
  2260. X                if (--ncursor < 0)
  2261. X                    return -1;
  2262. X            }
  2263. X        } while (es->cbuf[ncursor] != ch);
  2264. X    }
  2265. X    if (!incl) {
  2266. X        if (forw)
  2267. X            ncursor--;
  2268. X        else
  2269. X            ncursor++;
  2270. X    }
  2271. X    return ncursor;
  2272. X}
  2273. X
  2274. X#define Isalnum(x) (isalnum(x) || (x == '_'))
  2275. Xstatic int
  2276. Xforwword(argcnt)
  2277. X    int    argcnt;
  2278. X{
  2279. X    int    ncursor;
  2280. X
  2281. X    ncursor = es->cursor;
  2282. X    while (ncursor < es->linelen && argcnt--) {
  2283. X        if (Isalnum(es->cbuf[ncursor]))
  2284. X            while (Isalnum(es->cbuf[ncursor]) &&
  2285. X                    ++ncursor < es->linelen)
  2286. X                ;
  2287. X        else if (!isspace(es->cbuf[ncursor]))
  2288. X            while (!Isalnum(es->cbuf[ncursor]) &&
  2289. X                    !isspace(es->cbuf[ncursor]) &&
  2290. X                    ++ncursor < es->linelen)
  2291. X                ;
  2292. X        while (isspace(es->cbuf[ncursor]) && ++ncursor < es->linelen)
  2293. X            ;
  2294. X    }
  2295. X    return ncursor;
  2296. X}
  2297. X
  2298. Xstatic int
  2299. Xbackword(argcnt)
  2300. X    int    argcnt;
  2301. X{
  2302. X    int    ncursor;
  2303. X
  2304. X    ncursor = es->cursor;
  2305. X    while (ncursor > 0 && argcnt--) {
  2306. X        while (--ncursor > 0 && isspace(es->cbuf[ncursor]))
  2307. X            ;
  2308. X        if (ncursor > 0) {
  2309. X            if (Isalnum(es->cbuf[ncursor]))
  2310. X                while (--ncursor >= 0 &&
  2311. X                   Isalnum(es->cbuf[ncursor]))
  2312. X                    ;
  2313. X            else
  2314. X                while (--ncursor >= 0 &&
  2315. X                   !Isalnum(es->cbuf[ncursor]) &&
  2316. X                   !isspace(es->cbuf[ncursor]))
  2317. X                    ;
  2318. X            ncursor++;
  2319. X        }
  2320. X    }
  2321. X    return ncursor;
  2322. X}
  2323. X
  2324. Xstatic int
  2325. Xendword(argcnt)
  2326. X    int    argcnt;
  2327. X{
  2328. X    int    ncursor;
  2329. X
  2330. X    ncursor = es->cursor;
  2331. X    while (ncursor < es->linelen && argcnt--) {
  2332. X        while (++ncursor < es->linelen - 1 &&
  2333. X                isspace(es->cbuf[ncursor]))
  2334. X            ;
  2335. X        if (ncursor < es->linelen - 1) {
  2336. X            if (Isalnum(es->cbuf[ncursor]))
  2337. X                while (++ncursor < es->linelen &&
  2338. X                      Isalnum(es->cbuf[ncursor]))
  2339. X                    ;
  2340. X            else
  2341. X                while (++ncursor < es->linelen &&
  2342. X                   !Isalnum(es->cbuf[ncursor]) &&
  2343. X                   !isspace(es->cbuf[ncursor]))
  2344. X                    ;
  2345. X            ncursor--;
  2346. X        }
  2347. X    }
  2348. X    return ncursor;
  2349. X}
  2350. X
  2351. Xstatic int
  2352. XForwword(argcnt)
  2353. X    int    argcnt;
  2354. X{
  2355. X    int    ncursor;
  2356. X
  2357. X    ncursor = es->cursor;
  2358. X    while (ncursor < es->linelen && argcnt--) {
  2359. X        while (!isspace(es->cbuf[ncursor]) && ++ncursor < es->linelen)
  2360. X            ;
  2361. X        while (isspace(es->cbuf[ncursor]) && ++ncursor < es->linelen)
  2362. X            ;
  2363. X    }
  2364. X    return ncursor;
  2365. X}
  2366. X
  2367. Xstatic int
  2368. XBackword(argcnt)
  2369. X    int    argcnt;
  2370. X{
  2371. X    int    ncursor;
  2372. X
  2373. X    ncursor = es->cursor;
  2374. X    while (ncursor > 0 && argcnt--) {
  2375. X        while (--ncursor >= 0 && isspace(es->cbuf[ncursor]))
  2376. X            ;
  2377. X        while (ncursor >= 0 && !isspace(es->cbuf[ncursor]))
  2378. X            ncursor--;
  2379. X        ncursor++;
  2380. X    }
  2381. X    return ncursor;
  2382. X}
  2383. X
  2384. Xstatic int
  2385. XEndword(argcnt)
  2386. X    int    argcnt;
  2387. X{
  2388. X    int    ncursor;
  2389. X
  2390. X    ncursor = es->cursor;
  2391. X    while (ncursor < es->linelen - 1 && argcnt--) {
  2392. X        while (++ncursor < es->linelen - 1 &&
  2393. X                isspace(es->cbuf[ncursor]))
  2394. X            ;
  2395. X        if (ncursor < es->linelen - 1) {
  2396. X            while (++ncursor < es->linelen &&
  2397. X                    !isspace(es->cbuf[ncursor]))
  2398. X                ;
  2399. X            ncursor--;
  2400. X        }
  2401. X    }
  2402. X    return ncursor;
  2403. X}
  2404. X
  2405. Xstatic int
  2406. Xgrabhist(save, n)
  2407. X    int    save;
  2408. X    int    n;
  2409. X{
  2410. X    char    *hptr;
  2411. X    char    pos[10];
  2412. X
  2413. X    if (n < 0 || n > hlast)
  2414. X        return -1;
  2415. X    if (n == hlast) {
  2416. X        restore_cbuf();
  2417. X        return 0;
  2418. X    }
  2419. X    (void) histnum(n);
  2420. X    if ((hptr = *histpos()) == NULL) {
  2421. X        shellf("grabhist: bad history array\n");
  2422. X        return -1;
  2423. X    }
  2424. X    if (save)
  2425. X        save_cbuf();
  2426. X    es->linelen = strlen(hptr);
  2427. X    bcopy(hptr, es->cbuf, es->linelen);
  2428. X    es->cursor = 0;
  2429. X    return 0;
  2430. X}
  2431. X
  2432. Xstatic int
  2433. Xgrabsearch(save, start, fwd, pat)
  2434. X    int    save, start, fwd;
  2435. X    char    *pat;
  2436. X{
  2437. X    char    *hptr;
  2438. X
  2439. X    if ((start == 0 && fwd == 0) || (start >= hlast - 1 && fwd == 1))
  2440. X        return -1;
  2441. X    if ((hptr = findhist(start, fwd, pat)) == NULL) {
  2442. X        /* if (start != 0 && fwd && match(holdbuf, pat) >= 0) { */
  2443. X        if (start != 0 && fwd && strcmp(holdbuf, pat) >= 0) {
  2444. X            restore_cbuf();
  2445. X            return 0;
  2446. X        } else
  2447. X            return -1;
  2448. X    } else if (hptr == (char *)-1) {
  2449. X        return -1;
  2450. X    }
  2451. X    if (save)
  2452. X        save_cbuf();
  2453. X    es->linelen = strlen(hptr);
  2454. X    bcopy(hptr, es->cbuf, es->linelen);
  2455. X    es->cursor = 0;
  2456. X    return histN();
  2457. X}
  2458. X
  2459. Xstatic
  2460. Xredraw_line()
  2461. X{
  2462. X    x_putc('\r');
  2463. X    x_putc('\n');
  2464. X    x_flush();
  2465. X    pprompt(prompt);
  2466. X    cur_col = 2;
  2467. X    morec = ' ';
  2468. X}
  2469. X
  2470. Xstatic
  2471. Xrefresh(leftside)
  2472. X    int        leftside;
  2473. X{
  2474. X    if (leftside < 0)
  2475. X        leftside = lastref;
  2476. X    else
  2477. X        lastref = leftside;
  2478. X    if (outofwin())
  2479. X        rewindow();
  2480. X    display(wbuf[1 - win], wbuf[win], leftside);
  2481. X    win = 1 - win;
  2482. X}
  2483. X
  2484. Xstatic int
  2485. Xoutofwin()
  2486. X{
  2487. X    int    cur, col;
  2488. X
  2489. X    if (es->cursor < es->winleft)
  2490. X        return 1;
  2491. X    col = 0;
  2492. X    cur = es->winleft;
  2493. X    while (cur < es->cursor)
  2494. X        col = newcol(es->cbuf[cur++], col);
  2495. X    if (col > winwidth)
  2496. X        return 1;
  2497. X    return 0;
  2498. X}
  2499. X
  2500. Xstatic
  2501. Xrewindow()
  2502. X{
  2503. X    register int    tcur, tcol;
  2504. X    int        holdcur1, holdcol1;
  2505. X    int        holdcur2, holdcol2;
  2506. X
  2507. X    holdcur1 = holdcur2 = tcur = 0;
  2508. X    holdcol1 = holdcol2 = tcol = 0;
  2509. X    while (tcur < es->cursor) {
  2510. X        if (tcol - holdcol2 > winwidth / 2) {
  2511. X            holdcur1 = holdcur2;
  2512. X            holdcol1 = holdcol2;
  2513. X            holdcur2 = tcur;
  2514. X            holdcol2 = tcol;
  2515. X        }
  2516. X        tcol = newcol(es->cbuf[tcur++], tcol);
  2517. X    }
  2518. X    while (tcol - holdcol1 > winwidth / 2)
  2519. X        holdcol1 = newcol(es->cbuf[holdcur1++], holdcol1);
  2520. X    es->winleft = holdcur1;
  2521. X}
  2522. X
  2523. Xstatic int
  2524. Xnewcol(ch, col)
  2525. X    int    ch, col;
  2526. X{
  2527. X    if (ch < ' ' || ch == 0x7f) {
  2528. X        if (ch == '\t')
  2529. X            return (col | 7) + 1;
  2530. X        else
  2531. X            return col + 2;
  2532. X    } else
  2533. X        return col + 1;
  2534. X}
  2535. X
  2536. Xstatic
  2537. Xdisplay(wb1, wb2, leftside)
  2538. X    char    *wb1, *wb2;
  2539. X    int    leftside;
  2540. X{
  2541. X    char    *twb1, *twb2, mc;
  2542. X    int    cur, col, cnt;
  2543. X    int    ncol = 0; /* set to 0 kludge for gcc -W */
  2544. X    int    moreright;
  2545. X
  2546. X    col = 0;
  2547. X    cur = es->winleft;
  2548. X    moreright = 0;
  2549. X    twb1 = wb1;
  2550. X    while (col < winwidth && cur < es->linelen) {
  2551. X        if (cur == es->cursor && leftside)
  2552. X            ncol = col + pwidth;
  2553. X        if (es->cbuf[cur] < ' ' || es->cbuf[cur] == 0x7f) {
  2554. X            if (es->cbuf[cur] == '\t') {
  2555. X                do {
  2556. X                    *twb1++ = ' ';
  2557. X                } while (++col < winwidth && (col & 7) != 0);
  2558. X            } else {
  2559. X                *twb1++ = '^';
  2560. X                if (++col < winwidth) {
  2561. X                    *twb1++ = es->cbuf[cur] ^ '@';
  2562. X                    col++;
  2563. X                }
  2564. X            }
  2565. X        } else {
  2566. X            *twb1++ = es->cbuf[cur];
  2567. X            col++;
  2568. X        }
  2569. X        if (cur == es->cursor && !leftside)
  2570. X            ncol = col + pwidth - 1;
  2571. X        cur++;
  2572. X    }
  2573. X    if (cur == es->cursor)
  2574. X        ncol = col + pwidth;
  2575. X    if (col < winwidth) {
  2576. X        while (col < winwidth) {
  2577. X            *twb1++ = ' ';
  2578. X            col++;
  2579. X        }
  2580. X    } else
  2581. X        moreright++;
  2582. X    *twb1 = ' ';
  2583. X
  2584. X    col = pwidth;
  2585. X    cnt = winwidth;
  2586. X    twb1 = wb1;
  2587. X    twb2 = wb2;
  2588. X    while (cnt--) {
  2589. X        if (*twb1 != *twb2) {
  2590. X            if (cur_col != col)
  2591. X                ed_mov_opt(col, wb1);
  2592. X            x_putc(*twb1);
  2593. X            cur_col++;
  2594. X        }
  2595. X        twb1++;
  2596. X        twb2++;
  2597. X        col++;
  2598. X    }
  2599. X    if (es->winleft > 0 && moreright)
  2600. X        mc = '+';
  2601. X    else if (es->winleft > 0)
  2602. X        mc = '<';
  2603. X    else if (moreright)
  2604. X        mc = '>';
  2605. X    else
  2606. X        mc = ' ';
  2607. X    if (mc != morec) {
  2608. X        ed_mov_opt(x_cols - 2, wb1);
  2609. X        x_putc(mc);
  2610. X        cur_col++;
  2611. X        morec = mc;
  2612. X    }
  2613. X#if 0
  2614. X    /*
  2615. X     * Hack to fix teh ^r redraw problem, but it redraws way too much.
  2616. X     * Probably unacceptable at low baudrates.  Someone please fix this
  2617. X     */
  2618. X    else
  2619. X        {
  2620. X        ed_mov_opt(x_cols - 2, wb1);
  2621. X        }
  2622. X#endif
  2623. X    if (cur_col != ncol)
  2624. X        ed_mov_opt(ncol, wb1);
  2625. X}
  2626. X
  2627. Xstatic
  2628. Xed_mov_opt(col, wb)
  2629. X    int    col;
  2630. X    char    *wb;
  2631. X{
  2632. X    if (col < cur_col) {
  2633. X        if (col + 1 < cur_col - col) {
  2634. X            x_putc('\r');
  2635. X            x_flush();
  2636. X            pprompt(prompt);
  2637. X            cur_col = pwidth;
  2638. X            while (cur_col++ < col)
  2639. X                x_putc(*wb++);
  2640. X        } else {
  2641. X            while (cur_col-- > col)
  2642. X                x_putc('\b');
  2643. X        }
  2644. X    } else {
  2645. X        wb = &wb[cur_col - pwidth];
  2646. X        while (cur_col++ < col)
  2647. X            x_putc(*wb++);
  2648. X    }
  2649. X    cur_col = col;
  2650. X}
  2651. X
  2652. Xint
  2653. Xx_vi(buf, len)
  2654. X    char *buf;
  2655. X    size_t len;
  2656. X{
  2657. X    int    c;
  2658. X
  2659. X    vi_reset(buf, len > CMDLEN ? CMDLEN : len);
  2660. X    x_flush();
  2661. X    while ((c = getch()) != -1) {
  2662. X        if (vi_hook(c))
  2663. X            break;
  2664. X        x_flush();
  2665. X    }
  2666. X
  2667. X    if (c == -1)
  2668. X        return -1;
  2669. X
  2670. X    if (es->cbuf != buf) {
  2671. X        bcopy(es->cbuf, buf, es->linelen);
  2672. X        buf[es->linelen] = '\n';
  2673. X    } else
  2674. X        es->cbuf[es->linelen] = '\n';
  2675. X
  2676. X    es->linelen++;
  2677. X    return es->linelen;
  2678. X}
  2679. X
  2680. Xgetch()
  2681. X{
  2682. X    char    buf;
  2683. X
  2684. X    if (read(ttyfd, &buf, 1) != 1)
  2685. X        return -1;
  2686. X    if ((buf & 0x7f) == Ctrl('c')) {
  2687. X        /*
  2688. X         * If you hit ctrl-c, the buffer was left in a
  2689. X         * strange state; the next command typed was
  2690. X         * mucked up.  Doing all of this is probably
  2691. X         * overkill, but it works most of the time.
  2692. X         */
  2693. X        memset(es->cbuf, 0, CMDLEN);
  2694. X        es->winleft = 0;
  2695. X        es->cbufsize = 0;
  2696. X        es->linelen = 0;
  2697. X        es->cursor = 0;
  2698. X
  2699. X        memset(undo->cbuf, 0, CMDLEN);
  2700. X        undo->winleft = 0;
  2701. X        undo->cbufsize = 0;
  2702. X        undo->linelen = 0;
  2703. X        undo->cursor = 0;
  2704. X        x_mode(FALSE);
  2705. X        trapsig(SIGINT);
  2706. X    } else if ((buf & 0x7f) == Ctrl('d'))
  2707. X        return -1;
  2708. X    return buf & 0x7f;
  2709. X}
  2710. X
  2711. X
  2712. Xchar **globstr(stuff)
  2713. Xchar *stuff;
  2714. X    {
  2715. X    char *vecp[2];
  2716. X
  2717. X    vecp[0] = stuff;
  2718. X    vecp[1] = NULL;
  2719. X    return(eval(vecp, DOBLANK|DOGLOB|DOTILDE));
  2720. X    }
  2721. X#endif /* ifdef VI */
  2722. END_OF_FILE
  2723.   if test 30485 -ne `wc -c <'sh/vi.c'`; then
  2724.     echo shar: \"'sh/vi.c'\" unpacked with wrong size!
  2725.   fi
  2726.   # end of 'sh/vi.c'
  2727. fi
  2728. echo shar: End of archive 3 \(of 9\).
  2729. cp /dev/null ark3isdone
  2730. MISSING=""
  2731. for I in 1 2 3 4 5 6 7 8 9 ; do
  2732.     if test ! -f ark${I}isdone ; then
  2733.     MISSING="${MISSING} ${I}"
  2734.     fi
  2735. done
  2736. if test "${MISSING}" = "" ; then
  2737.     echo You have unpacked all 9 archives.
  2738.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2739. else
  2740.     echo You still must unpack the following archives:
  2741.     echo "        " ${MISSING}
  2742. fi
  2743. exit 0
  2744. exit 0 # Just in case...
  2745. -- 
  2746. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  2747. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  2748. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  2749. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  2750.