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