[comp.sources.games] v07i077: NetHack3 - display oriented dungeons & dragons

billr@saab.CNA.TEK.COM (Bill Randle) (07/25/89)

Submitted-by: Izchak Miller <izchak@linc.cis.upenn.edu>
Posting-number: Volume 7, Issue 77
Archive-name: NetHack3/Part22



#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 22 (of 38)."
# Contents:  amiga/amidos.c include/mkroom.h others/msdos.c
#   others/tos.c
# Wrapped by billr@saab on Sun Jul 23 21:33:05 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'amiga/amidos.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'amiga/amidos.c'\"
else
echo shar: Extracting \"'amiga/amidos.c'\" \(16238 characters\)
sed "s/^X//" >'amiga/amidos.c' <<'END_OF_FILE'
X/*    SCCS Id: @(#)amidos.c msdos.c - Amiga version   3.0    89/05/01
X/* NetHack may be freely redistributed.  See license for details. */
X/* An assortment of imitations of cheap plastic MSDOS functions.
X */
X
X#include <libraries/dos.h>
X
X#undef TRUE
X#undef FALSE
X#undef COUNT
X#undef NULL
X
X#include "hack.h"
X
Xextern char Initialized;
X
Xstruct FileLock *Lock(), *CurrentDir(); /* Cheating - BCPL pointers */
Xstruct FileHandle *Open();              /* Cheating - BCPL pointer */
Xlong Read(), Write(), IoErr(), AvailMem();
Xvoid *malloc();
Xchar *rindex(), *index();
X
Xint Enable_Abort = 0;	/* for stdio package */
X
X/* Initial path, so we can find NetHack.cnf */
X
Xchar PATH[PATHLEN] = "Ram:;df0:;NetHack:";
X
Xvoid
Xflushout()
X{
X    (void) fflush(stdout);
X}
X
X#ifndef getuid
Xgetuid()
X{
X    return 1;
X}
X#endif
X
X/*
X *  Actually make up a process id.
X *  Makes sure one can mess less with saved levels...
X */
X
Xint getpid()
X{
X    static short pid;
X
X    while (pid == 0) {
X	struct DateStamp dateStamp;
X	pid = rnd(30000);
X	pid += DateStamp(&dateStamp);    /* More or less random */
X	pid ^= (short) (dateStamp.ds_Days >> 16) ^
X	       (short) (dateStamp.ds_Days)       ^
X	       (short) (dateStamp.ds_Minute)     +
X	       (short) (dateStamp.ds_Tick);
X	pid %= 30000;
X    }
X
X    return pid;
X}
X
X#ifndef getlogin
Xchar *
Xgetlogin()
X{
X    return ((char *) NULL);
X}
X#endif
X
Xint
Xabs(x)
Xint x;
X{
X    return x < 0? -x: x;
X}
X
X#ifdef REDO
X
Xint
Xtgetch()
X{
X    char ch, popch();
X
X    if (!(ch = popch())) {
X	ch = WindowGetchar();
X    }
X    return ((ch == '\r') ? '\n' : ch);
X}
X#else /* REDO /**/
Xint
Xtgetch() {
X    char ch;
X
X    ch = WindowGetchar();
X    return ((ch == '\r') ? '\n' : ch);
X}
X#endif /* REDO /**/
X
X
X#ifdef DGK
X# include <ctype.h>
X/* # include <fcntl.h> */
X
X# define Sprintf (void) sprintf
X
X# ifdef SHELL
Xint
Xdosh()
X{
X    pline("No mysterious force prevented you from using multitasking.");
X    return 0;
X}
X# endif /* SHELL */
X
X#define ID_DOS1_DISK	'DOS\1'
X#define EXTENSION	72
X
X/*
X *  This routine uses an approximation of the free bytes on a disk.
X *  How large a file you can actually write depends on the number of
X *  extension blocks you need for it.
X *  In each extenstion block there are maximum 72 pointers to blocks,
X *  so every 73 disk blocks have only 72 available for data.
X *  The (necessary) file header is also good for 72 data block pointers.
X */
Xlong
Xfreediskspace(path)
Xchar *path;
X{
X    register long freeBytes = 0;
X    register struct InfoData *infoData; /* Remember... longword aligned */
X    char fileName[32];
X
X    /*
X     *	Find a valid path on the device of which we want the free space.
X     *	If there is a colon in the name, it is an absolute path
X     *	and all up to the colon is everything we need.
X     *	Remember slashes in a volume name are allowed!
X     *	If there is no colon, it is relative to the current directory,
X     *	so must be on the current device, so "" is enough...
X     */
X    {
X	register char *colon;
X
X	strncpy(fileName, path, sizeof(fileName)-1);
X	fileName[31] = 0;
X	if (colon = index(fileName, ':'))
X	    colon[1] = '\0';
X	else
X	    fileName[0] = '\0';
X    }
X
X    if (infoData = malloc(sizeof(*infoData))) {
X	struct FileLock *fileLock;  /* Cheating */
X	if (fileLock = Lock(fileName, SHARED_LOCK)) {
X	    if (Info(fileLock, infoData)) {
X		/* We got a kind of DOS volume, since we can Lock it. */
X		/* Calculate number of blocks available for new file */
X		/* Kludge for the ever-full VOID: (oops RAM:) device */
X		if (infoData->id_UnitNumber == -1 &&
X		    infoData->id_NumBlocks == infoData->id_NumBlocksUsed) {
X		    freeBytes = AvailMem(0L) - 64 * 1024L;
X		    /* Just a stupid guess at the */
X		    /* Ram-Handler overhead per block: */
X		    freeBytes -= freeBytes/16;
X		} else {
X		    /* Normal kind of DOS file system device/volume */
X		    freeBytes = infoData->id_NumBlocks -
X				infoData->id_NumBlocksUsed;
X		    freeBytes -= (freeBytes + EXTENSION) / (EXTENSION + 1);
X		    freeBytes *= infoData->id_BytesPerBlock;
X		}
X		if (freeBytes < 0)
X		    freeBytes = 0;
X	    }
X	    UnLock(fileLock);
X	}
X	free(infoData);
X    }
X    return freeBytes;
X}
X
X
Xlong
Xfilesize(file)
Xchar *file;
X{
X    register struct FileLock *fileLock;
X    register struct FileInfoBlock *fileInfoBlock;
X    register long size = 0;
X
X    if (fileInfoBlock = malloc(sizeof(*fileInfoBlock))) {
X	if (fileLock = Lock(file, SHARED_LOCK)) {
X	    if (Examine(fileLock, fileInfoBlock)) {
X		size = fileInfoBlock->fib_Size;
X	    }
X	    UnLock(fileLock);
X	}
X	free(fileInfoBlock);
X    }
X    return size;
X}
X
X/*
X *  On the Amiga, looking if a specific file exists is much faster
X *  than sequentially reading a directory.
X */
X
Xvoid
Xeraseall(path, files)
Xchar *path, *files;
X{
X    char buf[FILENAME];
X    short i;
X    struct FileLock *fileLock, *dirLock;
X
X    if (dirLock = Lock(path)) {
X	dirLock = CurrentDir(dirLock);
X
X	strcpy(buf, files);
X	for (i = 0; i < MAXLEVEL; i++) {
X	    name_file(buf, i);
X	    if (fileLock = Lock(buf, SHARED_LOCK)) {
X		UnLock(fileLock);
X		DeleteFile(buf);
X	    }
X	}
X
X	UnLock(CurrentDir(dirLock));
X    }
X}
X
X/* This size makes that most files can be copied with two Read()/Write()s */
X
X#define COPYSIZE    4096
X
Xchar *CopyFile(from, to)
Xchar *from, *to;
X{
X    register struct FileHandle *fromFile, *toFile;
X    register char *buffer;
X    register long size;
X    char *error = NULL;
X
X    if (buffer = malloc(COPYSIZE)) {
X	if (fromFile = Open(from, MODE_OLDFILE)) {
X	    if (toFile = Open(to, MODE_NEWFILE)) {
X		while (size = Read(fromFile, buffer, (long)COPYSIZE)) {
X		    if (size != Write(toFile, buffer, size)) {
X			error = "Write error";
X			break;
X		    }
X		}
X		Close(toFile);
X	    } else /* Can't open destination file */
X		error = "Cannot open destination";
X	    Close(fromFile);
X	} else /* Cannot open source file. Should not happen. */
X	    error = "Huh?? Cannot open source??";
X	free(buffer);
X	return error;
X    } else /* Cannot obtain buffer for copying */
X	return "No Memory !";
X}
X
Xvoid
Xcopybones(mode)
Xint mode;
X{
X    struct FileLock *fileLock;
X    char from[FILENAME], to[FILENAME];
X    char *frompath, *topath, *status;
X    short i;
X    extern int saveprompt;
X
X    if (!ramdisk)
X	return;
X
X    frompath = (mode != TOPERM) ? permbones : levels;
X    topath = (mode == TOPERM) ? permbones : levels;
X
X    /* Remove any bones files in `to' directory. */
X    eraseall(topath, allbones);
X
X    /* Copy `from' to `to' */
X    strcpy(from, frompath);
X    strcat(from, allbones);
X    strcpy(to, topath);
X    strcat(to, allbones);
X
X    for (i = 1; i < MAXLEVEL; i++) {
X	name_file(from, i);
X	name_file(to, i);
X	if (fileLock = Lock(from, SHARED_LOCK)) {
X	    UnLock(fileLock);
X	    if (status = CopyFile(from, to))
X		goto failed;
X	}
X    }
X
X    /*
X     * The last file got there.  Remove the ramdisk bones files.
X     */
X    if (mode == TOPERM)
X	eraseall(frompath, allbones);
X    return;
X
X    /* Last file didn't get there. */
X
Xfailed:
X    msmsg("Cannot copy `%s' to `%s'\n(%s)\n", from, to, status);
X
X    if (mode == TOPERM) {
X	msmsg("Bones will be left in `%s'\n",
X	    *frompath ? frompath : hackdir);
X	return;
X    } else {
X	/* Remove all bones files on the RAMdisk */
X	eraseall(levels, allbones);
X	playwoRAMdisk();
X    }
X}
X
Xvoid
XplaywoRAMdisk()
X{
X    msmsg("Do you wish to play without a RAMdisk (y/n) ? ");
X
X    /* Set ramdisk false *before* exit'ing (because msexit calls
X     * copybones)
X     */
X    ramdisk = FALSE;
X    if (Getchar() != 'y') {
X	settty("Be seeing you ...\n");
X	exit(0);
X    }
X    set_lock_and_bones();
X    return;
X}
X
Xint
XsaveDiskPrompt(start)
X{
X    extern int saveprompt;
X    char buf[BUFSIZ], *bp;
X    struct FileLock *fileLock;
X
X    if (saveprompt) {
X	/* Don't prompt if you can find the save file */
X	if (fileLock = Lock(SAVEF, SHARED_LOCK)) {
X	    UnLock(fileLock);
X	    return 1;
X	}
X	remember_topl();
X	home();
X	cl_end();
X	msmsg("If save file is on a SAVE disk, put that disk in now.\n");
X	cl_end();
X	msmsg("File name (default `%s'%s) ? ", SAVEF,
X	    start ? "" : ", <Esc> cancels save");
X	getlin(buf);
X	home();
X	cl_end();
X	curs(1, 2);
X	cl_end();
X	if (!start && *buf == '\033')
X	    return 0;
X
X	/* Strip any whitespace. Also, if nothing was entered except
X	 * whitespace, do not change the value of SAVEF.
X	 */
X	for (bp = buf; *bp; bp++)
X	    if (!isspace(*bp)) {
X		strncpy(SAVEF, bp, PATHLEN);
X		break;
X	    }
X    }
X    return 1;
X}
X
X/* Return 1 if the record file was found */
Xstatic boolean
Xrecord_exists()
X{
X    FILE *file;
X
X    if (file = fopenp(RECORD, "r")) {
X	fclose(file);
X	return TRUE;
X    }
X    return FALSE;
X}
X
X/* Prompt for game disk, then check for record file.
X */
Xvoid
XgameDiskPrompt()
X{
X    extern int saveprompt;
X
X    if (record_exists())
X	return;
X
X    if (saveprompt) {
X	(void) putchar('\n');
X	getreturn("when the GAME disk has been put in");
X    }
X
X    if (!record_exists()) {
X	msmsg("\n\nWARNING: can't find record file `%s'!\n", RECORD);
X
X	msmsg("If the GAME disk is not in, put it in now.\n");
X	getreturn("to continue");
X    }
X}
X
X/* Read configuration */
Xvoid
Xread_config_file()
X{
X    char    tmp_ramdisk[PATHLEN], tmp_levels[PATHLEN];
X    char    buf[BUFSZ], *bufp;
X    FILE    *fp, *fopenp();
X    extern  char plname[];
X    extern  int saveprompt;
X
X    tmp_ramdisk[0] = 0;
X    tmp_levels[0] = 0;
X    if ((fp = fopenp(configfile, "r")) == NULL) {
X	msmsg("Warning: no configuration file!\n");
X	getreturn("to continue");
X	return;
X    }
X    while (fgets(buf, BUFSZ, fp)) {
X	if (*buf == '#')
X	    continue;
X
X	/* remove trailing whitespace */
X
X	bufp = index(buf, '\n');
X	while (bufp > buf && isspace(*bufp))
X	    bufp--;
X	if (bufp == buf)
X	    continue;	     /* skip all-blank lines */
X	else
X	    *(bufp + 1) = 0;    /* 0 terminate line */
X
X	/* find the '=' */
X	if (!(bufp = index(buf, '='))) {
X	    msmsg("Bad option line: '%s'\n", buf);
X	    getreturn("to continue");
X	    continue;
X	}
X
X	/* skip  whitespace between '=' and value */
X	while (isspace(*++bufp))
X	    ;
X
X	/* Go through possible variables */
X	if (!strncmp(buf, "HACKDIR", 4)) {
X	    strncpy(hackdir, bufp, PATHLEN);
X
X	} else if (!strncmp(buf, "RAMDISK", 3)) {
X	    strncpy(tmp_ramdisk, bufp, PATHLEN);
X
X	} else if (!strncmp(buf, "LEVELS", 4)) {
X	    strncpy(tmp_levels, bufp, PATHLEN);
X
X	} else if (!strncmp(buf, "OPTIONS", 4)) {
X	    parseoptions(bufp, (boolean)TRUE);
X	    if (plname[0])        /* If a name was given */
X		plnamesuffix();    /* set the character class */
X
X	} else if (!strncmp(buf, "SAVE", 4)) {
X	    char *ptr;
X	    if (ptr = index(bufp, ';')) {
X		*ptr = '\0';
X		if (*(ptr+1) == 'n' || *(ptr+1) == 'N')
X		    saveprompt = FALSE;
X	    }
X	    (void) strncpy(SAVEF, bufp, PATHLEN);
X	    append_slash(SAVEF);
X	} else if (!strncmp(buf, "GRAPHICS", 4)) {
X	    unsigned int translate[28];   /* MAXPCHARS */
X	    int  i;
X
X	    if ((i = sscanf(bufp,
X		 "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
X				&translate[0], &translate[1], &translate[2],
X				&translate[3], &translate[4], &translate[5],
X				&translate[6], &translate[7], &translate[8],
X				&translate[9], &translate[10], &translate[11],
X				&translate[12], &translate[13], &translate[14],
X				&translate[15], &translate[16], &translate[17],
X				&translate[18], &translate[19], &translate[20],
X				&translate[21], &translate[22], &translate[23],
X				&translate[27], &translate[28], &translate[29],
X				&translate[30], &translate[31])) < 0) {
X		    msmsg ("Syntax error in GRAPHICS\n");
X		    getreturn("to continue");
X	    } /* Yuck! Worked only with low-byte first!!! */
X#define SETPCHAR(f, n)	showsyms.f = (i > n) ? translate[n] : defsyms.f
X			SETPCHAR(stone, 0);
X			SETPCHAR(vwall, 1);
X			SETPCHAR(hwall, 2);
X			SETPCHAR(tlcorn, 3);
X			SETPCHAR(trcorn, 4);
X			SETPCHAR(blcorn, 5);
X			SETPCHAR(brcorn, 6);
X			SETPCHAR(crwall, 7);
X			SETPCHAR(tuwall, 8);
X			SETPCHAR(tdwall, 9);
X			SETPCHAR(tlwall, 10);
X			SETPCHAR(trwall, 11);
X			SETPCHAR(vbeam, 12);
X			SETPCHAR(hbeam, 13);
X			SETPCHAR(lslant, 14);
X			SETPCHAR(rslant, 15);
X			SETPCHAR(door, 16);
X			SETPCHAR(room, 17);
X			SETPCHAR(corr, 18);
X			SETPCHAR(upstair, 19);
X			SETPCHAR(dnstair, 20);
X			SETPCHAR(trap, 21);
X			SETPCHAR(web, 22);
X			SETPCHAR(pool, 23);
X#ifdef FOUNTAINS
X			SETPCHAR(fountain, 24);
X#endif
X#ifdef SINKS
X			SETPCHAR(sink, 25);
X#endif
X#ifdef THRONES
X			SETPCHAR(throne, 26);
X#endif
X#ifdef ALTARS
X			SETPCHAR(altar, 27);
X#endif
X#ifdef STRONGHOLD
X			SETPCHAR(upladder, 28);
X			SETPCHAR(dnladder, 29);
X			SETPCHAR(dbvwall, 30);
X			SETPCHAR(dbhwall, 31);
X#endif
X#undef SETPCHAR
X	} else if (!strncmp(buf, "PATH", 4)) {
X	    strncpy(PATH, bufp, PATHLEN);
X
X	} else {
X	    msmsg("Bad option line: '%s'\n", buf);
X	    getreturn("to continue");
X	}
X    }
X    fclose(fp);
X
X    strcpy(permbones, tmp_levels);
X    if (tmp_ramdisk[0]) {
X	strcpy(levels, tmp_ramdisk);
X	if (strcmpi(permbones, levels))        /* if not identical */
X	    ramdisk = TRUE;
X    } else
X	strcpy(levels, tmp_levels);
X    strcpy(bones, levels);
X}
X
X/* Set names for bones[] and lock[] */
X
Xvoid
Xset_lock_and_bones()
X{
X    if (!ramdisk) {
X	strcpy(levels, permbones);
X	strcpy(bones, permbones);
X    }
X    append_slash(permbones);
X    append_slash(levels);
X    append_slash(bones);
X    strcat(bones, allbones);
X    strcpy(lock, levels);
X    strcat(lock, alllevels);
X}
X
X/*
X * Add a slash to any name not ending in / or :.  There must
X * be room for the /.
X */
Xvoid
Xappend_slash(name)
Xchar *name;
X{
X    char *ptr;
X
X    if (!*name)
X	return;
X    ptr = name + (strlen(name) - 1);
X    if (*ptr != '/' && *ptr != ':') {
X	*++ptr = '/';
X	*++ptr = '\0';
X    }
X}
X
X
Xvoid
Xgetreturn(str)
Xchar *str;
X{
X    int ch;
X
X    msmsg("Hit <RETURN> %s.", str);
X    while ((ch = Getchar()) != '\n')
X	;
X}
X
Xvoid
Xmsmsg(fmt, a1, a2, a3)
Xchar *fmt;
Xlong a1, a2, a3;
X{
X    printf(fmt, a1, a2, a3);
X    (void) fflush(stdout);
X}
X
X/* Follow the PATH, trying to fopen the file.
X */
X#define PATHSEP    ';'
X#undef fopen
X
XFILE *
Xfopenp(name, mode)
Xregister char *name, *mode;
X{
X    char buf[BUFSIZ], *bp, *pp, lastch;
X    FILE *fp;
X    register struct FileLock *theLock;
X
X    /* Try the default directory first.  Then look along PATH.
X     */
X    strcpy(buf, name);
X    if (theLock = Lock(buf, SHARED_LOCK)) {
X	UnLock(theLock);
X	if (fp = fopen(buf, mode))
X	    return fp;
X    }
X    pp = PATH;
X    while (pp && *pp) {
X	bp = buf;
X	while (*pp && *pp != PATHSEP)
X	    lastch = *bp++ = *pp++;
X	if (lastch != ':' && lastch != '/' && bp != buf)
X	    *bp++ = '/';
X	strcpy(bp, name);
X	if (theLock = Lock(buf, SHARED_LOCK)) {
X	    UnLock(theLock);
X	    if (fp = fopen(buf, mode))
X		return fp;
X	}
X	if (*pp)
X	    pp++;
X    }
X    return NULL;
X}
X#endif /* DGK */
X
X#ifdef CHDIR
X
X/*
X *  A not general-purpose directory changing routine.
X *  Assumes you want to return to the original directory eventually,
X *  by chdir()ing to orgdir.
X *  Assumes -1 is not a valid lock, since 0 is valid.
X */
X
X#define NO_LOCK     ((struct FileLock *) -1)
X
Xchar orgdir[1];
Xstatic struct FileLock *OrgDirLock = NO_LOCK;
X
Xchdir(dir)
Xchar *dir;
X{
X    if (dir == orgdir) {
X	/* We want to go back to where we came from. */
X	if (OrgDirLock != NO_LOCK) {
X	    UnLock(CurrentDir(OrgDirLock));
X	    OrgDirLock = NO_LOCK;
X	}
X    } else {
X	/*
X	 * Go to some new place. If still at the original
X	 * directory, save the FileLock.
X	 */
X	struct FileLock *newDir;
X
X	if (newDir = Lock(dir, SHARED_LOCK)) {
X	    if (OrgDirLock == NO_LOCK) {
X		OrgDirLock = CurrentDir(newDir);
X	    } else {
X		UnLock(CurrentDir(newDir));
X	    }
X	} else {
X	    return -1;	/* Failed */
X	}
X    }
X    /* CurrentDir always succeeds if you have a lock */
X    return 0;
X}
X
X#endif
X
X/* Chdir back to original directory
X */
X#undef exit
Xvoid
Xmsexit(code)
X{
X#ifdef CHDIR
X    extern char orgdir[];
X#endif
X
X#ifdef DGK
X    (void) fflush(stdout);
X    if (ramdisk)
X	copybones(TOPERM);
X#endif
X#ifdef CHDIR
X    chdir(orgdir);      /* chdir, not chdirx */
X#endif
X
X    CleanUp();
X    exit(code);
X}
X
X/*
X *  Strcmp while ignoring case. Not general-purpose, so static.
X */
X
Xstatic int strcmpi(a, b)
Xregister char *a, *b;
X{
X    while (tolower(*a) == tolower(*b)) {
X	if (!*a)        /* *a == *b, so at end of both strings */
X	    return 0;	/* equal. */
X	a++;
X	b++;
X    }
X    return 1;
X}
X
X/*
X *  memcmp - used to compare two struct symbols, in lev.c
X */
X
Xmemcmp(a, b, size)
Xregister unsigned char *a, *b;
Xregister int size;
X{
X    while (size--) {
X	if (*a++ != *b++)
X	    return 1;	/* not equal */
X    }
X
X    return 0;		/* equal */
X}
END_OF_FILE
if test 16238 -ne `wc -c <'amiga/amidos.c'`; then
    echo shar: \"'amiga/amidos.c'\" unpacked with wrong size!
