123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495 |
- /* $NetBSD: hack.pager.c,v 1.7 2003/04/02 18:36:39 jsm Exp $ */
- /*
- * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
- * Amsterdam
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * - Neither the name of the Stichting Centrum voor Wiskunde en
- * Informatica, nor the names of its contributors may be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- /*
- * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include <sys/cdefs.h>
- #ifndef lint
- __RCSID("$NetBSD: hack.pager.c,v 1.7 2003/04/02 18:36:39 jsm Exp $");
- #endif /* not lint */
- /* This file contains the command routine dowhatis() and a pager. */
- /*
- * Also readmail() and doshell(), and generally the things that contact the
- * outside world.
- */
- #include <sys/types.h>
- #include <signal.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include "hack.h"
- #include "extern.h"
- int
- dowhatis()
- {
- FILE *fp;
- char bufr[BUFSZ + 6];
- char *buf = &bufr[6], *ep, q;
- if (!(fp = fopen(DATAFILE, "r")))
- pline("Cannot open data file!");
- else {
- pline("Specify what? ");
- q = readchar();
- if (q != '\t')
- while (fgets(buf, BUFSZ, fp))
- if (*buf == q) {
- ep = strchr(buf, '\n');
- if (ep)
- *ep = 0;
- /* else: bad data file */
- /* Expand tab 'by hand' */
- if (buf[1] == '\t') {
- buf = bufr;
- buf[0] = q;
- (void) strncpy(buf + 1, " ", 7);
- }
- pline(buf);
- if (ep[-1] == ';') {
- pline("More info? ");
- if (readchar() == 'y') {
- page_more(fp, 1); /* does fclose() */
- return (0);
- }
- }
- (void) fclose(fp); /* kopper@psuvax1 */
- return (0);
- }
- pline("I've never heard of such things.");
- (void) fclose(fp);
- }
- return (0);
- }
- /* make the paging of a file interruptible */
- static int got_intrup;
- void
- intruph(n)
- int n __attribute__((__unused__));
- {
- got_intrup++;
- }
- /* simple pager, also used from dohelp() */
- void
- page_more(fp, strip)
- FILE *fp;
- int strip; /* nr of chars to be stripped from each line
- * (0 or 1) */
- {
- char *bufr, *ep;
- sig_t prevsig = signal(SIGINT, intruph);
- set_pager(0);
- bufr = (char *) alloc((unsigned) CO);
- bufr[CO - 1] = 0;
- while (fgets(bufr, CO - 1, fp) && (!strip || *bufr == '\t') && !got_intrup) {
- ep = strchr(bufr, '\n');
- if (ep)
- *ep = 0;
- if (page_line(bufr + strip)) {
- set_pager(2);
- goto ret;
- }
- }
- set_pager(1);
- ret:
- free(bufr);
- (void) fclose(fp);
- (void) signal(SIGINT, prevsig);
- got_intrup = 0;
- }
- static boolean whole_screen = TRUE;
- #define PAGMIN 12 /* minimum # of lines for page below level
- * map */
- void
- set_whole_screen()
- { /* called in termcap as soon as LI is known */
- whole_screen = (LI - ROWNO - 2 <= PAGMIN || !CD);
- }
- #ifdef NEWS
- int
- readnews()
- {
- int ret;
- whole_screen = TRUE; /* force a docrt(), our first */
- ret = page_file(NEWS, TRUE);
- set_whole_screen();
- return (ret); /* report whether we did docrt() */
- }
- #endif /* NEWS */
- void
- set_pager(mode)
- int mode; /* 0: open 1: wait+close 2: close */
- {
- static boolean so;
- if (mode == 0) {
- if (!whole_screen) {
- /* clear topline */
- clrlin();
- /* use part of screen below level map */
- curs(1, ROWNO + 4);
- } else {
- cls();
- }
- so = flags.standout;
- flags.standout = 1;
- } else {
- if (mode == 1) {
- curs(1, LI);
- more();
- }
- flags.standout = so;
- if (whole_screen)
- docrt();
- else {
- curs(1, ROWNO + 4);
- cl_eos();
- }
- }
- }
- int
- page_line(s) /* returns 1 if we should quit */
- const char *s;
- {
- if (cury == LI - 1) {
- if (!*s)
- return (0); /* suppress blank lines at top */
- putchar('\n');
- cury++;
- cmore("q\033");
- if (morc) {
- morc = 0;
- return (1);
- }
- if (whole_screen)
- cls();
- else {
- curs(1, ROWNO + 4);
- cl_eos();
- }
- }
- puts(s);
- cury++;
- return (0);
- }
- /*
- * Flexible pager: feed it with a number of lines and it will decide
- * whether these should be fed to the pager above, or displayed in a
- * corner.
- * Call:
- * cornline(0, title or 0) : initialize
- * cornline(1, text) : add text to the chain of texts
- * cornline(2, morcs) : output everything and cleanup
- * cornline(3, 0) : cleanup
- */
- void
- cornline(mode, text)
- int mode;
- const char *text;
- {
- static struct line {
- struct line *next_line;
- char *line_text;
- } *texthead, *texttail;
- static int maxlen;
- static int linect;
- struct line *tl;
- if (mode == 0) {
- texthead = 0;
- maxlen = 0;
- linect = 0;
- if (text) {
- cornline(1, text); /* title */
- cornline(1, ""); /* blank line */
- }
- return;
- }
- if (mode == 1) {
- int len;
- if (!text)
- return; /* superfluous, just to be sure */
- linect++;
- len = strlen(text);
- if (len > maxlen)
- maxlen = len;
- tl = (struct line *)
- alloc((unsigned) (len + sizeof(struct line) + 1));
- tl->next_line = 0;
- tl->line_text = (char *) (tl + 1);
- (void) strcpy(tl->line_text, text);
- if (!texthead)
- texthead = tl;
- else
- texttail->next_line = tl;
- texttail = tl;
- return;
- }
- /* --- now we really do it --- */
- if (mode == 2 && linect == 1) /* topline only */
- pline(texthead->line_text);
- else if (mode == 2) {
- int curline, lth;
- if (flags.toplin == 1)
- more(); /* ab@unido */
- remember_topl();
- lth = CO - maxlen - 2; /* Use full screen width */
- if (linect < LI && lth >= 10) { /* in a corner */
- home();
- cl_end();
- flags.toplin = 0;
- curline = 1;
- for (tl = texthead; tl; tl = tl->next_line) {
- curs(lth, curline);
- if (curline > 1)
- cl_end();
- putsym(' ');
- putstr(tl->line_text);
- curline++;
- }
- curs(lth, curline);
- cl_end();
- cmore(text);
- home();
- cl_end();
- docorner(lth, curline - 1);
- } else { /* feed to pager */
- set_pager(0);
- for (tl = texthead; tl; tl = tl->next_line) {
- if (page_line(tl->line_text)) {
- set_pager(2);
- goto cleanup;
- }
- }
- if (text) {
- cgetret(text);
- set_pager(2);
- } else
- set_pager(1);
- }
- }
- cleanup:
- while ((tl = texthead) != NULL) {
- texthead = tl->next_line;
- free((char *) tl);
- }
- }
- int
- dohelp()
- {
- char c;
- pline("Long or short help? ");
- while (((c = readchar()) != 'l') && (c != 's') && !strchr(quitchars, c))
- bell();
- if (!strchr(quitchars, c))
- (void) page_file((c == 'l') ? HELP : SHELP, FALSE);
- return (0);
- }
- int
- page_file(fnam, silent) /* return: 0 - cannot open fnam; 1 -
- * otherwise */
- const char *fnam;
- boolean silent;
- {
- #ifdef DEF_PAGER /* this implies that UNIX is defined */
- {
- /* use external pager; this may give security problems */
- int fd = open(fnam, O_RDONLY);
- if (fd < 0) {
- if (!silent)
- pline("Cannot open %s.", fnam);
- return (0);
- }
- if (child(1)) {
- /*
- * Now that child() does a setuid(getuid()) and a
- * chdir(), we may not be able to open file fnam
- * anymore, so make it stdin.
- */
- (void) close(0);
- if (dup(fd)) {
- if (!silent)
- printf("Cannot open %s as stdin.\n", fnam);
- } else {
- execl(catmore, "page", (char *) 0);
- if (!silent)
- printf("Cannot exec %s.\n", catmore);
- }
- exit(1);
- }
- (void) close(fd);
- }
- #else /* DEF_PAGER */
- {
- FILE *f; /* free after Robert Viduya */
- if ((f = fopen(fnam, "r")) == (FILE *) 0) {
- if (!silent) {
- home();
- perror(fnam);
- flags.toplin = 1;
- pline("Cannot open %s.", fnam);
- }
- return (0);
- }
- page_more(f, 0);
- }
- #endif /* DEF_PAGER */
- return (1);
- }
- #ifdef UNIX
- #ifdef SHELL
- int
- dosh()
- {
- char *str;
- if (child(0)) {
- if ((str = getenv("SHELL")) != NULL)
- execl(str, str, (char *) 0);
- else
- execl("/bin/sh", "sh", (char *) 0);
- pline("sh: cannot execute.");
- exit(1);
- }
- return (0);
- }
- #endif /* SHELL */
- #ifdef NOWAITINCLUDE
- union wait { /* used only for the cast (union wait *) 0 */
- int w_status;
- struct {
- unsigned short w_Termsig:7;
- unsigned short w_Coredump:1;
- unsigned short w_Retcode:8;
- } w_T;
- };
- #else
- #ifdef BSD
- #include <sys/wait.h>
- #else
- #include <wait.h>
- #endif /* BSD */
- #endif /* NOWAITINCLUDE */
- int
- child(int wt)
- {
- int status;
- int f;
- f = fork();
- if (f == 0) { /* child */
- settty((char *) 0); /* also calls end_screen() */
- (void) setuid(getuid());
- (void) setgid(getgid());
- #ifdef CHDIR
- (void) chdir(getenv("HOME"));
- #endif /* CHDIR */
- return (1);
- }
- if (f == -1) { /* cannot fork */
- pline("Fork failed. Try again.");
- return (0);
- }
- /* fork succeeded; wait for child to exit */
- (void) signal(SIGINT, SIG_IGN);
- (void) signal(SIGQUIT, SIG_IGN);
- (void) wait(&status);
- gettty();
- setftty();
- (void) signal(SIGINT, done1);
- #ifdef WIZARD
- if (wizard)
- (void) signal(SIGQUIT, SIG_DFL);
- #endif /* WIZARD */
- if (wt)
- getret();
- docrt();
- return (0);
- }
- #endif /* UNIX */
|