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