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