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.9 (Berkeley) 09/14/92"; 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 if (plod(strlen(cgp)) > 0) 131 plod(0); 132 else 133 tputs(cgp, 0, __cputchar); 134 } else 135 plod(0); 136 outline = destline; 137 outcol = destcol; 138 } 139 /* 140 * Move (slowly) to destination. 141 * Hard thing here is using home cursor on really deficient terminals. 142 * Otherwise just use cursor motions, hacking use of tabs and overtabbing 143 * and backspace. 144 */ 145 146 static int plodcnt, plodflg; 147 148 static void 149 plodput(c) 150 int c; 151 { 152 if (plodflg) 153 --plodcnt; 154 else 155 putchar(c); 156 } 157 158 static int 159 plod(cnt) 160 int cnt; 161 { 162 register int i, j, k, soutcol, soutline; 163 164 plodcnt = plodflg = cnt; 165 soutcol = outcol; 166 soutline = outline; 167 /* 168 * Consider homing and moving down/right from there, vs. moving 169 * directly with local motions to the right spot. 170 */ 171 if (HO) { 172 /* 173 * i is the cost to home and tab/space to the right to get to 174 * the proper column. This assumes ND space costs 1 char. So 175 * i + destcol is cost of motion with home. 176 */ 177 if (GT) 178 i = (destcol / HARDTABS) + (destcol % HARDTABS); 179 else 180 i = destcol; 181 182 /* j is cost to move locally without homing. */ 183 if (destcol >= outcol) { /* if motion is to the right */ 184 j = destcol / HARDTABS - outcol / HARDTABS; 185 if (GT && j) 186 j += destcol % HARDTABS; 187 else 188 j = destcol - outcol; 189 } else 190 /* leftward motion only works if we can backspace. */ 191 if (outcol - destcol <= i && (BS || BC)) 192 /* Cheaper to backspace. */ 193 i = j = outcol - destcol; 194 else 195 /* Impossibly expensive. */ 196 j = i + 1; 197 198 /* k is the absolute value of vertical distance. */ 199 k = outline - destline; 200 if (k < 0) 201 k = -k; 202 j += k; 203 204 /* Decision. We may not have a choice if no UP. */ 205 if (i + destline < j || (!UP && destline < outline)) { 206 /* 207 * Cheaper to home. Do it now and pretend it's a 208 * regular local motion. 209 */ 210 tputs(HO, 0, plodput); 211 outcol = outline = 0; 212 } else if (LL) { 213 /* 214 * Quickly consider homing down and moving from there. 215 * Assume cost of LL is 2. 216 */ 217 k = (LINES - 1) - destline; 218 if (i + k + 2 < j && (k <= 0 || UP)) { 219 tputs(LL, 0, plodput); 220 outcol = 0; 221 outline = LINES - 1; 222 } 223 } 224 } else 225 /* No home and no up means it's impossible. */ 226 if (!UP && destline < outline) 227 return (-1); 228 if (GT) 229 i = destcol % HARDTABS + destcol / HARDTABS; 230 else 231 i = destcol; 232 #ifdef notdef 233 if (BT && outcol > destcol && 234 (j = (((outcol+7) & ~7) - destcol - 1) >> 3)) { 235 j *= (k = strlen(BT)); 236 if ((k += (destcol&7)) > 4) 237 j += 8 - (destcol&7); 238 else 239 j += k; 240 } 241 else 242 #endif 243 j = outcol - destcol; 244 245 /* 246 * If we will later need a \n which will turn into a \r\n by the 247 * system or the terminal, then don't bother to try to \r. 248 */ 249 if ((!(origtermio.c_oflag & ONLCR) || !__pfast) && outline < destline) 250 goto dontcr; 251 252 /* 253 * If the terminal will do a \r\n and there isn't room for it, then 254 * we can't afford a \r. 255 */ 256 if (NC && outline >= destline) 257 goto dontcr; 258 259 /* 260 * If it will be cheaper, or if we can't back up, then send a return 261 * preliminarily. 262 */ 263 if (j > i + 1 || outcol > destcol && !BS && !BC) { 264 /* 265 * BUG: this doesn't take the (possibly long) length of CR 266 * into account. 267 */ 268 if (CR) 269 tputs(CR, 0, plodput); 270 else 271 plodput('\r'); 272 if (NC) { 273 if (NL) 274 tputs(NL, 0, plodput); 275 else 276 plodput('\n'); 277 outline++; 278 } 279 outcol = 0; 280 } 281 282 dontcr: while (outline < destline) { 283 outline++; 284 if (NL) 285 tputs(NL, 0, plodput); 286 else 287 plodput('\n'); 288 if (plodcnt < 0) 289 goto out; 290 if (!(origtermio.c_oflag & ONLCR) || __pfast == 0) 291 outcol = 0; 292 } 293 if (BT) 294 k = strlen(BT); 295 while (outcol > destcol) { 296 if (plodcnt < 0) 297 goto out; 298 #ifdef notdef 299 if (BT && outcol - destcol > k + 4) { 300 tputs(BT, 0, plodput); 301 outcol--; 302 outcol &= ~7; 303 continue; 304 } 305 #endif 306 outcol--; 307 if (BC) 308 tputs(BC, 0, plodput); 309 else 310 plodput('\b'); 311 } 312 while (outline > destline) { 313 outline--; 314 tputs(UP, 0, plodput); 315 if (plodcnt < 0) 316 goto out; 317 } 318 if (GT && destcol - outcol > 1) { 319 for (;;) { 320 i = tabcol(outcol, HARDTABS); 321 if (i > destcol) 322 break; 323 if (TA) 324 tputs(TA, 0, plodput); 325 else 326 plodput('\t'); 327 outcol = i; 328 } 329 if (destcol - outcol > 4 && i < COLS && (BC || BS)) { 330 if (TA) 331 tputs(TA, 0, plodput); 332 else 333 plodput('\t'); 334 outcol = i; 335 while (outcol > destcol) { 336 outcol--; 337 if (BC) 338 tputs(BC, 0, plodput); 339 else 340 plodput('\b'); 341 } 342 } 343 } 344 while (outcol < destcol) { 345 /* 346 * Move one char to the right. We don't use ND space because 347 * it's better to just print the char we are moving over. 348 */ 349 if (_win != NULL) 350 if (plodflg) /* Avoid a complex calculation. */ 351 plodcnt--; 352 else { 353 i = curscr->lines[outline]->line[outcol]; 354 if ((i & __STANDOUT) == 355 (curscr->flags & __STANDOUT)) 356 putchar(i & 0177); 357 else 358 goto nondes; 359 } 360 else 361 nondes: if (ND) 362 tputs(ND, 0, plodput); 363 else 364 plodput(' '); 365 outcol++; 366 if (plodcnt < 0) 367 goto out; 368 } 369 370 out: if (plodflg) { 371 outcol = soutcol; 372 outline = soutline; 373 } 374 return (plodcnt); 375 } 376 377 /* 378 * Return the column number that results from being in column col and 379 * hitting a tab, where tabs are set every ts columns. Work right for 380 * the case where col > COLS, even if ts does not divide COLS. 381 */ 382 static int 383 tabcol(col, ts) 384 int col, ts; 385 { 386 int offset; 387 388 if (col >= COLS) { 389 offset = COLS * (col / COLS); 390 col -= offset; 391 } else 392 offset = 0; 393 return (col + ts - (col % ts) + offset); 394 } 395