abstract
| - 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 != ' ') 99. while(fgets(buf,BUFSZ,fp)) 100. if(*buf == q) { 101. ep = index(buf, '
'); 102. if(ep) *ep = 0; 103. /* else: bad data file */ 104. /* Expand tab 'by hand' */ 105. if(buf[1] == ' '){ 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, '
'); 174. if(ep) *ep = 0; 175. if(!ctrl && buf[1] == ' '){ 176. buf = bufr; 177. buf[0] = q; 178. (void) strncpy(buf+1, " ", 7); 179. } else if (ctrl && buf[2] == ' '){ 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 == ' ')){ 230. bufp = buf; 231. bufrp = bufr; 232. while (*bufp && *bufp != '
') { 233. if (*bufp == ' ') { 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 == ' ')){ 247. ep = index(bufr, '
'); 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('
'); 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('
'); 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.
", fnam); 584. } else { 585. (void) execl(catmore, "page", NULL); 586. if(!silent) Printf("Cannot exec %s.
", 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 /**/
|