1 /* $NetBSD: cr_put.c,v 1.27 2008/07/23 13:32:41 tnozaki 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.27 2008/07/23 13:32:41 tnozaki 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
;
110 tputs(__tc_cr
, 0, __cputchar
);
115 tputs(__tc_nl
, 0, __cputchar
);
122 if (outline
> LINES
- 1) {
123 destline
-= outline
- (LINES
- 1);
127 if (destline
>= LINES
) {
129 destline
= LINES
- 1;
130 if (outline
< LINES
- 1) {
132 if (__pfast
== 0 && !__CA
)
138 /* The following linefeed (or simulation thereof) is
139 * supposed to scroll up the screen, since we are on
140 * the bottom line. We make the assumption that
141 * linefeed will scroll. If ns is in the capability
142 * list this won't work. We should probably have an
143 * sc capability but sf will generally take the place
146 * Superbee glitch: in the middle of the screen have to
147 * use esc B (down) because linefeed screws up in
148 * "Efficient Paging" (what a joke) mode (which is
149 * essential in some SB's because CRLF mode puts
150 * garbage in at end of memory), but you must use
151 * linefeed to scroll since down arrow won't go past
152 * memory end. I turned this off after recieving Paul
153 * Eggert's Superbee description which wins better. */
154 if (__tc_nl
/* && !__tc_xb */ && __pfast
)
155 tputs(__tc_nl
, 0, __cputchar
);
163 if (destline
< outline
&& !(__CA
|| __tc_up
))
165 if (__CA
&& t_goto(NULL
, __tc_cm
, destcol
, destline
, cgp
,
166 sizeof(cgp
) - 1) != -1) {
168 * Need this condition due to inconsistent behavior
169 * of backspace on the last column.
172 __CTRACE(__CTRACE_OUTPUT
, "fgoto: cgp=%s\n", cgp
);
174 if (outcol
!= COLS
- 1 &&
175 plod((int) strlen(cgp
), in_refresh
) > 0)
178 tputs(cgp
, 0, __cputchar
);
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
190 * XXX this needs to be revisited for wide characters since we may output
191 * XXX more than one byte for a character.
194 static int plodcnt
, plodflg
;
208 plod(cnt
, in_refresh
)
211 int i
, j
, k
, soutcol
, soutline
;
214 __CTRACE(__CTRACE_OUTPUT
, "plod: cnt=%d, in_refresh=%d\n",
217 plodcnt
= plodflg
= cnt
;
221 * Consider homing and moving down/right from there, vs. moving
222 * directly with local motions to the right spot.
226 * i is the cost to home and tab/space to the right to get to
227 * the proper column. This assumes nd space costs 1 char. So
228 * i + destcol is cost of motion with home.
231 i
= (destcol
/ HARDTABS
) + (destcol
% HARDTABS
);
235 /* j is cost to move locally without homing. */
236 if (destcol
>= outcol
) { /* if motion is to the right */
237 j
= destcol
/ HARDTABS
- outcol
/ HARDTABS
;
239 j
+= destcol
% HARDTABS
;
241 j
= destcol
- outcol
;
243 /* leftward motion only works if we can backspace. */
244 if (outcol
- destcol
<= i
&& (__tc_bs
|| __tc_bc
))
245 /* Cheaper to backspace. */
246 i
= j
= outcol
- destcol
;
248 /* Impossibly expensive. */
251 /* k is the absolute value of vertical distance. */
252 k
= outline
- destline
;
257 /* Decision. We may not have a choice if no up. */
258 if (i
+ destline
< j
|| (!__tc_up
&& destline
< outline
)) {
260 * Cheaper to home. Do it now and pretend it's a
261 * regular local motion.
263 tputs(__tc_ho
, 0, plodput
);
264 outcol
= outline
= 0;
268 * Quickly consider homing down and moving from
269 * there. Assume cost of ll is 2.
271 k
= (LINES
- 1) - destline
;
272 if (i
+ k
+ 2 < j
&& (k
<= 0 || __tc_up
)) {
273 tputs(__tc_ll
, 0, plodput
);
279 /* No home and no up means it's impossible. */
280 if (!__tc_up
&& destline
< outline
)
283 i
= destcol
% HARDTABS
+ destcol
/ HARDTABS
;
287 if (__tc_bt
&& outcol
> destcol
&&
288 (j
= (((outcol
+ 7) & ~7) - destcol
- 1) >> 3)) {
289 j
*= (k
= strlen(__tc_bt
));
290 if ((k
+= (destcol
& 7)) > 4)
291 j
+= 8 - (destcol
& 7);
296 j
= outcol
- destcol
;
299 * If we will later need a \n which will turn into a \r\n by the
300 * system or the terminal, then don't bother to try to \r.
302 if ((__NONL
|| !__pfast
) && outline
< destline
)
306 * If the terminal will do a \r\n and there isn't room for it, then
307 * we can't afford a \r.
309 if (__tc_nc
&& outline
>= destline
)
313 * If it will be cheaper, or if we can't back up, then send a return
316 if (j
> i
+ 1 || (outcol
> destcol
&& !__tc_bs
&& !__tc_bc
)) {
318 * BUG: this doesn't take the (possibly long) length of cr
322 tputs(__tc_cr
, 0, plodput
);
327 tputs(__tc_nl
, 0, plodput
);
334 dontcr
:while (outline
< destline
) {
337 tputs(__tc_nl
, 0, plodput
);
342 if (__NONL
|| __pfast
== 0)
346 k
= (int) strlen(__tc_bt
);
347 while (outcol
> destcol
) {
351 if (__tc_bt
&& outcol
- destcol
> k
+ 4) {
352 tputs(__tc_bt
, 0, plodput
);
360 tputs(__tc_bc
, 0, plodput
);
364 while (outline
> destline
) {
366 tputs(__tc_up
, 0, plodput
);
370 if (__GT
&& destcol
- outcol
> 1) {
372 i
= tabcol(outcol
, HARDTABS
);
376 tputs(__tc_ta
, 0, plodput
);
381 if (destcol
- outcol
> 4 && i
< COLS
&& (__tc_bc
|| __tc_bs
)) {
383 tputs(__tc_ta
, 0, plodput
);
387 while (outcol
> destcol
) {
390 tputs(__tc_bc
, 0, plodput
);
396 while (outcol
< destcol
) {
398 * Move one char to the right. We don't use nd space because
399 * it's better to just print the char we are moving over.
402 if (plodflg
) /* Avoid a complex calculation. */
406 i
= curscr
->alines
[outline
]->line
[outcol
].ch
408 if (curscr
->alines
[outline
]->line
[outcol
].attr
412 if ((curscr
->alines
[outline
]->line
[outcol
].attr
415 switch (WCOL(curscr
->alines
[outline
]->line
[outcol
])) {
417 __cputwchar(curscr
->alines
[outline
]->line
[outcol
].ch
);
418 __cursesi_putnsp(curscr
->alines
[outline
]->line
[outcol
].nsp
,
422 __CTRACE(__CTRACE_OUTPUT
,
423 "plod: (%d,%d)WCOL(%d), "
426 WCOL(curscr
->alines
[outline
]->line
[outcol
]),
427 curscr
->alines
[outline
]->line
[outcol
].ch
);
436 #endif /* HAVE_WCHAR */
442 tputs(__tc_nd
, 0, plodput
);
455 __CTRACE(__CTRACE_OUTPUT
, "plod: returns %d\n", plodcnt
);
460 * Return the column number that results from being in column col and
461 * hitting a tab, where tabs are set every ts columns. Work right for
462 * the case where col > COLS, even if ts does not divide COLS.
471 offset
= COLS
* (col
/ COLS
);
475 return (col
+ ts
- (col
% ts
) + offset
);