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