1 /* $NetBSD: cr_put.c,v 1.9 1997/07/22 07:36:30 mikel 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.9 1997/07/22 07:36:30 mikel 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 register int c, l; 98 register 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 if (NL) 116 tputs(NL, 0, __cputchar); 117 else 118 putchar('\n'); 119 l--; 120 } 121 outcol = 0; 122 } 123 if (outline > LINES - 1) { 124 destline -= outline - (LINES - 1); 125 outline = LINES - 1; 126 } 127 } 128 if (destline >= LINES) { 129 l = destline; 130 destline = LINES - 1; 131 if (outline < LINES - 1) { 132 c = destcol; 133 if (__pfast == 0 && !CA) 134 destcol = 0; 135 fgoto(in_refresh); 136 destcol = c; 137 } 138 while (l >= LINES) { 139 /* The following linefeed (or simulation thereof) is 140 * supposed to scroll up the screen, since we are on 141 * the bottom line. We make the assumption that 142 * linefeed will scroll. If ns is in the capability 143 * list this won't work. We should probably have an 144 * sc capability but sf will generally take the place 145 * if it works. 146 * 147 * Superbee glitch: in the middle of the screen have 148 * to use esc B (down) because linefeed screws up in 149 * "Efficient Paging" (what a joke) mode (which is 150 * essential in some SB's because CRLF mode puts 151 * garbage in at end of memory), but you must use 152 * linefeed to scroll since down arrow won't go past 153 * memory end. I turned this off after recieving Paul 154 * Eggert's Superbee description which wins better. 155 */ 156 if (NL /* && !XB */ && __pfast) 157 tputs(NL, 0, __cputchar); 158 else 159 putchar('\n'); 160 l--; 161 if (__pfast == 0) 162 outcol = 0; 163 } 164 } 165 if (destline < outline && !(CA || UP)) 166 destline = outline; 167 if (CA) { 168 cgp = tgoto(CM, destcol, destline); 169 170 /* 171 * Need this condition due to inconsistent behavior 172 * of backspace on the last column. 173 */ 174 if (outcol != COLS - 1 && plod(strlen(cgp), in_refresh) > 0) 175 plod(0, in_refresh); 176 else 177 tputs(cgp, 0, __cputchar); 178 } else 179 plod(0, in_refresh); 180 outline = destline; 181 outcol = destcol; 182 } 183 /* 184 * Move (slowly) to destination. 185 * Hard thing here is using home cursor on really deficient terminals. 186 * Otherwise just use cursor motions, hacking use of tabs and overtabbing 187 * and backspace. 188 */ 189 190 static int plodcnt, plodflg; 191 192 static void 193 plodput(c) 194 int c; 195 { 196 if (plodflg) 197 --plodcnt; 198 else 199 putchar(c); 200 } 201 202 static int 203 plod(cnt, in_refresh) 204 int cnt, in_refresh; 205 { 206 register int i, j, k, soutcol, soutline; 207 208 plodcnt = plodflg = cnt; 209 soutcol = outcol; 210 soutline = outline; 211 /* 212 * Consider homing and moving down/right from there, vs. moving 213 * directly with local motions to the right spot. 214 */ 215 if (HO) { 216 /* 217 * i is the cost to home and tab/space to the right to get to 218 * the proper column. This assumes ND space costs 1 char. So 219 * i + destcol is cost of motion with home. 220 */ 221 if (GT) 222 i = (destcol / HARDTABS) + (destcol % HARDTABS); 223 else 224 i = destcol; 225 226 /* j is cost to move locally without homing. */ 227 if (destcol >= outcol) { /* if motion is to the right */ 228 j = destcol / HARDTABS - outcol / HARDTABS; 229 if (GT && j) 230 j += destcol % HARDTABS; 231 else 232 j = destcol - outcol; 233 } else 234 /* leftward motion only works if we can backspace. */ 235 if (outcol - destcol <= i && (BS || BC)) 236 /* Cheaper to backspace. */ 237 i = j = outcol - destcol; 238 else 239 /* Impossibly expensive. */ 240 j = i + 1; 241 242 /* k is the absolute value of vertical distance. */ 243 k = outline - destline; 244 if (k < 0) 245 k = -k; 246 j += k; 247 248 /* Decision. We may not have a choice if no UP. */ 249 if (i + destline < j || (!UP && destline < outline)) { 250 /* 251 * Cheaper to home. Do it now and pretend it's a 252 * regular local motion. 253 */ 254 tputs(HO, 0, plodput); 255 outcol = outline = 0; 256 } else if (LL) { 257 /* 258 * Quickly consider homing down and moving from there. 259 * Assume cost of LL is 2. 260 */ 261 k = (LINES - 1) - destline; 262 if (i + k + 2 < j && (k <= 0 || UP)) { 263 tputs(LL, 0, plodput); 264 outcol = 0; 265 outline = LINES - 1; 266 } 267 } 268 } else 269 /* No home and no up means it's impossible. */ 270 if (!UP && destline < outline) 271 return (-1); 272 if (GT) 273 i = destcol % HARDTABS + destcol / HARDTABS; 274 else 275 i = destcol; 276 #ifdef notdef 277 if (BT && outcol > destcol && 278 (j = (((outcol+7) & ~7) - destcol - 1) >> 3)) { 279 j *= (k = strlen(BT)); 280 if ((k += (destcol&7)) > 4) 281 j += 8 - (destcol&7); 282 else 283 j += k; 284 } 285 else 286 #endif 287 j = outcol - destcol; 288 289 /* 290 * If we will later need a \n which will turn into a \r\n by the 291 * system or the terminal, then don't bother to try to \r. 292 */ 293 if ((NONL || !__pfast) && outline < destline) 294 goto dontcr; 295 296 /* 297 * If the terminal will do a \r\n and there isn't room for it, then 298 * we can't afford a \r. 299 */ 300 if (NC && outline >= destline) 301 goto dontcr; 302 303 /* 304 * If it will be cheaper, or if we can't back up, then send a return 305 * preliminarily. 306 */ 307 if (j > i + 1 || (outcol > destcol && !BS && !BC)) { 308 /* 309 * BUG: this doesn't take the (possibly long) length of CR 310 * into account. 311 */ 312 if (CR) 313 tputs(CR, 0, plodput); 314 else 315 plodput('\r'); 316 if (NC) { 317 if (NL) 318 tputs(NL, 0, plodput); 319 else 320 plodput('\n'); 321 outline++; 322 } 323 outcol = 0; 324 } 325 326 dontcr: while (outline < destline) { 327 outline++; 328 if (NL) 329 tputs(NL, 0, plodput); 330 else 331 plodput('\n'); 332 if (plodcnt < 0) 333 goto out; 334 if (NONL || __pfast == 0) 335 outcol = 0; 336 } 337 if (BT) 338 k = strlen(BT); 339 while (outcol > destcol) { 340 if (plodcnt < 0) 341 goto out; 342 #ifdef notdef 343 if (BT && outcol - destcol > k + 4) { 344 tputs(BT, 0, plodput); 345 outcol--; 346 outcol &= ~7; 347 continue; 348 } 349 #endif 350 outcol--; 351 if (BC) 352 tputs(BC, 0, plodput); 353 else 354 plodput('\b'); 355 } 356 while (outline > destline) { 357 outline--; 358 tputs(UP, 0, plodput); 359 if (plodcnt < 0) 360 goto out; 361 } 362 if (GT && destcol - outcol > 1) { 363 for (;;) { 364 i = tabcol(outcol, HARDTABS); 365 if (i > destcol) 366 break; 367 if (TA) 368 tputs(TA, 0, plodput); 369 else 370 plodput('\t'); 371 outcol = i; 372 } 373 if (destcol - outcol > 4 && i < COLS && (BC || BS)) { 374 if (TA) 375 tputs(TA, 0, plodput); 376 else 377 plodput('\t'); 378 outcol = i; 379 while (outcol > destcol) { 380 outcol--; 381 if (BC) 382 tputs(BC, 0, plodput); 383 else 384 plodput('\b'); 385 } 386 } 387 } 388 while (outcol < destcol) { 389 /* 390 * Move one char to the right. We don't use ND space because 391 * it's better to just print the char we are moving over. 392 */ 393 if (in_refresh) 394 if (plodflg) /* Avoid a complex calculation. */ 395 plodcnt--; 396 else { 397 i = curscr->lines[outline]->line[outcol].ch; 398 if ((curscr->lines[outline]->line[outcol].attr 399 & __STANDOUT) == 400 (curscr->flags & __WSTANDOUT)) 401 putchar(i); 402 else 403 goto nondes; 404 } 405 else 406 nondes: if (ND) 407 tputs(ND, 0, plodput); 408 else 409 plodput(' '); 410 outcol++; 411 if (plodcnt < 0) 412 goto out; 413 } 414 415 out: if (plodflg) { 416 outcol = soutcol; 417 outline = soutline; 418 } 419 return (plodcnt); 420 } 421 422 /* 423 * Return the column number that results from being in column col and 424 * hitting a tab, where tabs are set every ts columns. Work right for 425 * the case where col > COLS, even if ts does not divide COLS. 426 */ 427 static int 428 tabcol(col, ts) 429 int col, ts; 430 { 431 int offset; 432 433 if (col >= COLS) { 434 offset = COLS * (col / COLS); 435 col -= offset; 436 } else 437 offset = 0; 438 return (col + ts - (col % ts) + offset); 439 } 440