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