|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T t
Length: 29256 (0x7248)
Types: TextFile
Names: »te_exec2.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
└─⟦this⟧ »EUUGD11/euug-87hel/sec1/teco/te_exec2.c«
/* TECO for Ultrix Copyright 1986 Matt Fichtenbaum */
/* This program and its components belong to GenRad Inc, Concord MA 01742 */
/* They may be copied if this copyright notice is included */
/* te_exec2.c process "E" and "F" commands 2/26/87 */
#include "te_defs.h"
#include <sys/wait.h>
struct qh oldcstring; /* hold command string during ei */
/* file stuff for input/output files */
struct infiledata pi_file = { NULL, -1 }; /* input files */
struct infiledata si_file = { NULL, -1 };
struct infiledata *infile = &pi_file; /* pointer to currently active input file structure */
struct outfiledata po_file, so_file; /* output files */
struct outfiledata *outfile = &po_file; /* pointer to currently active output file structure */
FILE *eisw; /* indirect command file pointer */
/* process E commands */
do_e()
{
char c; /* temps */
int old_var;
FILE *t_eisw;
switch (mapch_l[getcmdc(trace_sw)]) /* read next character and dispatch */
{
/* numeric values */
case 'd': /* ED */
set_var(&ed_val);
break;
case 's': /* ES */
set_var(&es_val);
break;
case 't': /* ET */
old_var = et_val;
set_var(&et_val);
et_val = (et_val & 0100651) | 001006; /* force read_only bits */
if ((et_val ^ old_var) & ET_TRUNC) window(WIN_REDRAW); /* redraw if ET & 256 changes */
break;
case 'u': /* EU */
set_var(&eu_val);
break;
case 'v': /* EV */
set_var(&ev_val);
break;
case 'z': /* EZ */
old_var = ez_val;
set_var(&ez_val);
tabmask = (ez_val & EZ_TAB4) ? 3 : 7; /* set tab mask */
if ((ez_val ^ old_var) & EZ_TAB4) window(WIN_REDRAW); /* force window redisplay if EZ_TAB4 changes */
break;
\f
/* E_ search */
case '_':
do_nsearch('e');
break;
/* file I/O commands */
case 'a': /* set secondary output */
outfile = &so_file;
break;
case 'b': /* open read/write with backup */
if (!read_filename(1, 'r')) ERROR(E_NFI); /* read the name */
if (infile->fd) fclose(infile->fd); /* close previously-open file */
if (!(infile->fd = fopen(fbuf.f->ch, "r")))
{
if (!colonflag) ERROR(E_FNF);
}
else
{
if (outfile->fd) ERROR(E_OFO); /* output file already open */
for (ll = 0; ll < CELLSIZE; ll++) /* save file string */
if ((outfile->t_name[ll] = outfile->f_name[ll] = fbuf.f->ch[ll]) == '\0') break;
outfile->name_size = ll;
outfile->t_name[ll++] = '.';
outfile->t_name[ll++] = 't';
outfile->t_name[ll++] = 'm';
outfile->t_name[ll++] = 'p';
outfile->t_name[ll] = '\0';
if (!(outfile->fd = fopen(outfile->t_name, "w"))) ERROR(E_COF);
outfile->bak = 1; /* set backup mode */
}
infile->eofsw = -1 - (esp->val1 = (infile->fd) ? -1 : 0);
esp->flag1 = colonflag;
colonflag = 0;
break;
case 'x': /* finish edit and exit */
exitflag = -1;
/* --- fall through to "EC" --- */
case 'c': /* finish edit */
set_pointer(0, &aa); /* set a pointer to start of text buffer */
write_file(&aa, z, ctrl_e); /* write the current buffer */
dot = z = 0; /* empty the buffer */
window(WIN_REDRAW); /* force window redraw */
if ((outfile->fd) && (infile->fd) && !(infile->eofsw)) /* if any input remaining, copy it to output */
while ((c = getc(infile->fd)) != EOF) putc(c, outfile->fd);
/* --- fall through to "EF" --- */
\f
case 'f': /* close output file */
if (outfile->fd) /* only if one is open */
{
fclose(outfile->fd);
if (outfile->bak & 1) /* if this is "backup" mode */
{
outfile->f_name[outfile->name_size] = '.';
outfile->f_name[outfile->name_size+1] = 'b';
outfile->f_name[outfile->name_size+2] = 'a';
outfile->f_name[outfile->name_size+3] = 'k';
outfile->f_name[outfile->name_size+4] = '\0';
outfile->t_name[outfile->name_size] = '\0';
rename(outfile->t_name, outfile->f_name); /* rename orig file */
}
if (!(outfile->bak & 8)) /* if output file had ".tmp" extension */
{ /* remove it */
outfile->t_name[outfile->name_size] = '.';
outfile->f_name[outfile->name_size] = '\0';
rename(outfile->t_name, outfile->f_name); /* rename output */
}
}
outfile->fd = NULL; /* mark "no output file open" */
break;
case 'i': /* indirect file execution */
if (!read_filename(1, 'i')) /* if no filename specified, reset command input */
{
if (eisw) /* if ending a file execute, restore the previous "old command string" */
{
fclose(eisw); /* return the file descriptor */
dly_free_blist(cbuf.f); /* return the command string used by the file (after execution done) */
cbuf.f = oldcstring.f;
cbuf.z = oldcstring.z;
}
t_eisw = 0;
}
else if (!(t_eisw = fopen(fbuf.f->ch, "r")))
{
if (!colonflag) ERROR(E_FNF);
}
else if (!eisw) /* if this "ei" came from the command string */
{
oldcstring.f = cbuf.f; /* save current command string */
oldcstring.z = cbuf.z;
cbuf.f = NULL; /* and make it inaccessible to "rdcmd" */
}
if (eisw) fclose(eisw); /* if a command file had been open, close it */
esp->val1 = (eisw = t_eisw) ? -1 : 0;
esp->flag1 = colonflag;
colonflag = 0;
esp->op = OP_START;
break;
\f
case 'k': /* kill output file */
kill_output(outfile);
break;
case 'p': /* switch to secondary input */
infile = &si_file;
break;
case 'r': /* specify input file, or switch to primary input */
if (!read_filename(0, 'r')) infile = &pi_file; /* no name, switch to primary input */
else
{
if (infile->fd) fclose(infile->fd); /* close previously-open file */
if (!(infile->fd = fopen(fbuf.f->ch, "r")))
{
if (!colonflag) ERROR(E_FNF);
}
}
infile->eofsw = -1 - (esp->val1 = (infile->fd) ? -1 : 0);
esp->flag1 = colonflag;
colonflag = 0;
esp->op = OP_START;
break;
case 'w': /* specify output file, or switch to primary output */
if(!read_filename(0, 'w')) outfile = &po_file;
else
{
if (outfile->fd) ERROR(E_OFO); /* output file already open */
for (ll = 0; ll < CELLSIZE; ll++) /* save file string */
if ((outfile->t_name[ll] = outfile->f_name[ll] = fbuf.f->ch[ll]) == '\0') break;
outfile->name_size = ll;
if (!(ez_val & EZ_NOTMPFIL)) /* if not using literal output name */
{
outfile->t_name[ll++] = '.'; /* use provisional suffix ".tmp" */
outfile->t_name[ll++] = 't';
outfile->t_name[ll++] = 'm';
outfile->t_name[ll++] = 'p';
outfile->t_name[ll] = '\0';
}
if (!(outfile->fd = fopen(outfile->t_name, "w"))) ERROR(E_COF);
outfile->bak = ez_val & EZ_NOTMPFIL; /* save "temp suffix" status */
}
break;
case 'y': /* EY is Y without protection */
if (esp->flag1) ERROR(E_NYA);
dot = z = 0; /* clear buffer */
set_pointer(0, &aa);
read_file(&aa, &z, (ed_val & ED_EXPMEM ? -1 : 0) );
esp->flag1 = colonflag;
colonflag = 0;
esp->op = OP_START;
break;
\f
case 'n': /* wildcard filespec */
esp->val1 = do_en();
esp->flag1 = colonflag;
colonflag = 0;
esp->op = OP_START;
break;
case 'q': /* system command */
esp->val1 = do_eq(); /* do this as a separate routine */
esp->flag1 = colonflag;
colonflag = 0;
esp->op = OP_START;
break;
default:
ERROR(E_IEC);
}
}
\f
/* routine to execute a system command */
/* this is done by forking off another process */
/* to execute a shell via 'execl' */
/* routine returns -1 if success, 0 if error in fork */
int do_eq()
{
int t;
union wait status;
char *pname; /* pointer to name of shell */
extern char *getenv();
build_string(&sysbuf);
if (sysbuf.z > CELLSIZE-2) ERROR(E_STL); /* command must fit within one cell */
sysbuf.f->ch[sysbuf.z] = '\0'; /* store terminating null */
if (!(pname = getenv("SHELL"))) ERROR(E_SYS); /* read shell name */
if (!esp->flag1) /* if not m,nEQ command */
{
if (win_data[7]) window(WIN_SUSP); /* restore full screen */
crlf(); /* force characters out */
setup_tty(TTY_SUSP); /* restore terminal to normal mode */
t = vfork(); /* fork a new process */
if (t == 0) /* if this is the child */
{
execl(pname, pname, "-c", &sysbuf.f->ch[0], 0); /* call the named Unix routine */
printf("Error in 'execl'\n"); /* normally shouldn't get here */
exit(1);
}
while (wait(&status) != t); /* if parent, wait for child to finish */
if (status.w_retcode) t = -1; /* keep failure indication from child */
setup_tty(TTY_RESUME); /* restore terminal to teco mode */
if (win_data[7]) /* if window was enabled */
{
vt(VT_SETSPEC1); /* set reverse video */
fputs("Type RETURN to continue", stdout); /* require CR before continuing */
vt(VT_CLRSPEC); /* reverse video off */
while (gettty() != LF);
putchar(CR); /* back to beginning of line */
vt(VT_EEOL); /* and erase the message */
window(WIN_RESUME); /* re-enable window */
window(WIN_REDRAW); /* and make it redraw afterwards */
}
}
else t = do_eq1(pname); /* m,nEQ command */
return( (t == -1) ? 0 : -1); /* return failure if fork failed or proc status nonzero */
}
\f
/* Execute m,nEQtext$ command. Run "text" as a Unix command that */
/* receives its std input from chars m through n of teco's buffer. */
/* Output from the command is placed in Q#. */
int do_eq1(shell)
char *shell; /* arg is pointer to shell name */
{
int ff, pipe_in[2], pipe_out[2]; /* fork result and two pipes */
FILE *xx_in, *xx_out; /* std in and out for called process */
FILE *fdopen();
union wait status;
ll = line_args(1, &aa); /* set aa to start of text, ll to number of chars */
dot += ll; /* set pointer at end of text */
ctrl_s = -ll; /* set ^S to - # of chars */
if (pipe(pipe_out)) ERROR(E_SYS); /* make input pipe; failure if can't */
if (win_data[7]) window(WIN_SUSP); /* disable split screen */
setup_tty(TTY_SUSP); /* put console back to original state */
if ((ff = fork()) == -1) /* fork first child: if error, quit */
{
close(pipe_out[0]);
close(pipe_out[1]);
setup_tty(TTY_RESUME);
if (win_data[7]) window(WIN_RESUME), window(WIN_REDRAW);
ERROR(E_SYS);
}
if (ff) /* if this is the parent, the task is to read into q# */
{
make_buffer(&timbuf); /* initialize the q# header */
bb.p = timbuf.f; /* init bb to point to q# */
timbuf.z = bb.c = 0;
close(pipe_out[1]); /* parent won't write to this pipe */
if ((xx_out = fdopen(pipe_out[0], "r")) == 0) /* open the "std out" pipe for reading */
{
close(pipe_out[0]); /* if can't open output pipe */
setup_tty(TTY_RESUME);
if (win_data[7]) window(WIN_RESUME), window(WIN_REDRAW);
ERROR(E_SYS); /* "open" failure */
}
read_stream(xx_out, 0, &bb, &timbuf.z, 0, 0, 1); /* read from pipe to q# */
close(pipe_out[0]);
while (wait(&status) != ff); /* wait for children to finish */
setup_tty(TTY_RESUME);
if (win_data[7]) window(WIN_RESUME), window(WIN_REDRAW);
return(status.w_retcode ? -1 : 0);
}
\f
/* This is the child. It in turn forks into two processes, of which the "parent" */
/* (original child) writes the specified part of the buffer to the pipe, and the */
/* new child (grandchild to the original teco) execl's the Unix command. */
else /* this is the child */
{
close(pipe_out[0]); /* won't read from "output" pipe */
if (pipe(pipe_in)) exit(1); /* make the "std in" pipe for the process, quit if can't */
if ((ff = fork()) == -1) exit(1); /* fork to two processes (total 3), exit if error */
if (ff) /* parent - will send chars */
{
close(pipe_in[0]); /* won't read from this pipe */
/* open pipe for writing; exit if open fails */
if ((xx_in = fdopen(pipe_in[1], "w")) == 0) exit(1);
write_stream(xx_in, &aa, ll, 0); /* write to stream, CRLF becomes LF */
fclose(xx_in);
while (wait(&status) != ff); /* wait for child */
exit(status.w_retcode); /* exit with child's status */
}
else /* this process is the grandchild */
{
close(pipe_in[1]); /* close "input" for writing */
dup2(pipe_in[0], fileno(stdin)); /* substitute pipe_in for stdin */
dup2(pipe_out[1], fileno(stdout)); /* and pipe_out for stdout */
close(pipe_in[0]); /* close original descriptors */
close(pipe_out[1]);
execl(shell, shell, "-c", &sysbuf.f->ch[0], 0); /* execute specified routine */
fputs("execl failed\n", stderr);
exit(1);
}
}
}
\f
/* Routines to handle EN wild-card file specification */
/* ENfilespec$ defines file class, leaving 'filespec' */
/* in filespec buffer and reading expanded list of */
/* files into local buffer. EN$ gets next filespec */
/* into filespec buffer. */
struct qh en_buf; /* header for storage for file list */
struct qp en_ptr; /* pointer to load/read file list */
static char glob_cmd0[] = { 'g', 'l', 'o', 'b', ' ' } ;
int do_en()
{
int t;
if (build_string(&fbuf)) /* if a file string is specified */
{
if (fbuf.z > CELLSIZE-2) ERROR(E_STL); /* upper limit on string length */
fbuf.f->ch[fbuf.z] = '\0'; /* terminating null */
t = do_glob(&en_buf); /* glob the result */
en_ptr.p = en_buf.f; /* set the buffer pointer to the beginning of the buffer */
en_ptr.dot = en_ptr.c = 0;
}
else /* if no string, get next filename */
{
do_en_next();
t = (fbuf.z) ? -1 : 0; /* t zero if no more filespecs */
if (!t && !colonflag) ERROR(E_NFI); /* if no colon, end of spec is an error */
}
return (t);
}
\f
/* routine to expand the string in the filespec buffer */
/* argument is the address of a qh that gets the expanded string */
/* argument->v gets set to the number of file specs found */
int do_glob(buff)
struct qh *buff;
{
char glob_cmd[CELLSIZE+5]; /* "glob filespec" command string */
int t;
char c;
int glob_pipe[2]; /* pipe to forked shell for expanding filenames */
struct qp glob_ptr; /* pointer for loading result buffer */
FILE *xx_out; /* stream for reading chars from pipe */
FILE *fdopen();
union wait status;
make_buffer(buff); /* initialize expanded file buffer */
glob_ptr.p = buff->f; /* initialize pointer to buffer */
glob_ptr.c = glob_ptr.dot = buff->z = buff->v = 0;
for (t = 0; t < 5; t++) glob_cmd[t] = glob_cmd0[t]; /* set up "glob filespec" command */
for (t = 0; t < fbuf.z +1; t++) glob_cmd[t+5] = fbuf.f->ch[t];
if (pipe(glob_pipe)) ERROR(E_SYS); /* make a pipe */
setup_tty(TTY_SUSP); /* put console back to normal */
if ((t = fork()) == -1) /* spawn a child... if failure */
{
close(glob_pipe[0]); /* undo the pipe */
close(glob_pipe[1]);
setup_tty(TTY_RESUME);
ERROR(E_SYS); /* and exit with failure */
}
if (t) /* if this is the parent */
{
close(glob_pipe[1]); /* parent won't write */
if ((xx_out = fdopen(glob_pipe[0], "r")) == 0) /* open pipe for read */
{
close(glob_pipe[0]); /* failure to open */
setup_tty(TTY_RESUME);
ERROR(E_SYS);
}
while ((c = getc(xx_out)) != EOF) /* read characters from pipe */
{
if (c == '\0') ++buff->v; /* count null chars that separate file specs */
glob_ptr.p->ch[glob_ptr.c] = c; /* store them in buffer */
fwdcx(&glob_ptr);
}
fclose(xx_out); /* through with stream */
buff->z = glob_ptr.dot; /* save character count */
while (wait(&status) != t); /* wait for child to finish */
setup_tty(TTY_RESUME);
return(status.w_retcode ? 0 : -1); /* return success unless child exited nonzero */
}
\f
else /* this is the child */
{
close(glob_pipe[0]); /* child won't read */
dup2(glob_pipe[1], fileno(stdout)); /* substitute pipe for standard out */
close(glob_pipe[1]); /* don't need that anymore */
execl("/bin/csh", "csh", "-fc", glob_cmd, 0); /* execute the "glob" */
fputs("execl failed\n", stderr);
exit(1);
}
}
/* routine to get next file spec from "EN" list into filespec buffer */
do_en_next()
{
char c;
make_buffer(&fbuf); /* initialize the filespec buffer */
fbuf.z = 0;
while(en_ptr.dot < en_buf.z) /* stop at end of string */
{
c = en_ptr.p->ch[en_ptr.c];
fwdc(&en_ptr);
if (!c) break; /* null is terminator between file specs */
fbuf.f->ch[fbuf.z++] = c; /* store char */
if (fbuf.z >= CELLSIZE-1) ERROR(E_STL); /* limit on filespec size */
}
fbuf.f->ch[fbuf.z] = '\0'; /* filespec ends with NULL */
}
\f
/* routine to read a file name */
/* reads it into fbuf text area */
/* returns nonzero if a name, 0 if none */
/* flag nonzero => empty name clears filespec buffer */
/* func is 'r' for ER or EB cmds, 'i' for EI, 'w' for EW */
int read_filename(flag, func)
int flag;
char func;
{
int i, t, expand;
char c;
struct qh temp_buff; /* temp buffer for globbing filespec */
if (!(t = build_string(&fbuf))) /* if no name spec'd */
{
if (flag) fbuf.z = 0; /* if no name spec'd, set length to 0 */
}
else
{
if (fbuf.z > CELLSIZE-2) ERROR(E_STL);
fbuf.f->ch[fbuf.z] = '\0'; /* store terminating NULL */
/* check for characters to be expanded by the shell */
for (i = 0; i < fbuf.z; i++)
if ((c = fbuf.f->ch[i]) == '*' || c == '?' || c == '[' || c == 0173) break;
if ( (expand = (i < fbuf.z)) || fbuf.f->ch[0] == '~') /* one of these was found, or first char is ~ */
{
temp_buff.f = NULL; /* make a temp buffer to glob filename into */
make_buffer(temp_buff);
do_glob(&temp_buff); /* expand the file name */
if (temp_buff.z == 0) /* no match */
{
free_blist(temp_buff.f); /* return the storage */
ERROR(func == 'w' ? E_COF : E_FNF); /* "can't open" or "file not found" */
}
else if (temp_buff.v == 0) /* if exactly one file name */
{
free_blist(fbuf.f); /* return the old file spec */
fbuf.f = temp_buff.f; /* put the temp buffer there instead */
fbuf.z = temp_buff.z;
if (fbuf.z > CELLSIZE-2) ERROR(E_STL);
fbuf.f->ch[fbuf.z] = '\0';
if (func == 'w' && expand) /* if this is EW and 'twas from a wildcard expansion */
{
vt(VT_SETSPEC1); /* "file XXXX already exists: overwrite? [yn]" */
fputs("File ", stdout);
fputs(fbuf.f->ch, stdout);
fputs(" already exists: overwrite? [ny] ", stdout);
vt(VT_CLRSPEC);
c = gettty(); /* read user's response */
putchar(CR);
vt(VT_EEOL); /* clean up the screen */
if (c != 'y') ERROR(E_COF); /* abort here */
}
}
\f
else /* multiple file specs */
{
if (func != 'r' || !(ez_val & EZ_MULT)) /* if multiple file specs here aren't allowed */
{
free_blist(temp_buff.f); /* return the storage */
ERROR(E_AMB);
}
free_blist(en_buf.f); /* substitute the expansion for the "EN" list */
en_ptr.p = en_buf.f = temp_buff.f; /* and initialize the "EN" list pointer */
en_buf.z = temp_buff.z;
en_ptr.dot = en_ptr.c = 0;
do_en_next(); /* get the first file */
}
}
}
return(t);
}
/* fetch or set variable */
set_var(arg)
int *arg; /* argument is pointer to variable */
{
if (esp->flag1) /* if an argument, then set the variable */
{
if (esp->flag2) /* if two arguments, then <clr>, <set> */
*arg = (*arg & ~esp->val2) | esp->val1;
else *arg = esp->val1; /* one arg is new value */
esp->flag2 = esp->flag1 = 0; /* consume argument */
}
else /* otherwise fetch the variable's value */
{
esp->val1 = *arg;
esp->flag1 = 1;
}
}
/* read from selected input file stream into specified buffer */
/* terminate on end-of-file or form feed */
/* if endsw > 0 terminates after that many lines */
/* if endsw < 0 stops if z > BUFF_LIMIT */
/* returns -1 if read EOF, 0 otherwise */
int read_file(buff, nchars, endsw)
struct qp *buff;
int *nchars, endsw;
{
if (!infile->fd) infile->eofsw = -1, ctrl_e = 0; /* return if no input file open */
else infile->eofsw = read_stream(infile->fd, &ctrl_e, buff, nchars, endsw, ez_val & EZ_CRLF, ez_val & EZ_READFF);
return(esp->val1 = infile->eofsw);
}
\f
/* read from an I/O stream into specified buffer */
/* this is used by read_file and by "eq" pipe from other Unix processes */
/* args buff, nchars, endsw as above; file is stream pointer, ff_found is */
/* address of a switch to set if read ended with a FF, crlf_sw is lf->crlf */
/* conversion, ff_sw indicates whether to stop on a form feed. */
int read_stream(file, ff_found, buff, nchars, endsw, crlf_sw, ff_sw)
FILE *file;
struct qp *buff;
int *ff_found, *nchars, endsw, crlf_sw, ff_sw;
{
char chr;
int crflag;
register struct buffcell *p;
register int c;
p = (*buff).p; /* copy pointer locally */
c = (*buff).c;
crflag = 0; /* "last char wasn't CR" */
while (((chr = getc(file)) != EOF) && ((chr != FF) || ff_sw))
{
if ((chr == LF) && !crflag && !crlf_sw) /* automatic cr before lf */
{
p->ch[c] = CR; /* store a cr */
++(*nchars); /* increment buffer count */
if (++c > CELLSIZE-1) /* next cell? */
{
if (!p->f) /* need a new cell? */
{
p->f = get_bcell();
p->f->b = p;
}
p = p->f;
c = 0;
}
}
p->ch[c] = chr; /* store char */
++(*nchars); /* increment character count */
if (++c > CELLSIZE-1) /* next cell? */
{
if (!p->f) /* need a new cell? */
{
p->f = get_bcell();
p->f->b = p;
}
p = p->f;
c = 0;
}
crflag = (chr == CR); /* flag set if last char was CR */
if ((chr == LF) && ((endsw < 0 && z > BUFF_LIMIT) || (endsw > 0 && --endsw == 0))) break; /* term after N lines */
}
(*buff).p = p; /* update pointer */
(*buff).c = c;
if (ff_found) *ff_found = (chr == FF) ? -1 : 0; /* set flag to indicate whether FF found */
return( (chr == EOF) ? -1 : 0); /* and return "eof found" value */
}
\f
/* routine to write text buffer out to selected output file */
/* arguments are qp to start of text, number of characters, */
/* and an "append FF" switch */
write_file(buff, nchars, ffsw)
struct qp *buff;
int nchars, ffsw;
{
if (!outfile->fd && (nchars)) ERROR(E_NFO);
else write_stream(outfile->fd, buff, nchars, ez_val & EZ_CRLF);
if (outfile->fd && ffsw) putc(FF, outfile->fd);
}
/* routine to write text buffer to I/O stream. Used by */
/* write_file, above, and by "eq" write to pipe to other */
/* Unix processes. Arguments buff, nchars as above; file */
/* is stream pointer, crlf_sw zero converts CRLF to LF */
write_stream(file, buff, nchars, crlf_sw)
FILE *file;
struct qp *buff;
int nchars, crlf_sw;
{
char c;
int crflag;
crflag = 0;
for (; nchars > 0; nchars--)
{
if ((c = (*buff).p->ch[(*buff).c]) == CR) crflag = 1; /* set flag if a c.r. */
else
{
if ((crflag) && ((c != LF) || crlf_sw)) /* if c.r. not before lf, or if not in */
putc(CR, file); /* "no cr" mode, output the c.r. */
crflag = 0;
putc(c, file);
}
if (++(*buff).c > CELLSIZE-1)
{
(*buff).p = (*buff).p->f;
(*buff).c = 0;
}
}
}
/* routine to kill output file: argument is pointer to an output file structure */
kill_output(outptr)
struct outfiledata *outptr;
{
if (outptr->fd)
{
fclose(outptr->fd);
unlink(outptr->t_name);
outptr->fd = NULL;
}
}
\f
/* "panic" routine called when "hangup" signal occurs */
/* this routine saves the text buffer and closes the output files */
char panic_name[] = "TECO_SAVED.tmp"; /* name of file created to save buffer */
panic()
{
if (!outfile->fd && z) outfile->fd = fopen(panic_name, "w"); /* if buffer nonempty and no file open, make one */
set_pointer(0, &aa); /* set a pointer to start of text buffer */
if (outfile->fd && z) write_file(&aa, z, 0); /* and write out buffer unless "open" failed */
if (po_file.fd) fclose(po_file.fd), po_file.fd = NULL; /* close any open output files */
if (so_file.fd) fclose(so_file.fd), so_file.fd = NULL;
}
\f
/* do "F" commands */
do_f()
{
struct buffcell *delete_p;
switch (mapch_l[getcmdc(trace_sw)]) /* read next character and dispatch */
{
case '<': /* back to beginning of current iteration */
if (cptr.flag & F_ITER) /* if in iteration */
{
cptr.p = cptr.il->p; /* restore */
cptr.c = cptr.il->c;
cptr.dot = cptr.il->dot;
}
else for (cptr.dot = cptr.c = 0; cptr.p->b->b != NULL; cptr.p = cptr.p->b); /* else, restart current macro */
break;
case '>': /* to end of current iteration */
find_enditer(); /* find it */
if ( ( ((esp->flag1) ? esp->val1 : srch_result) >= 0) ? (~colonflag) : colonflag) /* if exit */
pop_iteration(0); /* and exit if appropriate */
break;
case '\'': /* to end of conditional */
case '|': /* to "else," or end */
find_endcond(cmdc);
break;
/* "F" search commands */
case 'b': /* bounded search, alternative args */
do_fb();
break;
case 'c': /* bounded search, alternative args, then "FR" */
if (do_fb()) goto do_fr;
while (getcmdc(trace_sw) != term_char); /* otherwise skip insert string */
break;
case 'n': /* do "N" and then "FR" */
if (do_nsearch('n')) goto do_fr;
while (getcmdc(trace_sw) != term_char); /* otherwise skip insert string */
break;
case '_': /* do "_" and then "FR" */
if (do_nsearch('_')) goto do_fr;
while (getcmdc(trace_sw) != term_char); /* otherwise skip insert string */
break;
case 's': /* search and replace: search, then do "FR" */
build_string(&sbuf); /* read search string and terminator */
if (end_search( do_search( setup_search() ) )) goto do_fr; /* if search passed, do "FR" */
while (getcmdc(trace_sw) != term_char); /* otherwise skip insert string */
break;
\f
case 'r': /* replace last insert, search, etc. */
if (esp->flag1) ERROR(E_NFR); /* shouldn't have argument */
term_char = (atflag) ? getcmdc(trace_sw) : ESC; /* set terminator */
atflag = 0;
do_fr: /* entry from FN, F_, and FC */
set_pointer(dot, &cc); /* save a pointer to the current spot */
dot += ctrl_s; /* back dot up over the string */
set_pointer(dot, &aa); /* code from "insert1": convert dot to a qp */
delete_p = aa.p; /* save beginning of original cell */
if (dot < buff_mod) buff_mod = dot; /* update earliest char loc touched */
insert_p = bb.p = get_bcell(); /* get a new cell */
bb.c = 0;
ins_count = aa.c; /* save char position of dot in cell */
aa.c = 0;
movenchars(&aa, &bb, ins_count); /* copy cell up to dot */
moveuntil(&cptr, &bb, term_char, &ins_count, cptr.z-cptr.dot, trace_sw); /* insert */
cptr.dot += ins_count; /* advance command-string pointer */
getcmdc(trace_sw); /* skip terminator */
z += ctrl_s; /* subtract delete length from buffer count */
delete_p->b->f = insert_p; /* put the new cell where the old one was */
insert_p->b = delete_p->b; /* code borrowed from "insert2" */
insert_p = NULL;
if (bb.c == cc.c) /* if replacement text was same length, we can save time */
{
for (; bb.c < CELLSIZE; bb.c++) bb.p->ch[bb.c] = cc.p->ch[bb.c]; /* copy rest of cell */
bb.p->f = cc.p->f; /* replace orig cell's place in chain with end of new list */
if (bb.p->f) bb.p->f->b = bb.p;
cc.p->f = NULL; /* terminate the part snipped out */
free_blist(delete_p); /* return the old part */
}
else /* different positions: shift the remainder of the buffer */
{
bb.p->f = delete_p; /* splice rest of buffer to end */
delete_p->b = bb.p;
movenchars(&cc, &bb, z-dot); /* squeeze buffer */
free_blist(bb.p->f); /* return unused cells */
bb.p->f = NULL; /* and end the buffer */
}
z += ins_count; /* add # of chars inserted */
dot += ins_count;
ctrl_s = -ins_count; /* save string length */
esp->flag1 = esp->flag2 = 0; /* and consume arguments */
esp->op = OP_START;
break;
default:
ERROR(E_IFC);
}
}
\f
/* routines for macro iteration */
/* pop iteration: if arg nonzero, exit unconditionally */
/* else check exit conditions and exit or reiterate */
pop_iteration(arg)
int arg;
{
if (!arg && (!cptr.il->dflag || (--(cptr.il->count) > 0)) ) /* if reiteration */
{
cptr.p = cptr.il->p; /* restore */
cptr.c = cptr.il->c;
cptr.dot = cptr.il->dot;
}
else
{
if (cptr.il->b) cptr.il = cptr.il->b; /* if not last thing on stack, back up */
else cptr.flag &= ~F_ITER; /* else clear "iteration" flag */
}
}
/* find end of iteration - read over arbitrary <> and one > */
find_enditer()
{
register int icnt;
for (icnt = 1; icnt > 0;) /* scan for matching > */
{
while ((skipto(0) != '<') && (skipc != '>')); /* scan for next < or > */
if (skipc == '<') ++icnt; /* and keep track of macro level */
else --icnt;
}
}
/* find end of conditional */
char find_endcond(arg)
char arg;
{
register int icnt;
for (icnt = 1; icnt > 0;)
{
while ((skipto(0) != '"') && (skipc != '\'') && (skipc != '|'));
if (skipc == '"') ++icnt;
else if (skipc == '\'') -- icnt;
else if ((icnt == 1) && (arg == '|')) break;
}
}