pc-hack

PC HACK 3.61 source code (archival)
git clone http://frotz.net/git/pc-hack.git
Log | Files | Refs

msdos.c (14805B)


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