xref: /dragonfly/games/hack/hack.topl.c (revision 4318c66e)
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 <stdlib.h>
65 #include "hack.h"
66 #include "extern.h"
67 
68 static char toplines[BUFSZ];
69 static xchar tlx, tly;		/* set by pline; used by addtopl */
70 
71 static struct topl {
72 	struct topl    *next_topl;
73 	char           *topl_text;
74 }              *old_toplines, *last_redone_topl;
75 #define	OTLMAX	20		/* max nr of old toplines remembered */
76 
77 static void redotoplin(void);
78 static void xmore(const char *);
79 
80 int
doredotopl(void)81 doredotopl(void)
82 {
83 	if (last_redone_topl)
84 		last_redone_topl = last_redone_topl->next_topl;
85 	if (!last_redone_topl)
86 		last_redone_topl = old_toplines;
87 	if (last_redone_topl) {
88 		(void) strcpy(toplines, last_redone_topl->topl_text);
89 	}
90 	redotoplin();
91 	return (0);
92 }
93 
94 static void
redotoplin(void)95 redotoplin(void)
96 {
97 	home();
98 	if (strchr(toplines, '\n'))
99 		cl_end();
100 	putstr(toplines);
101 	cl_end();
102 	tlx = curx;
103 	tly = cury;
104 	flags.toplin = 1;
105 	if (tly > 1)
106 		more();
107 }
108 
109 void
remember_topl(void)110 remember_topl(void)
111 {
112 	struct topl    *tl;
113 	int             cnt = OTLMAX;
114 	if (last_redone_topl &&
115 	    !strcmp(toplines, last_redone_topl->topl_text))
116 		return;
117 	if (old_toplines &&
118 	    !strcmp(toplines, old_toplines->topl_text))
119 		return;
120 	last_redone_topl = 0;
121 	tl = alloc(strlen(toplines) + sizeof(*tl) + 1);
122 	tl->next_topl = old_toplines;
123 	tl->topl_text = (char *) (tl + 1);
124 	(void) strcpy(tl->topl_text, toplines);
125 	old_toplines = tl;
126 	while (cnt && tl) {
127 		cnt--;
128 		tl = tl->next_topl;
129 	}
130 	if (tl && tl->next_topl) {
131 		free(tl->next_topl);
132 		tl->next_topl = 0;
133 	}
134 }
135 
136 void
addtopl(const char * s)137 addtopl(const char *s)
138 {
139 	curs(tlx, tly);
140 	if (tlx + (int)strlen(s) > CO)
141 		putsym('\n');
142 	putstr(s);
143 	tlx = curx;
144 	tly = cury;
145 	flags.toplin = 1;
146 }
147 
148 /* s = allowed chars besides space/return */
149 static void
xmore(const char * s)150 xmore(const char *s)
151 {
152 	if (flags.toplin) {
153 		curs(tlx, tly);
154 		if (tlx + 8 > CO)
155 			putsym('\n'), tly++;
156 	}
157 	if (flags.standout)
158 		standoutbeg();
159 	putstr("--More--");
160 	if (flags.standout)
161 		standoutend();
162 
163 	xwaitforspace(s);
164 	if (flags.toplin && tly > 1) {
165 		home();
166 		cl_end();
167 		docorner(1, tly - 1);
168 	}
169 	flags.toplin = 0;
170 }
171 
172 void
more(void)173 more(void)
174 {
175 	xmore("");
176 }
177 
178 void
cmore(const char * s)179 cmore(const char *s)
180 {
181 	xmore(s);
182 }
183 
184 void
clrlin(void)185 clrlin(void)
186 {
187 	if (flags.toplin) {
188 		home();
189 		cl_end();
190 		if (tly > 1)
191 			docorner(1, tly - 1);
192 		remember_topl();
193 	}
194 	flags.toplin = 0;
195 }
196 
197 void
pline(const char * fmt,...)198 pline(const char *fmt, ...)
199 {
200 	va_list ap;
201 
202 	va_start(ap, fmt);
203 	vpline(fmt, ap);
204 	va_end(ap);
205 }
206 
207 void
vpline(const char * line,va_list ap)208 vpline(const char *line, va_list ap)
209 {
210 	char            pbuf[BUFSZ];
211 	char           *bp = pbuf, *tl;
212 	int             n, n0, tlpos, dead;
213 
214 	if (!*line)
215 		return;
216 	if (!strchr(line, '%'))
217 		(void) strlcpy(pbuf, line, sizeof(pbuf));
218 	else
219 		(void) vsnprintf(pbuf, sizeof(pbuf), line, ap);
220 	if (flags.toplin == 1 && !strcmp(pbuf, toplines))
221 		return;
222 	nscr();			/* %% */
223 
224 	/* If there is room on the line, print message on same line */
225 	/* But messages like "You die..." deserve their own line */
226 	n0 = strlen(bp);
227 	if (flags.toplin == 1 && tly == 1 &&
228 	    n0 + (int)strlen(toplines) + 3 < CO - 8 &&	/* leave room for
229 							 * --More-- */
230 	    strncmp(bp, "You ", 4)) {
231 		(void) strcat(toplines, "  ");
232 		(void) strcat(toplines, bp);
233 		tlx += 2;
234 		addtopl(bp);
235 		return;
236 	}
237 	if (flags.toplin == 1)
238 		more();
239 	remember_topl();
240 	dead = 0;
241 	toplines[0] = 0;
242 	while (n0 && !dead) {
243 		if (n0 >= CO) {
244 			/* look for appropriate cut point */
245 			n0 = 0;
246 			for (n = 0; n < CO; n++)
247 				if (bp[n] == ' ')
248 					n0 = n;
249 			if (!n0)
250 				for (n = 0; n < CO - 1; n++)
251 					if (!letter(bp[n]))
252 						n0 = n;
253 			if (!n0)
254 				n0 = CO - 2;
255 		}
256 		tlpos = strlen(toplines);
257 		tl = toplines + tlpos;
258 		/* avoid overflow */
259 		if (tlpos + n0 > (int)sizeof(toplines) - 1) {
260 			n0 = sizeof(toplines) - 1 - tlpos;
261 			dead = 1;
262 		}
263 		(void) memcpy(tl, bp, n0);
264 		tl[n0] = 0;
265 		bp += n0;
266 
267 		/* remove trailing spaces, but leave one */
268 		while (n0 > 1 && tl[n0 - 1] == ' ' && tl[n0 - 2] == ' ')
269 			tl[--n0] = 0;
270 
271 		n0 = strlen(bp);
272 		if (n0 && tl[0])
273 			(void) strlcat(toplines, "\n", sizeof(toplines));
274 	}
275 	redotoplin();
276 }
277 
278 void
putsym(int c1)279 putsym(int c1)
280 {
281 	char c = c1; /* XXX this hack prevents .o diffs -- remove later */
282 
283 	switch (c) {
284 	case '\b':
285 		backsp();
286 		return;
287 	case '\n':
288 		curx = 1;
289 		cury++;
290 		if (cury > tly)
291 			tly = cury;
292 		break;
293 	default:
294 		if (curx == CO)
295 			putsym('\n');	/* 1 <= curx <= CO; avoid CO */
296 		else
297 			curx++;
298 	}
299 	(void) putchar(c);
300 }
301 
302 void
putstr(const char * s)303 putstr(const char *s)
304 {
305 	while (*s)
306 		putsym(*s++);
307 }
308