xref: /openbsd/games/hack/hack.topl.c (revision 898184e3)
1 /*	$OpenBSD: hack.topl.c,v 1.9 2009/10/27 23:59:25 deraadt 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 <stdarg.h>
66 #include <stdlib.h>
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
85 doredotopl()
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
99 redotoplin()
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
113 remember_topl()
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((char *) tl->next_topl);
137 		tl->next_topl = 0;
138 	}
139 }
140 
141 void
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
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
176 more()
177 {
178 	xmore("");
179 }
180 
181 void
182 cmore(char *s)
183 {
184 	xmore(s);
185 }
186 
187 void
188 clrlin()
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 /*VARARGS1*/
200 void
201 pline(char *line, ...)
202 {
203 	char pbuf[BUFSZ];
204 	char *bp = pbuf, *tl;
205 	int n,n0;
206 	va_list ap;
207 
208 	if(!line || !*line) return;
209 	va_start(ap, line);
210 	(void) vsnprintf(pbuf, sizeof pbuf, line, ap);
211 	va_end(ap);
212 	if(flags.toplin == 1 && !strcmp(pbuf, toplines)) return;
213 	nscr();		/* %% */
214 
215 	/* If there is room on the line, print message on same line */
216 	/* But messages like "You die..." deserve their own line */
217 	n0 = strlen(bp);
218 	if(flags.toplin == 1 && tly == 1 &&
219 	    n0 + strlen(toplines) + 3 < CO-8 &&  /* leave room for --More-- */
220 	    strncmp(bp, "You ", 4)) {
221 		(void) strlcat(toplines, "  ", sizeof toplines);
222 		(void) strlcat(toplines, bp, sizeof toplines);
223 		tlx += 2;
224 		addtopl(bp);
225 		return;
226 	}
227 	if(flags.toplin == 1) more();
228 	remember_topl();
229 	toplines[0] = 0;
230 	while(n0){
231 		if(n0 >= CO){
232 			/* look for appropriate cut point */
233 			n0 = 0;
234 			for(n = 0; n < CO; n++) if(bp[n] == ' ')
235 				n0 = n;
236 			if(!n0) for(n = 0; n < CO-1; n++)
237 				if(!letter(bp[n])) n0 = n;
238 			if(!n0) n0 = CO-2;
239 		}
240 		(void) strncpy((tl = eos(toplines)), bp, n0);
241 		tl[n0] = '\0';
242 		bp += n0;
243 
244 		/* remove trailing spaces, but leave one */
245 		while(n0 > 1 && tl[n0-1] == ' ' && tl[n0-2] == ' ')
246 			tl[--n0] = 0;
247 
248 		n0 = strlen(bp);
249 		if(n0 && tl[0])
250 			(void) strlcat(tl, "\n",
251 			    toplines + sizeof toplines - tl);
252 	}
253 	redotoplin();
254 }
255 
256 void
257 putsym(char c)
258 {
259 	switch(c) {
260 	case '\b':
261 		backsp();
262 		return;
263 	case '\n':
264 		curx = 1;
265 		cury++;
266 		if(cury > tly) tly = cury;
267 		break;
268 	default:
269 		if(curx == CO)
270 			putsym('\n');	/* 1 <= curx <= CO; avoid CO */
271 		else
272 			curx++;
273 	}
274 	(void) putchar(c);
275 }
276 
277 void
278 putstr(char *s)
279 {
280 	while(*s) putsym(*s++);
281 }
282