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