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