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