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