[comp.sources.games] v10i057: nethack3p9 - display oriented dungeons & dragons

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

Submitted-by: Izchak Miller <izchak@linc.cis.upenn.edu>
Posting-number: Volume 10, Issue 57
Archive-name: nethack3p9/Part12
Supersedes: 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 12 (of 56)."
# Contents:  Install.ami others/ovlmgr.asm
# Wrapped by billr@saab on Wed Jul 11 17:11:06 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Install.ami' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Install.ami'\"
else
echo shar: Extracting \"'Install.ami'\" \(16878 characters\)
sed "s/^X//" >'Install.ami' <<'END_OF_FILE'
X
X	Instructions for compiling and installing NetHack 3.0
X			on an AMIGA system
X	=====================================================
X		    Last Revision: 27 May 1990
X
XOverview
X--------
X    This file contains the procedure to follow when installing NetHack 3.0
X    on an Amiga computer system.  It also includes some procedures and hints
X    for individuals desiring to create a binary from the source.  This
X    document is divided into 4 sections.  Section I deals with installing
X    already existing binaries and data files to create a working NetHack
X    game disk (or directory, in the case of a hard drive).  Section II
X    describes, in general, how to produce working binaries from the source.
X    Section III and IV are compiler specific sections, with section III
X    designed for Lattice users, and section IV for Manx/Aztec users.
X
XRequirements
X------------
X    Amiga 500,1000,2000,2500  running WorkBench 1.3 and KickStart 1.2 or 1.3.
X    (As of this time, the Amiga 3000 running beta-release versions of
X    WorkBench 2.0 are not supported.  While the core of the game appears to
X    function, the custom font is not recognized by the operating system.
X    The NetHack team welcomes reports of specific problems and solutions on
X    this [or any other] subject.)
X	one meg of RAM and one floppy drive (painful, but functional)
Xor	one meg of RAM and two floppy drives (much better)
Xor	more than one meg of RAM and a hard disk with 2+ meg free (best)
X
XCredits
X-------
X    Olaf Seibert first ported NetHack 2.3 and 3.0 to the Amiga.  Richard
X    Addison, Jochen Erwied, Mark Gooderum, Ken Lorber, Greg Olson, Mike
X    Passaretti, and Gregg Wonderly polished and extended the 3.0 port.
X
XSection I - Installation Guide
X-------------------------------
X    This section assumes you have the following handy:
X
X	* NetHack (executable code)
X	* Rumors file
X	* Oracle file
X	* All of the various help and informational files (help, opthelp, etc)
X	* Special level files (castle, tower1, tower2, tower3, endgame)
X	* Amiga with at least 1 meg memory (may be optimistic....)
X
X    And optionally:
X
X	* Icons if WorkBench interface is to be used.  These files include
X		+ NetHack.info
X		+ NewGame.info
X		+ NetHackScore.info
X		+ Guidebook.info
X		+ default.icon
X	* Special NetHack font (files hack.font and 8).
X
X    Installation Steps:
X
X	1) If you have a hard disk, create a directory named NetHack.
X	   Assign Nethack: to be the path to this directory.  If you have a
X	   floppy, format a disk named NetHack.  (If you have a hard disk
X	   but only one meg of memory, you will probably not have enough
X	   memory: you may need to run from a floppy.)
X
X	2) If you have a hard disk, assign HackExe: to the above directory.
X	   If you have a floppy, format an additional disk named HackExe.
X
X	3) Copy Nethack, NetHack.info, NewGame.info, and NetHackScore.info
X	   to HackExe.  Create an empty file called NewGame (WorkBench
X	   refuses to Duplicate a project icon without a file attached).
X
X	4) Copy the remainder of the files to NetHack:.  If you are using
X	   the optional font, create a Hack subdirectory on NetHack:, and
X	   copy "8" into it.  Be sure that Guidebook and Guidebook.info are
X	   in the same directory, and that the Default Tool field points to
X	   the More program (found on your AmigaDos System disk in the
X	   Utilities directory).  Depending on where you got your copy of
X	   NetHack, the Guidebook file may be called Guidebook.mss.
X
X	5) Configure NetHack.cnf as per your configuration.  Remember not
X	   to set GRAPHICS if you are not using the optional font.  If you
X	   have only one meg of ram, do not use a ram disk.
X
X    That's all there is to it!  If you are using the CLI interface, make sure
X    that the stack is set fairly large (at LEAST 40000 bytes).  Move to the
X    NetHack: directory, and type NetHack <cmd line options>.  If you're
X    using the WorkBench interface, click on the NetHack directory/disk.
X    You should see 3 icons.  Select the "NewGame" option, and "Duplicate" from
X    the WorkBench pull down menu.  This icon now represents your personal
X    profile.  You can now rename this icon, and tailor it to your liking
X    as described below.  If you start a game from the WorkBench interface,
X    saving the game will automatically tie the personal file icon to the
X    saved game.  So the next time you select your icon, the game will be
X    restored.
X
X    As mentioned above, the icon representing your personal profile can be
X    customized.  This is done via the the Info command available from
X    WorkBench.  You can adjust the following using the ToolTypes from the
X    WorkBench info command:
X
X	* OPTIONS=<options> - Options as avaliable in the NetHack.cnf file.
X
X	* HACKDIR=<directory> - Set NetHack working directory to be this
X	  directory.
X
X	* RAMDISK=<ram disk> - Set up ram disk option.
X
X	* LEVELS=<levels> - Intermediate level saving device/directory.
X
X	* PATH=<path> - To search for files such as rumors, help, etc.
X
X	* CMDLINE=<args> - Arguments as passed on the CLI command line.
X	  Note:  only the following flags are valid: n, X, D, and r.
X
X	* SCORE <options> - Display the record of scores.  Options as
X	  available on the CLI command line after a -s flag.
X
X    Note that the NetHack.cnf file is read first, then the ToolTypes.  This
X    means that the options specified in the NetHack.cnf act as defaults
X    which can be overridden by an individual's personal icon's ToolTypes.
X    Thus the system oriented entries (HACKDIR, RAMDISK, LEVELS, and PATH)
X    should generally be set only in NetHack.cnf.  NetHack.cnf should have
X    default values for OPTIONS, which will generally be overridden by
X    ToolTypes entries.
X
X    Also, there is one additional option that may be specified in the
X    NetHack.cnf file or on an OPTIONS line: flush.  When enabled, flush
X    discards all characters in the queue except the first, which limits
X    but does NOT completely eliminate the "accidents" which can occur if
X    you get ahead of the game when typing.  The default setting is noflush.
X
XSection II - General Compilation Instructions
X---------------------------------------------
X
X    1)  Before doing any compilation, read the README files distributed
X	with the source.  These should familiarize you with the source tree
X	layout, and what files are shared with what computers.  Generally,
X	everything in the amiga directory is used exclusively by the Amiga.
X
X    2)  Create the sub-directories, and name them as indicated in the source
X	README file.  If you have a hard drive, this is fairly trivial
X	(create a directory, and corresponding NetHack sub-directories).
X	If you have only floppies, you'll have to be a bit more clever.
X	The makefile (Makefile.ami) is set up to depend upon certain
X        assignments, providing the developer with a fairly flexible
X	environment.  The main directory with which a floppy user will have
X        problems is the src directory.  In order to fit all of the source on
X	to floppies, the src directory has been split into logical units.
X	For example, the makefile expects:
X
X	    Src1:  contains src [a-l]*.c
X	    Src2:  contains src [m-po]*.c
X	    Src3:  contains src [pr-z]*.c
X
X	See makefile.ami for assignment assumptions.
X
X    3)  Edit config.h to your liking and system configuration.  The following
X	are strong suggestions for certain #define values.
X
X	    + UNIX - DO NOT DEFINE
X	    + MSDOS - DO NOT DEFINE HERE, IT WILL BE DONE LATER FOR YOU
X	    + COMPRESS - DO NOT DEFINE
X	    + ZEROCOMP - DEFINE
X	    + CHDIR - RECOMMENDED
X	    + HACKDIR - "NetHack:" MANDATORY
X	    + BITFIELDS - DO NOT DEFINE IF YOU HAVE MANX3.6
X	    + CLIPPING - DO NOT DEFINE
X
X	4) Edit amiconf.h to your liking.  It is recommended you leave
X	   everything as is with the following exceptions:
X
X            + TEXTCOLOR - Will allow the use of colors for text objects in
X              the game.  For instance, red gems will be red.  Unfortunately,
X              at this time this is only configurable at compile time, when
X	      it really should be configurable at run time.  Note also that
X	      there is a slight bug when running textcolor, namely that when
X	      you are polymorphed, the color you are is not correct because
X	      the cursor overlays the default monster color.  You can see
X	      yourself fine, but you do not represent the correct monster color.
X
X	    + HACKFONT - Enable if you want to use the special NetHack font,
X	      disable otherwise.
X
X            + AMIGA_WBENCH - Enable if you want the WorkBench interface to
X	      be compiled into the code. This does NOT preclude you from
X              running from CLI.
X
X	5) If you have significant spare ram, you may wish to make your
X	   compiler resident (Lattice 5.05's lc, lc1, and lc2 need about
X	   215K while Manx's cc and as need about 135K).
X
X	6) At this point, you're almost ready to begin a compile.  Read VERY
X	   CAREFULLY through the Makefile to familiarize yourself with which
X	   assignments are assumed.  Otherwise, you're going to get something
X	   like "Insert O_Src1: in any drive." requestors.  If you have the
X	   uudecode program and need to uudecode the various *.uu files from
X	   the Amiga: directory (font and icons), define the UUDEC symbol
X	   at the appropriate place in the makefile.  The first thing
X	   Makefile.ami does is build a program called 'makedefs', which
X	   handles a variety of data file generation, and a program called 
X	   'lev_comp' which compiles the special levels.  Makedefs will then be
X	   run to create a few files, followed by an alphabetically sorted
X	   compilation of the entire source tree.  This compilation process
X	   will compile selected files from Amiga:, Others:, Src1:, Src2:,
X	   and Src3: directories.  If all goes well, all of the  objects will
X	   be linked together to form a binary.  With all of the options
X	   enabled, the Manx 3.6 executable runs about 790K, and the Lattice
X	   executable runs about 750K (without debug hunks, or about 1025K
X	   with debug hunks - see below).  After building the main binary,
X	   the makefile will build and install the auxiliary files including
X	   help files, special levels, icons, and the font files.
X
XSECTION III - Lattice Compilation Instructions
X----------------------------------------------
X
X    If you're a Lattice user, you should be pretty well set up at this point.
X    If you have some spare ram, you may wish to examine the Amiga:compact.lat
X    script.  This script will reduce your compile time by using Lattice's
X    lcompact utility to pre-scan the header files and place compacted copies
X    onto the Ram: disk.  Read through the comments in that script if you
X    wish to utilize it.
X
X    Due to a problem with versions 5.04 and 5.05, you must make one change:
X    edit the file Others:lev_lex.c.  At (or near) line 1003 is the definition
X    for the function yyunput.  Delete the word "register" from this line.
X    Note that if you neglect to do this, you will get an Error 72 at line 319
X    of file lev_comp.l (this is the correct message - lev_lex.c is flex output).
X    Save the changed file.  Later compiler versions may or may not need this
X    fix.
X
X    Type 'CD NetHack:' and then type "lmk -f Amiga:Makefile.ami".  If all
X    goes well, you'll have a working binary a couple of hours later (depending
X    on your hardware configuration).  A couple of notes and warnings from the
X    Lattice users on the team:
X
X	* The primary Lattice compiler used on the Amiga port was version
X	  5.05.  Previous versions of NetHack have been successfully compiled
X	  with 5.04 and 5.04a.
X
X	* The function monsndx, in file mondata.c, has a section of code
X	  which Lattice 5.04 compiles incorrectly.  A hack has been written
X	  around this so that Lattice will generate the correct code.  It is
X	  recommended that you leave this in place, and not attempt to
X	  "improve" it.  This fix "does the right thing" in version 5.05.
X
X	* Included in the Lattice port is code for generating a SnapShot.tb
X	  file upon catching various internal disasters.  That is why the
X	  -d1 flag is in the makefile.  This adds about 270K to the disk
X	  image, but it does not increase the run time memory requirements.
X	  Floppy users will have to delete -d1 flag, or the binary won't
X	  fit on a single disk.
X
X	* The optimizer seems to work, but no extensive testing has been
X	  done with it.  (Note: optimizing objnam.c takes several hours.)
X
X	* There are a large number of warnings under Lattice, which are
X	  harmless.
X
XSECTION IV  - AZTEC/MANX Compilation Instructions
X-------------------------------------------------
X
X    NetHack 3.0 compiles and runs fine under Aztec 3.6, but a little bit
X    of work is necessary.  The problem is that the Aztec pre-processor
X    is fairly stupid, and doesn't recognize the defined() pre-processor
X    function.  Unfortunately, this function is laced throughout the NetHack
X    code, hence removing it would be quite a chore, and end up rendering the
X    code much more unreadable.
X
X    There are a couple solutions to this problem.  The first solution is to
X    run every source file through some c pre-processor which understands
X    defined() (the Decus cpp works fine).  The problem with this solution is
X    that the time it takes to compile/recompile is (at least) doubled.  My
X    configuration is a 33 meg hard drive and 2 1/2 megs of ram, and it still
X    takes over 4 hours to generate a binary from scratch!  Also note that
X    Makefile.ami was not built to support cpp, and so you'll have to modify
X    the makefile to add this step.
X
X    But don't despair, have we got a deal for you!  The Apple NetHackers also
X    had a similar problem with defined, which led them to developing a
X    defined() hack (located in config.h).  This hack basically adds
X    the defined() functionality to the Aztec pre-processor, with the exception
X    of performing this operation on strings.  Fortunately, using defined() on
X    strings is done very rarely, and they are handled on an individual basis.
X    (The only one I can think of right now is WIZARD/WIZARD_NAME).  What's the
X    catch, you ask?  Well, there is one. The problem is as follows.
X
X    The Aztec compiler doesn't know how to handle const, volatile, and signed
X    data types.  Normally, this can be fixed by sticking a #define const
X    before const is used, thereby rendering it disabled.  Unfortunately, the
X    Aztec pre-processor, in its infinite wisdom, WILL NOT LET YOU REDEFINE
X    these strings.
X
X    The solution to this is not quite as elegant as the solution to the
X    defined() problem above.  It requires a one time modification to the
X    Aztec cc binary.  (DO THIS TO A BACKUP COPY OF CC!!)  Find a disk zapper,
X    NewZap works fine.  Then do a search for the string 'const'.  Change
X    the const, signed and volatile strings to __nst, __gned and __latile.
X    (It's really not as bad as it sounds....)
X
X    A couple of warnings regarding the 3.6 compiler/NetHack:
X
X	* The 3.6 Manx bitfield handling is buggy at best.  Though I can't
X	  specifically cite a flaw when NetHack is compiled with it, I
X	  don't trust it.  I recommend you don't either.
X
X	* If your signal.h (in your Manx include directory) has SIGINT
X	  commented out, go ahead and uncomment it.
X
X	* If you use the cpp method, pass -DAZTEC_C and -DMCH_AMIGA to
X          the cpp.  These are defined automatically by Aztec C, but are
X          ineffective if the source is run through a filter first.
X
X	* There will be a few harmless warnings in the compile process.
X	  These warnings will be in amidos.c, and pickup.c.  There may also
X	  be a warning when defining lev_lex.c that LEV_LEX is redefined.  This
X	  is OK.  Any other warnings should be investigated.
X
X	* I haven't tried sdb on it, as I can't affort the disk space.  (You'll
X	  have to save the intermediate cpp files if you cpp).  Unless you've
X          got a whopping amount of memory, I suspect it's going to be too large.
X
X	* There are 2 versions of lev_lex.c that are being distributed; one
X	  generated by (unix) lex, and one generated by gnu flex.  The gnu
X	  flex lev_lex.c should work without modification.  If you use the
X          lex lev_lex.c, you will get 4 warnings regarding ptr/int conversions.
X          Change the masks from (int) to (long) to generate a clean binary.
X
X	* Unfortunately, Manx 5.0 arrived too late to integrate into patch
X	  level 7, but merging will occur in the next few weeks.  Contact us
X	  (below) for progress/hints.  (Postscript for PL8: the situation is
X	  very much improved, but there may be some problems remaining).
X
X			- - - - - - - - - - - -
X
XIf you have problems or questions, email to nethack-bugs@linc.cis.upenn.edu,
Xor directly to Greg Olson (golson@sundown.sun.com)  for Manx questions,
Xto Ken Lorber (keni@dtix.dt.navy.mil) for Lattice questions, or to
XRichard Addison (addison@pollux.usc.edu) for either.  Have fun!!
END_OF_FILE
if test 16878 -ne `wc -c <'Install.ami'`; then
    echo shar: \"'Install.ami'\" unpacked with wrong size!
fi
# end of 'Install.ami'
fi
if test -f 'others/ovlmgr.asm' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'others/ovlmgr.asm'\"
else
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'
fi
echo shar: End of archive 12 \(of 56\).
cp /dev/null ark12isdone
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 56 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