/* * Routine to expand a tab, calling the normal Outchar routine * to put out each implied character. Note that we call outchar * with a QUOTE. We use QUOTE internally to represent a position * which is part of the expansion of a tab. */ void vgotab(void) { register int i = tabcol(destcol, value(TABSTOP)) - destcol; do (*Outchar)(QUOTE); while (--i); }
int plod(int cnt) { register int i, j, k = 0; register int soutcol, soutline; plodcnt = plodflg = cnt; soutcol = outcol; soutline = outline; /* * Consider homing and moving down/right from there, vs moving * directly with local motions to the right spot. */ if (HO) { /* * i is the cost to home and tab/space to the right to * get to the proper column. This assumes ND space costs * 1 char. So i+destcol is cost of motion with home. */ if (GT) i = (destcol / value(HARDTABS)) + (destcol % value(HARDTABS)); else i = destcol; /* * j is cost to move locally without homing */ if (destcol >= outcol) { /* if motion is to the right */ j = destcol / value(HARDTABS) - outcol / value(HARDTABS); if (GT && j) j += destcol % value(HARDTABS); else j = destcol - outcol; } else /* leftward motion only works if we can backspace. */ if (outcol - destcol <= i && (BS || BC)) i = j = outcol - destcol; /* cheaper to backspace */ else j = i + 1; /* impossibly expensive */ /* k is the absolute value of vertical distance */ k = outline - destline; if (k < 0) k = -k; j += k; /* * Decision. We may not have a choice if no UP. */ if (i + destline < j || (!UP && destline < outline)) { /* * Cheaper to home. Do it now and pretend it's a * regular local motion. */ tputs(HO, 0, plodput); outcol = outline = 0; } else if (LL) { /* * Quickly consider homing down and moving from there. * Assume cost of LL is 2. */ k = (TLINES - 1) - destline; if (i + k + 2 < j && (k<=0 || UP)) { tputs(LL, 0, plodput); outcol = 0; outline = TLINES - 1; } } } else /* * No home and no up means it's impossible, so we return an * incredibly big number to make cursor motion win out. */ if (!UP && destline < outline) return (500); if (GT) i = destcol % value(HARDTABS) + destcol / value(HARDTABS); else i = destcol; /* if (BT && outcol > destcol && (j = (((outcol+7) & ~7) - destcol - 1) >> 3)) { j *= (k = strlen(BT)); if ((k += (destcol&7)) > 4) j += 8 - (destcol&7); else j += k; } else */ j = outcol - destcol; /* * If we will later need a \n which will turn into a \r\n by * the system or the terminal, then don't bother to try to \r. */ if ((NONL || !pfast) && outline < destline) goto dontcr; /* * If the terminal will do a \r\n and there isn't room for it, * then we can't afford a \r. */ if (NC && outline >= destline) goto dontcr; /* * If it will be cheaper, or if we can't back up, then send * a return preliminarily. */ if (j > i + 1 || outcol > destcol && !BS && !BC) { /* * BUG: this doesn't take the (possibly long) length * of xCR into account. */ if (ospeed != B0) { if (xCR) tputs(xCR, 0, plodput); else plodput('\r'); } if (NC) { if (xNL) tputs(xNL, 0, plodput); else plodput('\n'); outline++; } outcol = 0; } dontcr: /* Move down, if necessary, until we are at the desired line */ while (outline < destline) { j = destline - outline; if (j > costDP && DOWN_PARM) { /* Win big on Tek 4025 */ tputs(tgoto(DOWN_PARM, 0, j), j, plodput); outline += j; } else { outline++; if (xNL && pfast) tputs(xNL, 0, plodput); else plodput('\n'); } if (plodcnt < 0) goto out; if (NONL || pfast == 0) outcol = 0; } if (BT) k = strlen(BT); /* should probably be cost(BT) and moved out */ /* Move left, if necessary, to desired column */ while (outcol > destcol) { if (plodcnt < 0) goto out; if (BT && !insmode && outcol - destcol > 4+k) { tputs(BT, 0, plodput); outcol--; outcol -= outcol % value(HARDTABS); /* outcol &= ~7; */ continue; } j = outcol - destcol; if (j > costLP && LEFT_PARM) { tputs(tgoto(LEFT_PARM, 0, j), j, plodput); outcol -= j; } else { outcol--; if (BC) tputs(BC, 0, plodput); else plodput('\b'); } } /* Move up, if necessary, to desired row */ while (outline > destline) { j = outline - destline; if (UP_PARM && j > 1) { /* Win big on Tek 4025 */ tputs(tgoto(UP_PARM, 0, j), j, plodput); outline -= j; } else { outline--; tputs(UP, 0, plodput); } if (plodcnt < 0) goto out; } /* * Now move to the right, if necessary. We first tab to * as close as we can get. */ if (GT && !insmode && destcol - outcol > 1) { /* tab to right as far as possible without passing col */ for (;;) { i = tabcol(outcol, value(HARDTABS)); if (i > destcol) break; if (TA) tputs(TA, 0, plodput); else plodput('\t'); outcol = i; } /* consider another tab and then some backspaces */ if (destcol - outcol > 4 && i < TCOLUMNS && (BC || BS)) { if (TA) tputs(TA, 0, plodput); else plodput('\t'); outcol = i; /* * Back up. Don't worry about LEFT_PARM because * it's never more than 4 spaces anyway. */ while (outcol > destcol) { outcol--; if (BC) tputs(BC, 0, plodput); else plodput('\b'); } } } /* * We've tabbed as much as possible. If we still need to go * further (not exact or can't tab) space over. This is a * very common case when moving to the right with space. */ while (outcol < destcol) { j = destcol - outcol; if (j > costRP && RIGHT_PARM) { /* * This probably happens rarely, if at all. * It seems mainly useful for ANSI terminals * with no hardware tabs, and I don't know * of any such terminal at the moment. */ tputs(tgoto(RIGHT_PARM, 0, j), j, plodput); outcol += j; } else { /* * move one char to the right. We don't use ND space * because it's better to just print the char we are * moving over. There are various exceptions, however. * If !inopen, vtube contains garbage. If the char is * a null or a tab we want to print a space. Other * random chars we use space for instead, too. */ if (!inopen || vtube[outline]==NULL || #ifndef BIT8 ((i=vtube[outline][outcol]) < ' ') #else ((i=vtube[outline][outcol]) == 0) || (i!=MULTICOL && !printable(i&~INVBIT&~MULTICOL)) #endif ) i = ' '; if((i & (QUOTE|INVBIT)) == QUOTE) /* mjm: no sign extension on 3B */ i = ' '; if ((insmode || i == MULTICOL) && ND) tputs(ND, 0, plodput); else if (i == MULTICOL) { if (BS && BC) tputs(BC, 0, plodput); else plodput('\b'); plodput(vtube[outline][outcol-1]); } else plodput(i); outcol += i == MULTICOL ? 1 : colsc(i & ~MULTICOL); } if (plodcnt < 0) goto out; } out: if (plodflg) { outcol = soutcol; outline = soutline; } return(plodcnt); }
/* * Insert character c at current cursor position. * Multi-character inserts occur only as a result * of expansion of tabs (i.e. inssize == 1 except * for tabs) and code assumes this in several place * to make life simpler. */ int vinschar(int c) /* int c; /\* mjm: char --> int */ { register int i; register cell *tp; char *OIM; bool OXN; int noim, filler = 0; insmc1 = colsc(c) - 1; if ((!IM || !EI) && ((hold & HOLDQIK) || !value(REDRAW) || value(SLOWOPEN))) { /* * Don't want to try to use terminal * insert mode, or to try to fake it. * Just put the character out; the screen * will probably be wrong but we will fix it later. */ if (c == '\t') { vgotab(); return c; } vputchar(c); #ifdef MB if (insmc1 == 0 && (vtube0[destcol]&(TRIM|MULTICOL))==MULTICOL) vtube0[destcol] = INVBIT; #endif /* MB */ if (DEPTH(vcline) * WCOLS + !value(REDRAW) > (destline - LINE(vcline)) * WCOLS + destcol) return c; /* * The next line is about to be clobbered * make space for another segment of this line * (on an intelligent terminal) or just remember * that next line was clobbered (on a dumb one * if we don't care to redraw the tail. */ if (AL) { vnpins(0); } else { c = LINE(vcline) + DEPTH(vcline); if (c < LINE(vcline + 1) || c > WBOT) return c; i = destcol; vinslin(c, 1, vcline); DEPTH(vcline)++; vigoto(c, i); vprepins(); } return c; } /* * Compute the number of positions in the line image of the * current line. This is done from the physical image * since that is faster. Note that we have no memory * from insertion to insertion so that routines which use * us don't have to worry about moving the cursor around. */ if (*vtube0 == 0) linend = 0; else { /* * Search backwards for a non-null character * from the end of the displayed line. */ i = WCOLS * DEPTH(vcline); if (i == 0) i = WCOLS; tp = vtube0 + i; while (*--tp == 0) if (--i == 0) break; linend = i + insmc1; } /* * We insert at a position based on the physical location * of the output cursor. */ inscol = destcol + (destline - LINE(vcline)) * WCOLS; insmc0 = 0; #ifdef MB i = 0; while (inscol+i < LBSIZE && vtube0[inscol+i]&MULTICOL && (vtube0[inscol+insmc0+i]&(MULTICOL|TRIM)) != MULTICOL) i++; while (inscol+insmc0+i < LBSIZE && (vtube0[inscol+insmc0+i]&(MULTICOL|TRIM)) == MULTICOL) insmc0++; #endif /* MB */ if (c == '\t') { /* * Characters inserted from a tab must be * remembered as being part of a tab, but we can't * use QUOTE here since we really need to print blanks. * QUOTE|' ' is the representation of this. */ inssiz = tabcol(inscol+insmc0, value(TABSTOP)) - inscol - insmc0; c = ' ' | QUOTE; } else inssiz = 1; /* * If the text to be inserted is less than the number * of doomed positions, then we don't need insert mode, * rather we can just typeover. */ if (inssiz + insmc1 <= doomed) { endim(); if (inscol + insmc0 != linend) doomed -= inssiz + insmc1; #ifdef MB if (insmc1 == 0 && c != '\t' && vtube0[inscol+insmc0] & MULTICOL) vtube0[inscol+insmc0] = INVBIT; #endif /* MB */ do vputchar(c); while (--inssiz); return c; } /* * Have to really do some insertion, thus * stake out the bounds of the first following * group of tabs, computing starting position, * ending position, and the number of ``spaces'' therein * so we can tell how much it will squish. */ tp = vtube0 + inscol + insmc0; for (i = inscol + insmc0; i < linend; i++) { if (*tp++ & QUOTE) { --tp; break; } } tabstart = tabend = i; tabslack = 0; while (tabend < linend) { i = *tp++; if ((i & QUOTE) == 0) break; if ((i & (TRIM|MULTICOL)) == 0) tabslack++; tabsize++; tabend++; } tabsize = tabend - tabstart; /* * For HP's and DM's, e.g. tabslack has no meaning. */ if (!IN) tabslack = 0; #ifdef IDEBUG if (trace) { fprintf(trace, "inscol %d, inssiz %d, tabstart %d, ", inscol, inssiz, tabstart); fprintf(trace, "tabend %d, tabslack %d, linend %d\n", tabend, tabslack, linend); } #endif OIM = IM; OXN = XN; noim = 0; #ifdef MB if (mb_cur_max > 1) { if (destcol + 1 + insmc1 == WCOLS + 1) { noim = 1; if (insmc1 == 1 && insmc0 == 0) filler = 1; } for (i = inscol; vtube0[i]; i++) if (i + 1 >= WCOLS && vtube0[i] & MULTICOL) { noim = 1; break; } } #endif /* MB */ if (noim) { endim(); IM = 0; XN = 0; } /* * The real work begins. */ slakused = 0; shft = 0; if (tabsize) { /* * There are tabs on this line. * If they need to expand, then the rest of the line * will have to be shifted over. In this case, * we will need to make sure there are no ``spaces'' * in the rest of the line (on e.g. CONCEPT-100) * and then grab another segment on the screen if this * line is now deeper. We then do the shift * implied by the insertion. */ if (inssiz >= doomed + tabcol(tabstart, value(TABSTOP)) - tabstart) { if (IN) vrigid(); vneedpos(value(TABSTOP)); vishft(); } } else if (inssiz + insmc1 > doomed) /* * No tabs, but line may still get deeper. */ vneedpos(inssiz + insmc1 - doomed); /* * Now put in the inserted characters. */ viin(c); /* * Now put the cursor in its final resting place. */ destline = LINE(vcline); destcol = inscol + inssiz + insmc1 + filler; vcsync(); if (IM != OIM) { IM = OIM; XN = OXN; } return c; }