Source:NetHack 2.2a/msdos.c

Below is the full text to msdos.c from the source code of NetHack 2.2a. To link to a particular line, write [[NetHack 2.2a/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.1	87/10/19 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 == '\r') ? '\n' : 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 == '\r') ? '\n' : 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(&regs, &regs); 64.  	if (!regs.h.al) {	/* an extended code -- not yet supported */ 65.  		regs.h.ah = DIRECT_INPUT; 66.  		intdos(&regs, &regs);	/* 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 87.  #   include   88. dosh { 89.  	extern char orgdir[]; 90.  	char *comspec; 91.   92.   	if (comspec = getcomspec) { 93.  		settty("To return to HACK, type \"exit\" at the DOS prompt.\n"); 94.  		chdirx(orgdir, 0); 95.  		if (spawnl(P_WAIT, comspec, comspec, NULL) < 0) { 96.  			printf("\nCan't spawn %s !\n", 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, &regs, &regs); 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, &regs, &regs); 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(&regs, &regs); 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(&regs, &regs); 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(&regs, &regs, &sregs); 229. 	return !regs.x.cflag; 230. }  231.   232.  static 233. findnext { 234. 	union REGS regs; 235.  236.  	regs.x.ax = FINDNEXT; 237. 	intdos(&regs, &regs); 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(&regs, &regs, &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\n", 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'\n",  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 ...\n"); 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.\n"); 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('\n'); 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("\n\nWARNING: can't find comspec `%s'!\n", getcomspec); 449. 	if (!record_exists) 450. 		msmsg("\n\nWARNING: can't find record file `%s'!\n", RECORD); 451. 	msmsg("If the GAME disk is not in, put it in now.\n"); 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!\n"); 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, '\n'); 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'\n", 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\n"); 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'\n", 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) != '\n') 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(&regs, &regs); 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 */