Subject: v09i029: A TECO text editor, Part02/04 Newsgroups: mod.sources Approved: rs@mirror.TMC.COM Submitted by: genrad!mlf Mod.sources: Volume 9, Issue 29 Archive-name: teco/Part02 #! /bin/sh # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # If this archive is complete, you will see the message: # "End of archive 2 (of 4)." # Contents: te_chario.c te_defs.h te_srch.c te_subs.c # Wrapped by rs@mirror on Thu Mar 12 19:54:28 1987 PATH=/bin:/usr/bin:/usr/ucb ; export PATH echo shar: Extracting \"te_chario.c\" \(9049 characters\) if test -f te_chario.c ; then echo shar: Will not over-write existing file \"te_chario.c\" else sed "s/^X//" >te_chario.c <<'END_OF_te_chario.c' X/* TECO for Ultrix Copyright 1986 Matt Fichtenbaum */ X/* This program and its components belong to GenRad Inc, Concord MA 01742 */ X/* They may be copied if this copyright notice is included */ X X/* te_chario.c character I/O routines 10/9/86 */ X#include X#include "te_defs.h" X X#include X#ifndef DEBUG X#include Xextern int int_handler(); Xextern int stp_handler(); Xextern int hup_handler(); X#define SIGINTMASK 2 X#endif X Xint lf_sw; /* nonzero: make up a LF following an entered CR */ Xint ttyflags; /* flags for (stdin) file descriptor */ Xstruct tchars tc_orig, tc_new, tc_noint; /* original, new, disabled intrpt tty special chars */ Xstruct ltchars lc_orig, lc_new; /* original and new local special chars */ Xstruct sgttyb tty_orig, tty_new; /* original and new tty flags */ Xint tty_local; /* original tty local mode flags */ Xint lnoflsh = LNOFLSH; /* bit to force "no flush on interrupt */ X X#ifndef DEBUG Xstruct sigvec intsigstruc = { int_handler, 0, 0 } ; /* info structure for ^C interrupt */ Xstruct sigvec stpsigstruc = { stp_handler, 0, 0 } ; /* info structure for "stop" signal */ Xstruct sigvec hupsigstruc = { hup_handler, 0, 0 } ; /* info structure for "hangup" signal */ Xstruct sigvec nosigstr = { SIG_DFL, 0, 0 }; /* default structure for signal */ X#endif X Xint inp_noterm; /* nonzero if standard input is not a terminal */ Xint out_noterm; /* nonzero if standard output is not a terminal */ X /* set tty (stdin) mode. TECO mode is CBREAK, no ECHO, sep CR & LF */ X/* operation; normal mode is none of the above. TTY_OFF and TTY_ON do this */ X/* absolutely; TTY_SUSP and TTY_RESUME use saved signal status. */ X Xsetup_tty(arg) X int arg; X { X extern int errno; X int ioerr; X struct sgttyb tmpbuf; X X/* initial processing: set tty mode */ X X if (arg == TTY_ON) X { X ioerr = ioctl(fileno(stdin), TIOCGETP, &tty_orig); /* get std input characteristics */ X inp_noterm = (ioerr && (errno == ENOTTY)); /* nonzero if input not a terminal */ X ioerr = ioctl(fileno(stdout), TIOCGETP, &tmpbuf); /* get std output characteristics */ X out_noterm = (ioerr && (errno == ENOTTY)); /* nonzero if output not a terminal */ X ioctl(fileno(stdout), TIOCLGET, &tty_local); /* get current "local mode flags" word */ X X ttybuf = tty_new = tty_orig; /* make a copy of tty control structure */ X tty_new.sg_flags = (tty_new.sg_flags & ~ECHO & ~CRMOD) | CBREAK; /* turn on teco modes */ X X ioctl(fileno(stdin), TIOCGETC, &tc_orig); /* read current tchars */ X tc_new = tc_orig; /* make local copy */ X tc_new.t_quitc = tc_new.t_brkc = -1; /* disable "quit" and "delimiter" chars */ X tc_noint = tc_new; X tc_noint.t_intrc = -1; /* disable the interrupt char in this one */ X X ioctl(fileno(stdin), TIOCGLTC, &lc_orig); /* read current ltchars */ X lc_new = lc_orig; /* make local copy */ X lc_new.t_rprntc = lc_new.t_werasc = lc_new.t_lnextc = -1; /* disable "reprint," "word erase," "lit next" */ X } X X if ((arg == TTY_ON) || (arg == TTY_RESUME)) X { X ioctl(fileno(stdin), TIOCSETP, &tty_new); /* set flags for teco */ X ioctl(fileno(stdin), TIOCSETC, &tc_new); /* update both */ X ioctl(fileno(stdin), TIOCSLTC, &lc_new); X ioctl(fileno(stdout), TIOCLBIS, &lnoflsh); /* disable "interrupt => flush buffers" */ X#ifndef DEBUG X sigvec(SIGTSTP, &stpsigstruc, 0); /* set up to trap "stop" signal */ X sigvec(SIGINT, &intsigstruc, 0); /* and "interrupt" signal */ X sigvec(SIGHUP, &hupsigstruc, 0); /* and "hangup" signal */ X#endif X } X else X { X ioctl(fileno(stdin), TIOCSETP, &tty_orig); /* set flags back to original */ X ioctl(fileno(stdin), TIOCSETC, &tc_orig); /* put both back to orig states */ X ioctl(fileno(stdin), TIOCSLTC, &lc_orig); X ioctl(fileno(stdout), TIOCLSET, &tty_local); /* restore local mode flags to original states */ X#ifndef DEBUG X sigvec(SIGTSTP, &nosigstr, 0); /* restore default signal handling */ X sigvec(SIGINT, &nosigstr, 0); X sigvec(SIGHUP, &nosigstr, 0); X#endif X } X } X /* routines to handle keyboard input */ X X/* routine to get a character without waiting, used by ^T when ET & 64 is set */ X/* if lf_sw is nonzero, return the LF; else use the FNDELAY fcntl to inquire of the input */ X Xint gettty_nowait() X { X int c; X X if (lf_sw) X { X lf_sw = 0; X return(LF); /* LF to be sent: return it */ X } X fcntl(fileno(stdin), F_SETFL, ttyflags | FNDELAY); /* set to "no delay" mode */ X while (!(c = getchar())); /* read character, or -1, skip nulls */ X fcntl(fileno(stdin), F_SETFL, ttyflags); /* reset to normal mode */ X if (c == CR) ++lf_sw; /* CR: set switch to make up a LF */ X return(c); X } X X X X/* normal routine to get a character */ X Xint in_read = 0; /* flag for "read busy" (used by interrupt handler) */ X Xchar gettty() X { X int c; X X if (lf_sw) X { X lf_sw = 0; X return(LF); /* if switch set, make up a line feed */ X } X ++in_read; /* set "read busy" switch */ X while(!(c = getchar())); /* get character; skip nulls */ X in_read = 0; /* clear switch */ X if (c == CR) ++lf_sw; /* CR: set switch to make up a LF */ X if (c == EOF) ERROR(E_EFI); /* end-of-file from standard input */ X return( (char) c & 0177); /* and return the 7-bit char */ X } X X#ifndef DEBUG X X/* routine to handle interrupt signal */ X Xint_handler() X { X X if (exitflag <= 0) /* if executing commands */ X { X if (et_val & ET_CTRLC) et_val &= ~ET_CTRLC; /* if "trap ^C" set, clear it and ignore */ X else exitflag = -2; /* else set flag to stop execution */ X } X if (in_read) /* if interrupt happened in "getchar" pass a ^C to input */ X { X in_read = 0; /* clear "read" switch */ X ioctl(fileno(stdin), TIOCSETC, &tc_noint); /* disable interrupt char */ X qio_char(CTL (C)); /* send a ^C to input stream */ X ioctl(fileno(stdin), TIOCSETC, &tc_new); /* reenable interrupt char */ X } X } X#endif X /* routine to disable (1), enable (0) ^C interrupt, used to block interrupts during display update */ X Xint old_mask; /* storage for previous signal mask */ X#define INT_MASK 2 X Xblock_inter(func) X int func; X { X#ifndef DEBUG X if (func) old_mask = sigblock(INT_MASK); /* if arg nonzero, block interrupt */ X else sigsetmask(old_mask); /* otherwise restore old signal mask */ X#endif X } X X X X#ifndef DEBUG X/* routine to handle "stop" signal (^Y) */ X Xstp_handler() X { X window(WIN_SUSP); /* restore screen */ X setup_tty(TTY_SUSP); /* put tty back to normal */ X sigvec(SIGTSTP, &nosigstr, 0); /* put default action back */ X sigsetmask(0); /* unblock "suspend" signal */ X kill(0, SIGTSTP); /* suspend this process */ X X/* ----- process gets suspended here ----- */ X X sigvec(SIGTSTP, &stpsigstruc, 0); /* restore local handling of "stop" signal */ X setup_tty(TTY_RESUME); /* restore tty */ X buff_mod = 0; /* set whole screen modified */ X if (win_data[7]) /* redraw window */ X { X window(WIN_RESUME); /* re-enable window */ X window(WIN_REDRAW); /* force complete redraw */ X window(WIN_REFR); /* and refresh */ X } X qio_char('\0'); /* wake up the input X if (exitflag) retype_cmdstr('*'); /* if not executing, prompt again and echo command string so far */ X } X#endif X X X X/* simulate a character's having been typed on the keyboard */ X Xqio_char(c) X char c; X { X ioctl(fileno(stdin), TIOCSTI, &c); /* send char to input stream */ X } X /* routine to handle "hangup" signal */ X#ifndef DEBUG X Xhup_handler() X { X if (!exitflag) exitflag = -3; /* if executing, set flag to terminate */ X else X { X panic(); /* dump buffer and close output files */ X exit(1); X } X } X#endif X X X X/* type a crlf */ X Xcrlf() X { X type_char(CR); X type_char(LF); X } X X X X/* reset ^O status */ X Xint lflusho = LFLUSHO; Xint lfo; X Xreset_ctlo() X { X ioctl(fileno(stdin), TIOCLGET, &lfo); /* read flags */ X if (lfo & LFLUSHO) /* if ^O was set */ X { X ioctl(fileno(stdin), TIOCLBIC, &lflusho); /* reset ^O */ X crlf(); /* type a crlf */ X } X } X /* routine to type one character */ X Xtype_char(c) X char c; X { X X if ((char_count >= WN_width) && (c != CR) && !(spec_chars[c] & A_L)) /* spacing char beyond end of line */ X { X if (et_val & ET_TRUNC) return; /* truncate output to line width */ X else crlf(); /* otherwise do automatic new line (note recursive call to type_char) */ X } X X if ((c & 0140) == 0) /* control char? */ X { X switch (c & 0177) X { X case CR: X putchar(c); X char_count = 0; X break; X X case LF: X putchar(c); X/* scroll_dly(); /* filler chars in case VT-100 scrolls */ X break; X X case ESC: X if ((et_val & ET_IMAGE) && !exitflag) putchar(c); X else X { X putchar('$'); X char_count++; X } X break; X X case TAB: X if ((et_val & ET_IMAGE) && !exitflag) putchar(c); X else for (type_char(' '); (char_count & tabmask) != 0; type_char(' ')); X break; X X default: X if ((et_val & ET_IMAGE) && !exitflag) putchar(c); X else X { X putchar('^'); X putchar(c + 'A'-1); X char_count += 2; X } X break; X } X } X else X { X putchar(c); X char_count++; X } X } X END_OF_te_chario.c if test 9049 -ne `wc -c te_defs.h <<'END_OF_te_defs.h' X/* TECO for Ultrix Copyright 1986 Matt Fichtenbaum */ X/* This program and its components belong to GenRad Inc, Concord MA 01742 */ X/* They may be copied if this copyright notice is included */ X X/* te_defs.h definitions file 1/9/87 */ X X#include X#include X#include X#include X X#define CTL(x) (('x') & 0x1f) /* for control chars */ X#define ERROR(e) longjmp(xxx, (e)) X#define BLOCKSIZE (0x10000 - 8) /* size of memory block to allocate */ X#define CELLSIZE 256 /* number of characters per cell */ X#define CSTACKSIZE 64 /* size of command stack */ X#define MSTACKSIZE 64 /* size of macro stack */ X#define QSTACKSIZE 64 /* size of q register stack */ X#define ESTACKSIZE 64 /* size of expression stack */ X#define TTIBUFSIZE 1024 /* size of type-ahead buffer */ X#define BUFF_LIMIT 16384 /* text buffer soft limit for ED & 4 */ X#define NQREGS 36 /* number of Q registers */ X#define CBUFF 0 /* id for command buffer */ X#define SERBUF NQREGS+1 /* and search string buffer */ X#define FILBUF NQREGS+2 /* and file string buffer */ X#define SYSBUF NQREGS+3 /* and system command buffer */ X#define TIMBUF NQREGS+4 /* and time/date buffer */ X#define cbuf qreg[CBUFF] /* shorthand for command-string header */ X#define sbuf qreg[SERBUF] /* and for search-buffer header */ X#define fbuf qreg[FILBUF] /* and for file-buffer header */ X#define sysbuf qreg[SYSBUF] /* and for system command header */ X#define timbuf qreg[TIMBUF] /* and for time/date header */ X#define cptr (*msp) /* command string is top of macro stack */ X#define cmdstr mstack[0] /* for entering command string */ X#define TAB 011 /* define special chars */ X#define LF 012 X#define VT 013 X#define FF 014 X#define CR 015 X#define ESC 033 X#define DEL 0177 X X/* expression operators */ X#define OP_START 1 X#define OP_ADD 2 X#define OP_SUB 3 X#define OP_MULT 4 X#define OP_DIV 5 X#define OP_AND 6 X#define OP_OR 7 X X/* macro flags */ X#define F_ITER 1 X X/* bits in special-character table */ X#define A_S 1 /* "skipto()" special character */ X#define A_T 2 /* command with std text argument */ X#define A_E 4 /* E takes a text argument */ X#define A_F 8 /* F takes a text argument */ X#define A_X 16 /* char causes "skipto()" to exit */ X#define A_Q 32 /* command with q-register argument */ X#define A_A 64 /* special char in search string */ X#define A_L 128 /* character is a line separator */ X X/* error codes */ X#define E_BNI 1 X#define E_CPQ 2 X#define E_COF 3 X#define E_FNF 4 X#define E_IEC 5 X#define E_IFC 6 X#define E_IIA 7 X#define E_ILL 8 X#define E_ILN 9 X#define E_IPA 10 X#define E_IQC 11 X#define E_IQN 12 X#define E_IRA 13 X#define E_ISA 14 X#define E_ISS 15 X#define E_IUC 16 X#define E_MEM 17 X#define E_MRP 18 X#define E_NAB 19 X#define E_NAC 20 X#define E_NAE 21 X#define E_NAP 22 X#define E_NAQ 23 X#define E_NAS 24 X#define E_NAU 25 X#define E_NFI 26 X#define E_NFO 27 X#define E_NYA 28 X#define E_OFO 29 X#define E_PDO 30 X#define E_POP 31 X#define E_SNI 32 X#define E_SRH 33 X#define E_STL 34 X#define E_UTC 35 X#define E_UTM 36 X#define E_XAB 37 X#define E_YCA 38 X#define E_IWA 39 X#define E_NFR 40 X#define E_INT 41 X#define E_EFI 42 X#define E_IAA 43 X#define E_AMB 44 X#define E_SYS 45 X X/* define names for window control registers */ X#define WN_type win_data[0] X#define WN_width win_data[1] X#define WN_height win_data[2] X#define WN_seeall win_data[3] X#define WN_mark win_data[4] X#define WN_hold win_data[5] X#define WN_origin win_data[6] X#define WN_scroll win_data[7] X X/* define display operations */ X#define WIN_OFF 0 /* disable window */ X#define WIN_SUSP 1 /* suspend window */ X#define WIN_INIT 2 /* turn on window */ X#define WIN_RESUME 3 /* re-enable window */ X#define WIN_REFR 4 /* refresh window */ X#define WIN_LINE 5 /* display one line */ X#define WIN_REDRAW 6 /* force window absolute redraw on next refresh */ X#define WIN_DISP 7 /* refresh window even if not enabled */ X X/* define scope special functions */ X#define VT_CLEAR 0 /* clear screen */ X#define VT_EEOL 1 /* erase to eol */ X#define VT_SETSPEC1 2 /* set special (reverse) video */ X#define VT_SETSPEC2 3 /* alternative special video */ X#define VT_CLRSPEC 4 /* clear it */ X#define VT_BS1 5 /* backspace and erase 1 */ X#define VT_BS2 6 /* backspace and erase 2 */ X#define VT_LINEUP 7 /* up one line */ X#define VT_EBOL 8 /* erase from bol */ X X/* define keyboard modes */ X#define TTY_OFF 0 /* final "off" */ X#define TTY_SUSP 1 /* temporary suspend */ X#define TTY_ON 2 /* initial "on" */ X#define TTY_RESUME 3 /* resume after suspend */ X X/* define values for ED, ET, EZ flags */ X#define ED_CARET 1 X#define ED_YPROT 2 X#define ED_EXPMEM 4 X#define ED_SFAIL 16 X#define ED_SMULT 64 X X#define ET_IMAGE 1 X#define ET_NOECHO 8 X#define ET_CTRLO 16 X#define ET_NOWAIT 32 X#define ET_QUIT 128 X#define ET_TRUNC 256 X#define ET_CTRLC 32768 X X#define EZ_CRLF 1 X#define EZ_READFF 2 X#define EZ_TAB4 4 X#define EZ_NOTMPFIL 8 X#define EZ_NOTABI 16 X#define EZ_NOVTFF 32 X#define EZ_MULT 64 X /* define buffer cell */ X/* a buffer cell is a forward pointer, a backward pointer, */ X/* and CELLSIZE characters */ X Xstruct buffcell X { X struct buffcell *f; /* forward pointer */ X struct buffcell *b; /* backward pointer */ X char ch[CELLSIZE]; /* char storage */ X }; X X/* define structures for buffer header, q-register header, */ X/* q-register pointer, macro stack entry, and macro iteration list */ X/* these are really alternative ways of looking at the same cell */ X Xstruct qh /* q-register header */ X { X struct buffcell *f; /* forward pointer */ X struct buffcell *b; /* backward pointer */ X int z; /* number of characters */ X int v; /* q-register numeric value */ X } ; X Xstruct qp /* q-register pointer/macro stack entry */ X { X struct qp *f; /* forward pointer */ X struct buffcell *p; /* pointer to a buffer cell */ X int c; /* character offset */ X int z; /* number of characters in object pointed to */ X int dot; /* current character position */ X int flag; /* flags for "iteration in process," "ei macro," etc. */ X struct is *il; /* iteration list pointer */ X int *condsp; /* saved conditional stack pointer */ X } ; X Xstruct is /* macro iteration list entry */ X { X struct is *f; /* forward pointer */ X struct is *b; /* backward pointer */ X struct buffcell *p; /* cell with start of iteration */ X int c; /* char offset where iteration started */ X int dot; /* char position where iteration started */ X int count; /* iteration count */ X int dflag; /* definite iteration flag */ X } ; X Xstruct ms /* macro stack entry */ /* not used at present */ X { X struct ms *f; /* forward pointer */ X struct ms *b; /* backward pointer */ X struct buffcell *p; /* pointer to a buffer cell */ X int c; /* character offset */ X struct is *il; /* pointer to iteration list */ X } ; X Xstruct bh /* buffer header list entry */ X { X struct buffcell *f; /* pointer to buffer */ X struct buffcell *b; /* null pointer */ X int z; /* number of characters */ X int v; /* not used */ X struct bh *ff; /* forward pointer */ X struct bh *bb; /* backward pointer */ X } ; X X/* define expression stack entry */ Xstruct exp_entry X { X int val1; /* first value */ X int flag1; /* nonzero if there is a first value */ X int val2; /* second value (set by 'comma') */ X int flag2; /* nonzero if there is one */ X int exp; /* expression in process */ X int op; /* operation to be applied */ X } ; X X/* define file data structures */ Xstruct infiledata /* structure of input file info */ X { X FILE *fd; /* file pointer */ X int eofsw; /* end-of-file switch */ X } ; X Xstruct outfiledata /* structure of output file info */ X { X FILE *fd; /* file pointer */ X char f_name[CELLSIZE+5]; /* real name of output */ X char t_name[CELLSIZE+5]; /* temporary output name */ X int name_size; /* number of chars in name */ X int bak; /* backup flag */ X } ; X Xextern struct infiledata *infile; /* pointer to currently active intput file structure */ Xextern struct outfiledata *outfile; /* pointer to currently active output file structure */ Xextern struct outfiledata po_file, so_file; /* output file descriptors */ X /* define global variables, etc. */ X Xextern int char_count; /* char count for tab typer */ Xextern char lastc; /* last char read */ Xextern int ttyerr; /* error return from ioctl */ Xextern int errno; /* system error code */ Xextern struct sgttyb ttybuf; /* local copy of tty control data */ Xextern int inp_noterm; /* nonzero if standard in is not a terminal */ Xextern int out_noterm; /* nonzero if standard out is not a term. */ Xextern jmp_buf xxx; /* preserved environment for error restart */ Xextern int err; /* local error code */ Xextern struct qp t_qp; /* temporary buffer pointer */ Xextern struct qp aa, bb, cc; /* more temporaries */ Xextern struct buffcell t_bcell; /* temporary bcell */ Xextern int tabmask; /* mask for selecting 4/8 char tabs */ Xextern int exitflag; /* flag for ending command str exec */ Xextern char term_char; /* terminator for insert, search, etc. */ Xextern char cmdc; /* current command character */ Xextern char skipc; /* char found by "skipto()" */ Xextern int dot, z, tdot; /* current, last, temp buffer position */ Xextern int ll, mm, nn; /* general temps */ Xextern int ins_count; /* count of chars inserted */ Xextern int ctrl_e; /* form feed flag */ Xextern int ctrl_r; /* current number radix (8, 10, 16) */ Xextern int ctrl_s; /* string length for S, I, G */ Xextern int ctrl_x; /* search case flag */ Xextern int ed_val; /* ED value */ Xextern int es_val; /* ES value */ Xextern int et_val; /* ET value */ Xextern int eu_val; /* EU value */ Xextern int ev_val; /* EV value */ Xextern int ez_val; /* EZ value */ Xextern int srch_result; /* result of last :S executed */ Xextern int atflag; /* flag for @ char typed */ Xextern int colonflag; /* flag for : char typed */ Xextern int trace_sw; /* nonzero if tracing command exec */ X Xextern int win_data[]; /* window control parameters */ Xextern struct buffcell *insert_p; /* pointer to temp text buffer during insert */ Xextern int buff_mod; /* set to earliest buffer change */ Xextern int search_flag; /* set nonzero by search */ X Xextern char *errors[]; /* error text */ Xextern char mapch[], mapch_l[]; /* char mapping tables */ Xextern char spec_chars[]; /* special character table */ X Xextern char skipto(), find_endcond(), getcmdc(), getcmdc0(); /* routines that return chars */ X Xextern FILE *eisw; /* indirect command file pointer */ Xextern FILE *fopen(); X Xextern struct buffcell *freebuff; /* buffcell free-list pointer */ Xextern struct buffcell *dly_freebuff; /* delayed free-list pointer */ Xextern struct qp *freedcell; /* cell free-list pointer */ Xextern struct buffcell *get_bcell(); /* get buffcell routine */ Xextern struct qp *get_dcell(); /* get data cell routine */ X X/* the text buffer header */ Xextern struct qh buff; X X/* the q-register headers point to the start of the buffer and registers */ Xextern struct qh qreg[]; /* for q regs, command, search, file */ X X/* the q-register stack contains temporary copies of q-register contents */ Xextern struct qh qstack[]; /* q-reg stack */ Xextern struct qh *qsp; /* q-reg stack pointer */ X X/* the macro stack contains pointers to the currently active macros. */ X/* the top of the stack is the command pointer */ Xextern struct qp mstack[]; /* macro stack */ Xextern struct qp *msp; /* macro stack pointer */ X X/* the expression stack */ Xextern struct exp_entry estack[]; /* expression stack */ Xextern struct exp_entry *esp; /* expression stack pointer */ X END_OF_te_defs.h if test 11866 -ne `wc -c te_srch.c <<'END_OF_te_srch.c' X/* TECO for Ultrix Copyright 1986 Matt Fichtenbaum */ X/* This program and its components belong to GenRad Inc, Concord MA 01742 */ X/* They may be copied if this copyright notice is included */ X X/* te_srch.c routines associated with search operations 2/5/86 */ X#include "te_defs.h" X X/* routine to read in a string with string-build characters */ X/* used for search, tag, file name operations */ X/* returns 0 if empty string entered, nonzero otherwise */ X Xint build_string(buff) X struct qh *buff; /* arg is addr of q-reg header */ X { X int count; /* char count */ X struct buffcell *tp; /* pointer to temporary string */ X char c; /* temp character */ X X term_char = (atflag) ? getcmdc(trace_sw) : ESC; /* read terminator */ X count = atflag = 0; /* initialize char count */ X if (!peekcmdc(term_char)) /* if string is not empty */ X { X X/* create a temporary string and read chars into it until the terminator */ X for (tp = bb.p = get_bcell(), bb.c = 0; (c = getcmdc(trace_sw)) != term_char; ) X { X if ((c == '^') && !(ed_val & ED_CARET)) /* read next char as CTL */ X { X if ((c = getcmdc(trace_sw)) == term_char) ERROR(msp <= &mstack[0] ? E_UTC : E_UTM); X c &= 0x1f; X } X if ((c &= 0177) < ' ') /* if a control char */ X { X switch (c) X { X case CTL (Q): /* take next char literally */ X case CTL (R): X if ((c = getcmdc(trace_sw)) == term_char) ERROR((msp <= &mstack[0]) ? E_UTC : E_UTM); X break; /* fetch character and go store */ X X case CTL (V): /* take next char as lower case */ X if (getcmdc(trace_sw) == term_char) ERROR((msp <= &mstack[0]) ? E_UTC : E_UTM); X c = mapch_l[cmdc]; X break; X X case CTL (W): /* take next char as upper case */ X if ((c = getcmdc(trace_sw)) == term_char) ERROR((msp <= &mstack[0]) ? E_UTC : E_UTM); X if (islower(c)) c = toupper(c); X break; X X case CTL (E): /* expanded constructs */ X if (getcmdc(trace_sw) == term_char) ERROR((msp <= &mstack[0]) ? E_UTC : E_UTM); X switch (mapch_l[cmdc]) X { X case 'u': /* use char in q-reg */ X if (getcmdc(trace_sw) == term_char) ERROR((msp <= &mstack[0]) ? E_UTC : E_UTM); X c = qreg[getqspec(1, cmdc)].v & 0x7f; X break; X X case 'q': /* use string in q-reg */ X if (getcmdc(trace_sw) == term_char) ERROR((msp <= &mstack[0]) ? E_UTC : E_UTM); X ll = getqspec(1, cmdc); /* read the reg spec */ X aa.p = qreg[ll].f; /* set a pointer to it */ X aa.c = 0; X for (mm = 0; mm < qreg[ll].z; mm++) X { X bb.p->ch[bb.c] = aa.p->ch[aa.c]; /* store char */ X fwdcx(&bb); /* store next char */ X fwdc(&aa); X ++count; X } X continue; /* repeat loop without storing */ X X default: X bb.p->ch[bb.c] = CTL (E); /* not special: store the ^E */ X fwdcx(&bb); X ++count; X c = cmdc; /* and go store the following char */ X break; X X } /* end ^E switch */ X } /* end outer switch */ X } /* end "if a control char */ X bb.p->ch[bb.c] = c; /* store character */ X fwdcx(&bb); /* advance pointer */ X ++count; /* count characters */ X } /* end "for" loop */ X free_blist(buff->f); /* return old buffer */ X buff->f = tp; /* put in new one */ X buff->f->b = (struct buffcell *) buff; X buff->z = count; /* store count of chars in string */ X } /* end non-null string */ X else getcmdc(trace_sw); /* empty string: consume terminator */ X return(count); /* return char count */ X } X X X X X/* routine to handle end of a search operation */ X/* called with pass/fail result from search */ X/* returns same pass/fail result */ X Xint end_search(result) X int result; X { X if (!result) /* if search failed */ X { X if (!(esp->flag2 || (ed_val & ED_SFAIL))) dot = 0; /* if an unbounded search failed, clear ptr */ X if (!colonflag && !peekcmdc(';')) ERROR(E_SRH); /* if no real or implied colon, error if failure */ X } X esp->flag1 = colonflag; /* return a value if a :S command */ X srch_result = esp->val1 = result; /* and leave it for next ";" */ X esp->flag2 = colonflag = atflag = 0; /* consume arguments */ X esp->op = OP_START; X return(result); X } X X/* routine to set up for search operation */ X/* reads search arguments, returns search count */ X Xstatic struct qp sm, sb; /* match-string and buffer pointers */ Xstatic char *pmap; /* pointer to character mapping table */ Xstatic int locb; /* reverse search limit */ Xstatic int last_z; /* end point for reverse search */ X Xint setup_search() X { X int count; /* string occurrence counter */ X X set_pointer(dot, &aa); /* set a pointer to start of search */ X if (colonflag >= 2) esp->flag2 = esp->flag1 = esp->val2 = esp->val1 = 1; /* ::S is 1,1S */ X if ((count = get_value(1)) == 0) ERROR(E_ISA); /* read search count: default is 1 */ X else if (count > 0) /* search forward */ X { X if (esp->flag2) /* if bounded search */ X { X if (esp->val2 < 0) esp->val2 = -(esp->val2); /* set limit */ X if ((aa.z = dot + esp->val2) > z) aa.z = z; /* or z, whichever less */ X } X else aa.z = z; X } X else X { X if (esp->flag2) /* if bounded search */ X { X if (esp->val2 < 0) esp->val2 = -(esp->val2); /* set limit */ X if ((locb = dot - esp->val2) < 0) locb = 0; /* or 0, whichever greater */ X } X else locb = 0; X } X return(count); X } X X/* routine to do N, _, E_ searches: search, if search fails, then get */ X/* next page and continue */ X Xdo_nsearch(arg) X char arg; /* arg is 'n', '_', or 'e' to define which search */ X { X int scount; /* search count */ X X build_string(&sbuf); /* read the search string */ X if ((scount = get_value(1)) <= 0) ERROR(E_ISA); /* count must be >0 */ X set_pointer(dot, &aa); /* start search at dot */ X esp->flag2 = locb = 0; /* make it unbounded */ X X while (scount > 0) /* search until found */ X { X if (!do_search(1)) /* search forwards */ X { /* if search fails... */ X if (infile->eofsw || !infile->fd) break; /* if no input, quit */ X if (arg == 'n') X { X set_pointer(0, &aa); /* write file if 'n' */ X write_file(&aa, z, ctrl_e); X } X X /* not 'n': if _, and an output file, and data to lose, error */ X else if ((arg == '_') && (outfile->fd) && (z) && (ed_val & ED_YPROT)) ERROR(E_YCA); X X buff_mod = dot = z = 0; /* clear buffer */ X set_pointer(0, &aa); X read_file(&aa, &z, (ed_val & ED_EXPMEM ? -1 : 0) ); /* read next page */ X set_pointer(0, &aa); /* search next page from beginning */ X } X else --scount; /* search successful: one fewer to look for */ X } X return( end_search( (scount == 0) ? -1 : 0) ); /* use end_search to clean up */ X } X X X/* routine to do "FB" search - m,nFB is search from m to n, */ X/* nFB is search from . to nth line */ X/* convert arguments to args of normal m,nS command */ X Xint do_fb() /* returns search result */ X { X if (esp->flag1 && esp->flag2) /* if two arguments */ X { X dot = esp->val2; /* start from "m" arg */ X esp->val2 = esp->val1 - esp->val2; /* get number of chars */ X } X else /* if no or one args, treat as number of lines */ X { X esp->val2 = lines(get_value(1)); /* number of chars */ X esp->flag2 = esp->flag1 = 1; /* conjure up two args */ X } X esp->val1 = (esp->val2 > 0) ? 1 : -1; /* set search direction */ X X build_string(&sbuf); /* read search string and terminator */ X return(end_search( do_search( setup_search() ) )); /* do search and return result */ X } X X/* routine to do search operation: called with search count as argument */ X/* returns -1 (pass) or 0 (fail) */ X Xint do_search(count) X int count; X { X pmap = (ctrl_x) ? &mapch[0] : &mapch_l[0]; /* set approp. mapping table */ X sm.z = sbuf.z; /* copy # of chars in search buffer */ X X if (count > 0) X { X for (sm.dot = 0; count > 0; count--) /* loop to count occurrences */ X { X for (; aa.dot < aa.z; aa.dot++) /* loop to advance search pointer */ X { X for (sb.p = aa.p, sb.c = aa.c, sb.dot = aa.dot, sm.p = sbuf.f, sm.dot = sm.c = 0; X (sb.dot < z) && (sm.dot < sm.z); sm.dot++, sb.dot++) X { /* for each char in search string */ X if (spec_chars[ sm.p->ch[sm.c] ] & A_A) /* if search string char is "special" */ X { X if (!srch_cmp()) break; /* then use expanded comparison routine */ X } X else if (*(pmap + sb.p->ch[sb.c]) != *(pmap + sm.p->ch[sm.c])) break; /* else just compare */ X if (++sm.c > CELLSIZE-1) /* advance search-string ptr */ X { X sm.p = sm.p->f; X sm.c = 0; X } X if (++sb.c > CELLSIZE-1) /* advance buffer ptr */ X { X sb.p = sb.p->f; X sb.c = 0; X } X } /* end comparison loop */ X X if (sm.dot >= sm.z) break; /* exit if found */ X if (++aa.c > CELLSIZE-1) /* else not found: advance buffer pointer */ X { X aa.p = aa.p->f; X aa.c = 0; X } X } /* end search loop */ X X if (sm.dot < sm.z) break; /* if one search failed, don't do more */ X else X { X ctrl_s = aa.dot - sb.dot; /* otherwise save -length of string found */ X if ((ed_val & ED_SMULT) && (count > 1)) /* if funny "advance by 1" mode */ X { X ++aa.dot; /* advance buffer pointer by one only */ X if (++aa.c > CELLSIZE-1) X { X aa.p = aa.p->f; X aa.c = 0; X } X } X else X { X aa.dot = sb.dot; /* advance search pointer past string */ X aa.p = sb.p; X aa.c = sb.c; X } X } X } /* end "search n times" */ X } /* end "search forwards" */ X X else /* search backwards */ X { X for (last_z = z, sm.dot = 0; count < 0; count++) /* loop to count occurrences */ X { X for (; aa.dot >= locb; aa.dot--) /* loop to advance (backwards) search pointer */ X { X for (sb.p = aa.p, sb.c = aa.c, sb.dot = aa.dot, sm.p = sbuf.f, sm.dot = sm.c = 0; X (sb.dot < last_z) && (sm.dot < sm.z); sm.dot++, sb.dot++) X { /* loop to compare string */ X if (spec_chars[ sm.p->ch[sm.c] ] & A_A) /* if search string char is "special" */ X { X if (!srch_cmp()) break; /* then use expanded comparison routine */ X } X else if (*(pmap + sb.p->ch[sb.c]) != *(pmap + sm.p->ch[sm.c])) break; /* else just compare */ X if (++sm.c > CELLSIZE-1) /* advance search-string ptr */ X { X sm.p = sm.p->f; X sm.c = 0; X } X if (++sb.c > CELLSIZE-1) /* advance buffer ptr */ X { X sb.p = sb.p->f; X sb.c = 0; X } X } /* end comparison loop */ X if (sm.dot >= sm.z) /* search matches: */ X { X if (!(ed_val & ED_SMULT)) last_z = aa.dot; /* set last_z to point where this string was found */ X break; X } X if (sb.dot >= last_z) /* or if string is beyond end of buffer */ X { X sm.dot = sm.z; /* make search appear to have succeeded */ X --count; /* so as to back up pointer, and force one more look */ X break; X } X if (--aa.c < 0) /* else advance buffer pointer (backwards) */ X { X aa.p = aa.p->b; X aa.c = CELLSIZE-1; X } X } /* end search loop */ X if (sm.dot < sm.z) break; /* if one search failed, don't do more */ X else X { X if (count < -1) backc(&aa); /* if this is not last search, back pointer up one */ X else X { X ctrl_s = aa.dot - sb.dot; /* otherwise save -length of string found */ X aa.dot = sb.dot; /* advance pointer past string */ X aa.p = sb.p; X aa.c = sb.c; X } X } X } /* end "search n times" */ X } /* end "search backwards" */ X if (sm.dot >= sm.z) dot = aa.dot; /* if search succeeded, update pointer */ X search_flag = 1; /* set "search occurred" (for ES) */ X return((sm.dot >= sm.z) ? -1 : 0); /* and return -1 (pass) or 0 (fail) */ X } /* end "do_search" */ X X/* expanded search comparison */ X/* returns 1 if match, 0 if not */ X Xint srch_cmp() X { X int tq; /* q-reg name for ^EGq */ X struct qp tqp; /* pointer to read q reg */ X X switch (mapch_l[sm.p->ch[sm.c]]) /* what is search character */ X { X case CTL (N): /* match anything but following construct */ X if (sm.dot >= sm.z) ERROR(E_ISS); /* don't read past end of string */ X fwdc(&sm); /* skip the ^N */ X return(!srch_cmp()); X X case CTL (X): /* match any character */ X return(1); X X case CTL (Q): /* take next char literally */ X case CTL (R): X if (sm.dot >= sm.z) ERROR(E_ISS); /* don't read past end of string */ X fwdc(&sm); /* skip the ^Q */ X return(*(pmap + sb.p->ch[sb.c]) == *(pmap + sm.p->ch[sm.c])); X X case CTL (S): /* match any nonalphanumeric */ X return(!isalnum(sb.p->ch[sb.c])); X X case CTL (E): X if (sm.dot >= sm.z) ERROR(E_ISS); /* don't read past end of string */ X fwdc(&sm); /* skip the ^E */ X switch (mapch_l[sm.p->ch[sm.c]]) X { X case 'a': /* match any alpha */ X return(isalpha(sb.p->ch[sb.c])); X X case 'b': /* match any nonalpha */ X return(!isalnum(sb.p->ch[sb.c])); X X case 'c': /* rad50 symbol constituent */ X return(!isalnum(sb.p->ch[sb.c]) || (sb.p->ch[sb.c] == '$') || (sb.p->ch[sb.c] == '.')); X X case 'd': /* digit */ X return(isdigit(sb.p->ch[sb.c])); X X case 'l': /* line terminator LF, VT, FF */ X return((sb.p->ch[sb.c] == LF) || (sb.p->ch[sb.c] == FF) || (sb.p->ch[sb.c] == VT)); X X case 'r': /* alphanumeric */ X return(isalnum(sb.p->ch[sb.c])); X X case 'v': /* lower case */ X return(islower(sb.p->ch[sb.c])); X X case 'w': /* upper case */ X return(isupper(sb.p->ch[sb.c])); X X case 's': /* any non-null string of spaces or tabs */ X if (((sb.p->ch[sb.c]&0177) != ' ') && ((sb.p->ch[sb.c]&0177) != TAB)) return(0); /* failure */ X /* skip remaining spaces or tabs */ X for ( fwdc(&sb); ((sb.p->ch[sb.c]&0177) == ' ') || ((sb.p->ch[sb.c]&0177) == TAB); fwdc(&sb) ); X backc(&sb); /* back up one char (calling routine will skip it) */ X return(1); /* success */ X X case 'g': /* any char in specified q register */ X if (sm.dot >= sm.z) ERROR(E_ISS); /* don't read past end of string */ X fwdc(&sm); /* get to the next char */ X tq = getqspec(1, sm.p->ch[sm.c]); /* read q-reg spec */ X for (tqp.dot = tqp.c = 0, tqp.p = qreg[tq].f; tqp.dot < qreg[tq].z; fwdc(&tqp)) X if (*(pmap + tqp.p->ch[tqp.c]) == *(pmap + sb.p->ch[sb.c])) return(1); /* match */ X return(0); /* fail */ X X default: X ERROR(E_ISS); X } /* end ^E constructions */ X X default: X return(*(pmap + sb.p->ch[sb.c]) == *(pmap + sm.p->ch[sm.c])); X } /* end other constructions */ X } X END_OF_te_srch.c if test 14562 -ne `wc -c te_subs.c <<'END_OF_te_subs.c' X/* TECO for Ultrix Copyright 1986 Matt Fichtenbaum */ X/* This program and its components belong to GenRad Inc, Concord MA 01742 */ X/* They may be copied if this copyright notice is included */ X X/* te_subs.c subroutines 11/8/85 */ X#include "te_defs.h" X X/* routines to copy a string of characters */ X/* movenchars(from, to, n) */ X/* from, to are the addresses of qps */ X/* n is the number of characters to move */ X/* moveuntil(from, to, c, &n, max) */ X/* c is the match character that ends the move */ X/* n is the returned number of chars moved */ X/* max is the maximum number of chars to move */ X Xmovenchars(from, to, n) X struct qp *from, *to; /* address of buffer pointers */ X register int n; /* number of characters */ X { X register struct buffcell *fp, *tp; /* local qp ".p" pointers */ X register int fc, tc; /* local qp ".c" subscripts */ X X if (n != 0) X { X fp = from->p; /* copy pointers to local registers */ X fc = from->c; X tp = to->p; X tc = to->c; X X for (; n > 0; n--) X { X tp->ch[tc++] = fp->ch[fc++]; /* move one char */ X X if (tc > CELLSIZE-1) /* check current cell done */ X { X if (!tp->f) /* is there another following? */ X { X tp->f = get_bcell(); /* no, add one */ X tp->f->b = tp; X } X tp = tp->f; X tc = 0; X } X X if (fc > CELLSIZE-1) /* check current cell done */ X { X if (!fp->f) /* oops, run out of source */ X { X if (n > 1) ERROR(E_UTC); /* error if not done */ X } X else { X fp = fp->f; /* chain to next cell */ X fc = 0; X } X } X } X from->p = fp; /* restore arguments */ X to->p = tp; X from->c = fc; X to->c = tc; X } X } X moveuntil(from, to, c, n, max, trace) X struct qp *from, *to; /* address of buffer pointers */ X register char c; /* match char that ends move */ X int *n; /* pointer to returned value */ X int max; /* limit on chars to move */ X int trace; /* echo characters if nonzero */ X { X register struct buffcell *fp, *tp; /* local qpr ".p" pointers */ X register int fc, tc; /* local qpr ".c" subscripts */ X X fp = from->p; /* copy pointers to local registers */ X fc = from->c; X tp = to->p; X tc = to->c; X X for (*n = 0; fp->ch[fc] != c; (*n)++) /* until terminating char... */ X { X if (max-- <= 0) ERROR((msp <= &mstack[0]) ? E_UTC : E_UTM); X tp->ch[tc++] = fp->ch[fc++]; /* move one char */ X if (trace) type_char(tp->ch[tc-1]); /* type it out if trace mode */ X X if (tc > CELLSIZE-1) /* check current cell done */ X { X if (!tp->f) /* is there another following? */ X { X tp->f = get_bcell(); /* no, add one */ X tp->f->b = tp; X } X tp = tp->f; X tc = 0; X } X X if (fc > CELLSIZE-1) /* check current cell done */ X { X if (!fp->f) ERROR(E_UTC); /* oops, run out of source */ X else { X fp = fp->f; /* chain to next cell */ X fc = 0; X } X } X } X X from->p = fp; /* restore arguments */ X to->p = tp; X from->c = fc; X to->c = tc; X } X X/* routine to get numeric argument */ Xint get_value(d) /* get a value, default is argument */ X int d; X { X int v; X X v = (esp->flag1) ? esp->val1 : X (esp->op == OP_SUB) ? -d : d; X esp->flag1 = 0; /* consume argument */ X esp->op = OP_START; X return(v); X } X X X X X/* routine to convert a line count */ X/* returns number of chars between dot and nth line feed */ X Xint lines(arg) X register int arg; X { X register int i, c; X register struct buffcell *p; X X for (i = dot / CELLSIZE, p = buff.f; (i > 0) && (p->f); i--) p = p->f; /* find dot */ X c = dot % CELLSIZE; X if (arg <= 0) /* scan backwards */ X { X for (i = dot; (arg < 1) && (i > 0); ) /* repeat for each line */ X { X --i; /* count characters */ X if (--c < 0) /* back up the pointer */ X { X if (!(p = p->b)) break; X c = CELLSIZE - 1; X } X if ( (ez_val & EZ_NOVTFF) ? (p->ch[c] == LF) : (spec_chars[p->ch[c]] & A_L) ) ++arg; /* if line sep found */ X } X if (arg > 0) ++i; /* if terminated on a line separator, advance over the separator */ X } X X else /* scan forwards */ X { X for (i = dot; (arg > 0) && (i < z); i++) X { X if ( (ez_val & EZ_NOVTFF) ? (p->ch[c] == LF) : (spec_chars[p->ch[c]] & A_L) ) --arg; X if (++c > CELLSIZE-1) X { X if (!(p = p->f)) break; X c = 0; X } X } /* this will incr over the separator anyway */ X } X return(i - dot); X } X X/* routine to handle args for K, T, X, etc. */ X/* if two args, 'char x' to 'char y' */ X/* if just one arg, then n lines (default 1) */ X/* sets a pointer to the beginning of the specd */ X/* string, and a char count value */ X Xint line_args(d, p) X int d; /* nonzero: leave dot at start */ X struct qp *p; X { X int n; X X if (esp->flag1 && esp->flag2) /* if two args */ X { X if (esp->val1 <= esp->val2) /* in right order */ X { X if (esp->val1 < 0) esp->val1 = 0; X if (esp->val2 > z) esp->val2 = z; X if (d) dot = esp->val1; /* update dot */ X set_pointer(esp->val1, p); /* set the pointer */ X esp->flag2 = esp->flag1 = 0; /* consume arguments */ X esp->op = OP_START; X return(esp->val2 - esp->val1); /* and return the count */ X } X else X { X if (esp->val2 < 0) esp->val2 = 0; X if (esp->val1 > z) esp->val1 = z; X if (d) dot = esp->val2; /* update dot */ X set_pointer(esp->val2, p); /* args in reverse order */ X esp->flag2 = esp->flag1 = 0; /* consume arguments */ X esp->op = OP_START; X return(esp->val1 - esp->val2); X } X } X else X { X n = lines(get_value(1)); X if (n < -dot) n = -dot; X else if (n > z-dot) n = z-dot; X if (n >= 0) set_pointer(dot, p); X else X { X n = -n; X set_pointer(dot - n, p); X if (d) dot -= n; X } X return(n); X } X } X X/* convert character c to a q-register spec */ Xint getqspec(fors, c) /* fors ("file or search") nonzero = allow _ or * */ X int fors; X char c; X { X if (isdigit(c)) return(c - '0' + 1); X else if isalpha(c) return(mapch_l[c] - 'a' + 11); X else if (fors) X { X if (c == '_') return (SERBUF); X if (c == '*') return (FILBUF); X if (c == '%') return (SYSBUF); X if (c == '#') return (TIMBUF); X } X ERROR(E_IQN); X } X X X X/* routines to do insert operations */ X/* insert1() copies current cell up to dot into a new cell */ X/* leaves bb pointing to end of that text */ X/* insert2() copies rest of buffer */ X Xstruct buffcell *insert_p; X Xinsert1() X { X int nchars; /* number of chars in cell */ X X set_pointer(dot, &aa); /* convert dot to a qp */ X if (dot < buff_mod) buff_mod = dot; /* update earliest char loc touched */ X insert_p = bb.p = get_bcell(); /* get a new cell */ X bb.c = 0; X nchars = aa.c; /* save char position of dot in cell */ X aa.c = 0; X X/* now aa points to the beginning of the buffer cell that */ X/* contains dot, bb points to the beginning of a new cell,*/ X/* nchars is the number of chars before dot */ X X movenchars(&aa, &bb, nchars); /* copy cell up to dot */ X } X X X Xinsert2(count) /* count is the number of chars added */ X int count; X { X aa.p->b->f = insert_p; /* put the new cell where the old one was */ X insert_p->b = aa.p->b; X insert_p = NULL; X X bb.p->f = aa.p; /* splice rest of buffer to end */ X aa.p->b = bb.p; X movenchars(&aa, &bb, z-dot); /* squeeze buffer */ X free_blist(bb.p->f); /* return unused cells */ X bb.p->f = NULL; /* and end the buffer */ X z += count; /* add # of chars inserted */ X dot += count; X ctrl_s = -count; /* save string length */ X } X X/* subroutine to delete n characters starting at dot */ X/* argument is number of characters */ X Xdelete1(nchars) X int nchars; X { X if (!nchars) return; /* 0 chars is a nop */ X if (nchars < 0) /* delete negative number of characters? */ X { X nchars = -nchars; /* make ll positive */ X if (nchars > dot) ERROR(E_POP); /* don't delete beyond beg of buffer */ X dot -= nchars; /* put pointer before deleted text */ X } X else if (dot + nchars > z) ERROR(E_POP); /* don't delete beyond end of buffer */ X X set_pointer(dot, &aa); /* pointer to beginning of area to delete */ X set_pointer(dot+nchars, &bb); /* and to end */ X if (dot < buff_mod) buff_mod = dot; /* update earliest char loc touched */ X movenchars(&bb, &aa, z-(dot+nchars)); /* move text unless delete ends at z */ X free_blist(aa.p->f); /* return any cells after end */ X aa.p->f = NULL; /* end the buffer */ X z -= nchars; /* adjust z */ X } X X/* routine to process "O" command */ X Xstruct qh obuff; /* tag string buffer */ X Xdo_o() X { X int i, j; /* i used as start of tag, j as end */ X int p, level; /* p is pointer to tag string, level is iteration lvl */ X int epfound; /* flag for "second ! found" */ X X if (!build_string(&obuff)) return; /* no tag spec'd: continue */ X if (obuff.z > CELLSIZE) ERROR(E_STL); /* string too long */ X esp->op = OP_START; /* consume any argument */ X if (esp->flag1) /* is there one? */ X { X esp->flag1 = 0; /* consume it */ X if (esp->val1 < 0) return; /* computed goto out of range - */ X for (i = 0; (i < obuff.z) && (esp->val1 > 0); i++) /* scan to find right tag */ X if (obuff.f->ch[i] == ',') esp->val1--; /* count commas */ X if (esp->val1 > 0) return; /* computed goto out of range + */ X X/* now i is either at 0 or after the nth comma */ X X for (j = i; j < obuff.z; j++) /* find end of tag */ X if (obuff.f->ch[j] == ',') break; /* stop at next comma */ X if (j == i) return; /* two adjacent commas: zero length tag */ X } X X else X { X i = 0; /* not a computed goto: use whole tag buffer */ X j = obuff.z; X } X X/* start from beginning of iteration or macro, and look for tag */ X X if (cptr.flag & F_ITER) /* if in iteration */ X { X cptr.p = cptr.il->p; /* restore */ X cptr.c = cptr.il->c; X cptr.dot = cptr.il->dot; X } X else for (cptr.dot = cptr.c = 0; cptr.p->b->b != NULL; cptr.p = cptr.p->b); /* find macro start */ X X/* search for tag */ X X for (level = 0; ;) /* look through rest of command string */ X { X switch (skipto(1)) /* look for interesting things, including ! */ X { X case '<': /* start of iteration */ X ++level; X break; X X case '>': /* end of iteration */ X if ((level == 0) && (cptr.flag & F_ITER)) pop_iteration(1); X else --level; X break; X X case '!': /* start of tag */ X for (epfound = 0; ; epfound = 0) /* keep looking for tag */ X { X for (p = i; p < j; p++) X { X if (getcmdc(0) == '!') epfound = 1; /* mark "trailing ! found */ X if (mapch_l[cmdc] != mapch_l[obuff.f->ch[p]]) break; /* compare */ X } X if (p >= j) /* if all comparison chars matched */ X { X if (getcmdc(0) == '!') return; /* and tag ends with !, found it */ X } X else if (!epfound) while (getcmdc(0) != '!'); /* else look for next ! and continue */ X } X break; X } /* end of switch */ X } /* end of scan loop */ X } /* end of subroutine */ X X/* routine to skip to next ", ', |, <, or > */ X/* skips over these chars embedded in text strings */ X/* stops in ! if argument is nonzero */ X/* returns character found, and leaves it in skipc */ X Xchar skipto(arg) X int arg; X { X int atsw; /* "at" prefix */ X char ta, term; /* temp attributes, terminator */ X X for (atsw = 0; ;) /* forever */ X { X while (!(ta = spec_chars[skipc = getcmdc(0)] & (A_X | A_S | A_T | A_Q))); /* read until something interesting found */ X X again: X if (ta & A_Q) getcmdc(0); /* if command takes a Q spec, skip the spec */ X if (ta & A_X) /* sought char found: quit */ X { X if (skipc == '"') getcmdc(0); /* quote must skip next char */ X return(skipc); X } X if (ta & A_S) /* other special char */ X { X switch (skipc) X { X case '^': /* treat next char as CTL */ X if (ta = spec_chars[skipc = getcmdc(0) & 0x1f]) goto again; X break; X X case '@': /* use alternative text terminator */ X atsw = 1; X break; X X case CTL (^): /* ^^ is value of next char: skip that char */ X getcmdc(0); X break; X X case CTL (A): /* type text */ X term = (atsw) ? getcmdc(0) : CTL (A); X atsw = 0; X while (getcmdc(0) != term); /* skip text */ X break; X X case '!': /* tag */ X if (arg) return(skipc); X while (getcmdc(0) != '!'); /* skip until next ! */ X break; X X case 'e': /* first char of two-letter E or F command */ X case 'f': X if (spec_chars[getcmdc(0)] & ((skipc == 'e') ? A_E : A_F)) /* if one with a text arg */ X { X term = (atsw) ? getcmdc(0) : ESC; X atsw = 0; X while (getcmdc(0) != term); /* read past terminator */ X } X break; X } /* end "switch" */ X } /* end "if (ta & A_S)" */ X X else if (ta & A_T) /* command with a text argument */ X { X term = (atsw) ? getcmdc(0) : ESC; X atsw = 0; X while (getcmdc(0) != term); /* skip text */ X } X } /* end "forever" */ X } /* end "skipto()" */ X X/* find number of characters to next matching (, [, or { (like '%' in vi) */ X Xdo_ctlp() X { X int i, l; X char c, c1; X X set_pointer(dot, &aa); /* point to text buffer */ X switch(c1 = aa.p->ch[aa.c]) X { X case '(': X c = ')'; /* match char is ) */ X i = 1; /* direction is positive */ X break; X X case ')': X c = '('; /* match char is ( */ X i = -1; /* direction is negative */ X break; X X case '[': X c = ']'; X i = 1; X break; X X case ']': X c = '['; X i = -1; X break; X X case '{': X c = '}'; X i = 1; X break; X X case '}': X c = '{'; X i = -1; X break; X X case '<': X c = '>'; X i = 1; X break; X X case '>': X c = '<'; X i = -1; X break; X X case '"': X c = '\''; X i = 1; X break; X X case '\'': X c = '"'; X i = -1; X break; X X default: X esp->val1 = i = 0; /* not on a matchable char, return 0 */ X } X X l = 1; /* start with one unmatched char */ X if (i > 0) /* if searching forward */ X { X for (i = dot, fwdc(&aa); (i < z) && (l); fwdc(&aa) ) X { X ++i; X if (aa.p->ch[aa.c] == c) --l; X else if (aa.p->ch[aa.c] == c1) ++l; X } X esp->val1 = (i < z) ? i - dot : 0; X } X else if (i < 0) X { X for (i = dot, backc(&aa); (i >= 0) && (l); backc(&aa) ) X { X --i; X if (aa.p->ch[aa.c] == c) --l; X else if (aa.p->ch[aa.c] == c1) ++l; X } X esp->val1 = (i >= 0) ? i - dot : 0; X } X esp->flag1 = 1; X } X END_OF_te_subs.c if test 13995 -ne `wc -c