1 /* $NetBSD: hack.pager.c,v 1.7 2003/04/02 18:36:39 jsm Exp $ */ 2 3 /* 4 * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica, 5 * Amsterdam 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are 10 * met: 11 * 12 * - Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 15 * - Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * - Neither the name of the Stichting Centrum voor Wiskunde en 20 * Informatica, nor the names of its contributors may be used to endorse or 21 * promote products derived from this software without specific prior 22 * written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 25 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 27 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 28 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 30 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 31 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37 /* 38 * Copyright (c) 1982 Jay Fenlason <hack@gnu.org> 39 * All rights reserved. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 3. The name of the author may not be used to endorse or promote products 50 * derived from this software without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 53 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 54 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 55 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 56 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 57 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 58 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 59 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 60 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 61 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 62 */ 63 64 #include <sys/cdefs.h> 65 #ifndef lint 66 __RCSID("$NetBSD: hack.pager.c,v 1.7 2003/04/02 18:36:39 jsm Exp $"); 67 #endif /* not lint */ 68 69 /* This file contains the command routine dowhatis() and a pager. */ 70 /* 71 * Also readmail() and doshell(), and generally the things that contact the 72 * outside world. 73 */ 74 75 #include <sys/types.h> 76 #include <signal.h> 77 #include <stdlib.h> 78 #include <unistd.h> 79 #include "hack.h" 80 #include "extern.h" 81 82 int 83 dowhatis() 84 { 85 FILE *fp; 86 char bufr[BUFSZ + 6]; 87 char *buf = &bufr[6], *ep, q; 88 89 if (!(fp = fopen(DATAFILE, "r"))) 90 pline("Cannot open data file!"); 91 else { 92 pline("Specify what? "); 93 q = readchar(); 94 if (q != '\t') 95 while (fgets(buf, BUFSZ, fp)) 96 if (*buf == q) { 97 ep = strchr(buf, '\n'); 98 if (ep) 99 *ep = 0; 100 /* else: bad data file */ 101 /* Expand tab 'by hand' */ 102 if (buf[1] == '\t') { 103 buf = bufr; 104 buf[0] = q; 105 (void) strncpy(buf + 1, " ", 7); 106 } 107 pline(buf); 108 if (ep[-1] == ';') { 109 pline("More info? "); 110 if (readchar() == 'y') { 111 page_more(fp, 1); /* does fclose() */ 112 return (0); 113 } 114 } 115 (void) fclose(fp); /* kopper@psuvax1 */ 116 return (0); 117 } 118 pline("I've never heard of such things."); 119 (void) fclose(fp); 120 } 121 return (0); 122 } 123 124 /* make the paging of a file interruptible */ 125 static int got_intrup; 126 127 void 128 intruph(n) 129 int n __attribute__((__unused__)); 130 { 131 got_intrup++; 132 } 133 134 /* simple pager, also used from dohelp() */ 135 void 136 page_more(fp, strip) 137 FILE *fp; 138 int strip; /* nr of chars to be stripped from each line 139 * (0 or 1) */ 140 { 141 char *bufr, *ep; 142 sig_t prevsig = signal(SIGINT, intruph); 143 144 set_pager(0); 145 bufr = (char *) alloc((unsigned) CO); 146 bufr[CO - 1] = 0; 147 while (fgets(bufr, CO - 1, fp) && (!strip || *bufr == '\t') && !got_intrup) { 148 ep = strchr(bufr, '\n'); 149 if (ep) 150 *ep = 0; 151 if (page_line(bufr + strip)) { 152 set_pager(2); 153 goto ret; 154 } 155 } 156 set_pager(1); 157 ret: 158 free(bufr); 159 (void) fclose(fp); 160 (void) signal(SIGINT, prevsig); 161 got_intrup = 0; 162 } 163 164 static boolean whole_screen = TRUE; 165 #define PAGMIN 12 /* minimum # of lines for page below level 166 * map */ 167 168 void 169 set_whole_screen() 170 { /* called in termcap as soon as LI is known */ 171 whole_screen = (LI - ROWNO - 2 <= PAGMIN || !CD); 172 } 173 174 #ifdef NEWS 175 int 176 readnews() 177 { 178 int ret; 179 180 whole_screen = TRUE; /* force a docrt(), our first */ 181 ret = page_file(NEWS, TRUE); 182 set_whole_screen(); 183 return (ret); /* report whether we did docrt() */ 184 } 185 #endif /* NEWS */ 186 187 void 188 set_pager(mode) 189 int mode; /* 0: open 1: wait+close 2: close */ 190 { 191 static boolean so; 192 if (mode == 0) { 193 if (!whole_screen) { 194 /* clear topline */ 195 clrlin(); 196 /* use part of screen below level map */ 197 curs(1, ROWNO + 4); 198 } else { 199 cls(); 200 } 201 so = flags.standout; 202 flags.standout = 1; 203 } else { 204 if (mode == 1) { 205 curs(1, LI); 206 more(); 207 } 208 flags.standout = so; 209 if (whole_screen) 210 docrt(); 211 else { 212 curs(1, ROWNO + 4); 213 cl_eos(); 214 } 215 } 216 } 217 218 int 219 page_line(s) /* returns 1 if we should quit */ 220 const char *s; 221 { 222 if (cury == LI - 1) { 223 if (!*s) 224 return (0); /* suppress blank lines at top */ 225 putchar('\n'); 226 cury++; 227 cmore("q\033"); 228 if (morc) { 229 morc = 0; 230 return (1); 231 } 232 if (whole_screen) 233 cls(); 234 else { 235 curs(1, ROWNO + 4); 236 cl_eos(); 237 } 238 } 239 puts(s); 240 cury++; 241 return (0); 242 } 243 244 /* 245 * Flexible pager: feed it with a number of lines and it will decide 246 * whether these should be fed to the pager above, or displayed in a 247 * corner. 248 * Call: 249 * cornline(0, title or 0) : initialize 250 * cornline(1, text) : add text to the chain of texts 251 * cornline(2, morcs) : output everything and cleanup 252 * cornline(3, 0) : cleanup 253 */ 254 255 void 256 cornline(mode, text) 257 int mode; 258 const char *text; 259 { 260 static struct line { 261 struct line *next_line; 262 char *line_text; 263 } *texthead, *texttail; 264 static int maxlen; 265 static int linect; 266 struct line *tl; 267 268 if (mode == 0) { 269 texthead = 0; 270 maxlen = 0; 271 linect = 0; 272 if (text) { 273 cornline(1, text); /* title */ 274 cornline(1, ""); /* blank line */ 275 } 276 return; 277 } 278 if (mode == 1) { 279 int len; 280 281 if (!text) 282 return; /* superfluous, just to be sure */ 283 linect++; 284 len = strlen(text); 285 if (len > maxlen) 286 maxlen = len; 287 tl = (struct line *) 288 alloc((unsigned) (len + sizeof(struct line) + 1)); 289 tl->next_line = 0; 290 tl->line_text = (char *) (tl + 1); 291 (void) strcpy(tl->line_text, text); 292 if (!texthead) 293 texthead = tl; 294 else 295 texttail->next_line = tl; 296 texttail = tl; 297 return; 298 } 299 /* --- now we really do it --- */ 300 if (mode == 2 && linect == 1) /* topline only */ 301 pline(texthead->line_text); 302 else if (mode == 2) { 303 int curline, lth; 304 305 if (flags.toplin == 1) 306 more(); /* ab@unido */ 307 remember_topl(); 308 309 lth = CO - maxlen - 2; /* Use full screen width */ 310 if (linect < LI && lth >= 10) { /* in a corner */ 311 home(); 312 cl_end(); 313 flags.toplin = 0; 314 curline = 1; 315 for (tl = texthead; tl; tl = tl->next_line) { 316 curs(lth, curline); 317 if (curline > 1) 318 cl_end(); 319 putsym(' '); 320 putstr(tl->line_text); 321 curline++; 322 } 323 curs(lth, curline); 324 cl_end(); 325 cmore(text); 326 home(); 327 cl_end(); 328 docorner(lth, curline - 1); 329 } else { /* feed to pager */ 330 set_pager(0); 331 for (tl = texthead; tl; tl = tl->next_line) { 332 if (page_line(tl->line_text)) { 333 set_pager(2); 334 goto cleanup; 335 } 336 } 337 if (text) { 338 cgetret(text); 339 set_pager(2); 340 } else 341 set_pager(1); 342 } 343 } 344 cleanup: 345 while ((tl = texthead) != NULL) { 346 texthead = tl->next_line; 347 free((char *) tl); 348 } 349 } 350 351 int 352 dohelp() 353 { 354 char c; 355 356 pline("Long or short help? "); 357 while (((c = readchar()) != 'l') && (c != 's') && !strchr(quitchars, c)) 358 bell(); 359 if (!strchr(quitchars, c)) 360 (void) page_file((c == 'l') ? HELP : SHELP, FALSE); 361 return (0); 362 } 363 364 int 365 page_file(fnam, silent) /* return: 0 - cannot open fnam; 1 - 366 * otherwise */ 367 const char *fnam; 368 boolean silent; 369 { 370 #ifdef DEF_PAGER /* this implies that UNIX is defined */ 371 { 372 /* use external pager; this may give security problems */ 373 374 int fd = open(fnam, O_RDONLY); 375 376 if (fd < 0) { 377 if (!silent) 378 pline("Cannot open %s.", fnam); 379 return (0); 380 } 381 if (child(1)) { 382 383 /* 384 * Now that child() does a setuid(getuid()) and a 385 * chdir(), we may not be able to open file fnam 386 * anymore, so make it stdin. 387 */ 388 (void) close(0); 389 if (dup(fd)) { 390 if (!silent) 391 printf("Cannot open %s as stdin.\n", fnam); 392 } else { 393 execl(catmore, "page", (char *) 0); 394 if (!silent) 395 printf("Cannot exec %s.\n", catmore); 396 } 397 exit(1); 398 } 399 (void) close(fd); 400 } 401 #else /* DEF_PAGER */ 402 { 403 FILE *f; /* free after Robert Viduya */ 404 405 if ((f = fopen(fnam, "r")) == (FILE *) 0) { 406 if (!silent) { 407 home(); 408 perror(fnam); 409 flags.toplin = 1; 410 pline("Cannot open %s.", fnam); 411 } 412 return (0); 413 } 414 page_more(f, 0); 415 } 416 #endif /* DEF_PAGER */ 417 418 return (1); 419 } 420 421 #ifdef UNIX 422 #ifdef SHELL 423 int 424 dosh() 425 { 426 char *str; 427 if (child(0)) { 428 if ((str = getenv("SHELL")) != NULL) 429 execl(str, str, (char *) 0); 430 else 431 execl("/bin/sh", "sh", (char *) 0); 432 pline("sh: cannot execute."); 433 exit(1); 434 } 435 return (0); 436 } 437 #endif /* SHELL */ 438 439 #ifdef NOWAITINCLUDE 440 union wait { /* used only for the cast (union wait *) 0 */ 441 int w_status; 442 struct { 443 unsigned short w_Termsig:7; 444 unsigned short w_Coredump:1; 445 unsigned short w_Retcode:8; 446 } w_T; 447 }; 448 449 #else 450 451 #ifdef BSD 452 #include <sys/wait.h> 453 #else 454 #include <wait.h> 455 #endif /* BSD */ 456 #endif /* NOWAITINCLUDE */ 457 458 int 459 child(int wt) 460 { 461 int status; 462 int f; 463 464 f = fork(); 465 if (f == 0) { /* child */ 466 settty((char *) 0); /* also calls end_screen() */ 467 (void) setuid(getuid()); 468 (void) setgid(getgid()); 469 #ifdef CHDIR 470 (void) chdir(getenv("HOME")); 471 #endif /* CHDIR */ 472 return (1); 473 } 474 if (f == -1) { /* cannot fork */ 475 pline("Fork failed. Try again."); 476 return (0); 477 } 478 /* fork succeeded; wait for child to exit */ 479 (void) signal(SIGINT, SIG_IGN); 480 (void) signal(SIGQUIT, SIG_IGN); 481 (void) wait(&status); 482 gettty(); 483 setftty(); 484 (void) signal(SIGINT, done1); 485 #ifdef WIZARD 486 if (wizard) 487 (void) signal(SIGQUIT, SIG_DFL); 488 #endif /* WIZARD */ 489 if (wt) 490 getret(); 491 docrt(); 492 return (0); 493 } 494 #endif /* UNIX */ 495