Commit | Line | Data |
---|---|---|
15637ed4 RG |
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" | |
12 | extern int CO, LI; /* usually COLNO and ROWNO+2 */ | |
13 | extern char *CD; | |
14 | extern char quitchars[]; | |
15 | extern char *getenv(), *getlogin(); | |
16 | void done1(); | |
17 | ||
18 | dowhatis() | |
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 */ | |
60 | static int got_intrup; | |
61 | ||
62 | void | |
63 | intruph(){ | |
64 | got_intrup++; | |
65 | } | |
66 | ||
67 | /* simple pager, also used from dohelp() */ | |
68 | page_more(fp,strip) | |
69 | FILE *fp; | |
70 | int 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); | |
88 | ret: | |
89 | free(bufr); | |
90 | (void) fclose(fp); | |
91 | (void) signal(SIGINT, prevsig); | |
92 | got_intrup = 0; | |
93 | } | |
94 | ||
95 | static boolean whole_screen = TRUE; | |
96 | #define PAGMIN 12 /* minimum # of lines for page below level map */ | |
97 | ||
98 | set_whole_screen() { /* called in termcap as soon as LI is known */ | |
99 | whole_screen = (LI-ROWNO-2 <= PAGMIN || !CD); | |
100 | } | |
101 | ||
102 | #ifdef NEWS | |
103 | readnews() { | |
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 | ||
113 | set_pager(mode) | |
114 | register 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 | ||
143 | page_line(s) /* returns 1 if we should quit */ | |
144 | register 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 | ||
181 | cornline(mode, text) | |
182 | int mode; | |
183 | char *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 | ||
271 | cleanup: | |
272 | while(tl = texthead) { | |
273 | texthead = tl->next_line; | |
274 | free((char *) tl); | |
275 | } | |
276 | } | |
277 | ||
278 | dohelp() | |
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 | ||
290 | page_file(fnam, silent) /* return: 0 - cannot open fnam; 1 - otherwise */ | |
291 | register char *fnam; | |
292 | boolean 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 | |
341 | dosh(){ | |
342 | register 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 | |
356 | union 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 | ||
374 | child(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 |