BSD 4 release
[unix-history] / usr / src / cmd / ex / ex_unix.c
/* Copyright (c) 1979 Regents of the University of California */
static char *sccsid = "@(#)ex_unix.c 6.1 10/18/80";
#include "ex.h"
#include "ex_temp.h"
#include "ex_tty.h"
#include "ex_vis.h"
/*
* Unix escapes, filtering
*/
/*
* First part of a shell escape,
* parse the line, expanding # and % and ! and printing if implied.
*/
unix0(warn)
bool warn;
{
register char *up, *fp;
register short c;
char printub, puxb[UXBSIZE + sizeof (int)];
printub = 0;
CP(puxb, uxb);
c = getchar();
if (c == '\n' || c == EOF)
error("Incomplete shell escape command@- use 'shell' to get a shell");
up = uxb;
do {
switch (c) {
case '\\':
if (any(peekchar(), "%#!"))
c = getchar();
default:
if (up >= &uxb[UXBSIZE]) {
tunix:
uxb[0] = 0;
error("Command too long");
}
*up++ = c;
break;
case '!':
fp = puxb;
if (*fp == 0) {
uxb[0] = 0;
error("No previous command@to substitute for !");
}
printub++;
while (*fp) {
if (up >= &uxb[UXBSIZE])
goto tunix;
*up++ = *fp++;
}
break;
case '#':
fp = altfile;
if (*fp == 0) {
uxb[0] = 0;
error("No alternate filename@to substitute for #");
}
goto uexp;
case '%':
fp = savedfile;
if (*fp == 0) {
uxb[0] = 0;
error("No filename@to substitute for %%");
}
uexp:
printub++;
while (*fp) {
if (up >= &uxb[UXBSIZE])
goto tunix;
*up++ = *fp++ | QUOTE;
}
break;
}
c = getchar();
} while (c == '"' || c == '|' || !endcmd(c));
if (c == EOF)
ungetchar(c);
*up = 0;
if (!inopen)
resetflav();
if (warn)
ckaw();
if (warn && hush == 0 && chng && xchng != chng && value(WARN) && dol > zero) {
xchng = chng;
vnfl();
printf(mesg("[No write]|[No write since last change]"));
noonl();
flush();
} else
warn = 0;
if (printub) {
if (uxb[0] == 0)
error("No previous command@to repeat");
if (inopen) {
splitw++;
vclean();
vgoto(WECHO, 0);
}
if (warn)
vnfl();
if (hush == 0)
lprintf("!%s", uxb);
if (inopen && Outchar != termchar) {
vclreol();
vgoto(WECHO, 0);
} else
putnl();
flush();
}
}
/*
* Do the real work for execution of a shell escape.
* Mode is like the number passed to open system calls
* and indicates filtering. If input is implied, newstdin
* must have been setup already.
*/
ttymode
unixex(opt, up, newstdin, mode)
char *opt, *up;
int newstdin, mode;
{
int pvec[2];
ttymode f;
signal(SIGINT, SIG_IGN);
#ifdef SIGTSTP
if (dosusp)
signal(SIGTSTP, SIG_DFL);
#endif
if (inopen)
f = setty(normf);
if ((mode & 1) && pipe(pvec) < 0) {
/* Newstdin should be io so it will be closed */
if (inopen)
setty(f);
error("Can't make pipe for filter");
}
#ifndef VFORK
pid = fork();
#else
pid = vfork();
#endif
if (pid < 0) {
if (mode & 1) {
close(pvec[0]);
close(pvec[1]);
}
setrupt();
error("No more processes");
}
if (pid == 0) {
if (mode & 2) {
close(0);
dup(newstdin);
close(newstdin);
}
if (mode & 1) {
close(pvec[0]);
close(1);
dup(pvec[1]);
if (inopen) {
close(2);
dup(1);
}
close(pvec[1]);
}
if (io)
close(io);
if (tfile)
close(tfile);
#ifndef VMUNIX
close(erfile);
#endif
signal(SIGHUP, oldhup);
signal(SIGQUIT, oldquit);
if (ruptible)
signal(SIGINT, SIG_DFL);
execl(svalue(SHELL), "sh", opt, up, (char *) 0);
printf("No %s!\n", svalue(SHELL));
error(NOSTR);
}
if (mode & 1) {
io = pvec[0];
close(pvec[1]);
}
if (newstdin)
close(newstdin);
return (f);
}
/*
* Wait for the command to complete.
* F is for restoration of tty mode if from open/visual.
* C flags suppression of printing.
*/
unixwt(c, f)
bool c;
ttymode f;
{
waitfor();
#ifdef SIGTSTP
if (dosusp)
signal(SIGTSTP, onsusp);
#endif
if (inopen)
setty(f);
setrupt();
if (!inopen && c && hush == 0) {
printf("!\n");
flush();
termreset();
gettmode();
}
}
/*
* Setup a pipeline for the filtration implied by mode
* which is like a open number. If input is required to
* the filter, then a child editor is created to write it.
* If output is catch it from io which is created by unixex.
*/
filter(mode)
register int mode;
{
static int pvec[2];
register ttymode f;
register int lines = lineDOL();
mode++;
if (mode & 2) {
signal(SIGINT, SIG_IGN);
if (pipe(pvec) < 0)
error("Can't make pipe");
pid = fork();
io = pvec[0];
if (pid < 0) {
setrupt();
close(pvec[1]);
error("No more processes");
}
if (pid == 0) {
setrupt();
io = pvec[1];
close(pvec[0]);
putfile();
exit(0);
}
close(pvec[1]);
io = pvec[0];
setrupt();
}
f = unixex("-c", uxb, (mode & 2) ? pvec[0] : 0, mode);
if (mode == 3) {
delete(0);
addr2 = addr1 - 1;
}
if (mode & 1) {
if(FIXUNDO)
undap1 = undap2 = addr2+1;
ignore(append(getfile, addr2));
#ifdef TRACE
if (trace)
vudump("after append in filter");
#endif
}
close(io);
io = -1;
unixwt(!inopen, f);
netchHAD(lines);
}
/*
* Set up to do a recover, getting io to be a pipe from
* the recover process.
*/
recover()
{
static int pvec[2];
if (pipe(pvec) < 0)
error(" Can't make pipe for recovery");
pid = fork();
io = pvec[0];
if (pid < 0) {
close(pvec[1]);
error(" Can't fork to execute recovery");
}
if (pid == 0) {
close(2);
dup(1);
close(1);
dup(pvec[1]);
close(pvec[1]);
execl(EXRECOVER, "exrecover", svalue(DIRECTORY), file, (char *) 0);
close(1);
dup(2);
error(" No recovery routine");
}
close(pvec[1]);
}
/*
* Wait for the process (pid an external) to complete.
*/
waitfor()
{
do
rpid = wait(&status);
while (rpid != pid && rpid != -1);
status = (status >> 8) & 0377;
}
/*
* The end of a recover operation. If the process
* exits non-zero, force not edited; otherwise force
* a write.
*/
revocer()
{
waitfor();
if (pid == rpid && status != 0)
edited = 0;
else
change();
}