Generally use NULL instead of explicitly casting 0 to some pointer type (part2).
[dragonfly.git] / games / hack / hack.pager.c
CommitLineData
984263bc
MD
1/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
2/* hack.pager.c - version 1.0.3 */
3/* $FreeBSD: src/games/hack/hack.pager.c,v 1.7 1999/11/16 02:57:09 billf Exp $ */
c7106d58 4/* $DragonFly: src/games/hack/hack.pager.c,v 1.4 2006/08/21 19:45:32 pavalos Exp $ */
984263bc
MD
5
6/* This file contains the command routine dowhatis() and a pager. */
7/* Also readmail() and doshell(), and generally the things that
8 contact the outside world. */
9
10#include <sys/types.h>
11#include <sys/signal.h>
984263bc
MD
12#include "hack.h"
13extern int CO, LI; /* usually COLNO and ROWNO+2 */
14extern char *CD;
15extern char quitchars[];
984263bc 16
c7106d58
PA
17static void intruph(int);
18static void page_more(FILE *, int);
19
20int
21dowhatis(void)
984263bc
MD
22{
23 FILE *fp;
24 char bufr[BUFSZ+6];
25 char *buf = &bufr[6], *ep, q;
984263bc
MD
26
27 if(!(fp = fopen(DATAFILE, "r")))
28 pline("Cannot open data file!");
29 else {
30 pline("Specify what? ");
31 q = readchar();
32 if(q != '\t')
33 while(fgets(buf,BUFSZ,fp))
34 if(*buf == q) {
35 ep = index(buf, '\n');
36 if(ep) *ep = 0;
37 /* else: bad data file */
38 /* Expand tab 'by hand' */
39 if(buf[1] == '\t'){
40 buf = bufr;
41 buf[0] = q;
c7106d58 42 strncpy(buf+1, " ", 7);
984263bc
MD
43 }
44 pline(buf);
45 if(ep[-1] == ';') {
46 pline("More info? ");
47 if(readchar() == 'y') {
48 page_more(fp,1); /* does fclose() */
49 return(0);
50 }
51 }
c7106d58 52 fclose(fp); /* kopper@psuvax1 */
984263bc
MD
53 return(0);
54 }
55 pline("I've never heard of such things.");
c7106d58 56 fclose(fp);
984263bc
MD
57 }
58 return(0);
59}
60
61/* make the paging of a file interruptible */
62static int got_intrup;
63
c7106d58
PA
64static void
65intruph(__unused int unused)
66{
984263bc
MD
67 got_intrup++;
68}
69
70/* simple pager, also used from dohelp() */
c7106d58
PA
71/* strip = nr of chars to be stripped from each line (0 or 1) */
72static void
73page_more(FILE *fp, int strip)
984263bc
MD
74{
75 char *bufr, *ep;
76 sig_t prevsig = signal(SIGINT, intruph);
77
78 set_pager(0);
79 bufr = (char *) alloc((unsigned) CO);
80 bufr[CO-1] = 0;
81 while(fgets(bufr,CO-1,fp) && (!strip || *bufr == '\t') && !got_intrup){
82 ep = index(bufr, '\n');
83 if(ep)
84 *ep = 0;
85 if(page_line(bufr+strip)) {
86 set_pager(2);
87 goto ret;
88 }
89 }
90 set_pager(1);
91ret:
92 free(bufr);
c7106d58
PA
93 fclose(fp);
94 signal(SIGINT, prevsig);
984263bc
MD
95 got_intrup = 0;
96}
97
98static boolean whole_screen = TRUE;
99#define PAGMIN 12 /* minimum # of lines for page below level map */
100
c7106d58
PA
101void
102set_whole_screen(void) /* called in termcap as soon as LI is known */
103{
984263bc
MD
104 whole_screen = (LI-ROWNO-2 <= PAGMIN || !CD);
105}
106
107#ifdef NEWS
c7106d58
PA
108bool
109readnews(void)
110{
984263bc
MD
111 int ret;
112
113 whole_screen = TRUE; /* force a docrt(), our first */
114 ret = page_file(NEWS, TRUE);
115 set_whole_screen();
116 return(ret); /* report whether we did docrt() */
117}
304d60d9 118#endif /* NEWS */
984263bc 119
c7106d58
PA
120void
121set_pager(int mode) /* 0: open 1: wait+close 2: close */
984263bc
MD
122{
123 static boolean so;
124 if(mode == 0) {
125 if(!whole_screen) {
126 /* clear topline */
127 clrlin();
128 /* use part of screen below level map */
129 curs(1, ROWNO+4);
130 } else {
131 cls();
132 }
133 so = flags.standout;
134 flags.standout = 1;
135 } else {
136 if(mode == 1) {
137 curs(1, LI);
138 more();
139 }
140 flags.standout = so;
141 if(whole_screen)
142 docrt();
143 else {
144 curs(1, ROWNO+4);
145 cl_eos();
146 }
147 }
148}
149
c7106d58
PA
150bool
151page_line(const char *s) /* returns 1 if we should quit */
984263bc 152{
984263bc
MD
153 if(cury == LI-1) {
154 if(!*s)
155 return(0); /* suppress blank lines at top */
156 putchar('\n');
157 cury++;
158 cmore("q\033");
159 if(morc) {
160 morc = 0;
161 return(1);
162 }
163 if(whole_screen)
164 cls();
165 else {
166 curs(1, ROWNO+4);
167 cl_eos();
168 }
169 }
170 puts(s);
171 cury++;
172 return(0);
173}
174
175/*
176 * Flexible pager: feed it with a number of lines and it will decide
177 * whether these should be fed to the pager above, or displayed in a
178 * corner.
179 * Call:
180 * cornline(0, title or 0) : initialize
181 * cornline(1, text) : add text to the chain of texts
182 * cornline(2, morcs) : output everything and cleanup
183 * cornline(3, 0) : cleanup
184 */
185
c7106d58
PA
186void
187cornline(int mode, const char *text)
984263bc
MD
188{
189 static struct line {
190 struct line *next_line;
191 char *line_text;
192 } *texthead, *texttail;
193 static int maxlen;
194 static int linect;
195 struct line *tl;
196
197 if(mode == 0) {
198 texthead = 0;
199 maxlen = 0;
200 linect = 0;
201 if(text) {
202 cornline(1, text); /* title */
203 cornline(1, ""); /* blank line */
204 }
205 return;
206 }
207
208 if(mode == 1) {
209 int len;
210
211 if(!text) return; /* superfluous, just to be sure */
212 linect++;
213 len = strlen(text);
214 if(len > maxlen)
215 maxlen = len;
216 tl = (struct line *)
217 alloc((unsigned)(len + sizeof(struct line) + 1));
218 tl->next_line = 0;
219 tl->line_text = (char *)(tl + 1);
c7106d58 220 strcpy(tl->line_text, text);
984263bc
MD
221 if(!texthead)
222 texthead = tl;
223 else
224 texttail->next_line = tl;
225 texttail = tl;
226 return;
227 }
228
229 /* --- now we really do it --- */
230 if(mode == 2 && linect == 1) /* topline only */
231 pline(texthead->line_text);
232 else
233 if(mode == 2) {
234 int curline, lth;
235
236 if(flags.toplin == 1) more(); /* ab@unido */
237 remember_topl();
238
239 lth = CO - maxlen - 2; /* Use full screen width */
240 if (linect < LI && lth >= 10) { /* in a corner */
241 home ();
242 cl_end ();
243 flags.toplin = 0;
244 curline = 1;
245 for (tl = texthead; tl; tl = tl->next_line) {
246 curs (lth, curline);
247 if(curline > 1)
248 cl_end ();
249 putsym(' ');
250 putstr (tl->line_text);
251 curline++;
252 }
253 curs (lth, curline);
254 cl_end ();
255 cmore (text);
256 home ();
257 cl_end ();
258 docorner (lth, curline-1);
259 } else { /* feed to pager */
260 set_pager(0);
261 for (tl = texthead; tl; tl = tl->next_line) {
262 if (page_line (tl->line_text)) {
263 set_pager(2);
264 goto cleanup;
265 }
266 }
267 if(text) {
268 cgetret(text);
269 set_pager(2);
270 } else
271 set_pager(1);
272 }
273 }
274
275cleanup:
c7106d58 276 while((tl = texthead)) {
984263bc
MD
277 texthead = tl->next_line;
278 free((char *) tl);
279 }
280}
281
c7106d58
PA
282int
283dohelp(void)
984263bc
MD
284{
285 char c;
286
287 pline ("Long or short help? ");
288 while (((c = readchar ()) != 'l') && (c != 's') && !index(quitchars,c))
289 bell ();
290 if (!index(quitchars, c))
c7106d58 291 page_file((c == 'l') ? HELP : SHELP, FALSE);
984263bc
MD
292 return(0);
293}
294
c7106d58
PA
295/* return: 0 - cannot open fnam; 1 - otherwise */
296bool
297page_file(const char *fnam, bool silent)
984263bc
MD
298{
299#ifdef DEF_PAGER /* this implies that UNIX is defined */
300 {
301 /* use external pager; this may give security problems */
302
303 int fd = open(fnam, 0);
304
305 if(fd < 0) {
306 if(!silent) pline("Cannot open %s.", fnam);
307 return(0);
308 }
309 if(child(1)){
310 extern char *catmore;
311
312 /* Now that child() does a setuid(getuid()) and a chdir(),
313 we may not be able to open file fnam anymore, so make
314 it stdin. */
c7106d58 315 close(0);
984263bc
MD
316 if(dup(fd)) {
317 if(!silent) printf("Cannot open %s as stdin.\n", fnam);
318 } else {
902ec341 319 execl(catmore, "page", NULL);
984263bc
MD
320 if(!silent) printf("Cannot exec %s.\n", catmore);
321 }
322 exit(1);
323 }
c7106d58 324 close(fd);
984263bc 325 }
304d60d9 326#else /* DEF_PAGER */
984263bc
MD
327 {
328 FILE *f; /* free after Robert Viduya */
329
902ec341 330 if ((f = fopen (fnam, "r")) == NULL) {
984263bc
MD
331 if(!silent) {
332 home(); perror (fnam); flags.toplin = 1;
333 pline ("Cannot open %s.", fnam);
334 }
335 return(0);
336 }
337 page_more(f, 0);
338 }
304d60d9 339#endif /* DEF_PAGER */
984263bc
MD
340
341 return(1);
342}
343
344#ifdef UNIX
345#ifdef SHELL
c7106d58
PA
346int
347dosh(void)
348{
984263bc
MD
349char *str;
350 if(child(0)) {
c7106d58 351 if((str = getenv("SHELL")))
902ec341 352 execl(str, str, NULL);
984263bc 353 else
902ec341 354 execl("/bin/sh", "sh", NULL);
984263bc
MD
355 pline("sh: cannot execute.");
356 exit(1);
357 }
358 return(0);
359}
304d60d9 360#endif /* SHELL */
984263bc
MD
361
362#ifdef NOWAITINCLUDE
363union wait { /* used only for the cast (union wait *) 0 */
364 int w_status;
365 struct {
366 unsigned short w_Termsig:7;
367 unsigned short w_Coredump:1;
368 unsigned short w_Retcode:8;
369 } w_T;
370};
371
372#else
373
374#ifdef BSD
375#include <sys/wait.h>
376#else
377#include <wait.h>
304d60d9
EN
378#endif /* BSD */
379#endif /* NOWAITINCLUDE */
984263bc 380
c7106d58
PA
381bool
382child(bool wt)
383{
984263bc
MD
384 int status;
385 int f;
386
387 f = fork();
388 if(f == 0){ /* child */
902ec341 389 settty(NULL); /* also calls end_screen() */
984263bc
MD
390 /* revoke */
391 setgid(getgid());
392#ifdef CHDIR
c7106d58 393 chdir(getenv("HOME"));
304d60d9 394#endif /* CHDIR */
984263bc
MD
395 return(1);
396 }
397 if(f == -1) { /* cannot fork */
398 pline("Fork failed. Try again.");
399 return(0);
400 }
401 /* fork succeeded; wait for child to exit */
c7106d58
PA
402 signal(SIGINT,SIG_IGN);
403 signal(SIGQUIT,SIG_IGN);
404 wait(&status);
984263bc
MD
405 gettty();
406 setftty();
c7106d58 407 signal(SIGINT,done1);
984263bc 408#ifdef WIZARD
c7106d58 409 if(wizard) signal(SIGQUIT,SIG_DFL);
304d60d9 410#endif /* WIZARD */
984263bc
MD
411 if(wt) getret();
412 docrt();
413 return(0);
414}
304d60d9 415#endif /* UNIX */