fi
# end of 'amiga/amidos.c'
fi
if test -f 'include/mkroom.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'include/mkroom.h'\"
else
echo shar: Extracting \"'include/mkroom.h'\" \(2288 characters\)
sed "s/^X//" >'include/mkroom.h' <<'END_OF_FILE'
X/*	SCCS Id: @(#)mkroom.h	3.0	89/01/07
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed.  See license for details. */
X
X#ifndef MKROOM_H
X#define MKROOM_H
X
X/* mkroom.h - types and structures for room and shop initialization */
X
Xstruct mkroom {
X	schar lx,hx,ly,hy;	/* usually xchar, but hx may be -1 */
X	schar rtype,rlit,doorct,fdoor;
X};
X
Xstruct shclass {
X	char	*name;	/* name of the shop type */
X	char	symb;	/* this identifies the shop type */
X	int	prob;	/* the shop type probability in % */
X	schar	dist;	/* artifact placement type */
X#define D_SCATTER	0	/* normal placement */
X#define D_SHOP		1	/* shop-like placement */
X#define D_TEMPLE	2	/* temple-like placement */
X	struct itp {
X	    int	iprob;	/* probability of an item type */
X	    int itype;	/* item type: if >=0 a class, if < 0 a specific item */
X	} iprobs[5];
X	char **shknms;	/* string list of shopkeeper names for this type */
X};
Xextern const struct shclass shtypes[];	/* defined in shknam.c */
X
Xextern struct mkroom rooms[MAXNROFROOMS+1];
X/* the normal rooms on the current level are described in rooms[0..n] for
X * some n<MAXNROFROOMS
X * the vault, if any, is described by rooms[n+1]
X * the next rooms entry has hx -1 as a flag
X * there is at most one non-vault special room on a level
X */
Xextern coord doors[DOORMAX];
X
X/* values for rtype in the room definition structure */
X#define OROOM		 0	/* ordinary room */
X#define COURT		 2	/* contains a throne */
X#define	SWAMP		 3	/* contains pools */
X#define	VAULT		 4	/* contains piles of gold */
X#define	BEEHIVE		 5	/* contains killer bees and royal jelly */
X#define	MORGUE		 6	/* contains corpses, undead and ghosts */
X#define BARRACKS	 7	/* contains soldiers and their gear */
X#define	ZOO		 8	/* floor covered with treasure and monsters */
X#define DELPHI		 9	/* contains Oracle and peripherals */
X#define	TEMPLE		10	/* contains a shrine */
X#define	SHOPBASE	11	/* everything above this is a shop */
X#define ARMORSHOP	12	/* specific shop defines for level compiler */
X#define	SCROLLSHOP	13
X#define	POTIONSHOP	14
X#define	WEAPONSHOP	15
X#define	FOODSHOP	16
X#define	RINGSHOP	17
X#define	WANDSHOP	18
X#define	TOOLSHOP	19
X#ifdef SPELLS
X#define	BOOKSHOP	20
X#endif
X
X#define IS_SHOP(x)	((x).rtype >= SHOPBASE)
X
X#endif /* MKROOM_H /**/
END_OF_FILE
if test 2288 -ne `wc -c <'include/mkroom.h'`; then
    echo shar: \"'include/mkroom.h'\" unpacked with wrong size!
