cr_put.c revision 1.13 1 /* $NetBSD: cr_put.c,v 1.13 1999/06/28 13:32:43 simonb 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.13 1999/06/28 13:32:43 simonb Exp $");
42 #endif
43 #endif /* not lint */
44
45 #include <string.h>
46
47 #include "curses.h"
48
49 #define HARDTABS 8
50
51 /*
52 * Terminal driving and line formatting routines. Basic motion optimizations
53 * are done here as well as formatting lines (printing of control characters,
54 * line numbering and the like).
55 */
56
57 /* Stub function for the users. */
58 int
59 mvcur(ly, lx, y, x)
60 int ly, lx, y, x;
61 {
62 return (__mvcur(ly, lx, y, x, 0));
63 }
64
65 static void fgoto __P((int));
66 static int plod __P((int, int));
67 static void plodput __P((int));
68 static int tabcol __P((int, int));
69
70 static int outcol, outline, destcol, destline;
71
72 /*
73 * Sync the position of the output cursor. Most work here is rounding for
74 * terminal boundaries getting the column position implied by wraparound or
75 * the lack thereof and rolling up the screen to get destline on the screen.
76 */
77 int
78 __mvcur(ly, lx, y, x, in_refresh)
79 int ly, lx, y, x, in_refresh;
80 {
81 #ifdef DEBUG
82 __CTRACE("mvcur: moving cursor from (%d, %d) to (%d, %d)\n",
83 ly, lx, y, x);
84 #endif
85 destcol = x;
86 destline = y;
87 outcol = lx;
88 outline = ly;
89 fgoto(in_refresh);
90 return (OK);
91 }
92
93 static void
94 fgoto(in_refresh)
95 int in_refresh;
96 {
97 int c, l;
98 char *cgp;
99
100 if (destcol >= COLS) {
101 destline += destcol / COLS;
102 destcol %= COLS;
103 }
104 if (outcol >= COLS) {
105 l = (outcol + 1) / COLS;
106 outline += l;
107 outcol %= COLS;
108 if (AM == 0) {
109 while (l > 0) {
110 if (__pfast) {
111 if (CR)
112 tputs(CR, 0, __cputchar);
113 else
114 putchar('\r');
115 }
116 if (NL)
117 tputs(NL, 0, __cputchar);
118 else
119 putchar('\n');
120 l--;
121 }
122 outcol = 0;
123 }
124 if (outline > LINES - 1) {
125 destline -= outline - (LINES - 1);
126 outline = LINES - 1;
127 }
128 }
129 if (destline >= LINES) {
130 l = destline;
131 destline = LINES - 1;
132 if (outline < LINES - 1) {
133 c = destcol;
134 if (__pfast == 0 && !CA)
135 destcol = 0;
136 fgoto(in_refresh);
137 destcol = c;
138 }
139 while (l >= LINES) {
140 /* The following linefeed (or simulation thereof) is
141 * supposed to scroll up the screen, since we are on
142 * the bottom line. We make the assumption that
143 * linefeed will scroll. If ns is in the capability
144 * list this won't work. We should probably have an
145 * sc capability but sf will generally take the place
146 * if it works.
147 *
148 * Superbee glitch: in the middle of the screen have to
149 * use esc B (down) because linefeed screws up in
150 * "Efficient Paging" (what a joke) mode (which is
151 * essential in some SB's because CRLF mode puts
152 * garbage in at end of memory), but you must use
153 * linefeed to scroll since down arrow won't go past
154 * memory end. I turned this off after recieving Paul
155 * Eggert's Superbee description which wins better. */
156 if (NL /* && !XB */ && __pfast)
157 tputs(NL, 0, __cputchar);
158 else
159 putchar('\n');
160 l--;
161 if (__pfast == 0)
162 outcol = 0;
163 }
164 }
165 if (destline < outline && !(CA || UP))
166 destline = outline;
167 if (CA) {
168 cgp = tgoto(CM, destcol, destline);
169
170 /*
171 * Need this condition due to inconsistent behavior
172 * of backspace on the last column.
173 */
174 if (outcol != COLS - 1 && plod((int) strlen(cgp), in_refresh) > 0)
175 plod(0, in_refresh);
176 else
177 tputs(cgp, 0, __cputchar);
178 } else
179 plod(0, in_refresh);
180 outline = destline;
181 outcol = destcol;
182 }
183 /*
184 * Move (slowly) to destination.
185 * Hard thing here is using home cursor on really deficient terminals.
186 * Otherwise just use cursor motions, hacking use of tabs and overtabbing
187 * and backspace.
188 */
189
190 static int plodcnt, plodflg;
191
192 static void
193 plodput(c)
194 int c;
195 {
196 if (plodflg)
197 --plodcnt;
198 else
199 putchar(c);
200 }
201
202 static int
203 plod(cnt, in_refresh)
204 int cnt, in_refresh;
205 {
206 int i, j, k, soutcol, soutline;
207
208 plodcnt = plodflg = cnt;
209 soutcol = outcol;
210 soutline = outline;
211 /*
212 * Consider homing and moving down/right from there, vs. moving
213 * directly with local motions to the right spot.
214 */
215 if (HO) {
216 /*
217 * i is the cost to home and tab/space to the right to get to
218 * the proper column. This assumes ND space costs 1 char. So
219 * i + destcol is cost of motion with home.
220 */
221 if (GT)
222 i = (destcol / HARDTABS) + (destcol % HARDTABS);
223 else
224 i = destcol;
225
226 /* j is cost to move locally without homing. */
227 if (destcol >= outcol) { /* if motion is to the right */
228 j = destcol / HARDTABS - outcol / HARDTABS;
229 if (GT && j)
230 j += destcol % HARDTABS;
231 else
232 j = destcol - outcol;
233 } else
234 /* leftward motion only works if we can backspace. */
235 if (outcol - destcol <= i && (BS || BC))
236 /* Cheaper to backspace. */
237 i = j = outcol - destcol;
238 else
239 /* Impossibly expensive. */
240 j = i + 1;
241
242 /* k is the absolute value of vertical distance. */
243 k = outline - destline;
244 if (k < 0)
245 k = -k;
246 j += k;
247
248 /* Decision. We may not have a choice if no UP. */
249 if (i + destline < j || (!UP && destline < outline)) {
250 /*
251 * Cheaper to home. Do it now and pretend it's a
252 * regular local motion.
253 */
254 tputs(HO, 0, plodput);
255 outcol = outline = 0;
256 } else
257 if (LL) {
258 /*
259 * Quickly consider homing down and moving from there.
260 * Assume cost of LL is 2.
261 */
262 k = (LINES - 1) - destline;
263 if (i + k + 2 < j && (k <= 0 || UP)) {
264 tputs(LL, 0, plodput);
265 outcol = 0;
266 outline = LINES - 1;
267 }
268 }
269 } else
270 /* No home and no up means it's impossible. */
271 if (!UP && destline < outline)
272 return (-1);
273 if (GT)
274 i = destcol % HARDTABS + destcol / HARDTABS;
275 else
276 i = destcol;
277 #ifdef notdef
278 if (BT && outcol > destcol &&
279 (j = (((outcol + 7) & ~7) - destcol - 1) >> 3)) {
280 j *= (k = strlen(BT));
281 if ((k += (destcol & 7)) > 4)
282 j += 8 - (destcol & 7);
283 else
284 j += k;
285 } else
286 #endif
287 j = outcol - destcol;
288
289 /*
290 * If we will later need a \n which will turn into a \r\n by the
291 * system or the terminal, then don't bother to try to \r.
292 */
293 if ((NONL || !__pfast) && outline < destline)
294 goto dontcr;
295
296 /*
297 * If the terminal will do a \r\n and there isn't room for it, then
298 * we can't afford a \r.
299 */
300 if (NC && outline >= destline)
301 goto dontcr;
302
303 /*
304 * If it will be cheaper, or if we can't back up, then send a return
305 * preliminarily.
306 */
307 if (j > i + 1 || (outcol > destcol && !BS && !BC)) {
308 /*
309 * BUG: this doesn't take the (possibly long) length of CR
310 * into account.
311 */
312 if (CR)
313 tputs(CR, 0, plodput);
314 else
315 plodput('\r');
316 if (NC) {
317 if (NL)
318 tputs(NL, 0, plodput);
319 else
320 plodput('\n');
321 outline++;
322 }
323 outcol = 0;
324 }
325 dontcr:while (outline < destline) {
326 outline++;
327 if (NL)
328 tputs(NL, 0, plodput);
329 else
330 plodput('\n');
331 if (plodcnt < 0)
332 goto out;
333 if (NONL || __pfast == 0)
334 outcol = 0;
335 }
336 if (BT)
337 k = strlen(BT);
338 while (outcol > destcol) {
339 if (plodcnt < 0)
340 goto out;
341 #ifdef notdef
342 if (BT && outcol - destcol > k + 4) {
343 tputs(BT, 0, plodput);
344 outcol--;
345 outcol &= ~7;
346 continue;
347 }
348 #endif
349 outcol--;
350 if (BC)
351 tputs(BC, 0, plodput);
352 else
353 plodput('\b');
354 }
355 while (outline > destline) {
356 outline--;
357 tputs(UP, 0, plodput);
358 if (plodcnt < 0)
359 goto out;
360 }
361 if (GT && destcol - outcol > 1) {
362 for (;;) {
363 i = tabcol(outcol, HARDTABS);
364 if (i > destcol)
365 break;
366 if (TA)
367 tputs(TA, 0, plodput);
368 else
369 plodput('\t');
370 outcol = i;
371 }
372 if (destcol - outcol > 4 && i < COLS && (BC || BS)) {
373 if (TA)
374 tputs(TA, 0, plodput);
375 else
376 plodput('\t');
377 outcol = i;
378 while (outcol > destcol) {
379 outcol--;
380 if (BC)
381 tputs(BC, 0, plodput);
382 else
383 plodput('\b');
384 }
385 }
386 }
387 while (outcol < destcol) {
388 /*
389 * Move one char to the right. We don't use ND space because
390 * it's better to just print the char we are moving over.
391 */
392 if (in_refresh)
393 if (plodflg) /* Avoid a complex calculation. */
394 plodcnt--;
395 else {
396 i = curscr->lines[outline]->line[outcol].ch;
397 if ((curscr->lines[outline]->line[outcol].attr
398 & __STANDOUT) ==
399 (curscr->flags & __WSTANDOUT))
400 putchar(i);
401 else
402 goto nondes;
403 }
404 else
405 nondes: if (ND)
406 tputs(ND, 0, plodput);
407 else
408 plodput(' ');
409 outcol++;
410 if (plodcnt < 0)
411 goto out;
412 }
413
414 out: if (plodflg) {
415 outcol = soutcol;
416 outline = soutline;
417 }
418 return (plodcnt);
419 }
420 /*
421 * Return the column number that results from being in column col and
422 * hitting a tab, where tabs are set every ts columns. Work right for
423 * the case where col > COLS, even if ts does not divide COLS.
424 */
425 static int
426 tabcol(col, ts)
427 int col, ts;
428 {
429 int offset;
430
431 if (col >= COLS) {
432 offset = COLS * (col / COLS);
433 col -= offset;
434 } else
435 offset = 0;
436 return (col + ts - (col % ts) + offset);
437 }
438