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