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