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