Source:NetHack 1.3d/msdos.c

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

1.   /*	SCCS Id: @(#)msdos.c	1.3	87/07/14 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.    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(&regs, &regs); 49.  	if (!regs.h.al) {	/* an extended code -- not yet supported */ 50.  		regs.h.ah = DIRECT_INPUT; 51.  		intdos(&regs, &regs);	/* 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   60. # include   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   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, &regs, &regs); 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, &regs, &regs); 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(&regs, &regs); 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(&regs, &regs); 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(&regs, &regs, &sregs); 214. 	return !regs.x.cflag; 215. }  216.   217.  static 218. findnext { 219. 	union REGS regs; 220.  221.  	regs.x.ax = FINDNEXT; 222. 	intdos(&regs, &regs); 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(&regs, &regs, &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 ? "" : ",  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  %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(&regs, &regs); 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 */