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