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