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