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