fi
# end of 'include/mkroom.h'
fi
if test -f 'others/msdos.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'others/msdos.c'\"
else
echo shar: Extracting \"'others/msdos.c'\" \(16169 characters\)
sed "s/^X//" >'others/msdos.c' <<'END_OF_FILE'
X/*	SCCS Id: @(#)msdos.c	3.0	88/11/20
X/* NetHack may be freely redistributed.  See license for details. */
X/* An assortment of MSDOS functions.
X */
X
X#ifdef MSDOS
X#include <dos.h>
X#include "hack.h"
Xstatic char DOSgetch();
X#ifdef DGK
Xstatic char BIOSgetch();
X#endif
Xstatic unsigned int ioctl();
X
Xvoid
Xflushout()
X{
X	(void) fflush(stdout);
X	return;
X}
X
Xint
Xtgetch() {
X	char ch;
X
X#ifdef DGK
X	/* BIOSgetch can use the numeric key pad on IBM compatibles. */
X	if (flags.IBMBIOS)
X		ch = BIOSgetch();
X	else
X#endif
X		ch = DOSgetch();
X	return ((ch == '\r') ? '\n' : ch);
X}
X
X#define DIRECT_INPUT	0x7
Xstatic char
XDOSgetch() {
X	union REGS regs;
X
X	regs.h.ah = DIRECT_INPUT;
X	intdos(&regs, &regs);
X	if (!regs.h.al) {	/* an extended code -- not yet supported */
X		regs.h.ah = DIRECT_INPUT;
X		intdos(&regs, &regs);	/* eat the next character */
X		regs.h.al = 0;		/* and return a 0 */
X	}
X	return (regs.h.al);
X}
X
X#include <ctype.h>
X#include <fcntl.h>
X#include <process.h>
X
Xstatic char *COMSPEC = "COMSPEC";
X#define getcomspec() getenv(COMSPEC)
X
X#ifdef SHELL
Xint
Xdosh() {
X	extern char orgdir[];
X	char *comspec;
X
X	if (comspec = getcomspec()) {
X#ifdef DGK
X		settty("To return to NetHack, type \"exit\" at the DOS prompt.\n");
X#else
X		settty((char *)0);
X#endif /* DGK */
X		chdirx(orgdir, 0);
X		if (spawnl(P_WAIT, comspec, comspec, NULL) < 0) {
X			Printf("\nCan't spawn %s !\n", comspec);
X			flags.toplin = 0;
X			more();
X		}
X		chdirx(hackdir, 0);
X		start_screen();
X		docrt();
X	} else
X		pline("Cannot exec COMMAND.COM");
X	return 0;
X}
X#endif /* SHELL */
X
X#ifdef DGK
X/* Normal characters are output when the shift key is not pushed.
X * Shift characters are output when either shift key is pushed.
X */
X#define KEYPADHI	83
X#define KEYPADLOW	71
X#define PADKEYS		(KEYPADHI - KEYPADLOW + 1)
X#define iskeypad(x)	(KEYPADLOW <= (x) && (x) <= KEYPADHI)
Xstatic const struct pad {
X	char normal, shift;
X	} keypad[PADKEYS] = {
X			{'y', 'Y'},		/* 7 */
X			{'k', 'K'},		/* 8 */
X			{'u', 'U'},		/* 9 */
X			{'m', CTRL('P')},	/* - */
X			{'h', 'H'},		/* 4 */
X			{'g', 'g'},		/* 5 */
X			{'l', 'L'},		/* 6 */
X			{'p', 'P'},		/* + */
X			{'b', 'B'},		/* 1 */
X			{'j', 'J'},		/* 2 */
X			{'n', 'N'},		/* 3 */
X			{'i', 'I'},		/* Ins */
X			{'.', ':'}		/* Del */
X	}, numpad[PADKEYS] = {
X			{'7', '7'},		/* 7 */
X			{'8', '8'},		/* 8 */
X			{'9', '9'},		/* 9 */
X			{'m', CTRL('P')},	/* - */
X			{'4', '4'},		/* 4 */
X			{'g', 'G'},		/* 5 */
X			{'6', '6'},		/* 6 */
X			{'p', 'P'},		/* + */
X			{'1', '1'},		/* 1 */
X			{'2', '2'},		/* 2 */
X			{'3', '3'},		/* 3 */
X			{'i', 'I'},		/* Ins */
X			{'.', ':'}		/* Del */
X};
X
X/* BIOSgetch gets keys directly with a BIOS call.
X */
X#define SHIFT		(0x1 | 0x2)
X#define CTRL		0x4
X/* #define ALT		0x8 */
X#define KEYBRD_BIOS	0x16
X
Xstatic char
XBIOSgetch() {
X	unsigned char scan, shift, ch;
X	union REGS regs;
X	struct pad (*kpad)[PADKEYS];
X
X	/* Get scan code.
X	 */
X	regs.h.ah = 0;
X	int86(KEYBRD_BIOS, &regs, &regs);
X	ch = regs.h.al;
X	scan = regs.h.ah;
X
X	/* Get shift status.
X	 */
X	regs.h.ah = 2;
X	int86(KEYBRD_BIOS, &regs, &regs);
X	shift = regs.h.al;
X
X	/* If scan code is for the keypad, translate it.
X	 */
X	kpad = flags.num_pad ? numpad : keypad;
X	if (iskeypad(scan)) {
X		if (shift & SHIFT) {
X			flags.mv = flags.run = 1;
X			/* necessary if number_pad is on */
X			ch = (*kpad)[scan - KEYPADLOW].shift;
X		} else
X			ch = (*kpad)[scan - KEYPADLOW].normal;
X	}
X	return ch;
X}
X
X#define FINDFIRST	0x4E00
X#define FINDNEXT	0x4F00
X#define GETDTA		0x2F00
X#define SETFILETIME	0x5701
X#define GETSWITCHAR	0x3700
X#define FREESPACE	0x36
X
X#ifdef __TURBOC__
X#define switchar()	(char)getswitchar()
X#else
Xstatic char
Xswitchar()
X{
X	union REGS regs;
X
X	regs.x.ax = GETSWITCHAR;
X	intdos(&regs, &regs);
X	return regs.h.dl;
X}
X#endif
X
Xlong
Xfreediskspace(path)
Xchar *path;
X{
X	union REGS regs;
X
X	regs.h.ah = FREESPACE;
X	if (path[0] && path[1] == ':')
X		regs.h.dl = (toupper(path[0]) - 'A') + 1;
X	else
X		regs.h.dl = 0;
X	intdos(&regs, &regs);
X	if (regs.x.ax == 0xFFFF)
X		return -1L;		/* bad drive number */
X	else
X		return ((long) regs.x.bx * regs.x.cx * regs.x.ax);
X}
X
X/* Functions to get filenames using wildcards
X */
Xstatic int
Xfindfirst(path)
Xchar *path;
X{
X	union REGS regs;
X	struct SREGS sregs;
X
X	regs.x.ax = FINDFIRST;
X	regs.x.cx = 0;		/* normal files */
X	regs.x.dx = FP_OFF(path);
X	sregs.ds = FP_SEG(path);
X	intdosx(&regs, &regs, &sregs);
X	return !regs.x.cflag;
X}
X
Xstatic int
Xfindnext() {
X	union REGS regs;
X
X	regs.x.ax = FINDNEXT;
X	intdos(&regs, &regs);
X	return !regs.x.cflag;
X}
X
X/* Get disk transfer area, Turbo C already has getdta */
Xstatic char *
Xgetdta() {
X	union REGS regs;
X	struct SREGS sregs;
X	char *ret;
X
X	regs.x.ax = GETDTA;
X	intdosx(&regs, &regs, &sregs);
X#ifdef MK_FP
X	ret = MK_FP(sregs.es, regs.x.bx);
X#else
X	FP_OFF(ret) = regs.x.bx;
X	FP_SEG(ret) = sregs.es;
X#endif
X	return ret;
X}
X
Xlong
Xfilesize(file)
Xchar *file;
X{
X	char *dta;
X
X	if (findfirst(file)) {
X		dta = getdta();
X		return  (* (long *) (dta + 26));
X	} else
X		return -1L;
X}
X
Xvoid
Xeraseall(path, files)
Xchar *path, *files;
X{
X	char *dta, buf[PATHLEN];
X
X	dta = getdta();
X	Sprintf(buf, "%s%s", path, files);
X	if (findfirst(buf))
X		do {
X			Sprintf(buf, "%s%s", path, dta + 30);
X			(void) unlink(buf);
X		} while (findnext());
X	return;
X}
X
X/* Rewritten for version 3.3 to be faster
X */
Xvoid
Xcopybones(mode) {
X	char from[PATHLEN], to[PATHLEN], last[13], copy[8];
X	char *frompath, *topath, *dta, *comspec;
X	int status;
X	long fs;
X	extern saveprompt;
X
X	if (!ramdisk)
X		return;
X
X	/* Find the name of the last file to be transferred
X	 */
X	frompath = (mode != TOPERM) ? permbones : levels;
X	dta = getdta();
X	last[0] = '\0';
X	Sprintf(from, "%s%s", frompath, allbones);
X	if (findfirst(from))
X		do {
X			Strcpy(last, dta + 30);
X		} while (findnext());
X
X	topath = (mode == TOPERM) ? permbones : levels;
X	if (last[0]) {
X		Sprintf(copy, "%cC copy", switchar());
X
X		/* Remove any bones files in `to' directory.
X		 */
X		eraseall(topath, allbones);
X
X		/* Copy `from' to `to' */
X		Sprintf(to, "%s%s", topath, allbones);
X		comspec = getcomspec();
X		status =spawnl(P_WAIT, comspec, comspec, copy, from,
X			to, "> nul", NULL);
X	} else
X		return;
X
X	/* See if the last file got there.  If so, remove the ramdisk bones
X	 * files.
X	 */
X	Sprintf(to, "%s%s", topath, last);
X	if (findfirst(to)) {
X		if (mode == TOPERM)
X			eraseall(frompath, allbones);
X		return;
X	}
X
X	/* Last file didn't get there.
X	 */
X	Sprintf(to, "%s%s", topath, allbones);
X	msmsg("Cannot copy `%s' to `%s' -- %s\n", from, to,
X		(status < 0) ? "can't spawn COMSPEC !" :
X		(freediskspace(topath) < filesize(from)) ?
X			"insufficient disk space." : "bad path(s)?");
X	if (mode == TOPERM) {
X		msmsg("Bones will be left in `%s'\n",
X			*levels ? levels : hackdir);
X	} else {
X		/* Remove all bones files on the RAMdisk */
X		eraseall(levels, allbones);
X		playwoRAMdisk();
X	}
X	return;
X}
X
Xvoid
XplaywoRAMdisk() {
X	msmsg("Do you wish to play without a RAMdisk? ");
X
X	/* Set ramdisk false *before* exit'ing (because msexit calls
X	 * copybones)
X	 */
X	ramdisk = FALSE;
X	if (yn() != 'y') {
X		settty("Be seeing you...\n");
X		exit(0);
X	}
X	set_lock_and_bones();
X	return;
X}
X
Xint
XsaveDiskPrompt(start) {
X	extern saveprompt;
X	char buf[BUFSIZ], *bp;
X	int fd;
X
X	if (saveprompt) {
X		/* Don't prompt if you can find the save file */
X		if ((fd = open(SAVEF, 0)) >= 0) {
X			(void) close(fd);
X			return 1;
X		}
X		remember_topl();
X		home();
X		cl_end();
X		msmsg("If save file is on a SAVE disk, put that disk in now.\n");
X		cl_end();
X		msmsg("File name (default `%s'%s) ? ", SAVEF,
X			start ? "" : ", <Esc> cancels save");
X		getlin(buf);
X		home();
X		cl_end();
X		curs(1, 2);
X		cl_end();
X		if (!start && *buf == '\033')
X			return 0;
X
X		/* Strip any whitespace. Also, if nothing was entered except
X		 * whitespace, do not change the value of SAVEF.
X		 */
X		for (bp = buf; *bp; bp++)
X			if (!isspace(*bp)) {
X				strncpy(SAVEF, bp, PATHLEN);
X				break;
X			}
X	}
X	return 1;
X}
X
X/* Return 1 if the record file was found */
Xstatic boolean
Xrecord_exists() {
X	int fd;
X
X	if ((fd = open(RECORD, 0)) >= 0) {
X		(void) close(fd);
X		return TRUE;
X	}
X	return FALSE;
X}
X
X/* Return 1 if the comspec was found */
Xstatic boolean
Xcomspec_exists() {
X	int fd;
X	char *comspec;
X
X	if (comspec = getcomspec())
X		if ((fd = open(comspec, 0)) >= 0) {
X			(void) close(fd);
X			return TRUE;
X		}
X	return FALSE;
X}
X
X/* Prompt for game disk, then check for record file.
X */
Xvoid
XgameDiskPrompt() {
X	extern int saveprompt;
X
X	if (saveprompt) {
X		if (record_exists() && comspec_exists())
X			return;
X		(void) putchar('\n');
X		getreturn("when the GAME disk has been put in");
X	}
X	if (comspec_exists() && record_exists())
X		return;
X
X	if (!comspec_exists())
X		msmsg("\n\nWARNING: can't find comspec `%s'!\n", getcomspec());
X	if (!record_exists())
X		msmsg("\n\nWARNING: can't find record file `%s'!\n", RECORD);
X	msmsg("If the GAME disk is not in, put it in now.\n");
X	getreturn("to continue");
X	return;
X}
X#endif /* DGK */
X
X/* Read configuration */
Xvoid
Xread_config_file() {
X#ifdef DGK
X	char	tmp_ramdisk[PATHLEN];
X	extern	int saveprompt;
X	FILE	*fopenp();
X#else
X#define fopenp fopen
X#endif
X	char	tmp_levels[PATHLEN];
X	char	buf[BUFSZ], *bufp;
X	FILE	*fp;
X	extern	char plname[];
X
X#ifdef DGK
X	tmp_ramdisk[0] = 0;
X#endif
X	tmp_levels[0] = 0;
X	if ((fp = fopenp(configfile, "r")) == (FILE *)0) {
X		msmsg("Warning: no configuration file!\n");
X		getreturn("to continue");
X		return;
X	}
X	while (fgets(buf, BUFSZ, fp)) {
X		if (*buf == '#')
X			continue;
X
X		/* remove trailing whitespace
X		 */
X		bufp = index(buf, '\n');
X		while (bufp > buf && isspace(*bufp))
X			bufp--;
X		if (bufp == buf)
X			continue;		/* skip all-blank lines */
X		else
X			*(bufp + 1) = 0;	/* 0 terminate line */
X
X		/* find the '=' */
X		if (!(bufp = strchr(buf, '='))) {
X			msmsg("Bad option line: '%s'\n", buf);
X			getreturn("to continue");
X			continue;
X		}
X		
X		/* skip  whitespace between '=' and value */
X		while (isspace(*++bufp))
X			;
X
X		/* Go through possible variables */
X		if (!strncmp(buf, "HACKDIR", 4)) {
X			strncpy(hackdir, bufp, PATHLEN);
X		
X#ifdef DGK
X		} else if (!strncmp(buf, "RAMDISK", 3)) {
X			strncpy(tmp_ramdisk, bufp, PATHLEN);
X#endif
X
X		} else if (!strncmp(buf, "LEVELS", 4)) {
X			strncpy(tmp_levels, bufp, PATHLEN);
X
X		} else if (!strncmp(buf, "OPTIONS", 4)) {
X			parseoptions(bufp, TRUE);
X			if (plname[0])		/* If a name was given */
X				plnamesuffix();	/* set the character class */
X
X		} else if (!strncmp(buf, "SAVE", 4)) {
X#ifdef DGK
X			char *ptr;
X			if (ptr = index(bufp, ';')) {
X				*ptr = '\0';
X				if (*(ptr+1) == 'n' || *(ptr+1) == 'N')
X					saveprompt = FALSE;
X			}
X#endif /* DGK */
X			(void) strncpy(SAVEF, bufp, PATHLEN);
X			append_slash(SAVEF);
X		} else if (!strncmp(buf, "GRAPHICS", 4)) {
X			unsigned int translate[MAXPCHARS];
X			int i;
X
X		     if ((i = sscanf(bufp,
X		 "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
X				&translate[0], &translate[1], &translate[2],
X				&translate[3], &translate[4], &translate[5],
X				&translate[6], &translate[7], &translate[8],
X				&translate[9], &translate[10], &translate[11],
X				&translate[12], &translate[13], &translate[14],
X				&translate[15], &translate[16], &translate[17],
X				&translate[18], &translate[19], &translate[20],
X				&translate[21], &translate[22], &translate[23],
X				&translate[24], &translate[25], &translate[26],
X				&translate[27], &translate[28], &translate[29],
X				&translate[30], &translate[31])) < 0) {
X					msmsg ("Syntax error in GRAPHICS\n");
X					getreturn("to continue");
X			}
X#define SETPCHAR(f, n)	showsyms.f = (i > n) ? translate[n] : defsyms.f
X			SETPCHAR(stone, 0);
X			SETPCHAR(vwall, 1);
X			SETPCHAR(hwall, 2);
X			SETPCHAR(tlcorn, 3);
X			SETPCHAR(trcorn, 4);
X			SETPCHAR(blcorn, 5);
X			SETPCHAR(brcorn, 6);
X			SETPCHAR(crwall, 7);
X			SETPCHAR(tuwall, 8);
X			SETPCHAR(tdwall, 9);
X			SETPCHAR(tlwall, 10);
X			SETPCHAR(trwall, 11);
X			SETPCHAR(vbeam, 12);
X			SETPCHAR(hbeam, 13);
X			SETPCHAR(lslant, 14);
X			SETPCHAR(rslant, 15);
X			SETPCHAR(door, 16);
X			SETPCHAR(room, 17);
X			SETPCHAR(corr, 18);
X			SETPCHAR(upstair, 19);
X			SETPCHAR(dnstair, 20);
X			SETPCHAR(trap, 21);
X			SETPCHAR(web, 22);
X			SETPCHAR(pool, 23);
X#ifdef FOUNTAINS
X			SETPCHAR(fountain, 24);
X#endif
X#ifdef SINKS
X			SETPCHAR(sink, 25);
X#endif
X#ifdef THRONES
X			SETPCHAR(throne, 26);
X#endif
X#ifdef ALTARS
X			SETPCHAR(altar, 27);
X#endif
X#ifdef STRONGHOLD
X			SETPCHAR(upladder, 28);
X			SETPCHAR(dnladder, 29);
X			SETPCHAR(dbvwall, 30);
X			SETPCHAR(dbhwall, 31);
X#endif
X#undef SETPCHAR
X		} else {
X			msmsg("Bad option line: '%s'\n", buf);
X			getreturn("to continue");
X		}
X	}
X	(void) fclose(fp);
X
X#ifdef DGK
X	Strcpy(permbones, tmp_levels);
X	if (tmp_ramdisk[0]) {
X		Strcpy(levels, tmp_ramdisk);
X		if (strcmp(permbones, levels))		/* if not identical */
X			ramdisk = TRUE;
X	} else
X#endif /* DGK */
X		Strcpy(levels, tmp_levels);
X	Strcpy(bones, levels);
X	return;
X}
X
X#ifdef DGK
X/* Set names for bones[] and lock[]
X */
Xvoid
Xset_lock_and_bones() {
X	if (!ramdisk) {
X		Strcpy(levels, permbones);
X		Strcpy(bones, permbones);
X	}
X	append_slash(permbones);
X	append_slash(levels);
X	append_slash(bones);
X	Strcat(bones, allbones);
X	Strcpy(lock, levels);
X	Strcat(lock, alllevels);
X	return;
X}
X#endif /* DGK */
X
X/* Add a backslash to any name not ending in /, \ or :   There must
X * be room for the \
X */
Xvoid
Xappend_slash(name)
Xchar *name;
X{
X	char *ptr;
X
X	if (!*name)
X		return;
X	ptr = name + (strlen(name) - 1);
X	if (*ptr != '\\' && *ptr != '/' && *ptr != ':') {
X		*++ptr = '\\';
X		*++ptr = '\0';
X	}
X	return;
X}
X
Xvoid
Xgetreturn(str)
Xchar *str;
X{
X	msmsg("Hit <RETURN> %s.", str);
X	while (Getchar() != '\n') ;
X	return;
X}
X
Xvoid
Xmsmsg(fmt, a1, a2, a3)
Xchar *fmt;
Xlong a1, a2, a3;
X{
X	Printf(fmt, a1, a2, a3);
X	flushout();
X	return;
X}
X
X/* Chdrive() changes the default drive.
X */
X#ifndef __TURBOC__
X#define SELECTDISK	0x0E
Xvoid
Xchdrive(str)
Xchar *str;
X{
X	char *ptr;
X	union REGS inregs;
X	char drive;
X
X	if ((ptr = index(str, ':')) != NULL) {
X		drive = toupper(*(ptr - 1));
X		inregs.h.ah = SELECTDISK;
X		inregs.h.dl = drive - 'A';
X		intdos(&inregs, &inregs);
X	}
X	return;
X}
X#else
Xvoid
Xchdrive(str)
Xchar *str;
X{
X	if (str[1] == ':')
X		(void)setdisk((int)(toupper(str[0]) - 'A'));
X	return;
X}
X#endif
X
X/* Use the IOCTL DOS function call to change stdin and stdout to raw
X * mode.  For stdin, this prevents MSDOS from trapping ^P, thus
X * freeing us of ^P toggling 'echo to printer'.
X * Thanks to Mark Zbikowski (markz@microsoft.UUCP).
X */
X
X#define DEVICE		0x80
X#define RAW		0x20
X#define IOCTL		0x44
X#define STDIN		fileno(stdin)
X#define STDOUT		fileno(stdout)
X#define GETBITS		0
X#define SETBITS		1
X
Xstatic unsigned	int old_stdin, old_stdout;
X
Xvoid
Xdisable_ctrlP() {
X#ifdef DGK
X	if (!flags.rawio) return;
X#endif
X	old_stdin = ioctl(STDIN, GETBITS, 0);
X	old_stdout = ioctl(STDOUT, GETBITS, 0);
X	if (old_stdin & DEVICE)
X		ioctl(STDIN, SETBITS, old_stdin | RAW);
X	if (old_stdout & DEVICE)
X		ioctl(STDOUT, SETBITS, old_stdout | RAW);
X	return;
X}
X
Xvoid
Xenable_ctrlP() {
X#ifdef DGK
X	if (!flags.rawio) return;
X#endif
X	if (old_stdin)
X		(void) ioctl(STDIN, SETBITS, old_stdin);
X	if (old_stdout)
X		(void) ioctl(STDOUT, SETBITS, old_stdout);
X	return;
X}
X
Xstatic unsigned int
Xioctl(handle, mode, setvalue)
Xint handle, mode;
Xunsigned setvalue;
X{
X	union REGS regs;
X
X	regs.h.ah = IOCTL;
X	regs.h.al = mode;
X	regs.x.bx = handle;
X	regs.h.dl = setvalue;
X	regs.h.dh = 0;			/* Zero out dh */
X	intdos(&regs, &regs);
X	return (regs.x.dx);
X}
X
X#ifdef DGK
X/* Follow the PATH, trying to fopen the file.
X */
X#define PATHSEP	';'
X
XFILE *
Xfopenp(name, mode)
Xchar *name, *mode;
X{
X	char buf[BUFSIZ], *bp, *pp, lastch;
X	FILE *fp;
X
X	/* Try the default directory first.  Then look along PATH.
X	 */
X	Strcpy(buf, name);
X	if (fp = fopen(buf, mode))
X		return fp;
X	else {
X		pp = getenv("PATH");
X		while (pp && *pp) {
X			bp = buf;
X			while (*pp && *pp != PATHSEP)
X				lastch = *bp++ = *pp++;
X			if (lastch != '\\' && lastch != '/')
X				*bp++ = '\\';
X			Strcpy(bp, name);
X			if (fp = fopen(buf, mode))
X				return fp;
X			if (*pp)
X				pp++;
X		}
X	}
X	return (FILE *)0;
X}
X#endif /* DGK */
X
X/* Chdir back to original directory
X */
X#undef exit
Xvoid exit(int);
Xvoid
Xmsexit(code)
X{
X#ifdef CHDIR
X	extern char orgdir[];
X#endif
X
X	flushout();
X	enable_ctrlP();		/* in case this wasn't done */
X#ifdef DGK
X	if (ramdisk) copybones(TOPERM);
X#endif
X#ifdef CHDIR
X	chdir(orgdir);		/* chdir, not chdirx */
X	chdrive(orgdir);
X#endif
X	exit(code);
X	return;
X}
X#endif /* MSDOS */
END_OF_FILE
if test 16169 -ne `wc -c <'others/msdos.c'`; then
    echo shar: \"'others/msdos.c'\" unpacked with wrong size!
