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