1: /* 2: * Copyright (c) 1980 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #ifndef lint 8: static char sccsid[] = "@(#)cr_put.c 5.1 (Berkeley) 6/7/85"; 9: #endif not lint 10: 11: # include "curses.ext" 12: 13: # define HARDTABS 8 14: 15: extern char *tgoto(); 16: int plodput(); 17: 18: /* 19: * Terminal driving and line formatting routines. 20: * Basic motion optimizations are done here as well 21: * as formatting of lines (printing of control characters, 22: * line numbering and the like). 23: */ 24: 25: /* 26: * Sync the position of the output cursor. 27: * Most work here is rounding for terminal boundaries getting the 28: * column position implied by wraparound or the lack thereof and 29: * rolling up the screen to get destline on the screen. 30: */ 31: 32: static int outcol, outline, destcol, destline; 33: 34: WINDOW *_win; 35: 36: mvcur(ly, lx, y, x) 37: int ly, lx, y, x; { 38: 39: #ifdef DEBUG 40: fprintf(outf, "MVCUR: moving cursor from (%d,%d) to (%d,%d)\n", ly, lx, y, x); 41: #endif 42: destcol = x; 43: destline = y; 44: outcol = lx; 45: outline = ly; 46: fgoto(); 47: } 48: 49: fgoto() 50: { 51: reg char *cgp; 52: reg int l, c; 53: 54: if (destcol >= COLS) { 55: destline += destcol / COLS; 56: destcol %= COLS; 57: } 58: if (outcol >= COLS) { 59: l = (outcol + 1) / COLS; 60: outline += l; 61: outcol %= COLS; 62: if (AM == 0) { 63: while (l > 0) { 64: if (_pfast) 65: if (CR) 66: _puts(CR); 67: else 68: _putchar('\r'); 69: if (NL) 70: _puts(NL); 71: else 72: _putchar('\n'); 73: l--; 74: } 75: outcol = 0; 76: } 77: if (outline > LINES - 1) { 78: destline -= outline - (LINES - 1); 79: outline = LINES - 1; 80: } 81: } 82: if (destline >= LINES) { 83: l = destline; 84: destline = LINES - 1; 85: if (outline < LINES - 1) { 86: c = destcol; 87: if (_pfast == 0 && !CA) 88: destcol = 0; 89: fgoto(); 90: destcol = c; 91: } 92: while (l >= LINES) { 93: /* 94: * The following linefeed (or simulation thereof) 95: * is supposed to scroll up the screen, since we 96: * are on the bottom line. We make the assumption 97: * that linefeed will scroll. If ns is in the 98: * capability list this won't work. We should 99: * probably have an sc capability but sf will 100: * generally take the place if it works. 101: * 102: * Superbee glitch: in the middle of the screen we 103: * have to use esc B (down) because linefeed screws up 104: * in "Efficient Paging" (what a joke) mode (which is 105: * essential in some SB's because CRLF mode puts garbage 106: * in at end of memory), but you must use linefeed to 107: * scroll since down arrow won't go past memory end. 108: * I turned this off after recieving Paul Eggert's 109: * Superbee description which wins better. 110: */ 111: if (NL /* && !XB */ && _pfast) 112: _puts(NL); 113: else 114: _putchar('\n'); 115: l--; 116: if (_pfast == 0) 117: outcol = 0; 118: } 119: } 120: if (destline < outline && !(CA || UP)) 121: destline = outline; 122: if (CA) { 123: cgp = tgoto(CM, destcol, destline); 124: if (plod(strlen(cgp)) > 0) 125: plod(0); 126: else 127: tputs(cgp, 0, _putchar); 128: } 129: else 130: plod(0); 131: outline = destline; 132: outcol = destcol; 133: } 134: 135: /* 136: * Move (slowly) to destination. 137: * Hard thing here is using home cursor on really deficient terminals. 138: * Otherwise just use cursor motions, hacking use of tabs and overtabbing 139: * and backspace. 140: */ 141: 142: static int plodcnt, plodflg; 143: 144: plodput(c) 145: { 146: if (plodflg) 147: plodcnt--; 148: else 149: _putchar(c); 150: } 151: 152: plod(cnt) 153: { 154: register int i, j, k; 155: register int soutcol, soutline; 156: 157: plodcnt = plodflg = cnt; 158: soutcol = outcol; 159: soutline = outline; 160: /* 161: * Consider homing and moving down/right from there, vs moving 162: * directly with local motions to the right spot. 163: */ 164: if (HO) { 165: /* 166: * i is the cost to home and tab/space to the right to 167: * get to the proper column. This assumes ND space costs 168: * 1 char. So i+destcol is cost of motion with home. 169: */ 170: if (GT) 171: i = (destcol / HARDTABS) + (destcol % HARDTABS); 172: else 173: i = destcol; 174: /* 175: * j is cost to move locally without homing 176: */ 177: if (destcol >= outcol) { /* if motion is to the right */ 178: j = destcol / HARDTABS - outcol / HARDTABS; 179: if (GT && j) 180: j += destcol % HARDTABS; 181: else 182: j = destcol - outcol; 183: } 184: else 185: /* leftward motion only works if we can backspace. */ 186: if (outcol - destcol <= i && (BS || BC)) 187: i = j = outcol - destcol; /* cheaper to backspace */ 188: else 189: j = i + 1; /* impossibly expensive */ 190: 191: /* k is the absolute value of vertical distance */ 192: k = outline - destline; 193: if (k < 0) 194: k = -k; 195: j += k; 196: 197: /* 198: * Decision. We may not have a choice if no UP. 199: */ 200: if (i + destline < j || (!UP && destline < outline)) { 201: /* 202: * Cheaper to home. Do it now and pretend it's a 203: * regular local motion. 204: */ 205: tputs(HO, 0, plodput); 206: outcol = outline = 0; 207: } 208: else if (LL) { 209: /* 210: * Quickly consider homing down and moving from there. 211: * Assume cost of LL is 2. 212: */ 213: k = (LINES - 1) - destline; 214: if (i + k + 2 < j && (k<=0 || UP)) { 215: tputs(LL, 0, plodput); 216: outcol = 0; 217: outline = LINES - 1; 218: } 219: } 220: } 221: else 222: /* 223: * No home and no up means it's impossible. 224: */ 225: if (!UP && destline < outline) 226: return -1; 227: if (GT) 228: i = destcol % HARDTABS + destcol / HARDTABS; 229: else 230: i = destcol; 231: /* 232: if (BT && outcol > destcol && (j = (((outcol+7) & ~7) - destcol - 1) >> 3)) { 233: j *= (k = strlen(BT)); 234: if ((k += (destcol&7)) > 4) 235: j += 8 - (destcol&7); 236: else 237: j += k; 238: } 239: else 240: */ 241: j = outcol - destcol; 242: /* 243: * If we will later need a \n which will turn into a \r\n by 244: * the system or the terminal, then don't bother to try to \r. 245: */ 246: if ((NONL || !_pfast) && outline < destline) 247: goto dontcr; 248: /* 249: * If the terminal will do a \r\n and there isn't room for it, 250: * then we can't afford a \r. 251: */ 252: if (NC && outline >= destline) 253: goto dontcr; 254: /* 255: * If it will be cheaper, or if we can't back up, then send 256: * a return preliminarily. 257: */ 258: if (j > i + 1 || outcol > destcol && !BS && !BC) { 259: /* 260: * BUG: this doesn't take the (possibly long) length 261: * of CR into account. 262: */ 263: if (CR) 264: tputs(CR, 0, plodput); 265: else 266: plodput('\r'); 267: if (NC) { 268: if (NL) 269: tputs(NL, 0, plodput); 270: else 271: plodput('\n'); 272: outline++; 273: } 274: outcol = 0; 275: } 276: dontcr: 277: while (outline < destline) { 278: outline++; 279: if (NL) 280: tputs(NL, 0, plodput); 281: else 282: plodput('\n'); 283: if (plodcnt < 0) 284: goto out; 285: if (NONL || _pfast == 0) 286: outcol = 0; 287: } 288: if (BT) 289: k = strlen(BT); 290: while (outcol > destcol) { 291: if (plodcnt < 0) 292: goto out; 293: /* 294: if (BT && outcol - destcol > k + 4) { 295: tputs(BT, 0, plodput); 296: outcol--; 297: outcol &= ~7; 298: continue; 299: } 300: */ 301: outcol--; 302: if (BC) 303: tputs(BC, 0, plodput); 304: else 305: plodput('\b'); 306: } 307: while (outline > destline) { 308: outline--; 309: tputs(UP, 0, plodput); 310: if (plodcnt < 0) 311: goto out; 312: } 313: if (GT && destcol - outcol > 1) { 314: for (;;) { 315: i = tabcol(outcol, HARDTABS); 316: if (i > destcol) 317: break; 318: if (TA) 319: tputs(TA, 0, plodput); 320: else 321: plodput('\t'); 322: outcol = i; 323: } 324: if (destcol - outcol > 4 && i < COLS && (BC || BS)) { 325: if (TA) 326: tputs(TA, 0, plodput); 327: else 328: plodput('\t'); 329: outcol = i; 330: while (outcol > destcol) { 331: outcol--; 332: if (BC) 333: tputs(BC, 0, plodput); 334: else 335: plodput('\b'); 336: } 337: } 338: } 339: while (outcol < destcol) { 340: /* 341: * move one char to the right. We don't use ND space 342: * because it's better to just print the char we are 343: * moving over. 344: */ 345: if (_win != NULL) 346: if (plodflg) /* avoid a complex calculation */ 347: plodcnt--; 348: else { 349: i = curscr->_y[outline][outcol]; 350: if ((i&_STANDOUT) == (curscr->_flags&_STANDOUT)) 351: _putchar(i); 352: else 353: goto nondes; 354: } 355: else 356: nondes: 357: if (ND) 358: tputs(ND, 0, plodput); 359: else 360: plodput(' '); 361: outcol++; 362: if (plodcnt < 0) 363: goto out; 364: } 365: out: 366: if (plodflg) { 367: outcol = soutcol; 368: outline = soutline; 369: } 370: return(plodcnt); 371: } 372: 373: /* 374: * Return the column number that results from being in column col and 375: * hitting a tab, where tabs are set every ts columns. Work right for 376: * the case where col > COLS, even if ts does not divide COLS. 377: */ 378: tabcol(col, ts) 379: int col, ts; 380: { 381: int offset, result; 382: 383: if (col >= COLS) { 384: offset = COLS * (col / COLS); 385: col -= offset; 386: } 387: else 388: offset = 0; 389: return col + ts - (col % ts) + offset; 390: }