NetBSD/lib/libcurses/cr_put.c

441 lines
11 KiB
C
Raw Normal View History

/* $NetBSD: cr_put.c,v 1.21 2002/06/26 18:14:00 christos Exp $ */
1997-07-22 11:36:20 +04:00
1993-03-21 12:45:37 +03:00
/*
1994-08-18 01:51:41 +04:00
* Copyright (c) 1981, 1993, 1994
* The Regents of the University of California. All rights reserved.
1993-03-21 12:45:37 +03:00
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
1997-07-22 11:36:20 +04:00
#include <sys/cdefs.h>
1993-03-21 12:45:37 +03:00
#ifndef lint
1997-07-22 11:36:20 +04:00
#if 0
1994-08-18 01:51:41 +04:00
static char sccsid[] = "@(#)cr_put.c 8.3 (Berkeley) 5/4/94";
1997-07-22 11:36:20 +04:00
#else
__RCSID("$NetBSD: cr_put.c,v 1.21 2002/06/26 18:14:00 christos Exp $");
1997-07-22 11:36:20 +04:00
#endif
#endif /* not lint */
1993-03-21 12:45:37 +03:00
1993-08-07 09:48:37 +04:00
#include <string.h>
1993-03-21 12:45:37 +03:00
1994-08-18 01:51:41 +04:00
#include "curses.h"
2000-04-11 17:57:08 +04:00
#include "curses_private.h"
1994-08-18 01:51:41 +04:00
/* the following is defined and set up in setterm.c */
extern struct tinfo *_cursesi_genbuf;
1993-08-07 09:48:37 +04:00
#define HARDTABS 8
1993-03-21 12:45:37 +03:00
/*
1993-08-07 09:48:37 +04:00
* Terminal driving and line formatting routines. Basic motion optimizations
* are done here as well as formatting lines (printing of control characters,
1993-03-21 12:45:37 +03:00
* line numbering and the like).
*/
/* Stub function for the users. */
int
mvcur(int ly, int lx, int y, int x)
{
return (__mvcur(ly, lx, y, x, 0));
}
static void fgoto __P((int));
static int plod __P((int, int));
static int plodput __P((int));
static int tabcol __P((int, int));
1993-08-07 09:48:37 +04:00
static int outcol, outline, destcol, destline;
1993-03-21 12:45:37 +03:00
/*
1993-08-07 09:48:37 +04:00
* Sync the position of the output cursor. Most work here is rounding for
* terminal boundaries getting the column position implied by wraparound or
* the lack thereof and rolling up the screen to get destline on the screen.
1993-03-21 12:45:37 +03:00
*/
1993-08-07 09:48:37 +04:00
int
__mvcur(int ly, int lx, int y, int x, int in_refresh)
1993-08-07 09:48:37 +04:00
{
1993-03-21 12:45:37 +03:00
#ifdef DEBUG
__CTRACE("mvcur: moving cursor from (%d, %d) to (%d, %d)\n",
1993-08-07 09:48:37 +04:00
ly, lx, y, x);
1993-03-21 12:45:37 +03:00
#endif
destcol = x;
destline = y;
outcol = lx;
outline = ly;
fgoto(in_refresh);
1993-08-07 09:48:37 +04:00
return (OK);
}
1993-08-07 09:48:37 +04:00
static void
fgoto(in_refresh)
int in_refresh;
1993-03-21 12:45:37 +03:00
{
int c, l;
char cgp[128];
1993-03-21 12:45:37 +03:00
if (destcol >= COLS) {
destline += destcol / COLS;
destcol %= COLS;
}
if (outcol >= COLS) {
l = (outcol + 1) / COLS;
outline += l;
outcol %= COLS;
if (__tc_am == 0) {
1993-03-21 12:45:37 +03:00
while (l > 0) {
1998-08-19 04:17:41 +04:00
if (__pfast) {
if (__tc_cr)
tputs(__tc_cr, 0, __cputchar);
1993-03-21 12:45:37 +03:00
else
__cputchar('\r');
1998-08-19 04:17:41 +04:00
}
if (__tc_nl)
tputs(__tc_nl, 0, __cputchar);
1993-03-21 12:45:37 +03:00
else
__cputchar('\n');
1993-03-21 12:45:37 +03:00
l--;
}
outcol = 0;
}
if (outline > LINES - 1) {
destline -= outline - (LINES - 1);
outline = LINES - 1;
}
}
if (destline >= LINES) {
l = destline;
destline = LINES - 1;
if (outline < LINES - 1) {
c = destcol;
if (__pfast == 0 && !__CA)
1993-03-21 12:45:37 +03:00
destcol = 0;
fgoto(in_refresh);
1993-03-21 12:45:37 +03:00
destcol = c;
}
while (l >= LINES) {
1993-08-07 09:48:37 +04:00
/* The following linefeed (or simulation thereof) is
* supposed to scroll up the screen, since we are on
* the bottom line. We make the assumption that
* linefeed will scroll. If ns is in the capability
* list this won't work. We should probably have an
* sc capability but sf will generally take the place
* if it works.
*
* Superbee glitch: in the middle of the screen have to
* use esc B (down) because linefeed screws up in
1993-08-07 09:48:37 +04:00
* "Efficient Paging" (what a joke) mode (which is
* essential in some SB's because CRLF mode puts
* garbage in at end of memory), but you must use
* linefeed to scroll since down arrow won't go past
* memory end. I turned this off after recieving Paul
* Eggert's Superbee description which wins better. */
if (__tc_nl /* && !__tc_xb */ && __pfast)
tputs(__tc_nl, 0, __cputchar);
1993-03-21 12:45:37 +03:00
else
__cputchar('\n');
1993-03-21 12:45:37 +03:00
l--;
1993-08-07 09:48:37 +04:00
if (__pfast == 0)
1993-03-21 12:45:37 +03:00
outcol = 0;
}
}
if (destline < outline && !(__CA || __tc_up))
1993-03-21 12:45:37 +03:00
destline = outline;
if (__CA && t_goto(NULL, __tc_cm, destcol, destline, cgp,
sizeof(cgp) - 1) != -1) {
/*
* Need this condition due to inconsistent behavior
* of backspace on the last column.
*/
if (outcol != COLS - 1 &&
plod((int) strlen(cgp), in_refresh) > 0)
plod(0, in_refresh);
else
1993-08-07 09:48:37 +04:00
tputs(cgp, 0, __cputchar);
} else
plod(0, in_refresh);
1993-03-21 12:45:37 +03:00
outline = destline;
outcol = destcol;
}
/*
* Move (slowly) to destination.
* Hard thing here is using home cursor on really deficient terminals.
* Otherwise just use cursor motions, hacking use of tabs and overtabbing
* and backspace.
*/
static int plodcnt, plodflg;
static int
1993-03-21 12:45:37 +03:00
plodput(c)
int c;
1993-03-21 12:45:37 +03:00
{
if (plodflg)
1993-08-07 09:48:37 +04:00
--plodcnt;
1993-03-21 12:45:37 +03:00
else
__cputchar(c);
return (0);
1993-03-21 12:45:37 +03:00
}
1993-08-07 09:48:37 +04:00
static int
plod(cnt, in_refresh)
int cnt, in_refresh;
1993-03-21 12:45:37 +03:00
{
int i, j, k, soutcol, soutline;
1993-03-21 12:45:37 +03:00
plodcnt = plodflg = cnt;
soutcol = outcol;
soutline = outline;
/*
1993-08-07 09:48:37 +04:00
* Consider homing and moving down/right from there, vs. moving
1993-03-21 12:45:37 +03:00
* directly with local motions to the right spot.
*/
if (__tc_ho) {
1993-03-21 12:45:37 +03:00
/*
1993-08-07 09:48:37 +04:00
* i is the cost to home and tab/space to the right to get to
* the proper column. This assumes nd space costs 1 char. So
1993-08-07 09:48:37 +04:00
* i + destcol is cost of motion with home.
1993-03-21 12:45:37 +03:00
*/
if (__GT)
1993-03-21 12:45:37 +03:00
i = (destcol / HARDTABS) + (destcol % HARDTABS);
else
i = destcol;
1993-08-07 09:48:37 +04:00
/* j is cost to move locally without homing. */
1993-03-21 12:45:37 +03:00
if (destcol >= outcol) { /* if motion is to the right */
j = destcol / HARDTABS - outcol / HARDTABS;
if (__GT && j)
1993-03-21 12:45:37 +03:00
j += destcol % HARDTABS;
else
j = destcol - outcol;
1993-08-07 09:48:37 +04:00
} else
1993-03-21 12:45:37 +03:00
/* leftward motion only works if we can backspace. */
if (outcol - destcol <= i && (__tc_bs || __tc_bc))
1993-08-07 09:48:37 +04:00
/* Cheaper to backspace. */
i = j = outcol - destcol;
1993-03-21 12:45:37 +03:00
else
1993-08-07 09:48:37 +04:00
/* Impossibly expensive. */
j = i + 1;
1993-03-21 12:45:37 +03:00
1993-08-07 09:48:37 +04:00
/* k is the absolute value of vertical distance. */
1993-03-21 12:45:37 +03:00
k = outline - destline;
if (k < 0)
k = -k;
j += k;
/* Decision. We may not have a choice if no up. */
if (i + destline < j || (!__tc_up && destline < outline)) {
1993-03-21 12:45:37 +03:00
/*
* Cheaper to home. Do it now and pretend it's a
* regular local motion.
*/
tputs(__tc_ho, 0, plodput);
1993-03-21 12:45:37 +03:00
outcol = outline = 0;
} else
if (__tc_ll) {
/*
* Quickly consider homing down and moving from
* there. Assume cost of ll is 2.
*/
k = (LINES - 1) - destline;
if (i + k + 2 < j && (k <= 0 || __tc_up)) {
tputs(__tc_ll, 0, plodput);
outcol = 0;
outline = LINES - 1;
}
1993-03-21 12:45:37 +03:00
}
1993-08-07 09:48:37 +04:00
} else
/* No home and no up means it's impossible. */
if (!__tc_up && destline < outline)
1993-08-07 09:48:37 +04:00
return (-1);
if (__GT)
1993-03-21 12:45:37 +03:00
i = destcol % HARDTABS + destcol / HARDTABS;
else
i = destcol;
1993-08-07 09:48:37 +04:00
#ifdef notdef
if (__tc_bt && outcol > destcol &&
(j = (((outcol + 7) & ~7) - destcol - 1) >> 3)) {
j *= (k = strlen(__tc_bt));
if ((k += (destcol & 7)) > 4)
j += 8 - (destcol & 7);
1993-03-21 12:45:37 +03:00
else
j += k;
} else
1993-08-07 09:48:37 +04:00
#endif
1993-03-21 12:45:37 +03:00
j = outcol - destcol;
1993-08-07 09:48:37 +04:00
1993-03-21 12:45:37 +03:00
/*
1993-08-07 09:48:37 +04:00
* If we will later need a \n which will turn into a \r\n by the
* system or the terminal, then don't bother to try to \r.
1993-03-21 12:45:37 +03:00
*/
if ((__NONL || !__pfast) && outline < destline)
1993-03-21 12:45:37 +03:00
goto dontcr;
1993-08-07 09:48:37 +04:00
1993-03-21 12:45:37 +03:00
/*
1993-08-07 09:48:37 +04:00
* If the terminal will do a \r\n and there isn't room for it, then
* we can't afford a \r.
1993-03-21 12:45:37 +03:00
*/
if (__tc_nc && outline >= destline)
1993-03-21 12:45:37 +03:00
goto dontcr;
1993-08-07 09:48:37 +04:00
1993-03-21 12:45:37 +03:00
/*
1993-08-07 09:48:37 +04:00
* If it will be cheaper, or if we can't back up, then send a return
* preliminarily.
1993-03-21 12:45:37 +03:00
*/
if (j > i + 1 || (outcol > destcol && !__tc_bs && !__tc_bc)) {
1993-03-21 12:45:37 +03:00
/*
* BUG: this doesn't take the (possibly long) length of cr
1993-08-07 09:48:37 +04:00
* into account.
1993-03-21 12:45:37 +03:00
*/
if (__tc_cr)
tputs(__tc_cr, 0, plodput);
1993-03-21 12:45:37 +03:00
else
plodput('\r');
if (__tc_nc) {
if (__tc_nl)
tputs(__tc_nl, 0, plodput);
1993-03-21 12:45:37 +03:00
else
plodput('\n');
outline++;
}
outcol = 0;
}
dontcr:while (outline < destline) {
1993-03-21 12:45:37 +03:00
outline++;
if (__tc_nl)
tputs(__tc_nl, 0, plodput);
1993-03-21 12:45:37 +03:00
else
plodput('\n');
if (plodcnt < 0)
goto out;
if (__NONL || __pfast == 0)
1993-03-21 12:45:37 +03:00
outcol = 0;
}
if (__tc_bt)
k = (int) strlen(__tc_bt);
1993-03-21 12:45:37 +03:00
while (outcol > destcol) {
if (plodcnt < 0)
goto out;
1993-08-07 09:48:37 +04:00
#ifdef notdef
if (__tc_bt && outcol - destcol > k + 4) {
tputs(__tc_bt, 0, plodput);
1993-03-21 12:45:37 +03:00
outcol--;
outcol &= ~7;
continue;
}
1993-08-07 09:48:37 +04:00
#endif
1993-03-21 12:45:37 +03:00
outcol--;
if (__tc_bc)
tputs(__tc_bc, 0, plodput);
1993-03-21 12:45:37 +03:00
else
plodput('\b');
}
while (outline > destline) {
outline--;
tputs(__tc_up, 0, plodput);
1993-03-21 12:45:37 +03:00
if (plodcnt < 0)
goto out;
}
if (__GT && destcol - outcol > 1) {
1993-03-21 12:45:37 +03:00
for (;;) {
i = tabcol(outcol, HARDTABS);
if (i > destcol)
break;
if (__tc_ta)
tputs(__tc_ta, 0, plodput);
1993-03-21 12:45:37 +03:00
else
plodput('\t');
outcol = i;
}
if (destcol - outcol > 4 && i < COLS && (__tc_bc || __tc_bs)) {
if (__tc_ta)
tputs(__tc_ta, 0, plodput);
1993-03-21 12:45:37 +03:00
else
plodput('\t');
outcol = i;
while (outcol > destcol) {
outcol--;
if (__tc_bc)
tputs(__tc_bc, 0, plodput);
1993-03-21 12:45:37 +03:00
else
plodput('\b');
}
}
}
while (outcol < destcol) {
/*
* Move one char to the right. We don't use nd space because
1993-08-07 09:48:37 +04:00
* it's better to just print the char we are moving over.
1993-03-21 12:45:37 +03:00
*/
if (in_refresh)
1993-08-07 09:48:37 +04:00
if (plodflg) /* Avoid a complex calculation. */
1993-03-21 12:45:37 +03:00
plodcnt--;
else {
2000-04-11 17:57:08 +04:00
i = curscr->lines[outline]->line[outcol].ch
& __CHARTEXT;
if (curscr->lines[outline]->line[outcol].attr
== curscr->wattr)
__cputchar(i);
1993-03-21 12:45:37 +03:00
else
goto nondes;
}
else
nondes: if (__tc_nd)
tputs(__tc_nd, 0, plodput);
1993-08-07 09:48:37 +04:00
else
plodput(' ');
1993-03-21 12:45:37 +03:00
outcol++;
if (plodcnt < 0)
goto out;
}
1993-08-07 09:48:37 +04:00
out: if (plodflg) {
1993-03-21 12:45:37 +03:00
outcol = soutcol;
outline = soutline;
}
1993-08-07 09:48:37 +04:00
return (plodcnt);
1993-03-21 12:45:37 +03:00
}
/*
* Return the column number that results from being in column col and
* hitting a tab, where tabs are set every ts columns. Work right for
* the case where col > COLS, even if ts does not divide COLS.
*/
1993-08-07 09:48:37 +04:00
static int
1993-03-21 12:45:37 +03:00
tabcol(col, ts)
int col, ts;
1993-03-21 12:45:37 +03:00
{
int offset;
1993-03-21 12:45:37 +03:00
if (col >= COLS) {
offset = COLS * (col / COLS);
col -= offset;
1993-08-07 09:48:37 +04:00
} else
1993-03-21 12:45:37 +03:00
offset = 0;
1993-08-07 09:48:37 +04:00
return (col + ts - (col % ts) + offset);
1993-03-21 12:45:37 +03:00
}