/* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1980 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ #include #include "curses.ext" #include #define HARDTABS 8 /* forward declarations */ /* should be static, but we may have prior application-dependency, sigh! */ void fgoto(void); int plodput(char); int plod(int); int tabcol(int, int); /* * Terminal driving and line formatting routines. * Basic motion optimizations are done here as well * as formatting of lines (printing of control characters, * line numbering and the like). */ /* * Sync the position of the output cursor. * Most work here is rounding for terminal boundaries getting the * column position implied by wraparound or the lack thereof and * rolling up the screen to get destline on the screen. */ static int outcol, outline, destcol, destline; extern WINDOW *_win; int mvcur(int ly, int lx, int y, int x) { #ifdef DEBUG fprintf(outf, "MVCUR: moving cursor from (%d,%d) to (%d,%d)\n", ly, lx, y, x); #endif destcol = x; destline = y; outcol = lx; outline = ly; fgoto(); return (OK); } void fgoto(void) { char *cgp; int l, c; if (destcol >= COLS) { destline += destcol / COLS; destcol %= COLS; } if (outcol >= COLS) { l = (outcol + 1) / COLS; outline += l; outcol %= COLS; if (AM == 0) { while (l > 0) { if (_pfast) if (CR) (void) _puts(CR); else (void) _putchar('\r'); if (NL) (void) _puts(NL); else (void) _putchar('\n'); l--; } outcol = 0; } if (outline > LINES - 1) { destline -= outline - (LINES - 1); outline = LINES - 1; } } if (destline >= LINES) { l = destline; destline = LINES - 1; if (outline < LINES - 1) { c = destcol; if (_pfast == 0 && !CA) destcol = 0; fgoto(); destcol = c; } while (l >= LINES) { /* * The following linefeed (or simulation thereof) * is supposed to scroll up the screen, since we * are on the bottom line. We make the assumption * that linefeed will scroll. If ns is in the * capability list this won't work. We should * probably have an sc capability but sf will * generally take the place if it works. * * Superbee glitch: in the middle of the screen we * have to use esc B (down) because linefeed screws up * in "Efficient Paging" (what a joke) mode (which is * essential in some SB's because CRLF mode puts garbage * in at end of memory), but you must use linefeed to * scroll since down arrow won't go past memory end. * I turned this off after recieving Paul Eggert's * Superbee description which wins better. */ if (NL /* && !XB */ && _pfast) (void) _puts(NL); else (void) _putchar('\n'); l--; if (_pfast == 0) outcol = 0; } } if (destline < outline && !(CA || UP)) destline = outline; if (CA) { cgp = tgoto(CM, destcol, destline); if (plod((int)strlen(cgp)) > 0) (void) plod(0); else (void) tputs(cgp, 0, _putchar); } else (void) plod(0); outline = destline; outcol = destcol; } /* * Move (slowly) to destination. * Hard thing here is using home cursor on really deficient terminals. * Otherwise just use cursor motions, hacking use of tabs and overtabbing * and backspace. */ static int plodcnt, plodflg; int plodput(char c) { if (plodflg) plodcnt--; else (void) _putchar(c); return (OK); } int plod(int cnt) { int i, j, k; 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 / HARDTABS) + (destcol % HARDTABS); else i = destcol; /* * j is cost to move locally without homing */ if (destcol >= outcol) { /* if motion is to the right */ j = destcol / HARDTABS - outcol / HARDTABS; if (GT && j) j += destcol % 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. */ (void) 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 = (LINES - 1) - destline; if (i + k + 2 < j && (k <= 0 || UP)) { (void) tputs(LL, 0, plodput); outcol = 0; outline = LINES - 1; } } } else /* * No home and no up means it's impossible. */ if (!UP && destline < outline) return (-1); if (GT) i = destcol % HARDTABS + destcol / HARDTABS; else i = destcol; /* * if (BT && outcol > destcol && * (j = (((outcol+7) & ~7) - destcol - 1) >> 3)) { * j *= (k = (int)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 CR into account. */ if (CR) (void) tputs(CR, 0, plodput); else (void) plodput('\r'); if (NC) { if (NL) (void) tputs(NL, 0, plodput); else (void) plodput('\n'); outline++; } outcol = 0; } dontcr: while (outline < destline) { outline++; if (NL) (void) tputs(NL, 0, plodput); else (void) plodput('\n'); if (plodcnt < 0) goto out; if (NONL || _pfast == 0) outcol = 0; } if (BT) k = (int)strlen(BT); while (outcol > destcol) { if (plodcnt < 0) goto out; /* * if (BT && outcol - destcol > k + 4) { * (void) tputs(BT, 0, plodput); * outcol--; * outcol &= ~7; * continue; * } */ outcol--; if (BC) (void) tputs(BC, 0, plodput); else (void) plodput('\b'); } while (outline > destline) { outline--; (void) tputs(UP, 0, plodput); if (plodcnt < 0) goto out; } if (GT && destcol - outcol > 1) { for (;;) { i = tabcol(outcol, HARDTABS); if (i > destcol) break; if (TA) (void) tputs(TA, 0, plodput); else (void) plodput('\t'); outcol = i; } if (destcol - outcol > 4 && i < COLS && (BC || BS)) { if (TA) (void) tputs(TA, 0, plodput); else (void) plodput('\t'); outcol = i; while (outcol > destcol) { outcol--; if (BC) (void) tputs(BC, 0, plodput); else (void) plodput('\b'); } } } while (outcol < destcol) { /* * 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. */ if (_win != NULL) if (plodflg) /* avoid a complex calculation */ plodcnt--; else { i = curscr->_y[outline][outcol]; if ((i&_STANDOUT) == (curscr->_flags&_STANDOUT)) (void) _putchar(i & 0177); else goto nondes; } else nondes: if (ND) (void) tputs(ND, 0, plodput); else (void) plodput(' '); outcol++; if (plodcnt < 0) goto out; } out: if (plodflg) { outcol = soutcol; outline = soutline; } return (plodcnt); } /* * Return the column number that results from being in column col and * hitting a tab, where tabs are set every ts columns. Work right for * the case where col > COLS, even if ts does not divide COLS. */ int tabcol(int col, int ts) { int offset; if (col >= COLS) { offset = COLS * (col / COLS); col -= offset; } else offset = 0; return (col + ts - (col % ts) + offset); }