abstract
| - Below is the full text to msdos.c from the source code of NetHack 2.3e. To link to a particular line, write [[NetHack 2.3e/msdos.c#line123]], for example. Warning! This is the source code from an old release. For the latest release, see Source code 1. /* SCCS Id: @(#)msdos.c 2.3 87/12/16 2. /* An assortment of MSDOS functions. 3. */ 4. 5. #include 6. #include "hack.h" 7. 8. #ifdef MSDOS 9. # include 10. 11. void 12. flushout() 13. { 14. (void) fflush(stdout); 15. } 16. 17. getuid() { 18. return 1; 19. } 20. 21. char * 22. getlogin() { 23. return ((char *) NULL); 24. } 25. # ifdef REDO 26. tgetch() { 27. char ch, popch(); 28. static char DOSgetch(), BIOSgetch(); 29. 30. if (!(ch = popch())) { 31. # ifdef DGK 32. /* BIOSgetch can use the numeric key pad on IBM compatibles. */ 33. if (flags.IBMBIOS) 34. ch = BIOSgetch(); 35. else 36. # endif 37. ch = DOSgetch(); 38. } 39. return ((ch == '') ? '
' : ch); 40. } 41. # else /* REDO /**/ 42. tgetch() { 43. char ch; 44. static char DOSgetch(), BIOSgetch(); 45. 46. # ifdef DGK 47. /* BIOSgetch can use the numeric key pad on IBM compatibles. */ 48. if (flags.IBMBIOS) 49. ch = BIOSgetch(); 50. else 51. # endif 52. ch = DOSgetch(); 53. return ((ch == '') ? '
' : ch); 54. } 55. # endif /* REDO /**/ 56. 57. # define DIRECT_INPUT 0x7 58. static char 59. DOSgetch() { 60. union REGS regs; 61. 62. regs.h.ah = DIRECT_INPUT; 63. intdos(®s, ®s); 64. if (!regs.h.al) { /* an extended code -- not yet supported */ 65. regs.h.ah = DIRECT_INPUT; 66. intdos(®s, ®s); /* eat the next character */ 67. regs.h.al = 0; /* and return a 0 */ 68. } 69. return (regs.h.al); 70. } 71. 72. 73. # ifdef DGK 74. # include 75. # include 76. 77. # define Sprintf (void) sprintf 78. # define WARN 1 79. # define NOWARN 0 80. 81. static char * 82. getcomspec(warn) { 83. return getenv("COMSPEC"); 84. } 85. 86. # ifdef SHELL 88. dosh() { 89. extern char orgdir[]; 90. char *comspec; 91. 92. if (comspec = getcomspec()) { 93. settty("To return to NetHack, type \"exit\" at the DOS prompt.
"); 94. chdirx(orgdir, 0); 95. if (spawnl(P_WAIT, comspec, comspec, NULL) < 0) { 96. printf("
Can't spawn %s !
", comspec); 97. flags.toplin = 0; 98. more(); 99. } 100. chdirx(hackdir, 0); 101. start_screen(); 102. docrt(); 103. } else 104. pline("No COMSPEC !? Can't exec COMMAND.COM"); 105. return(0); 106. } 107. # endif /* SHELL */ 108. 109. /* Normal characters are output when the shift key is not pushed. 110. * Shift characters are output when either shift key is pushed. 111. */ 112. # define KEYPADHI 83 113. # define KEYPADLOW 71 114. # define iskeypad(x) (KEYPADLOW <= (x) && (x) <= KEYPADHI) 115. static struct { 116. char normal, shift; 117. } keypad[KEYPADHI - KEYPADLOW + 1] = { 118. {'y', 'Y'}, /* 7 */ 119. {'k', 'K'}, /* 8 */ 120. {'u', 'U'}, /* 9 */ 121. {'m', CTRL('P')}, /* - */ 122. {'h', 'H'}, /* 4 */ 123. {'g', 'g'}, /* 5 */ 124. {'l', 'L'}, /* 6 */ 125. {'p', 'P'}, /* + */ 126. {'b', 'B'}, /* 1 */ 127. {'j', 'J'}, /* 2 */ 128. {'n', 'N'}, /* 3 */ 129. {'i', 'I'}, /* Ins */ 130. {'.', ':'} /* Del */ 131. }; 132. 133. /* BIOSgetch gets keys directly with a BIOS call. 134. */ 135. # define SHIFT (0x1 | 0x2) 136. # define KEYBRD_BIOS 0x16 137. 138. static char 139. BIOSgetch() { 140. unsigned char scan, shift, ch; 141. union REGS regs; 142. 143. /* Get scan code. 144. */ 145. regs.h.ah = 0; 146. int86(KEYBRD_BIOS, ®s, ®s); 147. ch = regs.h.al; 148. scan = regs.h.ah; 149. 150. /* Get shift status. 151. */ 152. regs.h.ah = 2; 153. int86(KEYBRD_BIOS, ®s, ®s); 154. shift = regs.h.al; 155. 156. /* If scan code is for the keypad, translate it. 157. */ 158. if (iskeypad(scan)) { 159. if (shift & SHIFT) 160. ch = keypad[scan - KEYPADLOW].shift; 161. else 162. ch = keypad[scan - KEYPADLOW].normal; 163. } 164. return ch; 165. } 166. 167. /* construct the string file.level */ 168. void 169. name_file(file, level) 170. char *file; 171. int level; 172. { 173. char *tf; 174. 175. if (tf = rindex(file, '.')) 176. Sprintf(tf+1, "%d", level); 177. } 178. 179. 180. # define FINDFIRST 0x4E00 181. # define FINDNEXT 0x4F00 182. # define GETDTA 0x2F00 183. # define SETFILETIME 0x5701 184. # define GETSWITCHAR 0x3700 185. # define FREESPACE 0x36 186. 187. static char 188. switchar() 189. { 190. union REGS regs; 191. 192. regs.x.ax = GETSWITCHAR; 193. intdos(®s, ®s); 194. return regs.h.dl; 195. } 196. 197. long 198. freediskspace(path) 199. char *path; 200. { 201. union REGS regs; 202. 203. regs.h.ah = FREESPACE; 204. if (path[0] && path[1] == ':') 205. regs.h.dl = (toupper(path[0]) - 'A') + 1; 206. else 207. regs.h.dl = 0; 208. intdos(®s, ®s); 209. if (regs.x.ax == 0xFFFF) 210. return -1L; /* bad drive number */ 211. else 212. return ((long) regs.x.bx * regs.x.cx * regs.x.ax); 213. } 214. 215. /* Functions to get filenames using wildcards 216. */ 217. static 218. findfirst(path) 219. char *path; 220. { 221. union REGS regs; 222. struct SREGS sregs; 223. 224. regs.x.ax = FINDFIRST; 225. regs.x.cx = 0; /* normal files */ 226. regs.x.dx = FP_OFF(path); 227. sregs.ds = FP_SEG(path); 228. intdosx(®s, ®s, &sregs); 229. return !regs.x.cflag; 230. } 231. 232. static 233. findnext() { 234. union REGS regs; 235. 236. regs.x.ax = FINDNEXT; 237. intdos(®s, ®s); 238. return !regs.x.cflag; 239. } 240. 241. #ifndef __TURBOC__ 242. /* Get disk transfer area, Turbo C already has getdta */ 243. static char * 244. getdta() { 245. union REGS regs; 246. struct SREGS sregs; 247. char *ret; 248. 249. regs.x.ax = GETDTA; 250. intdosx(®s, ®s, &sregs); 251. FP_OFF(ret) = regs.x.bx; 252. FP_SEG(ret) = sregs.es; 253. return ret; 254. } 255. #endif 256. 257. long 258. filesize(file) 259. char *file; 260. { 261. char *dta; 262. 263. if (findfirst(file)) { 264. dta = getdta(); 265. return (* (long *) (dta + 26)); 266. } else 267. return -1L; 268. } 269. 270. void 271. eraseall(path, files) 272. char *path, *files; 273. { 274. char *dta, buf[PATHLEN]; 275. 276. dta = getdta(); 277. Sprintf(buf, "%s%s", path, files); 278. if (findfirst(buf)) 279. do { 280. Sprintf(buf, "%s%s", path, dta + 30); 281. (void) unlink(buf); 282. } while (findnext()); 283. } 284. 285. /* Rewritten for version 3.3 to be faster 286. */ 287. void 288. copybones(mode) { 289. char from[PATHLEN], to[PATHLEN], last[13], copy[8]; 290. char *frompath, *topath, *dta, *comspec; 291. int status; 292. long fs; 293. extern saveprompt; 294. 295. if (!ramdisk) 296. return; 297. 298. /* Find the name of the last file to be transferred 299. */ 300. frompath = (mode != TOPERM) ? permbones : levels; 301. dta = getdta(); 302. last[0] = '\0'; 303. Sprintf(from, "%s%s", frompath, allbones); 304. if (findfirst(from)) 305. do { 306. strcpy(last, dta + 30); 307. } while (findnext()); 308. 309. topath = (mode == TOPERM) ? permbones : levels; 310. if (last[0]) { 311. Sprintf(copy, "%cC copy", switchar()); 312. 313. /* Remove any bones files in `to' directory. 314. */ 315. eraseall(topath, allbones); 316. 317. /* Copy `from' to `to' */ 318. Sprintf(to, "%s%s", topath, allbones); 319. comspec = getcomspec(); 320. status =spawnl(P_WAIT, comspec, comspec, copy, from, 321. to, "> nul", NULL); 322. } else 323. return; 324. 325. /* See if the last file got there. If so, remove the ramdisk bones 326. * files. 327. */ 328. Sprintf(to, "%s%s", topath, last); 329. if (findfirst(to)) { 330. if (mode == TOPERM) 331. eraseall(frompath, allbones); 332. return; 333. } 334. 335. /* Last file didn't get there. 336. */ 337. Sprintf(to, "%s%s", topath, allbones); 338. msmsg("Cannot copy `%s' to `%s' -- %s
", from, to, 339. (status < 0) ? "can't spawn COMSPEC !" : 340. (freediskspace(topath) < filesize(from)) ? 341. "insufficient disk space." : "bad path(s)?"); 342. if (mode == TOPERM) { 343. msmsg("Bones will be left in `%s'
", 344. *levels ? levels : hackdir); 345. return; 346. } else { 347. /* Remove all bones files on the RAMdisk */ 348. eraseall(levels, allbones); 349. playwoRAMdisk(); 350. } 351. } 352. 353. playwoRAMdisk() { 354. msmsg("Do you wish to play without a RAMdisk (y/n) ? "); 355. 356. /* Set ramdisk false *before* exit'ing (because msexit calls 357. * copybones) 358. */ 359. ramdisk = FALSE; 360. if (getchar() != 'y') { 361. settty("Be seeing you ...
"); 362. exit(0); 363. } 364. set_lock_and_bones(); 365. return; 366. } 367. 368. saveDiskPrompt(start) { 369. extern saveprompt; 370. char buf[BUFSIZ], *bp; 371. int fd; 372. 373. if (saveprompt) { 374. /* Don't prompt if you can find the save file */ 375. if ((fd = open(SAVEF, 0)) >= 0) { 376. (void) close(fd); 377. return 1; 378. } 379. remember_topl(); 380. home(); 381. cl_end(); 382. msmsg("If save file is on a SAVE disk, put that disk in now.
"); 383. cl_end(); 384. msmsg("File name (default `%s'%s) ? ", SAVEF, 385. start ? "" : ", cancels save"); 386. getlin(buf); 387. home(); 388. cl_end(); 389. curs(1, 2); 390. cl_end(); 391. if (!start && *buf == '\033') 392. return 0; 393. 394. /* Strip any whitespace. Also, if nothing was entered except 395. * whitespace, do not change the value of SAVEF. 396. */ 397. for (bp = buf; *bp; bp++) 398. if (!isspace(*bp)) { 399. strncpy(SAVEF, bp, PATHLEN); 400. break; 401. } 402. } 403. return 1; 404. } 405. 406. /* Return 1 if the record file was found */ 407. static 408. record_exists() { 409. int fd; 410. 411. if ((fd = open(RECORD, 0)) >= 0) { 412. close(fd); 413. return TRUE; 414. } 415. return FALSE; 416. } 417. 418. /* Return 1 if the comspec was found */ 419. static 420. comspec_exists() { 421. int fd; 422. char *comspec; 423. 424. if (comspec = getcomspec()) 425. if ((fd = open(comspec, 0)) >= 0) { 426. close(fd); 427. return TRUE; 428. } 429. return FALSE; 430. } 431. 432. /* Prompt for game disk, then check for record file. 433. */ 434. void 435. gameDiskPrompt() { 436. extern saveprompt; 437. 438. if (saveprompt) { 439. if (record_exists() && comspec_exists()) 440. return; 441. (void) putchar('
'); 442. getreturn("when the GAME disk has been put in"); 443. } 444. if (comspec_exists() && record_exists()) 445. return; 446. 447. if (!comspec_exists()) 448. msmsg("
WARNING: can't find comspec `%s'!
", getcomspec()); 449. if (!record_exists()) 450. msmsg("
WARNING: can't find record file `%s'!
", RECORD); 451. msmsg("If the GAME disk is not in, put it in now.
"); 452. getreturn("to continue"); 453. } 454. 455. /* Read configuration */ 456. void 457. read_config_file() { 458. char tmp_ramdisk[PATHLEN], tmp_levels[PATHLEN]; 459. char buf[BUFSZ], *bufp; 460. FILE *fp, *fopenp(); 461. extern char plname[]; 462. extern int saveprompt; 463. 464. tmp_ramdisk[0] = 0; 465. tmp_levels[0] = 0; 466. if ((fp = fopenp(configfile, "r")) == NULL) { 467. msmsg("Warning: no configuration file!
"); 468. getreturn("to continue"); 469. return; 470. } 471. while (fgets(buf, BUFSZ, fp)) { 472. if (*buf == '#') 473. continue; 474. 475. /* remove trailing whitespace 476. */ 477. bufp = index(buf, '
'); 478. while (bufp > buf && isspace(*bufp)) 479. bufp--; 480. if (bufp == buf) 481. continue; /* skip all-blank lines */ 482. else 483. *(bufp + 1) = 0; /* 0 terminate line */ 484. 485. /* find the '=' */ 486. if (!(bufp = strchr(buf, '='))) { 487. msmsg("Bad option line: '%s'
", buf); 488. getreturn("to continue"); 489. continue; 490. } 491. 492. /* skip whitespace between '=' and value */ 493. while (isspace(*++bufp)) 494. ; 495. 496. /* Go through possible variables */ 497. if (!strncmp(buf, "HACKDIR", 4)) { 498. strncpy(hackdir, bufp, PATHLEN); 499. 500. } else if (!strncmp(buf, "RAMDISK", 3)) { 501. strncpy(tmp_ramdisk, bufp, PATHLEN); 502. 503. } else if (!strncmp(buf, "LEVELS", 4)) { 504. strncpy(tmp_levels, bufp, PATHLEN); 505. 506. } else if (!strncmp(buf, "OPTIONS", 4)) { 507. parseoptions(bufp, TRUE); 508. if (plname[0]) /* If a name was given */ 509. plnamesuffix(); /* set the character class */ 510. 511. } else if (!strncmp(buf, "SAVE", 4)) { 512. char *ptr; 513. if (ptr = index(bufp, ';')) { 514. *ptr = '\0'; 515. if (*(ptr+1) == 'n' || *(ptr+1) == 'N') 516. saveprompt = FALSE; 517. } 518. (void) strncpy(SAVEF, bufp, PATHLEN); 519. append_slash(SAVEF); 520. #ifdef GRAPHICS 521. } else if (!strncmp(buf, "GRAPHICS", 4)) { 522. char translate[17]; 523. short i; 524. 525. if ((i = sscanf(bufp, "%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u", 526. &translate[0], &translate[1], &translate[2], 527. &translate[3], &translate[4], &translate[5], 528. &translate[6], &translate[7], &translate[8], 529. &translate[9], &translate[10], &translate[11], 530. &translate[12], &translate[13], &translate[14], 531. &translate[15], &translate[16])) < 0) { 532. msmsg ("Syntax error in GRAPHICS
"); 533. getreturn("to continue"); 534. } 535. translate[i] = '\0'; 536. #endif /* GRAPHICS /**/ 537. /* 538. * You could have problems here if you configure FOUNTAINS, SPIDERS or NEWCLASS 539. * in or out and forget to change the tail entries in your graphics string. 540. */ 541. #define SETPCHAR(f, n) showsyms.f = (strlen(translate) > n) ? translate[n] : defsyms.f 542. SETPCHAR(stone, 0); 543. SETPCHAR(vwall, 1); 544. SETPCHAR(hwall, 2); 545. SETPCHAR(tlcorn, 3); 546. SETPCHAR(trcorn, 4); 547. SETPCHAR(blcorn, 5); 548. SETPCHAR(brcorn, 6); 549. SETPCHAR(door, 7); 550. SETPCHAR(room, 8); 551. SETPCHAR(corr, 9); 552. SETPCHAR(upstair, 10); 553. SETPCHAR(dnstair, 11); 554. SETPCHAR(trap, 12); 555. #ifdef FOUNTAINS 556. SETPCHAR(pool, 13); 557. SETPCHAR(fountain, 14); 558. #endif 559. #ifdef NEWCLASS 560. SETPCHAR(throne, 15); 561. #endif 562. #ifdef SPIDERS 563. SETPCHAR(web, 16); 564. #endif 565. #undef SETPCHAR 566. } else { 567. msmsg("Bad option line: '%s'
", buf); 568. getreturn("to continue"); 569. } 570. } 571. fclose(fp); 572. 573. strcpy(permbones, tmp_levels); 574. if (tmp_ramdisk[0]) { 575. strcpy(levels, tmp_ramdisk); 576. if (strcmpi(permbones, levels)) /* if not identical */ 577. ramdisk = TRUE; 578. } else 579. strcpy(levels, tmp_levels); 580. strcpy(bones, levels); 581. } 582. 583. /* Set names for bones[] and lock[] 584. */ 585. void 586. set_lock_and_bones() { 587. if (!ramdisk) { 588. strcpy(levels, permbones); 589. strcpy(bones, permbones); 590. } 591. append_slash(permbones); 592. append_slash(levels); 593. append_slash(bones); 594. strcat(bones, allbones); 595. strcpy(lock, levels); 596. strcat(lock, alllevels); 597. } 598. 599. /* Add a backslash to any name not ending in /, \ or : There must 600. * be room for the \ 601. */ 602. void 603. append_slash(name) 604. char *name; 605. { 606. char *ptr; 607. 608. if (!*name) 609. return; 610. ptr = name + (strlen(name) - 1); 611. if (*ptr != '\\' && *ptr != '/' && *ptr != ':') { 612. *++ptr = '\\'; 613. *++ptr = '\0'; 614. } 615. } 616. 617. 618. void 619. getreturn(str) 620. char *str; 621. { 622. int ch; 623. 624. msmsg("Hit %s.", str); 625. while ((ch = getchar()) != '
') 626. ; 627. } 628. 629. void 630. msmsg(fmt, a1, a2, a3) 631. char *fmt; 632. long a1, a2, a3; 633. { 634. printf(fmt, a1, a2, a3); 635. flushout(); 636. } 637. 638. /* Chdrive() changes the default drive. 639. */ 640. #define SELECTDISK 0x0E 641. void 642. chdrive(str) 643. char *str; 644. { 645. char *ptr; 646. union REGS inregs; 647. char drive; 648. 649. if ((ptr = index(str, ':')) != NULL) { 650. drive = toupper(*(ptr - 1)); 651. inregs.h.ah = SELECTDISK; 652. inregs.h.dl = drive - 'A'; 653. intdos(&inregs, &inregs); 654. } 655. } 656. 657. /* Use the IOCTL DOS function call to change stdin and stdout to raw 658. * mode. For stdin, this prevents MSDOS from trapping ^P, thus 659. * freeing us of ^P toggling 'echo to printer'. 660. * Thanks to Mark Zbikowski (markz@microsoft.UUCP). 661. */ 662. 663. # define DEVICE 0x80 664. # define RAW 0x20 665. # define IOCTL 0x44 666. # define STDIN fileno(stdin) 667. # define STDOUT fileno(stdout) 668. # define GETBITS 0 669. # define SETBITS 1 670. 671. static unsigned old_stdin, old_stdout, ioctl(); 672. 673. disable_ctrlP() { 674. if (!flags.rawio) 675. return; 676. old_stdin = ioctl(STDIN, GETBITS, 0); 677. old_stdout = ioctl(STDOUT, GETBITS, 0); 678. if (old_stdin & DEVICE) 679. ioctl(STDIN, SETBITS, old_stdin | RAW); 680. if (old_stdout & DEVICE) 681. ioctl(STDOUT, SETBITS, old_stdout | RAW); 682. } 683. 684. enable_ctrlP() { 685. if (!flags.rawio) 686. return; 687. if (old_stdin) 688. (void) ioctl(STDIN, SETBITS, old_stdin); 689. if (old_stdout) 690. (void) ioctl(STDOUT, SETBITS, old_stdout); 691. } 692. 693. static unsigned 694. ioctl(handle, mode, setvalue) 695. unsigned setvalue; 696. { 697. union REGS regs; 698. 699. regs.h.ah = IOCTL; 700. regs.h.al = mode; 701. regs.x.bx = handle; 702. regs.h.dl = setvalue; 703. regs.h.dh = 0; /* Zero out dh */ 704. intdos(®s, ®s); 705. return (regs.x.dx); 706. } 707. 708. /* Follow the PATH, trying to fopen the file. 709. */ 710. #define PATHSEP ';' 711. 712. FILE * 713. fopenp(name, mode) 714. char *name, *mode; 715. { 716. char buf[BUFSIZ], *bp, *pp, *getenv(), lastch; 717. FILE *fp; 718. 719. /* Try the default directory first. Then look along PATH. 720. */ 721. strcpy(buf, name); 722. if (fp = fopen(buf, mode)) 723. return fp; 724. else { 725. pp = getenv("PATH"); 726. while (pp && *pp) { 727. bp = buf; 728. while (*pp && *pp != PATHSEP) 729. lastch = *bp++ = *pp++; 730. if (lastch != '\\' && lastch != '/') 731. *bp++ = '\\'; 732. strcpy(bp, name); 733. if (fp = fopen(buf, mode)) 734. return fp; 735. if (*pp) 736. pp++; 737. } 738. } 739. return NULL; 740. } 741. # endif /* DGK */ 742. 743. /* Chdir back to original directory 744. */ 745. # undef exit 746. void 747. msexit(code) 748. { 749. # ifdef CHDIR 750. extern char orgdir[]; 751. # endif 752. 753. # ifdef DGK 754. flushout(); 755. enable_ctrlP(); /* in case this wasn't done */ 756. if (ramdisk) 757. copybones(TOPERM); 758. # endif 759. # ifdef CHDIR 760. chdir(orgdir); /* chdir, not chdirx */ 761. # ifdef DGK 762. chdrive(orgdir); 763. # endif 764. # endif 765. exit(code); 766. } 767. #endif /* MSDOS */
|