#include "ded.h" #include "match.h" #include "char.h" #include "signal.h" #include "ter.h" /************************************************************************ * * * copyright Richard Bornat 1981 * * * ************************************************************************/ /************************************************************************ * * * The problem with the 'change' procedure is to decide when to stop. * * * * Given a range of lines and a starting position within those lines, * * consider the problem of a forward exchange (x/foo/baz): * * * * .......................................... (line 1) * * .......................................... (line 2) * * etc. * * .......................................... (line k-1) * * ...................*...................... (line k) * * .......................................... (line k+1) * * etc. * * .......................................... (line N-1) * * .......................................... (line N) * * * * The '*' character in the picture shows the position of the cursor. * * The exchange is performed first on the text following the start * * position (line k above) and on lines k+1 to N. This gives no * * difficulty, since it can't move the start position. Exchange is * * now performed on the text from line 1 up to the start position. * * This CAN move the start position, by changing the number of lines * * which precede it, by changing the number of characters in line k * * which precede it or by changing the text which includes the start * * position. This makes it difficult to tell when the second pass * * should stop. * * * * There is a second difficulty: should it be possible to make an * * exchange which includes the start position? The answer seems to * * be yes, provided that it doesn't include any text which was altered * * in the first pass. * * * * In the case of a backward exchange (x;foo;baz) the difficulty * * arises on pass1, and the point at which the exchange should * * should terminate is likewise difficult to determine. * * * * Hence the complexity of the 'go_on' and 'include decisions below. * * * ************************************************************************/ /************************************************************************ * * * auxiliary procedures * * * ************************************************************************/ int c_row, c_col; /* keep track of the replacement picture */ char *cbk_pos, *ctl_pos; /* character pointers to important text positions */ int cbk_line, cbk_col, cbk_set, ctl_line, ctl_col, ctl_set; /* the picture positions which correspond to those text positions */ int fin_line; /* the position where the changes stop */ /* a procedure to avoid setting up auxscreen for single-line substitutions */ char *auxpic(i) register int i; { if (i==0) return(auxl); else { if (auxscreen == (char**) 0) auxscreen = newscreen(); return(auxscreen[i]); } } /* procedure to copy text into the replacement picture */ copyover(str, fromstring) char *str; register int fromstring; { register char c; register char *auxrow = auxpic(c_row); while (true) { if (!fromstring) /* check the funny positions */ { if (cbk_pos==str) { cbk_line = ms_line+c_row; cbk_col=c_col; cbk_set=true; } if (ctl_pos==str) { ctl_line = ms_line+c_row; ctl_col=c_col; ctl_set=true; } } switch (c = *str++) { case '\'': if (fromstring) { c = *str++; switch (c) { case '\0': fdiag("!! replacement string ends with ' !!"); /* no need to break */ case '&': /* copy the matched portion of text */ copytext(ms_line, ms_col, mf_line, mf_col); auxrow = auxpic(c_row); continue; case '(': /* copy bracketed portion of text */ { char i = (*str++ - '0'); if (i>=1 && i<=br_count) { struct BR *b = &br_note[i]; if (b->bfline != -1) copytext(b->bsline, b->bscol, b->bfline, b->bfcol); } else if (0<=i && i<=9) fdiag("!! invalid digit after bracket !!"); else fdiag("!! no digit after bracket !!"); auxrow = auxpic(c_row); continue; } case '$': goto nxline; case '\'': case '/': case ';': break; default: fdiag("!! invalid sequence '%c !!", c); } } /* fall through on some characters */ goto normalchar; case '/': case ';': if (fromstring) { auxrow[c_col] = 0; return; } /* otherwise fall through to default */ default: normalchar: if (c_col==ncols) { char xline[ENOUGH]; int x_col = c_col-1; auxrow[c_col] = 0; while ((c=auxrow[x_col])==c_CONTROL || c==c_MODIFY) x_col--; /* find place to break line */ cat(auxrow+x_col,xline); /* copy it over */ c_col=x_col; /* now break the line there */ auxrow[c_col++] = c_CONTROL; /* linebreak marker */ copyover("\n", false); copyover(xline, false); str--; /* rescan character */ auxrow = auxpic(c_row); continue; } else { auxrow[c_col++] = c; continue; } case '\n': break; case '\0': auxrow[c_col] = 0; return; } /* switch c */ /* move to a new row */ nxline: if (++c_row >=NINROWS) { ab_line=ms_line; ab_col=ms_col; abandon("!! replacement too large !!"); } else { auxrow[c_col] = 0; /* end of previous line */ linetag(ms_line, (auxrow = auxpic(c_row)) ); c_col=MARGIN; } } /* while true */ } copytext(sline,scol, fline,fcol) register int sline, scol; int fline, fcol; { char linebuf[ENOUGH]; while (slinebk_line || (mf_line==bk_line && bk_col<=mf_col)) ); int oc_row, oc_col; char line[ENOUGH]; int newsize, oldsize; /* stop the exchange if control-c has been typed */ if (NORMAL_INPUT) { dlogout(intr_typed ? 1 : /* substitution abandoned */ 2 ); /* substitution occurred */ } else { if (ttyin()!=2) intr_typed = true; /* was abandoned */ } if (intr_typed) abandon("!! substitution abandoned by ^C !!"); c_row=0; c_col=ms_col; /* portion of the line before the match */ getline(ms_line, auxpic(0)); /* the replacement string - remember where it ends */ copyover(str, true); oc_row=c_row; oc_col=c_col; /* portion of the line after the match - * if this contains any of the 'stop' positions then this * must be noted */ getline(mf_line,line); cbk_set=ctl_set=false; if (mf_line==bk_line) cbk_pos=line+bk_col; else cbk_pos=0; if (mf_line==tl_line) ctl_pos=line+tl_col; else ctl_pos=0; copyover(line+mf_col, false); /* copyover will abandon if the replacement is too large */ fin_line = ms_line+c_row; newsize=c_row+1; oldsize=mf_line-ms_line+1; /* if necessary stretch the file a bit */ while (fin_line>maxl) inc_maxl(); /* We must save the screen so that it * can be restored if the exchange is rejected. * This need not be done if 'silence', since the exchange * cannot be rejected and it was done on the last substitute * if necessary. */ if (!silence || firstmatch) savescreen(); firstmatch=false; /* calculate which portion of the picture should be * on-screen */ if (!silence) { int border, b1; int newtop = topl; int on_first, on_last; border=(NINROWS-newsize)/2; if (ms_line