xref: /minix3/lib/libcurses/cr_put.c (revision 0c3ae37f525eceade8dc047e551f5c9cb33faeb1)
1*0c3ae37fSLionel Sambuc /*	$NetBSD: cr_put.c,v 1.31 2011/10/03 12:32:15 roy Exp $	*/
251ffecc1SBen Gras 
351ffecc1SBen Gras /*
451ffecc1SBen Gras  * Copyright (c) 1981, 1993, 1994
551ffecc1SBen Gras  *	The Regents of the University of California.  All rights reserved.
651ffecc1SBen Gras  *
751ffecc1SBen Gras  * Redistribution and use in source and binary forms, with or without
851ffecc1SBen Gras  * modification, are permitted provided that the following conditions
951ffecc1SBen Gras  * are met:
1051ffecc1SBen Gras  * 1. Redistributions of source code must retain the above copyright
1151ffecc1SBen Gras  *    notice, this list of conditions and the following disclaimer.
1251ffecc1SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
1351ffecc1SBen Gras  *    notice, this list of conditions and the following disclaimer in the
1451ffecc1SBen Gras  *    documentation and/or other materials provided with the distribution.
1551ffecc1SBen Gras  * 3. Neither the name of the University nor the names of its contributors
1651ffecc1SBen Gras  *    may be used to endorse or promote products derived from this software
1751ffecc1SBen Gras  *    without specific prior written permission.
1851ffecc1SBen Gras  *
1951ffecc1SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2051ffecc1SBen Gras  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2151ffecc1SBen Gras  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2251ffecc1SBen Gras  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2351ffecc1SBen Gras  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2451ffecc1SBen Gras  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2551ffecc1SBen Gras  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2651ffecc1SBen Gras  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2751ffecc1SBen Gras  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2851ffecc1SBen Gras  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2951ffecc1SBen Gras  * SUCH DAMAGE.
3051ffecc1SBen Gras  */
3151ffecc1SBen Gras 
3251ffecc1SBen Gras #include <sys/cdefs.h>
3351ffecc1SBen Gras #ifndef lint
3451ffecc1SBen Gras #if 0
3551ffecc1SBen Gras static char sccsid[] = "@(#)cr_put.c	8.3 (Berkeley) 5/4/94";
3651ffecc1SBen Gras #else
37*0c3ae37fSLionel Sambuc __RCSID("$NetBSD: cr_put.c,v 1.31 2011/10/03 12:32:15 roy Exp $");
3851ffecc1SBen Gras #endif
3951ffecc1SBen Gras #endif				/* not lint */
4051ffecc1SBen Gras 
4151ffecc1SBen Gras #include <string.h>
4251ffecc1SBen Gras 
4351ffecc1SBen Gras #include "curses.h"
4451ffecc1SBen Gras #include "curses_private.h"
4551ffecc1SBen Gras 
4651ffecc1SBen Gras #define	HARDTABS	8
4751ffecc1SBen Gras 
4851ffecc1SBen Gras /*
4951ffecc1SBen Gras  * Terminal driving and line formatting routines.  Basic motion optimizations
5051ffecc1SBen Gras  * are done here as well as formatting lines (printing of control characters,
5151ffecc1SBen Gras  * line numbering and the like).
5251ffecc1SBen Gras  */
5351ffecc1SBen Gras 
5451ffecc1SBen Gras /* Stub function for the users. */
5551ffecc1SBen Gras int
mvcur(int ly,int lx,int y,int x)5651ffecc1SBen Gras mvcur(int ly, int lx, int y, int x)
5751ffecc1SBen Gras {
5851ffecc1SBen Gras 	return (__mvcur(ly, lx, y, x, 0));
5951ffecc1SBen Gras }
6051ffecc1SBen Gras 
6151ffecc1SBen Gras static void fgoto __P((int));
6251ffecc1SBen Gras static int plod __P((int, int));
6351ffecc1SBen Gras static int plodput __P((int));
6451ffecc1SBen Gras static int tabcol __P((int, int));
6551ffecc1SBen Gras 
6651ffecc1SBen Gras static int outcol, outline, destcol, destline;
6751ffecc1SBen Gras 
6851ffecc1SBen Gras /*
6951ffecc1SBen Gras  * Sync the position of the output cursor.  Most work here is rounding for
7051ffecc1SBen Gras  * terminal boundaries getting the column position implied by wraparound or
7151ffecc1SBen Gras  * the lack thereof and rolling up the screen to get destline on the screen.
7251ffecc1SBen Gras  */
7351ffecc1SBen Gras int
__mvcur(int ly,int lx,int y,int x,int in_refresh)7451ffecc1SBen Gras __mvcur(int ly, int lx, int y, int x, int in_refresh)
7551ffecc1SBen Gras {
7651ffecc1SBen Gras #ifdef DEBUG
7751ffecc1SBen Gras 	__CTRACE(__CTRACE_OUTPUT,
7851ffecc1SBen Gras 	    "mvcur: moving cursor from (%d, %d) to (%d, %d)\n", ly, lx, y, x);
7951ffecc1SBen Gras #endif
8051ffecc1SBen Gras 	destcol = x;
8151ffecc1SBen Gras 	destline = y;
8251ffecc1SBen Gras 	outcol = lx;
8351ffecc1SBen Gras 	outline = ly;
8451ffecc1SBen Gras 	fgoto(in_refresh);
8551ffecc1SBen Gras 	return (OK);
8651ffecc1SBen Gras }
8751ffecc1SBen Gras 
8851ffecc1SBen Gras static void
fgoto(in_refresh)8951ffecc1SBen Gras fgoto(in_refresh)
9051ffecc1SBen Gras 	int	 in_refresh;
9151ffecc1SBen Gras {
9251ffecc1SBen Gras 	int	 c, l;
9351ffecc1SBen Gras 	char	*cgp;
9451ffecc1SBen Gras 
9551ffecc1SBen Gras #ifdef DEBUG
9651ffecc1SBen Gras 	__CTRACE(__CTRACE_OUTPUT, "fgoto: in_refresh=%d\n", in_refresh);
9751ffecc1SBen Gras #endif /* DEBUG */
9851ffecc1SBen Gras 	if (destcol >= COLS) {
9951ffecc1SBen Gras 		destline += destcol / COLS;
10051ffecc1SBen Gras 		destcol %= COLS;
10151ffecc1SBen Gras 	}
10251ffecc1SBen Gras 	if (outcol >= COLS) {
10351ffecc1SBen Gras 		l = (outcol + 1) / COLS;
10451ffecc1SBen Gras 		outline += l;
10551ffecc1SBen Gras 		outcol %= COLS;
10651ffecc1SBen Gras 		if (auto_left_margin == 0) {
10751ffecc1SBen Gras 			while (l > 0) {
10851ffecc1SBen Gras 				if (__pfast) {
10951ffecc1SBen Gras 					if (carriage_return)
11051ffecc1SBen Gras 						tputs(carriage_return,
11151ffecc1SBen Gras 							0, __cputchar);
11251ffecc1SBen Gras 					else
11351ffecc1SBen Gras 						__cputchar('\r');
11451ffecc1SBen Gras 				}
11551ffecc1SBen Gras 				if (cursor_down)
11651ffecc1SBen Gras 					tputs(cursor_down, 0, __cputchar);
11751ffecc1SBen Gras 				else
11851ffecc1SBen Gras 					__cputchar('\n');
11951ffecc1SBen Gras 				l--;
12051ffecc1SBen Gras 			}
12151ffecc1SBen Gras 			outcol = 0;
12251ffecc1SBen Gras 		}
12351ffecc1SBen Gras 		if (outline > LINES - 1) {
12451ffecc1SBen Gras 			destline -= outline - (LINES - 1);
12551ffecc1SBen Gras 			outline = LINES - 1;
12651ffecc1SBen Gras 		}
12751ffecc1SBen Gras 	}
12851ffecc1SBen Gras 	if (destline >= LINES) {
12951ffecc1SBen Gras 		l = destline;
13051ffecc1SBen Gras 		destline = LINES - 1;
13151ffecc1SBen Gras 		if (outline < LINES - 1) {
13251ffecc1SBen Gras 			c = destcol;
13351ffecc1SBen Gras 			if (__pfast == 0 && !cursor_address)
13451ffecc1SBen Gras 				destcol = 0;
13551ffecc1SBen Gras 			fgoto(in_refresh);
13651ffecc1SBen Gras 			destcol = c;
13751ffecc1SBen Gras 		}
13851ffecc1SBen Gras 		while (l >= LINES) {
13951ffecc1SBen Gras 			/* The following linefeed (or simulation thereof) is
14051ffecc1SBen Gras 			 * supposed to scroll up the screen, since we are on
14151ffecc1SBen Gras 			 * the bottom line.  We make the assumption that
14251ffecc1SBen Gras 			 * linefeed will scroll.  If ns is in the capability
14351ffecc1SBen Gras 			 * list this won't work.  We should probably have an
14451ffecc1SBen Gras 			 * sc capability but sf will generally take the place
14551ffecc1SBen Gras 			 * if it works.
14651ffecc1SBen Gras 			 *
14751ffecc1SBen Gras 			 * Superbee glitch: in the middle of the screen have to
14851ffecc1SBen Gras 			 * use esc B (down) because linefeed screws up in
14951ffecc1SBen Gras 			 * "Efficient Paging" (what a joke) mode (which is
15051ffecc1SBen Gras 			 * essential in some SB's because CRLF mode puts
15151ffecc1SBen Gras 			 * garbage in at end of memory), but you must use
15251ffecc1SBen Gras 			 * linefeed to scroll since down arrow won't go past
15351ffecc1SBen Gras 			 * memory end. I turned this off after recieving Paul
15451ffecc1SBen Gras 			 * Eggert's Superbee description which wins better. */
15551ffecc1SBen Gras 			if (cursor_down /* && !__tc_xb */ && __pfast)
15651ffecc1SBen Gras 				tputs(cursor_down, 0, __cputchar);
15751ffecc1SBen Gras 			else
15851ffecc1SBen Gras 				__cputchar('\n');
15951ffecc1SBen Gras 			l--;
16051ffecc1SBen Gras 			if (__pfast == 0)
16151ffecc1SBen Gras 				outcol = 0;
16251ffecc1SBen Gras 		}
16351ffecc1SBen Gras 	}
16451ffecc1SBen Gras 	if (destline < outline && !(cursor_address || cursor_up))
16551ffecc1SBen Gras 		destline = outline;
16651ffecc1SBen Gras 
16751ffecc1SBen Gras 	if (cursor_address &&
168*0c3ae37fSLionel Sambuc 	    (cgp = tiparm(cursor_address, destline, destcol)))
16951ffecc1SBen Gras 	{
17051ffecc1SBen Gras 		/*
17151ffecc1SBen Gras 		 * Need this condition due to inconsistent behavior
17251ffecc1SBen Gras 		 * of backspace on the last column.
17351ffecc1SBen Gras 		 */
17451ffecc1SBen Gras #ifdef DEBUG
17551ffecc1SBen Gras 		__CTRACE(__CTRACE_OUTPUT, "fgoto: cgp=%s\n", cgp);
17651ffecc1SBen Gras #endif /* DEBUG */
17751ffecc1SBen Gras 		if (outcol != COLS - 1 &&
17851ffecc1SBen Gras 		    plod((int) strlen(cgp), in_refresh) > 0)
17951ffecc1SBen Gras 			plod(0, in_refresh);
18051ffecc1SBen Gras 		else
18151ffecc1SBen Gras 			tputs(cgp, 0, __cputchar);
18251ffecc1SBen Gras 	} else
18351ffecc1SBen Gras 		plod(0, in_refresh);
18451ffecc1SBen Gras 	outline = destline;
18551ffecc1SBen Gras 	outcol = destcol;
18651ffecc1SBen Gras }
18751ffecc1SBen Gras /*
18851ffecc1SBen Gras  * Move (slowly) to destination.
18951ffecc1SBen Gras  * Hard thing here is using home cursor on really deficient terminals.
19051ffecc1SBen Gras  * Otherwise just use cursor motions, hacking use of tabs and overtabbing
19151ffecc1SBen Gras  * and backspace.
19251ffecc1SBen Gras  *
19351ffecc1SBen Gras  * XXX this needs to be revisited for wide characters since we may output
19451ffecc1SBen Gras  * XXX more than one byte for a character.
19551ffecc1SBen Gras  */
19651ffecc1SBen Gras 
19751ffecc1SBen Gras static int plodcnt, plodflg;
19851ffecc1SBen Gras 
19951ffecc1SBen Gras static int
plodput(c)20051ffecc1SBen Gras plodput(c)
20151ffecc1SBen Gras 	int	 c;
20251ffecc1SBen Gras {
20351ffecc1SBen Gras 	if (plodflg)
20451ffecc1SBen Gras 		--plodcnt;
20551ffecc1SBen Gras 	else
20651ffecc1SBen Gras 		__cputchar(c);
20751ffecc1SBen Gras 	return (0);
20851ffecc1SBen Gras }
20951ffecc1SBen Gras 
21051ffecc1SBen Gras static int
plod(cnt,in_refresh)21151ffecc1SBen Gras plod(cnt, in_refresh)
21251ffecc1SBen Gras 	int	 cnt, in_refresh;
21351ffecc1SBen Gras {
21451ffecc1SBen Gras 	int	 i, j, k, soutcol, soutline;
21551ffecc1SBen Gras 
21651ffecc1SBen Gras #ifdef DEBUG
21751ffecc1SBen Gras 	__CTRACE(__CTRACE_OUTPUT, "plod: cnt=%d, in_refresh=%d\n",
21851ffecc1SBen Gras 	    cnt, in_refresh);
21951ffecc1SBen Gras #endif /* DEBUG */
22051ffecc1SBen Gras 	plodcnt = plodflg = cnt;
22151ffecc1SBen Gras 	soutcol = outcol;
22251ffecc1SBen Gras 	soutline = outline;
22351ffecc1SBen Gras 
22451ffecc1SBen Gras 	/*
22551ffecc1SBen Gras 	 * Consider homing and moving down/right from there, vs. moving
22651ffecc1SBen Gras 	 * directly with local motions to the right spot.
22751ffecc1SBen Gras 	 */
22851ffecc1SBen Gras 	if (cursor_home) {
22951ffecc1SBen Gras 		/*
23051ffecc1SBen Gras 		 * i is the cost to home and tab/space to the right to get to
23151ffecc1SBen Gras 		 * the proper column.  This assumes nd space costs 1 char.  So
23251ffecc1SBen Gras 		 * i + destcol is cost of motion with home.
23351ffecc1SBen Gras 		 */
23451ffecc1SBen Gras 		if (__GT)
23551ffecc1SBen Gras 			i = (destcol / HARDTABS) + (destcol % HARDTABS);
23651ffecc1SBen Gras 		else
23751ffecc1SBen Gras 			i = destcol;
23851ffecc1SBen Gras 
23951ffecc1SBen Gras 		/* j is cost to move locally without homing. */
24051ffecc1SBen Gras 		if (destcol >= outcol) {	/* if motion is to the right */
24151ffecc1SBen Gras 			j = destcol / HARDTABS - outcol / HARDTABS;
24251ffecc1SBen Gras 			if (__GT && j)
24351ffecc1SBen Gras 				j += destcol % HARDTABS;
24451ffecc1SBen Gras 			else
24551ffecc1SBen Gras 				j = destcol - outcol;
24651ffecc1SBen Gras 		} else
24751ffecc1SBen Gras 			/* leftward motion only works if we can backspace. */
24851ffecc1SBen Gras 			if (outcol - destcol <= i)
24951ffecc1SBen Gras 				/* Cheaper to backspace. */
25051ffecc1SBen Gras 				i = j = outcol - destcol;
25151ffecc1SBen Gras 			else
25251ffecc1SBen Gras 				/* Impossibly expensive. */
25351ffecc1SBen Gras 				j = i + 1;
25451ffecc1SBen Gras 
25551ffecc1SBen Gras 		/* k is the absolute value of vertical distance. */
25651ffecc1SBen Gras 		k = outline - destline;
25751ffecc1SBen Gras 		if (k < 0)
25851ffecc1SBen Gras 			k = -k;
25951ffecc1SBen Gras 		j += k;
26051ffecc1SBen Gras 
26151ffecc1SBen Gras 		/* Decision.  We may not have a choice if no up. */
26251ffecc1SBen Gras 		if (i + destline < j || (!cursor_up && destline < outline)) {
26351ffecc1SBen Gras 			/*
26451ffecc1SBen Gras 			 * Cheaper to home.  Do it now and pretend it's a
26551ffecc1SBen Gras 			 * regular local motion.
26651ffecc1SBen Gras 			 */
26751ffecc1SBen Gras 			tputs(cursor_home, 0, plodput);
26851ffecc1SBen Gras 			outcol = outline = 0;
26951ffecc1SBen Gras 		} else
27051ffecc1SBen Gras 			if (cursor_to_ll) {
27151ffecc1SBen Gras 				/*
27251ffecc1SBen Gras 				 * Quickly consider homing down and moving from
27351ffecc1SBen Gras 				 * there.  Assume cost of ll is 2.
27451ffecc1SBen Gras 				 */
27551ffecc1SBen Gras 				k = (LINES - 1) - destline;
27651ffecc1SBen Gras 				if (i + k + 2 < j && (k <= 0 || cursor_up)) {
27751ffecc1SBen Gras 					tputs(cursor_to_ll, 0, plodput);
27851ffecc1SBen Gras 					outcol = 0;
27951ffecc1SBen Gras 					outline = LINES - 1;
28051ffecc1SBen Gras 				}
28151ffecc1SBen Gras 			}
28251ffecc1SBen Gras 	} else
28351ffecc1SBen Gras 		/* No home and no up means it's impossible. */
28451ffecc1SBen Gras 		if (!cursor_up && destline < outline)
28551ffecc1SBen Gras 			return (-1);
28651ffecc1SBen Gras 	if (__GT)
28751ffecc1SBen Gras 		i = destcol % HARDTABS + destcol / HARDTABS;
28851ffecc1SBen Gras 	else
28951ffecc1SBen Gras 		i = destcol;
29051ffecc1SBen Gras #ifdef notdef
29151ffecc1SBen Gras 	if (back_tab && outcol > destcol &&
29251ffecc1SBen Gras 	    (j = (((outcol + 7) & ~7) - destcol - 1) >> 3)) {
29351ffecc1SBen Gras 		j *= (k = strlen(back_tab));
29451ffecc1SBen Gras 		if ((k += (destcol & 7)) > 4)
29551ffecc1SBen Gras 			j += 8 - (destcol & 7);
29651ffecc1SBen Gras 		else
29751ffecc1SBen Gras 			j += k;
29851ffecc1SBen Gras 	} else
29951ffecc1SBen Gras #endif
30051ffecc1SBen Gras 		j = outcol - destcol;
30151ffecc1SBen Gras 
30251ffecc1SBen Gras 	/*
30351ffecc1SBen Gras 	 * If we will later need a \n which will turn into a \r\n by the
30451ffecc1SBen Gras 	 * system or the terminal, then don't bother to try to \r.
30551ffecc1SBen Gras 	 */
30651ffecc1SBen Gras 	if ((__NONL || !__pfast) && outline < destline)
30751ffecc1SBen Gras 		goto dontcr;
30851ffecc1SBen Gras 
30951ffecc1SBen Gras 	/*
31051ffecc1SBen Gras 	 * If the terminal will do a \r\n and there isn't room for it, then
31151ffecc1SBen Gras 	 * we can't afford a \r.
31251ffecc1SBen Gras 	 */
31351ffecc1SBen Gras 	if (!carriage_return && outline >= destline)
31451ffecc1SBen Gras 		goto dontcr;
31551ffecc1SBen Gras 
31651ffecc1SBen Gras 	/*
31751ffecc1SBen Gras 	 * If it will be cheaper, or if we can't back up, then send a return
31851ffecc1SBen Gras 	 * preliminarily.
31951ffecc1SBen Gras 	 */
32051ffecc1SBen Gras 	if (j > i + 1 || outcol > destcol) {
32151ffecc1SBen Gras 		/*
32251ffecc1SBen Gras 		 * BUG: this doesn't take the (possibly long) length of cr
32351ffecc1SBen Gras 		 * into account.
32451ffecc1SBen Gras 		 */
32551ffecc1SBen Gras 		if (carriage_return)
32651ffecc1SBen Gras 			tputs(carriage_return, 0, plodput);
32751ffecc1SBen Gras 		else
32851ffecc1SBen Gras 			plodput('\r');
32951ffecc1SBen Gras 		if (!carriage_return) {
33051ffecc1SBen Gras 			if (cursor_down)
33151ffecc1SBen Gras 				tputs(cursor_down, 0, plodput);
33251ffecc1SBen Gras 			else
33351ffecc1SBen Gras 				plodput('\n');
33451ffecc1SBen Gras 			outline++;
33551ffecc1SBen Gras 		}
33651ffecc1SBen Gras 		outcol = 0;
33751ffecc1SBen Gras 	}
33851ffecc1SBen Gras dontcr:while (outline < destline) {
33951ffecc1SBen Gras 		outline++;
34051ffecc1SBen Gras 		if (cursor_down)
34151ffecc1SBen Gras 			tputs(cursor_down, 0, plodput);
34251ffecc1SBen Gras 		else
34351ffecc1SBen Gras 			plodput('\n');
34451ffecc1SBen Gras 		if (plodcnt < 0)
34551ffecc1SBen Gras 			goto out;
34651ffecc1SBen Gras 		if (__NONL || __pfast == 0)
34751ffecc1SBen Gras 			outcol = 0;
34851ffecc1SBen Gras 	}
34951ffecc1SBen Gras 	if (back_tab)
35051ffecc1SBen Gras 		k = (int) strlen(back_tab);
35151ffecc1SBen Gras 	while (outcol > destcol) {
35251ffecc1SBen Gras 		if (plodcnt < 0)
35351ffecc1SBen Gras 			goto out;
35451ffecc1SBen Gras #ifdef notdef
35551ffecc1SBen Gras 		if (back_tab && outcol - destcol > k + 4) {
35651ffecc1SBen Gras 			tputs(back_tab, 0, plodput);
35751ffecc1SBen Gras 			outcol--;
35851ffecc1SBen Gras 			outcol &= ~7;
35951ffecc1SBen Gras 			continue;
36051ffecc1SBen Gras 		}
36151ffecc1SBen Gras #endif
36251ffecc1SBen Gras 		outcol--;
36351ffecc1SBen Gras 		if (cursor_left)
36451ffecc1SBen Gras 			tputs(cursor_left, 0, plodput);
36551ffecc1SBen Gras 		else
36651ffecc1SBen Gras 			plodput('\b');
36751ffecc1SBen Gras 	}
36851ffecc1SBen Gras 	while (outline > destline) {
36951ffecc1SBen Gras 		outline--;
37051ffecc1SBen Gras 		tputs(cursor_up, 0, plodput);
37151ffecc1SBen Gras 		if (plodcnt < 0)
37251ffecc1SBen Gras 			goto out;
37351ffecc1SBen Gras 	}
37451ffecc1SBen Gras 	if (__GT && destcol - outcol > 1) {
37551ffecc1SBen Gras 		for (;;) {
37651ffecc1SBen Gras 			i = tabcol(outcol, HARDTABS);
37751ffecc1SBen Gras 			if (i > destcol)
37851ffecc1SBen Gras 				break;
37951ffecc1SBen Gras 			if (tab)
38051ffecc1SBen Gras 				tputs(tab, 0, plodput);
38151ffecc1SBen Gras 			else
38251ffecc1SBen Gras 				plodput('\t');
38351ffecc1SBen Gras 			outcol = i;
38451ffecc1SBen Gras 		}
38551ffecc1SBen Gras 		if (destcol - outcol > 4 && i < COLS) {
38651ffecc1SBen Gras 			if (tab)
38751ffecc1SBen Gras 				tputs(tab, 0, plodput);
38851ffecc1SBen Gras 			else
38951ffecc1SBen Gras 				plodput('\t');
39051ffecc1SBen Gras 			outcol = i;
39151ffecc1SBen Gras 			while (outcol > destcol) {
39251ffecc1SBen Gras 				outcol--;
39351ffecc1SBen Gras 				if (cursor_left)
39451ffecc1SBen Gras 					tputs(cursor_left, 0, plodput);
39551ffecc1SBen Gras 				else
39651ffecc1SBen Gras 					plodput('\b');
39751ffecc1SBen Gras 			}
39851ffecc1SBen Gras 		}
39951ffecc1SBen Gras 	}
40051ffecc1SBen Gras 	while (outcol < destcol) {
40151ffecc1SBen Gras 		/*
40251ffecc1SBen Gras 		 * Move one char to the right.  We don't use nd space because
40351ffecc1SBen Gras 		 * it's better to just print the char we are moving over.
40451ffecc1SBen Gras 		 */
40551ffecc1SBen Gras 		if (in_refresh)
40651ffecc1SBen Gras 			if (plodflg)	/* Avoid a complex calculation. */
40751ffecc1SBen Gras 				plodcnt--;
40851ffecc1SBen Gras 			else {
40951ffecc1SBen Gras #ifndef HAVE_WCHAR
41051ffecc1SBen Gras 				i = curscr->alines[outline]->line[outcol].ch
41151ffecc1SBen Gras 				    & __CHARTEXT;
41251ffecc1SBen Gras 				if (curscr->alines[outline]->line[outcol].attr
41351ffecc1SBen Gras 				    == curscr->wattr)
41451ffecc1SBen Gras 					__cputchar(i);
41551ffecc1SBen Gras #else
41651ffecc1SBen Gras 				if ((curscr->alines[outline]->line[outcol].attr
41751ffecc1SBen Gras 				    & WA_ATTRIBUTES)
41851ffecc1SBen Gras 				    == curscr->wattr) {
41951ffecc1SBen Gras 					switch (WCOL(curscr->alines[outline]->line[outcol])) {
42051ffecc1SBen Gras 					case 1:
42151ffecc1SBen Gras 						__cputwchar(curscr->alines[outline]->line[outcol].ch);
42251ffecc1SBen Gras 						__cursesi_putnsp(curscr->alines[outline]->line[outcol].nsp,
42351ffecc1SBen Gras 								outline,
42451ffecc1SBen Gras 								outcol);
42551ffecc1SBen Gras #ifdef DEBUG
42651ffecc1SBen Gras 						__CTRACE(__CTRACE_OUTPUT,
42751ffecc1SBen Gras 						    "plod: (%d,%d)WCOL(%d), "
42851ffecc1SBen Gras 						    "putwchar(%x)\n",
42951ffecc1SBen Gras 						    outline, outcol,
43051ffecc1SBen Gras 						    WCOL(curscr->alines[outline]->line[outcol]),
43151ffecc1SBen Gras 						    curscr->alines[outline]->line[outcol].ch);
43251ffecc1SBen Gras #endif /* DEBUG */
43351ffecc1SBen Gras 					/*FALLTHROUGH*/
43451ffecc1SBen Gras 					case 0:
43551ffecc1SBen Gras 						break;
43651ffecc1SBen Gras 					default:
43751ffecc1SBen Gras 						goto nondes;
43851ffecc1SBen Gras 					}
43951ffecc1SBen Gras 				}
44051ffecc1SBen Gras #endif /* HAVE_WCHAR */
44151ffecc1SBen Gras 				else
44251ffecc1SBen Gras 					goto nondes;
44351ffecc1SBen Gras 			}
44451ffecc1SBen Gras 		else
44551ffecc1SBen Gras 	nondes:	if (cursor_right)
44651ffecc1SBen Gras 			tputs(cursor_right, 0, plodput);
44751ffecc1SBen Gras 		else
44851ffecc1SBen Gras 			plodput(' ');
44951ffecc1SBen Gras 		outcol++;
45051ffecc1SBen Gras 		if (plodcnt < 0)
45151ffecc1SBen Gras 			goto out;
45251ffecc1SBen Gras 	}
45351ffecc1SBen Gras 
45451ffecc1SBen Gras out:	if (plodflg) {
45551ffecc1SBen Gras 		outcol = soutcol;
45651ffecc1SBen Gras 		outline = soutline;
45751ffecc1SBen Gras 	}
45851ffecc1SBen Gras #ifdef DEBUG
45951ffecc1SBen Gras 	__CTRACE(__CTRACE_OUTPUT, "plod: returns %d\n", plodcnt);
46051ffecc1SBen Gras #endif /* DEBUG */
46151ffecc1SBen Gras 	return (plodcnt);
46251ffecc1SBen Gras }
46351ffecc1SBen Gras /*
46451ffecc1SBen Gras  * Return the column number that results from being in column col and
46551ffecc1SBen Gras  * hitting a tab, where tabs are set every ts columns.  Work right for
46651ffecc1SBen Gras  * the case where col > COLS, even if ts does not divide COLS.
46751ffecc1SBen Gras  */
46851ffecc1SBen Gras static int
tabcol(col,ts)46951ffecc1SBen Gras tabcol(col, ts)
47051ffecc1SBen Gras 	int	 col, ts;
47151ffecc1SBen Gras {
47251ffecc1SBen Gras 	int	 offset;
47351ffecc1SBen Gras 
47451ffecc1SBen Gras 	if (col >= COLS) {
47551ffecc1SBen Gras 		offset = COLS * (col / COLS);
47651ffecc1SBen Gras 		col -= offset;
47751ffecc1SBen Gras 	} else
47851ffecc1SBen Gras 		offset = 0;
47951ffecc1SBen Gras 	return (col + ts - (col % ts) + offset);
48051ffecc1SBen Gras }
481