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