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

billr@saab.CNA.TEK.COM (Bill Randle) (06/06/90)

Submitted-by: Izchak Miller <izchak@linc.cis.upenn.edu>
Posting-number: Volume 10, Issue 38
Archive-name: NetHack3/Patch8t
Patch-To: NetHack3: Volume 7, Issue 56-93



#! /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 20 (of 24)."
# Contents:  Install.mac do_patch8.sh others/ovlmgr.asm
#   vms/vmsmisc.c
# Wrapped by billr@saab on Mon Jun  4 15:40:30 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo shar: Extracting \"'Install.mac'\" \(14959 characters\)
sed "s/^X//" >'Install.mac' <<'END_OF_FILE'
X                Macintosh NetHack 3.0 Installation Guide
X                ========================================
X                last modification date: May 28th, 1990
X
X(Original credit for porting NetHack 3.0 to the Macintosh goes to Johnny
XLee and Michael Sokolov. David Hairston, Kevin Sitze, Andy Swanson, Jon
XWatte and Tom West helped polish this port in later versions.)
X
X0.  Some notes before getting started. These instructions work for the
X    Think C 4.0 compiler. Other Macintosh compilers should be okay (i.e.
X    Lightspeed C 3.0 and Manx Aztec C), however some work may be needed
X    to complete the build. For other compilers you can use the various
X    Makefiles and your compiler errors as guides in building the game.
X
X    You should maintain the file/folder structure given in the distri-
X    bution file "Files". These notes assume the file structure listed
X    below. Place the "top" folder appropriately in your compilers
X    development folder. You'll need ~6M disk space for development.
X    top:
X      Files
X      Install.mac
X      Makefile.top
X      auxil:    (... all files) {auxiliary support files}
X      include:  (... all files) {header files}
X      mac:      (... all files) {Macintosh specific files}
X      others:   (pcconf.c, pcmain.c, pctty.c & random.c only)
X      src:      (... all files) {generic source files}
X
X    Now is a good time to decode the *.hqx files (mac folder), creating
X    3 Think C 4.0 project files and 2 associated resource files. You may
X    use BinHex 4.0 or Stuffit 1.5.1 for this. These 5 files (*.proj and
X    *.rsrc) should be moved from the mac folder into the "top" folder.
X
X    Use your favorite text editor to create an empty file of type "TEXT".
X    This file should be called "news" and should be placed in the auxil
X    folder. If you decide to use the news feature of NetHack you can
X    write an appropriate starting message in this file.
X
X    Create a folder called "dungeon" in your "top" folder. This is where
X    we'll copy the final files needed to run NetHack.
X
X    Finally, you should have no problem compiling the NetHack sources, as
X    distributed. However, if you intend to make changes to the sources you
X    should consider backing up your disk to prevent problems. Also, trash
X    (or perhaps alter the creator signature of) your old versions of NetHack
X    3.0 to avoid conflicts.
X
X    Okay, let's get started. We're going to make 3 applications, in order:
X    (1) makedefs, to create customized files for the game, (2) spec_lev,
X    to create special challenging maze-like levels and (3) nethack! The
X    full build from scratch takes less than an hour using Think C 4.0 .
X
X1a. Make sure all the NetHack files are in the appropriate folder structure.
X    You should have a top folder with subfolders auxil, include, mac, others,
X    and src. The provided Think C 4.0 projects assume this structure (as do
X    the provided Makefiles).
X
X1b. If your compiler doesn't handle subfolders you'll need to place all the
X    inter-related source (*.c) and header (*.h) files in a common folder. It
X    may require some work but you should be able to follow the dependencies
X    in the Makefiles to build the game.
X
X2.  If your compiler utilizes the make/Makefile facilities, you'll need to
X    remove the tags from the Makefiles (auxil, src and top) and edit them
X    appropriately. The Makefiles are not needed if you can use the provided
X    Think C 4.0 project files.
X
X3.  Edit the config.h file making the following changes to configure it
X    properly for the Macintosh:
X
X    Section 1. OS Selection.
X    Comment out: #define UNIX
X    Uncomment  : #define MACOS (bottom of the ifdef __MSDOS__ else clause).
X
X    Within the #ifdef MACOS segment configure the #define's to choose your
X    compiler. The default is to use THINKC4. For now, skip the other
X    #define's there. Note that if your compiler is LSC or AZTEC, the KR1ED
X    compiler directive is automatically defined for you. This directive
X    allows these compilers to use the defined() construct. Additionally,
X    for the LSC a/o AZTEC compilers you'll also need to add the line:
X    #define defined(x) (-x-1 != -1)
X    before the first occurrence of #if defined(x) in random.c and mon.c!
X
X    Section 2. Some global parameters and filenames.
X    For THINKC4 define the WIZARD name. A good choice is "debug" since
X    that is the purpose of this option. For LSC or AZTEC define the
X    WIZARD_NAME appropriately. This is the name that needs to appear in
X    your "NetHack Prefs" file (system folder) in order to use Wizard
X    (Debug) mode.
X
X    Comment out: #define LOGFILE "logfile"
X
X    Section 3. Definitions that may vary with system type.
X    The defaults are all okay here for THINKC4, LSC and AZTEC.
X     
X    Section 4. THE FUN STUFF!!!
X    uncomment:   #define SCORE_ON_BOTL  (This is optional. It will allow
X    you to see your current score on the bottom line during play.)
X    The rest of the #define's default to configuring a "full-featured"
X    NetHack game.
X
X    Save the config.h file.
X
X    If you intend to customize the game you will want to look at the files
X    macconf.h and system.h. This typically isn't needed for simply building
X    the game.
X
X4.  Now we're going to build the makedefs application. This application
X    depends on various header files and the source files:
X    alloc.c  macfile.c  makedefs.c  monst.c  objects.c  & panic.c .
X    If necessary look at the Makefile(.src) to determine the dependencies.
X    You'll need to load the libraries appropriate for your compiler. THINKC4
X    users can simply open the "makedefs.proj" file.
X
X    Re-edit the config.h file! Go to the #ifdef MACOS segment in section 1.
X    Comment out: #define CUSTOM_IO .
X    Uncomment  : #define MAKEDEFS_C .
X
X    Close the config.h file, saving the changes.
X
X    Build the makedefs application. The Think C 4.0 project uses resources
X    from the "makedefs.proj.rsrc" file. Save the application in the "top"
X    folder. Close the project. Run the makedefs application, sequentially
X    choosing all seven options. This will require re-launching each time.
X    You've now created additional auxiliary files for the game and added
X    icons and signatures to these 12 files (auxil folder): cmdhelp, data,
X    help, hh, history, license, MacHelp, news, opthelp, oracles, record,
X    and rumors. These files can now be copied into the dungeon folder.
X
X    If you decide to change features in the game, remember to always
X    rebuild makedefs first to setup the needed data structures and so on
X    for the game.
X
X5.  Next, we're going to build the spec_lev application. This application
X    depends on various header files and the source files:
X    alloc.c  lev_comp.c  lev_lex.c  lev_main.c  macfile.c  monst.c
X    objects.c  & panic.c
X    If you copied the alternate file lev_lex.c in the "others" folder, you
X    should remove (or rename) it to avoid problems with src:lev_lex.c. The
X    dependencies here are similar to the ones for the makedefs project.
X    Again, if necessary, refer to the Makefile(.src) for help. You should
X    need the same libraries for this application as you did for makedefs.
X    THINKC4 users can simply open the "spec_lev.proj" file.
X
X    The changes needed to build this application are more complicated than
X    before, however the checklist provided below should cover all the bases.
X
X   *Edit config.h (Section 1. within the #ifdef MACOS segment)
X    Comment out: #define MAKEDEFS_C
X    Comment out: #define NEED_VARARGS  {more on pre-compiled headers later}
X    Save the changes to config.h and close the file.
X
X   *Edit lev_lex.c. These changes will appear sequentially:
X    Find                                    Replace with
X    {... near the beginning ...}
X    int yyleng; extern char yytext[];       int yyleng; extern char *yytext;
X    int yymorfg;                            int yymorfg;
X    extern char *yysptr, yysbuf[];          extern char *yysptr, *yysbuf;
X    int yytchar;                            int yytchar;
X    File *yyin ={stdin}, *yyout ={stdout};  File *yyin =stdin, *yyout =stdout;
X    {... near the end ...}
X    {... If you're using LSC or THINKC4 comment out: ...}
X    {... #define NLSTATE yyprevious=YYNEWLINE ...}
X    char yytext[YYLMAX];                    char *yytext;
X    {... Skip a line ...}
X    char yysbuf[YYLMAX];                    char *yysbuf;
X    char *yysptr = yysbuf;                  char *yysptr;
X    Save the changes to lev_lex.c and close the file.
X
X   *Edit lev_comp.c near the middle of the file.
X    Find                                    Replace with
X    #endif not lint                         #endif /* not lint */
X    Save the change to lev_comp.c and close the file.
X
X   *Edit lev_main.c near the beginning of the file.
X    Uncomment:   #include "hack.h"
X    Save the change to lev_main.c and close the file.
X
X    Build the spec_lev application and save it into the "top" folder.
X    Close the spec_lev project. Now run the spec_lev application, it
X    will show you what file it is currently working on and create the
X    5 special levels: castle, endgame, tower1, tower2 and tower3 in
X    the top folder. These 5 files should be moved into the dungeon
X    folder.
X
X    If you're really motivated and want to create customized special
X    levels it should be possible to modify the special level compiler
X    to accomodate your efforts. You'll also want to edit the "descrip[]"
X    and "argc" variables, appropriately in lev_main.c within the ifdef
X    MACOS segments, to get the compiler to recognize your custom levels.
X    This is not trivial! You probably won't bother (no one has)!
X
X    If you decide to change features in the game, remember to rebuild
X    the special levels compiler to reflect those changes and also
X    recreate the special levels.
X
X6.  This is what you've been waiting for! Now we're going to build the
X    game. The file "Segments.mac" shows the source dependencies for this
X    application and suggests a workable scheme for creating properly sized
X    segments. THINKC4 users can simply open the "nethack.proj" file, other
X    users should build segments according to "Segments.mac" and also add
X    in the appropriate libraries.
X
X    Follow the checklist below which indicates the changes needed to build
X    the game.
X
X   *Edit topten.c near the beginning and set the following values:
X    #define POINTSMIN 51
X    #define ENTRYMAX 50
X    comment out: #define PERS_IS_UID
X    This will keep the size of the record file reasonable. Save your
X    changes and close topten.c .
X
X   *Edit config.h within the #ifdef MACOS segment:
X    uncomment:   #define CUSTOM_IO
X    uncomment:   #define NEED_VARARGS
X    Save your changes to config.h and close the file.
X
X    Since we're going to use pre-compiled headers in our THINKC4 project
X    a minor lexical change needs to be made to several files. The
X    affected files are:
X    alloc.c     apply.c     end.c       extralev.c  mkroom.c    monmove.c
X    pager.c     pctty.c     pri.c       priest.c    save.c      shk.c
X    sounds.c    termcap.c   topl.c      topten.c
X    In these files we'll need to comment out the #define's that appear
X    before the first #include compiler directive. Usually this only
X    involves a single #define (end.c, monmove.c and topten.c are exceptions).
X    This can be done fairly easily using the regular expression search
X    feature of the "Find" command. Assuming that all files are in the project
X    invoke the "Find" command from the "Search" menu. Enter these fields:
X    Search For:                            Replace with:
X    ^\(#.*pre-compiled headers \*\/\)      /*\1
X    Check the "Grep" and "Multi-File Search" check boxes (you'll be
X    looking in all .c files) then click the "Don't Find" button.
X    Now repeat this sequence:
X    1) Select "Find in Next File" from the "Search" menu.
X    2) When it finally makes a match, Select "Replace All".
X    3) Click the "Okay" button in the ensuing alert and go back to (1),
X    until there are no more matches. Save the changes to these files
X    and close them all (you may consider doing 6 at a time if having
X    too many open windows is a problem).
X
X    Copy the files hack.h and config.h to oldhack.h. and oldconfig.h,
X    respectively. You'll need the old*.h files (properly renamed) if you
X    make changes to the game and need to rebuild the makedefs and spec_lev
X    applications. Trash the hack.h file and "Open" the "oldhack.h" file
X    for editing. Select "Precompile ..." fom the "Source menu and save the
X    result as "hack.h". Close the oldhack.h file. Now trash the "config.h"
X    file and "Open" the "oldconfig.h" file for editing. Again select
X    "Precompile ..." and save the result as "config.h". Close the file
X    oldconfig.h . Make sure that you aren't auto-including "MacHeaders"
X    by selecting the "Options ..." entry from the "Edit" menu. Click the
X    "Code Generation" radio button and make sure that "<MacHeaders>" is
X    not checked.
X
X    Build the application, this make take a few minutes. Save the game
X    into the dungeon folder. Close the nethack project and you're ready
X    to play the game (I hope all went well).
X
XSpecial Note: If you are attempting to build Nethack 3.0 on a 1M Macintosh
X    using Think C 4.0, then memory may be a problem. It is suggested that
X    you turn off debugging info for monst.c and objects.c . Also, if for
X    some reason, compilation stops in the segment containing these two
X    files after they have been compiled, then you should drag these two
X    files into a separate segment, finish compiling the files of the
X    original segment and then restore these two files to the original
X    segment. Alternatively, you may decide to "Kompile" monst.c and
X    objects.c separately while preserving the given segmentation scheme.
X
X7.  Cleanup. It's a good idea to always rebuild the makedefs and spec_lev
X    applications from scratch. Therefore you can trash these applications
X    and also remove the objects from their respective projects (Think C
X    compilers) to conserve disk space. The same can be done for your
X    nethack project. Consider the changes outlined above and undo them
X    as needed to rebuild the project, if you decide to modify the game.
X    If you're satisfied with the "full-featured" game you can trash all
X    the files for a real saving!
X
XNotes:
X1.  You should trash bones and save files from previous versions since
X    they will not work with this version. Record files will work but
X    notice that new scores will have a different format. It is easiest
X    to just start fresh with a new scoreboard (record file).
X
X2.  If you can afford the RAM space you might consider giving the game
X    a 1M partition in Multifinder instead of the default 750k.
X
X    We, the members of the Macintosh NetHack Development Team, hope you
X    enjoy the game. We've worked hard at porting and polishing it to
X    make it behave in the Macintosh way!
END_OF_FILE
if test 14959 -ne `wc -c <'Install.mac'`; then
    echo shar: \"'Install.mac'\" unpacked with wrong size!
fi
# end of 'Install.mac'
echo shar: Extracting \"'do_patch8.sh'\" \(330 characters\)
sed "s/^X//" >'do_patch8.sh' <<'END_OF_FILE'
X#! /bin/sh
X# script to call patch to apply diff files
X# make sure all of the patch files (and this file) are in your top level
X# NetHack directory
X#
Xecho "deleting outdated files"
Xrm -f mac/NH3.proj.hqx mac/NH3.rsrc.hqx vms/Install.com
Xecho "applying patch8"
Xcat patch8.?? | patch -p
Xecho "all patches applied, check for rejects"
END_OF_FILE
if test 330 -ne `wc -c <'do_patch8.sh'`; then
    echo shar: \"'do_patch8.sh'\" unpacked with wrong size!
fi
chmod +x 'do_patch8.sh'
# end of 'do_patch8.sh'
echo shar: Extracting \"'others/ovlmgr.asm'\" \(40486 characters\)
sed "s/^X//" >'others/ovlmgr.asm' <<'END_OF_FILE'
X;	SCCS Id: @(#)ovlmgr.asm 		90/05/27
X;  Copyright (c) 1989, 1990 Pierre Martineau and Stephen Spackman. All Rights Reserved.
X;  This product may be freely redistributed.  See NetHack license for details.
X
XVERSION 	EQU	3081h
X
X		PAGE	57,132
X		TITLE	'DOS Overlay Manager for MSC 5.1+'
X		SUBTTL	'Copyright (c) 1989, 1990 Pierre Martineau and Stephen Spackman. All Rights Reserved.'
X
X; acknowledgements:   - Many thanks to Norm Meluch for his invaluable help
X;		      - No thanks to Microsoft
X;		      - alltrsidsctysti!!!
X;		      - izchak and friends for impetus
X;		      - us for brilliance
X;		      - coffee for speed
X;		      - others as necessary
X
X; assumptions:	      - all registers are preserved including flags
X;		      - the stack is preserved
X;		      - re-entrancy is not required
X
XDOSALLOC	EQU	48h			; memory allocation
XDOSFREE 	EQU	49h			; free allocated memory
XDOSREALLOC	EQU	4ah			; modify memory block
XDOSREAD 	EQU	3fh			; read bytes from handle
XDOSSEEK 	EQU	42h			; logical handle seek
XDOSOPEN 	EQU	3dh			; open handle
XDOSCLOSE	EQU	3eh			; close handle
XDOSEXEC 	EQU	4bh			; exec child process
XDOSPUTC 	EQU	02h			; print a char
XDOSVERSION	EQU	30h			; get version number
XDOSGETVEC	EQU	35h			; get interrupt vector
XDOS		EQU	21h			; Dos interrupt #
XPRINT		EQU	09h			; print string
XTERMINATE	EQU	4ch			; terminate process
XEMM		EQU	67h			; EMM handler int vector
XEMMSTATUS	EQU	40h			; get EMM status
XEMMFRAME	EQU	41h			; get EMM page frame
XEMMTOTALS	EQU	42h			; get EMM pages available
XEMMALLOC	EQU	43h			; allocate EMM pages
XEMMMAP		EQU	44h			; map EMM pages
XEMMFREE 	EQU	45h			; free EMM pages
XCR		EQU	0dh
XLF		EQU	0ah
XESCAPE		EQU	1bh
XBELL		EQU	07h
XPARSIZ		EQU	10h			; this is the size of a paragraph - this better not change!
XFAERIE		EQU	00h			; Used for dummy segment allocation
X
XNOERR		EQU	0
XDOSERR		EQU	1
XFILEERR 	EQU	2
XNOMEMERR	EQU	3
XFILEIOERR	EQU	4
XVICTIMERR	EQU	5
XRELERR		EQU	6
XEMSERR		EQU	7
XHDRERR		EQU	8
X
X; The following EXTRNs are supplied by the linker
X
XEXTRN		$$OVLBASE:BYTE			; segment of OVERLAY_AREA
XEXTRN		$$MPGSNOVL:BYTE 		; ^ to module table
XEXTRN		$$MPGSNBASE:WORD		; ^ to module segment fixups
XEXTRN		$$INTNO:BYTE			; interrupt number to be used
XEXTRN		$$COVL:WORD			; number of physical overlays
XEXTRN		$$CGSN:WORD			; number of modules
XEXTRN		$$MAIN:FAR			; ^ to function main()
X
XPUBLIC		$$OVLINIT			; Our entry point
X						; called by the c startup code
XIFDEF i386
XOP32		MACRO				; 32 bit operand override
X		DB	066h
X		ENDM
X
Xpusha		MACRO				; push all registers
X		DB	060h
X		ENDM
X
Xpopa		MACRO				; pop all registers
X		DB	061h
X		ENDM
XENDIF
X
Xovlflgrec	RECORD	locked:1=0,ems:1=0,loaded:1=0 ; overlay flags
X
X; This is a dirty hack. What we need is a virtual segment that will be built
X; by the (our) loader in multiple copies, one per overlay. Unfortunately, this
X; doesn't seem to be a sensible idea in the minds of the folks at Microsoft.
X; Declaring this segment AT will ensure that it never appears in the exefile,
X; and ASSUME is dumb enough to be fooled.
X;
X; The reason we want to do this is also not-to-be-tried-at-home: it turns out
X; that we can code a faster interrupt handler if we map overlay numbers to
X; segment values. Normally we would consider this unacceptable programming
X; practise because it is 86-mode specific, but the *need* for this entire
X; programme is 86-mode specific, anyway.
X
Xpspseg		SEGMENT PARA AT FAERIE		; dummy segment for psp
X		ORG	2ch			; ^ to segment of environmemt in psp
Xpspenv		LABEL	WORD
Xpspseg		ENDS
X
Xovltbl		SEGMENT PARA AT FAERIE		; Dummy segment definition for overlay table
X
X; NOTE: This segment definition MUST be exactly 16 bytes long
X
Xovlflg		ovlflgrec	<0,0,0> 	; overlay flags
Xovlinvcnt	DB	?			; invocation count
Xovlmemblk	DW	?			; ^ to allocated memory block
Xovllrudat	DD	?			; misc lru data (pseudo time stamp)
Xovlemshdl	DW	?			; ovl ems memory handle
Xovlfiloff	DW	?			; ovl file offset in pages (512 bytes)
Xovlsiz		DW	?			; ovl size in paragraphs
Xovlhdrsiz	DW	?			; hdr size in paragraphs
X
XIF1
XIF		($ - ovlflg) GT PARSIZ
X		.ERR
X		%OUT This segment MUST be no more than 16 bytes, REALLY!!!
XENDIF
XENDIF
X
XOVLSEGSIZ	EQU	PARSIZ			; this had better be true!!! (16 bytes)
X
Xovltbl		ENDS
X
XEXEHDR		STRUC				; structure of an EXE header
Xexesign 	DW	5a4dh			; signature
Xexelstpgesiz	DW	?			; last page size (512 byte pages)
Xexesiz		DW	?			; total pages (including partial last page)
Xrelocitems	DW	?			; number of relocation entries
Xhdrparas	DW	?			; number of paragraphs in the header
Xminalloc	DW	?			; minimum paragraph allocation
Xmaxalloc	DW	?			; maximum patagraph allocation
Xexess		DW	?			; initial stack segment
Xexesp		DW	?			; initial stack pointer
Xexechksum	DW	?			; checksum
Xexeip		DW	?			; initial instruction pointer
Xexecs		DW	?			; initial code segment
Xreloctbloff	DW	?			; offset from beginning of header to relocation table
Xexeovlnum	DW	?			; overlay number
XEXEHDR		ENDS
X
XMASK_used	EQU	1			; memory block flag
X
XMEMCTLBLK	STRUC				; memory block structure
Xmemblkflg	DB	?			; flags
Xmemblkpad1	DB	?			; go ahead, delete me!
Xmemblknxt	DW	?			; ^ to next block
Xmemblkprv	DW	?			; ^ to previous block
Xmemblkovl	DW	?			; ^ to overlay occupying this block
Xmemblksiz	DW	?			; size in paragraphs
Xmemblkpad	DB	PARSIZ - memblkpad MOD PARSIZ DUP (?) ; pad to 16 bytes
XMEMCTLBLK	ENDS
X
XMEMCTLBLKSIZ	EQU	TYPE MEMCTLBLK / PARSIZ ; should equal 1 paragraph
X
X;-------------------------------------------------------------------------------
X
Xcode		SEGMENT PUBLIC
X
X; NOTE: the following order is optimum for alignment purposes across the
X;	entire INTEL 80x86 family of processors.
X
Xovltim		DD	?			; pseudo-lru time variable
Xfarcall 	DD	?			; internal trampoline.
Xoldvec		DD	-1			; saved interrupt vector
Xoldint21	DD	-1			; saved int 21 vector
Xsireg		DW	?			; temp save area
XIFDEF i386
X		DW	?			; for esi
XENDIF
Xdsreg		DW	?			; temp save area
Xssreg		DW	?
Xspreg		DW	?
Xovlexefilhdl	DW	-1			; always-open file handle of our .EXE
Xovltblbse	DW	-1			; segment of first overlay descriptor
Xmemblks 	DW	16 DUP (-1)		; allocated memory blocks
Xmemblk1st	DW	?			; first memory block
Xemsmemblks	DW	16 DUP (-1)		; ems allocated memory blocks (64K each)
Xcuremshandle	DW	-1			; currently mapped handle
Xovlcnt		DW	?			; # overlays
Xmodcnt		DW	?			; # of modules
Xovlrootcode	DW	?			; logical segment of OVERLAY_AREA
Xovldata 	DW	?			; logical segment of OVERLAY_END
Xpspadd		DW	?			; our psp address + 10h (for relocations)
Xemsframe	DW	?			; EMM page frame segment
Xmoduletbl	DD	256 DUP (?)		; module lookup table (256 modules)
Xcurovl		DW	OFFSET stkframe 	; ^ into stack frame
Xstkframe	DW	256*3 DUP (?)		; internal stack (256 ovls deep)
Xtempmem 	DW	16 DUP (-1)		; temp mem block storage
Xintnum		DW	?			; ovlmgr int number
Xhdr		EXEHDR	<>			; EXE header work area
X		DB	512-TYPE EXEHDR DUP (?) ; exe hdr buffer for relocations
XEXEHDRTMPSIZ	EQU	$ - hdr 		; size of temp reloc buffer
Xerrortbl	DW	-1			; error message pointers
X		DW	OFFSET baddos
X		DW	OFFSET nofile
X		DW	OFFSET noroom
X		DW	OFFSET nofile
X		DW	OFFSET nocore
X		DW	OFFSET nocore
X		DW	OFFSET badems
X		DW	OFFSET nofile
X		DW	OFFSET unknown
X		DW	OFFSET unknown
X		DW	OFFSET unknown
X		DW	OFFSET unknown
X		DW	OFFSET unknown
X		DW	OFFSET unknown
X		DW	OFFSET unknown
Xemmname 	DB	"EMMXXXX0"              ; EMM device driver name
Xemmtot		DW	0			; total emm blocks free
Xemmframesiz	DW	4			; frame size in blocks
Xemmflg		DB	0			; EMM present flag
X
Xi386code	DB	'386 specific code enabled.',CR,LF,'$'
Xmemavl		DB	'Conventional memory available: $'
Xparagraphs	DB	'H paragraphs.',CR,LF,'$'
Xemsavl		DB	'EMS memory available: $'
Xpages		DB	'H 16K-pages.',CR,LF,'$'
Xnoroom		DB	'Not enough free memory left to run this program.$'
Xnocore		DB	'Internal memory allocation failure.$'
Xnofile		DB	'Inaccessible EXE file. Can',27,'t load overlays.$'
Xbaddos		DB	'Incorrect DOS version. Must be 3.00 or later.$'
Xbadems		DB	'EMS memory manager error.$'
Xunknown 	DB	'Unknown error!$'
Xmsghead 	DB	ESCAPE,'[0m',ESCAPE,'[K',CR,LF,ESCAPE,'[K',ESCAPE,'[1mOVLMGR:',ESCAPE,'[0m $'
Xdiag		DB	ESCAPE,'[K',CR,LF,ESCAPE,'[K','        ($'
Xmsgtail 	DB	ESCAPE,'[K',CR,LF,ESCAPE,'[K',BELL,'$'
X
X;-------------------------------------------------------------------------------
X
X$$OVLINIT	PROC	FAR			; Init entry point
X
X		ASSUME	CS:code,DS:pspseg,ES:NOTHING
X
X		push	ax
X		push	bx
X		push	cx
X		push	dx
X		push	si
X		push	di
X		push	bp
X		push	ds
X		push	es			; save the world
X		cld
X		mov	ax,ds			; get our psp
X		add	ax,10h
X		mov	pspadd,ax		; save it
X		mov	ah,DOSVERSION
X		int	DOS
X		cmp	al,3			; DOS 3.0 or later
X		jnc	doenvthing
X		mov	al,DOSERR		; incorrect version of dos
X		jmp	putserr
Xdoenvthing:
X		mov	ds,pspenv		; get environment segment
X		mov	si,-1
Xenvloop:					; search for end of environment
X		inc	si
X		cmp	WORD PTR [si],0
X		jnz	envloop
X		add	si,4			; point to EXE filename
X		mov	al,0			; access code
X		mov	ah,DOSOPEN
X		mov	dx,si
X		int	DOS			; open EXE
X		jnc	dontdie
X		mov	al,FILEERR		; can't open file!
X		jmp	putserr
Xdontdie:
X		mov	ovlexefilhdl,ax 	; save handle
XIFNDEF NOEMS
Xchkems:
X		mov	ah,DOSGETVEC
X		mov	al,EMM
X		int	DOS
X		mov	ax,cs
X		mov	ds,ax
X		mov	di,0ah
X		mov	si,OFFSET emmname
X		mov	cx,8
X		repe	cmpsb
X		mov	al,0
X		jnz	setemmflg
X		mov	al,-1
Xsetemmflg:
X		mov	emmflg,al
X		jnz	noemshere
X		mov	ah,EMMFRAME
X		int	EMM
X		mov	emsframe,bx
X		mov	ah,EMMTOTALS
X		int	EMM
X		mov	emmtot,bx
Xnoemshere:
XENDIF
X		mov	ax,SEG $$OVLBASE	; OVERLAY_AREA segment
X		mov	ovlrootcode,ax
X		mov	ax,SEG $$COVL		; segment of DGROUP
X		mov	ds,ax
X		mov	bx,$$CGSN		; number of modules
X		mov	modcnt,bx		; save for later use
X		mov	bx,$$COVL		; number of physical overlays
X		mov	ovlcnt,bx		; save for later use
X
X; Now allocate memory
X		mov	ah,DOSALLOC		; bx contains # paras needed for ovltbl
X		int	DOS
X		jnc	gotovlram
X		jmp	buyram
Xgotovlram:
X		mov	ovltblbse,ax		; overlay descriptor table begins at start of memory block
X
X		push	cs
X		pop	ds
XIFDEF DEBUG
XIFDEF i386
X		mov	ah,print
X		mov	dx,OFFSET msghead
X		int	DOS
X		mov	ah,print
X		mov	dx,OFFSET i386code
X		int	DOS
XENDIF
X		mov	ah,print
X		mov	dx,OFFSET msghead
X		int	DOS
X		mov	ah,print
X		mov	dx,OFFSET memavl
X		int	DOS
X		mov	ax,0a000h
X		sub	ax,ovltblbse
X		call	itoa
X		mov	ah,print
X		mov	dx,OFFSET paragraphs
X		int	DOS
XIFNDEF NOEMS
X		mov	ah,print
X		mov	dx,OFFSET msghead
X		int	DOS
X		mov	ah,print
X		mov	dx,OFFSET emsavl
X		int	DOS
X		mov	ax,emmtot
X		call	itoa
X		mov	ah,print
X		mov	dx,OFFSET pages
X		int	DOS
XENDIF
XENDIF
X		ASSUME	ES:ovltbl
X
X		xor	bp,bp
X		xor	di,di
X		xor	si,si
Xfilsegtbllpp:					; initialise ovl table
X		call	gethdr			; get an EXE header
X		mov	ax,ovltblbse
X		add	ax,hdr.exeovlnum
X		mov	es,ax			; ^ to ovl table entry
X		xor	ax,ax
X		mov	WORD PTR ovllrudat,ax	; initialise ovl lru
X		mov	WORD PTR ovllrudat+2,ax
X		mov	ovlflg,al		; initialise ovl flags
X		mov	ovlinvcnt,al		; initialise invocation count
X		mov	ovlemshdl,-1
X		mov	ax,hdr.exesiz
X		shl	ax,1
X		shl	ax,1
X		shl	ax,1
X		shl	ax,1
X		shl	ax,1			; * 32
X		mov	dx,hdr.exelstpgesiz
X		or	dx,dx
X		jz	emptypage
X		shr	dx,1
X		shr	dx,1
X		shr	dx,1
X		shr	dx,1			; / 16
X		inc	dx
X		sub	ax,20h
X		add	ax,dx
Xemptypage:
X		sub	ax,hdr.hdrparas 	; actual size of code
X		mov	ovlsiz,ax		; overlay size in paragraphs
X		cmp	hdr.exeovlnum,0 	; skip if ovl 0 (root code)
X		jz	notlargest
X		cmp	ax,di			; find largest ovl
X		jc	notlargest
X		mov	di,ax
Xnotlargest:
X		mov	ax,hdr.hdrparas
X		shl	ax,1
X		shl	ax,1
X		shl	ax,1
X		shl	ax,1
X		mov	ovlhdrsiz,ax		; hdr size in bytes
X		mov	ovlfiloff,bp		; initialise ovl file offset
X		add	bp,hdr.exesiz		; ^ to next overlay
X		mov	dx,bp
X		mov	cl,dh
X		mov	dh,dl
X		xor	ch,ch
X		xor	dl,dl
X		shl	dx,1
X		rcl	cx,1			; cx:dx = bp * 512
X		mov	al,0
X		mov	ah,DOSSEEK		; seek to next ovl
X		int	DOS
X		mov	ax,ovlcnt
X		dec	ax
X		cmp	ax,hdr.exeovlnum	; all overlays done?
X		jz	makmemblk
X		jmp	filsegtbllpp		; Nope, go for more.
Xmakmemblk:
X		ASSUME	ES:nothing		; prepare first memory block
X
X		mov	ax,ovlrootcode		; OVERLAY_AREA segment
X		mov	memblk1st,ax		; save pointer to first mem block
X		mov	es,ax
X		mov	es:memblkflg,0		; clear mem flags
X		mov	es:memblknxt,0		; set next to nothing
X		mov	es:memblkprv,0		; set previous to nothing
X		mov	es:memblkovl,0		; no overlay loaded
X		mov	es:memblksiz,di 	; di contains OVERLAY_AREA size in paragraphs
X		add	ax,di
X		mov	ovldata,ax		; end of OVERLAY_END
X		push	di
X		mov	es,ovltblbse		; temporary
X		call	getemsmem		; see if any ems available
X		mov	es:ovlemshdl,-1 	; fix these!
X		and	es:ovlflg,NOT MASK ems
X		push	dx
X		call	getmoreram		; see if there are any other pieces lying around
X		pop	ax
X		pop	di
X		or	ax,ax			; any ems?
X		jnz	noramcheck
X		inc	di
X		cmp	dx,di
X		jc	buyram
Xnoramcheck:
X		mov	WORD PTR ovltim,0	; initialise global lru time stamp
X		mov	WORD PTR ovltim+2,0
X		mov	di,OFFSET stkframe
X		mov	WORD PTR cs:[di],-1	; initialise stack frame
X		add	di,6
X		mov	ax,ovltblbse
X		mov	cs:[di],ax
X		mov	curovl,di		; initialise stack frame pointer
X		mov	es,ax
X		mov	es:ovlflg,MASK locked OR MASK loaded ; set flags on ovl 0
X		jmp	short chgintvec
Xbuyram:
X		mov	al,NOMEMERR		; free up some TSRs or something
X		jmp	putserr
Xchgintvec:
X		mov	ax,SEG $$INTNO
X		mov	ds,ax
X		mov	al,$$INTNO		; get int number to use
X		xor	ah,ah
X		shl	ax,1
X		shl	ax,1
X		mov	intnum,ax
X		call	setvectors		; set up interrupt vectors
X		mov	cx,modcnt		; module count
X		mov	ax,SEG $$MPGSNBASE
X		mov	es,ax
X		mov	ax,cs
X		mov	ds,ax
X
X		ASSUME	DS:code
X
X		mov	bx,OFFSET $$MPGSNBASE	; ^ to linker provided overlay segment fixups
X		mov	si,OFFSET $$MPGSNOVL	; ^ to linker provided module table
X		mov	di,OFFSET moduletbl	; ^ to our module table
Xmodloop:
X		mov	al,es:[si]		; real physical ovl number
X		xor	ah,ah
X		add	ax,ovltblbse		; ovlctlseg address
X		mov	[di],ax 		; save in module table
X		mov	ax,es:[bx]		; get seg fixup
X		sub	ax,ovlrootcode		; adjust for relative reference
X		mov	[di+2],ax		; save in module table
X		add	di,4
X		add	bx,2
X		inc	si
X		loop	modloop
X		pop	es
X		pop	ds
X		pop	bp
X		pop	di
X		pop	si
X		pop	dx
X		pop	cx
X		pop	bx
X		pop	ax			; restore the world
X		jmp	$$MAIN			; And away we go!
X
X$$OVLINIT	ENDP
X
X;-------------------------------------------------------------------------------
X
Xovlmgr		PROC	FAR			; This is the it!
X
X		ASSUME	DS:NOTHING,ES:NOTHING
X
XIFDEF i386
X		OP32
XENDIF
X		mov	sireg,si		; preserve si
X		mov	dsreg,ds		; and ds
X		pop	si			; retrieve caller ip
X		pop	ds			;     "      "    cs
X		push	ax
X		push	bx
X		cld
X		lodsb				; module # to call
X		xor	ah,ah
X		mov	bx,ax
X		lodsw				; offset in ovl to call
X		mov	WORD PTR farcall,ax	; into trampoline
X		mov	ax,si
X		mov	si,curovl		; get stack frame pointer
X		add	si,6			; update stack
X		mov	cs:[si-4],ds		; save return seg
X		mov	cs:[si-2],ax		; and return offset
X
X		shl	bx,1
X		shl	bx,1			; * 4 (2 words/entry in module tbl)
X		add	bx,OFFSET moduletbl
X		mov	ds,cs:[bx]		; ovl tbl entry
X		mov	ax,cs:[bx+2]		; segment fixup
X		mov	cs:[si],ds		; ovl entry into stack frame
X		mov	curovl,si
X
X		ASSUME	DS:ovltbl
X
XIFDEF i386
X		OP32
XENDIF
X		mov	si,WORD PTR ovltim	; lru time stamp
XIFDEF i386
X		OP32
XENDIF
X		inc	si			; time passes!
XIFDEF i386
X		OP32
XENDIF
X		mov	WORD PTR ovltim,si	; update global clock
XIFDEF i386
X		OP32
XENDIF
X		mov	WORD PTR ovllrudat,si	; as well as ovl clock
XIFNDEF i386
X		mov	si,WORD PTR ovltim+2
X		jz	ininc			; dword increment
Xcryupcdon:
X		mov	WORD PTR ovllrudat+2,si ; as well as ovl clock
XENDIF
X		test	ovlflg,MASK loaded	; ovl loaded?
X		jz	inload			; load it or map it then.
Xovlloadedupc:
X		inc	ovlinvcnt
X		add	ax,ovlmemblk		; add fixup and segment address
X		mov	WORD PTR farcall+2,ax	; into trampoline
XIFDEF i386
X		OP32
XENDIF
X		mov	si,sireg		; retore all registers
X		mov	ds,dsreg
X		pop	bx
X		pop	ax
X		popf				; don't forget these!
X		call	DWORD PTR farcall	; and GO
X		pushf				; preserve registers again!
X		mov	dsreg,ds
XIFDEF i386
X		OP32
XENDIF
X		mov	sireg,si
X		mov	si,curovl		; stack frame pointer
X		mov	ds,cs:[si]
X		dec	ovlinvcnt
X		sub	si,6			; adjust stack
X		mov	ds,cs:[si]		; retrieve ovl tbl entry
X		push	cs:[si+2]		; set return address
X		push	cs:[si+4]
X		mov	curovl,si
XIFDEF i386
X		OP32
XENDIF
X		mov	si,WORD PTR ovltim	; do the lru thing again
XIFDEF i386
X		OP32
XENDIF
X		inc	si
XIFDEF i386
X		OP32
XENDIF
X		mov	WORD PTR ovltim,si
XIFDEF i386
X		OP32
XENDIF
X		mov	WORD PTR ovllrudat,si
XIFNDEF i386
X		mov	si,WORD PTR ovltim+2
X		jz	outinc
Xcrydncdon:
X		mov	WORD PTR ovllrudat+2,si
XENDIF
X		test	ovlflg,MASK loaded	; ovl loaded?
X		jz	outload 		; better get it before someone notices
Xjmpback:
XIFDEF i386
X		OP32
XENDIF
X		mov	si,sireg		; get registers back
X		mov	ds,dsreg
X		iret				; and GO back
X
XIFNDEF i386
Xininc:
X		inc	si
X		mov	WORD PTR ovltim+2,si	; update global and
X		jmp	cryupcdon
XENDIF
X
Xinload:
X		test	ovlflg,MASK ems
X		jz	infile
X		push	ax
X		mov	ax,ovlemshdl
X		call	mappage
X		pop	ax
X		jmp	ovlloadedupc
Xinfile:
X		call	loadoverlay		; self explanatory
X		jmp	ovlloadedupc
X
XIFNDEF i386
Xoutinc:
X		inc	si
X		mov	WORD PTR ovltim+2,si
X		jmp	crydncdon
XENDIF
X
Xoutload:
X		test	ovlflg,MASK ems
X		jz	outfile
X		push	ax
X		mov	ax,ovlemshdl
X		call	mappage
X		pop	ax
X		jmp	jmpback
Xoutfile:
X		call	loadoverlay
X		jmp	jmpback
X
Xovlmgr		ENDP
X
X;-------------------------------------------------------------------------------
X
Xloadoverlay	PROC	NEAR			; load overlay pointed to by es
X
X		ASSUME	DS:NOTHING,ES:ovltbl
X
XIFDEF i386
X		OP32
X		pusha			       ; eax,ecx,edx,ebx,esp,ebp,esi,edi
XELSE
X		push	ax
X		push	cx
X		push	dx
X		push	bx
X		push	bp
X		push	si
X		push	di
XENDIF
X		push	ds
X		push	es			; just in case
X		mov	ax,ds
X		mov	es,ax
X		cmp	ovlinvcnt,0
X		jnz	fxdadr			; Yup, it's a toughie
X		mov	ax,ovlsiz		; How much?
X		call	getpages		; never fail mem alloc, you bet.
X		jmp	gleaner
Xfxdadr:
X		call	releasepages		; free memory where this ovl should be loaded
Xgleaner:
X		add	ax,MEMCTLBLKSIZ 	; skip mem ctl blk
X		mov	ovlmemblk,ax		; memory block to use
X		mov	ds,ax
X		mov	dx,ovlfiloff		; where in the file is it?
X		mov	cl,dh
X		mov	dh,dl
X		xor	ch,ch
X		xor	dl,dl
X		shl	dx,1
X		rcl	cx,1			; cx:dx = dx * 512
X		mov	ax,ovlhdrsiz
X		push	cx
X		push	dx
X		add	dx,ax
X		adc	cx,0			; position to code
X		mov	ah,DOSSEEK		; lseek to code
X		mov	al,0			; from beginning of file
X		mov	bx,ovlexefilhdl 	; never closing handle
X		int	DOS
X		jc	burnhead		; oops!
X		xor	dx,dx			; buf = ds:0
X		mov	cx,ovlsiz		; number of paragraphs to load
X		shl	cx,1
X		shl	cx,1
X		shl	cx,1
X		shl	cx,1			; * 16 = number of bytes
X		mov	ah,DOSREAD		; prevent random DOS behaviour
X		int	DOS			; read in code
X		jc	burnhead		; double oops!
X		pop	dx
X		pop	cx			; position of hdr
X		mov	ah,DOSSEEK		; lseek to hdr
X		mov	al,0			; from beginning of file
X		mov	bx,ovlexefilhdl 	; never closing handle
X		int	DOS
X		jc	burnhead		; oops!
X		mov	cx,EXEHDRTMPSIZ 	; reloc buffer size
X		mov	dx,OFFSET hdr
X		push	ds
X		mov	ax,cs
X		mov	ds,ax
X		mov	ah,DOSREAD		; prevent random DOS behaviour
X		int	DOS			; read in header
X		pop	ds
X		jc	burnhead		; double oops!
X
X		call	ovlrlc			; perform relocation normally done by DOS EXE loader
X		pop	es			; retrieve ovl tbl entry
X		pop	ds
X
X		ASSUME	DS:ovltbl,ES:NOTHING
X
X		or	ovlflg,MASK loaded	; because it is now
XIFDEF i386
X		OP32
X		popa
XELSE
X		pop	di
X		pop	si
X		pop	bp
X		pop	bx
X		pop	dx
X		pop	cx
X		pop	ax
XENDIF
X		ret
X
Xburnhead:
X		mov	al,FILEIOERR		; some kind of I/O error
X		jmp	putserr
X
Xloadoverlay	ENDP
X
X;-------------------------------------------------------------------------------
X
Xovlrlc		PROC	NEAR			; ds:0 -> the overlay to relocate
X
X		ASSUME	DS:NOTHING,ES:NOTHING
X
X		mov	si,OFFSET hdr
X		mov	bp,si
X		add	bp,EXEHDRTMPSIZ 	; ^ to end of buf+1
X		mov	cx,cs:[si.relocitems]	; roto-count
X		jcxz	relocdone		; not such a good idea, after all
X		mov	di,ds
X		sub	di,ovlrootcode		; segment fixup value
X		add	si,cs:[si.reloctbloff]	; ^ relocation table
Xdorelocs:					; labels don't GET comments
X		cmp	si,bp			; past the end ?
X		jc	getoffsetl
X		call	getnxtreloc		; get another hunk
Xgetoffsetl:
X		mov	bl,cs:[si]		; offset into load module
X		inc	si
X		cmp	si,bp			; past the end ?
X		jc	getoffseth
X		call	getnxtreloc		; get another hunk
Xgetoffseth:
X		mov	bh,cs:[si]		; offset into load module
X		inc	si
X		cmp	si,bp			; past the end ?
X		jc	getsegmentl
X		call	getnxtreloc		; get another hunk
Xgetsegmentl:
X		mov	al,cs:[si]		; segment in load module (zero reference)
X		inc	si
X		cmp	si,bp			; past the end ?
X		jc	getsegmenth
X		call	getnxtreloc		; get another hunk
Xgetsegmenth:
X		mov	ah,cs:[si]		; segment in load module (zero reference)
X		inc	si
X		add	ax,pspadd		; now it is psp relative
X		add	ax,di			; and now it is relative to the actual load address
X		mov	es,ax
X		mov	ax,es:[bx]		; pickup item to relocate
X		add	ax,pspadd		; make it psp relative
X		cmp	ax,ovlrootcode		; is it below the OVERLAY_AREA?
X		jc	reloccomputed		; yup. it's relocated
X		cmp	ax,ovldata		; is it above OVERLAY_AREA
X		jnc	reloccomputed		; yup. it's relocated
X		add	ax,di			; it's in OVERLAY_AREA, this one's ours.
Xreloccomputed:
X		mov	es:[bx],ax		; RAM it home!?!
X		loop	dorelocs		; what goes around, comes around.
Xrelocdone:	ret
X
Xovlrlc		ENDP
X
X;-------------------------------------------------------------------------------
X
Xgetnxtreloc	PROC	NEAR
X
X		ASSUME	DS:NOTHING,ES:NOTHING
X
X		push	bx
X		push	cx
X		push	di
X		push	bp
X		push	ds
X		push	es
X		mov	cx,EXEHDRTMPSIZ 	; reloc buffer size
X		mov	dx,OFFSET hdr
X		mov	ax,cs
X		mov	ds,ax
X		mov	bx,ovlexefilhdl 	; never closing handle
X		mov	ah,DOSREAD		; prevent random DOS behaviour
X		int	DOS			; read in header
X		jnc	nxtrelocok
X		jmp	burnhead		; double oops!
Xnxtrelocok:
X		mov	si,OFFSET hdr
X		pop	es
X		pop	ds
X		pop	bp
X		pop	di
X		pop	cx
X		pop	bx
X		ret
X
Xgetnxtreloc	ENDP
X
X;-------------------------------------------------------------------------------
X
Xgetvictim	PROC	NEAR			; select a victim to discard (and free up some memory)
X
X		ASSUME	DS:ovltbl,ES:NOTHING
X
X		push	bx
X		push	cx
X		push	dx
X		push	si
X		push	di
X		push	bp
X		push	ds
X		mov	ds,ovltblbse		; ^ ovl tbl
XIFDEF i386
X		OP32
XENDIF
X		xor	ax,ax			; will contain the low word of lru
XIFDEF i386
X		OP32
XENDIF
X		mov	dx,ax			; will contain the high word of lru
X		mov	bp,ax			; will contain ovl tbl entry
X		mov	bx,ax			; ovl tbl ptr
X		mov	cx,ovlcnt
Xfoon1:
X		test	ovlflg[bx],MASK locked
X		jnz	skip1
X		test	ovlflg[bx],MASK ems
X		jnz	foon2
X		test	ovlflg[bx],MASK loaded
X		jz	skip1
Xfoon2:
XIFDEF i386
X		OP32
XENDIF
X		mov	si,WORD PTR ovltim
XIFNDEF i386
X		mov	di,WORD PTR ovltim+2
XENDIF
XIFDEF i386
X		OP32
XENDIF
X		sub	si,WORD PTR ovllrudat[bx]
XIFNDEF i386
X		sbb	di,WORD PTR ovllrudat[bx+2]
XENDIF
XIFDEF i386
X		OP32
X		cmp	dx,si
XELSE
X		cmp	dx,di
XENDIF
XIFDEF i386
X		jnc	skip1
XELSE
X		jc	better1
X		jnz	skip1
X		cmp	ax,si
X		jnc	skip1
XENDIF
Xbetter1:
XIFDEF i386
X		OP32
X		mov	dx,si
XELSE
X		mov	ax,si
X		mov	dx,di
XENDIF
X		mov	bp,bx
Xskip1:
X		add	bx,OVLSEGSIZ
X		loop	foon1
X		or	bp,bp			; were we more successful this time?
X		jnz	gotvictim		; now we got one.
Xnomoremem:
X		mov	al,VICTIMERR		; were really %$# now!
X		jmp	putserr
Xgotvictim:
X		shr	bp,1			; convert offset to segment
X		shr	bp,1
X		shr	bp,1
X		shr	bp,1
X		mov	ax,ds
X		add	ax,bp
X		pop	ds
X		pop	bp
X		pop	di
X		pop	si
X		pop	dx
X		pop	cx
X		pop	bx
X		ret
X
Xgetvictim	ENDP
X
X;-------------------------------------------------------------------------------
X
Xint21		PROC	FAR
X
X; free almost all overlay memory if app. tries to call the DOS exec function.
X
X		cmp	ah,DOSEXEC
X		jz	freeall
X		cmp	ah,TERMINATE
X		jz	saybyebye
Xnotours:
X		jmp	cs:oldint21
Xsaybyebye:
X		mov	al,NOERR		; return code 0
X		jmp	putserr
Xfreeall:
X		or	al,al			; is it load and exec?
X		jnz	notours
X		push	ax
X		push	cx
X		push	dx
X		push	bx
X		push	bp
X		push	si
X		push	di
X		push	es
X		push	ds			; preserve calling env.
X
X		ASSUME	DS:NOTHING,ES:ovltbl
X
X		mov	es,ovltblbse
X		mov	cx,ovlcnt		; unload all overlays that are
X		mov	bx,OVLSEGSIZ		; in EMS or are in alloced mem.
X		dec	cx
Xmemunloadlp:
X		test	[bx.ovlflg],MASK ems
X		jnz	memunload
X		test	[bx.ovlflg],MASK loaded
X		jz	nxtmemunload
X		mov	ax,[bx.ovlmemblk]
X		sub	ax,MEMCTLBLKSIZ
X		cmp	ax,memblks		; allocated memory ?
X		jc	nxtmemunload
Xmemunload:
X		and	[bx.ovlflg],NOT MASK loaded ; you're outta there!
Xnxtmemunload:
X		add	bx,OVLSEGSIZ
X		loop	memunloadlp
X
X		mov	curemshandle,-1 	; no current handle anymore
X
X		mov	ax,memblks
X		cmp	ax,-1
X		jz	nosecondblk
X		mov	es,ax			; ^ to second mem blk
X		mov	es,es:memblkprv 	; get previous pointer
X		mov	es:memblknxt,0		; no other blocks after this one
Xnosecondblk:
X		mov	cx,16			; do all allocated mem blocks
X		mov	si,OFFSET memblks
Xfreememblklp:
X		mov	ax,cs:[si]		; get memory blk segment
X		cmp	ax,-1			; was one ever allocated?
X		jz	nxtmemblklp		; nope
X		mov	es,ax
X		mov	ah,DOSFREE		; must free it.
X		int	DOS
X		mov	WORD PTR cs:[si],-1
Xnxtmemblklp:
X		add	si,2
X		loop	freememblklp
X
X		call	rstvectors		; restore all int vectors
X
X		mov	bp,sp
X		push	[bp+22] 		; ensure returned flags are based on user's!
X		popf
X		pop	ds
X		pop	es
X		pop	di
X		pop	si
X		pop	bp
X		pop	bx
X		pop	dx
X		pop	cx
X		pop	ax
X
X		mov	ssreg,ss		; preserve these due to a
X		mov	spreg,sp		; DOS bug.
X
X		int	DOS			; allow DOS to continue!
X
X		mov	ss,ssreg
X		mov	sp,spreg
X
X		push	ax
X		push	cx
X		push	dx
X		push	bx
X		push	bp
X		push	si
X		push	di
X		push	es
X		push	ds			; preserve calling env.
X		mov	bp,sp
X		pushf
X		pop	[bp+22] 		; fix return flags
X
X		call	getmoreram		; re-allocate our memory
X		call	setvectors		; patch vectors again
X
X		pop	ds
X		pop	es
X		pop	di
X		pop	si
X		pop	bp
X		pop	bx
X		pop	dx
X		pop	cx
X		pop	ax
X		iret
X
Xint21		ENDP
X
X;-------------------------------------------------------------------------------
X
Xreleasepages	PROC	NEAR			; Arg in es, result in ax
X
X; release any memory (and overlays) where this overlay should reside
X
X		ASSUME	DS:NOTHING,ES:ovltbl
X
X		mov	bx,ovlmemblk		; start of memory to release
X		sub	bx,MEMCTLBLKSIZ
X		mov	dx,bx
X		add	dx,es:ovlsiz
X		add	dx,MEMCTLBLKSIZ 	; end of memory to release
X		mov	ax,ovlemshdl
X		cmp	ax,-1
X		jz	doitagain
X		call	mappage
X		or	ovlflg,MASK ems
X		mov	ax,emsframe
X		jmp	dvart
Xdoitagain:
X		mov	ax,memblk1st		; first memory blk
X		jmp	dvart
Xdvartloop:
X		mov	ds,ax			; memory blk to check
X		cmp	bx,ax			; does it start below the memory to release?
X		jnc	dvartsmaller		; yup
X		cmp	ax,dx			; does it start above?
X		jnc	dvartnocore		; yup
X		call	killmem 		; it's in the way. Zap it.
X		jmp	dvartloop
Xdvartsmaller:
X		add	ax,ds:memblksiz 	; end of this memory blk
X		cmp	bx,ax			; does it end below the memory to release?
X		jnc	dvartsilly		; yup
X		test	ds:memblkflg,MASK_used
X		jz	dvartfree
X		call	killmem 		; Oh well, zap it too.
X		add	ax,ds:memblksiz 	; end of this memory blk
Xdvartfree:
X		cmp	ax,dx			; does it end in the memory to be released?
X		jc	dvartsilly
Xdvartgotblk:
X		mov	ax,ds			; this is it!
X		mov	cx,bx
X		sub	cx,ax			; # of paragraphs between start of memory to release and mem blk
X		jz	nosplit
X		push	es
X		call	splitblk
X		or	es:memblkflg,MASK_used	; set high block used
X		call	mergemem		; merge remaining free memory
X		mov	ax,es
X		mov	ds,ax
X		pop	es
Xnosplit:
X		mov	cx,es:ovlsiz
X		add	cx,MEMCTLBLKSIZ 	; paragraphs needed to load ovl
X		jmp	splitblklow		; split remaining block
Xdvartsilly:
X		mov	ax,ds:memblknxt
Xdvart:
X		or	ax,ax			; end of mem list?
X		jz	dvartnocore
X		jmp	dvartloop		; play it again Sam.
Xdvartnocore:
X		mov	al,RELERR		; super OOPS!
X		jmp	putserr
X
Xreleasepages	ENDP
X
X;-------------------------------------------------------------------------------
X
Xgetpages	PROC	NEAR			; get enough memory to load ovl
X
X		ASSUME	DS:NOTHING,ES:ovltbl
X
X		mov	ovlemshdl,-1		; clear any EMS stuff
X		and	ovlflg,NOT MASK ems
X		mov	cx,ax
X		add	cx,MEMCTLBLKSIZ 	; total paragraphs needed
Xdorkagain:
X		call	largestmem		; find largest free blk
X		cmp	dx,cx			; large enough?
X		jnc	gotdork 		; yup.
X		call	getemsmem		; try to allocate ems
X		cmp	dx,cx			; any available ?
X		jnc	gotdork
Xdorkkill:
X		call	getvictim		; select a victim to release
X		call	killovl 		; kill the selected victim
X		jmp	dorkagain
Xgotdork:
X		jmp	splitblklow		; split the free blk
X
Xgetpages	ENDP
X
X;-------------------------------------------------------------------------------
X
Xsplitblklow	PROC	NEAR
X
X; split a block of memory returning the lower one to be used.
X
X		ASSUME	DS:NOTHING,ES:NOTHING
X
X		push	es
X		or	ds:memblkflg,MASK_used	; set low block used
X		call	splitblk
X		jc	splitlowdone
X		push	ds
X		mov	ax,es
X		mov	ds,ax
X		call	mergemem		; merge remaining free memory
X		pop	ds
Xsplitlowdone:
X		pop	es
X		mov	ds:memblkovl,es 	; fix ptr to ovl
X		mov	ax,ds			; return lower blk segment
X		ret
X
Xsplitblklow	ENDP
X
X;-------------------------------------------------------------------------------
X
Xsplitblk	PROC	NEAR
X
X		ASSUME	DS:NOTHING,ES:NOTHING
X
X		mov	ax,ds
X		add	ax,cx
X		mov	es,ax			; ^ to upper blk to be created
X		mov	ax,ds:memblksiz
X		sub	ax,cx
X		jbe	nofix			; must be at least 1 para remaining to split
X		mov	ds:memblksiz,cx 	; fix blk sizes
X		mov	es:memblksiz,ax
X		mov	ax,ds:memblknxt 	; fix pointers
X		mov	es:memblknxt,ax
X		mov	ds:memblknxt,es
X		mov	es:memblkprv,ds
X		mov	es:memblkflg,0		; set upper to not used
X		mov	ax,es:memblknxt
X		or	ax,ax
X		jz	nofix
X		push	ds
X		mov	ds,ax			; fix blk after upper to point to upper
X		mov	ds:memblkprv,es
X		pop	ds
X		clc
X		ret
Xnofix:
X		stc
X		ret
X
Xsplitblk	ENDP
X
X;-------------------------------------------------------------------------------
X
Xlargestmem	PROC	NEAR	; returns seg in ax, size in dx
X				; retruns first block that's large enough if possible
X
X		ASSUME	DS:NOTHING,ES:ovltbl
X
X		mov	ax,memblk1st		; first mem blk
X		xor	dx,dx			; largest size found
X		jmp	gook
Xgookloop:
X		mov	ds,ax
X		test	ds:memblkflg,MASK_used	; is this blk used?
X		jnz	gookme			; yup
X		cmp	ds:memblksiz,cx 	; is it large enough?
X		jc	gookme			; nope
X		mov	dx,ds:memblksiz 	; got one!
X		ret
Xgookme:
X		mov	ax,ds:memblknxt
Xgook:
X		or	ax,ax			; end of list?
X		jnz	gookloop		; around and around
X		ret
X
Xlargestmem	ENDP
X
X;-------------------------------------------------------------------------------
X
Xkillmem 	PROC	NEAR
X
X		ASSUME	DS:NOTHING,ES:ovltbl
X
X		test	ds:memblkflg,MASK_used	; is it used?
X		jz	memnotused		; don't kill ovl
X		push	es
X		mov	es,ds:memblkovl
X		and	ovlflg,NOT MASK loaded	; zap ovl associated with this blk
X		and	ovlflg,NOT MASK ems
X		pop	es
Xmemnotused:
X		jmp	mergemem		; merge free memory
X
Xkillmem 	ENDP
X
X;-------------------------------------------------------------------------------
X
Xkillovl 	PROC	NEAR		; preserves bx
X
X		ASSUME	DS:ovltbl,ES:NOTHING
X
X		mov	ds,ax
X		and	ovlflg,NOT MASK loaded	; ovl no longer loaded
X		test	ovlflg,MASK ems 	; was it in ems ?
X		jz	noemskill
X		and	ovlflg,NOT MASK ems	; no longer in ems
X		mov	ax,ovlemshdl
X		call	mappage
Xnoemskill:
X		mov	ax,ovlmemblk		; get mem blk
X		sub	ax,MEMCTLBLKSIZ
X		mov	ds,ax
X		jmp	mergemem		; merge free memory
X
Xkillovl 	ENDP
X
X;-------------------------------------------------------------------------------
X
Xmergemem	PROC	NEAR
X
X; merge physically adjacent free memory blocks. Preserves es. ds -> a free block.
X
X		ASSUME	DS:NOTHING,ES:NOTHING
X
X		push	dx
X		push	es
X		and	ds:memblkflg,NOT MASK_used ; set current free
X		mov	ax,ds:memblkprv 	; get previous blk
X		or	ax,ax			; was there a previous blk?
X		jz	gibber			; nope
X		mov	es,ax
X		test	es:memblkflg,MASK_used	; is the previous blk used?
X		jnz	gibber			; yup
X		add	ax,es:memblksiz 	; end of previous blk
X		mov	dx,ds
X		cmp	dx,ax			; physically adjacent?
X		jnz	gibber			; nope
X		mov	ax,ds:memblksiz
X		add	es:memblksiz,ax 	; adjust size of new larger blk
X		mov	ax,ds:memblknxt 	; fix pointers
X		mov	es:memblknxt,ax
X		or	ax,ax
X		jz	almostgibber
X		mov	ds,ax			; fix pointer of next blk
X		mov	ds:memblkprv,es
Xalmostgibber:
X		mov	ax,es
X		mov	ds,ax			; new blk segment
Xgibber:
X		mov	ax,ds:memblknxt 	; get next blk
X		or	ax,ax			; was there a next blk?
X		jz	killdone		; nope
X		mov	es,ax
X		test	es:memblkflg,MASK_used	; is the nxt blk used?
X		jnz	killdone		; yup
X		mov	ax,ds
X		add	ax,ds:memblksiz 	; end of this blk
X		mov	dx,es
X		cmp	ax,dx			; physically adjacent?
X		jnz	killdone		; nope
X		mov	ax,es:memblksiz
X		add	ds:memblksiz,ax 	; adjust size of new larger blk
X		mov	ax,es:memblknxt 	; fix pointers
X		mov	ds:memblknxt,ax
X		or	ax,ax
X		jz	killdone
X		mov	es,ax			; fix pointer of blk after nxt
X		mov	es:memblkprv,ds
Xkilldone:
X		and	ds:memblkflg,NOT MASK_used ; make sure it's free
X		pop	es
X		pop	dx
X		mov	ax,ds
X		ret
X
Xmergemem	ENDP
X
X;-------------------------------------------------------------------------------
X
Xgetmoreram	PROC	NEAR			; try to alloc remaining pieces
X						; of memory if any
X		ASSUME	DS:NOTHING,ES:NOTHING	; return dx = biggest block
X
X		push	cx
X		push	bx
X		push	si
X		push	di
X		push	ds
X		push	es
X		xor	dx,dx
X		mov	ax,memblk1st
Xnxtlowblk:
X		mov	ds,ax
X		mov	ax,ds:memblknxt
X		or	ax,ax
X		jnz	nxtlowblk
X
X		mov	si,OFFSET memblks	; a place to store the handles
X		mov	di,OFFSET tempmem	; a place to store the rejects
X		mov	cx,16			; 16 more max
Xgetramlp:
X		mov	ah,DOSALLOC
X		mov	bx,0ffffh		; Everything
X		int	DOS
X		cmp	bx,10h			; nothing smaller than .25k please
X		jc	gotallram
X		mov	ah,DOSALLOC		; allocate our own memory
X		int	DOS
X		jc	gotallram		; oops!
X		cmp	ax,ovltblbse		; is it after our first mem blk?
X		jc	releaseblk
X		cmp	dx,bx
X		jnc	notbigger
X		mov	dx,bx
Xnotbigger:
X		mov	cs:[si],ax		; save it
X		mov	es,ax
X		mov	es:memblkflg,0		; clear mem flags
X		mov	es:memblknxt,0		; set next to nothing
X		mov	es:memblkovl,0		; no overlays loaded
X		mov	es:memblkprv,ds 	; point to previous
X		mov	es:memblksiz,bx 	; allocated memory block size
X		mov	ds:memblknxt,es 	; point to next
X		add	si,2
X		mov	ds,ax
X		jmp	short getnxtram
Xreleaseblk:
X		mov	cs:[di],ax
X		add	di,2
Xgetnxtram:
X		loop	getramlp
Xgotallram:
X		mov	si,OFFSET tempmem
X		mov	cx,16
Xreleaselp:
X		mov	ax,cs:[si]
X		cmp	ax,-1
X		jz	relnext
X		mov	es,ax
X		mov	ah,DOSFREE
X		int	DOS
X		mov	WORD PTR cs:[si],-1
Xrelnext:
X		add	si,2
X		loop	releaselp
X		pop	es
X		pop	ds
X		pop	di
X		pop	si
X		pop	bx
X		pop	cx
X		ret
X
Xgetmoreram	ENDP
X
X;-------------------------------------------------------------------------------
X
Xgetemsmem	PROC	NEAR
X
X		ASSUME	DS:NOTHING,ES:ovltbl
X
X		xor	dx,dx			; no ems memory
X		cmp	emmflg,-1
X		jz	testemsslots
X		ret
Xtestemsslots:
X		mov	curemshandle,-1
X		mov	di,OFFSET emsmemblks
X		mov	bx,cx
X		mov	cx,16
Xemsfreeslot:
X		mov	ax,cs:[di]
X		cmp	ax, -1
X		jz	gotemsslot
X		call	mappage
X		cmp	ax,bx
X		jnc	foundpage
X		add	di,2
X		loop	emsfreeslot
X		mov	cx,bx
X		xor	dx,dx
X		ret
Xgotemsslot:
X		mov	cx,bx
X		mov	bx,4
X		mov	ah,EMMALLOC
X		push	cx			; paranoia ! shouldn't be necessary.
X		push	di
X		push	es
X		int	EMM
X		pop	es
X		pop	di
X		pop	cx
X		or	ah,ah
X		jz	gotsomeems
X		xor	dx,dx
X		ret
Xgotsomeems:
X		mov	cs:[di],dx
X		mov	ovlemshdl,dx
X		or	ovlflg,MASK ems
X		mov	ax,dx
X		call	mapemspages
X		mov	ax,emsframe
X		mov	ds,ax
X		mov	ds:memblkflg,0		; clear mem flags
X		mov	ds:memblknxt,0		; set next to nothing
X		mov	ds:memblkprv,0		; set previous to nothing
X		mov	ds:memblkovl,0		; no overlay loaded
X		mov	dx,1000h
X		mov	ds:memblksiz,dx
X		ret
X
Xfoundpage:
X		mov	cx,bx
X		mov	ds,si
X		mov	dx,ax
X		mov	ax,cs:[di]
X		mov	ovlemshdl,ax
X		or	ovlflg,MASK ems
X		ret
X
Xgetemsmem	ENDP
X
X;-------------------------------------------------------------------------------
X
Xmappage 	PROC	NEAR			; map a 64K block of EMS mem.
X
X		ASSUME	DS:NOTHING,ES:ovltbl
X
X		cmp	ax,curemshandle
X		jnz	doems
X		ret
Xdoems:
X		push	bx
X		push	dx
X		push	ds
X		push	es
X		call	mapemspages
X		mov	ax,emsframe
X		xor	dx,dx
X		xor	si,si
Xemsset:
X		mov	ds,ax
X		test	ds:memblkflg,MASK_used	; mem blk used ?
X		jz	emsfreeblk
X		mov	es,ds:memblkovl
X		or	ovlflg,MASK ems OR MASK loaded
X		jmp	emsnext
Xemsfreeblk:
X		mov	ax,ds:memblksiz
X		cmp	dx,ax
X		jnc	emsnext
X		mov	dx,ax
X		mov	si,ds
Xemsnext:
X		mov	ax,ds:memblknxt
X		or	ax,ax
X		jnz	emsset
X
X		mov	ax,dx
X		pop	es
X		pop	ds
X		pop	dx
X		pop	bx
X		ret
X
Xmappage 	ENDP
X
X;-------------------------------------------------------------------------------
X
Xmapemspages	PROC	NEAR
X
X		ASSUME	DS:NOTHING,ES:ovltbl
X
X		push	es
X		push	bx
X		push	cx
X		push	dx
X		mov	curemshandle,ax
X		mov	dx,ax
X		mov	ah,EMMMAP
X		xor	al,al			; physical page 0
X		xor	bx,bx			; logical page 0
X		push	dx
X		int	EMM
X		pop	dx
X		or	ah,ah
X		jnz	emmerror
X		mov	ah,EMMMAP
X		mov	al,1			; physical page 1
X		mov	bx,1			; logical page 1
X		push	dx
X		int	EMM
X		pop	dx
X		or	ah,ah
X		jnz	emmerror
X		mov	ah,EMMMAP
X		mov	al,2			; physical page 2
X		mov	bx,2			; logical page 2
X		push	dx
X		int	EMM
X		pop	dx
X		or	ah,ah
X		jnz	emmerror
X		mov	ah,EMMMAP
X		mov	al,3			; physical page 3
X		mov	bx,3			; logical page 3
X		int	EMM
X		or	ah,ah
X		jnz	emmerror
X		mov	es,ovltblbse
X		mov	cx,ovlcnt
X		xor	bx,bx
Xtestems:
X		test	ovlflg[bx],MASK ems
X		jz	nxttestems
X		and	ovlflg[bx],NOT MASK loaded
Xnxttestems:
X		add	bx,OVLSEGSIZ
X		loop	testems
X		pop	dx
X		pop	cx
X		pop	bx
X		pop	es
X		ret
X
Xemmerror:
X		mov	al,EMSERR		; ems manager error
X		jmp	putserr
X
Xmapemspages	ENDP
X
X;-------------------------------------------------------------------------------
X
Xgethdr		PROC	NEAR			; read EXE header from handle
X
X		ASSUME	DS:NOTHING,ES:NOTHING
X
X		push	cx
X		push	ds
X		mov	ax,cs
X		mov	ds,ax
X		mov	dx,OFFSET hdr		; a place to put it
X		mov	bx,ovlexefilhdl 	; the file handle
X		mov	cx,TYPE EXEHDR		; header size in bytes
X		mov	ah,DOSREAD
X		int	DOS			; read from file
X		jc	exegone 		; oops
X		cmp	ax,cx			; got correct number of bytes?
X		jnz	exegone 		; nope
X		pop	ds
X		pop	cx
X		ret				; Wow, it worked!
Xexegone:
X		mov	al,HDRERR		; You lose!
X		jmp	putserr
X
Xgethdr		ENDP
X
X;-------------------------------------------------------------------------------
X
Xputserr 	PROC	NEAR
X
X; display error msg, close file, restore int vectors, free mem and return to DOS.
X
X		ASSUME	DS:NOTHING,ES:NOTHING
X
X		xor	ah,ah
X		push	ax			; keep return code for later
X		push	cs
X		pop	ds
X		mov	bx,ax
X		shl	bx,1
X		add	bx,OFFSET errortbl
X		mov	dx,[bx]
X		cmp	dx,-1
X		jz	freeints
X		push	dx
X		mov	dx,OFFSET msghead
X		mov	ah,PRINT
X		int	DOS
X		pop	dx
X		mov	ah,PRINT
X		int	DOS			; display error msg
X
X		mov	ah,PRINT
X		mov	dx,OFFSET diag
X		int	DOS
X		pop	ax
X		push	ax
X		call	itoa			; error number
X		mov	ah,DOSPUTC
X		mov	dl,':'
X		int	DOS
X		mov	ax,VERSION
X		call	itoa			; version number
X		mov	ah,DOSPUTC
X		mov	dl,':'
X		int	DOS
X		mov	ax,0a000h
X		sub	ax,ovltblbse		; conventional memory
X		call	itoa
X		mov	ah,DOSPUTC
X		mov	dl,':'
X		int	DOS
X		mov	si,OFFSET emsmemblks
X		mov	cx,16
X		xor	ax,ax
Xemstotlp:
X		cmp	WORD PTR cs:[si],-1
X		jz	gotemstot
X		add	ax,emmframesiz
X		add	si,2
X		loop	emstotlp
Xgotemstot:
X		call	itoa			; ems usage in blocks
X		mov	ah,DOSPUTC
X		mov	dl,')'
X		int	DOS
X
X		mov	dx,OFFSET msgtail
X		mov	ah,PRINT
X		int	DOS
Xfreeints:
X		call	rstvectors		; restore all int vectors
X
X		mov	ax,ovltblbse
X		cmp	ax,-1
X		jz	freememblks
X		mov	es,ax
X		mov	ah,DOSFREE
X		int	DOS
Xfreememblks:
X		mov	cx,16			; do all allocated mem blocks
X		mov	si,OFFSET memblks
Xfreememlp:
X		mov	ax,cs:[si]		; get memory blk segment
X		cmp	ax,-1			; was one ever allocated?
X		jz	nxtmemlp		; nope
X		mov	es,ax
X		mov	ah,DOSFREE		; must free it.
X		int	DOS
Xnxtmemlp:
X		add	si,2
X		loop	freememlp
X		mov	cx,16			; do all allocated ems blocks
X		mov	si,OFFSET emsmemblks
Xfreeemsmemlp:
X		mov	dx,cs:[si]		; get memory blk segment
X		cmp	dx,-1			; was one ever allocated?
X		jz	nxtemsmemlp		; nope
X		mov	ah,EMMFREE		; must free it.
X		int	EMM
Xnxtemsmemlp:
X		add	si,2
X		loop	freeemsmemlp
Xclosefile:
X		mov	bx,ovlexefilhdl 	; get file handle
X		cmp	bx,-1			; was the file ever opened?
X		jz	byebye			; nope
X		mov	ah,DOSCLOSE		; close it
X		int	DOS
Xbyebye:
X		pop	ax			; return code in al
X		mov	ah,TERMINATE
X		int	DOS			; terminate this process
X
Xputserr 	ENDP
X
X;-------------------------------------------------------------------------------
X
Xitoa		PROC	NEAR
X
X		push	ax
X		xchg	ah,al
X		call	putbyte
X		pop	ax
X		jmp	putbyte
X
Xitoa		ENDP
X
X;-------------------------------------------------------------------------------
X
Xputbyte 	PROC	NEAR
X
X		push	ax
X		shr	al,1
X		shr	al,1
X		shr	al,1
X		shr	al,1
X		call	nibble
X		pop	ax
X		jmp	nibble
X
Xputbyte 	ENDP
X
X;-------------------------------------------------------------------------------
X
Xnibble		PROC	NEAR
X
X		and	al,0fh
X		add	al,30h
X		cmp	al,3ah
X		jc	nibok
X		add	al,7
Xnibok:
X		mov	dl,al
X		mov	ah,DOSPUTC
X		int	DOS
X		ret
X
Xnibble		ENDP
X
X;-------------------------------------------------------------------------------
X
Xsetvectors	PROC	NEAR
X
X		push	ds
X		xor	ax,ax
X		mov	ds,ax
X		mov	si,cs:intnum
X		cli
X		mov	ax,[si]
X		mov	WORD PTR cs:oldvec,ax	; save original vector
X		mov	ax,[si+2]
X		mov	WORD PTR cs:oldvec+2,ax
X		mov	ax,OFFSET ovlmgr	; point to ovlmgr
X		mov	[si],ax 		; set int vector
X		mov	[si+2],cs
X
X		mov	si,DOS*4
X		mov	ax,[si]
X		mov	WORD PTR cs:oldint21,ax ; save original vector
X		mov	ax,[si+2]
X		mov	WORD PTR cs:oldint21+2,ax
X		mov	ax,OFFSET int21 	; point to new int21
X		mov	[si],ax 		; set int vector
X		mov	[si+2],cs
X		sti
X		pop	ds
X		ret
X
Xsetvectors	ENDP
X
X;-------------------------------------------------------------------------------
X
Xrstvectors	PROC	NEAR
X
X		push	ds
X		xor	ax,ax
X		mov	ds,ax
X		mov	si,DOS*4
X		cli
X		mov	ax,WORD PTR cs:oldint21 ; put back dos vector
X		cmp	ax,-1
X		jz	rstvec
X		mov	[si],ax
X		mov	ax,WORD PTR cs:oldint21+2
X		mov	[si+2],ax
Xrstvec:
X		mov	si,cs:intnum
X		mov	ax,WORD PTR cs:oldvec	; put back ovlmgr vector
X		cmp	ax,-1
X		jz	rstdone
X		mov	[si],ax
X		mov	ax,WORD PTR cs:oldvec+2
X		mov	[si+2],ax
X		sti
Xrstdone:
X		pop	ds
X		ret
X
Xrstvectors	ENDP
X
Xcode		ENDS
X
X		END
END_OF_FILE
if test 40486 -ne `wc -c <'others/ovlmgr.asm'`; then
    echo shar: \"'others/ovlmgr.asm'\" unpacked with wrong size!
fi
# end of 'others/ovlmgr.asm'
echo shar: Extracting \"'vms/vmsmisc.c'\" \(386 characters\)
sed "s/^X//" >'vms/vmsmisc.c' <<'END_OF_FILE'
X/*	SCCS Id: @(#)vmsmisc.c	3.0	90/22/02
X/* NetHack may be freely redistributed.  See license for details. */
X
X#include <ssdef.h>
X#include <stsdef.h>
X
Xvoid
Xvms_exit(status)
Xint status;
X{
X    exit(status ? (SS$_ABORT | STS$M_INHIB_MSG) : SS$_NORMAL);
X}
X
Xvoid
Xvms_abort()
X{
X    (void) LIB$SIGNAL(SS$_DEBUG);
X}
X
X#ifdef VERYOLD_VMS
X#include "oldcrtl.c"        /* "[-.vms]oldcrtl.c" */
X#endif
END_OF_FILE
if test 386 -ne `wc -c <'vms/vmsmisc.c'`; then
    echo shar: \"'vms/vmsmisc.c'\" unpacked with wrong size!
fi
# end of 'vms/vmsmisc.c'
echo shar: End of archive 20 \(of 24\).
cp /dev/null ark20isdone
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 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 24 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