1 /*        $NetBSD: hack.topl.c,v 1.14 2011/08/06 20:29:37 dholland Exp $        */
2 
3 /*
4  * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
5  * Amsterdam
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are
10  * met:
11  *
12  * - Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * - Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in the
17  * documentation and/or other materials provided with the distribution.
18  *
19  * - Neither the name of the Stichting Centrum voor Wiskunde en
20  * Informatica, nor the names of its contributors may be used to endorse or
21  * promote products derived from this software without specific prior
22  * written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
25  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
27  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
28  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36 
37 /*
38  * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
39  * All rights reserved.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. The name of the author may not be used to endorse or promote products
50  *    derived from this software without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
53  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
54  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
55  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
56  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
57  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
58  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
59  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
60  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
61  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62  */
63 
64 #include <sys/cdefs.h>
65 #ifndef lint
66 __RCSID("$NetBSD: hack.topl.c,v 1.14 2011/08/06 20:29:37 dholland Exp $");
67 #endif                                  /* not lint */
68 
69 #include <stdlib.h>
70 #include "hack.h"
71 #include "extern.h"
72 
73 static char toplines[BUFSZ];
74 static xchar tlx, tly;                  /* set by pline; used by addtopl */
75 
76 static struct topl {
77           struct topl    *next_topl;
78           char           *topl_text;
79 }              *old_toplines, *last_redone_topl;
80 #define   OTLMAX    20                  /* max nr of old toplines remembered */
81 
82 static void redotoplin(void);
83 static void xmore(const char *);
84 
85 int
doredotopl(void)86 doredotopl(void)
87 {
88           if (last_redone_topl)
89                     last_redone_topl = last_redone_topl->next_topl;
90           if (!last_redone_topl)
91                     last_redone_topl = old_toplines;
92           if (last_redone_topl) {
93                     (void) strcpy(toplines, last_redone_topl->topl_text);
94           }
95           redotoplin();
96           return (0);
97 }
98 
99 static void
redotoplin(void)100 redotoplin(void)
101 {
102           home();
103           if (strchr(toplines, '\n'))
104                     cl_end();
105           putstr(toplines);
106           cl_end();
107           tlx = curx;
108           tly = cury;
109           flags.toplin = 1;
110           if (tly > 1)
111                     more();
112 }
113 
114 void
remember_topl(void)115 remember_topl(void)
116 {
117           struct topl    *tl;
118           int             cnt = OTLMAX;
119           if (last_redone_topl &&
120               !strcmp(toplines, last_redone_topl->topl_text))
121                     return;
122           if (old_toplines &&
123               !strcmp(toplines, old_toplines->topl_text))
124                     return;
125           last_redone_topl = 0;
126           tl = alloc(strlen(toplines) + sizeof(*tl) + 1);
127           tl->next_topl = old_toplines;
128           tl->topl_text = (char *) (tl + 1);
129           (void) strcpy(tl->topl_text, toplines);
130           old_toplines = tl;
131           while (cnt && tl) {
132                     cnt--;
133                     tl = tl->next_topl;
134           }
135           if (tl && tl->next_topl) {
136                     free(tl->next_topl);
137                     tl->next_topl = 0;
138           }
139 }
140 
141 void
addtopl(const char * s)142 addtopl(const char *s)
143 {
144           curs(tlx, tly);
145           if (tlx + (int)strlen(s) > CO)
146                     putsym('\n');
147           putstr(s);
148           tlx = curx;
149           tly = cury;
150           flags.toplin = 1;
151 }
152 
153 /* s = allowed chars besides space/return */
154 static void
xmore(const char * s)155 xmore(const char *s)
156 {
157           if (flags.toplin) {
158                     curs(tlx, tly);
159                     if (tlx + 8 > CO)
160                               putsym('\n'), tly++;
161           }
162           if (flags.standout)
163                     standoutbeg();
164           putstr("--More--");
165           if (flags.standout)
166                     standoutend();
167 
168           xwaitforspace(s);
169           if (flags.toplin && tly > 1) {
170                     home();
171                     cl_end();
172                     docorner(1, tly - 1);
173           }
174           flags.toplin = 0;
175 }
176 
177 void
more(void)178 more(void)
179 {
180           xmore("");
181 }
182 
183 void
cmore(const char * s)184 cmore(const char *s)
185 {
186           xmore(s);
187 }
188 
189 void
clrlin(void)190 clrlin(void)
191 {
192           if (flags.toplin) {
193                     home();
194                     cl_end();
195                     if (tly > 1)
196                               docorner(1, tly - 1);
197                     remember_topl();
198           }
199           flags.toplin = 0;
200 }
201 
202 void
pline(const char * fmt,...)203 pline(const char *fmt, ...)
204 {
205           va_list ap;
206 
207           va_start(ap, fmt);
208           vpline(fmt, ap);
209           va_end(ap);
210 }
211 
212 void
vpline(const char * line,va_list ap)213 vpline(const char *line, va_list ap)
214 {
215           char            pbuf[BUFSZ];
216           char           *bp = pbuf, *tl;
217           int             n, n0, tlpos, dead;
218 
219           if (!line || !*line)
220                     return;
221           if (!strchr(line, '%'))
222                     (void) strlcpy(pbuf, line, sizeof(pbuf));
223           else
224                     (void) vsnprintf(pbuf, sizeof(pbuf), line, ap);
225           if (flags.toplin == 1 && !strcmp(pbuf, toplines))
226                     return;
227           nscr();                       /* %% */
228 
229           /* If there is room on the line, print message on same line */
230           /* But messages like "You die..." deserve their own line */
231           n0 = strlen(bp);
232           if (flags.toplin == 1 && tly == 1 &&
233               n0 + (int)strlen(toplines) + 3 < CO - 8 &&    /* leave room for
234                                                                        * --More-- */
235               strncmp(bp, "You ", 4)) {
236                     (void) strcat(toplines, "  ");
237                     (void) strcat(toplines, bp);
238                     tlx += 2;
239                     addtopl(bp);
240                     return;
241           }
242           if (flags.toplin == 1)
243                     more();
244           remember_topl();
245           dead = 0;
246           toplines[0] = 0;
247           while (n0 && !dead) {
248                     if (n0 >= CO) {
249                               /* look for appropriate cut point */
250                               n0 = 0;
251                               for (n = 0; n < CO; n++)
252                                         if (bp[n] == ' ')
253                                                   n0 = n;
254                               if (!n0)
255                                         for (n = 0; n < CO - 1; n++)
256                                                   if (!letter(bp[n]))
257                                                             n0 = n;
258                               if (!n0)
259                                         n0 = CO - 2;
260                     }
261                     tlpos = strlen(toplines);
262                     tl = toplines + tlpos;
263                     /* avoid overflow */
264                     if (tlpos + n0 > (int)sizeof(toplines) - 1) {
265                               n0 = sizeof(toplines) - 1 - tlpos;
266                               dead = 1;
267                     }
268                     (void) memcpy(tl, bp, n0);
269                     tl[n0] = 0;
270                     bp += n0;
271 
272                     /* remove trailing spaces, but leave one */
273                     while (n0 > 1 && tl[n0 - 1] == ' ' && tl[n0 - 2] == ' ')
274                               tl[--n0] = 0;
275 
276                     n0 = strlen(bp);
277                     if (n0 && tl[0])
278                               (void) strlcat(toplines, "\n", sizeof(toplines));
279           }
280           redotoplin();
281 }
282 
283 void
putsym(int c1)284 putsym(int c1)
285 {
286           char c = c1; /* XXX this hack prevents .o diffs -- remove later */
287 
288           switch (c) {
289           case '\b':
290                     backsp();
291                     return;
292           case '\n':
293                     curx = 1;
294                     cury++;
295                     if (cury > tly)
296                               tly = cury;
297                     break;
298           default:
299                     if (curx == CO)
300                               putsym('\n');       /* 1 <= curx <= CO; avoid CO */
301                     else
302                               curx++;
303           }
304           (void) putchar(c);
305 }
306 
307 void
putstr(const char * s)308 putstr(const char *s)
309 {
310           while (*s)
311                     putsym(*s++);
312 }
313