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