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 8*45770Sbostic #include <sys/types.h> 9*45770Sbostic #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(); 1639156Sbostic int done1(); 1739156Sbostic 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 6339156Sbostic intruph(){ 6439156Sbostic got_intrup++; 6539156Sbostic } 6639156Sbostic 6739156Sbostic /* simple pager, also used from dohelp() */ 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 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 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 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 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 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 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 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 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 37439156Sbostic child(wt) { 37539156Sbostic register int f = fork(); 37639156Sbostic if(f == 0){ /* child */ 37739156Sbostic settty((char *) 0); /* also calls end_screen() */ 37839156Sbostic (void) setuid(getuid()); 37939156Sbostic (void) setgid(getgid()); 38039156Sbostic #ifdef CHDIR 38139156Sbostic (void) chdir(getenv("HOME")); 38239156Sbostic #endif CHDIR 38339156Sbostic return(1); 38439156Sbostic } 38539156Sbostic if(f == -1) { /* cannot fork */ 38639156Sbostic pline("Fork failed. Try again."); 38739156Sbostic return(0); 38839156Sbostic } 38939156Sbostic /* fork succeeded; wait for child to exit */ 39039156Sbostic (void) signal(SIGINT,SIG_IGN); 39139156Sbostic (void) signal(SIGQUIT,SIG_IGN); 39239156Sbostic (void) wait((union wait *) 0); 39339156Sbostic gettty(); 39439156Sbostic setftty(); 39539156Sbostic (void) signal(SIGINT,done1); 39639156Sbostic #ifdef WIZARD 39739156Sbostic if(wizard) (void) signal(SIGQUIT,SIG_DFL); 39839156Sbostic #endif WIZARD 39939156Sbostic if(wt) getret(); 40039156Sbostic docrt(); 40139156Sbostic return(0); 40239156Sbostic } 40339156Sbostic #endif UNIX 404