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