1*acae6852Splunky /* $NetBSD: hack.pager.c,v 1.21 2011/09/01 07:18:50 plunky Exp $ */
23ea4a95cSchristos
3210cab45Smycroft /*
41c7f94e5Sjsm * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
51c7f94e5Sjsm * Amsterdam
61c7f94e5Sjsm * All rights reserved.
71c7f94e5Sjsm *
81c7f94e5Sjsm * Redistribution and use in source and binary forms, with or without
91c7f94e5Sjsm * modification, are permitted provided that the following conditions are
101c7f94e5Sjsm * met:
111c7f94e5Sjsm *
121c7f94e5Sjsm * - Redistributions of source code must retain the above copyright notice,
131c7f94e5Sjsm * this list of conditions and the following disclaimer.
141c7f94e5Sjsm *
151c7f94e5Sjsm * - Redistributions in binary form must reproduce the above copyright
161c7f94e5Sjsm * notice, this list of conditions and the following disclaimer in the
171c7f94e5Sjsm * documentation and/or other materials provided with the distribution.
181c7f94e5Sjsm *
191c7f94e5Sjsm * - Neither the name of the Stichting Centrum voor Wiskunde en
201c7f94e5Sjsm * Informatica, nor the names of its contributors may be used to endorse or
211c7f94e5Sjsm * promote products derived from this software without specific prior
221c7f94e5Sjsm * written permission.
231c7f94e5Sjsm *
241c7f94e5Sjsm * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
251c7f94e5Sjsm * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
261c7f94e5Sjsm * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
271c7f94e5Sjsm * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
281c7f94e5Sjsm * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
291c7f94e5Sjsm * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
301c7f94e5Sjsm * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
311c7f94e5Sjsm * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
321c7f94e5Sjsm * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
331c7f94e5Sjsm * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
341c7f94e5Sjsm * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
351c7f94e5Sjsm */
361c7f94e5Sjsm
371c7f94e5Sjsm /*
381c7f94e5Sjsm * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
391c7f94e5Sjsm * All rights reserved.
401c7f94e5Sjsm *
411c7f94e5Sjsm * Redistribution and use in source and binary forms, with or without
421c7f94e5Sjsm * modification, are permitted provided that the following conditions
431c7f94e5Sjsm * are met:
441c7f94e5Sjsm * 1. Redistributions of source code must retain the above copyright
451c7f94e5Sjsm * notice, this list of conditions and the following disclaimer.
461c7f94e5Sjsm * 2. Redistributions in binary form must reproduce the above copyright
471c7f94e5Sjsm * notice, this list of conditions and the following disclaimer in the
481c7f94e5Sjsm * documentation and/or other materials provided with the distribution.
491c7f94e5Sjsm * 3. The name of the author may not be used to endorse or promote products
501c7f94e5Sjsm * derived from this software without specific prior written permission.
511c7f94e5Sjsm *
521c7f94e5Sjsm * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
531c7f94e5Sjsm * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
541c7f94e5Sjsm * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
551c7f94e5Sjsm * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
561c7f94e5Sjsm * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
571c7f94e5Sjsm * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
581c7f94e5Sjsm * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
591c7f94e5Sjsm * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
601c7f94e5Sjsm * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
611c7f94e5Sjsm * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62210cab45Smycroft */
63210cab45Smycroft
643ea4a95cSchristos #include <sys/cdefs.h>
65210cab45Smycroft #ifndef lint
66*acae6852Splunky __RCSID("$NetBSD: hack.pager.c,v 1.21 2011/09/01 07:18:50 plunky Exp $");
67210cab45Smycroft #endif /* not lint */
6861f28255Scgd
6961f28255Scgd /* This file contains the command routine dowhatis() and a pager. */
703ea4a95cSchristos /*
713ea4a95cSchristos * Also readmail() and doshell(), and generally the things that contact the
723ea4a95cSchristos * outside world.
733ea4a95cSchristos */
7461f28255Scgd
7561f28255Scgd #include <sys/types.h>
76842dc544Sdholland #include <sys/wait.h>
77e6371e01Sjtc #include <signal.h>
78e6371e01Sjtc #include <stdlib.h>
79e6371e01Sjtc #include <unistd.h>
8061f28255Scgd #include "hack.h"
813ea4a95cSchristos #include "extern.h"
8261f28255Scgd
839b92b189Sdholland static void intruph(int);
849b92b189Sdholland static void page_more(FILE *, int);
859b92b189Sdholland static int page_file(const char *, boolean);
869b92b189Sdholland static int child(int);
879b92b189Sdholland
883ea4a95cSchristos int
dowhatis(void)891fa8a9a6Sdholland dowhatis(void)
9061f28255Scgd {
9161f28255Scgd FILE *fp;
9261f28255Scgd char bufr[BUFSZ + 6];
933ea4a95cSchristos char *buf = &bufr[6], *ep, q;
9461f28255Scgd
9561f28255Scgd if (!(fp = fopen(DATAFILE, "r")))
9661f28255Scgd pline("Cannot open data file!");
9761f28255Scgd else {
9861f28255Scgd pline("Specify what? ");
9961f28255Scgd q = readchar();
10061f28255Scgd if (q != '\t')
10161f28255Scgd while (fgets(buf, BUFSZ, fp))
10261f28255Scgd if (*buf == q) {
1033ea4a95cSchristos ep = strchr(buf, '\n');
1043ea4a95cSchristos if (ep)
1053ea4a95cSchristos *ep = 0;
10661f28255Scgd /* else: bad data file */
107db7b70f4Sjnemeth else {
108db7b70f4Sjnemeth pline("Bad data file!");
1098710461aSchristos (void) fclose(fp);
110db7b70f4Sjnemeth return(0);
111db7b70f4Sjnemeth }
11261f28255Scgd /* Expand tab 'by hand' */
11361f28255Scgd if (buf[1] == '\t') {
11461f28255Scgd buf = bufr;
11561f28255Scgd buf[0] = q;
11661f28255Scgd (void) strncpy(buf + 1, " ", 7);
11761f28255Scgd }
11857c13365Sjoerg pline("%s", buf);
11961f28255Scgd if (ep[-1] == ';') {
12061f28255Scgd pline("More info? ");
12161f28255Scgd if (readchar() == 'y') {
12261f28255Scgd page_more(fp, 1); /* does fclose() */
12361f28255Scgd return (0);
12461f28255Scgd }
12561f28255Scgd }
12661f28255Scgd (void) fclose(fp); /* kopper@psuvax1 */
12761f28255Scgd return (0);
12861f28255Scgd }
12961f28255Scgd pline("I've never heard of such things.");
13061f28255Scgd (void) fclose(fp);
13161f28255Scgd }
13261f28255Scgd return (0);
13361f28255Scgd }
13461f28255Scgd
13561f28255Scgd /* make the paging of a file interruptible */
13661f28255Scgd static int got_intrup;
13761f28255Scgd
1389b92b189Sdholland static void
intruph(int n __unused)1391fa8a9a6Sdholland intruph(int n __unused)
1403ea4a95cSchristos {
14161f28255Scgd got_intrup++;
14261f28255Scgd }
14361f28255Scgd
14461f28255Scgd /* simple pager, also used from dohelp() */
1451fa8a9a6Sdholland /* strip: nr of chars to be stripped from each line (0 or 1) */
1469b92b189Sdholland static void
page_more(FILE * fp,int strip)1471fa8a9a6Sdholland page_more(FILE *fp, int strip)
14861f28255Scgd {
1493ea4a95cSchristos char *bufr, *ep;
15061f28255Scgd sig_t prevsig = signal(SIGINT, intruph);
15161f28255Scgd
15261f28255Scgd set_pager(0);
153434d266eSdholland bufr = alloc(CO);
15461f28255Scgd bufr[CO - 1] = 0;
15561f28255Scgd while (fgets(bufr, CO - 1, fp) && (!strip || *bufr == '\t') && !got_intrup) {
1563ea4a95cSchristos ep = strchr(bufr, '\n');
15761f28255Scgd if (ep)
15861f28255Scgd *ep = 0;
15961f28255Scgd if (page_line(bufr + strip)) {
16061f28255Scgd set_pager(2);
16161f28255Scgd goto ret;
16261f28255Scgd }
16361f28255Scgd }
16461f28255Scgd set_pager(1);
16561f28255Scgd ret:
16661f28255Scgd free(bufr);
16761f28255Scgd (void) fclose(fp);
16861f28255Scgd (void) signal(SIGINT, prevsig);
16961f28255Scgd got_intrup = 0;
17061f28255Scgd }
17161f28255Scgd
17261f28255Scgd static boolean whole_screen = TRUE;
1733ea4a95cSchristos #define PAGMIN 12 /* minimum # of lines for page below level
1743ea4a95cSchristos * map */
17561f28255Scgd
1763ea4a95cSchristos void
set_whole_screen(void)1771fa8a9a6Sdholland set_whole_screen(void)
1783ea4a95cSchristos { /* called in termcap as soon as LI is known */
17961f28255Scgd whole_screen = (LI - ROWNO - 2 <= PAGMIN || !CD);
18061f28255Scgd }
18161f28255Scgd
18261f28255Scgd #ifdef NEWS
1833ea4a95cSchristos int
readnews(void)1841fa8a9a6Sdholland readnews(void)
1853ea4a95cSchristos {
1863ea4a95cSchristos int ret;
18761f28255Scgd
18861f28255Scgd whole_screen = TRUE; /* force a docrt(), our first */
18961f28255Scgd ret = page_file(NEWS, TRUE);
19061f28255Scgd set_whole_screen();
19161f28255Scgd return (ret); /* report whether we did docrt() */
19261f28255Scgd }
1933ea4a95cSchristos #endif /* NEWS */
19461f28255Scgd
1951fa8a9a6Sdholland /* mode: 0: open 1: wait+close 2: close */
1963ea4a95cSchristos void
set_pager(int mode)1971fa8a9a6Sdholland set_pager(int mode)
19861f28255Scgd {
19961f28255Scgd static boolean so;
20061f28255Scgd if (mode == 0) {
20161f28255Scgd if (!whole_screen) {
20261f28255Scgd /* clear topline */
20361f28255Scgd clrlin();
20461f28255Scgd /* use part of screen below level map */
20561f28255Scgd curs(1, ROWNO + 4);
20661f28255Scgd } else {
20761f28255Scgd cls();
20861f28255Scgd }
20961f28255Scgd so = flags.standout;
21061f28255Scgd flags.standout = 1;
21161f28255Scgd } else {
21261f28255Scgd if (mode == 1) {
21361f28255Scgd curs(1, LI);
21461f28255Scgd more();
21561f28255Scgd }
21661f28255Scgd flags.standout = so;
21761f28255Scgd if (whole_screen)
21861f28255Scgd docrt();
21961f28255Scgd else {
22061f28255Scgd curs(1, ROWNO + 4);
22161f28255Scgd cl_eos();
22261f28255Scgd }
22361f28255Scgd }
22461f28255Scgd }
22561f28255Scgd
2263ea4a95cSchristos int
page_line(const char * s)2271fa8a9a6Sdholland page_line(const char *s) /* returns 1 if we should quit */
22861f28255Scgd {
22961f28255Scgd if (cury == LI - 1) {
23061f28255Scgd if (!*s)
23161f28255Scgd return (0); /* suppress blank lines at top */
23261f28255Scgd putchar('\n');
23361f28255Scgd cury++;
23461f28255Scgd cmore("q\033");
23561f28255Scgd if (morc) {
23661f28255Scgd morc = 0;
23761f28255Scgd return (1);
23861f28255Scgd }
23961f28255Scgd if (whole_screen)
24061f28255Scgd cls();
24161f28255Scgd else {
24261f28255Scgd curs(1, ROWNO + 4);
24361f28255Scgd cl_eos();
24461f28255Scgd }
24561f28255Scgd }
24661f28255Scgd puts(s);
24761f28255Scgd cury++;
24861f28255Scgd return (0);
24961f28255Scgd }
25061f28255Scgd
25161f28255Scgd /*
25261f28255Scgd * Flexible pager: feed it with a number of lines and it will decide
25361f28255Scgd * whether these should be fed to the pager above, or displayed in a
25461f28255Scgd * corner.
25561f28255Scgd * Call:
25661f28255Scgd * cornline(0, title or 0) : initialize
25761f28255Scgd * cornline(1, text) : add text to the chain of texts
25861f28255Scgd * cornline(2, morcs) : output everything and cleanup
25961f28255Scgd * cornline(3, 0) : cleanup
26061f28255Scgd */
26161f28255Scgd
2623ea4a95cSchristos void
cornline(int mode,const char * text)2631fa8a9a6Sdholland cornline(int mode, const char *text)
26461f28255Scgd {
26561f28255Scgd static struct line {
26661f28255Scgd struct line *next_line;
26761f28255Scgd char *line_text;
26861f28255Scgd } *texthead, *texttail;
26961f28255Scgd static int maxlen;
27061f28255Scgd static int linect;
2713ea4a95cSchristos struct line *tl;
27261f28255Scgd
27361f28255Scgd if (mode == 0) {
27461f28255Scgd texthead = 0;
27561f28255Scgd maxlen = 0;
27661f28255Scgd linect = 0;
27761f28255Scgd if (text) {
27861f28255Scgd cornline(1, text); /* title */
27961f28255Scgd cornline(1, ""); /* blank line */
28061f28255Scgd }
28161f28255Scgd return;
28261f28255Scgd }
28361f28255Scgd if (mode == 1) {
2843ea4a95cSchristos int len;
28561f28255Scgd
2863ea4a95cSchristos if (!text)
2873ea4a95cSchristos return; /* superfluous, just to be sure */
28861f28255Scgd linect++;
28961f28255Scgd len = strlen(text);
29061f28255Scgd if (len > maxlen)
29161f28255Scgd maxlen = len;
292434d266eSdholland tl = alloc(len + sizeof(*tl) + 1);
29361f28255Scgd tl->next_line = 0;
29461f28255Scgd tl->line_text = (char *) (tl + 1);
29561f28255Scgd (void) strcpy(tl->line_text, text);
29661f28255Scgd if (!texthead)
29761f28255Scgd texthead = tl;
29861f28255Scgd else
29961f28255Scgd texttail->next_line = tl;
30061f28255Scgd texttail = tl;
30161f28255Scgd return;
30261f28255Scgd }
30361f28255Scgd /* --- now we really do it --- */
30461f28255Scgd if (mode == 2 && linect == 1) /* topline only */
30557c13365Sjoerg pline("%s", texthead->line_text);
3063ea4a95cSchristos else if (mode == 2) {
3073ea4a95cSchristos int curline, lth;
30861f28255Scgd
3093ea4a95cSchristos if (flags.toplin == 1)
3103ea4a95cSchristos more(); /* ab@unido */
31161f28255Scgd remember_topl();
31261f28255Scgd
31361f28255Scgd lth = CO - maxlen - 2; /* Use full screen width */
31461f28255Scgd if (linect < LI && lth >= 10) { /* in a corner */
31561f28255Scgd home();
31661f28255Scgd cl_end();
31761f28255Scgd flags.toplin = 0;
31861f28255Scgd curline = 1;
31961f28255Scgd for (tl = texthead; tl; tl = tl->next_line) {
32061f28255Scgd curs(lth, curline);
32161f28255Scgd if (curline > 1)
32261f28255Scgd cl_end();
32361f28255Scgd putsym(' ');
32461f28255Scgd putstr(tl->line_text);
32561f28255Scgd curline++;
32661f28255Scgd }
32761f28255Scgd curs(lth, curline);
32861f28255Scgd cl_end();
32961f28255Scgd cmore(text);
33061f28255Scgd home();
33161f28255Scgd cl_end();
33261f28255Scgd docorner(lth, curline - 1);
33361f28255Scgd } else { /* feed to pager */
33461f28255Scgd set_pager(0);
33561f28255Scgd for (tl = texthead; tl; tl = tl->next_line) {
33661f28255Scgd if (page_line(tl->line_text)) {
33761f28255Scgd set_pager(2);
33861f28255Scgd goto cleanup;
33961f28255Scgd }
34061f28255Scgd }
34161f28255Scgd if (text) {
34261f28255Scgd cgetret(text);
34361f28255Scgd set_pager(2);
34461f28255Scgd } else
34561f28255Scgd set_pager(1);
34661f28255Scgd }
34761f28255Scgd }
34861f28255Scgd cleanup:
3493ea4a95cSchristos while ((tl = texthead) != NULL) {
35061f28255Scgd texthead = tl->next_line;
3518e73b3adSdholland free(tl);
35261f28255Scgd }
35361f28255Scgd }
35461f28255Scgd
3553ea4a95cSchristos int
dohelp(void)3561fa8a9a6Sdholland dohelp(void)
35761f28255Scgd {
35861f28255Scgd char c;
35961f28255Scgd
36061f28255Scgd pline("Long or short help? ");
3613ea4a95cSchristos while (((c = readchar()) != 'l') && (c != 's') && !strchr(quitchars, c))
36298eb8895Sroy sound_bell();
3633ea4a95cSchristos if (!strchr(quitchars, c))
36461f28255Scgd (void) page_file((c == 'l') ? HELP : SHELP, FALSE);
36561f28255Scgd return (0);
36661f28255Scgd }
36761f28255Scgd
3681fa8a9a6Sdholland /* return: 0 - cannot open fnam; 1 - otherwise */
3699b92b189Sdholland static int
page_file(const char * fnam,boolean silent)3701fa8a9a6Sdholland page_file(const char *fnam, boolean silent)
37161f28255Scgd {
37261f28255Scgd #ifdef DEF_PAGER /* this implies that UNIX is defined */
37361f28255Scgd {
37461f28255Scgd /* use external pager; this may give security problems */
37561f28255Scgd
376ab8b6343Sjsm int fd = open(fnam, O_RDONLY);
37761f28255Scgd
37861f28255Scgd if (fd < 0) {
3793ea4a95cSchristos if (!silent)
3803ea4a95cSchristos pline("Cannot open %s.", fnam);
38161f28255Scgd return (0);
38261f28255Scgd }
38361f28255Scgd if (child(1)) {
38461f28255Scgd
3853ea4a95cSchristos /*
3863ea4a95cSchristos * Now that child() does a setuid(getuid()) and a
3873ea4a95cSchristos * chdir(), we may not be able to open file fnam
3883ea4a95cSchristos * anymore, so make it stdin.
3893ea4a95cSchristos */
39061f28255Scgd (void) close(0);
39161f28255Scgd if (dup(fd)) {
3923ea4a95cSchristos if (!silent)
3933ea4a95cSchristos printf("Cannot open %s as stdin.\n", fnam);
39461f28255Scgd } else {
395*acae6852Splunky execl(catmore, "page", (char *)NULL);
3963ea4a95cSchristos if (!silent)
3973ea4a95cSchristos printf("Cannot exec %s.\n", catmore);
39861f28255Scgd }
39961f28255Scgd exit(1);
40061f28255Scgd }
40161f28255Scgd (void) close(fd);
40261f28255Scgd }
4033ea4a95cSchristos #else /* DEF_PAGER */
40461f28255Scgd {
40561f28255Scgd FILE *f; /* free after Robert Viduya */
40661f28255Scgd
40761f28255Scgd if ((f = fopen(fnam, "r")) == (FILE *) 0) {
40861f28255Scgd if (!silent) {
4093ea4a95cSchristos home();
4103ea4a95cSchristos perror(fnam);
4113ea4a95cSchristos flags.toplin = 1;
41261f28255Scgd pline("Cannot open %s.", fnam);
41361f28255Scgd }
41461f28255Scgd return (0);
41561f28255Scgd }
41661f28255Scgd page_more(f, 0);
41761f28255Scgd }
4183ea4a95cSchristos #endif /* DEF_PAGER */
41961f28255Scgd
42061f28255Scgd return (1);
42161f28255Scgd }
42261f28255Scgd
42361f28255Scgd #ifdef UNIX
42461f28255Scgd #ifdef SHELL
4253ea4a95cSchristos int
dosh(void)4261fa8a9a6Sdholland dosh(void)
4273ea4a95cSchristos {
4283ea4a95cSchristos char *str;
42961f28255Scgd if (child(0)) {
4303ea4a95cSchristos if ((str = getenv("SHELL")) != NULL)
431*acae6852Splunky execl(str, str, (char *)NULL);
43261f28255Scgd else
433*acae6852Splunky execl("/bin/sh", "sh", (char *)NULL);
43461f28255Scgd pline("sh: cannot execute.");
43561f28255Scgd exit(1);
43661f28255Scgd }
43761f28255Scgd return (0);
43861f28255Scgd }
4393ea4a95cSchristos #endif /* SHELL */
44061f28255Scgd
4419b92b189Sdholland static int
child(int wt)442ab8b6343Sjsm child(int wt)
4433ea4a95cSchristos {
44461f28255Scgd int status;
4453ea4a95cSchristos int f;
44661f28255Scgd
44761f28255Scgd f = fork();
44861f28255Scgd if (f == 0) { /* child */
4492c0ecb1aSdholland settty(NULL); /* also calls end_screen() */
45061f28255Scgd (void) setuid(getuid());
45161f28255Scgd (void) setgid(getgid());
45261f28255Scgd #ifdef CHDIR
45361f28255Scgd (void) chdir(getenv("HOME"));
4543ea4a95cSchristos #endif /* CHDIR */
45561f28255Scgd return (1);
45661f28255Scgd }
45761f28255Scgd if (f == -1) { /* cannot fork */
45861f28255Scgd pline("Fork failed. Try again.");
45961f28255Scgd return (0);
46061f28255Scgd }
46161f28255Scgd /* fork succeeded; wait for child to exit */
46261f28255Scgd (void) signal(SIGINT, SIG_IGN);
46361f28255Scgd (void) signal(SIGQUIT, SIG_IGN);
46461f28255Scgd (void) wait(&status);
46561f28255Scgd gettty();
46661f28255Scgd setftty();
46761f28255Scgd (void) signal(SIGINT, done1);
46861f28255Scgd #ifdef WIZARD
4693ea4a95cSchristos if (wizard)
4703ea4a95cSchristos (void) signal(SIGQUIT, SIG_DFL);
4713ea4a95cSchristos #endif /* WIZARD */
4723ea4a95cSchristos if (wt)
4733ea4a95cSchristos getret();
47461f28255Scgd docrt();
47561f28255Scgd return (0);
47661f28255Scgd }
4773ea4a95cSchristos #endif /* UNIX */
478