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