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