|
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; } }