hack.pager.c 11 KB

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