This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / lib / libcurses / cr_put.c
CommitLineData
15637ed4 1/*
b80b8de3
AC
2 * Copyright (c) 1981, 1993
3 * The Regents of the University of California. All rights reserved.
15637ed4
RG
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
b80b8de3
AC
35static char sccsid[] = "@(#)cr_put.c 8.2 (Berkeley) 1/9/94";
36#endif /* not lint */
15637ed4 37
b80b8de3
AC
38#include <curses.h>
39#include <string.h>
15637ed4 40
b80b8de3 41#define HARDTABS 8
15637ed4
RG
42
43/*
b80b8de3
AC
44 * Terminal driving and line formatting routines. Basic motion optimizations
45 * are done here as well as formatting lines (printing of control characters,
15637ed4
RG
46 * line numbering and the like).
47 */
48
b80b8de3
AC
49/* Stub function for the users. */
50int
51mvcur(ly, lx, y, x)
52 int ly, lx, y, x;
53{
54 return (__mvcur(ly, lx, y, x, 0));
55}
15637ed4 56
b80b8de3
AC
57static void fgoto __P((int));
58static int plod __P((int, int));
31ebf6e3 59static void plodput __P((int));
b80b8de3 60static int tabcol __P((int, int));
15637ed4 61
b80b8de3 62static int outcol, outline, destcol, destline;
15637ed4 63
b80b8de3
AC
64/*
65 * Sync the position of the output cursor. Most work here is rounding for
66 * terminal boundaries getting the column position implied by wraparound or
67 * the lack thereof and rolling up the screen to get destline on the screen.
68 */
69int
70__mvcur(ly, lx, y, x, in_refresh)
71 int ly, lx, y, x, in_refresh;
72{
15637ed4 73#ifdef DEBUG
b80b8de3
AC
74 __CTRACE("mvcur: moving cursor from (%d, %d) to (%d, %d)\n",
75 ly, lx, y, x);
15637ed4
RG
76#endif
77 destcol = x;
78 destline = y;
79 outcol = lx;
80 outline = ly;
b80b8de3
AC
81 fgoto(in_refresh);
82 return (OK);
83}
84
85static void
86fgoto(in_refresh)
87 int in_refresh;
15637ed4 88{
b80b8de3
AC
89 register int c, l;
90 register char *cgp;
15637ed4
RG
91
92 if (destcol >= COLS) {
93 destline += destcol / COLS;
94 destcol %= COLS;
95 }
96 if (outcol >= COLS) {
97 l = (outcol + 1) / COLS;
98 outline += l;
99 outcol %= COLS;
100 if (AM == 0) {
101 while (l > 0) {
b80b8de3 102 if (__pfast)
15637ed4 103 if (CR)
b80b8de3 104 tputs(CR, 0, __cputchar);
15637ed4 105 else
b80b8de3 106 putchar('\r');
15637ed4 107 if (NL)
b80b8de3 108 tputs(NL, 0, __cputchar);
15637ed4 109 else
b80b8de3 110 putchar('\n');
15637ed4
RG
111 l--;
112 }
113 outcol = 0;
114 }
115 if (outline > LINES - 1) {
116 destline -= outline - (LINES - 1);
117 outline = LINES - 1;
118 }
119 }
120 if (destline >= LINES) {
121 l = destline;
122 destline = LINES - 1;
123 if (outline < LINES - 1) {
124 c = destcol;
b80b8de3 125 if (__pfast == 0 && !CA)
15637ed4 126 destcol = 0;
b80b8de3 127 fgoto(in_refresh);
15637ed4
RG
128 destcol = c;
129 }
130 while (l >= LINES) {
b80b8de3
AC
131 /* The following linefeed (or simulation thereof) is
132 * supposed to scroll up the screen, since we are on
133 * the bottom line. We make the assumption that
134 * linefeed will scroll. If ns is in the capability
135 * list this won't work. We should probably have an
136 * sc capability but sf will generally take the place
137 * if it works.
138 *
139 * Superbee glitch: in the middle of the screen have
140 * to use esc B (down) because linefeed screws up in
141 * "Efficient Paging" (what a joke) mode (which is
142 * essential in some SB's because CRLF mode puts
143 * garbage in at end of memory), but you must use
144 * linefeed to scroll since down arrow won't go past
145 * memory end. I turned this off after recieving Paul
146 * Eggert's Superbee description which wins better.
15637ed4 147 */
b80b8de3
AC
148 if (NL /* && !XB */ && __pfast)
149 tputs(NL, 0, __cputchar);
15637ed4 150 else
b80b8de3 151 putchar('\n');
15637ed4 152 l--;
b80b8de3 153 if (__pfast == 0)
15637ed4
RG
154 outcol = 0;
155 }
156 }
157 if (destline < outline && !(CA || UP))
158 destline = outline;
159 if (CA) {
160 cgp = tgoto(CM, destcol, destline);
b80b8de3
AC
161
162 /*
163 * Need this condition due to inconsistent behavior
164 * of backspace on the last column.
165 */
166 if (outcol != COLS - 1 && plod(strlen(cgp), in_refresh) > 0)
167 plod(0, in_refresh);
168 else
169 tputs(cgp, 0, __cputchar);
170 } else
171 plod(0, in_refresh);
15637ed4
RG
172 outline = destline;
173 outcol = destcol;
174}
15637ed4
RG
175/*
176 * Move (slowly) to destination.
177 * Hard thing here is using home cursor on really deficient terminals.
178 * Otherwise just use cursor motions, hacking use of tabs and overtabbing
179 * and backspace.
180 */
181
182static int plodcnt, plodflg;
183
31ebf6e3 184static void
15637ed4 185plodput(c)
b80b8de3 186 int c;
15637ed4
RG
187{
188 if (plodflg)
b80b8de3 189 --plodcnt;
15637ed4 190 else
b80b8de3 191 putchar(c);
15637ed4
RG
192}
193
b80b8de3
AC
194static int
195plod(cnt, in_refresh)
196 int cnt, in_refresh;
15637ed4 197{
b80b8de3 198 register int i, j, k, soutcol, soutline;
15637ed4
RG
199
200 plodcnt = plodflg = cnt;
201 soutcol = outcol;
202 soutline = outline;
203 /*
b80b8de3 204 * Consider homing and moving down/right from there, vs. moving
15637ed4
RG
205 * directly with local motions to the right spot.
206 */
207 if (HO) {
208 /*
b80b8de3
AC
209 * i is the cost to home and tab/space to the right to get to
210 * the proper column. This assumes ND space costs 1 char. So
211 * i + destcol is cost of motion with home.
15637ed4
RG
212 */
213 if (GT)
214 i = (destcol / HARDTABS) + (destcol % HARDTABS);
215 else
216 i = destcol;
b80b8de3
AC
217
218 /* j is cost to move locally without homing. */
15637ed4
RG
219 if (destcol >= outcol) { /* if motion is to the right */
220 j = destcol / HARDTABS - outcol / HARDTABS;
221 if (GT && j)
222 j += destcol % HARDTABS;
223 else
224 j = destcol - outcol;
b80b8de3 225 } else
15637ed4
RG
226 /* leftward motion only works if we can backspace. */
227 if (outcol - destcol <= i && (BS || BC))
b80b8de3
AC
228 /* Cheaper to backspace. */
229 i = j = outcol - destcol;
15637ed4 230 else
b80b8de3
AC
231 /* Impossibly expensive. */
232 j = i + 1;
15637ed4 233
b80b8de3 234 /* k is the absolute value of vertical distance. */
15637ed4
RG
235 k = outline - destline;
236 if (k < 0)
237 k = -k;
238 j += k;
239
b80b8de3 240 /* Decision. We may not have a choice if no UP. */
15637ed4
RG
241 if (i + destline < j || (!UP && destline < outline)) {
242 /*
243 * Cheaper to home. Do it now and pretend it's a
244 * regular local motion.
245 */
246 tputs(HO, 0, plodput);
247 outcol = outline = 0;
b80b8de3 248 } else if (LL) {
15637ed4
RG
249 /*
250 * Quickly consider homing down and moving from there.
251 * Assume cost of LL is 2.
252 */
253 k = (LINES - 1) - destline;
b80b8de3 254 if (i + k + 2 < j && (k <= 0 || UP)) {
15637ed4
RG
255 tputs(LL, 0, plodput);
256 outcol = 0;
257 outline = LINES - 1;
258 }
259 }
b80b8de3
AC
260 } else
261 /* No home and no up means it's impossible. */
15637ed4 262 if (!UP && destline < outline)
b80b8de3 263 return (-1);
15637ed4
RG
264 if (GT)
265 i = destcol % HARDTABS + destcol / HARDTABS;
266 else
267 i = destcol;
b80b8de3
AC
268#ifdef notdef
269 if (BT && outcol > destcol &&
270 (j = (((outcol+7) & ~7) - destcol - 1) >> 3)) {
15637ed4
RG
271 j *= (k = strlen(BT));
272 if ((k += (destcol&7)) > 4)
273 j += 8 - (destcol&7);
274 else
275 j += k;
276 }
277 else
b80b8de3 278#endif
15637ed4 279 j = outcol - destcol;
b80b8de3 280
15637ed4 281 /*
b80b8de3
AC
282 * If we will later need a \n which will turn into a \r\n by the
283 * system or the terminal, then don't bother to try to \r.
15637ed4 284 */
b80b8de3 285 if ((NONL || !__pfast) && outline < destline)
15637ed4 286 goto dontcr;
b80b8de3 287
15637ed4 288 /*
b80b8de3
AC
289 * If the terminal will do a \r\n and there isn't room for it, then
290 * we can't afford a \r.
15637ed4
RG
291 */
292 if (NC && outline >= destline)
293 goto dontcr;
b80b8de3 294
15637ed4 295 /*
b80b8de3
AC
296 * If it will be cheaper, or if we can't back up, then send a return
297 * preliminarily.
15637ed4
RG
298 */
299 if (j > i + 1 || outcol > destcol && !BS && !BC) {
300 /*
b80b8de3
AC
301 * BUG: this doesn't take the (possibly long) length of CR
302 * into account.
15637ed4
RG
303 */
304 if (CR)
305 tputs(CR, 0, plodput);
306 else
307 plodput('\r');
308 if (NC) {
309 if (NL)
310 tputs(NL, 0, plodput);
311 else
312 plodput('\n');
313 outline++;
314 }
315 outcol = 0;
316 }
b80b8de3
AC
317
318dontcr: while (outline < destline) {
15637ed4
RG
319 outline++;
320 if (NL)
321 tputs(NL, 0, plodput);
322 else
323 plodput('\n');
324 if (plodcnt < 0)
325 goto out;
b80b8de3 326 if (NONL || __pfast == 0)
15637ed4
RG
327 outcol = 0;
328 }
329 if (BT)
330 k = strlen(BT);
331 while (outcol > destcol) {
332 if (plodcnt < 0)
333 goto out;
b80b8de3 334#ifdef notdef
15637ed4
RG
335 if (BT && outcol - destcol > k + 4) {
336 tputs(BT, 0, plodput);
337 outcol--;
338 outcol &= ~7;
339 continue;
340 }
b80b8de3 341#endif
15637ed4
RG
342 outcol--;
343 if (BC)
344 tputs(BC, 0, plodput);
345 else
346 plodput('\b');
347 }
348 while (outline > destline) {
349 outline--;
350 tputs(UP, 0, plodput);
351 if (plodcnt < 0)
352 goto out;
353 }
354 if (GT && destcol - outcol > 1) {
355 for (;;) {
356 i = tabcol(outcol, HARDTABS);
357 if (i > destcol)
358 break;
359 if (TA)
360 tputs(TA, 0, plodput);
361 else
362 plodput('\t');
363 outcol = i;
364 }
365 if (destcol - outcol > 4 && i < COLS && (BC || BS)) {
366 if (TA)
367 tputs(TA, 0, plodput);
368 else
369 plodput('\t');
370 outcol = i;
371 while (outcol > destcol) {
372 outcol--;
373 if (BC)
374 tputs(BC, 0, plodput);
375 else
376 plodput('\b');
377 }
378 }
379 }
380 while (outcol < destcol) {
381 /*
b80b8de3
AC
382 * Move one char to the right. We don't use ND space because
383 * it's better to just print the char we are moving over.
15637ed4 384 */
b80b8de3
AC
385 if (in_refresh)
386 if (plodflg) /* Avoid a complex calculation. */
15637ed4
RG
387 plodcnt--;
388 else {
b80b8de3
AC
389 i = curscr->lines[outline]->line[outcol].ch;
390 if ((curscr->lines[outline]->line[outcol].attr
391 & __STANDOUT) ==
392 (curscr->flags & __WSTANDOUT))
393 putchar(i);
15637ed4
RG
394 else
395 goto nondes;
396 }
397 else
b80b8de3
AC
398nondes: if (ND)
399 tputs(ND, 0, plodput);
400 else
401 plodput(' ');
15637ed4
RG
402 outcol++;
403 if (plodcnt < 0)
404 goto out;
405 }
b80b8de3
AC
406
407out: if (plodflg) {
15637ed4
RG
408 outcol = soutcol;
409 outline = soutline;
410 }
b80b8de3 411 return (plodcnt);
15637ed4
RG
412}
413
414/*
415 * Return the column number that results from being in column col and
416 * hitting a tab, where tabs are set every ts columns. Work right for
417 * the case where col > COLS, even if ts does not divide COLS.
418 */
b80b8de3 419static int
15637ed4 420tabcol(col, ts)
b80b8de3 421 int col, ts;
15637ed4 422{
b80b8de3 423 int offset;
15637ed4
RG
424
425 if (col >= COLS) {
426 offset = COLS * (col / COLS);
427 col -= offset;
b80b8de3 428 } else
15637ed4 429 offset = 0;
b80b8de3 430 return (col + ts - (col % ts) + offset);
15637ed4 431}