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