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