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