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