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