Source:NetHack 1.3d/pager.c

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