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