Source:NetHack 2.3e/pager.c

Below is the full text to pager.c from the source code of NetHack 2.3e. To link to a particular line, write [[NetHack 2.3e/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.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	  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.  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 /**/