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