xref: /csrg-svn/games/hack/hack.pager.c (revision 47700)
139156Sbostic /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
239156Sbostic /* hack.pager.c - version 1.0.3 */
339156Sbostic 
439156Sbostic /* This file contains the command routine dowhatis() and a pager. */
539156Sbostic /* Also readmail() and doshell(), and generally the things that
639156Sbostic    contact the outside world. */
739156Sbostic 
845770Sbostic #include	<sys/types.h>
945770Sbostic #include	<sys/signal.h>
1039156Sbostic #include	<stdio.h>
1139156Sbostic #include "hack.h"
1239156Sbostic extern int CO, LI;	/* usually COLNO and ROWNO+2 */
1339156Sbostic extern char *CD;
1439156Sbostic extern char quitchars[];
1539156Sbostic extern char *getenv(), *getlogin();
16*47700Sbostic void done1();
1739156Sbostic 
dowhatis()1839156Sbostic dowhatis()
1939156Sbostic {
2039156Sbostic 	FILE *fp;
2139156Sbostic 	char bufr[BUFSZ+6];
2239156Sbostic 	register char *buf = &bufr[6], *ep, q;
2339156Sbostic 	extern char readchar();
2439156Sbostic 
2539156Sbostic 	if(!(fp = fopen(DATAFILE, "r")))
2639156Sbostic 		pline("Cannot open data file!");
2739156Sbostic 	else {
2839156Sbostic 		pline("Specify what? ");
2939156Sbostic 		q = readchar();
3039156Sbostic 		if(q != '\t')
3139156Sbostic 		while(fgets(buf,BUFSZ,fp))
3239156Sbostic 		    if(*buf == q) {
3339156Sbostic 			ep = index(buf, '\n');
3439156Sbostic 			if(ep) *ep = 0;
3539156Sbostic 			/* else: bad data file */
3639156Sbostic 			/* Expand tab 'by hand' */
3739156Sbostic 			if(buf[1] == '\t'){
3839156Sbostic 				buf = bufr;
3939156Sbostic 				buf[0] = q;
4039156Sbostic 				(void) strncpy(buf+1, "       ", 7);
4139156Sbostic 			}
4239156Sbostic 			pline(buf);
4339156Sbostic 			if(ep[-1] == ';') {
4439156Sbostic 				pline("More info? ");
4539156Sbostic 				if(readchar() == 'y') {
4639156Sbostic 					page_more(fp,1); /* does fclose() */
4739156Sbostic 					return(0);
4839156Sbostic 				}
4939156Sbostic 			}
5039156Sbostic 			(void) fclose(fp); 	/* kopper@psuvax1 */
5139156Sbostic 			return(0);
5239156Sbostic 		    }
5339156Sbostic 		pline("I've never heard of such things.");
5439156Sbostic 		(void) fclose(fp);
5539156Sbostic 	}
5639156Sbostic 	return(0);
5739156Sbostic }
5839156Sbostic 
5939156Sbostic /* make the paging of a file interruptible */
6039156Sbostic static int got_intrup;
6139156Sbostic 
6239157Sbostic void
intruph()6339156Sbostic intruph(){
6439156Sbostic 	got_intrup++;
6539156Sbostic }
6639156Sbostic 
6739156Sbostic /* simple pager, also used from dohelp() */
page_more(fp,strip)6839156Sbostic page_more(fp,strip)
6939156Sbostic FILE *fp;
7039156Sbostic int strip;	/* nr of chars to be stripped from each line (0 or 1) */
7139156Sbostic {
7239156Sbostic 	register char *bufr, *ep;
7339157Sbostic 	sig_t prevsig = signal(SIGINT, intruph);
7439156Sbostic 
7539156Sbostic 	set_pager(0);
7639156Sbostic 	bufr = (char *) alloc((unsigned) CO);
7739156Sbostic 	bufr[CO-1] = 0;
7839156Sbostic 	while(fgets(bufr,CO-1,fp) && (!strip || *bufr == '\t') && !got_intrup){
7939156Sbostic 		ep = index(bufr, '\n');
8039156Sbostic 		if(ep)
8139156Sbostic 			*ep = 0;
8239156Sbostic 		if(page_line(bufr+strip)) {
8339156Sbostic 			set_pager(2);
8439156Sbostic 			goto ret;
8539156Sbostic 		}
8639156Sbostic 	}
8739156Sbostic 	set_pager(1);
8839156Sbostic ret:
8939156Sbostic 	free(bufr);
9039156Sbostic 	(void) fclose(fp);
9139156Sbostic 	(void) signal(SIGINT, prevsig);
9239156Sbostic 	got_intrup = 0;
9339156Sbostic }
9439156Sbostic 
9539156Sbostic static boolean whole_screen = TRUE;
9639156Sbostic #define	PAGMIN	12	/* minimum # of lines for page below level map */
9739156Sbostic 
set_whole_screen()9839156Sbostic set_whole_screen() {	/* called in termcap as soon as LI is known */
9939156Sbostic 	whole_screen = (LI-ROWNO-2 <= PAGMIN || !CD);
10039156Sbostic }
10139156Sbostic 
10239156Sbostic #ifdef NEWS
readnews()10339156Sbostic readnews() {
10439156Sbostic 	register int ret;
10539156Sbostic 
10639156Sbostic 	whole_screen = TRUE;	/* force a docrt(), our first */
10739156Sbostic 	ret = page_file(NEWS, TRUE);
10839156Sbostic 	set_whole_screen();
10939156Sbostic 	return(ret);		/* report whether we did docrt() */
11039156Sbostic }
11139156Sbostic #endif NEWS
11239156Sbostic 
set_pager(mode)11339156Sbostic set_pager(mode)
11439156Sbostic register int mode;	/* 0: open  1: wait+close  2: close */
11539156Sbostic {
11639156Sbostic 	static boolean so;
11739156Sbostic 	if(mode == 0) {
11839156Sbostic 		if(!whole_screen) {
11939156Sbostic 			/* clear topline */
12039156Sbostic 			clrlin();
12139156Sbostic 			/* use part of screen below level map */
12239156Sbostic 			curs(1, ROWNO+4);
12339156Sbostic 		} else {
12439156Sbostic 			cls();
12539156Sbostic 		}
12639156Sbostic 		so = flags.standout;
12739156Sbostic 		flags.standout = 1;
12839156Sbostic 	} else {
12939156Sbostic 		if(mode == 1) {
13039156Sbostic 			curs(1, LI);
13139156Sbostic 			more();
13239156Sbostic 		}
13339156Sbostic 		flags.standout = so;
13439156Sbostic 		if(whole_screen)
13539156Sbostic 			docrt();
13639156Sbostic 		else {
13739156Sbostic 			curs(1, ROWNO+4);
13839156Sbostic 			cl_eos();
13939156Sbostic 		}
14039156Sbostic 	}
14139156Sbostic }
14239156Sbostic 
page_line(s)14339156Sbostic page_line(s)		/* returns 1 if we should quit */
14439156Sbostic register char *s;
14539156Sbostic {
14639156Sbostic 	extern char morc;
14739156Sbostic 
14839156Sbostic 	if(cury == LI-1) {
14939156Sbostic 		if(!*s)
15039156Sbostic 			return(0);	/* suppress blank lines at top */
15139156Sbostic 		putchar('\n');
15239156Sbostic 		cury++;
15339156Sbostic 		cmore("q\033");
15439156Sbostic 		if(morc) {
15539156Sbostic 			morc = 0;
15639156Sbostic 			return(1);
15739156Sbostic 		}
15839156Sbostic 		if(whole_screen)
15939156Sbostic 			cls();
16039156Sbostic 		else {
16139156Sbostic 			curs(1, ROWNO+4);
16239156Sbostic 			cl_eos();
16339156Sbostic 		}
16439156Sbostic 	}
16539156Sbostic 	puts(s);
16639156Sbostic 	cury++;
16739156Sbostic 	return(0);
16839156Sbostic }
16939156Sbostic 
17039156Sbostic /*
17139156Sbostic  * Flexible pager: feed it with a number of lines and it will decide
17239156Sbostic  * whether these should be fed to the pager above, or displayed in a
17339156Sbostic  * corner.
17439156Sbostic  * Call:
17539156Sbostic  *	cornline(0, title or 0)	: initialize
17639156Sbostic  *	cornline(1, text)	: add text to the chain of texts
17739156Sbostic  *	cornline(2, morcs)	: output everything and cleanup
17839156Sbostic  *	cornline(3, 0)		: cleanup
17939156Sbostic  */
18039156Sbostic 
cornline(mode,text)18139156Sbostic cornline(mode, text)
18239156Sbostic int mode;
18339156Sbostic char *text;
18439156Sbostic {
18539156Sbostic 	static struct line {
18639156Sbostic 		struct line *next_line;
18739156Sbostic 		char *line_text;
18839156Sbostic 	} *texthead, *texttail;
18939156Sbostic 	static int maxlen;
19039156Sbostic 	static int linect;
19139156Sbostic 	register struct line *tl;
19239156Sbostic 
19339156Sbostic 	if(mode == 0) {
19439156Sbostic 		texthead = 0;
19539156Sbostic 		maxlen = 0;
19639156Sbostic 		linect = 0;
19739156Sbostic 		if(text) {
19839156Sbostic 			cornline(1, text);	/* title */
19939156Sbostic 			cornline(1, "");	/* blank line */
20039156Sbostic 		}
20139156Sbostic 		return;
20239156Sbostic 	}
20339156Sbostic 
20439156Sbostic 	if(mode == 1) {
20539156Sbostic 	    register int len;
20639156Sbostic 
20739156Sbostic 	    if(!text) return;	/* superfluous, just to be sure */
20839156Sbostic 	    linect++;
20939156Sbostic 	    len = strlen(text);
21039156Sbostic 	    if(len > maxlen)
21139156Sbostic 		maxlen = len;
21239156Sbostic 	    tl = (struct line *)
21339156Sbostic 		alloc((unsigned)(len + sizeof(struct line) + 1));
21439156Sbostic 	    tl->next_line = 0;
21539156Sbostic 	    tl->line_text = (char *)(tl + 1);
21639156Sbostic 	    (void) strcpy(tl->line_text, text);
21739156Sbostic 	    if(!texthead)
21839156Sbostic 		texthead = tl;
21939156Sbostic 	    else
22039156Sbostic 		texttail->next_line = tl;
22139156Sbostic 	    texttail = tl;
22239156Sbostic 	    return;
22339156Sbostic 	}
22439156Sbostic 
22539156Sbostic 	/* --- now we really do it --- */
22639156Sbostic 	if(mode == 2 && linect == 1)			    /* topline only */
22739156Sbostic 		pline(texthead->line_text);
22839156Sbostic 	else
22939156Sbostic 	if(mode == 2) {
23039156Sbostic 	    register int curline, lth;
23139156Sbostic 
23239156Sbostic 	    if(flags.toplin == 1) more();	/* ab@unido */
23339156Sbostic 	    remember_topl();
23439156Sbostic 
23539156Sbostic 	    lth = CO - maxlen - 2;		   /* Use full screen width */
23639156Sbostic 	    if (linect < LI && lth >= 10) {		     /* in a corner */
23739156Sbostic 		home ();
23839156Sbostic 		cl_end ();
23939156Sbostic 		flags.toplin = 0;
24039156Sbostic 		curline = 1;
24139156Sbostic 		for (tl = texthead; tl; tl = tl->next_line) {
24239156Sbostic 		    curs (lth, curline);
24339156Sbostic 		    if(curline > 1)
24439156Sbostic 			cl_end ();
24539156Sbostic 		    putsym(' ');
24639156Sbostic 		    putstr (tl->line_text);
24739156Sbostic 		    curline++;
24839156Sbostic 		}
24939156Sbostic 		curs (lth, curline);
25039156Sbostic 		cl_end ();
25139156Sbostic 		cmore (text);
25239156Sbostic 		home ();
25339156Sbostic 		cl_end ();
25439156Sbostic 		docorner (lth, curline-1);
25539156Sbostic 	    } else {					/* feed to pager */
25639156Sbostic 		set_pager(0);
25739156Sbostic 		for (tl = texthead; tl; tl = tl->next_line) {
25839156Sbostic 		    if (page_line (tl->line_text)) {
25939156Sbostic 			set_pager(2);
26039156Sbostic 			goto cleanup;
26139156Sbostic 		    }
26239156Sbostic 		}
26339156Sbostic 		if(text) {
26439156Sbostic 			cgetret(text);
26539156Sbostic 			set_pager(2);
26639156Sbostic 		} else
26739156Sbostic 			set_pager(1);
26839156Sbostic 	    }
26939156Sbostic 	}
27039156Sbostic 
27139156Sbostic cleanup:
27239156Sbostic 	while(tl = texthead) {
27339156Sbostic 		texthead = tl->next_line;
27439156Sbostic 		free((char *) tl);
27539156Sbostic 	}
27639156Sbostic }
27739156Sbostic 
dohelp()27839156Sbostic dohelp()
27939156Sbostic {
28039156Sbostic 	char c;
28139156Sbostic 
28239156Sbostic 	pline ("Long or short help? ");
28339156Sbostic 	while (((c = readchar ()) != 'l') && (c != 's') && !index(quitchars,c))
28439156Sbostic 		bell ();
28539156Sbostic 	if (!index(quitchars, c))
28639156Sbostic 		(void) page_file((c == 'l') ? HELP : SHELP, FALSE);
28739156Sbostic 	return(0);
28839156Sbostic }
28939156Sbostic 
page_file(fnam,silent)29039156Sbostic page_file(fnam, silent)	/* return: 0 - cannot open fnam; 1 - otherwise */
29139156Sbostic register char *fnam;
29239156Sbostic boolean silent;
29339156Sbostic {
29439156Sbostic #ifdef DEF_PAGER			/* this implies that UNIX is defined */
29539156Sbostic       {
29639156Sbostic 	/* use external pager; this may give security problems */
29739156Sbostic 
29839156Sbostic 	register int fd = open(fnam, 0);
29939156Sbostic 
30039156Sbostic 	if(fd < 0) {
30139156Sbostic 		if(!silent) pline("Cannot open %s.", fnam);
30239156Sbostic 		return(0);
30339156Sbostic 	}
30439156Sbostic 	if(child(1)){
30539156Sbostic 		extern char *catmore;
30639156Sbostic 
30739156Sbostic 		/* Now that child() does a setuid(getuid()) and a chdir(),
30839156Sbostic 		   we may not be able to open file fnam anymore, so make
30939156Sbostic 		   it stdin. */
31039156Sbostic 		(void) close(0);
31139156Sbostic 		if(dup(fd)) {
31239156Sbostic 			if(!silent) printf("Cannot open %s as stdin.\n", fnam);
31339156Sbostic 		} else {
31439156Sbostic 			execl(catmore, "page", (char *) 0);
31539156Sbostic 			if(!silent) printf("Cannot exec %s.\n", catmore);
31639156Sbostic 		}
31739156Sbostic 		exit(1);
31839156Sbostic 	}
31939156Sbostic 	(void) close(fd);
32039156Sbostic       }
32139156Sbostic #else DEF_PAGER
32239156Sbostic       {
32339156Sbostic 	FILE *f;			/* free after Robert Viduya */
32439156Sbostic 
32539156Sbostic 	if ((f = fopen (fnam, "r")) == (FILE *) 0) {
32639156Sbostic 		if(!silent) {
32739156Sbostic 			home(); perror (fnam); flags.toplin = 1;
32839156Sbostic 			pline ("Cannot open %s.", fnam);
32939156Sbostic 		}
33039156Sbostic 		return(0);
33139156Sbostic 	}
33239156Sbostic 	page_more(f, 0);
33339156Sbostic       }
33439156Sbostic #endif DEF_PAGER
33539156Sbostic 
33639156Sbostic 	return(1);
33739156Sbostic }
33839156Sbostic 
33939156Sbostic #ifdef UNIX
34039156Sbostic #ifdef SHELL
dosh()34139156Sbostic dosh(){
34239156Sbostic register char *str;
34339156Sbostic 	if(child(0)) {
34439156Sbostic 		if(str = getenv("SHELL"))
34539156Sbostic 			execl(str, str, (char *) 0);
34639156Sbostic 		else
34739156Sbostic 			execl("/bin/sh", "sh", (char *) 0);
34839156Sbostic 		pline("sh: cannot execute.");
34939156Sbostic 		exit(1);
35039156Sbostic 	}
35139156Sbostic 	return(0);
35239156Sbostic }
35339156Sbostic #endif SHELL
35439156Sbostic 
35539156Sbostic #ifdef NOWAITINCLUDE
35639156Sbostic union wait {		/* used only for the cast  (union wait *) 0  */
35739156Sbostic 	int w_status;
35839156Sbostic 	struct {
35939156Sbostic 		unsigned short w_Termsig:7;
36039156Sbostic 		unsigned short w_Coredump:1;
36139156Sbostic 		unsigned short w_Retcode:8;
36239156Sbostic 	} w_T;
36339156Sbostic };
36439156Sbostic 
36539156Sbostic #else
36639156Sbostic 
36739156Sbostic #ifdef BSD
36839156Sbostic #include	<sys/wait.h>
36939156Sbostic #else
37039156Sbostic #include	<wait.h>
37139156Sbostic #endif BSD
37239156Sbostic #endif NOWAITINCLUDE
37339156Sbostic 
child(wt)37439156Sbostic child(wt) {
375*47700Sbostic 	int status;
376*47700Sbostic 	register int f;
377*47700Sbostic 
378*47700Sbostic 	f = fork();
37939156Sbostic 	if(f == 0){		/* child */
38039156Sbostic 		settty((char *) 0);		/* also calls end_screen() */
38139156Sbostic 		(void) setuid(getuid());
38239156Sbostic 		(void) setgid(getgid());
38339156Sbostic #ifdef CHDIR
38439156Sbostic 		(void) chdir(getenv("HOME"));
38539156Sbostic #endif CHDIR
38639156Sbostic 		return(1);
38739156Sbostic 	}
38839156Sbostic 	if(f == -1) {	/* cannot fork */
38939156Sbostic 		pline("Fork failed. Try again.");
39039156Sbostic 		return(0);
39139156Sbostic 	}
39239156Sbostic 	/* fork succeeded; wait for child to exit */
39339156Sbostic 	(void) signal(SIGINT,SIG_IGN);
39439156Sbostic 	(void) signal(SIGQUIT,SIG_IGN);
395*47700Sbostic 	(void) wait(&status);
39639156Sbostic 	gettty();
39739156Sbostic 	setftty();
39839156Sbostic 	(void) signal(SIGINT,done1);
39939156Sbostic #ifdef WIZARD
40039156Sbostic 	if(wizard) (void) signal(SIGQUIT,SIG_DFL);
40139156Sbostic #endif WIZARD
40239156Sbostic 	if(wt) getret();
40339156Sbostic 	docrt();
40439156Sbostic 	return(0);
40539156Sbostic }
40639156Sbostic #endif UNIX
407