]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - hack/hack.pager.c
dca670d8e7980c931a97d72682c0e22613feabf4
[bsdgames-darwin.git] / hack / hack.pager.c
1 /* $NetBSD: hack.pager.c,v 1.15 2011/05/23 22:53:25 joerg 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 <sys/cdefs.h>
65 #ifndef lint
66 __RCSID("$NetBSD: hack.pager.c,v 1.15 2011/05/23 22:53:25 joerg Exp $");
67 #endif /* not lint */
68
69 /* This file contains the command routine dowhatis() and a pager. */
70 /*
71 * Also readmail() and doshell(), and generally the things that contact the
72 * outside world.
73 */
74
75 #include <sys/types.h>
76 #include <signal.h>
77 #include <stdlib.h>
78 #include <unistd.h>
79 #include "hack.h"
80 #include "extern.h"
81
82 static void intruph(int);
83 static void page_more(FILE *, int);
84 static int page_file(const char *, boolean);
85 static int child(int);
86
87 int
88 dowhatis(void)
89 {
90 FILE *fp;
91 char bufr[BUFSZ + 6];
92 char *buf = &bufr[6], *ep, q;
93
94 if (!(fp = fopen(DATAFILE, "r")))
95 pline("Cannot open data file!");
96 else {
97 pline("Specify what? ");
98 q = readchar();
99 if (q != '\t')
100 while (fgets(buf, BUFSZ, fp))
101 if (*buf == q) {
102 ep = strchr(buf, '\n');
103 if (ep)
104 *ep = 0;
105 /* else: bad data file */
106 else {
107 pline("Bad data file!");
108 (void) fclose(fp);
109 return(0);
110 }
111 /* Expand tab 'by hand' */
112 if (buf[1] == '\t') {
113 buf = bufr;
114 buf[0] = q;
115 (void) strncpy(buf + 1, " ", 7);
116 }
117 pline("%s", buf);
118 if (ep[-1] == ';') {
119 pline("More info? ");
120 if (readchar() == 'y') {
121 page_more(fp, 1); /* does fclose() */
122 return (0);
123 }
124 }
125 (void) fclose(fp); /* kopper@psuvax1 */
126 return (0);
127 }
128 pline("I've never heard of such things.");
129 (void) fclose(fp);
130 }
131 return (0);
132 }
133
134 /* make the paging of a file interruptible */
135 static int got_intrup;
136
137 static void
138 intruph(int n __unused)
139 {
140 got_intrup++;
141 }
142
143 /* simple pager, also used from dohelp() */
144 /* strip: nr of chars to be stripped from each line (0 or 1) */
145 static void
146 page_more(FILE *fp, int strip)
147 {
148 char *bufr, *ep;
149 sig_t prevsig = signal(SIGINT, intruph);
150
151 set_pager(0);
152 bufr = (char *) alloc((unsigned) CO);
153 bufr[CO - 1] = 0;
154 while (fgets(bufr, CO - 1, fp) && (!strip || *bufr == '\t') && !got_intrup) {
155 ep = strchr(bufr, '\n');
156 if (ep)
157 *ep = 0;
158 if (page_line(bufr + strip)) {
159 set_pager(2);
160 goto ret;
161 }
162 }
163 set_pager(1);
164 ret:
165 free(bufr);
166 (void) fclose(fp);
167 (void) signal(SIGINT, prevsig);
168 got_intrup = 0;
169 }
170
171 static boolean whole_screen = TRUE;
172 #define PAGMIN 12 /* minimum # of lines for page below level
173 * map */
174
175 void
176 set_whole_screen(void)
177 { /* called in termcap as soon as LI is known */
178 whole_screen = (LI - ROWNO - 2 <= PAGMIN || !CD);
179 }
180
181 #ifdef NEWS
182 int
183 readnews(void)
184 {
185 int ret;
186
187 whole_screen = TRUE; /* force a docrt(), our first */
188 ret = page_file(NEWS, TRUE);
189 set_whole_screen();
190 return (ret); /* report whether we did docrt() */
191 }
192 #endif /* NEWS */
193
194 /* mode: 0: open 1: wait+close 2: close */
195 void
196 set_pager(int mode)
197 {
198 static boolean so;
199 if (mode == 0) {
200 if (!whole_screen) {
201 /* clear topline */
202 clrlin();
203 /* use part of screen below level map */
204 curs(1, ROWNO + 4);
205 } else {
206 cls();
207 }
208 so = flags.standout;
209 flags.standout = 1;
210 } else {
211 if (mode == 1) {
212 curs(1, LI);
213 more();
214 }
215 flags.standout = so;
216 if (whole_screen)
217 docrt();
218 else {
219 curs(1, ROWNO + 4);
220 cl_eos();
221 }
222 }
223 }
224
225 int
226 page_line(const char *s) /* returns 1 if we should quit */
227 {
228 if (cury == LI - 1) {
229 if (!*s)
230 return (0); /* suppress blank lines at top */
231 putchar('\n');
232 cury++;
233 cmore("q\033");
234 if (morc) {
235 morc = 0;
236 return (1);
237 }
238 if (whole_screen)
239 cls();
240 else {
241 curs(1, ROWNO + 4);
242 cl_eos();
243 }
244 }
245 puts(s);
246 cury++;
247 return (0);
248 }
249
250 /*
251 * Flexible pager: feed it with a number of lines and it will decide
252 * whether these should be fed to the pager above, or displayed in a
253 * corner.
254 * Call:
255 * cornline(0, title or 0) : initialize
256 * cornline(1, text) : add text to the chain of texts
257 * cornline(2, morcs) : output everything and cleanup
258 * cornline(3, 0) : cleanup
259 */
260
261 void
262 cornline(int mode, const char *text)
263 {
264 static struct line {
265 struct line *next_line;
266 char *line_text;
267 } *texthead, *texttail;
268 static int maxlen;
269 static int linect;
270 struct line *tl;
271
272 if (mode == 0) {
273 texthead = 0;
274 maxlen = 0;
275 linect = 0;
276 if (text) {
277 cornline(1, text); /* title */
278 cornline(1, ""); /* blank line */
279 }
280 return;
281 }
282 if (mode == 1) {
283 int len;
284
285 if (!text)
286 return; /* superfluous, just to be sure */
287 linect++;
288 len = strlen(text);
289 if (len > maxlen)
290 maxlen = len;
291 tl = (struct line *)
292 alloc((unsigned) (len + sizeof(struct line) + 1));
293 tl->next_line = 0;
294 tl->line_text = (char *) (tl + 1);
295 (void) strcpy(tl->line_text, text);
296 if (!texthead)
297 texthead = tl;
298 else
299 texttail->next_line = tl;
300 texttail = tl;
301 return;
302 }
303 /* --- now we really do it --- */
304 if (mode == 2 && linect == 1) /* topline only */
305 pline("%s", texthead->line_text);
306 else if (mode == 2) {
307 int curline, lth;
308
309 if (flags.toplin == 1)
310 more(); /* ab@unido */
311 remember_topl();
312
313 lth = CO - maxlen - 2; /* Use full screen width */
314 if (linect < LI && lth >= 10) { /* in a corner */
315 home();
316 cl_end();
317 flags.toplin = 0;
318 curline = 1;
319 for (tl = texthead; tl; tl = tl->next_line) {
320 curs(lth, curline);
321 if (curline > 1)
322 cl_end();
323 putsym(' ');
324 putstr(tl->line_text);
325 curline++;
326 }
327 curs(lth, curline);
328 cl_end();
329 cmore(text);
330 home();
331 cl_end();
332 docorner(lth, curline - 1);
333 } else { /* feed to pager */
334 set_pager(0);
335 for (tl = texthead; tl; tl = tl->next_line) {
336 if (page_line(tl->line_text)) {
337 set_pager(2);
338 goto cleanup;
339 }
340 }
341 if (text) {
342 cgetret(text);
343 set_pager(2);
344 } else
345 set_pager(1);
346 }
347 }
348 cleanup:
349 while ((tl = texthead) != NULL) {
350 texthead = tl->next_line;
351 free((char *) tl);
352 }
353 }
354
355 int
356 dohelp(void)
357 {
358 char c;
359
360 pline("Long or short help? ");
361 while (((c = readchar()) != 'l') && (c != 's') && !strchr(quitchars, c))
362 sound_bell();
363 if (!strchr(quitchars, c))
364 (void) page_file((c == 'l') ? HELP : SHELP, FALSE);
365 return (0);
366 }
367
368 /* return: 0 - cannot open fnam; 1 - otherwise */
369 static int
370 page_file(const char *fnam, boolean silent)
371 {
372 #ifdef DEF_PAGER /* this implies that UNIX is defined */
373 {
374 /* use external pager; this may give security problems */
375
376 int fd = open(fnam, O_RDONLY);
377
378 if (fd < 0) {
379 if (!silent)
380 pline("Cannot open %s.", fnam);
381 return (0);
382 }
383 if (child(1)) {
384
385 /*
386 * Now that child() does a setuid(getuid()) and a
387 * chdir(), we may not be able to open file fnam
388 * anymore, so make it stdin.
389 */
390 (void) close(0);
391 if (dup(fd)) {
392 if (!silent)
393 printf("Cannot open %s as stdin.\n", fnam);
394 } else {
395 execl(catmore, "page", (char *) 0);
396 if (!silent)
397 printf("Cannot exec %s.\n", catmore);
398 }
399 exit(1);
400 }
401 (void) close(fd);
402 }
403 #else /* DEF_PAGER */
404 {
405 FILE *f; /* free after Robert Viduya */
406
407 if ((f = fopen(fnam, "r")) == (FILE *) 0) {
408 if (!silent) {
409 home();
410 perror(fnam);
411 flags.toplin = 1;
412 pline("Cannot open %s.", fnam);
413 }
414 return (0);
415 }
416 page_more(f, 0);
417 }
418 #endif /* DEF_PAGER */
419
420 return (1);
421 }
422
423 #ifdef UNIX
424 #ifdef SHELL
425 int
426 dosh(void)
427 {
428 char *str;
429 if (child(0)) {
430 if ((str = getenv("SHELL")) != NULL)
431 execl(str, str, (char *) 0);
432 else
433 execl("/bin/sh", "sh", (char *) 0);
434 pline("sh: cannot execute.");
435 exit(1);
436 }
437 return (0);
438 }
439 #endif /* SHELL */
440
441 #ifdef NOWAITINCLUDE
442 union wait { /* used only for the cast (union wait *) 0 */
443 int w_status;
444 struct {
445 unsigned short w_Termsig:7;
446 unsigned short w_Coredump:1;
447 unsigned short w_Retcode:8;
448 } w_T;
449 };
450
451 #else
452
453 #ifdef BSD
454 #include <sys/wait.h>
455 #else
456 #include <wait.h>
457 #endif /* BSD */
458 #endif /* NOWAITINCLUDE */
459
460 static int
461 child(int wt)
462 {
463 int status;
464 int f;
465
466 f = fork();
467 if (f == 0) { /* child */
468 settty((char *) 0); /* also calls end_screen() */
469 (void) setuid(getuid());
470 (void) setgid(getgid());
471 #ifdef CHDIR
472 (void) chdir(getenv("HOME"));
473 #endif /* CHDIR */
474 return (1);
475 }
476 if (f == -1) { /* cannot fork */
477 pline("Fork failed. Try again.");
478 return (0);
479 }
480 /* fork succeeded; wait for child to exit */
481 (void) signal(SIGINT, SIG_IGN);
482 (void) signal(SIGQUIT, SIG_IGN);
483 (void) wait(&status);
484 gettty();
485 setftty();
486 (void) signal(SIGINT, done1);
487 #ifdef WIZARD
488 if (wizard)
489 (void) signal(SIGQUIT, SIG_DFL);
490 #endif /* WIZARD */
491 if (wt)
492 getret();
493 docrt();
494 return (0);
495 }
496 #endif /* UNIX */