abstract
| - 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 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 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. 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 != ' ') 90. while(fgets(buf,BUFSZ,fp)) 91. if(*buf == q) { 92. ep = index(buf, '
'); 93. if(ep) *ep = 0; 94. /* else: bad data file */ 95. /* Expand tab 'by hand' */ 96. if(buf[1] == ' '){ 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 == ' ')){ 146. bufp = buf; 147. bufrp = bufr; 148. while (*bufp && *bufp != '
') { 149. if (*bufp == ' ') { 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 == ' ')){ 165. ep = index(bufr, '
'); 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('
'); 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('
'); 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.
", fnam); 402. } else { 403. execl(catmore, "page", (char *) 0); 404. if(!silent) printf("Cannot exec %s.
", 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 /**/
|