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