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