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