1 /* $NetBSD: cr_put.c,v 1.21 2002/06/26 18:14:00 christos 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.21 2002/06/26 18:14:00 christos Exp $"); 42 #endif 43 #endif /* not lint */ 44 45 #include <string.h> 46 47 #include "curses.h" 48 #include "curses_private.h" 49 50 /* the following is defined and set up in setterm.c */ 51 extern struct tinfo *_cursesi_genbuf; 52 53 #define HARDTABS 8 54 55 /* 56 * Terminal driving and line formatting routines. Basic motion optimizations 57 * are done here as well as formatting lines (printing of control characters, 58 * line numbering and the like). 59 */ 60 61 /* Stub function for the users. */ 62 int 63 mvcur(int ly, int lx, int y, int x) 64 { 65 return (__mvcur(ly, lx, y, x, 0)); 66 } 67 68 static void fgoto __P((int)); 69 static int plod __P((int, int)); 70 static int plodput __P((int)); 71 static int tabcol __P((int, int)); 72 73 static int outcol, outline, destcol, destline; 74 75 /* 76 * Sync the position of the output cursor. Most work here is rounding for 77 * terminal boundaries getting the column position implied by wraparound or 78 * the lack thereof and rolling up the screen to get destline on the screen. 79 */ 80 int 81 __mvcur(int ly, int lx, int y, int x, int in_refresh) 82 { 83 #ifdef DEBUG 84 __CTRACE("mvcur: moving cursor from (%d, %d) to (%d, %d)\n", 85 ly, lx, y, x); 86 #endif 87 destcol = x; 88 destline = y; 89 outcol = lx; 90 outline = ly; 91 fgoto(in_refresh); 92 return (OK); 93 } 94 95 static void 96 fgoto(in_refresh) 97 int in_refresh; 98 { 99 int c, l; 100 char cgp[128]; 101 102 if (destcol >= COLS) { 103 destline += destcol / COLS; 104 destcol %= COLS; 105 } 106 if (outcol >= COLS) { 107 l = (outcol + 1) / COLS; 108 outline += l; 109 outcol %= COLS; 110 if (__tc_am == 0) { 111 while (l > 0) { 112 if (__pfast) { 113 if (__tc_cr) 114 tputs(__tc_cr, 0, __cputchar); 115 else 116 __cputchar('\r'); 117 } 118 if (__tc_nl) 119 tputs(__tc_nl, 0, __cputchar); 120 else 121 __cputchar('\n'); 122 l--; 123 } 124 outcol = 0; 125 } 126 if (outline > LINES - 1) { 127 destline -= outline - (LINES - 1); 128 outline = LINES - 1; 129 } 130 } 131 if (destline >= LINES) { 132 l = destline; 133 destline = LINES - 1; 134 if (outline < LINES - 1) { 135 c = destcol; 136 if (__pfast == 0 && !__CA) 137 destcol = 0; 138 fgoto(in_refresh); 139 destcol = c; 140 } 141 while (l >= LINES) { 142 /* The following linefeed (or simulation thereof) is 143 * supposed to scroll up the screen, since we are on 144 * the bottom line. We make the assumption that 145 * linefeed will scroll. If ns is in the capability 146 * list this won't work. We should probably have an 147 * sc capability but sf will generally take the place 148 * if it works. 149 * 150 * Superbee glitch: in the middle of the screen have to 151 * use esc B (down) because linefeed screws up in 152 * "Efficient Paging" (what a joke) mode (which is 153 * essential in some SB's because CRLF mode puts 154 * garbage in at end of memory), but you must use 155 * linefeed to scroll since down arrow won't go past 156 * memory end. I turned this off after recieving Paul 157 * Eggert's Superbee description which wins better. */ 158 if (__tc_nl /* && !__tc_xb */ && __pfast) 159 tputs(__tc_nl, 0, __cputchar); 160 else 161 __cputchar('\n'); 162 l--; 163 if (__pfast == 0) 164 outcol = 0; 165 } 166 } 167 if (destline < outline && !(__CA || __tc_up)) 168 destline = outline; 169 if (__CA && t_goto(NULL, __tc_cm, destcol, destline, cgp, 170 sizeof(cgp) - 1) != -1) { 171 /* 172 * Need this condition due to inconsistent behavior 173 * of backspace on the last column. 174 */ 175 if (outcol != COLS - 1 && 176 plod((int) strlen(cgp), in_refresh) > 0) 177 plod(0, in_refresh); 178 else 179 tputs(cgp, 0, __cputchar); 180 } else 181 plod(0, in_refresh); 182 outline = destline; 183 outcol = destcol; 184 } 185 /* 186 * Move (slowly) to destination. 187 * Hard thing here is using home cursor on really deficient terminals. 188 * Otherwise just use cursor motions, hacking use of tabs and overtabbing 189 * and backspace. 190 */ 191 192 static int plodcnt, plodflg; 193 194 static int 195 plodput(c) 196 int c; 197 { 198 if (plodflg) 199 --plodcnt; 200 else 201 __cputchar(c); 202 return (0); 203 } 204 205 static int 206 plod(cnt, in_refresh) 207 int cnt, in_refresh; 208 { 209 int i, j, k, soutcol, soutline; 210 211 plodcnt = plodflg = cnt; 212 soutcol = outcol; 213 soutline = outline; 214 /* 215 * Consider homing and moving down/right from there, vs. moving 216 * directly with local motions to the right spot. 217 */ 218 if (__tc_ho) { 219 /* 220 * i is the cost to home and tab/space to the right to get to 221 * the proper column. This assumes nd space costs 1 char. So 222 * i + destcol is cost of motion with home. 223 */ 224 if (__GT) 225 i = (destcol / HARDTABS) + (destcol % HARDTABS); 226 else 227 i = destcol; 228 229 /* j is cost to move locally without homing. */ 230 if (destcol >= outcol) { /* if motion is to the right */ 231 j = destcol / HARDTABS - outcol / HARDTABS; 232 if (__GT && j) 233 j += destcol % HARDTABS; 234 else 235 j = destcol - outcol; 236 } else 237 /* leftward motion only works if we can backspace. */ 238 if (outcol - destcol <= i && (__tc_bs || __tc_bc)) 239 /* Cheaper to backspace. */ 240 i = j = outcol - destcol; 241 else 242 /* Impossibly expensive. */ 243 j = i + 1; 244 245 /* k is the absolute value of vertical distance. */ 246 k = outline - destline; 247 if (k < 0) 248 k = -k; 249 j += k; 250 251 /* Decision. We may not have a choice if no up. */ 252 if (i + destline < j || (!__tc_up && destline < outline)) { 253 /* 254 * Cheaper to home. Do it now and pretend it's a 255 * regular local motion. 256 */ 257 tputs(__tc_ho, 0, plodput); 258 outcol = outline = 0; 259 } else 260 if (__tc_ll) { 261 /* 262 * Quickly consider homing down and moving from 263 * there. Assume cost of ll is 2. 264 */ 265 k = (LINES - 1) - destline; 266 if (i + k + 2 < j && (k <= 0 || __tc_up)) { 267 tputs(__tc_ll, 0, plodput); 268 outcol = 0; 269 outline = LINES - 1; 270 } 271 } 272 } else 273 /* No home and no up means it's impossible. */ 274 if (!__tc_up && destline < outline) 275 return (-1); 276 if (__GT) 277 i = destcol % HARDTABS + destcol / HARDTABS; 278 else 279 i = destcol; 280 #ifdef notdef 281 if (__tc_bt && outcol > destcol && 282 (j = (((outcol + 7) & ~7) - destcol - 1) >> 3)) { 283 j *= (k = strlen(__tc_bt)); 284 if ((k += (destcol & 7)) > 4) 285 j += 8 - (destcol & 7); 286 else 287 j += k; 288 } else 289 #endif 290 j = outcol - destcol; 291 292 /* 293 * If we will later need a \n which will turn into a \r\n by the 294 * system or the terminal, then don't bother to try to \r. 295 */ 296 if ((__NONL || !__pfast) && outline < destline) 297 goto dontcr; 298 299 /* 300 * If the terminal will do a \r\n and there isn't room for it, then 301 * we can't afford a \r. 302 */ 303 if (__tc_nc && outline >= destline) 304 goto dontcr; 305 306 /* 307 * If it will be cheaper, or if we can't back up, then send a return 308 * preliminarily. 309 */ 310 if (j > i + 1 || (outcol > destcol && !__tc_bs && !__tc_bc)) { 311 /* 312 * BUG: this doesn't take the (possibly long) length of cr 313 * into account. 314 */ 315 if (__tc_cr) 316 tputs(__tc_cr, 0, plodput); 317 else 318 plodput('\r'); 319 if (__tc_nc) { 320 if (__tc_nl) 321 tputs(__tc_nl, 0, plodput); 322 else 323 plodput('\n'); 324 outline++; 325 } 326 outcol = 0; 327 } 328 dontcr:while (outline < destline) { 329 outline++; 330 if (__tc_nl) 331 tputs(__tc_nl, 0, plodput); 332 else 333 plodput('\n'); 334 if (plodcnt < 0) 335 goto out; 336 if (__NONL || __pfast == 0) 337 outcol = 0; 338 } 339 if (__tc_bt) 340 k = (int) strlen(__tc_bt); 341 while (outcol > destcol) { 342 if (plodcnt < 0) 343 goto out; 344 #ifdef notdef 345 if (__tc_bt && outcol - destcol > k + 4) { 346 tputs(__tc_bt, 0, plodput); 347 outcol--; 348 outcol &= ~7; 349 continue; 350 } 351 #endif 352 outcol--; 353 if (__tc_bc) 354 tputs(__tc_bc, 0, plodput); 355 else 356 plodput('\b'); 357 } 358 while (outline > destline) { 359 outline--; 360 tputs(__tc_up, 0, plodput); 361 if (plodcnt < 0) 362 goto out; 363 } 364 if (__GT && destcol - outcol > 1) { 365 for (;;) { 366 i = tabcol(outcol, HARDTABS); 367 if (i > destcol) 368 break; 369 if (__tc_ta) 370 tputs(__tc_ta, 0, plodput); 371 else 372 plodput('\t'); 373 outcol = i; 374 } 375 if (destcol - outcol > 4 && i < COLS && (__tc_bc || __tc_bs)) { 376 if (__tc_ta) 377 tputs(__tc_ta, 0, plodput); 378 else 379 plodput('\t'); 380 outcol = i; 381 while (outcol > destcol) { 382 outcol--; 383 if (__tc_bc) 384 tputs(__tc_bc, 0, plodput); 385 else 386 plodput('\b'); 387 } 388 } 389 } 390 while (outcol < destcol) { 391 /* 392 * Move one char to the right. We don't use nd space because 393 * it's better to just print the char we are moving over. 394 */ 395 if (in_refresh) 396 if (plodflg) /* Avoid a complex calculation. */ 397 plodcnt--; 398 else { 399 i = curscr->lines[outline]->line[outcol].ch 400 & __CHARTEXT; 401 if (curscr->lines[outline]->line[outcol].attr 402 == curscr->wattr) 403 __cputchar(i); 404 else 405 goto nondes; 406 } 407 else 408 nondes: if (__tc_nd) 409 tputs(__tc_nd, 0, plodput); 410 else 411 plodput(' '); 412 outcol++; 413 if (plodcnt < 0) 414 goto out; 415 } 416 417 out: if (plodflg) { 418 outcol = soutcol; 419 outline = soutline; 420 } 421 return (plodcnt); 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