Source:NetHack 3.0.0/pager.c

Below is the full text to pager.c from the source code of NetHack 3.0.0. To link to a particular line, write [[NetHack 3.0.0/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	3.0	88/10/25 */ 2.   /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3.    /* NetHack may be freely redistributed. See license for details. */ 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.    /* block some unused #defines to avoid overloading some cpp's */ 10.  #define MONATTK_H 11.  #include	 "hack.h"  12. 13.  #ifndef TOS 14.  #include   15. #endif 16.  #if defined(BSD) || defined(ULTRIX) 17.  #include   18. #endif 19.   20.   static char hc = 0; 21.   22.   static void page_more; 23.   24.   int 25.  dowhatis 26.  {  27.   	FILE *fp; 28.  	char bufr[BUFSZ+6]; 29.  	register char *buf = &bufr[6], *ep, q;  30. register struct monst *mtmp; 31.   32.   	if(!(fp = fopen(DATAFILE, "r"))) 33.  		pline("Cannot open data file!"); 34.  	else { 35.  		coord	cc; 36.  		uchar	r; 37.   38.   		pline ("Specify unknown object by cursor? "); 39.  		q = ynq; 40.  		cc.x = cc.y = -1; 41.  		if (q == 'q') { 42.  			(void) fclose(fp); 43.  			return 0; 44.  		} else if (q == 'n') { 45.  			pline("Specify what? "); 46.  			r = readchar; 47.  		} else { 48.  		    if(flags.verbose) 49.  			pline("Please move the cursor to the unknown object."); 50.  		    getpos(&cc, TRUE, "the unknown object"); 51.  		    r = levl[cc.x][cc.y].scrsym; 52.  		}  53.    54.   		if (r == showsyms.stone) q = defsyms.stone; 55.  		else if (r == showsyms.vwall) q = defsyms.vwall; 56.  		else if (r == showsyms.hwall) q = defsyms.hwall; 57.  		else if (r == showsyms.tlcorn) q = defsyms.tlcorn; 58.  		else if (r == showsyms.trcorn) q = defsyms.trcorn; 59.  		else if (r == showsyms.blcorn) q = defsyms.blcorn; 60.  		else if (r == showsyms.brcorn) q = defsyms.brcorn; 61.  		else if (r == showsyms.crwall) q = defsyms.crwall; 62.  		else if (r == showsyms.tuwall) q = defsyms.tuwall; 63.  		else if (r == showsyms.tdwall) q = defsyms.tdwall; 64.  		else if (r == showsyms.tlwall) q = defsyms.tlwall; 65.  		else if (r == showsyms.trwall) q = defsyms.trwall; 66.  		else if (r == showsyms.door) q = defsyms.door; 67.  		else if (r == showsyms.room) q = defsyms.room; 68.  		else if (r == showsyms.corr) q = defsyms.corr; 69.  		else if (r == showsyms.upstair) q = defsyms.upstair; 70.  		else if (r == showsyms.dnstair) q = defsyms.dnstair; 71.  		else if (r == showsyms.trap) q = defsyms.trap; 72.  #ifdef FOUNTAINS 73.  		else if (r == showsyms.pool) q = defsyms.pool; 74.  		else if (r == showsyms.fountain) q = defsyms.fountain; 75.  #endif 76.  #ifdef THRONES 77.  		else if (r == showsyms.throne) q = defsyms.throne; 78.  #endif 79.  		else if (r == showsyms.web) q = defsyms.web; 80.  #ifdef SINKS 81.  		else if (r == showsyms.sink) q = defsyms.sink; 82.  #endif 83.  #ifdef ALTARS 84.  		else if (r == showsyms.altar) q = defsyms.altar; 85.  #endif 86.  		else 87.  		    q = r;  88. if (index(quitchars, q)) { 89.  			(void) fclose(fp); /* sweet@scubed */ 90.  			return 0; 91.  		}  92.   		if(q == '%') { 93.  			pline("%%       a piece of food"); 94.  			(void) fclose(fp); 95.  			return 0; 96.  		}  97.    98.   		if(q != '\t') 99.  		while(fgets(buf,BUFSZ,fp)) 100. 		    if(*buf == q) { 101. 			ep = index(buf, '\n'); 102. 			if(ep) *ep = 0; 103. 			/* else: bad data file */ 104. 			/* Expand tab 'by hand' */ 105. 			if(buf[1] == '\t'){ 106. 				buf = bufr; 107. 				buf[0] = r;  108. (void) strncpy(buf+1, "      ", 7); 109. 			}  110.  			pline(buf); 111. 			if(cc.x != -1 && IS_ALTAR(levl[cc.x][cc.y].typ)) { 112. 			    int type = levl[u.ux][u.uy].altarmask & ~A_SHRINE; 113. 			    pline("(%s)", (type==0) ? "chaotic" :  114.  				(type==1) ? "neutral" : "lawful"); 115. 			}  116.  			if (!Invisible && u.ux==cc.x && u.uy==cc.y) { 117. 			    pline("(%s named %s)",  118.  #ifdef POLYSELF  119.  				u.mtimedone ? mons[u.umonnum].mname :  120.  #endif  121.  				pl_character, plname); 122. 			} else if((q >= 'A' && q <= 'z') || index(";:& @`",q)) { 123. 			    for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) 124. 				if(mtmp->mx == cc.x && mtmp->my == cc.y) { 125. 				    pline("(%s%s)",  126.  					mtmp->mtame ? "tame " :  127.  					  mtmp->mpeaceful ? "peaceful " : "",  128.  					strncmp(lmonnam(mtmp), "the ", 4)  129.  					  ? lmonnam(mtmp) : lmonnam(mtmp)+4); 130. 				    break; 131. 				}  132.  			}  133.  			if(ep[-1] == ';') { 134. 				pline("More info? "); 135. 				if(yn == 'y') { 136. 					page_more(fp,1); /* does fclose */ 137. 					return 0; 138. 				}  139.  			}  140.  			(void) fclose(fp); 	/* kopper@psuvax1 */ 141. 			return 0; 142. 		    }  143.  		pline("I've never heard of such things."); 144. 		(void) fclose(fp); 145. 	}  146.  	return 0; 147. }  148.   149.  int 150. dowhatdoes 151. {  152.  	FILE *fp; 153. 	char bufr[BUFSZ+6]; 154. 	register char *buf = &bufr[6], *ep, q, ctrl; 155.  156.  	if(!(fp = fopen(CMDHELPFILE, "r"))) { 157. 		pline("Cannot open data file!"); 158. 		return 0; 159. 	}  160.  	pline("What command? "); 161. #ifdef UNIX 162. 	introff; 163. #endif 164. 	q = readchar; 165. #ifdef UNIX 166. 	intron; 167. #endif 168. 	if (q == '\033') ctrl = '['; 169. 	else if (q != unctrl(q)) ctrl = q - 1 + 'A'; 170. 	else ctrl = 0; 171. 	while(fgets(buf,BUFSZ,fp)) 172. 	    if ((!ctrl && *buf==q) || (ctrl && *buf=='^' && *(buf+1)==ctrl)) { 173. 		ep = index(buf, '\n'); 174. 		if(ep) *ep = 0; 175. 		if(!ctrl && buf[1] == '\t'){ 176. 			buf = bufr; 177. 			buf[0] = q;  178. (void) strncpy(buf+1, "      ", 7); 179. 		} else if (ctrl && buf[2] == '\t'){ 180. 			buf = bufr + 1; 181. 			buf[0] = '^'; 182. 			buf[1] = ctrl; 183. 			(void) strncpy(buf+2, "      ", 6); 184. 		}  185.  		pline(buf); 186. 		(void) fclose(fp); 187. 		return 0; 188. 	    }  189.  	pline("I've never heard of such commands."); 190. 	(void) fclose(fp); 191. 	return 0; 192. }  193.   194.  /* make the paging of a file interruptible */ 195. static int got_intrup; 196.  197.  #if !defined(MSDOS) && !defined(TOS) 198. static int 199. intruph{ 200. 	(void) signal(SIGINT, (SIG_RET_TYPE) intruph); 201. 	got_intrup++; 202. 	return 0; 203. }  204.  #endif 205.  206.  /* simple pager, also used from dohelp */ 207. static void 208. page_more(fp,strip) 209. FILE *fp; 210. int strip;	/* nr of chars to be stripped from each line (0 or 1) */ 211. {  212.  	register char *bufr; 213. #if !defined(MSDOS) && !defined(MINIMAL_TERM) 214. 	register char *ep; 215. #endif 216. #if !defined(MSDOS) && !defined(TOS) 217. 	int (*prevsig) = (int (*))signal(SIGINT, (SIG_RET_TYPE) intruph); 218. #endif 219. #if defined(MSDOS) || defined(MINIMAL_TERM) 220. 	/* There seems to be a bug in ANSI.SYS  The first tab character 221. 	 * after a clear screen sequence is not expanded correctly. Thus 222. 	 * expand the tabs by hand -dgk 223. 	 */  224.  	int tabstop = 8, spaces; 225. 	char buf[BUFSIZ], *bufp, *bufrp; 226.  227.  	set_pager(0); 228. 	bufr = (char *) alloc((unsigned) COLNO); 229. 	while (fgets(buf, BUFSIZ, fp) && (!strip || *buf == '\t')){ 230. 		bufp = buf; 231. 		bufrp = bufr; 232. 		while (*bufp && *bufp != '\n') { 233. 			if (*bufp == '\t') { 234. 				spaces = tabstop - (bufrp - bufr) % tabstop; 235. 				while (spaces--) 236. 					*bufrp++ = ' '; 237. 				bufp++; 238. 			} else 239. 				*bufrp++ = *bufp++; 240. 		}  241.  		*bufrp = '\0'; 242. #else /* MSDOS /**/ 243. 	set_pager(0); 244. 	bufr = (char *) alloc((unsigned) COLNO); 245. 	bufr[COLNO-1] = 0; 246. 	while(fgets(bufr,COLNO-1,fp) && (!strip || *bufr == '\t')){ 247. 		ep = index(bufr, '\n'); 248. 		if(ep) 249. 			*ep = 0; 250. #endif /* MSDOS /**/ 251. 		if(got_intrup || page_line(bufr+strip)) { 252. 			set_pager(2); 253. 			goto ret; 254. 		}  255.  	}  256.  	set_pager(1); 257. ret: 258. 	free((genericptr_t) bufr); 259. 	(void) fclose(fp); 260. #if !defined(MSDOS) && !defined(TOS) 261. 	(void) signal(SIGINT, (SIG_RET_TYPE) prevsig); 262. 	got_intrup = 0; 263. #endif 264. }  265.   266.  static boolean whole_screen = TRUE; 267. #define	PAGMIN	12	/* minimum # of lines for page below level map */ 268.  269.  void 270. set_whole_screen {	/* called in termcap as soon as LI is known */ 271. 	whole_screen = (LI-ROWNO-2 <= PAGMIN || !CD); 272. }  273.   274.  #ifdef NEWS 275. int 276. readnews { 277. 	register int ret; 278.  279.  	whole_screen = TRUE;	/* force a docrt, our first */ 280. 	ret = page_file(NEWS, TRUE); 281. 	set_whole_screen; 282. 	return(ret);		/* report whether we did docrt */ 283. }  284.  #endif 285.  286.  void 287. set_pager(mode) 288. register int mode;	/* 0: open  1: wait+close  2: close */ 289. {  290.  #ifdef LINT	/* lint may handle static decl poorly -- static boolean so; */ 291. 	boolean so; 292. #else 293. 	static boolean so; 294. #endif 295. 	if(mode == 0) { 296. 		if(!whole_screen) { 297. 			/* clear topline */ 298. 			clrlin; 299. 			/* use part of screen below level map */ 300. 			curs(1, ROWNO+4); 301. 		} else { 302. 			cls; 303. 		}  304.  		so = flags.standout; 305. 		flags.standout = 1; 306. 	} else { 307. 		if(mode == 1) { 308. 			curs(1, LI); 309. 			more; 310. 		}  311.  		flags.standout = so; 312. 		if(whole_screen) 313. 			docrt; 314. 		else { 315. 			curs(1, ROWNO+4); 316. 			cl_eos; 317. 		}  318.  	}  319.  }  320.   321.  int 322. page_line(s)		/* returns 1 if we should quit */ 323. register char *s; 324. {  325.  	if(cury == LI-1) { 326. 		if(!*s) 327. 			return(0);	/* suppress blank lines at top */ 328. 		(void) putchar('\n'); 329. 		cury++; 330. 		cmore("q\033"); 331. 		if(morc) { 332. 			morc = 0; 333. 			return(1); 334. 		}  335.  		if(whole_screen) 336. 			cls; 337. 		else { 338. 			curs(1, ROWNO+4); 339. 			cl_eos; 340. 		}  341.  	}  342.  #ifdef TERMINFO 343. 	xputs(s); xputc('\n'); 344. #else 345. 	(void) puts(s); 346. #endif 347. 	cury++; 348. 	return(0); 349. }  350.   351.  /*  352.   * Flexible pager: feed it with a number of lines and it will decide 353.  * whether these should be fed to the pager above, or displayed in a  354. * corner. 355.  * Call: 356.  *	cornline(0, title or 0)	: initialize 357.  *	cornline(1, text)	: add text to the chain of texts 358.  *	cornline(2, morcs)	: output everything and cleanup 359.  *	cornline(3, 0)		: cleanup 360.  *	cornline(-1,"")		: special, for help menu mode only 361.  */  362.   363.  void 364. cornline(mode, text) 365. int mode; 366. char *text; 367. {  368.  	static struct line { 369. 		struct line *next_line; 370. 		char *line_text; 371. 	} *texthead, *texttail; 372. 	static int maxlen; 373. 	static int linect; 374. 	register struct line *tl; 375. 	register boolean hmenu = FALSE; 376.  377.  	if(mode == -1) { /* help menu display only */ 378. 		mode = 2; 379. 		hmenu = TRUE; 380. 	}  381.  	if(mode == 0) { 382. 		texthead = 0; 383. 		maxlen = 0; 384. 		linect = 0; 385. 		if(text) { 386. 			cornline(1, text);	/* title */ 387. 			cornline(1, "");	/* blank line */ 388. 		}  389.  		return; 390. 	}  391.   392.  	if(mode == 1) { 393. 	    register int len; 394.  395.  	    if(!text) return;	/* superfluous, just to be sure */ 396. 	    linect++; 397. 	    len = strlen(text) + 1; /* allow for an extra leading space */ 398. 	    if(len > maxlen) 399. 		maxlen = len; 400. 	    tl = (struct line *) 401. 		alloc((unsigned)(len + sizeof(struct line) + 1)); 402. 	    tl->next_line = 0; 403. 	    tl->line_text = (char *)(tl + 1); 404. 	    tl->line_text[0] = ' '; 405. 	    tl->line_text[1] = '\0'; 406. 	    Strcat(tl->line_text, text); 407. 	    if(!texthead) 408. 		texthead = tl; 409. 	    else 410. 		texttail->next_line = tl; 411. 	    texttail = tl; 412. 	    return; 413. 	}  414.   415.  	/* --- now we really do it --- */ 416. 	if(mode == 2 && linect == 1)			    /* topline only */ 417. 		pline(texthead->line_text); 418. 	else 419. 	if(mode == 2) { 420. 	    register int curline, lth; 421.  422.  	    if(flags.toplin == 1) more;	/* ab@unido */ 423. 	    remember_topl; 424.  425.  	    lth = CO - maxlen - 2;		   /* Use full screen width */ 426. 	    if (linect < LI && lth >= 10) {		     /* in a corner */ 427. 		home ; 428. 		cl_end ; 429. 		flags.toplin = 0; 430. 		curline = 1; 431. 		for (tl = texthead; tl; tl = tl->next_line) { 432. #if defined(MSDOS) && !defined(AMIGA) 433. 		    cmov (lth, curline); 434. #else 435. 		    curs (lth, curline); 436. #endif 437. 		    if(curline > 1) 438. 			cl_end ; 439. 		    xputs(tl->line_text); 440. 		    curx = curx + strlen(tl->line_text); 441. 		    curline++; 442. 		}  443.  		if(hmenu) hc = lowc(readchar); /* help menu display */ 444. #if defined(MSDOS) && !defined(AMIGA) 445. 		cmov (lth, curline); 446. #else 447. 		curs (lth, curline); 448. #endif 449. 		cl_end ; 450. 		if (!hmenu) cmore (text); 451. 		home ; 452. 		cl_end ; 453. 		docorner (lth, curline-1); 454. 	    } else {					/* feed to pager */ 455. 		set_pager(0); 456. 		for (tl = texthead; tl; tl = tl->next_line) { 457. 		    if (page_line (tl->line_text)) { 458. 			set_pager(2); 459. 			goto cleanup; 460. 		    }  461.  		}  462.  		if(text) { 463. 			cgetret(text); 464. 			set_pager(2); 465. 		} else 466. 			set_pager(1); 467. 	    }  468.  	}  469.   470.  cleanup: 471. 	while(tl = texthead) { 472. 		texthead = tl->next_line; 473. 		free((genericptr_t) tl); 474. 	}  475.  }  476.   477.  #ifdef WIZARD 478. static 479. void 480. wiz_help 481. {  482.  	cornline(0, "Wizard-Mode Quick Reference:"); 483. 	cornline(1, "^E  ==  detect secret doors and traps."); 484. 	cornline(1, "^F  ==  do magic mapping."); 485. 	cornline(1, "^G  ==  create monster."); 486. 	cornline(1, "^I  ==  identify items in pack."); 487. 	cornline(1, "^O  ==  tell locations of special levels."); 488. 	cornline(1, "^T  ==  do intra-level teleport."); 489. 	cornline(1, "^V  ==  do trans-level teleport."); 490. 	cornline(1, "^W  ==  make wish."); 491. 	cornline(1, "^X  ==  show intrinsic attributes."); 492. 	cornline(1, ""); 493. 	cornline(2, ""); 494. }  495.  #endif 496.  497.  static void 498. help_menu { 499. 	cornline(0, "Information available:"); 500. 	cornline(1, "a.  Long description of the game and commands."); 501. 	cornline(1, "b.  List of game commands."); 502. 	cornline(1, "c.  Concise history of NetHack."); 503. 	cornline(1, "d.  Info on a character in the game display."); 504. 	cornline(1, "e.  Info on what a given key does."); 505. 	cornline(1, "f.  List of game options."); 506. 	cornline(1, "g.  Longer explanation of game options."); 507. 	cornline(1, "h.  List of extended commands."); 508. 	cornline(1, "i.  The NetHack license."); 509. #ifdef WIZARD 510. 	if (wizard) 511. 		cornline(1, "j.  List of wizard-mode commands."); 512. #endif 513. 	cornline(1, ""); 514. #ifdef WIZARD 515. 	if (wizard) 516. 		cornline(1, "Select one of a,b,c,d,e,f,g,h,i,j or ESC: "); 517. 	else 518. #endif 519. 		cornline(1, "Select one of a,b,c,d,e,f,g,h,i or ESC: "); 520. 	cornline(-1,""); 521. }  522.   523.  int 524. dohelp 525. {  526.  	char c;  527. 528. 	do { 529. 	    help_menu; 530. 	    c = hc; 531. #ifdef WIZARD 532. 	} while ((c < 'a' || c > (wizard ? 'j' : 'i')) && !index(quitchars,c)); 533. #else 534. 	} while ((c < 'a' || c > 'i') && !index(quitchars,c)); 535. #endif 536. 	if (!index(quitchars, c)) { 537. 		switch(c) { 538. 			case 'a':  (void) page_file(HELP, FALSE);  break; 539. 			case 'b':  (void) page_file(SHELP, FALSE);  break; 540. 			case 'c':  (void) dohistory;  break; 541. 			case 'd':  (void) dowhatis;  break; 542. 			case 'e':  (void) dowhatdoes;  break; 543. 			case 'f':  option_help;  break; 544. 			case 'g':  (void) page_file(OPTIONFILE, FALSE);  break; 545. 			case 'h':  (void) doextlist;  break; 546. 			case 'i':  (void) page_file(LICENSE, FALSE);  break; 547. #ifdef WIZARD 548. 			case 'j':  wiz_help;  break; 549. #endif 550. 		}  551.  	}  552.  	return 0; 553. }  554.   555.  int 556. dohistory 557. {  558.  	(void) page_file(HISTORY, FALSE); 559. 	return 0; 560. }  561.   562.  int 563. page_file(fnam, silent)	/* return: 0 - cannot open fnam; 1 - otherwise */ 564. register char *fnam; 565. boolean silent; 566. {  567.  #ifdef DEF_PAGER			/* this implies that UNIX is defined */ 568.       {  569.  	/* use external pager; this may give security problems */ 570.  571.  	register int fd = open(fnam, 0); 572.  573.  	if(fd < 0) { 574. 		if(!silent) pline("Cannot open %s.", fnam); 575. 		return(0); 576. 	}  577.  	if(child(1)){ 578. 		/* Now that child does a setuid(getuid) and a chdir, 579. 		   we may not be able to open file fnam anymore, so make 580. 		   it stdin. */ 581.  		(void) close(0); 582. 		if(dup(fd)) { 583. 			if(!silent) Printf("Cannot open %s as stdin.\n", fnam); 584. 		} else { 585. 			(void) execl(catmore, "page", NULL); 586. 			if(!silent) Printf("Cannot exec %s.\n", catmore); 587. 		}  588.  		exit(1); 589. 	}  590.  	(void) close(fd); 591.       }  592.  #else 593.       {  594.  	FILE *f;			/* free after Robert Viduya */ 595.  596.  	if ((f = fopen (fnam, "r")) == (FILE *) 0) { 597. 		if(!silent) { 598. 			home; perror (fnam); flags.toplin = 1; 599. 			pline ("Cannot open %s.", fnam); 600. 		}  601.  		return(0); 602. 	}  603.  	page_more(f, 0); 604.       }  605.  #endif /* DEF_PAGER /**/ 606.  607.  	return(1); 608. }  609.   610.  #ifdef UNIX 611. #ifdef SHELL 612. int 613. dosh{ 614. register char *str; 615. 	if(child(0)) { 616. 		if(str = getenv("SHELL")) 617. 			(void) execl(str, str, NULL); 618. 		else 619. 			(void) execl("/bin/sh", "sh", NULL); 620. 		pline("sh: cannot execute."); 621. 		exit(1); 622. 	}  623.  	return 0; 624. }  625.  #endif /* SHELL /**/ 626.  627.  int 628. child(wt) 629. int wt; 630. {  631.  register int f = fork; 632. 	if(f == 0){		/* child */ 633. 		settty(NULL);		/* also calls end_screen */ 634. 		(void) setgid(getgid); 635. 		(void) setuid(getuid); 636. #ifdef CHDIR 637. 		(void) chdir(getenv("HOME")); 638. #endif 639. 		return(1); 640. 	}  641.  	if(f == -1) {	/* cannot fork */ 642. 		pline("Fork failed.  Try again."); 643. 		return(0); 644. 	}  645.  	/* fork succeeded; wait for child to exit */ 646. 	(void) signal(SIGINT,SIG_IGN); 647. 	(void) signal(SIGQUIT,SIG_IGN); 648. 	(void) wait(  649.  #if defined(BSD) || defined(ULTRIX)  650.  		(union wait *)  651.  #else  652.  		(int *)  653.  #endif  654.  		0); 655. 	gettty; 656. 	setftty; 657. 	(void) signal(SIGINT, (SIG_RET_TYPE) done1); 658. #ifdef WIZARD 659. 	if(wizard) (void) signal(SIGQUIT,SIG_DFL); 660. #endif 661. 	if(wt) getret; 662. 	docrt; 663. 	return(0); 664. }  665.  #endif /* UNIX /**/