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