Source:NetHack 2.3e/pager.c

From NetHackWiki
Revision as of 23:18, 3 July 2024 by Furey (talk | contribs) (Delete link-to-particular-source instructions. Source code covers that now. "the latest release" -> "newer releases".)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Below is the full text to pager.c from the source code of NetHack 2.3e.

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

Screenshots and source code from Hack are used under the CWI license.

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