Source:NetHack 2.2a/pager.c
Jump to navigation
Jump to search
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
Screenshots and source code from Hack are used under the CWI license.
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 <stdio.h> 9. #include <signal.h> 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 /**/