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