fi
# end of 'others/msdos.c'
fi
if test -f 'others/tos.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'others/tos.c'\"
else
echo shar: Extracting \"'others/tos.c'\" \(16197 characters\)
sed "s/^X//" >'others/tos.c' <<'END_OF_FILE'
X/*	SCCS Id: @(#)tos.c	3.0	88/11/09
X * An assortment of functions for the Atari with Lattice C compiler.
X * Adapted from a similar set for MSDOS (written by Don Kneller) by
X * R. Black (Louisville, CO).
X */
X/* NetHack may be freely redistributed.  See license for details. */
X
X#include "hack.h"
X#include "osbind.h"
X
Xextern int errno;
X
Xvoid
Xflushout()
X{
X	(void) fflush(stdout);
X}
X
Xgetuid()
X{
X	return 1;
X}
X
Xchar *
Xgetlogin()
X{
X	return NULL;
X}
X
Xtgetch()
X{
X	char ch;
X	ch = BIOSgetch();
X	return ((ch == '\r') ? '\n' : ch);
X}
X
X#ifdef exit
X#undef exit
X#endif
X
X#undef creat
X#define LEVELS	"level.00"
X#define BONES	"bones.00"
X
Xextern char hackdir[], levels[], SAVEF[], bones[], permbones[];
Xextern int ramdisk;
X
X#ifdef SHELL
X#ifndef UNIXDEBUG
X#include <process.h>
X#else	    /* null stuff for debugging purposes */
X#define	    P_WAIT	0
X#endif
Xdosh()
X{
X	char *comspec, *getenv();
X	extern char orgdir[];
X
X	if (comspec = getenv("COMSPEC")) {
X		end_screen();
X		clear_screen();
X		(void) puts("To return to HACK, type \"exit\" at the TOS prompt.");
X		(void) fflush(stdout);
X		chdirx(orgdir, 0);
X		if (spawnl(P_WAIT, comspec, NULL)) {
X			Printf("\nCan't execute COMSPEC \"%s\"!\n", comspec);
X			flags.toplin = 0;
X			more();
X		}
X		chdirx(hackdir, 0);
X		start_screen();
X		docrt();
X	}
X	return(0);
X}
X#endif SHELL
X
X/* Map the keypad to equivalent character output.  If scroll lock is turned
X * on, run without stopping at interesting branches (like YUHJKLBN keys), if
X * it is off, run with stopping at branches (like ^Y^U^H^J^K^L^B^N keys).
X */
Xstatic char
XBIOSgetch()
X{
X	int scan,c,result;
X	char ch;
X	result=Crawcin();
X	scan=(result>>16)&0xff;
X	c=result&0xff;
X	switch (scan) {
X		case 0x4a : {/*-*/
X			ch=(c==0x2d) ? 'm' : '\20';
X			break;
X		}
X		case 0x4e : {/*+*/
X			ch=(c==0x2b) ? 'p' : 'P';
X			break;
X		}
X		case 0x6d : {/*1*/
X			if (flags.num_pad) ch='1';
X			else ch=(c==0x31) ? 'b' : '\2';
X			break;
X		}
X		case 0x6e : {/*2*/
X			if (flags.num_pad) ch='2';
X			else ch=(c==0x32) ? 'j' : '\12';
X			break;
X		}
X		case 0x6f : {/*3*/
X			if (flags.num_pad) ch='3';
X			else ch=(c==0x33) ? 'n' : '\16';
X			break;
X		}
X		case 0x6a : {/*4*/
X			if (flags.num_pad) ch='4';
X			else ch=(c==0x34) ? 'h' : '\10';
X			break;
X		}
X		case 0x6b : {/*5*/
X			ch='.';
X			break;
X		}
X		case 0x6c : {/*6*/
X			if (flags.num_pad) ch='6';
X			else ch=(c==0x36) ? 'l' : '\14';
X			break;
X		}
X		case 0x67 : {/*7*/
X			if (flags.num_pad) ch='7';
X			else ch=(c==0x37) ? 'y' : '\31';
X			break;
X		}
X		case 0x68 : {/*8*/
X			if (flags.num_pad) ch='8';
X			else ch=(c==0x38) ? 'k' : '\13';
X			break;
X		}
X		case 0x69 : {/*9*/
X			if (flags.num_pad) ch='9';
X			else ch=(c==0x39) ? 'u' : '\25';
X			break;
X		}
X		default : ch=c;
X	}
X	return (ch);
X}
X
X/* After changing the value of flags.invlet_constant, make the current
X * inventory letters the fixed ones. -dgk
X */
Xvoid
Xfixinv()
X{
X	struct obj *otmp;
X	extern int lastinvnr;
X	char ilet = 'a';
X
X	for(otmp = invent; otmp; otmp = otmp->nobj) {
X		otmp->invlet = ilet;
X		if (++ilet > 'z') ilet = 'A';
X	}
X	lastinvnr = 51;
X}
X
X
Xlong
Xfreediskspace(path)
Xchar *path;
X{
X	int drive = 0;
X	struct {
X		long freal; /*free allocation units*/
X		long total; /*total number of allocation units*/
X		long bps;   /*bytes per sector*/
X		long pspal; /*physical sectors per allocation unit*/
X	} freespace;
X	if (path[0] && path[1] == ':')
X		drive = (toupper(path[0]) - 'A') + 1;
X	if (Dfree(&freespace,drive)<0) return -1;
X	return freespace.freal*freespace.bps*freespace.pspal;
X}
X
Xlong
Xfilesize(file)
Xchar *file;
X{
X	long old_dta;
X	struct {
X		char pad1[21];
X		char attr;
X		unsigned short time;
X		unsigned short date;
X		long size;
X		char name[14];
X	} fcb;
X	fcb.size = (-1L);
X	old_dta=Fgetdta();
X	Fsetdta(&fcb);
X	Fsfirst(file,0);
X	Fsetdta(old_dta);
X	return fcb.size;
X}
X
Xlong
Xall_files_size(path)
Xchar *path;
X{
X	register int level;
X	long size, tmp;
X	char buf[PATHLEN];
X
X	Strcpy(buf, path);
X	for (level = 1, size = 0; level <= MAXLEVEL; level++) {
X		name_file(buf, level);
X		tmp = filesize(buf);
X		if (tmp > 0)
X			size += tmp;
X	}
X	return (size);
X}
X
Xvoid
Xcopybones(mode)
Xint mode;
X{
X	register int fd, level;
X	char from[PATHLEN], to[PATHLEN];
X	long sizes[MAXLEVEL + 1];
X	extern boolean level_exists[];
X	if (!ramdisk)
X		return;
X	Strcpy(to, (mode == TOPERM) ? permbones : bones);
X	Strcpy(from, (mode == TOPERM) ? bones : permbones);
X
X	for (level = 1; level <= MAXLEVEL; level++) {
X		name_file(from, level);
X		sizes[level] = filesize(from);	/* -1 if file doesn't exist */
X		name_file(to, level);
X		(void) unlink(to);	/* remove old bones files in 'to' */
X	}
X	for (level = 1; level <= MAXLEVEL; level++) {
X		if (sizes[level] == -1L)
X			continue;
X		name_file(from, level);
X		name_file(to, level);
X		if (sizes[level] > freediskspace(to)) {
X			cprintf(
X				"Not enough room to copy file '%s' to '%s'.\n",
X				from, to);
X			goto cleanup;
X		}
X		/* We use savelev and getlev to move the bones files around,
X		 * but savelev sets level_exists[] TRUE for this level, so
X		 * we have to set it back FALSE again.
X		 */
X#ifdef TOS
X		if ((fd = open(from, 0x8000)) < 0) {
X#else TOS
X		if ((fd = open(from, 0)) < 0) {
X#endif TOS
X			cprintf( "Warning: can't open '%s'.\n", from);
X			continue;
X		} else {
X			sizes[level] = 0;	/* 'from' bones exists */
X			getlev(fd, 0, level, FALSE);
X			(void) close(fd);
X			if ((fd = creat(to, FCMASK)) < 0) {
X				cprintf(
X					"Warning: can't create '%s'.\n", to);
X				continue;
X			} else {
X				savelev(fd, level);
X				(void) close(fd);
X				level_exists[level] = FALSE;	/* see above */
X			}
X		}
X	}
X	/* If we are copying bones files back to permanent storage, unlink
X	 * the bones files in the LEVELS directory.
X	 */
X	if (mode == TOPERM)
X		for (level = 1; level <= MAXLEVEL; level++) {
X			if (sizes[level] == -1)
X				continue;
X			name_file(from, level);
X			(void) unlink(from);
X		}
X	return;
X
Xcleanup:
X	/* Ran out of disk space!  Unlink the "to" files and issue an
X	 * appropriate message.
X	 */
X	for (level = 1; level <= MAXLEVEL; level++)
X		if (sizes[level] == 0) {
X			name_file(to, level);
X			(void) unlink(to);
X		}
X	cprintf( "There is not enough room in ");
X	if (mode == TOPERM) {
X		cprintf( "permanent storage for bones files!\n");
X		cprintf("Bones will be left in LEVELS directory '%s'!\n",
X			levels[0] ? levels : ".");
X			return;
X	} else {
X		cprintf("LEVELS directory '%s' to copy bones files!\n",
X			levels[0] ? levels : ".");
X		getreturn("to quit");
X		settty("Be seeing you...\n");
X		exit(0);
X	}
X}
X
XsaveDiskPrompt(start)
Xint start;
X{
X	extern saveprompt;
X	char buf[BUFSIZ];
X	int i;
X
X	if (saveprompt) {
X		remember_topl();
X		home();
X		cl_end();
X		Printf("If save file is on a SAVE disk, put that disk in now.\n");
X		cl_end();
X		Printf("Name of save file (default: '%s'%s) ? ", SAVEF,
X			start ? "" : ", <Esc> aborts save");
X		(void) fflush(stdout);
X		getlin(buf);
X		if (!start && buf[0] == '\033') {
X			home();
X			cl_end();
X			curs(1, 2);
X			cl_end();
X			return 0;
X		}
X		for (i = 0; buf[i]; i++)
X			if (!isspace(buf[i])) {
X				strncpy(SAVEF, buf, PATHLEN);
X				break;
X			}
X	}
X	return 1;
X}
X
X/* Prompt for the game disk, then check if you can access the record file.
X * If not, warn the player.
X */
Xvoid
XgameDiskPrompt()
X{
X	FILE	*fp;
X	extern saveprompt;
X
X	if (saveprompt) {
X		putch('\n');
X		getreturn("when the GAME disk is ready");
X	}
X	if ((fp = fopen(RECORD, "r")))	/* check for GAME disk */
X		(void) fclose(fp);
X	else {
X		cprintf("\n\nWARNING: I can't find record file '%s'!\n",
X			 RECORD);
X		cprintf("If the GAME disk is not in, put it in now.\n");
X		getreturn("to continue");
X	}
X}
X
X#define CONFIGFILE	"hack103.cnf"
Xvoid
Xread_config_file()
X{
X	char	config[FILENAME], tmp_ramdisk[PATHLEN], tmp_levels[PATHLEN];
X	char	buf[BUFSZ], *bufp;
X	FILE	*fp;
X	extern	char plname[];
X	extern	int saveprompt;
X
X	tmp_ramdisk[0] = 0;
X	tmp_levels[0] = 0;
X	Strcpy(config, hackdir);
X	append_slash(config);
X	Strcat(config, CONFIGFILE);
X	if (!(fp = fopen(config, "r"))) {
X		cprintf("Warning: no configuration file '%s'!\n",
X			config);
X		getreturn("to continue");
X		return;
X	}
X	while (fgets(buf, BUFSZ, fp)) {
X		if (*buf == '#')		/* comment first character */
X			continue;
X
X		/* remove any trailing whitespace
X		 */
X		bufp = index(buf, '\n');
X		while (bufp > buf && isspace(*bufp))
X			bufp--;
X		if (bufp == buf)
X			continue;		/* skip all-blank lines */
X		else
X			*(bufp + 1) = 0;	/* 0 terminate line */
X
X		/* find the '=' separating option name from option value
X		 */
X		if (!(bufp = strchr(buf, '='))) {
X			cprintf("Bad option line: '%s'\n", buf);
X			getreturn("to continue");
X			continue;
X		}
X
X		/* move past whitespace between '=' and option value
X		 */
X		while (isspace(*++bufp))
X			;
X
X		/* Now go through the possible configurations
X		 */
X		if (!strncmp(buf, "RAMDISK", 3)) {
X			strncpy(tmp_ramdisk, bufp, PATHLEN);
X
X		} else if (!strncmp(buf, "LEVELS", 4)) {
X			strncpy(tmp_levels, bufp, PATHLEN);
X
X		} else if (!strncmp(buf, "OPTIONS", 4)) {
X			parseoptions(bufp, TRUE);
X			if (plname[0])		/* If a name was given */
X				plnamesuffix();	/* set the character class */
X
X		} else if (!strncmp(buf, "SAVE", 4)) {
X			char *ptr;
X			if (ptr = index(bufp, ';')) {
X				*ptr = '\0';
X				if (*(ptr+1) == 'n' || *(ptr+1) == 'N')
X					saveprompt = FALSE;
X			}
X			(void) strncpy(SAVEF, bufp, PATHLEN);
X			append_slash(SAVEF);
X
X		} else if (!strncmp(buf, "GRAPHICS", 4)) {
X			unsigned int translate[MAXPCHARS];
X			int i;
X
X		     if ((i = sscanf(bufp,
X		     "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
X				&translate[0], &translate[1], &translate[2],
X				&translate[3], &translate[4], &translate[5],
X				&translate[6], &translate[7], &translate[8],
X				&translate[9], &translate[10], &translate[11],
X				&translate[12], &translate[13], &translate[14],
X				&translate[15], &translate[16], &translate[17],
X				&translate[18], &translate[19], &translate[20],
X				&translate[21], &translate[22], &translate[23],
X				&translate[24], &translate[25], &translate[26],
X				&translate[27], &translate[28], &translate[29],
X				&translate[30], &translate[31])) < 0) {
X					cprintf("Syntax error in GRAPHICS\n");
X					getreturn("to continue");
X			}
X#define SETPCHAR(f, n)	showsyms.f = (i > n) ? translate[n] : defsyms.f
X			SETPCHAR(stone, 0);
X			SETPCHAR(vwall, 1);
X			SETPCHAR(hwall, 2);
X			SETPCHAR(tlcorn, 3);
X			SETPCHAR(trcorn, 4);
X			SETPCHAR(blcorn, 5);
X			SETPCHAR(brcorn, 6);
X			SETPCHAR(crwall, 7);
X			SETPCHAR(tuwall, 8);
X			SETPCHAR(tdwall, 9);
X			SETPCHAR(tlwall, 10);
X			SETPCHAR(trwall, 11);
X			SETPCHAR(vbeam, 12);
X			SETPCHAR(hbeam, 13);
X			SETPCHAR(lslant, 14);
X			SETPCHAR(rslant, 15);
X			SETPCHAR(door, 16);
X			SETPCHAR(room, 17);
X			SETPCHAR(corr, 18);
X			SETPCHAR(upstair, 19);
X			SETPCHAR(dnstair, 20);
X			SETPCHAR(trap, 21);
X			SETPCHAR(web, 22);
X			SETPCHAR(pool, 23);
X#ifdef FOUNTAINS
X			SETPCHAR(fountain, 24);
X#endif
X#ifdef SINKS
X			SETPCHAR(sink, 25);
X#endif
X#ifdef THRONES
X			SETPCHAR(throne, 26);
X#endif
X#ifdef ALTARS
X			SETPCHAR(altar, 27);
X#endif
X#ifdef STRONGHOLD
X			SETPCHAR(upladder, 28);
X			SETPCHAR(dnladder, 29);
X			SETPCHAR(dbvwall, 30);
X			SETPCHAR(dbhwall, 31);
X#endif
X#undef SETPCHAR
X		} else {
X			cprintf("Bad option line: '%s'\n", buf);
X			getreturn("to continue");
X		}
X	}
X	(void) fclose(fp);
X
X	Strcpy(permbones, tmp_levels);
X	if (tmp_ramdisk[0]) {
X		Strcpy(levels, tmp_ramdisk);
X		if (strcmp(permbones, levels))		/* if not identical */
X			ramdisk = TRUE;
X	} else
X		Strcpy(levels, tmp_levels);
X	Strcpy(bones, levels);
X}
X
Xvoid
Xset_lock_and_bones()
X{
X	if (!ramdisk) {
X		Strcpy(levels, permbones);
X		Strcpy(bones, permbones);
X	}
X	append_slash(bones);
X	Strcat(bones, BONES);
X	append_slash(permbones);
X	Strcat(permbones, BONES);
X	Strcpy(lock, levels);
X	append_slash(lock);
X	Strcat(lock, LEVELS);
X}
X
Xvoid
Xappend_slash(name)
Xchar *name;
X{
X	char *ptr;
X
X	if (!name[0])
X		return;
X	ptr = name + (strlen(name) - 1);
X	if (*ptr != '\\' && *ptr != '/' && *ptr != ':') {
X		*(ptr + 1) = '\\';
X		*(ptr + 2) = 0;
X	}
X}
X
X
Xcheck_then_creat(file, pmode)
Xchar *file;
Xint pmode;
X{
X	long freespace = freediskspace(file);
X	extern boolean restoring;
X	if (freespace < 0)
X		return (-1);
X	if (!restoring && freespace < 8000L) {
X		pline("\7NetHack is almost out of disk space for making levels!");
X		pline("You should save the game now.  Save this game?");
X		(void) fflush(stdout);
X		if (yn() == 'y')
X			dosave();
X		return(-1);	/* In case he decides not to save don't let him
X				 * change levels
X				 */
X	}
X	return( creat(file, pmode));
X}
X
Xvoid
Xgetreturn(str)
Xchar *str;
X{
X	int ch;
X
X	cprintf("Hit <RETURN> %s.", str);
X	while ((ch = Getchar()) != '\n')
X		putch(ch);
X}
X
Xvoid
Xchdrive(str)
Xchar *str;
X{
X	int drive;
X	char *ptr;
X	if ((ptr = index(str, ':')) != NULL) {
X		drive = toupper(*(ptr - 1))-'A';
X		Dsetdrv(drive);
X	}
X}
X
X
X/* Do a chdir back to the original directory
X */
Xvoid msexit(code)
Xint code;
X{
X#ifdef CHDIR
X	extern char orgdir[];
X#endif CHDIR
X
X#ifdef DGK
X	(void) fflush(stdout);
X	copybones(TOPERM);
X#endif DGK
X#ifdef CHDIR
X	Dsetpath(orgdir);	/* do the chdir, but not with chdirx */
X#endif CHDIR
X	exit(code);
X}
X
X/*qsort: sort an array.  Really a shell sort, but it will do*/
Xvoid qsort(base,nel,size,compar)
Xchar *base;
Xint nel, size;
Xint (*compar) ();
X{
X	int gap, i, j;
X	register int cnt;
X	for (gap=nel>>1; gap>0; gap>>=1)
X		for (i=gap; i<nel; i++)
X			for (j=i-gap; j>=0; j-=gap) {
X				register char *s1, *s2;
X				s1=base+(j*size);
X				s2=base+((j+gap)*size);
X				if ((*compar)(s1,s2)<=0) break;
X				for (cnt=size;--cnt>=0;) {
X					register char ch;
X					ch    = *s1;
X					*s1++ = *s2;
X					*s2++ = ch;
X				}
X			}
X/*end qsort*/}
X
Xstatic 	char *msgs[]={" ",
X		"not file owner",
X		"no such file or directory",
X		"no such process",
X		"interrupted system call",
X		"I/O error",
X		"no such device",
X		"argument list too long",
X		"exec format error",
X		"bad file number",
X		"no child process",
X		"no more processes allowed",
X		"not enough memory space",
X		"permission denied",
X		"bad memory address",
X		"bulk device required",
X		"resource is busy",
X		"file exists",
X		"cross device link",
X		"no such device",
X		"not a directory",
X		"is a directory",
X		"invalid argument",
X		"no more files allowed",
X		"too many open files",
X		"not a terminal",
X		"text file busy",
X		"file too large",
X		"no space left on device",
X		"illegal seek",
X		"read only file system",
X		"too many links",
X		"broken pipe",
X		"math argument error",
X		"math result too large"};
X
X/*perror: print a string, then the error*/
Xvoid perror(s)
Xchar *s;
X{
X	int select;
X	if ((errno<0) || (errno>34)) select=0;
X	else select=errno;
X	cprintf("%s: %s\n",s,msgs[select]);
X/*end perror*/}
X
Xsetrandom()
X{
X	Srand(Tgettime());
X/*end setrandom*/}
X
Xgetyear()
X{
X	return (1980+((Tgetdate()>>9)&0x7f));
X/*end getyear*/}
X
Xchar *getdate()
X{
X	static char datestr[7];
X	int day, mo, yr, date;
X	date=Tgetdate();
X	day=date&0x1f;
X	mo=(date>>5)&0xf;
X	yr=getyear()-1900;
X	Sprintf(datestr,"%2d%2d%2d",yr,mo,day);
X	if (datestr[2]==' ') datestr[2]='0';
X	if (datestr[4]==' ') datestr[4]='0';
X	return (datestr);
X/*getdate*/}
Xstatic int cum[]={0,0,31,59,90,120,151,181,212,243,273,304,334};
X
Xphase_of_the_moon()
X{
X	int day,mo,epact,golden,date;
X	date=Tgetdate();
X	day=date&0x1f;
X	mo=(date>>5)&0xf;
X	day+=cum[mo];
X	if (((getyear() % 4)==0) && (mo>2)) day++;
X	golden=(getyear()%19)+1;
X	epact=(11*golden+18) % 30;
X	if ((epact==25 && golden>11) || (epact==24)) epact++;
X	return( (((((day+epact)*6)+11)%177)/22)&7);
X/*end phase_of_the_moon*/}
X
Xnight()
X{
X	int hour;
X	hour=(Tgettime()>>11)&0x1f;
X	return ((hour<6) || (hour>21));
X/*end night*/}
X
Xmidnight()
X{
X	int hour;
X	hour=(Tgettime()>>11)&0x1f;
X	return (hour==0);
X/*end midnight*/}
X
Xgethdate(name) char *name;
X{
X/*end gethdate*/}
X
Xuptodate(fd)
X{
X	return(1);
X/*end uptodate*/}
X
Xgetlock()
X{
X/*end getlock*/}
X
Xgetenv(s)
Xchar *s;
X{
X	return(0);
X/*end getenv*/}
X
X/*getcwd: return the current directory*/
Xchar *getcwd(path,len)
Xchar *path;
Xint len;
X{
X	if (Dgetpath(path,0)<0) return (NULL);
X	else return(path);
X/*end getcwd*/}
X
X/*chdir: change directories*/
Xchdir(path)
Xchar *path;
X{
X	if (*path) return (Dsetpath(path));
X	else return 0;
X/*end chdir*/}
X
X/*Lattice's strncpy always appends a null*/
Xint strncpy(to,from,len)
Xchar *to,*from;
Xint len;
X{	int result;
X	result=len;
X	while (*from && len) {*to++ = *from++; --len;}
X	if (len) {*to='\0'; --len;}
X	return result-len;
X/*end strncpy*/}
X
X#ifdef DEBUG
Xprinter(s)
Xchar *s;
X{
X	while (*s) Cprnout(*s++);
X/*end printer*/}
X#endif DEBUG
END_OF_FILE
if test 16197 -ne `wc -c <'others/tos.c'`; then
    echo shar: \"'others/tos.c'\" unpacked with wrong size!
fi
# end of 'others/tos.c'
fi
echo shar: End of archive 22 \(of 38\).
cp /dev/null ark22isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 38 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0