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