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