Wikihack
Advertisement

Below is the full text to pager.c from the source code of NetHack 1.3d. To link to a particular line, write [[NetHack 1.3d/pager.c#line123]], for example.

Warning! This is the source code from an old release. For the latest release, see Source code

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