1 /* $NetBSD: hack.pager.c,v 1.12 2009/06/07 18:30:39 dholland 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.12 2009/06/07 18:30:39 dholland 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(void) 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 else { 102 pline("Bad data file!"); 103 (void) fclose(fp); 104 return(0); 105 } 106 /* Expand tab 'by hand' */ 107 if (buf[1] == '\t') { 108 buf = bufr; 109 buf[0] = q; 110 (void) strncpy(buf + 1, " ", 7); 111 } 112 pline(buf); 113 if (ep[-1] == ';') { 114 pline("More info? "); 115 if (readchar() == 'y') { 116 page_more(fp, 1); /* does fclose() */ 117 return (0); 118 } 119 } 120 (void) fclose(fp); /* kopper@psuvax1 */ 121 return (0); 122 } 123 pline("I've never heard of such things."); 124 (void) fclose(fp); 125 } 126 return (0); 127 } 128 129 /* make the paging of a file interruptible */ 130 static int got_intrup; 131 132 void 133 intruph(int n __unused) 134 { 135 got_intrup++; 136 } 137 138 /* simple pager, also used from dohelp() */ 139 /* strip: nr of chars to be stripped from each line (0 or 1) */ 140 void 141 page_more(FILE *fp, int strip) 142 { 143 char *bufr, *ep; 144 sig_t prevsig = signal(SIGINT, intruph); 145 146 set_pager(0); 147 bufr = (char *) alloc((unsigned) CO); 148 bufr[CO - 1] = 0; 149 while (fgets(bufr, CO - 1, fp) && (!strip || *bufr == '\t') && !got_intrup) { 150 ep = strchr(bufr, '\n'); 151 if (ep) 152 *ep = 0; 153 if (page_line(bufr + strip)) { 154 set_pager(2); 155 goto ret; 156 } 157 } 158 set_pager(1); 159 ret: 160 free(bufr); 161 (void) fclose(fp); 162 (void) signal(SIGINT, prevsig); 163 got_intrup = 0; 164 } 165 166 static boolean whole_screen = TRUE; 167 #define PAGMIN 12 /* minimum # of lines for page below level 168 * map */ 169 170 void 171 set_whole_screen(void) 172 { /* called in termcap as soon as LI is known */ 173 whole_screen = (LI - ROWNO - 2 <= PAGMIN || !CD); 174 } 175 176 #ifdef NEWS 177 int 178 readnews(void) 179 { 180 int ret; 181 182 whole_screen = TRUE; /* force a docrt(), our first */ 183 ret = page_file(NEWS, TRUE); 184 set_whole_screen(); 185 return (ret); /* report whether we did docrt() */ 186 } 187 #endif /* NEWS */ 188 189 /* mode: 0: open 1: wait+close 2: close */ 190 void 191 set_pager(int mode) 192 { 193 static boolean so; 194 if (mode == 0) { 195 if (!whole_screen) { 196 /* clear topline */ 197 clrlin(); 198 /* use part of screen below level map */ 199 curs(1, ROWNO + 4); 200 } else { 201 cls(); 202 } 203 so = flags.standout; 204 flags.standout = 1; 205 } else { 206 if (mode == 1) { 207 curs(1, LI); 208 more(); 209 } 210 flags.standout = so; 211 if (whole_screen) 212 docrt(); 213 else { 214 curs(1, ROWNO + 4); 215 cl_eos(); 216 } 217 } 218 } 219 220 int 221 page_line(const char *s) /* returns 1 if we should quit */ 222 { 223 if (cury == LI - 1) { 224 if (!*s) 225 return (0); /* suppress blank lines at top */ 226 putchar('\n'); 227 cury++; 228 cmore("q\033"); 229 if (morc) { 230 morc = 0; 231 return (1); 232 } 233 if (whole_screen) 234 cls(); 235 else { 236 curs(1, ROWNO + 4); 237 cl_eos(); 238 } 239 } 240 puts(s); 241 cury++; 242 return (0); 243 } 244 245 /* 246 * Flexible pager: feed it with a number of lines and it will decide 247 * whether these should be fed to the pager above, or displayed in a 248 * corner. 249 * Call: 250 * cornline(0, title or 0) : initialize 251 * cornline(1, text) : add text to the chain of texts 252 * cornline(2, morcs) : output everything and cleanup 253 * cornline(3, 0) : cleanup 254 */ 255 256 void 257 cornline(int mode, const char *text) 258 { 259 static struct line { 260 struct line *next_line; 261 char *line_text; 262 } *texthead, *texttail; 263 static int maxlen; 264 static int linect; 265 struct line *tl; 266 267 if (mode == 0) { 268 texthead = 0; 269 maxlen = 0; 270 linect = 0; 271 if (text) { 272 cornline(1, text); /* title */ 273 cornline(1, ""); /* blank line */ 274 } 275 return; 276 } 277 if (mode == 1) { 278 int len; 279 280 if (!text) 281 return; /* superfluous, just to be sure */ 282 linect++; 283 len = strlen(text); 284 if (len > maxlen) 285 maxlen = len; 286 tl = (struct line *) 287 alloc((unsigned) (len + sizeof(struct line) + 1)); 288 tl->next_line = 0; 289 tl->line_text = (char *) (tl + 1); 290 (void) strcpy(tl->line_text, text); 291 if (!texthead) 292 texthead = tl; 293 else 294 texttail->next_line = tl; 295 texttail = tl; 296 return; 297 } 298 /* --- now we really do it --- */ 299 if (mode == 2 && linect == 1) /* topline only */ 300 pline(texthead->line_text); 301 else if (mode == 2) { 302 int curline, lth; 303 304 if (flags.toplin == 1) 305 more(); /* ab@unido */ 306 remember_topl(); 307 308 lth = CO - maxlen - 2; /* Use full screen width */ 309 if (linect < LI && lth >= 10) { /* in a corner */ 310 home(); 311 cl_end(); 312 flags.toplin = 0; 313 curline = 1; 314 for (tl = texthead; tl; tl = tl->next_line) { 315 curs(lth, curline); 316 if (curline > 1) 317 cl_end(); 318 putsym(' '); 319 putstr(tl->line_text); 320 curline++; 321 } 322 curs(lth, curline); 323 cl_end(); 324 cmore(text); 325 home(); 326 cl_end(); 327 docorner(lth, curline - 1); 328 } else { /* feed to pager */ 329 set_pager(0); 330 for (tl = texthead; tl; tl = tl->next_line) { 331 if (page_line(tl->line_text)) { 332 set_pager(2); 333 goto cleanup; 334 } 335 } 336 if (text) { 337 cgetret(text); 338 set_pager(2); 339 } else 340 set_pager(1); 341 } 342 } 343 cleanup: 344 while ((tl = texthead) != NULL) { 345 texthead = tl->next_line; 346 free((char *) tl); 347 } 348 } 349 350 int 351 dohelp(void) 352 { 353 char c; 354 355 pline("Long or short help? "); 356 while (((c = readchar()) != 'l') && (c != 's') && !strchr(quitchars, c)) 357 bell(); 358 if (!strchr(quitchars, c)) 359 (void) page_file((c == 'l') ? HELP : SHELP, FALSE); 360 return (0); 361 } 362 363 /* return: 0 - cannot open fnam; 1 - otherwise */ 364 int 365 page_file(const char *fnam, boolean silent) 366 { 367 #ifdef DEF_PAGER /* this implies that UNIX is defined */ 368 { 369 /* use external pager; this may give security problems */ 370 371 int fd = open(fnam, O_RDONLY); 372 373 if (fd < 0) { 374 if (!silent) 375 pline("Cannot open %s.", fnam); 376 return (0); 377 } 378 if (child(1)) { 379 380 /* 381 * Now that child() does a setuid(getuid()) and a 382 * chdir(), we may not be able to open file fnam 383 * anymore, so make it stdin. 384 */ 385 (void) close(0); 386 if (dup(fd)) { 387 if (!silent) 388 printf("Cannot open %s as stdin.\n", fnam); 389 } else { 390 execl(catmore, "page", (char *) 0); 391 if (!silent) 392 printf("Cannot exec %s.\n", catmore); 393 } 394 exit(1); 395 } 396 (void) close(fd); 397 } 398 #else /* DEF_PAGER */ 399 { 400 FILE *f; /* free after Robert Viduya */ 401 402 if ((f = fopen(fnam, "r")) == (FILE *) 0) { 403 if (!silent) { 404 home(); 405 perror(fnam); 406 flags.toplin = 1; 407 pline("Cannot open %s.", fnam); 408 } 409 return (0); 410 } 411 page_more(f, 0); 412 } 413 #endif /* DEF_PAGER */ 414 415 return (1); 416 } 417 418 #ifdef UNIX 419 #ifdef SHELL 420 int 421 dosh(void) 422 { 423 char *str; 424 if (child(0)) { 425 if ((str = getenv("SHELL")) != NULL) 426 execl(str, str, (char *) 0); 427 else 428 execl("/bin/sh", "sh", (char *) 0); 429 pline("sh: cannot execute."); 430 exit(1); 431 } 432 return (0); 433 } 434 #endif /* SHELL */ 435 436 #ifdef NOWAITINCLUDE 437 union wait { /* used only for the cast (union wait *) 0 */ 438 int w_status; 439 struct { 440 unsigned short w_Termsig:7; 441 unsigned short w_Coredump:1; 442 unsigned short w_Retcode:8; 443 } w_T; 444 }; 445 446 #else 447 448 #ifdef BSD 449 #include <sys/wait.h> 450 #else 451 #include <wait.h> 452 #endif /* BSD */ 453 #endif /* NOWAITINCLUDE */ 454 455 int 456 child(int wt) 457 { 458 int status; 459 int f; 460 461 f = fork(); 462 if (f == 0) { /* child */ 463 settty((char *) 0); /* also calls end_screen() */ 464 (void) setuid(getuid()); 465 (void) setgid(getgid()); 466 #ifdef CHDIR 467 (void) chdir(getenv("HOME")); 468 #endif /* CHDIR */ 469 return (1); 470 } 471 if (f == -1) { /* cannot fork */ 472 pline("Fork failed. Try again."); 473 return (0); 474 } 475 /* fork succeeded; wait for child to exit */ 476 (void) signal(SIGINT, SIG_IGN); 477 (void) signal(SIGQUIT, SIG_IGN); 478 (void) wait(&status); 479 gettty(); 480 setftty(); 481 (void) signal(SIGINT, done1); 482 #ifdef WIZARD 483 if (wizard) 484 (void) signal(SIGQUIT, SIG_DFL); 485 #endif /* WIZARD */ 486 if (wt) 487 getret(); 488 docrt(); 489 return (0); 490 } 491 #endif /* UNIX */ 492