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