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