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.20 (Berkeley) 05/25/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 /* 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 ((!(__orig_termios.c_oflag & ONLCR) || 261 !__pfast) && outline < destline) 262 goto dontcr; 263 264 /* 265 * If the terminal will do a \r\n and there isn't room for it, then 266 * we can't afford a \r. 267 */ 268 if (NC && outline >= destline) 269 goto dontcr; 270 271 /* 272 * If it will be cheaper, or if we can't back up, then send a return 273 * preliminarily. 274 */ 275 if (j > i + 1 || outcol > destcol && !BS && !BC) { 276 /* 277 * BUG: this doesn't take the (possibly long) length of CR 278 * into account. 279 */ 280 if (CR) 281 tputs(CR, 0, plodput); 282 else 283 plodput('\r'); 284 if (NC) { 285 if (NL) 286 tputs(NL, 0, plodput); 287 else 288 plodput('\n'); 289 outline++; 290 } 291 outcol = 0; 292 } 293 294 dontcr: while (outline < destline) { 295 outline++; 296 if (NL) 297 tputs(NL, 0, plodput); 298 else 299 plodput('\n'); 300 if (plodcnt < 0) 301 goto out; 302 if (!(__orig_termios.c_oflag & ONLCR) || __pfast == 0) 303 outcol = 0; 304 } 305 if (BT) 306 k = strlen(BT); 307 while (outcol > destcol) { 308 if (plodcnt < 0) 309 goto out; 310 #ifdef notdef 311 if (BT && outcol - destcol > k + 4) { 312 tputs(BT, 0, plodput); 313 outcol--; 314 outcol &= ~7; 315 continue; 316 } 317 #endif 318 outcol--; 319 if (BC) 320 tputs(BC, 0, plodput); 321 else 322 plodput('\b'); 323 } 324 while (outline > destline) { 325 outline--; 326 tputs(UP, 0, plodput); 327 if (plodcnt < 0) 328 goto out; 329 } 330 if (GT && destcol - outcol > 1) { 331 for (;;) { 332 i = tabcol(outcol, HARDTABS); 333 if (i > destcol) 334 break; 335 if (TA) 336 tputs(TA, 0, plodput); 337 else 338 plodput('\t'); 339 outcol = i; 340 } 341 if (destcol - outcol > 4 && i < COLS && (BC || BS)) { 342 if (TA) 343 tputs(TA, 0, plodput); 344 else 345 plodput('\t'); 346 outcol = i; 347 while (outcol > destcol) { 348 outcol--; 349 if (BC) 350 tputs(BC, 0, plodput); 351 else 352 plodput('\b'); 353 } 354 } 355 } 356 while (outcol < destcol) { 357 /* 358 * Move one char to the right. We don't use ND space because 359 * it's better to just print the char we are moving over. 360 */ 361 if (in_refresh) 362 if (plodflg) /* Avoid a complex calculation. */ 363 plodcnt--; 364 else { 365 i = curscr->lines[outline]->line[outcol].ch; 366 if ((curscr->lines[outline]->line[outcol].attr 367 & __STANDOUT) == 368 (curscr->flags & __WSTANDOUT)) 369 putchar(i); 370 else 371 goto nondes; 372 } 373 else 374 nondes: if (ND) 375 tputs(ND, 0, plodput); 376 else 377 plodput(' '); 378 outcol++; 379 if (plodcnt < 0) 380 goto out; 381 } 382 383 out: if (plodflg) { 384 outcol = soutcol; 385 outline = soutline; 386 } 387 return (plodcnt); 388 } 389 390 /* 391 * Return the column number that results from being in column col and 392 * hitting a tab, where tabs are set every ts columns. Work right for 393 * the case where col > COLS, even if ts does not divide COLS. 394 */ 395 static int 396 tabcol(col, ts) 397 int col, ts; 398 { 399 int offset; 400 401 if (col >= COLS) { 402 offset = COLS * (col / COLS); 403 col -= offset; 404 } else 405 offset = 0; 406 return (col + ts - (col % ts) + offset); 407 } 408