]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - hack/hack.pager.c
Fix Coverity issues 2366 and 2365 -- REVERSE_INULL.
[bsdgames-darwin.git] / hack / hack.pager.c
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 */