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