diff options
Diffstat (limited to 'ex_vops2.c')
-rw-r--r-- | ex_vops2.c | 1097 |
1 files changed, 1097 insertions, 0 deletions
diff --git a/ex_vops2.c b/ex_vops2.c new file mode 100644 index 0000000..d7cd3fb --- /dev/null +++ b/ex_vops2.c @@ -0,0 +1,1097 @@ +/* + * This code contains changes by + * Gunnar Ritter, Freiburg i. Br., Germany, 2002. All rights reserved. + * + * Conditions 1, 2, and 4 and the no-warranty notice below apply + * to these changes. + * + * + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * Redistributions of source code and documentation must retain the + * above copyright notice, this list of conditions and the following + * disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of + * other contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE + * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef lint +#ifdef DOSCCS +static char sccsid[] = "@(#)ex_vops2.c 1.34 (gritter) 1/12/05"; +#endif +#endif + +/* from ex_vops2.c 6.8 (Berkeley) 6/7/85 */ + +#include "ex.h" +#include "ex_tty.h" +#include "ex_vis.h" + +/* + * Low level routines for operations sequences, + * and mostly, insert mode (and a subroutine + * to read an input line, including in the echo area.) + */ +extern char *vUA1, *vUA2; /* mjm: extern; also in ex_vops.c */ +extern char *vUD1, *vUD2; /* mjm: extern; also in ex_vops.c */ + +/* + * Obleeperate characters in hardcopy + * open with \'s. + */ +void +bleep(register int i, char *cp) +{ + + i -= column(cp); + do + putchar('\\' | QUOTE); + while (--i >= 0); + rubble = 1; +} + +/* + * Common code for middle part of delete + * and change operating on parts of lines. + */ +int +vdcMID(void) +{ + register char *cp; + + squish(); + setLAST(); + if (FIXUNDO) + vundkind = VCHNG, CP(vutmp, linebuf); + if (wcursor < cursor) + cp = wcursor, wcursor = cursor, cursor = cp; + vUD1 = vUA1 = vUA2 = cursor; vUD2 = wcursor; + return (column(wcursor + skipleft(linebuf, wcursor))); +} + +/* + * Take text from linebuf and stick it + * in the VBSIZE buffer BUF. Used to save + * deleted text of part of line. + */ +void +takeout(cell *BUF) +{ + register char *cp; + + if (wcursor < linebuf) + wcursor = linebuf; + if (cursor == wcursor) { + beep(); + return; + } + if (wcursor < cursor) { + cp = wcursor; + wcursor = cursor; + cursor = cp; + } + setBUF(BUF); + if ((BUF[0] & (QUOTE|TRIM)) == OVERBUF) + beep(); +} + +/* + * Are we at the end of the printed representation of the + * line? Used internally in hardcopy open. + */ +int +ateopr(void) +{ + register int i, c; + register cell *cp = vtube[destline] + destcol; + + for (i = WCOLS - destcol; i > 0; i--) { + c = *cp++; + if (c == 0) + return (1); + if (c != ' ' && (c & QUOTE) == 0) + return (0); + } + return (1); +} + +void +showmode(int mode) +{ + int sdc = destcol, sdl = destline; + char *ocurs, *str; + + if (value(SHOWMODE) == 0 || TCOLUMNS <= 20 || state == ONEOPEN + || state == HARDOPEN || vmacp != NULL) + return; + ocurs = cursor; + fixech(); + vgoto(WECHO, TCOLUMNS - 20); + switch (mode) { + case 0: str = catgets(catd, 1, 227, + " "); + break; + case 'A': /*FALLTHROUGH*/ + case 'a': str = catgets(catd, 1, 228, + "AAPPEND MODE"); + break; + case 'C': /*FALLTHROUGH*/ + case 'c': str = catgets(catd, 1, 229, + "CCHANGE MODE"); + break; + case 'O': /*FALLTHROUGH*/ + case 'o': str = catgets(catd, 1, 230, + "OOPEN MODE"); + break; + case 'R': str = catgets(catd, 1, 231, + "RREPLACE MODE"); + break; + case 'r': str = catgets(catd, 1, 232, + "rREPLACE 1 CHAR"); + break; + default: str = catgets(catd, 1, 233, + "IINSERT MODE"); + } + if (value(TERSE)) + putchar(str[0]); + else + printf(&str[1]); + vgoto(sdl, sdc); + cursor = ocurs; + splitw = 0; +} + +/* + * Append. + * + * This routine handles the top level append, doing work + * as each new line comes in, and arranging repeatability. + * It also handles append with repeat counts, and calculation + * of autoindents for new lines. + */ +bool vaifirst; +bool gobbled; +char *ogcursor; + +/* + * The addtext() and addto() routines combined, accepting a single + * cell character. + */ +void +addc(cell c) +{ + register cell *cp = INS; + + if (vglobp) + return; + if ((cp[0] & (QUOTE|TRIM)) != OVERBUF) { + if (cellen(cp) + 2 >= VBSIZE) { + cp[0] = OVERBUF; + lastcmd[0] = 0; + } else { + while (*cp) + cp++; + *cp++ = c; + *cp++ = 0; + } + } +} + +void +vappend(int ch, int cnt, int indent) +/* int ch; /\* mjm: char --> int */ +{ + register int i = 0; + register char *gcursor; + bool escape; + int repcnt, savedoomed; + short oldhold = hold; +#ifdef SIGWINCH + sigset_t set, oset; +#endif + + /* + * Before a move in hardopen when the line is dirty + * or we are in the middle of the printed representation, + * we retype the line to the left of the cursor so the + * insert looks clean. + */ + if (ch != 'o' && state == HARDOPEN && (rubble || !ateopr())) { + rubble = 1; + gcursor = cursor; + i = *gcursor; + *gcursor = ' '; + wcursor = gcursor; + vmove(0); + *gcursor = i; + } + vaifirst = indent == 0; + + showmode(ch); + + /* + * Handle replace character by (eventually) + * limiting the number of input characters allowed + * in the vgetline routine. + */ + if (ch == 'r') + repcnt = 2; + else + repcnt = 0; + + /* + * If an autoindent is specified, then + * generate a mixture of blanks to tabs to implement + * it and place the cursor after the indent. + * Text read by the vgetline routine will be placed in genbuf, + * so the indent is generated there. + */ + if (value(AUTOINDENT) && indent != 0) { + gcursor = genindent(indent); + *gcursor = 0; + vgotoCL(qcolumn(cursor + skipright(cursor, linebuf), genbuf)); + } else { + gcursor = genbuf; + *gcursor = 0; + if (ch == 'o') + vfixcurs(); + } + + /* + * Prepare for undo. Pointers delimit inserted portion of line. + */ + vUA1 = vUA2 = cursor; + + /* + * If we are not in a repeated command and a ^@ comes in + * then this means the previous inserted text. + * If there is none or it was too long to be saved, + * then beep() and also arrange to undo any damage done + * so far (e.g. if we are a change.) + */ + if ((vglobp && *vglobp == 0) || peekbr()) { + if ((INS[0] & (QUOTE|TRIM)) == OVERBUF) { + beep(); + if (!splitw) + ungetkey('u'); + doomed = 0; + hold = oldhold; + showmode(0); + return; + } + /* + * Unread input from INS. + * An escape will be generated at end of string. + * Hold off n^^2 type update on dumb terminals. + */ + vglobp = INS; + hold |= HOLDQIK; + } else if (vglobp == 0) + /* + * Not a repeated command, get + * a new inserted text for repeat. + */ + INS[0] = 0; + + /* + * For wrapmargin to hack away second space after a '.' + * when the first space caused a line break we keep + * track that this happened in gobblebl, which says + * to gobble up a blank silently. + */ + gobblebl = 0; + +#ifdef SIGWINCH + sigemptyset(&set); + sigaddset(&set, SIGWINCH); + sigprocmask(SIG_BLOCK, &set, &oset); +#endif + /* + * Text gathering loop. + * New text goes into genbuf starting at gcursor. + * cursor preserves place in linebuf where text will eventually go. + */ + if (*cursor == 0 || state == CRTOPEN) + hold |= HOLDROL; + for (;;) { + if (ch == 'r' && repcnt == 0) + escape = 0; + else { + gcursor = vgetline(repcnt, gcursor, &escape, ch); + + /* + * After an append, stick information + * about the ^D's and ^^D's and 0^D's in + * the repeated text buffer so repeated + * inserts of stuff indented with ^D as backtab's + * can work. + */ + if (HADUP) + addc('^'); + else if (HADZERO) + addc('0'); + while (CDCNT > 0) +#ifndef BIT8 + addc('\204'), CDCNT--; +#else + addc(OVERBUF), CDCNT--; +#endif + + if (gobbled) + addc(' '); + addtext(ogcursor); + } + repcnt = 0; + + /* + * Smash the generated and preexisting indents together + * and generate one cleanly made out of tabs and spaces + * if we are using autoindent. + */ + if (!vaifirst && value(AUTOINDENT)) { + i = fixindent(indent); + if (!HADUP) + indent = i; + gcursor = strend(genbuf); + } + + /* + * Limit the repetition count based on maximum + * possible line length; do output implied + * by further count (> 1) and cons up the new line + * in linebuf. + */ + cnt = vmaxrep(ch, cnt); + CP(gcursor + skipright(ogcursor, gcursor), cursor); + do { + CP(cursor, genbuf); + if (cnt > 1) { + int oldhold = hold; + + Outchar = vinschar; + hold |= HOLDQIK; + printf("%s", genbuf); + hold = oldhold; + Outchar = vputchar; + } + cursor += gcursor - genbuf; + } while (--cnt > 0); + endim(); + vUA2 = cursor; + if (escape != '\n') + CP(cursor, gcursor + skipright(ogcursor, gcursor)); + + /* + * If doomed characters remain, clobber them, + * and reopen the line to get the display exact. + */ + if (state != HARDOPEN) { + DEPTH(vcline) = 0; + savedoomed = doomed; + if (doomed > 0) { + register int cind = cindent(); + + physdc(cind, cind + doomed); + doomed = 0; + } + i = vreopen(LINE(vcline), lineDOT(), vcline); +#ifdef TRACE + if (trace) + fprintf(trace, "restoring doomed from %d to %d\n", doomed, savedoomed); +#endif + if (ch == 'R') + doomed = savedoomed; + } + + /* + * All done unless we are continuing on to another line. + */ + if (escape != '\n') + break; + + /* + * Set up for the new line. + * First save the current line, then construct a new + * first image for the continuation line consisting + * of any new autoindent plus the pushed ahead text. + */ + showmode(0); + killU(); + addc(gobblebl ? ' ' : '\n'); + vsave(); + cnt = 1; + if (value(AUTOINDENT)) { +#ifdef LISPCODE + if (value(LISP)) + indent = lindent(dot + 1); + else +#endif + if (!HADUP && vaifirst) + indent = whitecnt(linebuf); + vaifirst = 0; + strcLIN(vpastwh(gcursor + 1)); + gcursor = genindent(indent); + *gcursor = 0; + if (gcursor + strlen(linebuf) > &genbuf[LBSIZE - 2]) + gcursor = genbuf; + CP(gcursor, linebuf); + } else { + CP(genbuf, gcursor + skipright(ogcursor, gcursor)); + gcursor = genbuf; + } + + /* + * If we started out as a single line operation and are now + * turning into a multi-line change, then we had better yank + * out dot before it changes so that undo will work + * correctly later. + */ + if (FIXUNDO && vundkind == VCHNG) { + vremote(1, yank, 0); + undap1--; + } + + /* + * Now do the append of the new line in the buffer, + * and update the display. If slowopen + * we don't do very much. + */ + vdoappend(genbuf); + vundkind = VMANYINS; + vcline++; + if (state != VISUAL) + vshow(dot, NOLINE); + else { + i += LINE(vcline - 1); + vopen(dot, i); + if (value(SLOWOPEN)) + vscrap(); + else + vsync1(LINE(vcline)); + } + strcLIN(gcursor); + *gcursor = 0; + cursor = linebuf; + vgotoCL(qcolumn(cursor + skipleft(ogcursor, cursor), genbuf)); + showmode(ch); + } + + /* + * All done with insertion, position the cursor + * and sync the screen. + */ + showmode(0); + hold = oldhold; + if (cursor > linebuf) + cursor += skipleft(linebuf, cursor); + if (state != HARDOPEN) + vsyncCL(); + else if (cursor > linebuf) + back1(); + doomed = 0; + wcursor = cursor; + vmove(0); +#ifdef SIGWINCH + sigprocmask(SIG_SETMASK, &oset, NULL); +#endif +} + +/* + * Subroutine for vgetline to back up a single character position, + * backwards around end of lines (vgoto can't hack columns which are + * less than 0 in general). + */ +void +back1(void) +{ + + vgoto(destline - 1, WCOLS + destcol - 1); +} + +#define gappend(c) { \ + int _c = c; \ + xgappend(_c, &gcursor); \ + } + +static void +xgappend(int c, char **gp) +{ + if (*gp >= &genbuf[MAXBSIZE-mb_cur_max-1]) { + beep(); + return; + } +#ifdef MB + if (mb_cur_max > 1 && !(c & INVBIT)) { + char mb[MB_LEN_MAX]; + int i, n; + n = wctomb(mb, c); + for (i = 0; i < n; i++) + *(*gp)++ = mb[i]; + } else +#endif /* MB */ + *(*gp)++ = c & 0377; +} + +/* + * Get a line into genbuf after gcursor. + * Cnt limits the number of input characters + * accepted and is used for handling the replace + * single character command. Aescaped is the location + * where we stick a termination indicator (whether we + * ended with an ESCAPE or a newline/return. + * + * We do erase-kill type processing here and also + * are careful about the way we do this so that it is + * repeatable. (I.e. so that your kill doesn't happen, + * when you repeat an insert if it was escaped with \ the + * first time you did it. commch is the command character + * involved, including the prompt for readline. + */ +char * +vgetline(int cnt, char *gcursor, bool *aescaped, int commch) +{ + register int c, ch; + register char *cp; + int x, y, iwhite, backsl=0; + cell *iglobp; + char cstr[2]; + int (*OO)() = Outchar; + + /* + * Clear the output state and counters + * for autoindent backwards motion (counts of ^D, etc.) + * Remember how much white space at beginning of line so + * as not to allow backspace over autoindent. + */ + *aescaped = 0; + ogcursor = gcursor; + flusho(); + CDCNT = 0; + HADUP = 0; + HADZERO = 0; + gobbled = 0; + iwhite = whitecnt(genbuf); + iglobp = vglobp; + + /* + * Carefully avoid using vinschar in the echo area. + */ + if (splitw) + Outchar = vputchar; + else { + Outchar = vinschar; + vprepins(); + } + for (;;) { + backsl = 0; + if (gobblebl) + gobblebl--; + if (cnt != 0) { + cnt--; + if (cnt == 0) + goto vadone; + } + c = getkey(); + if (c != ATTN) + c &= (QUOTE|TRIM); + ch = c; + maphopcnt = 0; + if (vglobp == 0 && Peekkey == 0 && commch != 'r') + while ((ch = map(c, immacs)) != c) { + c = ch; + if (!value(REMAP)) + break; + if (++maphopcnt > 256) + error(catgets(catd, 1, 234, + "Infinite macro loop")); + } + if (!iglobp) { + + /* + * Erase-kill type processing. + * Only happens if we were not reading + * from untyped input when we started. + * Map users erase to ^H, kill to -1 for switch. + */ + if (c == tty.c_cc[VERASE]) + c = CTRL('h'); + else if (c == tty.c_cc[VKILL]) + c = -1; + if (c == ATTN) + goto case_ATTN; + switch (c) { + + /* + * ^? Interrupt drops you back to visual + * command mode with an unread interrupt + * still in the input buffer. + * + * ^\ Quit does the same as interrupt. + * If you are a ex command rather than + * a vi command this will drop you + * back to command mode for sure. + */ + case QUIT: +case_ATTN: + ungetkey(c); + goto vadone; + + /* + * ^H Backs up a character in the input. + * + * BUG: Can't back around line boundaries. + * This is hard because stuff has + * already been saved for repeat. + */ + case CTRL('h'): +bakchar: + cp = gcursor + skipleft(ogcursor, gcursor); + if (cp < ogcursor) { + if (splitw) { + /* + * Backspacing over readecho + * prompt. Pretend delete but + * don't beep. + */ + ungetkey(c); + goto vadone; + } + beep(); + continue; + } + goto vbackup; + + /* + * ^W Back up a white/non-white word. + */ + case CTRL('w'): + wdkind = 1; + for (cp = gcursor; cp > ogcursor + && isspace(cp[-1]&0377); cp--) + continue; + for (c = wordch(cp - 1); + cp > ogcursor && wordof(c, cp - 1); cp--) + continue; + goto vbackup; + + /* + * users kill Kill input on this line, back to + * the autoindent. + */ + case -1: + cp = ogcursor; +vbackup: + if (cp == gcursor) { + beep(); + continue; + } + endim(); + *cp = 0; + c = cindent(); + vgotoCL(qcolumn(cursor + + skipleft(linebuf, cursor), genbuf)); + if (doomed >= 0) + doomed += c - cindent(); + gcursor = cp; + continue; + + /* + * \ Followed by erase or kill + * maps to just the erase or kill. + */ + case '\\': + x = destcol, y = destline; + putchar('\\'); + vcsync(); + c = getkey(); + if (c == tty.c_cc[VERASE] + || c == tty.c_cc[VKILL]) + { + vgoto(y, x); + if (doomed >= 0) + doomed++; + goto def; + } + ungetkey(c), c = '\\'; + backsl = 1; + break; + + /* + * ^Q Super quote following character + * Only ^@ is verboten (trapped at + * a lower level) and \n forces a line + * split so doesn't really go in. + * + * ^V Synonym for ^Q + */ + case CTRL('q'): + case CTRL('v'): + x = destcol, y = destline; + putchar('^'); + vgoto(y, x); + c = getkey(); + if (c != NL) { + if (doomed >= 0) + doomed++; + goto def; + } + break; + } + } + + /* + * If we get a blank not in the echo area + * consider splitting the window in the wrapmargin. + */ + if (c != NL && !splitw) { + if (c == ' ' && gobblebl) { + gobbled = 1; + continue; + } + if (value(WRAPMARGIN) && + (outcol >= OCOLUMNS - value(WRAPMARGIN) || + backsl && outcol==0) && + commch != 'r') { + /* + * At end of word and hit wrapmargin. + * Move the word to next line and keep going. + */ + wdkind = 1; + gappend(c); + if (backsl) + gappend(getkey()); + *gcursor = 0; + /* + * Find end of previous word if we are past it. + */ + for (cp=gcursor; cp>ogcursor + && isspace(cp[-1]&0377); cp--) + ; + if (outcol+(backsl?OCOLUMNS:0) - (gcursor-cp) >= OCOLUMNS - value(WRAPMARGIN)) { + /* + * Find beginning of previous word. + */ + for (; cp>ogcursor && !isspace(cp[-1]&0377); cp--) + ; + if (cp <= ogcursor) { + /* + * There is a single word that + * is too long to fit. Just + * let it pass, but beep for + * each new letter to warn + * the luser. + */ + c = *--gcursor; + *gcursor = 0; + beep(); + goto dontbreak; + } + /* + * Save it for next line. + */ + macpush(cp, 0); + cp--; + } + macpush("\n", 0); + /* + * Erase white space before the word. + */ + while (cp > ogcursor && isspace(cp[-1]&0377)) + cp--; /* skip blank */ + gobblebl = 3; + goto vbackup; + } + dontbreak:; + } + + /* + * Word abbreviation mode. + */ + cstr[0] = c; + if (anyabbrs && gcursor > ogcursor && !wordch(cstr) && wordch(gcursor-1)) { + int wdtype, abno; + + cstr[1] = 0; + wdkind = 1; + cp = gcursor + skipleft(ogcursor, gcursor); + for (wdtype = wordch(cp - 1); + cp > ogcursor && wordof(wdtype, cp - 1); cp--) + ; + *gcursor = 0; + for (abno=0; abbrevs[abno].mapto; abno++) { + if (!abbrevs[abno].hadthis && + eq(cp, abbrevs[abno].cap)) { + abbrevs[abno].hadthis++; + macpush(cstr, 0); + macpush(abbrevs[abno].mapto, 0); + goto vbackup; + } + } + } + +#ifdef BIT8 + if (c == OVERBUF) + goto btrp; +#endif + switch (c) { + + /* + * ^M Except in repeat maps to \n. + */ + case CR: + if (vglobp) + goto def; + c = '\n'; + /* presto chango ... */ + + /* + * \n Start new line. + */ + case NL: + *aescaped = c; + goto vadone; + + /* + * escape End insert unless repeat and more to repeat. + */ + case ESCAPE: + if (lastvgk) + goto def; + goto vadone; + + /* + * ^D Backtab. + * ^T Software forward tab. + * + * Unless in repeat where this means these + * were superquoted in. + */ + case CTRL('d'): + case CTRL('t'): + if (vglobp) + goto def; + /* fall into ... */ + + /* + * ^D|QUOTE Is a backtab (in a repeated command). + */ +#ifndef BIT8 + case CTRL('d') | QUOTE: +#else +btrp: +#endif + *gcursor = 0; + cp = vpastwh(genbuf); + c = whitecnt(genbuf); + if (ch == CTRL('t')) { + /* + * ^t just generates new indent replacing + * current white space rounded up to soft + * tab stop increment. + */ + if (cp != gcursor) + /* + * BUG: Don't hack ^T except + * right after initial + * white space. + */ + continue; + cp = genindent(iwhite = backtab(c + value(SHIFTWIDTH) + 1)); + ogcursor = cp; + goto vbackup; + } + /* + * ^D works only if we are at the (end of) the + * generated autoindent. We count the ^D for repeat + * purposes. + */ + if (c == iwhite && c != 0) + if (cp == gcursor) { + iwhite = backtab(c); + CDCNT++; + ogcursor = cp = genindent(iwhite); + goto vbackup; + } else if (&cp[1] == gcursor && + (*cp == '^' || *cp == '0')) { + /* + * ^^D moves to margin, then back + * to current indent on next line. + * + * 0^D moves to margin and then + * stays there. + */ + HADZERO = *cp == '0'; + ogcursor = cp = genbuf; + HADUP = 1 - HADZERO; + CDCNT = 1; + endim(); + back1(); + vputchar(' '); + goto vbackup; + } + if (vglobp && vglobp - iglobp >= 2 && + (vglobp[-2] == '^' || vglobp[-2] == '0') + && gcursor == ogcursor + 1) + goto bakchar; + continue; + + default: + /* + * Possibly discard control inputs. + */ + if (!vglobp && junk(c)) { + beep(); + continue; + } +def: + if (!backsl) { + /* int cnt; */ + putchar(c); + flush(); + } + if (gcursor > &genbuf[LBSIZE - 2]) + error(catgets(catd, 1, 235, "Line too long")); + gappend(c & TRIM); + vcsync(); + if (value(SHOWMATCH) && !iglobp) + if (c == ')' || c == '}') + lsmatch(gcursor); + continue; + } + } +vadone: + *gcursor = 0; + if (Outchar != termchar) + Outchar = OO; + endim(); + return (gcursor); +} + +char *vsplitpt; + +/* + * Append the line in buffer at lp + * to the buffer after dot. + */ +void +vdoappend(char *lp) +{ + register int oing = inglobal; + + vsplitpt = lp; + inglobal = 1; + ignore(append(vgetsplit, dot)); + inglobal = oing; +} + +/* + * Subroutine for vdoappend to pass to append. + */ +int +vgetsplit(void) +{ + + if (vsplitpt == 0) + return (EOF); + strcLIN(vsplitpt); + vsplitpt = 0; + return (0); +} + +/* + * Vmaxrep determines the maximum repetitition factor + * allowed that will yield total line length less than + * LBSIZE characters and also does hacks for the R command. + */ +int +vmaxrep(int ch, register int cnt) +{ + register int len, replen; + + if (cnt > LBSIZE - 2) + cnt = LBSIZE - 2; + replen = strlen(genbuf); + if (ch == 'R') { + len = strlen(cursor); + if (replen < len) + len = replen; +#ifdef MB + if (mb_cur_max > 1) { + char *cp, *gp; + int c, g; + for (gp = genbuf, g = 0; *gp; g++) + gp += wskipright(genbuf, gp); + for (cp = cursor, c = 0; c < g; c++) + cp += wskipright(cursor, cp); + CP(cursor, cp); + } else +#endif /* MB */ + CP(cursor, cursor + len); + vUD2 += len; + } + len = strlen(linebuf); + if (len + cnt * replen <= LBSIZE - 2) + return (cnt); + cnt = (LBSIZE - 2 - len) / replen; + if (cnt == 0) { + vsave(); + error(catgets(catd, 1, 236, "Line too long")); + } + return (cnt); +} |