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