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