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