Source:NetHack 2.3e/pager.c
Revision as of 23:18, 3 July 2024 by Furey (talk | contribs) (Delete link-to-particular-source instructions. Source code covers that now. "the latest release" -> "newer releases".)
Below is the full text to pager.c from the source code of NetHack 2.3e.
Warning! This is the source code from an old release. For newer releases, see Source code
Screenshots and source code from Hack are used under the CWI license.
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 <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. 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 /**/