Source:NetHack 2.2a/pager.c

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