Source:NetHack 1.4f/pager.c

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

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

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