abstract
| - Below is the full text to pager.c from the source code of NetHack 2.3e. To link to a particular line, write [[NetHack 2.3e/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 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 9. #include 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 != ' ') 94. while(fgets(buf,BUFSZ,fp)) 95. if(*buf == q) { 96. ep = index(buf, '
'); 97. if(ep) *ep = 0; 98. /* else: bad data file */ 99. /* Expand tab 'by hand' */ 100. if(buf[1] == ' '){ 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 == ' ')){ 150. bufp = buf; 151. bufrp = bufr; 152. while (*bufp && *bufp != '
') { 153. if (*bufp == ' ') { 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 == ' ')){ 169. ep = index(bufr, '
'); 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('
'); 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('
'); 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.
", fnam); 420. } else { 421. execl(catmore, "page", (char *) 0); 422. if(!silent) printf("Cannot exec %s.
", 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 /**/
|