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