Difference between revisions of "Source:NetHack 3.0.0/pager.c"
Jump to navigation
Jump to search
m (Automated source code upload) |
Kernigh bot (talk | contribs) m (NetHack 3.0.0/pager.c moved to Source:NetHack 3.0.0/pager.c: Robot: moved page) |
(No difference)
|
Revision as of 05:11, 4 March 2008
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
The NetHack General Public License applies to screenshots, source code and other content from NetHack.
This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.
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 <signal.h> 15. #endif 16. #if defined(BSD) || defined(ULTRIX) 17. #include <sys/wait.h> 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 != '\t') 99. while(fgets(buf,BUFSZ,fp)) 100. if(*buf == q) { 101. ep = index(buf, '\n'); 102. if(ep) *ep = 0; 103. /* else: bad data file */ 104. /* Expand tab 'by hand' */ 105. if(buf[1] == '\t'){ 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, '\n'); 174. if(ep) *ep = 0; 175. if(!ctrl && buf[1] == '\t'){ 176. buf = bufr; 177. buf[0] = q; 178. (void) strncpy(buf+1, " ", 7); 179. } else if (ctrl && buf[2] == '\t'){ 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 == '\t')){ 230. bufp = buf; 231. bufrp = bufr; 232. while (*bufp && *bufp != '\n') { 233. if (*bufp == '\t') { 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 == '\t')){ 247. ep = index(bufr, '\n'); 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('\n'); 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('\n'); 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.\n", fnam); 584. } else { 585. (void) execl(catmore, "page", NULL); 586. if(!silent) Printf("Cannot exec %s.\n", 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 /**/