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