Source:NetHack 1.4f/msdos.c

Below is the full text to msdos.c from the source code of NetHack 1.4f. To link to a particular line, write [[NetHack 1.4f/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.4	87/08/08 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.  #ifndef __TURBOC__ 227. /* Get disk transfer area, Turbo C already has getdta */ 228. static char * 229. getdta { 230. 	union REGS regs; 231. 	struct SREGS sregs; 232. 	char *ret; 233.  234.  	regs.x.ax = GETDTA; 235. 	intdosx(&regs, &regs, &sregs); 236. 	FP_OFF(ret) = regs.x.bx; 237. 	FP_SEG(ret) = sregs.es; 238. 	return ret; 239. }  240.  #endif 241.  242.  long 243. filesize(file) 244. char *file; 245. {  246.  	char *dta; 247.  248.  	if (findfirst(file)) { 249. 		dta = getdta; 250. 		return  (* (long *) (dta + 26)); 251. 	} else 252. 		return -1L; 253. }  254.   255.  void 256. eraseall(path, files) 257. char *path, *files; 258. {  259.  	char	*dta, buf[PATHLEN]; 260.  261.  	dta = getdta; 262. 	Sprintf(buf, "%s%s", path, files); 263. 	if (findfirst(buf)) 264. 		do { 265. 			Sprintf(buf, "%s%s", path, dta + 30); 266. 			(void) unlink(buf); 267. 		} while (findnext); 268. }  269.   270.  /* Rewritten for version 3.3 to be faster 271.  */  272.  void 273. copybones(mode) { 274. 	char from[PATHLEN], to[PATHLEN], last[13], copy[8]; 275. 	char *frompath, *topath, *dta, *comspec; 276. 	int status; 277. 	long fs; 278. 	extern saveprompt; 279.  280.  	if (!ramdisk) 281. 		return; 282.  283.  	/* Find the name of the last file to be transferred 284. 	 */  285.  	frompath = (mode != TOPERM) ? permbones : levels; 286. 	dta = getdta; 287. 	last[0] = '\0'; 288. 	Sprintf(from, "%s%s", frompath, allbones); 289. 	if (findfirst(from)) 290. 		do { 291. 			strcpy(last, dta + 30); 292. 		} while (findnext); 293.  294.  	topath = (mode == TOPERM) ? permbones : levels; 295. 	if (last[0]) { 296. 		Sprintf(copy, "%cC copy", switchar); 297.  298.  		/* Remove any bones files in `to' directory. 299. 		 */  300.  		eraseall(topath, allbones); 301.  302.  		/* Copy `from' to `to' */ 303. 		Sprintf(to, "%s%s", topath, allbones); 304. 		comspec = getcomspec; 305. 		status =spawnl(P_WAIT, comspec, comspec, copy, from,  306.  			to, "> nul", NULL); 307. 	} else 308. 		return; 309.  310.  	/* See if the last file got there. If so, remove the ramdisk bones 311. 	 * files. 312. 	 */  313.  	Sprintf(to, "%s%s", topath, last); 314. 	if (findfirst(to)) { 315. 		if (mode == TOPERM) 316. 			eraseall(frompath, allbones); 317. 		return; 318. 	}  319.   320.  	/* Last file didn't get there. 321. 	 */  322.  	Sprintf(to, "%s%s", topath, allbones); 323. 	msmsg("Cannot copy `%s' to `%s' -- %s\n", from, to,  324.  		(status < 0) ? "can't spawn COMSPEC !" :  325.  		(freediskspace(topath) < filesize(from)) ?  326.  			"insufficient disk space." : "bad path(s)?"); 327. 	if (mode == TOPERM) { 328. 		msmsg("Bones will be left in `%s'\n",  329.  			*levels ? levels : hackdir); 330. 		return; 331. 	} else { 332. 		/* Remove all bones files on the RAMdisk */ 333. 		eraseall(levels, allbones); 334. 		playwoRAMdisk; 335. 	}  336.  }  337.   338.  playwoRAMdisk { 339. 	msmsg("Do you wish to play without a RAMdisk (y/n) ? "); 340.  341.  	/* Set ramdisk false *before* exit'ing (because msexit calls  342.  	 * copybones) 343. 	 */  344.  	ramdisk = FALSE; 345. 	if (getchar != 'y') { 346. 		settty("Be seeing you ...\n"); 347. 		exit(0); 348. 	}  349.  	set_lock_and_bones; 350. 	return; 351. }  352.   353.  saveDiskPrompt(start) { 354. 	extern saveprompt; 355. 	char buf[BUFSIZ], *bp; 356. 	int fd; 357.  358.  	if (saveprompt) { 359. 		/* Don't prompt if you can find the save file */ 360. 		if ((fd = open(SAVEF, 0)) >= 0) { 361. 			(void) close(fd); 362. 			return 1; 363. 		}  364.  		remember_topl; 365. 		home; 366. 		cl_end; 367. 		msmsg("If save file is on a SAVE disk, put that disk in now.\n"); 368. 		cl_end; 369. 		msmsg("File name (default `%s'%s) ? ", SAVEF,  370.  			start ? "" : ",  cancels save"); 371. 		getlin(buf); 372. 		home; 373. 		cl_end; 374. 		curs(1, 2); 375. 		cl_end; 376. 		if (!start && *buf == '\033') 377. 			return 0; 378.  379.  		/* Strip any whitespace. Also, if nothing was entered except 380. 		 * whitespace, do not change the value of SAVEF. 381. 		 */  382.  		for (bp = buf; *bp; bp++) 383. 			if (!isspace(*bp)) { 384. 				strncpy(SAVEF, bp, PATHLEN); 385. 				break; 386. 			}  387.  	}  388.  	return 1; 389. }  390.   391.  /* Return 1 if the record file was found */ 392. static 393. record_exists { 394. 	int fd; 395.  396.  	if ((fd = open(RECORD, 0)) >= 0) { 397. 		close(fd); 398. 		return TRUE; 399. 	}  400.  	return FALSE; 401. }  402.   403.  /* Return 1 if the comspec was found */ 404. static 405. comspec_exists { 406. 	int fd; 407. 	char *comspec; 408.  409.  	if (comspec = getcomspec) 410. 		if ((fd = open(comspec, 0)) >= 0) { 411. 			close(fd); 412. 			return TRUE; 413. 		}  414.  	return FALSE; 415. }  416.   417.  /* Prompt for game disk, then check for record file. 418.  */  419.  void 420. gameDiskPrompt { 421. 	extern saveprompt; 422.  423.  	if (saveprompt) { 424. 		if (record_exists && comspec_exists) 425. 			return; 426. 		(void) putchar('\n'); 427. 		getreturn("when the GAME disk has been put in"); 428. 	}  429.  	if (comspec_exists && record_exists) 430. 		return; 431.  432.  	if (!comspec_exists) 433. 		msmsg("\n\nWARNING: can't find comspec `%s'!\n", getcomspec); 434. 	if (!record_exists) 435. 		msmsg("\n\nWARNING: can't find record file `%s'!\n", RECORD); 436. 	msmsg("If the GAME disk is not in, put it in now.\n"); 437. 	getreturn("to continue"); 438. }  439.   440.  /* Read configuration */ 441. void 442. read_config_file { 443. 	char	tmp_ramdisk[PATHLEN], tmp_levels[PATHLEN]; 444. 	char	buf[BUFSZ], *bufp; 445. 	FILE	*fp, *fopenp; 446. 	extern	char plname[]; 447. 	extern	int saveprompt; 448.  449.  	tmp_ramdisk[0] = 0; 450. 	tmp_levels[0] = 0; 451. 	if ((fp = fopenp(configfile, "r")) == NULL) { 452. 		msmsg("Warning: no configuration file!\n"); 453. 		getreturn("to continue"); 454. 		return; 455. 	}  456.  	while (fgets(buf, BUFSZ, fp)) { 457. 		if (*buf == '#') 458. 			continue; 459.  460.  		/* remove trailing whitespace 461. 		 */  462.  		bufp = index(buf, '\n'); 463. 		while (bufp > buf && isspace(*bufp)) 464. 			bufp--; 465. 		if (bufp == buf) 466. 			continue;		/* skip all-blank lines */ 467. 		else 468. 			*(bufp + 1) = 0;	/* 0 terminate line */ 469.  470.  		/* find the '=' */ 471. 		if (!(bufp = strchr(buf, '='))) { 472. 			msmsg("Bad option line: '%s'\n", buf); 473. 			getreturn("to continue"); 474. 			continue; 475. 		}  476.  		  477.  		/* skip  whitespace between '=' and value */ 478. 		while (isspace(*++bufp)) 479. 			;  480.   481.  		/* Go through possible variables */ 482. 		if (!strncmp(buf, "HACKDIR", 4)) { 483. 			strncpy(hackdir, bufp, PATHLEN); 484. 		  485.  		} else if (!strncmp(buf, "RAMDISK", 3)) { 486. 			strncpy(tmp_ramdisk, bufp, PATHLEN); 487.  488.  		} else if (!strncmp(buf, "LEVELS", 4)) { 489. 			strncpy(tmp_levels, bufp, PATHLEN); 490.  491.  		} else if (!strncmp(buf, "OPTIONS", 4)) { 492. 			parseoptions(bufp, TRUE); 493. 			if (plname[0])		/* If a name was given */ 494. 				plnamesuffix;	/* set the character class */ 495.  496.  		} else if (!strncmp(buf, "SAVE", 4)) { 497. 			char *ptr; 498. 			if (ptr = index(bufp, ';')) { 499. 				*ptr = '\0'; 500. 				if (*(ptr+1) == 'n' || *(ptr+1) == 'N') 501. 					saveprompt = FALSE; 502. 			}  503.  			(void) strncpy(SAVEF, bufp, PATHLEN); 504. 			append_slash(SAVEF); 505.  506.  		} else if (!strncmp(buf, "GRAPHICS", 4)) { 507. 			struct symbols s;  508. 509. 			if (sscanf(bufp, "%u%u%u%u%u%u%u%u%u", &s.vwall, 510. 				    &s.hwall, &s.tlcorn, &s.trcorn, &s.blcorn, 511. 				    &s.brcorn, &s.door, &s.room, &s.corr) == 9) 512. 				symbol = s;  513. else { 514. 				msmsg("GRAPHICS did not contain 9 values\n"); 515. 				getreturn("to continue"); 516. 			}  517.  		} else { 518. 			msmsg("Bad option line: '%s'\n", buf); 519. 			getreturn("to continue"); 520. 		}  521.  	}  522.  	fclose(fp); 523.  524.  	strcpy(permbones, tmp_levels); 525. 	if (tmp_ramdisk[0]) { 526. 		strcpy(levels, tmp_ramdisk); 527. 		if (strcmpi(permbones, levels))		/* if not identical */ 528. 			ramdisk = TRUE; 529. 	} else 530. 		strcpy(levels, tmp_levels); 531. 	strcpy(bones, levels); 532. }  533.   534.  /* Set names for bones[] and lock[] 535.  */  536.  void 537. set_lock_and_bones { 538. 	if (!ramdisk) { 539. 		strcpy(levels, permbones); 540. 		strcpy(bones, permbones); 541. 	}  542.  	append_slash(permbones); 543. 	append_slash(levels); 544. 	append_slash(bones); 545. 	strcat(bones, allbones); 546. 	strcpy(lock, levels); 547. 	strcat(lock, alllevels); 548. }  549.   550.  /* Add a backslash to any name not ending in /, \ or :   There must 551.  * be room for the \ 552.  */  553.  void 554. append_slash(name) 555. char *name; 556. {  557.  	char *ptr; 558.  559.  	if (!*name) 560. 		return; 561. 	ptr = name + (strlen(name) - 1); 562. 	if (*ptr != '\\' && *ptr != '/' && *ptr != ':') { 563. 		*++ptr = '\\'; 564. 		*++ptr = '\0'; 565. 	}  566.  }  567.   568.   569.  void 570. getreturn(str) 571. char *str; 572. {  573.  	int ch; 574.  575.  	msmsg("Hit  %s.", str); 576. 	while ((ch = getchar) != '\n') 577. 		;  578.  }  579.   580.  void 581. msmsg(fmt, a1, a2, a3) 582. char *fmt; 583. long a1, a2, a3; 584. {  585.  	printf(fmt, a1, a2, a3); 586. 	flushout; 587. }  588.   589.  /* Chdrive changes the default drive. 590.  */  591.  #define SELECTDISK	0x0E 592. void 593. chdrive(str) 594. char *str; 595. {  596.  	char *ptr; 597. 	union REGS inregs; 598. 	char drive; 599.  600.  	if ((ptr = index(str, ':')) != NULL) { 601. 		drive = toupper(*(ptr - 1)); 602. 		inregs.h.ah = SELECTDISK; 603. 		inregs.h.dl = drive - 'A'; 604. 		intdos(&inregs, &inregs); 605. 	}  606.  }  607.   608.  /* Use the IOCTL DOS function call to change stdin and stdout to raw 609.  * mode. For stdin, this prevents MSDOS from trapping ^P, thus 610.  * freeing us of ^P toggling 'echo to printer'. 611.  * Thanks to Mark Zbikowski (markz@microsoft.UUCP). 612.  */  613.   614.  #  define DEVICE	0x80 615. #  define RAW		0x20 616. #  define IOCTL		0x44 617. #  define STDIN		fileno(stdin) 618. #  define STDOUT	fileno(stdout) 619. #  define GETBITS	0 620. #  define SETBITS	1 621.  622.  static unsigned	old_stdin, old_stdout, ioctl; 623.  624.  disable_ctrlP { 625. 	if (!flags.rawio) 626. 		return; 627. 	old_stdin = ioctl(STDIN, GETBITS, 0); 628. 	old_stdout = ioctl(STDOUT, GETBITS, 0); 629. 	if (old_stdin & DEVICE) 630. 		ioctl(STDIN, SETBITS, old_stdin | RAW); 631. 	if (old_stdout & DEVICE) 632. 		ioctl(STDOUT, SETBITS, old_stdout | RAW); 633. }  634.   635.  enable_ctrlP { 636. 	if (!flags.rawio) 637. 		return; 638. 	if (old_stdin) 639. 		(void) ioctl(STDIN, SETBITS, old_stdin); 640. 	if (old_stdout) 641. 		(void) ioctl(STDOUT, SETBITS, old_stdout); 642. }  643.   644.  static unsigned 645. ioctl(handle, mode, setvalue) 646. unsigned setvalue; 647. {  648.  	union REGS regs; 649.  650.  	regs.h.ah = IOCTL; 651. 	regs.h.al = mode; 652. 	regs.x.bx = handle; 653. 	regs.h.dl = setvalue; 654. 	regs.h.dh = 0;			/* Zero out dh */ 655. 	intdos(&regs, &regs); 656. 	return (regs.x.dx); 657. }  658.   659.  /* Follow the PATH, trying to fopen the file. 660.  */  661.  #define PATHSEP	';' 662.  663.  FILE * 664. fopenp(name, mode) 665. char *name, *mode; 666. {  667.  	char buf[BUFSIZ], *bp, *pp, *getenv, lastch; 668. 	FILE *fp; 669.  670.  	/* Try the default directory first. Then look along PATH. 671. 	 */  672.  	strcpy(buf, name); 673. 	if (fp = fopen(buf, mode)) 674. 		return fp; 675. 	else { 676. 		pp = getenv("PATH"); 677. 		while (pp && *pp) { 678. 			bp = buf; 679. 			while (*pp && *pp != PATHSEP) 680. 				lastch = *bp++ = *pp++; 681. 			if (lastch != '\\' && lastch != '/') 682. 				*bp++ = '\\'; 683. 			strcpy(bp, name); 684. 			if (fp = fopen(buf, mode)) 685. 				return fp; 686. 			if (*pp) 687. 				pp++; 688. 		}  689.  	}  690.  	return NULL; 691. }  692.  # endif /* DGK */ 693.  694.  /* Chdir back to original directory 695.  */  696.  # undef exit 697. void 698. msexit(code) 699. {  700.  # ifdef CHDIR 701. 	extern char orgdir[]; 702. # endif 703.  704.  # ifdef DGK 705. 	flushout; 706. 	enable_ctrlP;		/* in case this wasn't done */ 707. 	if (ramdisk) 708. 		copybones(TOPERM); 709. # endif 710. # ifdef CHDIR 711. 	chdir(orgdir);		/* chdir, not chdirx */ 712. #  ifdef DGK 713. 	chdrive(orgdir); 714. #  endif 715. # endif 716. 	exit(code); 717. }  718.  #endif /* MSDOS */