1 /* $NetBSD: cr_put.c,v 1.30 2010/02/12 10:06:15 roy Exp $ */
4 * Copyright (c) 1981, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
35 static char sccsid
[] = "@(#)cr_put.c 8.3 (Berkeley) 5/4/94";
37 __RCSID("$NetBSD: cr_put.c,v 1.30 2010/02/12 10:06:15 roy Exp $");
44 #include "curses_private.h"
49 * Terminal driving and line formatting routines. Basic motion optimizations
50 * are done here as well as formatting lines (printing of control characters,
51 * line numbering and the like).
54 /* Stub function for the users. */
56 mvcur(int ly
, int lx
, int y
, int x
)
58 return (__mvcur(ly
, lx
, y
, x
, 0));
61 static void fgoto
__P((int));
62 static int plod
__P((int, int));
63 static int plodput
__P((int));
64 static int tabcol
__P((int, int));
66 static int outcol
, outline
, destcol
, destline
;
69 * Sync the position of the output cursor. Most work here is rounding for
70 * terminal boundaries getting the column position implied by wraparound or
71 * the lack thereof and rolling up the screen to get destline on the screen.
74 __mvcur(int ly
, int lx
, int y
, int x
, int in_refresh
)
77 __CTRACE(__CTRACE_OUTPUT
,
78 "mvcur: moving cursor from (%d, %d) to (%d, %d)\n", ly
, lx
, y
, x
);
96 __CTRACE(__CTRACE_OUTPUT
, "fgoto: in_refresh=%d\n", in_refresh
);
98 if (destcol
>= COLS
) {
99 destline
+= destcol
/ COLS
;
102 if (outcol
>= COLS
) {
103 l
= (outcol
+ 1) / COLS
;
106 if (auto_left_margin
== 0) {
110 tputs(carriage_return
,
116 tputs(cursor_down
, 0, __cputchar
);
123 if (outline
> LINES
- 1) {
124 destline
-= outline
- (LINES
- 1);
128 if (destline
>= LINES
) {
130 destline
= LINES
- 1;
131 if (outline
< LINES
- 1) {
133 if (__pfast
== 0 && !cursor_address
)
139 /* The following linefeed (or simulation thereof) is
140 * supposed to scroll up the screen, since we are on
141 * the bottom line. We make the assumption that
142 * linefeed will scroll. If ns is in the capability
143 * list this won't work. We should probably have an
144 * sc capability but sf will generally take the place
147 * Superbee glitch: in the middle of the screen have to
148 * use esc B (down) because linefeed screws up in
149 * "Efficient Paging" (what a joke) mode (which is
150 * essential in some SB's because CRLF mode puts
151 * garbage in at end of memory), but you must use
152 * linefeed to scroll since down arrow won't go past
153 * memory end. I turned this off after recieving Paul
154 * Eggert's Superbee description which wins better. */
155 if (cursor_down
/* && !__tc_xb */ && __pfast
)
156 tputs(cursor_down
, 0, __cputchar
);
164 if (destline
< outline
&& !(cursor_address
|| cursor_up
))
167 if (cursor_address
&&
168 (cgp
= t_vparm(NULL
, cursor_address
, destline
, destcol
)))
171 * Need this condition due to inconsistent behavior
172 * of backspace on the last column.
175 __CTRACE(__CTRACE_OUTPUT
, "fgoto: cgp=%s\n", cgp
);
177 if (outcol
!= COLS
- 1 &&
178 plod((int) strlen(cgp
), in_refresh
) > 0)
181 tputs(cgp
, 0, __cputchar
);
188 * Move (slowly) to destination.
189 * Hard thing here is using home cursor on really deficient terminals.
190 * Otherwise just use cursor motions, hacking use of tabs and overtabbing
193 * XXX this needs to be revisited for wide characters since we may output
194 * XXX more than one byte for a character.
197 static int plodcnt
, plodflg
;
211 plod(cnt
, in_refresh
)
214 int i
, j
, k
, soutcol
, soutline
;
217 __CTRACE(__CTRACE_OUTPUT
, "plod: cnt=%d, in_refresh=%d\n",
220 plodcnt
= plodflg
= cnt
;
225 * Consider homing and moving down/right from there, vs. moving
226 * directly with local motions to the right spot.
230 * i is the cost to home and tab/space to the right to get to
231 * the proper column. This assumes nd space costs 1 char. So
232 * i + destcol is cost of motion with home.
235 i
= (destcol
/ HARDTABS
) + (destcol
% HARDTABS
);
239 /* j is cost to move locally without homing. */
240 if (destcol
>= outcol
) { /* if motion is to the right */
241 j
= destcol
/ HARDTABS
- outcol
/ HARDTABS
;
243 j
+= destcol
% HARDTABS
;
245 j
= destcol
- outcol
;
247 /* leftward motion only works if we can backspace. */
248 if (outcol
- destcol
<= i
)
249 /* Cheaper to backspace. */
250 i
= j
= outcol
- destcol
;
252 /* Impossibly expensive. */
255 /* k is the absolute value of vertical distance. */
256 k
= outline
- destline
;
261 /* Decision. We may not have a choice if no up. */
262 if (i
+ destline
< j
|| (!cursor_up
&& destline
< outline
)) {
264 * Cheaper to home. Do it now and pretend it's a
265 * regular local motion.
267 tputs(cursor_home
, 0, plodput
);
268 outcol
= outline
= 0;
272 * Quickly consider homing down and moving from
273 * there. Assume cost of ll is 2.
275 k
= (LINES
- 1) - destline
;
276 if (i
+ k
+ 2 < j
&& (k
<= 0 || cursor_up
)) {
277 tputs(cursor_to_ll
, 0, plodput
);
283 /* No home and no up means it's impossible. */
284 if (!cursor_up
&& destline
< outline
)
287 i
= destcol
% HARDTABS
+ destcol
/ HARDTABS
;
291 if (back_tab
&& outcol
> destcol
&&
292 (j
= (((outcol
+ 7) & ~7) - destcol
- 1) >> 3)) {
293 j
*= (k
= strlen(back_tab
));
294 if ((k
+= (destcol
& 7)) > 4)
295 j
+= 8 - (destcol
& 7);
300 j
= outcol
- destcol
;
303 * If we will later need a \n which will turn into a \r\n by the
304 * system or the terminal, then don't bother to try to \r.
306 if ((__NONL
|| !__pfast
) && outline
< destline
)
310 * If the terminal will do a \r\n and there isn't room for it, then
311 * we can't afford a \r.
313 if (!carriage_return
&& outline
>= destline
)
317 * If it will be cheaper, or if we can't back up, then send a return
320 if (j
> i
+ 1 || outcol
> destcol
) {
322 * BUG: this doesn't take the (possibly long) length of cr
326 tputs(carriage_return
, 0, plodput
);
329 if (!carriage_return
) {
331 tputs(cursor_down
, 0, plodput
);
338 dontcr
:while (outline
< destline
) {
341 tputs(cursor_down
, 0, plodput
);
346 if (__NONL
|| __pfast
== 0)
350 k
= (int) strlen(back_tab
);
351 while (outcol
> destcol
) {
355 if (back_tab
&& outcol
- destcol
> k
+ 4) {
356 tputs(back_tab
, 0, plodput
);
364 tputs(cursor_left
, 0, plodput
);
368 while (outline
> destline
) {
370 tputs(cursor_up
, 0, plodput
);
374 if (__GT
&& destcol
- outcol
> 1) {
376 i
= tabcol(outcol
, HARDTABS
);
380 tputs(tab
, 0, plodput
);
385 if (destcol
- outcol
> 4 && i
< COLS
) {
387 tputs(tab
, 0, plodput
);
391 while (outcol
> destcol
) {
394 tputs(cursor_left
, 0, plodput
);
400 while (outcol
< destcol
) {
402 * Move one char to the right. We don't use nd space because
403 * it's better to just print the char we are moving over.
406 if (plodflg
) /* Avoid a complex calculation. */
410 i
= curscr
->alines
[outline
]->line
[outcol
].ch
412 if (curscr
->alines
[outline
]->line
[outcol
].attr
416 if ((curscr
->alines
[outline
]->line
[outcol
].attr
419 switch (WCOL(curscr
->alines
[outline
]->line
[outcol
])) {
421 __cputwchar(curscr
->alines
[outline
]->line
[outcol
].ch
);
422 __cursesi_putnsp(curscr
->alines
[outline
]->line
[outcol
].nsp
,
426 __CTRACE(__CTRACE_OUTPUT
,
427 "plod: (%d,%d)WCOL(%d), "
430 WCOL(curscr
->alines
[outline
]->line
[outcol
]),
431 curscr
->alines
[outline
]->line
[outcol
].ch
);
440 #endif /* HAVE_WCHAR */
445 nondes
: if (cursor_right
)
446 tputs(cursor_right
, 0, plodput
);
459 __CTRACE(__CTRACE_OUTPUT
, "plod: returns %d\n", plodcnt
);
464 * Return the column number that results from being in column col and
465 * hitting a tab, where tabs are set every ts columns. Work right for
466 * the case where col > COLS, even if ts does not divide COLS.
475 offset
= COLS
* (col
/ COLS
);
479 return (col
+ ts
- (col
% ts
) + offset
);