diff options
Diffstat (limited to 'usr.bin/vi/nex/ex_script.c')
-rw-r--r-- | usr.bin/vi/nex/ex_script.c | 570 |
1 files changed, 0 insertions, 570 deletions
diff --git a/usr.bin/vi/nex/ex_script.c b/usr.bin/vi/nex/ex_script.c deleted file mode 100644 index 606e479d6af40..0000000000000 --- a/usr.bin/vi/nex/ex_script.c +++ /dev/null @@ -1,570 +0,0 @@ -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef lint -static char sccsid[] = "@(#)ex_script.c 8.10 (Berkeley) 12/22/93"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/wait.h> - -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "vi.h" -#include "excmd.h" -#include "script.h" - -/* - * XXX - */ -int openpty __P((int *, int *, char *, struct termios *, struct winsize *)); - -static int sscr_getprompt __P((SCR *, EXF *)); -static int sscr_init __P((SCR *, EXF *)); -static int sscr_matchprompt __P((SCR *, char *, size_t, size_t *)); -static int sscr_setprompt __P((SCR *, char *, size_t)); - -/* - * ex_script -- : sc[ript][!] [file] - * - * Switch to script mode. - */ -int -ex_script(sp, ep, cmdp) - SCR *sp; - EXF *ep; - EXCMDARG *cmdp; -{ - /* Vi only command. */ - if (!IN_VI_MODE(sp)) { - msgq(sp, M_ERR, - "The script command is only available in vi mode."); - return (1); - } - - /* Switch to the new file. */ - if (cmdp->argc != 0 && ex_edit(sp, ep, cmdp)) - return (1); - - /* - * Create the shell, figure out the prompt. - * - * !!! - * The files just switched, use sp->ep. - */ - if (sscr_init(sp, sp->ep)) - return (1); - - return (0); -} - -/* - * sscr_init -- - * Create a pty setup for a shell. - */ -static int -sscr_init(sp, ep) - SCR *sp; - EXF *ep; -{ - SCRIPT *sc; - char *sh, *sh_path; - - MALLOC_RET(sp, sc, SCRIPT *, sizeof(SCRIPT)); - sp->script = sc; - sc->sh_prompt = NULL; - sc->sh_prompt_len = 0; - - /* - * There are two different processes running through this code. - * They are the shell and the parent. - */ - sc->sh_master = sc->sh_slave = -1; - - if (tcgetattr(STDIN_FILENO, &sc->sh_term) == -1) { - msgq(sp, M_SYSERR, "tcgetattr"); - goto err; - } - - /* - * Turn off output postprocessing and echo. - */ - sc->sh_term.c_oflag &= ~OPOST; - sc->sh_term.c_cflag &= ~(ECHO|ECHOE|ECHONL|ECHOK); - - if (ioctl(STDIN_FILENO, TIOCGWINSZ, &sc->sh_win) == -1) { - msgq(sp, M_SYSERR, "tcgetattr"); - goto err; - } - - if (openpty(&sc->sh_master, - &sc->sh_slave, sc->sh_name, &sc->sh_term, &sc->sh_win) == -1) { - msgq(sp, M_SYSERR, "openpty"); - goto err; - } - - /* - * Don't use vfork() here, because the signal semantics - * differ from implementation to implementation. - */ - switch (sc->sh_pid = fork()) { - case -1: /* Error. */ - msgq(sp, M_SYSERR, "fork"); -err: if (sc->sh_master != -1) - (void)close(sc->sh_master); - if (sc->sh_slave != -1) - (void)close(sc->sh_slave); - return (1); - case 0: /* Utility. */ - /* - * The utility has default signal behavior. Don't bother - * using sigaction(2) 'cause we want the default behavior. - */ - (void)signal(SIGINT, SIG_DFL); - (void)signal(SIGQUIT, SIG_DFL); - - /* - * XXX - * So that shells that do command line editing turn it off. - */ - (void)putenv("TERM=emacs"); - (void)putenv("TERMCAP=emacs:"); - (void)putenv("EMACS=t"); - - (void)setsid(); -#ifdef TIOCSCTTY - /* - * 4.4BSD allocates a controlling terminal using the TIOCSCTTY - * ioctl, not by opening a terminal device file. POSIX 1003.1 - * doesn't define a portable way to do this. If TIOCSCTTY is - * not available, hope that the open does it. - */ - (void)ioctl(sc->sh_slave, TIOCSCTTY, 0); -#endif - (void)close(sc->sh_master); - (void)dup2(sc->sh_slave, STDIN_FILENO); - (void)dup2(sc->sh_slave, STDOUT_FILENO); - (void)dup2(sc->sh_slave, STDERR_FILENO); - (void)close(sc->sh_slave); - - /* Assumes that all shells have -i. */ - sh_path = O_STR(sp, O_SHELL); - if ((sh = strrchr(sh_path, '/')) == NULL) - sh = sh_path; - else - ++sh; - execl(sh_path, sh, "-i", NULL); - msgq(sp, M_ERR, - "Error: execl: %s: %s", sh_path, strerror(errno)); - _exit(127); - default: - break; - } - - if (sscr_getprompt(sp, ep)) - return (1); - - F_SET(sp, S_REDRAW | S_SCRIPT); - return (0); - -} - -/* - * sscr_getprompt -- - * Eat lines printed by the shell until a line with no trailing - * carriage return comes; set the prompt from that line. - */ -static int -sscr_getprompt(sp, ep) - SCR *sp; - EXF *ep; -{ - struct timeval tv; - SCRIPT *sc; - fd_set fdset; - recno_t lline; - size_t llen, len; - u_int value; - int nr; - char *endp, *p, *t, buf[1024]; - - FD_ZERO(&fdset); - endp = buf; - len = sizeof(buf); - - /* Wait up to a second for characters to read. */ - tv.tv_sec = 5; - tv.tv_usec = 0; - sc = sp->script; - FD_SET(sc->sh_master, &fdset); - switch (select(sc->sh_master + 1, &fdset, NULL, NULL, &tv)) { - case -1: /* Error or interrupt. */ - msgq(sp, M_SYSERR, "select"); - goto prompterr; - case 0: /* Timeout */ - msgq(sp, M_ERR, "Error: timed out."); - goto prompterr; - case 1: /* Characters to read. */ - break; - } - - /* Read the characters. */ -more: len = sizeof(buf) - (endp - buf); - switch (nr = read(sc->sh_master, endp, len)) { - case 0: /* EOF. */ - msgq(sp, M_ERR, "Error: shell: EOF"); - goto prompterr; - case -1: /* Error or interrupt. */ - msgq(sp, M_SYSERR, "shell"); - goto prompterr; - default: - endp += nr; - break; - } - - /* If any complete lines, push them into the file. */ - for (p = t = buf; p < endp; ++p) { - value = term_key_val(sp, *p); - if (value == K_CR || value == K_NL) { - if (file_lline(sp, ep, &lline) || - file_aline(sp, ep, 0, lline, t, p - t)) - goto prompterr; - t = p + 1; - } - } - if (p > buf) { - memmove(buf, t, endp - t); - endp = buf + (endp - t); - } - if (endp == buf) - goto more; - - /* Wait up 1/10 of a second to make sure that we got it all. */ - tv.tv_sec = 0; - tv.tv_usec = 100000; - switch (select(sc->sh_master + 1, &fdset, NULL, NULL, &tv)) { - case -1: /* Error or interrupt. */ - msgq(sp, M_SYSERR, "select"); - goto prompterr; - case 0: /* Timeout */ - break; - case 1: /* Characters to read. */ - goto more; - } - - /* Timed out, so theoretically we have a prompt. */ - llen = endp - buf; - endp = buf; - - /* Append the line into the file. */ - if (file_lline(sp, ep, &lline) || - file_aline(sp, ep, 0, lline, buf, llen)) { -prompterr: sscr_end(sp); - return (1); - } - - return (sscr_setprompt(sp, buf, llen)); -} - -/* - * sscr_exec -- - * Take a line and hand it off to the shell. - */ -int -sscr_exec(sp, ep, lno) - SCR *sp; - EXF *ep; - recno_t lno; -{ - SCRIPT *sc; - recno_t last_lno; - size_t blen, len, last_len, tlen; - int matchprompt, nw, rval; - char *bp, *p; - - /* If there's a prompt on the last line, append the command. */ - if (file_lline(sp, ep, &last_lno)) - return (1); - if ((p = file_gline(sp, ep, last_lno, &last_len)) == NULL) { - GETLINE_ERR(sp, last_lno); - return (1); - } - if (sscr_matchprompt(sp, p, last_len, &tlen) && tlen == 0) { - matchprompt = 1; - GET_SPACE_RET(sp, bp, blen, last_len + 128); - memmove(bp, p, last_len); - } else - matchprompt = 0; - - /* Get something to execute. */ - if ((p = file_gline(sp, ep, lno, &len)) == NULL) { - if (file_lline(sp, ep, &lno)) - goto err1; - if (lno == 0) - goto empty; - else - GETLINE_ERR(sp, lno); - goto err1; - } - - /* Empty lines aren't interesting. */ - if (len == 0) - goto empty; - - /* Delete any prompt. */ - if (sscr_matchprompt(sp, p, len, &tlen)) { - if (tlen == len) { -empty: msgq(sp, M_BERR, "Nothing to execute."); - goto err1; - } - p += (len - tlen); - len = tlen; - } - - /* Push the line to the shell. */ - sc = sp->script; - if ((nw = write(sc->sh_master, p, len)) != len) - goto err2; - rval = 0; - if (write(sc->sh_master, "\n", 1) != 1) { -err2: if (nw == 0) - errno = EIO; - msgq(sp, M_SYSERR, "shell"); - goto err1; - } - - if (matchprompt) { - ADD_SPACE_RET(sp, bp, blen, last_len + len); - memmove(bp + last_len, p, len); - if (file_sline(sp, ep, last_lno, bp, last_len + len)) -err1: rval = 1; - } - if (matchprompt) - FREE_SPACE(sp, bp, blen); - return (rval); -} - -/* - * sscr_input -- - * Take a line from the shell and insert it into the file. - */ -int -sscr_input(sp) - SCR *sp; -{ - struct timeval tv; - SCRIPT *sc; - EXF *ep; - recno_t lno; - size_t blen, len, tlen; - u_int value; - int nr, rval; - char *bp, *endp, *p, *t; - - /* Find out where the end of the file is. */ - ep = sp->ep; - if (file_lline(sp, ep, &lno)) - return (1); - -#define MINREAD 1024 - GET_SPACE_RET(sp, bp, blen, MINREAD); - endp = bp; - - /* Read the characters. */ - rval = 1; - sc = sp->script; -more: switch (nr = read(sc->sh_master, endp, MINREAD)) { - case 0: /* EOF; shell just exited. */ - sscr_end(sp); - F_CLR(sp, S_SCRIPT); - rval = 0; - goto ret; - case -1: /* Error or interrupt. */ - msgq(sp, M_SYSERR, "shell"); - goto ret; - default: - endp += nr; - break; - } - - /* Append the lines into the file. */ - for (p = t = bp; p < endp; ++p) { - value = term_key_val(sp, *p); - if (value == K_CR || value == K_NL) { - len = p - t; - if (file_aline(sp, ep, 1, lno++, t, len)) - goto ret; - t = p + 1; - } - } - if (p > t) { - len = p - t; - /* - * If the last thing from the shell isn't another prompt, wait - * up to 1/10 of a second for more stuff to show up, so that - * we don't break the output into two separate lines. Don't - * want to hang indefinitely because some program is hanging, - * confused the shell, or whatever. - */ - if (!sscr_matchprompt(sp, t, len, &tlen) || tlen != 0) { - tv.tv_sec = 0; - tv.tv_usec = 100000; - FD_SET(sc->sh_master, &sp->rdfd); - FD_CLR(STDIN_FILENO, &sp->rdfd); - if (select(sc->sh_master + 1, - &sp->rdfd, NULL, NULL, &tv) == 1) { - memmove(bp, t, len); - endp = bp + len; - goto more; - } - } - if (sscr_setprompt(sp, t, len)) - return (1); - if (file_aline(sp, ep, 1, lno++, t, len)) - goto ret; - } - - /* The cursor moves to EOF. */ - sp->lno = lno; - sp->cno = len ? len - 1 : 0; - rval = sp->s_refresh(sp, ep); - -ret: FREE_SPACE(sp, bp, blen); - return (rval); -} - -/* - * sscr_setprompt -- - * - * Set the prompt to the last line we got from the shell. - * - */ -static int -sscr_setprompt(sp, buf, len) - SCR *sp; - char* buf; - size_t len; -{ - SCRIPT *sc; - - sc = sp->script; - if (sc->sh_prompt) - FREE(sc->sh_prompt, sc->sh_prompt_len); - MALLOC(sp, sc->sh_prompt, char *, len + 1); - if (sc->sh_prompt == NULL) { - sscr_end(sp); - return (1); - } - memmove(sc->sh_prompt, buf, len); - sc->sh_prompt_len = len; - sc->sh_prompt[len] = '\0'; - return (0); -} - -/* - * sscr_matchprompt -- - * Check to see if a line matches the prompt. Nul's indicate - * parts that can change, in both content and size. - */ -static int -sscr_matchprompt(sp, lp, line_len, lenp) - SCR *sp; - char *lp; - size_t line_len, *lenp; -{ - SCRIPT *sc; - size_t prompt_len; - char *pp; - - sc = sp->script; - if (line_len < (prompt_len = sc->sh_prompt_len)) - return (0); - - for (pp = sc->sh_prompt; - prompt_len && line_len; --prompt_len, --line_len) { - if (*pp == '\0') { - for (; prompt_len && *pp == '\0'; --prompt_len, ++pp); - if (!prompt_len) - return (0); - for (; line_len && *lp != *pp; --line_len, ++lp); - if (!line_len) - return (0); - } - if (*pp++ != *lp++) - break; - } - - if (prompt_len) - return (0); - if (lenp != NULL) - *lenp = line_len; - return (1); -} - -/* - * sscr_end -- - * End the pipe to a shell. - */ -int -sscr_end(sp) - SCR *sp; -{ - SCRIPT *sc; - int rval; - - if ((sc = sp->script) == NULL) - return (0); - - /* Turn off the script flag. */ - F_CLR(sp, S_SCRIPT); - - /* Close down the parent's file descriptors. */ - if (sc->sh_master != -1) - (void)close(sc->sh_master); - if (sc->sh_slave != -1) - (void)close(sc->sh_slave); - - /* This should have killed the child. */ - rval = proc_wait(sp, (long)sc->sh_pid, "script-shell", 0); - - /* Free memory. */ - FREE(sc->sh_prompt, sc->sh_prompt_len); - FREE(sc, sizeof(SCRIPT)); - sp->script = NULL; - - return (rval); -} |