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