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