MS-DOS v2.0 Release

This commit is contained in:
Rich Turner 1983-08-12 17:53:34 -07:00
parent fce0f75959
commit 80ab2fddfd
156 changed files with 56403 additions and 0 deletions

BIN
v2.0/bin/ANSI.DOC Normal file

Binary file not shown.

BIN
v2.0/bin/CHKDSK.COM Normal file

Binary file not shown.

BIN
v2.0/bin/COMMAND.COM Normal file

Binary file not shown.

BIN
v2.0/bin/CONFIG.DOC Normal file

Binary file not shown.

BIN
v2.0/bin/CREF.EXE Normal file

Binary file not shown.

BIN
v2.0/bin/DEBUG.COM Normal file

Binary file not shown.

802
v2.0/bin/DEVDRIV.DOC Normal file
View File

@ -0,0 +1,802 @@
MS-DOS 2.0 Device Drivers
INTRODUCTION
In the past, DOS-device driver (BIOS for those who are
familiar with CP/M) communication has been mediated with
registers and a fixed-address jump-table. This approach
has suffered heavily from the following two observations:
o The old jump-table ideas of the past are fixed in
scope and allow no extensibility.
o The past device driver interfaces have been written
without regard for the true power of the hardware.
When a multitasking system or interrupt driven
hardware is installed a new BIOS must be written
largely from scratch.
In MSDOS 2.0, the DOS-device driver interface has changed
from the old jump-table style to one in which the device
drivers are linked together in a list. This allows new
drivers for optional hardware to be installed (and even
written) in the field by other vendors or the user himself.
This flexibility is one of the major new features of MS-DOS
2.0.
Each driver in the chain defines two entry points; the
strategy routine and the interrupt routine. The 2.0 DOS
does not really make use of two entry points (it simply calls
strategy, then immediately calls interrupt). This dual entry
point scheme is designed to facilitate future multi-tasking
versions of MS-DOS. In multi-tasking environments I/O must
be asynchronous, to accomplish this the strategy routine
will be called to queue (internally) a request and return
quickly. It is then the responsibility of the interrupt
routine to perform the actual I/O at interrupt time by picking
requests off the internal queue (set up by the strategy
routine), and process them. When a request is complete,
it is flagged as "done" by the interrupt routine. The DOS
periodically scans the list of requests looking for ones
flagged as done, and "wakes up" the process waiting for the
completion of the request.
In order for requests to be queued as above it is no
longer sufficient to pass I/O information in registers, since
many requests may be pending at any one time. Therefore
the new device interface uses data "packets" to pass request
information. A device is called with a pointer to a packet,
this packet is linked into a global chain of all pending
I/O requests maintained by the DOS. The device then links
the packet into its own local chain of requests for this
particular device. The device interrupt routine picks
requests of the local chain for processing. The DOS scans
the global chain looking for completed requests. These
packets are composed of two pieces, a static piece which
has the same format for all requests (called the static
request header), which is followed by information specific
to the request. Thus packets have a variable size and format.
At this points it should be emphasized that MS-DOS 2.0
does not implement most of these features, as future versions
will. There is no global or local queue. Only one request
is pending at any one time, and the DOS waits for this current
request to be completed. For 2.0 it is sufficient for the
strategy routine to simply store the address of the packet
at a fixed location, and for the interrupt routine to then
process this packet by doing the request and returning.
Remember: the DOS just calls the strategy routine and then
immediately calls the interrupt routine, it is assumed that
the request is completed when the interrupt routine returns.
This additional functionality is defined at this time so
that people will be aware and thinking about the future.
FORMAT OF A DEVICE DRIVER
A device driver is simply a relocatable memory image
with all of the code in it to implement the device (like
a .COM file, but not ORGed at 100 Hex). In addition it has
a special header at the front of it which identifies it as
a device, defines the strategy and interrupt entry points,
and defines various attributes. It should also be noted
that there are two basic types of devices.
The first is character devices. These are devices which
are designed to do character I/O in a serial manner like
CON, AUX, and PRN. These devices are named (ie. CON, AUX,
CLOCK, etc.), and users may open channels (FCBs) to do I/O
to them.
The second class of devices is block devices. These
devices are the "disk drives" on the system, they can do
random I/O in pieces called blocks (usually the physical
sector size) and hence the name. These devices are not
"named" as the character devices are, and therefore cannot
be "opened" directly. Instead they are "mapped" via the
drive letters (A,B,C, etc.).
Block devices also have units. In other words a single
driver may be responsible for one or more disk drives. For
instance block device driver ALPHA (please note that we cannot
actually refer to block devices by a name!) may be
responsible for drives A,B,C and D, this simply means that
it has four units (0-3) defined and therefore takes up four
drive letters. Which units correspond to which drive letters
is determined by the position of the driver in the chain
of all drivers: if driver ALPHA is the first block driver
in the device chain, and it defines 4 units (0-3), then they
will be A,B,C and D. If BETA is the second block driver
and defines three units (0-2), then they will be E,F and
G and so on. MS-DOS 2.0 is not limited to 16 block device
units, as previous versions were. The theoretical limit
is 63 (2^6 - 1), but it should be noted that after 26 the
drive letters get a little strange (like ] \ and ^). NOTE:
Character devices cannot define multiple units (this because
they have only one name).
Here is what that special device header looks like:
+--------------------------------------+
| DWORD Pointer to next device |
| (Must be set to -1) |
+--------------------------------------+
| WORD Attributes |
| Bit 15 = 1 if char device 0 if blk |
| if bit 15 is 1 |
| Bit 0 = 1 if Current sti device |
| Bit 1 = 1 if Current sto output |
| Bit 2 = 1 if Current NUL device |
| Bit 3 = 1 if Current CLOCK dev |
| Bit 4 = 1 if SPECIAL |
| Bit 14 is the IOCTL bit (see below) |
| Bit 13 is the NON IBM FORMAT bit |
+--------------------------------------+
| WORD Pointer to Device strategy |
| entry point |
+--------------------------------------+
| WORD Pointer to Device interrupt |
| entry point |
+--------------------------------------+
| 8-BYTE character device name field |
| Character devices set a device name |
| For block devices the first byte is |
| The number of units |
+--------------------------------------+
Note that the device entry points are words. They must
be offsets from the same segment number used to point to
this table. Ie. if XXX.YYY points to the start of this
table, then XXX.strategy and XXX.interrupt are the entry
points.
A word about the Attribute field. This field is used
most importantly to tell the system whether this device is
a block or character device (bit 15). Most of other bits
are used to give selected character devices certain special
treatment (NOTE: these bits mean nothing on a block device).
Let's say a user has a new device driver which he wants to
be the standard input and output. Besides just installing
the driver he needs to tell SYSINIT (and the DOS) that he
wishes his new driver to override the current sti and sto
(the "CON" device). This is accomplished by setting the
attributes to the desired characteristics, so he would set
Bits 0 and 1 to 1 (note that they are separate!!). Similarly
a new CLOCK device could be installed by setting that
attribute, see the section at the end on the CLOCK device.
NOTE: that although there is a NUL device attribute, the
NUL device cannot be re-assigned. This attribute exists
for the DOS so that it can tell if the NUL device is being
used.
The NON IBM FORMAT bit applies only to block devices
and effects the operation of the get BPB device call (see
below).
The other bit of interest is the IOCTL bit which has
meaning on character or block devices. This bit tells the
DOS whether this device can handle control strings (via the
IOCTL system call).
If a driver cannot process control strings, it should
initially set this bit to 0. This tells the DOS to return
an error if an attempt is made (via IOCTL system call) to
send or receive control strings to this device. A device
which can process control strings should initialize it to
1. For drivers of this type, the DOS will make calls to
the IOCTL INPUT and OUTPUT device functions to send and
receive IOCTL strings (see IOCTL in the SYSTEM-CALLS
document).
The IOCTL functions allow data to be sent and received
by the device itself for its own use (to set baud rate, stop
bits, form length etc., etc.), instead of passing data over
the device channel as a normal read or write does. The
interpretation of the passed information is up to the device,
but it MUST NOT simply be treated as a normal I/O.
The SPECIAL bit applies only to character drivers and
more particularly to CON drivers. The new 2.0 interface
is a much more general and consistent interface than the
old 1.25 DOS interface. It allows for a number of additional
features of 2.0. It is also slower than 1.25 if old style
"single byte" system calls are made. To make most efficient
use of the interface all applications should block their
I/O as much as possible. This means make one XENIX style
system call to output X bytes rather than X system calls
to output one byte each. Also putting a device channel in
RAW mode (see IOCTL) provides a means of putting out
characters even FASTER than 1.25. To help alleviate the
CON output speed problem for older programs which use the
1 - 12 system calls to output large amounts of data the
SPECIAL bit has been implemented. If this bit is 1 it means
the device is the CON output device, and has implemented
an interrupt 29 Hex handler, where the 29 Hex handler is
defined as follows:
Interrupt 29h handlers
Input:
Character in AL
Function:
output the character in al to the user
screen.
Output:
None
Registers:
all registers except bx must be preserved.
No registers except for al have a known or
consistent value.
If a character device implements the SPECIAL bit, it
is the responsibility of the driver to install an address
at the correct location in the interrupt table for interrupt
29 Hex as part of its INIT code. IMPLICATION: There can
be only one device driver with the SPECIAL bit set in the
system. There is no check to insure this state.
WARNING: THIS FEATURE WILL NOT BE SUPPORTED IN FUTURE VERSIONS
OF THE OPERATING SYSTEM. IMPLICATION: Any application
(not device driver) which uses INT 29H directly will
not work on future versions, YOU HAVE BEEN WARNED.
In order to "make" a device driver that SYSINIT can
install, a memory image or .EXE (non-IBM only) format file
must be created with the above header at the start. The
link field should be initialized to -1 (SYSINIT fills it
in). The attribute field and entry points must be set
correctly, and if the device is a character device, the name
field must be filled in with the name (if a block device
SYSINIT will fill in the correct unit count). This name
can be any 8 character "legal" file name. In fact SYSINIT
always installs character devices at the start of the device
list, so if you want to install a new CON device all you
have to do is name it "CON". The new one is ahead of the
old one in the list and thus preempts the old one as the
search for devices stops on the first match. Be sure to
set the sti and sto bits on a new CON device!
NOTE: Since SYSINIT may install the driver anywhere, you
must be very careful about FAR memory references. You
should NOT expect that your driver will go in the same
place every time (The default BIOS drivers are exempted
from this of course).
INSTALLATION OF DEVICE DRIVERS
Unlike past versions MS-DOS 2.0 allows new device drivers
to be installed dynamically at boot time. This is
accomplished by the new SYSINIT module supplied by Microsoft,
which reads and processes the CONFIG.SYS file. This module
is linked together with the OEM default BIOS in a similar
manner to the way FORMAT is built.
One of the functions defined for each device is INIT.
This routine is called once when the device is installed,
and never again. The only thing returned by the init routine
is a location (DS:DX) which is a pointer to the first free
byte of memory after the device driver, (like a terminate
and stay resident). This pointer method can be used to "throw
away" initialization code that is only needed once, saving
on space.
Block devices are installed the same way and also return
a first free byte pointer as above, additional information
is also returned:
o The number of units is returned, this determines
logical device names. If the current maximum logical
device letter is F at the time of the install call,
and the init routine returns 4 as the number of units,
then they will have logical names G, H, I and J.
This mapping is determined by by the position of
the driver in the device list and the number of units
on the device (stored in the first byte of the device
name field).
o A pointer to a BPB (Bios Parameter Block) pointer
array is also returned. This will be similar to
the INIT table used in previous versions, but will
have more information in it. There is one table
for each unit defined. These blocks will be used
to build a DPB (Drive Parameter Block) for each of
the units. The pointer passed to the DOS from the
driver points to an array of n word pointers to BPBs
where n is the number of units defined. In this
way if all units are the same, all of the pointers
can point to the same BPB, saving space. NOTE: this
array must be protected (below the free pointer set
by the return) since the DPB will be built starting
at the byte pointed to by the free pointer. The
sector size defined must be less than or equal to
the maximum sector size defined at default BIOS init
time. If it isn't the install will fail. One new
piece of DPB info set from this table will be a "media
descriptor byte". This byte means nothing to the
DOS, but is passed to devices so that they know what
form of a DPB the DOS is currently using for a
particular Drive-Unit.
Block devices may take several approaches; they may be
dumb or smart. A dumb device would define a unit (and
therefore a DPB) for each possible media drive combination.
Unit 0 = drive 0 single side, unit 1 = drive 0 double side,
etc. For this approach media descriptor bytes would mean
nothing. A smart device would allow multiple media per unit,
in this case the BPB table returned at init must define space
large enough to accommodate the largest possible media
supported. Smart drivers will use the "media byte" to pass
around info about what media is currently in a unit. NOTE:
If the DPB is a "hybrid" made to get the right sizes, it
should give an invalid "media byte" back to the DOS.
The BOOT (default BIOS) drivers are installed pretty
much as above. The preset device list is scanned. If block
drivers are encountered they are installed as above (with
the exception that the break is not moved since the drivers
are already resident in the BIOS). Note that the logical
drive letters are assigned in list order, thus the driver
which is to have logical A must be the first unit of the
first block device in the list. The order of character
devices is also important. There must be at least 4 character
devices defined at boot which must be the first four devices
(of either type), the first will become standard input,
standard output, and standard error output. The second will
become standard auxiliary input and output, the third will
become standard list output, and the forth will become the
date/time (CLOCK) device. Thus the BIOS device list must
look like this:
->CON->AUX->PRN->CLOCK->any other block or character devices
THE DRIVER
A device driver will define the following functions:
Command Function
Code
0 INIT
1 MEDIA CHECK (Block only, NOP for character)
2 BUILD BPB " " " " "
3 IOCTL INPUT (Only called if device has IOCTL)
4 INPUT (read)
5 NON-DESTRUCTIVE INPUT NO WAIT (Char devs only)
6 INPUT STATUS " " "
7 INPUT FLUSH " " "
8 OUTPUT (write)
9 OUTPUT (Write) with verify
10 OUTPUT STATUS " " "
11 OUTPUT FLUSH " " "
12 IOCTL OUTPUT (Only called if device has IOCTL)
As mentioned before, the first entry point is the strategy
routine which is called with a pointer to a data block. This
call does not perform the request, all it does is queue it
(save the data block pointer). The second interrupt entry
point is called immediately after the strategy call. The
"interrupt" routine is called with no parameters, its primary
function is to perform the operation based on the queued
data block and set up any returns.
The "BUILD BPB" and "MEDIA CHECK" are the interesting
new ones, these are explained by examining the sequence of
events in the DOS which occurs when a drive access call (other
than read or write) is made:
I. Turn drive letter into DPB pointer by looking
for DPB with correct driver-unit number.
II. Call device driver and request media check for
Drive-Unit. DOS passes its current Media
descriptor byte (from DPB). Call returns:
Media Not Changed
Media Changed
Not Sure
Error
Error - If an error occurs the error code should
be set accordingly.
Media Not changed - Current DPB and media byte
are OK, done.
Media Changed - Current DPB and media are wrong,
invalidate any buffers for this unit, and
goto III.
Not Sure - If there are dirty buffers for this
unit, assume DPB and media byte are OK and
done. If nothing dirty, assume media changed,
invalidate any buffers for unit, and goto
III.
NOTE: If a hybrid DPB was built at init and
an invalid Media byte was set, the driver
should return media changed when this invalid
media byte is encountered.
III. Call device driver to build BPB with media byte
and buffer.
What the driver must do at step III is determine the
correct media that is currently in the unit, and return a
pointer to a BPB table (same as for the install call). This
table will be used as at init to build a correct DPB for
the unit If the determined media descriptor byte in the table
turns out to be the same as the one passed in, then the DOS
will not build a new table, but rather just use the old one.
Therefore in this case the driver doesn't have to correctly
fill in the other entries if desired.
The build BPB call also gets a pointer to a one sector
buffer. What this buffer contains is determined by the NON
IBM FORMAT bit in the attribute field. If the bit is zero
(device is IBM format compatible) then the buffer contains
the first sector of the first FAT, in particular the FAT
ID byte is the first byte of this buffer. NOTE: It must
be true that the BPB is the same, as far as location of the
FAT is concerned, for all possible media. This is because
this first FAT sector must be read BEFORE the actual BPB
is returned. If the NON IBM FORMAT bit is set then the
pointer points to one sector of scratch space which may be
used for anything.
CALL FORMAT
When the DOS calls a device driver to perform a finction,
it passes a structure (Drive Request Structure) in ES:BX
to perform operations and does a long call to the driver's
strategy entry point. This structure is a fixed length header
(Static Request Header) followed by data pertinent to the
operation being performed. NOTE: It is the drivers
responsibility to preserve machine state.
STATIC REQUEST HEADER ->
+-----------------------------+
| BYTE length of record |
| Length in bytes of this |
| Drive Request Structure |
+-----------------------------+
| BYTE unit code |
| The subunit the operation |
| is for (minor device) |
| (no meaning on character |
| devices) |
+-----------------------------+
| BYTE command code |
+-----------------------------+
| WORD Status |
+-----------------------------+
| 8 bytes reserved here for |
| two DWORD links. One will |
| be a link for the DOS queue |
| The other for the device |
| queue |
+-----------------------------+
STATUS WORD
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+---+---+--+--+--+--+---+---+--+--+--+--+--+--+--+--+
| E | | B | D | |
| R | RESERVED | U | O | ERROR CODE (bit 15 on)|
| R | | I | N | |
+---+---+--+--+--+--+---+---+--+--+--+--+--+--+--+--+
The status word is zero on entry and is set by the driver
interrupt routine on return.
Bit 8 is the done bit, it means the operation is complete.
For the moment the Driver just sets it to one when it exits,
in the future this will be set by the interrupt routine to
tell the DOS the operation is complete.
Bit 15 is the error bit, if it is set then the low 8
bits indicate the error:
0 Write Protect violation
(NEW) 1 Unknown Unit
2 Drive not ready
(NEW) 3 Unknown command
4 CRC error
(NEW) 5 Bad Drive Request Structure length
6 Seek error
(NEW) 7 Unknown media
8 Sector not found
(NEW) 9 Printer out of paper
A Write Fault
(NEW) B Read Fault
C General Failure
Bit 9 is the busy bit which is set only by status calls (see
STATUS CALL below).
Here is the data block format for each function:
READ or WRITE - ES:BX (Including IOCTL) ->
+------------------------------------+
| 13-BYTE Static Request Header |
+------------------------------------+
| BYTE Media descriptor from DPB |
+------------------------------------+
| DWORD transfer address |
+------------------------------------+
| WORD byte/sector Count |
---+------------------------------------+---
| WORD starting sector number |
| (ignored on Char Devs) |
+------------------------------------+
In addition to setting the status word, the driver must
set the Sector count to the actual number of sectors (or
bytes) transferred. NOTE: No error check is performed on
an IOCTL I/O call, driver MUST correctly set the return sector
(byte) count to the actual number of bytes transferred,
however.
NOTE: THE FOLLOWING APPLIES TO BLOCK DEVICE DRIVERS.
Under certain circumstances the BIOS may be asked to
do a write operation of 64K bytes which seems to be a "wrap
around" of the transfer address in the BIOS I/O packet. This
arises due to an optimization added to the write code in
MS-DOS. It will only manifest on user WRITEs which are within
a sector size of 64K bytes on files which are "growing" past
the current EOF. IT IS ALLOWABLE FOR THE BIOS TO IGNORE
THE BALANCE OF THE WRITE WHICH "WRAPS AROUND" IF IT SO
CHOOSES. For instance a WRITE of 10000H bytes worth of
sectors with a transfer address of XXX:1 could ignore the
last two bytes (remember that a user program can never request
an I/O of more than FFFFH bytes and cannot wrap around (even
to 0) in his transfer segment, so in this case the last two
bytes can be ignored).
NON DESRUCTIVE READ NO WAIT - ES:BX ->
+------------------------------------+
| 13-BYTE Static Request Header |
+------------------------------------+
| BYTE read from device |
+------------------------------------+
This call is analogous to the console input status call
on MS-DOS 1.25. If the character device returns Busy bit
= 0 (characters in buffer), then the next character that
would be read is returned. This character is NOT removed
from the input buffer (hence the term Non Destructive Read).
In essence this call allows the DOS to look ahead one input
character.
MEDIA CHECK - ES:BX ->
+------------------------------------+
| 13-BYTE Static Request Header |
+------------------------------------+
| BYTE Media Descriptor from DPB |
+------------------------------------+
| BYTE returned |
+------------------------------------+
In addition to setting status word, driver must set the
return byte.
Return Byte :
-1 Media has been changed
0 Don't know if media has been changed
1 Media has not been changed
If the driver can return -1 or 1 (by having a door-lock
or other interlock mechanism) the performance of MSDOS 2.0
is enhanced as the DOS need not reread the FAT for each
directory access.
BUILD BPB - ES:BX ->
+------------------------------------+
| 13-BYTE Static Request Header |
+------------------------------------+
| BYTE Media Descriptor from DPB |
+------------------------------------+
| DWORD Transfer Address |
| (points to one sectors worth of |
| scratch space or first sector |
| of FAT depending on the value |
| of the NON IBM FORMAT bit) |
+------------------------------------+
| DWORD Pointer to BPB |
+------------------------------------+
If the NON IBM FORMAT bit of the device is set, then
the DWORD Transfer Address points to a one sector buffer
which can be used for any purpose. If the NON IBM FORMAT
bit is 0, then this buffer contains the first sector of the
FAT; in this case the driver must not alter this buffer (this
mode is useful if all that is desired is to read the FAT
ID byte).
If IBM compatible format is used (NON IBM FORMAT BIT
= 0), then it must be true that the first sector of the first
FAT is located at the same sector on all possible media.
This is because the FAT sector will be read BEFORE the media
is actually determined.
In addition to setting status word, driver must set the
Pointer to the BPB on return.
In order to allow for many different OEMs to read each
other's disks, the following standard is suggested: The
information relating to the BPB for a particular piece of
media is kept in the boot sector for the media. In
particular, the format of the boot sector is:
+------------------------------------+
| 3 BYTE near JUMP to boot code |
+------------------------------------+
| 8 BYTES OEM name and version |
---+------------------------------------+---
B | WORD bytes per sector |
P +------------------------------------+
B | BYTE sectors per allocation unit |
+------------------------------------+
| | WORD reserved sectors |
V +------------------------------------+
| BYTE number of FATs |
+------------------------------------+
| WORD number of root dir entries |
+------------------------------------+
| WORD number of sectors in logical |
^ | image |
| +------------------------------------+
B | BYTE media descriptor |
P +------------------------------------+
B | WORD number of FAT sectors |
---+------------------------------------+---
| WORD sectors per track |
+------------------------------------+
| WORD number of heads |
+------------------------------------+
| WORD number of hidden sectors |
+------------------------------------+
The three words at the end are optional, the DOS doesn't
care about them (since they are not part of the BPB). They
are intended to help the BIOS understand the media. Sectors
per track may be redundant (could be figured out from total
size of the disk). Number of heads is useful for supporting
different multi-head drives which have the same storage
capacity, but a different number of surfaces. Number of
hidden sectors is useful for supporting drive partitioning
schemes.
Currently, the media descriptor byte has been defined
for a small range of media:
5 1/4" diskettes:
Flag bits:
01h - on -> 2 double sided
All other bits must be on.
8" disks:
FEh - IBM 3740 format, singled-sided, single-density,
128 bytes per sector, soft sectored, 4 sectors
per allocation unit, 1 reserved sector, 2 FATs,
68 directory entries, 77*26 sectors
FDh - 8" IBM 3740 format, singled-sided,
single-density, 128 bytes per sector, soft
sectored, 4 sectors per allocation unit, 4
reserved sectors, 2 FATs, 68 directory entries,
77*26 sectors
FEh - 8" Double-sided, double-density, 1024 bytes
per sector, soft sectored, 1 sector per allocation
unit, 1 reserved sector, 2 FATs, 192 directory
entries, 77*8*2 sectors
STATUS Calls - ES:BX ->
+------------------------------------+
| 13-BYTE Static Request Header |
+------------------------------------+
All driver must do is set status word accordingly and
set the busy bit as follows:
o For output on character devices: If it is 1 on
return, a write request (if made) would wait for
completion of a current request. If it is 0, there
is no current request and a write request (if made)
would start immediately.
o For input on character devices with a buffer a return
of 1 means, a read request (if made) would go to
the physical device. If it is 0 on return, then
there are characters in the devices buffer and a
read would return quickly, it also indicates that
the user has typed something. The DOS assumes all
character devices have an input type ahead buffer.
Devices which don't have them should always return
busy = 0 so that the DOS won't hang waiting for
something to get into a buffer which doesn't exist.
FLUSH Calls - ES:BX ->
+------------------------------------+
| 13-BYTE Static Request Header |
+------------------------------------+
This call tells the driver to flush (terminate) all
pending requests that it has knowledge of. Its primary use
is to flush the input queue on character devices.
INIT - ES:BX ->
+------------------------------------+
| 13-BYTE Static Request Header |
+------------------------------------+
| BYTE # of units |
+------------------------------------+
| DWORD Break Address |
---+------------------------------------+---
| DWORD Pointer to BPB array |
| (not set by Character devices) |
+------------------------------------+
The number of units, break address, and BPB pointer are
set by the driver.
FORMAT OF BPB (Bios Parameter Block) -
+------------------------------------+
| WORD Sector size in Bytes |
| Must be at least 32 |
+------------------------------------+
| BYTE Sectors/Allocation unit |
| Must be a power of 2 |
+------------------------------------+
| WORD Number of reserved sectors |
| May be zero |
+------------------------------------+
| BYTE Number of FATS |
+------------------------------------+
| WORD Number of directory entries |
+------------------------------------+
| WORD Total number of sectors |
+------------------------------------+
| BYTE Media descriptor |
+------------------------------------+
| WORD Number of sectors occupied by |
| FAT |
+------------------------------------+
THE CLOCK DEVICE
One of the most popular add on boards seems to be "Real
Time CLOCK Boards". To allow these boards to be integrated
into the system for TIME and DATE, there is a special device
(determined by the attribute word) which is the CLOCK device.
In all respects this device defines and performs functions
like any other character device (most functions will be "set
done bit, reset error bit, return). When a read or write
to this device occurs, exactly 6 bytes are transferred. This
I/O can be thought of as transferring 3 words which correspond
exactly to the values of AX, CX and DX which were used in
the old 1.25 DOS date and time routines. Thus the first
two bytes are a word which is the count of days since 1-1-80.
The third byte is minutes, the fourth hours, the fifth
hundredths of seconds, and the sixth seconds. Reading the
CLOCK device gets the date and time, writing to it sets the
date and time.

BIN
v2.0/bin/DISKCOPY.COM Normal file

Binary file not shown.

62
v2.0/bin/DOSPATCH.TXT Normal file
View File

@ -0,0 +1,62 @@
There are three locations in the DOS where OEMs may want to
patch in information specific to their installation.
The first is the location of the default switch character.
This character is one byte at DEBUG location 1E5, and is
set to '/'. To change it to '-' (XENIX compatible)
do:
DEBUG MSDOS.SYS
>e1e5
XXXX:01E5 2F. <at this point give the desired
new switch character in HEX and
hit return>
>w
Writing YYYY Bytes
>q
If the byte at 1E5 is not 2F, look around in the immediate
vacinity (do d1e0) for it. It is the only 2F in that area.
The second is the location of the 24 bit user number and the
8 bit OEM number. These values are returned by the GET_VERSION
system call.
The user number is 3 bytes starting at
debug location 683, The OEM number is one byte at debug location
686. The user number is initialized to 0, the OEM number to -1
and they immediatly follow the Microsoft Copyright message. If these
bytes are not zero, look for the four bytes following the
Copyright message which should be in the vacinity of 683.
OEMs should request an OEM number from Microsoft if they
want one of their very own, this prevents selecting one someone
else already has.
The third is the location of the editing template definitions.
This is a table which defines the two byte edit function keys
for system call 10 and for EDLIN. This table is at debug location
33EA, and should start with a 1B. If the byte at 33EA is not
1B, look around in the immediate vacinity. Here is what the
default table looks like. It is a definition for the Zenith
Z-19 terminal:
ESCCHAR DB 1BH ;The Escape character, Nul (0) on IBM
ESCTAB:
DB "Z" ;5AH Put a ^Z in the template, F6 on IBM
DB "S" ;53H Copy one char, --> on IBM
DB "V" ;56H Skip one char, DEL on IBM
DB "T" ;54H Copy to char, F2 on IBM
DB "W" ;57H Skip to char, F4 on IBM
DB "U" ;55H Copy line, F3 on IBM
DB "E" ;45H Kill line, Not used on IBM
DB "J" ;4AH Reedit line, F5 on IBM
DB "D" ;44H Backspace, <-- on IBM
DB "P" ;50H Toggle insert mode, INS on IBM
DB "Q" ;51H Toggle insert mode, INS on IBM
DB "R" ;52H Escape char, F7 on IBM
DB "R" ;52H End of table, must be same as previos character


BIN
v2.0/bin/EDLIN.COM Normal file

Binary file not shown.

BIN
v2.0/bin/EXE2BIN.EXE Normal file

Binary file not shown.

BIN
v2.0/bin/FC.EXE Normal file

Binary file not shown.

BIN
v2.0/bin/FILBP.PAS Normal file

Binary file not shown.

BIN
v2.0/bin/FIND.EXE Normal file

Binary file not shown.

393
v2.0/bin/FORMAT.DOC Normal file
View File

@ -0,0 +1,393 @@
FORMAT - formats a new disk, clears the FAT and DIRECTORY
and optionally copies the SYSTEM and COMMAND.COM to this
new disk.
Command syntax:
FORMAT [drive:][/switch1][/switch2]...[/switch16]
Where "drive:" is a legal drive specification and if
omitted indicates that the default drive will be used.
There may be up to 16 legal switches included in the
command line.
The OEM must supply five (NEAR) routines to the program
along with 6 data items. The names of the routines are INIT,
DISKFORMAT, BADSECTOR, WRTFAT and DONE, and their flow of
control (by the Microsoft module) is like this:
|
+---------+
| INIT |
+---------+
|
|<------------------------------+
+------------+ |
| DISKFORMAT | |
+------------+ |
|<-------+ |
+-----------+ |-This loop is done |- This loop done
| BADSECTOR | | for each group of | once for each disk
+-----------+ | bad sectors | to be formatted.
|----->--+ | If variable HARDFLAG
| | is set then the loop
+----------+ | is only performed
| | | once.
| WRTFAT | |
+----------+ |
| |
+------+ |
| DONE | |
+------+ |
+---->--------------------------+
The INIT, DISKFORMAT, and BADSECTOR routines are free
to use any MS-DOS system calls, except for calls that cause
disk accesses on the disk being formatted. DONE may use
ANY calls, since by the time it is called the new disk has
been formatted.
The following data must be declared PUBLIC in a module
provided by the OEM:
SWITCHLIST - A string of bytes. The first byte is count
N, followed by N characters which are the switches to
be accepted by the command line scanner. Alphabetic
characters must be in upper case (the numeric
characters 0-9 are allowed). The last three switches,
normally "O", "V" and "S", have pre-defined meanings.
The "S" switch is the switch which causes the
system files IO.SYS, MSDOS.SYS, and COMMAND.COM to be
transfered to the disk after it is formatted thus
making a "S"ystem disk. The switch can be some letter
other than "S", but the last switch in the list is
assumed to have the meaning "transfer system",
regardles of what the particular letter is.
The second to the last switch, "V", causes FORMAT
to prompt the user for a volume label after the disk
is formatted. Again, as with "S", the particular
letter is not important but rather the position in the
list.
The third to the last switch, "O", causes FORMAT to
produce an IBM Personal Computer DOS version 1.X
compatible disk. Normally FORMAT causes a 0 byte to
be placed in the first byte of each directory entry
instead of the 0E5 Hex free entry designator. This
results in a very marked directory search performance
increase due to an optimization in the DOS. Disks
made this way cause trouble on IBM PC DOS 1.X
versions, however, which did not have this
optimization. The 0 byte fools IBM 1.X versions into
thinking these entries are allocated instead of free,
NOTE that IBM Personnal Computer DOS version 2.00 and
MS-DOS version 1.25 will have no trouble with these
disks, since they have the same optimization. The "O"
switch causes FORMAT to re-do the directory with a 0E5
Hex byte at the start of each entry so that the disk
may be used with 1.X versions of IBM PC DOS, as well
as MS-DOS 1.25/2.00 and IBM PC DOS 2.00. This switch
should only be given when needed because it takes a
fair amount of time for FORMAT to perform the
conversion, and it noticably decreases 1.25 and 2.00
performance on disks with few directory entries.
Up to 16 switches are permitted. Normally a "C"
switch is specified for "Clear". This switch should
cause the formatting operation to be bypassed (within
DISKFORMAT or BADSECTOR). This is provided as a
time-saving convenience to the user, who may wish
to "start fresh" on a previosly formatted and used
disk.
HARDFLAG - BYTE location which specifies whether the
OEM routine is formatting a fixed disk or a a drive
with removable media. A zero indicates removable
media, any other value indicates a fixed disk. The
status of this byte only effect the messages printed
by the main format module. This value should be
set or reset by the OEM supplied INIT routine.
FATID - BYTE location containing the value to be used
in the first byte of the FAT. Must be in the range
F8 hex to FF hex.
STARTSECTOR - WORD location containing the sector number
of the first sector of the data area.
FATSPACE - WORD location containing the address of the
start of the FAT area. A FAT built in this area
will be written to disk using the OEM supplied WRTFAT
subroutine. 6k is sufficient to store any FAT. This
area must not overlap the FREESPACE area.
FREESPACE - WORD location which contains the address
of the start of free memory space. This is where
the system will be loaded, by the Microsoft module,
for transferring to the newly formatted disk. Memory
should be available from this address to the end
of memory, so it is typically the address of the
end of the OEM module.
The following routines must be declared PUBLIC in the
OEM-supplied module:
INIT - An initialization routine. This routine is called
once at the start of the FORMAT run after the switches
have been processed. This routine should perform
any functions that only need to be done once per
FORMAT run. An example of what this routine might
do is read the boot sector into a buffer so that
it can be transferred to the new disks by DISKFORMAT.
If this routine returns with the CARRY flag set it
indicates an error, and FORMAT will print "Format
failure" and quit. This feature can be used to detect
conflicting switches (like specifying both single
and double density) and cause FORMAT to quit without
doing anything.
DISKFORMAT - Formats the disk according to the options
indicated by the switches and the value of FATID
must be defined when it returns (although INIT may
have already done it). This routine is called once
for EACH disk to be formatted. If neccessary it
must transfer the Bootstrap loader. If any error
conditions are detected, set the CARRY flag and return
to FORMAT. FORMAT will report a 'Format failure'
and prompt for another disk. (If you only require
a clear directory and FAT then simply setting the
appropriate FATID, if not done by INIT, will be all
that DISKFORMAT must do.)
BADSECTOR - Reports the sector number of any bad sectors
that may have been found during the formatting of
the disk. This routine is called at least once for
EACH disk to be formatted, and is called repeatedly
until AX is zero or the carry flag is set. The carry
flag is used just as in DISKFORMAT to indicate an
error, and FORMAT handles it in the same way. The
first sector in the data area must be in STARTSECTOR
for the returns from this routine to be interpreted
correctly. If there are bad sectors, BADSECTOR must
return a sector number in in register BX, the number
of consecutive bad sectors in register AX, and carry
clear. FORMAT will then process the bad sectors
and call BADSECTOR again. When BADSECTOR returns
with AX = 0 this means there are no more bad sectors;
FORMAT clears the directory and goes on to DONE,
so for this last return BX need not contain anything
meaningful.
FORMAT processes bad sectors by determining their
corresponding allocation unit and marking that unit
with an FF7 hex in the File Allocation Table. CHKDSK
understands the FF7 mark as a flag for bad sectors
and accordingly reports the number of bytes marked
in this way.
NOTE: Actual formatting of the disk can be done in
BADSECTOR instead of DISKFORMAT on a "report as you
go" basis. Formatting goes until a group of bad
sectors is encountered, BADSECTOR then reports them
by returning with AX and BX set. FORMAT will then
call BADSECTOR again and formatting can continue.
WRTFAT - This routine is called after the disk is
formatted and bad sectors have been reported. Its
purpose is to write all copies of the FAT from the
area of memory referenced by FATSPACE to the drive
just formatted. It may be possible to use INT 26H
to perform the write, or a direct BIOS call. Whether
this is possible depends on whether the FAT ID byte
is used by the BIOS to determine the media in the
drive. If it is, these methods will probably fail
because there is no FAT ID byte on the disk yet (in
this case WRTFATs primary job is to get the FAT ID
byte out on the disk and thus solve the chicken and
egg problem).
DONE - This routine is called after the formatting is
complete, the disk directory has been initialized,
and the system has been transferred. It is called
once for EACH disk to be formatted. This gives the
chance for any finishing-up operations, if needed.
If the OEM desires certain extra files to be put
on the diskette by default, or according to a switch,
this could be done in DONE. Again, as in BADSECTOR
and DISKFORMAT, carry flag set on return means an
error has occurred: 'Format failure' will be printed
and FORMAT will prompt for another disk.
The following data is declared PUBLIC in Microsoft's FORMAT
module:
SWITCHMAP - A word with a bit vector indicating what
switches have been included in the command line. The
correspondence of the bits to the switches is
determined by SWITCHLIST. The right-most
(highest-addressed) switch in SWITCHLIST (which must
be the system transfer switch, normally "S")
corresponds to bit 0, the second from the right,
normally "V" to bit 1, etc. For example, if
SWITCHLIST is the string "7,'AGI2OVS'", and the user
specifies "/G/S" on the command line, then bit 6 will
be 0 (A not specified), bit 5 will be 1 (G specified),
bits 4,3,2 and 1 will be 0 (neither I,2,O or V
specified), and bit 0 will be 1 (S specified).
Bits 0,1 and 2 are the only switches used in
Microsoft's FORMAT module. These switches are used 1)
after INIT has been called, to determine if it is
necessary to load the system; 2) after the last
BADSECTOR call, to determine if the system is to be
written, E5 directory conversion is to be done, and/or
a volume label is to be asked for. INIT may force
these bits set or reset if desired (for example, some
drives may never be used as system disk, such as hard
disks). After INIT, the "S" bit may be turned off
(but not on, since the system was never read) if
something happens that means the system should not be
transferred.
After INIT, a second copy of SWITCHMAP is made
internally which is used to restore SWITCHMAP for
each disk to be formatted. FORMAT itself will turn
off the system bit if bad sectors are reported in
the system area; DISKFORMAT and BADSECTOR are also
allowed to change the map. However, these changes
affect only the current disk being formatted, since
SWITCHMAP is restored after each disk. (Changes
made to SWITCHMAP by INIT do affect ALL disks.)
DRIVE - A byte containing the drive specified in the
command line. 0=A, 1=B, etc.
Once the OEM-supplied module has been prepared, it must linked
with Microsoft's FORMAT.OBJ module and the FORMES.OBJ module.
If the OEM-supplied module is called OEMFOR.OBJ, then the
following linker command will do:
LINK FORMAT FORMES OEMFOR;
This command will produce a file called FORMAT.EXE. FORMAT
has been designed to run under MS-DOS as a simple binary
.COM file. This conversion is performed by LOCATE (EXE2BIN)
with the command
LOCATE FORMAT.EXE FORMAT.COM
which will produce the file FORMAT.COM.
;*****************************************
;
; A Sample OEM module
;
;*****************************************
CODE SEGMENT BYTE PUBLIC 'CODE'
; This segment must be
; named CODE, it must be
; PUBLIC, and it's
; classname must be 'CODE'
ASSUME CS:CODE,DS:CODE,ES:CODE
; Must declare data and routines PUBLIC
PUBLIC FATID,STARTSECTOR,SWITCHLIST,FREESPACE
PUBLIC INIT,DISKFORMAT,BADSECTOR,DONE,WRTFAT
PUBLIC FATSPACE,HARDFLAG
; This data defined in Microsoft-supplied module
EXTRN SWITCHMAP:WORD,DRIVE:BYTE
INIT:
; Read the boot sector into memory
CALL READBOOT
...
; Set FATID to double sided if "D" switch specified
TEST SWITCHMAP,10H
JNZ SETDBLSIDE
...
RET
DISKFORMAT:
...
; Use the bit map in SWITCHMAP to determine
; what switches are set
TEST SWITCHMAP,8 ;Is there a "/C"?
JNZ CLEAR ; Yes -- clear operation
; requested jump around the
; format code
< format the disk >
CLEAR:
...
; Transfer the boot from memory to the new disk
CALL TRANSBOOT
...
RET
; Error return - set carry
ERRET:
STC
RET
BADSECTOR:
...
RET
WRTFAT:
...
WRTFATLOOP:
< Set up call to write out a fat to disk>
...
MOV BX,[FATSPACE]
< Write out one fat to disk>
JC ERRET
...
< Decrement fat counter >
JNZ WRTFATLOOP
CLC ;Good return
RET
DONE:
...
RET
; Default Single sided
FATID DB 0FEH
HARDFLAG DB 0
STARTSECTOR DW 9
SWITCHLIST DB 5,"DCOVS" ; "OVS" must be the last
; switches in the list
FATSPACE DW FATBUF
FREESPACE DW ENDBOOT
BOOT DB BOOTSIZE DUP(?) ; Buffer for the
; boot sector
FATBUF DB 6 * 1024 DUP(?) ; Fat buffer
ENDBOOT LABEL BYTE
CODE ENDS
END

BIN
v2.0/bin/FORMAT.OBJ Normal file

Binary file not shown.

BIN
v2.0/bin/FORMES.OBJ Normal file

Binary file not shown.

BIN
v2.0/bin/INCOMP.DOC Normal file

Binary file not shown.

BIN
v2.0/bin/INT24.DOC Normal file

Binary file not shown.

BIN
v2.0/bin/LINK.EXE Normal file

Binary file not shown.

BIN
v2.0/bin/MASM.EXE Normal file

Binary file not shown.

BIN
v2.0/bin/MORE.COM Normal file

Binary file not shown.

BIN
v2.0/bin/MSDOS.SYS Normal file

Binary file not shown.

BIN
v2.0/bin/PRINT.COM Normal file

Binary file not shown.

BIN
v2.0/bin/PROFIL.OBJ Normal file

Binary file not shown.

BIN
v2.0/bin/PROFILE.DOC Normal file

Binary file not shown.

BIN
v2.0/bin/PROHST.EXE Normal file

Binary file not shown.

403
v2.0/bin/PROHST.PAS Normal file
View File

@ -0,0 +1,403 @@
PROGRAM prohst(input,output);
{$debug- $line- $symtab+}
{**********************************************************************}
{* *}
{* prohst *}
{* *}
{* This program produces a histogram from the profile file produced *}
{* by the MS-DOS profile utility. It optionally reads the map file *}
{* generated when the program being profiled was linked, and writes *}
{* either the module address or, if available, the line number as *}
{* a prefix to the line of the graph which describes a particular *}
{* bucket. *}
{* *}
{* After using filbm (derived from the Pascal and Fortran front end *}
{* command scanner) to parse its parameters, prohst opens the map *}
{* file if specified, searches for the heading line, and then reads *}
{* the lines giving the names and positions of the modules. It builds *}
{* a linked list of module names and start addresses. *}
{* *}
{* It then reads the bucket file header and and bucket array elements *}
{* into a variable created on the heap. It simultaneously calculates *}
{* a normalization factor. It writes the profile listing header and *}
{* starts to write the profile lines. For each bucket, the address *}
{* is calculated. The first entry in the address/name linked list *}
{* is the lowest addressed module. This is initially the 'current' *}
{* module. The bucket address is compared with the current module *}
{* address. When it becomes the greater, the module name is written *}
{* to the listing and the next entry in the address/name list becomes *}
{* the current module. If line numbers are available, the bucket *}
{* address is also compared to the current line/address. This is *}
{* read and calculated directly from the file. Since there may be *}
{* more than one line per bucket, several entries may be read until *}
{* the addresses compare within the span of addresses encompassed by *}
{* a bucket (its 'width'). Note that the idiosyncracies of Pascal i/o *}
{* make it necessary to continually check for the end of the map file *}
{* and the complexity of this code is mainly due to an attempt to *}
{* make it reasonably resilient to changes in the format of the map *}
{* file. *}
{* *}
{**********************************************************************}
CONST
max_file = 32;
TYPE
filenam = LSTRING (max_file);
sets = SET OF 0..31;
address_pointer = ^address_record;
address_record = RECORD
next: address_pointer;
name: STRING (15);
address: WORD;
END;
VAR
i: INTEGER;
bucket: FILE OF WORD;
hist: TEXT;
map: TEXT;
first_address,
this_address: address_pointer;
current_base: WORD;
bucket_name,
hist_name,
map_name: filenam;
switches: sets;
line: LSTRING (100);
map_avail: BOOLEAN;
line_nos_avail: BOOLEAN;
norm: REAL;
per_cent: INTEGER;
real_bucket,
norm_bucket: REAL;
cum_per_cent,
real_per_cent: REAL;
bucket_num,
clock_grain,
bucket_size,
prog_low_pa,
prog_high_pa,
dos_pa,
hit_io,
hit_dos,
hit_high: WORD;
seg,
offset,
parcel: WORD;
address: WORD;
new_line_no,
line_no: WORD;
dummy : LSTRING (8);
name: LSTRING (20);
line_no_part: LSTRING (17);
start: LSTRING (6);
buckets: ^SUPER ARRAY [1 .. *] OF REAL;
this_bucket: WORD;
LABEL 1;
PROCEDURE filbm (VAR prffil, hstfil, mapfil: filenam;
VAR switches: sets); EXTERN;
FUNCTION realword (w: WORD): REAL;
BEGIN
IF ORD (w) < 0 THEN BEGIN
realword := FLOAT (maxint) + FLOAT (ORD (w - maxint));
END
ELSE BEGIN
realword := FLOAT (ORD(w));
END {IF};
END {realword};
PROCEDURE skip_spaces;
BEGIN
WHILE NOT eof(map) AND THEN map^ = ' ' DO BEGIN
get (map);
END {WHILE};
END {skip_spaces};
FUNCTION hex_char (ch: CHAR): WORD;
BEGIN
IF ch >= '0' AND THEN ch <= '9' THEN BEGIN
hex_char := WRD (ch) - WRD ('0');
END
ELSE IF ch >= 'A' AND THEN ch <= 'F' THEN BEGIN
hex_char := WRD (ch) - WRD ('A') + 10;
END
ELSE BEGIN
WRITELN ('Invalid hex character');
hex_char := 0;
END {IF};
END {hex_char};
FUNCTION read_hex (i :WORD): WORD;
VAR
hex_val: WORD;
BEGIN
skip_spaces;
hex_val := 0;
WHILE NOT eof (map) AND THEN i <> 0 DO BEGIN
hex_val := hex_val * 16 + hex_char (map^);
GET (map);
i := i - 1;
END {WHILE};
read_hex := hex_val;
END {read_hex};
FUNCTION read_h: WORD;
BEGIN
read_h := read_hex (4);
get (map);
get (map);
END;
FUNCTION read_word: WORD;
VAR
int_value: WORD;
BEGIN
int_value := 0;
IF NOT EOF (map) THEN BEGIN
READ (map, int_value);
END {IF};
read_word := int_value;
END {read_word};
FUNCTION map_digit: BOOLEAN;
BEGIN
map_digit := (map^ >= '0') OR (map^ <= '9');
END {map_digit};
BEGIN {prohst}
writeln (output, ' Profile Histogram Utility - Version 1.0');
writeln (output);
writeln (output, ' Copyright - Microsoft, 1983');
start := ' ';
filbm (bucket_name, hist_name, map_name, switches);
IF 31 IN switches THEN BEGIN
ABORT ('Map file must not be terminal', 0, 0);
END {IF};
IF NOT (28 IN switches) THEN BEGIN
ABORT ('No histogram file specified', 0, 0);
END {IF};
ASSIGN (bucket, bucket_name);
reset (bucket);
ASSIGN (hist, hist_name);
rewrite (hist);
map_avail := 29 IN switches;
line_nos_avail := FALSE;
IF map_avail THEN BEGIN
ASSIGN (map, map_name);
RESET (map);
WHILE NOT EOF (map) AND THEN start <> ' Start' DO BEGIN
READLN (map, start);
END {WHILE};
NEW (first_address);
this_address := NIL;
WHILE NOT EOF(map) DO BEGIN
READLN (map, line);
IF line.len < 6 OR ELSE line [2] < '0' OR ELSE
line [2] > '9' THEN BEGIN
BREAK;
END {IF};
IF this_address <> NIL THEN BEGIN
NEW (this_address^.next);
this_address := this_address^.next;
END
ELSE BEGIN
this_address := first_address;
END {IF};
this_address^.next := NIL;
this_address^.address := (hex_char (line [2]) * 4096) +
(hex_char (line [3]) * 256) +
(hex_char (line [4]) * 16) +
hex_char (line [5]);
FOR i := 1 TO 15 DO BEGIN
this_address^.name [i] := line [22 + i];
END {FOR};
END {WHILE};
WHILE NOT EOF (map) DO BEGIN
READLN (map, line_no_part);
IF line_no_part = 'Line numbers for ' THEN BEGIN
line_nos_avail := TRUE;
BREAK;
END {IF};
END {WHILE};
END {IF};
read (bucket, clock_grain, bucket_num, bucket_size,
prog_low_pa, prog_high_pa, dos_pa, hit_io, hit_dos, hit_high);
NEW (buckets,ORD (bucket_num));
norm := 0.0;
norm_bucket := 0.0;
FOR i := 1 TO ORD (bucket_num) DO BEGIN
read (bucket, this_bucket);
real_bucket := realword (this_bucket);
IF real_bucket > norm_bucket THEN BEGIN
norm_bucket := real_bucket;
END {IF};
norm := norm + real_bucket;
buckets^[i] := real_bucket;
END {FOR};
norm_bucket := 45.0/norm_bucket;
norm := 100.0/norm;
WRITELN (hist, 'Microsoft Profiler Output Listing');
WRITELN (hist);
WRITELN (hist, ORD (bucket_num):6, bucket_size:4,'-byte buckets.');
WRITELN (hist);
WRITELN (hist, 'Profile taken between ', prog_low_pa*16::16,
' and ', prog_high_pa*16::16, '.');
WRITELN (hist);
WRITELN (hist, 'DOS program address:', dos_pa::16);
WRITELN (hist);
WRITELN (hist, 'Number of hits in DOS: ', hit_dos:5,
' or ', realword (hit_dos) * norm:4:1, '%.');
WRITELN (hist, 'Number of hits in I/O: ', hit_io:5,
' or ', realword (hit_io) * norm:4:1, '%.');
WRITELN (hist, 'Number of hits high : ', hit_high:5,
' or ', realword (hit_high) * norm:4:1, '%.');
WRITELN (hist);
WRITELN (hist, ' Hits Addr. Line/ Cumul. % 0.0 ',
' ',
1.0/norm:1:1);
WRITELN (hist, ' Offset +----------------',
'----------------------------');
WRITELN (hist, name);
i := 0;
parcel := 0;
current_base := 0;
line_no := 0;
new_line_no := 0;
cum_per_cent := 0.0;
WHILE i < ORD (bucket_num) DO BEGIN
i := i + 1;
IF buckets^[i] < 0.9 THEN BEGIN
WRITELN (hist);
REPEAT
i := i + 1;
UNTIL (i = ORD (bucket_num)) OR ELSE buckets^[i] > 0.0;
END {IF};
address := bucket_size * (WRD (i) - 1);
WHILE map_avail AND THEN
address >= first_address^.address DO BEGIN
WRITELN (hist, ' ', first_address^.name);
current_base := first_address^.address;
first_address := first_address^.next;
END {WHILE};
WHILE line_nos_avail AND THEN NOT eof (map) AND THEN
address >= parcel DO BEGIN
skip_spaces;
WHILE (map^ < '0') OR (map^ > '9') DO BEGIN
IF EOF (map) THEN BEGIN
goto 1;
END {IF};
READLN (map);
skip_spaces;
END {WHILE};
line_no := new_line_no;
new_line_no := read_word;
seg := read_hex (4);
IF EOF (map) THEN BEGIN
GOTO 1;
END {IF};
IF map^ <> ':' THEN BEGIN
WRITELN ('Invalid map file');
END {IF};
get (map);
IF EOF (map) THEN BEGIN
GOTO 1;
END {IF};
offset := read_hex (3) + WRD (hex_char (map^) > 0);
get (map);
IF map^ <> 'H' THEN BEGIN
WRITELN ('Invalid map file');
END {IF};
IF EOF (map) THEN BEGIN
GOTO 1;
END {IF};
get (map);
parcel := seg + offset;
END {WHILE};
1: real_per_cent := buckets^[i] * norm;
cum_per_cent := cum_per_cent + real_per_cent;
per_cent := ROUND ( buckets^[i] * norm_bucket);
WRITE (hist, buckets^ [i]:6:0, ' ',
address*16:6:16);
IF line_no <> 0 THEN BEGIN
WRITE (hist, line_no:6);
line_no := 0;
END
ELSE IF map_avail AND THEN first_address <> NIL THEN BEGIN
WRITE (hist, ' #', address - first_address^.address:4:16);
END
ELSE BEGIN
WRITE (hist, ' ');
END {IF};
WRITELN (hist, ' ', cum_per_cent:5:1, ' ', real_per_cent:4:1, ' |',
'*': per_cent);
END {WHILE};
WRITELN (hist, ' +-----------------',
'------------------');
END.

BIN
v2.0/bin/QUICK.DOC Normal file

Binary file not shown.

177
v2.0/bin/README.DOC Normal file
View File

@ -0,0 +1,177 @@
MSDOS 2.0 RELEASE
The 2.0 Release of MSDOS includes five 5 1/4 double density single sided
diskettes or three 8 iinch CP/M 80 format diskettes.
The software/documentation on the five inch diskettes is arranged
as follows:
1. DOS distribution diskette. This diskette contains files which
should be distriibuted to all users. This allows the DOS distri-
bution diskette to meet the requirements of users of high level
language compilers as well as users running only applications.
Many compilers marketed independently through the retail channel
(including those of Microsoft) assume LINK comes with the DOS, as
in the case of IBM. How you choose to distrubute BASIC (contracted
for separately) is up to you.
2. Assembly Language Development System diskette. This diskette
contains files of interest to assembly language programmers.
High level language programmers do not need these programs unless
they are writing assembly language subroutines. IBM chose to
unbundle this package from the DOS distribution diskette (except
for DEBUG), but you do not have to do so.
3. PRINT and FORMAT diskette. This diskette contains .ASM source
files which are necessary to assemble the print spooler, which you
may wish to customize for greater performance. .OBJ files are also
included for the FORMAT utility.
4. Skeltal BIOS and documentation diskette. This diskette contains
the skeltal BIOS source code and the SYSINIT and SYSIMES object
modules which must be linked with your BIOS module. The proper
sequence for linking is BIOS - SYSINIT - SYSIMES.
A profiler utiliity is also included on the diskette, but this
is not intended for end-users. This is distributed for use by
your development staff only and is not supported by Microsoft
If you do decide to distribute it, it is at your own risk!
5. Documentation. Features of 2.0 are documented on this disk.
The user manual contains some significant errors. Most of these are
due to last minute changes to achieve a greater degree of compatibility
with IBM's implementation of MS-DOS (PC DOS). This includes the use
of "\" instead of "/" as the path separator, and "/" instead of "-"
as the switch character. For transporting of batch files across
machines, Microsoft encourages the use of "\" and "/" respectively
in the U.S. market. (See DOSPATCH.TXT for how you can overide this.
The user guide explains how the end-user can override this in CONFIG.SYS).
Both the printer echo keys and insert mode keys have now been made to
toggle. The default prompt (this may also be changed by the user
with the PROMPT command) has been changed from "A:" to "A>".
We apologize for any inconveniences these changes may have caused
your technical publications staff.
Here is what you need to do to MSDOS 2.0 to create a shipable product:
(see "Making a Bootable Diskette" below)
1. BIOS. If you have developed a BIOS for the Beta Test 2.0 version
You should link your BIOS module to SYSINIT.OBJ and SYSIMES.OBJ.
You must modify your BIOS to accomodate the call back to the BIOS
at the end of SYSINIT. If you have no need for this call, simply
find a far RET and label it RE_INIT and declare it public.
An example of this can be found in the skeletal BIOS. In addition
please add support for the new fast console output routine as
described in the device drivers document. We strongly recommend
that you adapt the standard boot sector format also described in
device drivers. Once again, please refer to the skeletal BIOS.
If you have not yet implemented version 2.0 please read the device
drivers document. Microsoft strongly recommends that machines
incorporating integrated display devices with memory mapped video
RAM implement some sort of terminal emulations through the use of
escape sequences. The skeletal BIOS includes a sample ANSI
terminal driver.
2. Please refer to DOSPATCH.TXT for possible changes you might wish
to make. We strongly recommend that you not patch the switch
characters for the U.S. market. Your one byte serial number
will be issued upon signing the license agreement. Please patch
the DOS accordingly. If you wish to serialize the DOS, this is
described in DOSPATCH.TXT. Please patch the editing template
definitions. Please note the addition of the Control-Z entry
at the beginning of the table. Also note that the insert switches
have now both been made to toggle.
3. Utilities. FORMAT must be configured for each specific system.
GENFOR is a generic example of a system independent format module,
but it is not recommended that this be distributed to your customers.
Link in the following order: FORMAT, FORMES, (your format module).
The print spooler is distributed as an executable file, which only
prints during wait for keyboard input. If you wish with your
implementation to steal some compute time when printing as well,
you will need to customize it and reassemble. Please note that
you can use a printer-ready or timer interrupt. The former is more
efficient, but ties the user to a specific device. Sample code
is conditionaled out for the IBM PC timer interrupt.
The following problems are known to exist:
1. Macro assembler does not support the initialization of 10-byte
floating point constants in 8087 emulation mode - the last two bytes
are zero filled.
2. LIB has not been provided. The version which incorporates support
for 2.0 path names will be completed in a couple of weeks. The
1.x version should work fine if you cannot wait. Because the library
manager acts as a counterpart to the linker, we recommend that it
be distributed with the DOS distribution diskette as opposed to the
assembly language development system.
3. International (French, German, Japanese, and U.K.) versions will be
available in several months.
4. COMMAND.ASM is currently too large to assemble on a micro. It is
being broken down into separate modules so it can be asembled on
a machine. Source licensees should realize that the resultant
binaries from the new version will not correspond exactly to the
old version.
5. If you have any further questions regarding the MSDOS 2.0 distribution
please contact Don Immerwahr (OEM technical support (206) 828-8086).
Sincerely yours,
Chris Larson
MS-DOS Product Marketing Manager
(206) 828-8080
BUILDING A BOOTABLE (MSDOS FORMAT) DISKETTE
1. In implementing MSDOS on a new machine, it is highly recommended
that an MSDOS machine be available for the development.
Please note that utilities shipped with MSDOS 2.0 use MSDOS 2.0
system calls and WILL NOT not run under MSDOS 1.25.
2. Use your MSDOS development machine and EDLIN or a word processor
package to write BOOT.ASM, your bootstrap loader BIOS.ASM and
your Format module.
3. Use MASM, the Microsoft Macro-86 Assembler, to assemble these
modules. LINK is then used to link together the .OBJ modules in
the order specified.
4. Link creates .EXE format files which are not memory image files
and contain relocation information in their headers. Since your
BIOS and BOOT routines will not be loaded by the EXE loader in
MSDOS, they must first be turned into memory image files by
using the EXE2BIN utility.
5. The easiest thing to do is to (using your development machine)
FORMAT a single sided diskette without the system. Use DEBUG
to load and write your BOOT.COM bootstrap loader to the BOOT
sector of that diskette. You may decide to have your bootstrap
load BIOS and let the BIOS load MSDOS or it may load both. Note that
the Bootstrap loader will have to know physically where to go on
the disk to get the BIOS and the DOS. COMMAND.COM is loaded
by the SYSINIT module.
6. Use the COPY command to copy your IO.SYS file (what the
BIOS-SYSINIT-SYSIMES module is usually called) onto the disk
followed by MSDOS.SYS and COMMAND.COM. You may use DEBUG
to change the directory attribute bytes to make these files hidden.
CAUTION:
At all times, the BIOS writer should be careful to preserve the state
of the DOS - including the flags. You should be also be cautioned that
the MSDOS stack is not deep. You should not count on more than one or
two pushes of the registers.

BIN
v2.0/bin/RECOVER.COM Normal file

Binary file not shown.

BIN
v2.0/bin/SORT.EXE Normal file

Binary file not shown.

BIN
v2.0/bin/SYS.COM Normal file

Binary file not shown.

1657
v2.0/bin/SYSCALL.DOC Normal file

File diff suppressed because it is too large Load Diff

BIN
v2.0/bin/SYSIMES.OBJ Normal file

Binary file not shown.

BIN
v2.0/bin/SYSINIT.DOC Normal file

Binary file not shown.

BIN
v2.0/bin/SYSINIT.OBJ Normal file

Binary file not shown.

813
v2.0/bin/UTILITY.DOC Normal file
View File

@ -0,0 +1,813 @@
MS-DOS 2.0
Utility Extensions
The following notation is used below:
[item] item is optional.
item* item is repeated 0 or more times.
item+ item is repeated 1 or more times.
{item1 | item2}
item1 is present or item 2 is present but
not both.
<object> indicates a syntactic variable.
COMMAND invokation
COMMAND [[<drive>:]<path>] [<cttydev>] [-D] [-P] [-C <string>]
-P If present COMMAND will be permanent, otherwise
this is a transient command.
-D If present COMMAND will not prompt for DATE and
TIME when it comes up.
d: Specifies device where command will look for
COMMAND.COM current default drive if absent.
<Path> Specifies a directory on device d: root
directory if absent.
<cttydev> Name of the CTTY device. /DEV/CON if absent
and command is permanent. The /DEV/ may be left
off if AVAILDEV is TRUE (see sysinit doc).
-C <string> If present -C must be the last switch.
This causes COMMAND to try to execute the string
as if the user had typed it at the standard input.
COMMAND executes this single command string and
then exits. If the -P switch is present it is
ignored (can't have a single command, permanent
COMMAND). NOTE: ALL of the text on the command
line after the -C is just passed on. It is not
processed for more arguments, this is why -C must
be last.
COMMAND extensions
IF <condition> <command>
where <condition> is one of the following:
ERRORLEVEL <number>
true if and only if the previous program EXECed by
COMMAND had an exit code of <number> or higher.
<string1> == <string2>
true if and only if <string1> and <string2> are
identical after parameter substitution. Strings
may not have embedded delimiters.
EXIST <filename>
true if and only if <filename> exists.
NOT <condition>
true if and only if <condition> is false.
The IF statement allows conditional execution of commands.
When the <condition> is true, then the <command> is
executed otherwise, the <command> is skipped.
Examples:
IF not exist /tmp/foo ECHO Can't find file /tmp/foo
IF $1x == x ECHO Need at least one parameter
IF NOT ERRORLEVEL 3 LINK $1,,;
FOR %%<c> IN <set> DO <command>
<c> can be any character but 0,1,2,3,..,9 (so there is no
confusion with the %0 - %9 batch parameters).
<set> is ( <item>* )
The %%<c> variable is sequentially set to each member of
<set> and then <command> is evaluated. If a member of
<set> is an expression involving * and/or ?, then the
variable is set to each matching pattern from disk. In
this case only one such <item> may be in the set, any
<item>s after the first are ignored.
Example:
FOR %%f IN ( *.ASM ) DO MASM %%f;
for %%f in (FOO BAR BLECH) do REM %%f to you
NOTE: The '%%' is needed so that after Batch parameter
(%0 - %9) processing is done, there is one '%' left.
If only '%f' were there, the batch parameter processor
would see the '%' then look at 'f', decide that '%f'
was an error (bad parameter reference) and throw out
the '%f' so that FOR would never see it. If the FOR
is NOT in a batch file, then only ONE '%' should be
used.
SHIFT
Currently, command files are limited to handling 10
parameters: %0 through %9. To allow access to more than
these, the command SHIFT will perform a 'pop' of the
command line parameters:
if %0 = "foo"
%1 = "bar"
%2 = "blech"
%3...%9 are empty
then a SHIFT will result in the following:
%0 = "bar"
%1 = "blech"
%2...%9 are empty
If there are more than 10 parameters given on a command
line, then the those that appear after the 10th (%9) will
be shifted one at a time into %9 by successive shifts.
:<label>
This is essentially a no-op. It defines a label in the
batch file for a subsequent GOTO. It may also be used to
put comment lines in batch files since all lines that
start with ':' are ignored.
GOTO <label>
Causes commands to be taken from the batch file beginning
with the line after the <label> definition. If no label
has been defined, the current batch file will terminate.
Example:
:foo
REM looping...
GOTO foo
will produce a infinite sequence of messages:
'REM looping...'
NOTE: Labels are case insensitive, :FOO == :foo == :Foo
ECHO [{ON | OFF | <message>}]
Normally, commands in a BATCH file are echoed onto the
standard output as they are seen by COMMAND. ECHO OFF
turns off this feature. ECHO ON turns echoing back on.
If ON or OFF is not specified and there is text following
the command, that text (a message) is echoed to standard
output. If there are no arguments at all, the current
setting of echo (on or off) is echoed to the standard
output in the form:
ECHO is xxx
Where xxx is "on" or "off".
Redirection of standard input/standard output.
Programs that read from the keyboard and write to the
screen are said to be doing I/O to the standard input and
standard output. Using any of the following will result
in I/O to these standard devices:
Writing to default handles 1 / read from default
handle 0.
Doing byte I/O using system calls 1, 2, 6-12.
These standard devices may be redirected to/from files by
the following in command line arguments:
> <filename>
causes <filename> to be created (or truncated to
zero length) and then assigns standard output to
that file. All output from the command will be
placed in the file.
< <filename>
causes standard input to be assigned to
<filename>. All input to the command will come
from this file. If end-of-file is reached, then
system calls 1, 2, 6-12 will return ^Z , while
reading from handle 0 will return zero characters.
>> <filename>
causes <filename> to be opened (created if
necessary) and positions the write pointer at the
end of the file so that all output will be
appended to the file.
Note that the above will not appear in the command line
that the program being invoked sees.
Examples:
DIR *.ASM > FOO.LST
Sends the output of the dir command to the file
FOO.LST.
FOR %0 IN (*.ASM) DO MASM %0; >>ERRS.LST
Sends all error output from assembling every .ASM file
into the file ERRS.LST.
Piping of standard I/O
It is often useful for the output of one program to be
sent as input to another program. A typical case is a
program that produces columnar output that must later be
sorted.
The pipe feature allows this to occur naturally is the
programs do all of their I/O to the standard devices.
For example, if we had a program SORT that read all of
it's standard input, sorted it and then wrote it to the
standard output, then we could get a sorted directory
listing as follows:
DIR | SORT
The | would cause all standard output generated by the
left-hand command to be sent to the standard input of the
right-hand command.
If we wanted the sorted directory to be sent to a file, we
type:
DIR | SORT >FILE
and away it goes.
The piping feature is implemented as sequential execution
of the procedures with redirection to and from temporary
files. In the example above, the following would be an
exact equivalent:
DIR >/tmp/std1
SORT </tmp/std1 >FILE
The pipe is not a real pipe but rather a quasi-pipe
that uses temporary files to hold the input and output as
it sequentially executes the elements of the pipe. These
files are created in the current directory, of the current
drive and have the form %PIPEx%.$$$, where x will be 1 or
2. This means that any program that runs in the pipe must
be sure to restore the current directory and drive if it
has changed them, otherwise the pipe files will be lost.
VER
Prints DOS version number.
VOL [<drive>:]
Prints the volume ID of the disk in drive d:. No d: does
default drive.
CHDIR [{<drive>: | <path>}]
Change directory, or print current. directory.If no
argument is given, the current directory on the default
drive is printed. If d: alone is given, the durrent
directory of drive d is printed. Otherwise the current
directory is set to path.
NOTE:"CD" is accepted as an abbreviation.
MKDIR <path> - Make a directory.
"MD" is accepted as an abbreviation.
RMDIR <path> - Remove a directory.
"RD" is accepted as an abbreviation.
The directory must be empty except for
'.' and '..'.
<path> - A standard XENIX style path with the optional
addition of a drive spec:
A:/FOO/BAR Full path
/FOO/BAR Full path, current drive
FOO/BAR Current dir relative
A:FOO/BAR " " "
VERIFY [{ON | OFF}]
Select/deselect verify after write mode. This supliments
the V switch to the COPY command. Once turned ON, it
stays on until some program changes it (via the set verify
system call) or the VERIFY OFF command is given. If no
argument is given, the current setting of VERIFY is
printed to the standard output in the form:
VERIFY is xxx
Where xxx is "on" or "off".
PATH [<path>{;<path>}*]
Set command search paths. This allows users to set
directories that should be searched for external commands
after a search of the current directory is made. The
default value is /bin. In addition there are two special
cases: PATH all by itself with no arguments will print
the current path. Path with the single argument ';' (ie.
"PATH ;") will set the NUL path (no directories other than
the current one searched). If no argument is given, the
current value of PATH is printed to the standard output in
the form:
PATH=text of path
or
No path
NOTE: On IBM systems, the default value of path is No
path.
EXIT
For COMMANDs run without the P switch, this causes COMMAND
to return. For a normal COMMAND it causes a return to
itself.
BREAK [{ON | OFF}]
Like in CONFIG.SYS, "BREAK ON" turns on the Control C
check in the DOS function dispatcher. "BREAK OFF" turns
it off. If no argument is given the setting of BREAK is
printed to the standard output in the form:
BREAK is xxx
Where xxx is "on" or "off".
PROMPT [<prompt-text>]
Set the system prompt. MS-DOS prompts are now user
settable, all of the text on the command line is taken to
be the new prompt. If no text is present the prompt is
set to the default prompt. There are meta strings for
various special prompts. These are of the form '$c' where
c is one of the following:
$ - The '$' character.
t - The time.
d - The date.
p - The current directory of the default drive.
v - The version number.
n - The default drive.
g - The '>' character.
l - The '<' character.
b - The '|' character.
s - The ' ' character.
e - The ESC character.
_ - A CR LF sequence.
EXAMPLE:
PROMPT $n:
Would set the normal MS-DOS prompt.
PROMPT $n>
Would det the normal PC-DOS prompt.
PROMPT Time = $t$_Date = $d
Would set a two line prompt which printed
Time = (current time)
Date = (current date)
NOTE: For '$c' sequences, lower case = upper case, and
any character not on the above list is mapped to
nothing.
SET (ENVNAME)=(ENVTEXT)
Set environment strings. This command inserts strings in
COMMAND's environment. For instance:
SET PROMPT=$n>
Duplicates the function of the PROMPT command.
SET PATH=p1;p2
Duplicates the function of the PATH command.
SET foo=bar
Puts the string FOO=bar into the environment (note the
case mapping of (ENVNAME)).
NOTE: Environments are very flexible, almost anything can
be put into the environment with the SET command; the
only requirement is that a single '=' be present in
the string.
CLS
Clear screen, causes the ANSI escape sequence ESC[2J to be
sent to standard output.
CTTY /DEV/dev - Change console TTY. For instance:
CTTY /DEV/AUX
Would move all command I/O to the AUX port.
CTTY /DEV/CON
Would move it back to the normal device. The
/dev/ prefix may be left off if AVAILDEV is
TRUE (see configuration-file doc).
COMMAND internal commands take path arguments.
DIR <path>
COPY <path> <path>
DEL(ERASE) <path>
If the path is a dir, all files in that dir
are deleted.
NOTE: The "Are you sure (Y/N)" prompt for DEL and
ERASE now uses buffered standard input, so
users must type a return after their answer.
This gives them the chance to correct if they
type 'y' by mistake.
TYPE <path> (must specify a file)
FILCOM - compare two files
The FILCOM program compares two files and produces a log
of differences between them. The comparison may be made
in two fashions; either on a line-by-line basis, or on a
byte-by-byte basis.
The line-by-line compare will isolate blocks of lines that
are different between the two files and will print the
blocks from each file. The line-by-line compare is the
default when neither of the two files being compared has
the extension .EXE, .COM, or .OBJ.
The byte-by-byte compare will display exactly which bytes
are different between the two files. If either file being
compared has extension .EXE, .COM, or .OBJ then the files
will be compared in byte-by-byte mode.
RECOVER - recover files from a trashed disk.
If a sector on a disk goes bad, you can recover either the
file that contained that sector (without the sector) or
the entire disk (if the bad sector was in the directory).
To recover a particular file:
RECOVER <file-to-recover>
This will cause the file to be read sector by sector and
to be have the bad sector skipped. Note that this implies
that the allocation unit containing the bad sector will be
read as much as possible. When such a bad sector is
found, its containing allocation unit is marked as bad,
thus preventing future allocations of that bad sector.
To recover a particular disk:
RECOVER <drive-letter>:
This will cause a scan to be made of the drive's FAT for
chains of allocation units (files). A new root directory
is then written that has entries of the form FILEnnnn.
Each FILEnnnn will point to the head of one of the
allocation unit chains.
If there are more chains than directory entries in the
root, RECOVER prints a message and leaves the un-RECOVERED
chains in the FAT so that RECOVER can be run again once
some room has been made in the ROOT.
DEBUG ON MS-DOS 2.0
When 2.0 DEBUG is invoked it sets up a program header
atoffset 0 in its program work area. On previous versions it
was OK to overwrite this header with impunity: this is true
of the default header set up if no <filespec> is given to
DEBUG. If DEBUGging a .COM or .EXE file, however, you must be
careful not to tamper with the header of the program below
address 5CH, to do this will probably result in a crash. It
is also important that an attempt is not made to "restart" a
program once the "program terminated normally" message is
given. The program must be reloaded with the N and L commands
in order for it to run properly.
NEW FEATURES
The A (Assemble) Command
FORMAT: A [<address>]
PURPOSE: To assemble 8086/8087/8088 mnemonics directly into
memory.
o If a syntax error is encountered, DEBUG responds with
^ Error
and redisplays the current assembly address.
o All numeric values are hexadecimal and may be entered
as 1-4 characters.
o Prefix mnemonics must be entered in front of the opcode
to which they refer. They may also be entered on a
separate line.
o The segment override mnemonics are CS:, DS:, ES:, and
SS:
o String manipulation mnemonics must explictly state the
string size. For example, the MOVSW must be used to
move word strings and MOVSB must be used to move byte
strings.
o The mnemonic for the far return is RETF.
o The assembler will automatically assemble short, near
or far jumps and calls depending on byte displacement
to the destination address. These may be overridden
with the NEAR or FAR prefix. For example:
0100:0500 JMP 502 ; a 2 byte short jump
0100:0502 JMP NEAR 505 ; a 3 byte near jump
0100:0505 JMP FAR 50A ; a 5 byte far jump
The NEAR prefix may be abbreviated to NE but the FAR
prefix cannot be abbreviated.
o DEBUG cannot tell whether some operands refer to a word
memory location or a byte memroy location. In this case
the data type must be explicity stated with the prefix
"WORD PTR" or "BYTE PTR". DEBUG will also except the
abbreviations "WO" and "BY". For example:
NEG BYTE PTR [128]
DEC WO [SI]
o DEBUG also cannot tell whether an operand refers to a
memory location or to an immediate operand. DEBUG uses
the common convention that operands enclosed in square
brackets refer to memory. For example:
MOV AX,21 ;Load AX with 21H
MOV AX,[21] ;Load AX with the contents
;of memory location 21H
o Two popular pseudo-instructions have also been included.
The DB opcode will assemble byte values directly into
memory. The DW opcode will assemble word values directly
into memory. For example:
DB 1,2,3,4,"THIS IS AN EXAMPLE"
DB 'THIS IS A QUOTE: "'
DB "THIS IS A QUOTE: '"
DW 1000,2000,3000,"BACH"
o All forms of the register indirect commands are supported.
For example:
ADD BX,34[BP+2].[SI-1]
POP [BP+DI]
PUSH [SI]
o All opcode synonyms are supported, For example:
LOOPZ 100
LOOPE 100
JA 200
JNBE 200
o For 8087 opcodes the WAIT or FWAIT prefix must be
explictly specified. For example:
FWAIT FADD ST,ST(3) ; This lines will assemble
; a FWAIT prefix
FLD TBYTE PTR [BX] ; This line will not
FORMAT enhancements
FORMAT will now install volume id's during the format
process. DIR and CHKDSK will display these volume id's.
User programs can read the volume id on a particular drive
by doing a 'search next' with the volume id attribute. It
is impossible, using normal DOS calls, to delete a volume
id or to create another one. The only way to create a
volume id is to reformat the disk.
NOTE: On IBM systems the V switch must be given to FORMAT
to have it do Volume IDs.
CHKDSK FOR MS-DOS 2.0
MS-DOS 2.0 has a tree structured directory scheme which
did not exist on previous versions of MS-DOS. As a result
CHKDSK is a much more complex program than in previous
versions since it must perform a tree traversal to find all of
the files on a given disk. It employes a depth first
traversal in order to accomplish this.
Previous versions of CHKDSK automatically "fixed"
disks (regardless of whether it was appropriate). CHKDSK 2.00
run normally will not alter the disk in any way, it simply
reports on any inconsistencies found. To actually "fix" a
disk CHKDSK must be run with the F switch (Fix). This allows
you to perhaps take some alternate (to CHKDSK repairs) action
before letting CHKDSK loose on your disk.
CHKDSK 2.00 will report on non-contiguous allocation units
(extents) for specified files. This is handy for gaging how
"fragmented" a disk volume has become. This is done by simply
giving a filespec:
CHKDSK B:*.*
This would report extents for all files in the current
directory for drive B after doing a normal consistency check
on drive B. Files which have many extents can be copied and
renamed to restore them to a contiguous state, thus improving
I/O performance to the files.
Previous versions of CHKDSK would simply free
allocation units which were marked as used, but were not
actually part of any file. CHKDSK 2.00 will recover these
"orphan" allocation units if specified. If orphan allocation
units are found, CHKDSK prompts for free or recover. Free
just frees the orphans as previous versions did, recover will
employ allocation chain analysis to create "orphan files" in
the root directory of the disk. These files will have the
form "%ORPHAN%.l$$" where l will take on some ASCII value
greater than '@'. These files may then be inspected to see if
valuable data was contained in them. If there is not enough
room to make all of the "orphan" files, CHKDSK leaves the
unrecovered chains in the FAT so that CHKDSK can be run again
(once some entries in the ROOT have been deleted). NOTE:
Making ORPHAN files is a SLOW process.
Verbose mode. CHKDSK 2.00 may be run with the V switch
which causes a trace of the files and directories being
processed to be printed as CHKDSK runs.
FILTERS FOR MS-DOS 2.0
A filter is a utility that reads from standard input,
modifies the information in some way, then writes the result
to standard output. In this way the data is said to have been
"filtered" by the program. Since different filters can be
piped together in many different ways a few filters can take
the place of a large number of specific purpose programs. The
following describes the filters that are provided with MS-DOS
2.0:
CIPHER <key word>
Cipher reads a program from standard input, encrypts it
using the key word provided by the user, then writes the
result to standard output. To decrypt the file simply run
CIPHER again using the same keyword. For example:
A>CIPHER MYSTERY <NSA.CIA >SECRET.FIL
This command line will read file NSA.CIA, encrypt it using
the key word "MYSTERY", then write the result to file
SECRET.FIL To view the original file the following command
line could be used:
A>CIPHER MYSTERY <SECRET.FIL
This will read file SECRET.FIL, decrypt the file using the
key word "MYSTERY", then write the result to standard output,
which in this case is the console.
FGREP
This filter takes as arguments a string and optionally a
series of file names. It will send to standard output all
lines from the files specified in the command line that
contain the string.
If no files are specified FGREP will take the input from
standard in. The format for the command line invocation of
FGREP is:
FGREP [<option>] <string> <filename>*
The options available are:
/v Will cause FGREP to output all lines NOT
containing the specified string.
/c Will cause FGREP to only print the count of
lines matched in each of the files.
/n Each line matched is preceded by its relative
line number in the file.
The string argument should be enclosed in double quotes.
Two double quotes in succession are taken as a single double
quote. So,
A>FGREP "Fool""s Paradise" book1.txt book2.txt bible
will output all lines from the book1.txt, book2.txt and bible
(in that order that contain the string: Fool"s Paradise .
And,
A>dir b: | fgrep /v "DAT"
will output all names of the files in disk b: which do not
contain the string DAT .
MORE
The filter MORE reads from standard input, sends one
screen full of information to standard output and then pauses
with message:
-- More --
Pressing the RETURN key will cause another screen full of
information to be written to standard output. This process
continues until all the input data is read.
SORT [/R] [/+n]
Sort reads from standard input, sorts the data, the writes
the information to standard output. The sort is done using
the ASCII collating sequence. There are switches which allow
the user to select various options:
R - Reverse the sort, that is make "Z" come before "A"
+n - Sort starting with column "n" where n is some integer.
The default is start the comparisons with column 1,
this switch allows the user to start in any column.
example:
A>SORT /R <UNSORT.TXT >SORT.TXT
This command line will read the file UNSORT.TXT, do a reverse
sort, then write the output to file SORT.TXT
A>DIR | SORT /+14
This command line will cause the output of the directory
command to be piped to the sort filter, the sort filter will
sort starting with column 14 (This is the column the file size
starts), then send the output to the console. Thus a
directory sorted by file size will be the result. To get real
fancy:
A>DIR | SORT /+14 | MORE
will do the same thing except that MORE will give you a chance
to read the directory before it scrolls off the screen.

371
v2.0/source/ALLOC.ASM Normal file
View File

@ -0,0 +1,371 @@
;
; xenix memory calls for MSDOS
;
; CAUTION: The following routines rely on the fact that arena_signature and
; arena_owner_system are all equal to zero and are contained in DI.
;
INCLUDE DOSSEG.ASM
CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME SS:DOSGROUP,CS:DOSGROUP
.xlist
.xcref
INCLUDE DOSSYM.ASM
INCLUDE DEVSYM.ASM
.cref
.list
TITLE ALLOC.ASM - memory arena manager
NAME Alloc
SUBTTL memory allocation utility routines
PAGE
;
; arena data
;
i_need arena_head,WORD ; seg address of start of arena
i_need CurrentPDB,WORD ; current process data block addr
i_need FirstArena,WORD ; first free block found
i_need BestArena,WORD ; best free block found
i_need LastArena,WORD ; last free block found
i_need AllocMethod,BYTE ; how to alloc first(best)last
;
; arena_free_process
; input: BX - PID of process
; output: free all blocks allocated to that PID
;
procedure arena_free_process,NEAR
ASSUME DS:NOTHING,ES:NOTHING
MOV DI,arena_signature
MOV AX,[arena_head]
CALL Check_Signature ; ES <- AX, check for valid block
arena_free_process_loop:
retc
PUSH ES
POP DS
CMP DS:[arena_owner],BX ; is block owned by pid?
JNZ arena_free_next ; no, skip to next
MOV DS:[arena_owner],DI ; yes... free him
arena_free_next:
CMP BYTE PTR DS:[DI],arena_signature_end
; end of road, Jack?
retz ; never come back no more
CALL arena_next ; next item in ES/AX carry set if trash
JMP arena_free_process_loop
arena_free_process ENDP
;
; arena_next
; input: DS - pointer to block head
; output: AX,ES - pointers to next head
; carry set if trashed arena
;
procedure arena_next,NEAR
ASSUME DS:NOTHING,ES:NOTHING
MOV AX,DS ; AX <- current block
ADD AX,DS:[arena_size] ; AX <- AX + current block length
INC AX ; remember that header!
;
; fall into check_signature and return
;
; CALL check_signature ; ES <- AX, carry set if error
; RET
arena_next ENDP
;
; check_signature
; input: AX - address of block header
; output: ES=AX, carry set if signature is bad
;
procedure check_signature,NEAR
ASSUME DS:NOTHING,ES:NOTHING
MOV ES,AX ; ES <- AX
CMP BYTE PTR ES:[DI],arena_signature_normal
; IF next signature = not_end THEN
JZ check_signature_ok ; GOTO ok
CMP BYTE PTR ES:[DI],arena_signature_end
; IF next signature = end then
JZ check_signature_ok ; GOTO ok
STC ; set error
return
check_signature_ok:
CLC
return
Check_signature ENDP
;
; Coalesce - combine free blocks ahead with current block
; input: DS - pointer to head of free block
; output: updated head of block, AX is next block
; carry set -> trashed arena
;
procedure Coalesce,NEAR
ASSUME DS:NOTHING,ES:NOTHING
CMP BYTE PTR DS:[DI],arena_signature_end
; IF current signature = END THEN
retz ; GOTO ok
CALL arena_next ; ES, AX <- next block, Carry set if error
retc ; IF no error THEN GOTO check
coalesce_check:
CMP ES:[arena_owner],DI
retnz ; IF next block isnt free THEN return
MOV CX,ES:[arena_size] ; CX <- next block size
INC CX ; CX <- CX + 1 (for header size)
ADD DS:[arena_size],CX ; current size <- current size + CX
MOV CL,ES:[DI] ; move up signature
MOV DS:[DI],CL
JMP coalesce ; try again
Coalesce ENDP
SUBTTL $Alloc - allocate space in memory
PAGE
;
; Assembler usage:
; MOV BX,size
; MOV AH,Alloc
; INT 21h
; AX:0 is pointer to allocated memory
; BX is max size if not enough memory
;
; Description:
; Alloc returns a pointer to a free block of
; memory that has the requested size in paragraphs.
;
; Error return:
; AX = error_not_enough_memory
; = error_arena_trashed
;
procedure $ALLOC,NEAR
ASSUME DS:NOTHING,ES:NOTHING
XOR AX,AX
MOV DI,AX
MOV [FirstArena],AX ; init the options
MOV [BestArena],AX
MOV [LastArena],AX
PUSH AX ; alloc_max <- 0
MOV AX,[arena_head] ; AX <- beginning of arena
CALL Check_signature ; ES <- AX, carry set if error
JC alloc_err ; IF error THEN GOTO err
alloc_scan:
PUSH ES
POP DS ; DS <- ES
CMP DS:[arena_owner],DI
JZ alloc_free ; IF current block is free THEN examine
alloc_next:
CMP BYTE PTR DS:[DI],arena_signature_end
; IF current block is last THEN
JZ alloc_end ; GOTO end
CALL arena_next ; AX, ES <- next block, Carry set if error
JNC alloc_scan ; IF no error THEN GOTO scan
alloc_err:
POP AX
alloc_trashed:
error error_arena_trashed
alloc_end:
CMP [FirstArena],0
JNZ alloc_do_split
alloc_fail:
invoke get_user_stack
POP BX
MOV [SI].user_BX,BX
error error_not_enough_memory
alloc_free:
CALL coalesce ; add following free block to current
JC alloc_err ; IF error THEN GOTO err
MOV CX,DS:[arena_size]
POP DX ; check for max found size
CMP CX,DX
JNA alloc_test
MOV DX,CX
alloc_test:
PUSH DX
CMP BX,CX ; IF BX > size of current block THEN
JA alloc_next ; GOTO next
CMP [FirstArena],0
JNZ alloc_best
MOV [FirstArena],DS ; save first one found
alloc_best:
CMP [BestArena],0
JZ alloc_make_best ; initial best
PUSH ES
MOV ES,[BestArena]
CMP ES:[arena_size],CX ; is size of best larger than found?
POP ES
JBE alloc_last
alloc_make_best:
MOV [BestArena],DS ; assign best
alloc_last:
MOV [LastArena],DS ; assign last
JMP alloc_next
;
; split the block high
;
alloc_do_split_high:
MOV DS,[LastArena]
MOV CX,DS:[arena_size]
SUB CX,BX
MOV DX,DS
JE alloc_set_owner ; sizes are equal, no split
ADD DX,CX ; point to next block
MOV ES,DX ; no decrement!
DEC CX
XCHG BX,CX ; bx has size of lower block
JMP alloc_set_sizes ; cx has upper (requested) size
;
; we have scanned memory and have found all appropriate blocks
; check for the type of allocation desired; first and best are identical
; last must be split high
;
alloc_do_split:
CMP BYTE PTR [AllocMethod], 1
JA alloc_do_split_high
MOV DS,[FirstArena]
JB alloc_get_size
MOV DS,[BestArena]
alloc_get_size:
MOV CX,DS:[arena_size]
SUB CX,BX ; get room left over
MOV AX,DS
MOV DX,AX ; save for owner setting
JE alloc_set_owner ; IF BX = size THEN (don't split)
ADD AX,BX
INC AX ; remember the header
MOV ES,AX ; ES <- DS + BX (new header location)
DEC CX ; CX <- size of split block
alloc_set_sizes:
MOV DS:[arena_size],BX ; current size <- BX
MOV ES:[arena_size],CX ; split size <- CX
MOV BL,arena_signature_normal
XCHG BL,DS:[DI] ; current signature <- 4D
MOV ES:[DI],BL ; new block sig <- old block sig
MOV ES:[arena_owner],DI
alloc_set_owner:
MOV DS,DX
MOV AX,[CurrentPDB]
MOV DS:[arena_owner],AX
MOV AX,DS
INC AX
POP BX
transfer SYS_RET_OK
$alloc ENDP
SUBTTL $SETBLOCK - change size of an allocated block (if possible)
PAGE
;
; Assembler usage:
; MOV ES,block
; MOV BX,newsize
; MOV AH,setblock
; INT 21h
; if setblock fails for growing, BX will have the maximum
; size possible
; Error return:
; AX = error_invalid_block
; = error_arena_trashed
; = error_not_enough_memory
; = error_invalid_function
;
procedure $SETBLOCK,NEAR
ASSUME DS:NOTHING,ES:NOTHING
MOV DI,arena_signature
MOV AX,ES
DEC AX
CALL check_signature
JNC setblock_grab
setblock_bad:
JMP alloc_trashed
setblock_grab:
MOV DS,AX
CALL coalesce
JC setblock_bad
MOV CX,DS:[arena_size]
PUSH CX
CMP BX,CX
JBE alloc_get_size
JMP alloc_fail
$setblock ENDP
SUBTTL $DEALLOC - free previously allocated piece of memory
PAGE
;
; Assembler usage:
; MOV ES,block
; MOV AH,dealloc
; INT 21h
;
; Error return:
; AX = error_invalid_block
; = error_arena_trashed
;
procedure $DEALLOC,NEAR
ASSUME DS:NOTHING,ES:NOTHING
MOV DI,arena_signature
MOV AX,ES
DEC AX
CALL check_signature
JC dealloc_err
MOV ES:[arena_owner],DI
transfer SYS_RET_OK
dealloc_err:
error error_invalid_block
$DEALLOC ENDP
SUBTTL $AllocOper - get/set allocation mechanism
PAGE
;
; Assembler usage:
; MOV AH,AllocOper
; MOV BX,method
; MOV AL,func
; INT 21h
;
; Error return:
; AX = error_invalid_function
;
procedure $AllocOper,NEAR
ASSUME DS:NOTHING,ES:NOTHING
CMP AL,1
JB AllocOperGet
JZ AllocOperSet
error error_invalid_function
AllocOperGet:
MOV AL,BYTE PTR [AllocMethod]
XOR AH,AH
transfer SYS_RET_OK
AllocOperSet:
MOV [AllocMethod],BL
transfer SYS_RET_OK
$AllocOper ENDP
do_ext
CODE ENDS
END

BIN
v2.0/source/ANSI.txt Normal file

Binary file not shown.

508
v2.0/source/BUF.ASM Normal file
View File

@ -0,0 +1,508 @@
;
; buffer management for MSDOS
;
INCLUDE DOSSEG.ASM
CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME SS:DOSGROUP,CS:DOSGROUP
.xlist
.xcref
INCLUDE DOSSYM.ASM
INCLUDE DEVSYM.ASM
.cref
.list
i_need BuffHead,DWORD
i_need PreRead,WORD
i_need LastBuffer,DWORD
i_need CurBuf,DWORD
i_need WPErr,BYTE
SUBTTL SETVISIT,SKIPVISIT -- MANAGE BUFFER SCANS
PAGE
procedure SETVISIT,near
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; None
; Function:
; Set up a scan of I/O buffers
; Outputs:
; All visit flags = 0
; NOTE: This pre-scan is needed because a hard disk error
; may cause a scan to stop in the middle leaving some
; visit flags set, and some not set.
; DS:DI Points to [BUFFHEAD]
; No other registers altered
LDS DI,[BUFFHEAD]
PUSH AX
XOR AX,AX
SETLOOP:
MOV [DI.VISIT],AL
LDS DI,[DI.NEXTBUF]
CMP DI,-1
JNZ SETLOOP
LDS DI,[BUFFHEAD]
POP AX
return
entry SKIPVISIT
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; DS:DI Points to a buffer
; Function:
; Skip visited buffers
; Outputs:
; DS:DI Points to next unvisited buffer
; Zero is set if skip to LAST buffer
; No other registers altered
CMP DI,-1
retz
CMP [DI.VISIT],1
retnz
LDS DI,[DI.NEXTBUF]
JMP SHORT SKIPVISIT
return
SetVisit ENDP
SUBTTL SCANPLACE, PLACEBUF -- PUT A BUFFER BACK IN THE POOL
PAGE
procedure ScanPlace,near
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; Same as PLACEBUF
; Function:
; Save scan location and call PLACEBUF
; Outputs:
; DS:DI Points to saved scan location
; SI destroyed, other registers unchanged
PUSH ES
LES SI,[DI.NEXTBUF] ; Save scan location
CALL PLACEBUF
PUSH ES
POP DS ; Restore scan location
MOV DI,SI
POP ES
return
ScanPlace ENDP
NRETJ: JMP SHORT NRET
procedure PLACEBUF,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Input:
; DS:DI points to buffer
; Function:
; Remove buffer from queue and re-insert it in proper place.
; If buffer doesn't go at end, and isn't free, decrement
; priorities.
; NO registers altered
;
; DS:SI -- Curbuf, current buffer in list
; ES:DI -- Buf, buffer passed as argument
; BP:CX -- Pointsave, saved Buf.nextbuf
; DX:BX -- Lastbuf, previous buffer in list
; AL -- Inserted, Buf has been inserted
; AH -- Removed, Buf has been removed
IF IBM
IF NOT IBM
invoke save_world
XOR AX,AX ; Inserted = Removed = FALSE
LES CX,[DI.NEXTBUF]
MOV BP,ES ; Pointsave = Buf.nextbuf
MOV SI,DS
MOV ES,SI ; Buf is ES:DI
LDS SI,[BUFFHEAD] ; Curbuf = HEAD
CALL POINTCOMP ; Buf == HEAD?
JNZ TNEWHEAD
CMP CX,-1 ; Buf is LAST?
JZ NRETJ ; Only one buffer, nothing to do
MOV WORD PTR [BUFFHEAD],CX
MOV WORD PTR [BUFFHEAD+2],BP ; HEAD = Pointsave
INC AH ; Removed = TRUE
MOV DS,BP
MOV SI,CX ; Curbuf = HEAD
TNEWHEAD:
MOV BL,ES:[DI.BUFPRI]
CMP BL,[SI.BUFPRI]
JGE BUFLOOP
NEWHEAD: ; If Buf.pri < HEAD.pri
MOV WORD PTR ES:[DI.NEXTBUF],SI
MOV WORD PTR ES:[DI.NEXTBUF+2],DS ; Buf.nextbuf = HEAD
MOV WORD PTR [BUFFHEAD],DI
MOV WORD PTR [BUFFHEAD+2],ES ; HEAD = Buf
INC AL ; Inserted = TRUE
OR AH,AH
JNZ NRET ; If Removed == TRUE
BUFLOOP:
PUSH DS
PUSH SI
LDS SI,[SI.NEXTBUF]
CALL POINTCOMP
POP SI
POP DS
JNZ TESTINS
MOV WORD PTR [SI.NEXTBUF],CX ; If Curbuf.nextbuf == buf
MOV WORD PTR [SI.NEXTBUF+2],BP ; Curbuf.nextbuf = Pointsave
INC AH ; Removed = TRUE
OR AL,AL
JNZ SHUFFLE ; If Inserted == TRUE
TESTINS:
OR AL,AL
JNZ LOOKBUF
PUSH CX ; If NOT Inserted
MOV CL,ES:[DI.BUFPRI]
CMP CL,[SI.BUFPRI]
POP CX
JGE LOOKBUF
PUSH DS ; If Buf.pri < Curbuf.pri
MOV DS,DX
MOV WORD PTR [BX.NEXTBUF],DI
MOV WORD PTR [BX.NEXTBUF+2],ES ; Lastbuf.nextbuf = Buf
POP DS
MOV WORD PTR ES:[DI.NEXTBUF],SI
MOV WORD PTR ES:[DI.NEXTBUF+2],DS ; Buf.nextbuf = Curbuf
INC AL ; Inserted = TRUE
OR AH,AH
JNZ SHUFFLE ; If Removed == TRUE
LOOKBUF:
MOV BX,SI
MOV DX,DS ; Lastbuf = Curbuf
CMP WORD PTR [SI.NEXTBUF],-1
JZ ISLAST
LDS SI,[SI.NEXTBUF] ; Curbuf = Curbuf.nextbuf
JMP SHORT BUFLOOP
ISLAST: ; If Curbuf is LAST
MOV WORD PTR [SI.NEXTBUF],DI
MOV WORD PTR [SI.NEXTBUF+2],ES ; Curbuf.nextbuf = Buf
MOV WORD PTR ES:[DI.NEXTBUF],-1
MOV WORD PTR ES:[DI.NEXTBUF+2],-1 ; Buf is LAST
NRET:
invoke restore_world
return
SHUFFLE:
LDS DI,[BUFFHEAD]
DECLOOP:
CMP [DI.BUFPRI],FREEPRI
JZ NODEC
DEC [DI.BUFPRI]
NODEC:
LDS DI,[DI.NEXTBUF]
CMP DI,-1
JNZ DECLOOP
JMP SHORT NRET
ENDIF
ENDIF
invoke save_world
LES CX,[DI.NEXTBUF]
CMP CX,-1 ; Buf is LAST?
JZ NRET ; Buffer already last
MOV BP,ES ; Pointsave = Buf.nextbuf
PUSH DS
POP ES ; Buf is ES:DI
LDS SI,[BUFFHEAD] ; Curbuf = HEAD
CALL POINTCOMP ; Buf == HEAD?
JNZ BUFLOOP
MOV WORD PTR [BUFFHEAD],CX
MOV WORD PTR [BUFFHEAD+2],BP ; HEAD = Pointsave
JMP SHORT LOOKEND
BUFLOOP:
PUSH DS
PUSH SI
LDS SI,[SI.NEXTBUF]
CALL POINTCOMP
JZ GOTTHEBUF
POP AX
POP AX
JMP SHORT BUFLOOP
GOTTHEBUF:
POP SI
POP DS
MOV WORD PTR [SI.NEXTBUF],CX ; If Curbuf.nextbuf == buf
MOV WORD PTR [SI.NEXTBUF+2],BP ; Curbuf.nextbuf = Pointsave
LOOKEND:
PUSH DS
PUSH SI
LDS SI,[SI.NEXTBUF]
CMP SI,-1
JZ GOTHEEND
POP AX
POP AX
JMP SHORT LOOKEND
GOTHEEND:
POP SI
POP DS
MOV WORD PTR [SI.NEXTBUF],DI
MOV WORD PTR [SI.NEXTBUF+2],ES ; Curbuf.nextbuf = Buf
MOV WORD PTR ES:[DI.NEXTBUF],-1
MOV WORD PTR ES:[DI.NEXTBUF+2],-1 ; Buf is LAST
NRET:
invoke restore_world
return
PLACEBUF ENDP
procedure PLACEHEAD,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; SAME AS PLACEBUF except places buffer at head
invoke save_world
PUSH DS
POP ES
LDS SI,[BUFFHEAD]
MOV WORD PTR [BUFFHEAD],DI
MOV WORD PTR [BUFFHEAD+2],ES
MOV WORD PTR ES:[DI.NEXTBUF],SI
MOV WORD PTR ES:[DI.NEXTBUF+2],DS
LOOKEND2:
PUSH DS
PUSH SI
LDS SI,[SI.NEXTBUF]
CALL POINTCOMP
JZ GOTHEEND2
POP AX
POP AX
JMP SHORT LOOKEND2
GOTHEEND2:
POP SI
POP DS
MOV WORD PTR [SI.NEXTBUF],-1
MOV WORD PTR [SI.NEXTBUF+2],-1 ; Buf is LAST
JMP SHORT NRET
PLACEHEAD ENDP
SUBTTL POINTCOMP -- 20 BIT POINTER COMPARE
PAGE
procedure PointComp,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Compare DS:SI to ES:DI (or DS:DI to ES:SI) for equality
; DO NOT USE FOR < or >
; No Registers altered
CMP SI,DI
retnz
PUSH CX
PUSH DX
MOV CX,DS
MOV DX,ES
CMP CX,DX
POP DX
POP CX
return
PointComp ENDP
SUBTTL GETBUFFR -- GET A SECTOR INTO A BUFFER
PAGE
procedure GETBUFFR,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Input:
; AH = Priority buffer is to have
; AL = 0 means sector must be pre-read
; ELSE no pre-read
; DX = Desired physical sector number
; ES:BP = Pointer to drive parameters
; Function:
; Get the specified sector into one of the I/O buffers
; And shuffle the queue
; Output:
; [CURBUF] Points to the Buffer for the sector
; DX,ES:BP unchanged, all other registers destroyed
XOR SI,SI
entry GETBUFFRB
MOV [PREREAD],AX
MOV AL,ES:[BP.dpb_drive]
LDS DI,[LASTBUFFER]
ASSUME DS:NOTHING
CMP DI,-1 ; Recency pointer valid?
JZ SKBUF ; No
CMP DX,[DI.BUFSECNO]
JNZ SKBUF ; Wrong sector
CMP AL,[DI.BUFDRV]
JNZ SKBUF ; Wrong Drive
JMP SHORT JUSTBUF ; Just asked for same buffer
SKBUF:
LDS DI,[BUFFHEAD]
NXTBFF:
CMP DX,[DI.BUFSECNO]
JNZ BUMP
CMP AL,[DI.BUFDRV]
JNZ BUMP
JMP SHORT SETINF
BUMP:
LDS DI,[DI.NEXTBUF]
CMP DI,-1
JNZ NXTBFF
LDS DI,[BUFFHEAD]
PUSH SI
PUSH DX
PUSH BP
PUSH ES
CALL BUFWRITE ; Write out the dirty buffer
POP ES
POP BP
POP DX
POP SI
RDSEC: ; Read in the new sector
TEST BYTE PTR [PREREAD],-1
JNZ SETBUF
LEA BX,[DI.BufInSiz] ; Point at buffer
MOV CX,1
PUSH SI
PUSH DI
PUSH DX
OR SI,SI
JZ NORMSEC
invoke FATSECRD
JMP SHORT GOTTHESEC ; Buffer is marked free if read barfs
NORMSEC:
invoke DREAD ; Buffer is marked free if read barfs
GOTTHESEC:
POP DX
POP DI
POP SI
SETBUF:
MOV [DI.BUFSECNO],DX
MOV WORD PTR [DI.BUFDRVDP],BP
MOV WORD PTR [DI.BUFDRVDP+2],ES
XOR AH,AH
MOV AL,ES:[BP.dpb_drive]
MOV WORD PTR [DI.BUFDRV],AX
SETINF:
MOV AX,1 ; Default to not a FAT sector
OR SI,SI
JZ SETSTUFFOK
MOV AL,ES:[BP.dpb_FAT_count]
MOV AH,ES:[BP.dpb_FAT_size]
SETSTUFFOK:
MOV WORD PTR [DI.BUFWRTCNT],AX
CALL PLACEBUF
JUSTBUF:
MOV WORD PTR [CURBUF+2],DS
MOV WORD PTR [LASTBUFFER+2],DS
PUSH SS
POP DS
ASSUME DS:DOSGROUP
MOV WORD PTR [CURBUF],DI
MOV WORD PTR [LASTBUFFER],DI
return
GETBUFFR ENDP
SUBTTL FLUSHBUF -- WRITE OUT DIRTY BUFFERS
PAGE
procedure FlushBuf,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Input:
; DS = DOSGROUP
; AL = Physical unit number
; = -1 for all units
; Function:
; Write out all dirty buffers for unit, and flag them as clean
; DS Preserved, all others destroyed (ES too)
LDS DI,[BUFFHEAD]
ASSUME DS:NOTHING
MOV AH,-1
NXTBUFF:
CMP [DI.BUFDRV],AH
JZ SKIPBFF ; Skip free buffers
CMP AH,AL
JZ DOBUFFER ; Do all dirty buffers
CMP AL,[DI.BUFDRV]
JNZ SKIPBFF ; Buffer not for this unit
DOBUFFER:
CMP BYTE PTR [DI.BUFDIRTY],0
JZ SKIPBFF ; Buffer not dirty
PUSH AX
PUSH WORD PTR [DI.BUFDRV]
CALL BUFWRITE
POP AX
XOR AH,AH ; Buffer is clean
CMP AL,BYTE PTR [WPERR]
JNZ NOZAP
MOV AL,0FFH ; Invalidate buffer, it is inconsistent
NOZAP:
MOV WORD PTR [DI.BUFDRV],AX
POP AX ; Search info
SKIPBFF:
LDS DI,[DI.NEXTBUF]
CMP DI,-1
JNZ NXTBUFF
PUSH SS
POP DS
return
FlushBuf ENDP
SUBTTL BUFWRITE -- WRITE OUT A BUFFER IF DIRTY
PAGE
procedure BufWrite,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Input:
; DS:DI Points to the buffer
; Function:
; Write out all the buffer if dirty.
; Output:
; Buffer marked free
; DS:DI Preserved, ALL others destroyed (ES too)
MOV AX,00FFH
XCHG AX,WORD PTR [DI.BUFDRV] ; Free, in case write barfs
CMP AL,0FFH
retz ; Buffer is free.
OR AH,AH
retz ; Buffer is clean.
CMP AL,BYTE PTR [WPERR]
retz ; If in WP error zap buffer
LES BP,[DI.BUFDRVDP]
LEA BX,[DI.BufInSiz] ; Point at buffer
MOV DX,[DI.BUFSECNO]
MOV CX,WORD PTR [DI.BUFWRTCNT]
MOV AL,CH ; [DI.BUFWRTINC]
XOR CH,CH
MOV AH,CH
PUSH DI
WRTAGAIN:
PUSH CX
PUSH AX
MOV CX,1
PUSH BX
PUSH DX
invoke DWRITE ; Write out the dirty buffer
POP DX
POP BX
POP AX
POP CX
ADD DX,AX
LOOP WRTAGAIN
POP DI
return
BufWrite ENDP
do_ext
CODE ENDS
END

901
v2.0/source/CHKDSK.ASM Normal file
View File

@ -0,0 +1,901 @@
TITLE CHKDSK - MS-DOS Disk consistancy checker
; CHKDSK Version 2.30
; Verifies and repairs MS-DOS disk directory.
; To build CHKDSK you need three modules:
; CHKDSK CHKPROC CHKMES
; They should be linked the that order as well.
; REVISION HISTORY
;REV 1.1
; 05/21/82 Added rev number
;REV 1.5
; Mod by NANCYP to report on extents
; Mod by AARONR to report volume ID
;REV 2.0
; Total rewrite for directories
;REV 2.1
; Added ^C and INT 24H handlers
;REV 2.2
; INTERNATIONAL support
;REV 2.3
; Split into two modules to allow assembly on a PC
; CHKDSK and CHKPROC
FALSE EQU 0
TRUE EQU NOT FALSE
DRVCHAR EQU ":"
;The following defines the ranges of DOS version numbers for which this CHKDSK
; is good
DOSVER_LOW EQU 0136H ;1.54 in hex
DOSVER_HIGH EQU 020BH ;2.11 in hex
INCLUDE DOSSYM.ASM
FCB EQU 5CH
;Drive parameter block from DOS header
SUBTTL Segments used in load order
CODE SEGMENT PUBLIC
CODE ENDS
CONST SEGMENT PUBLIC BYTE
CONST ENDS
DATA SEGMENT PUBLIC WORD
DATA ENDS
DG GROUP CODE,CONST,DATA
SUBTTL Initialized Data
PAGE
CONST SEGMENT PUBLIC BYTE
PUBLIC HECODE,SWITCHAR,NOISY,DOFIX,CONBUF,ORPHCNT,ORPHSIZ,DOFIX
PUBLIC HIDCNT,HIDSIZ,DIRCNT,DIRSIZ,FILCNT,FILSIZ,BADSIZ,LCLUS
PUBLIC DOTENT,HAVFIX,SECONDPASS,NUL,ALLFILE,PARSTR,ERRSUB,LCLUS
PUBLIC DIRTYFAT,BADSIZ,DDOTENT,CROSSCNT,ORPHFCB,ORPHEXT,ALLDRV
PUBLIC FRAGMENT,USERDIR,DIRBUF,USERDIR,FIXMFLG,DOTMES,DIRCHAR
EXTRN IDMES1:BYTE,IDPOST:BYTE,VNAME:BYTE,MONTAB:BYTE
EXTRN TCHAR:BYTE,BADREAD_PRE:BYTE,BADREAD_POST:BYTE
EXTRN CRLF:BYTE,BADVER:BYTE,BADSUBDIR:BYTE,CENTRY:BYTE
EXTRN BADDRV:BYTE,BADCD:BYTE,BADRDMES:BYTE,OPNERR:BYTE
EXTRN CONTAINS:BYTE,EXTENTS:BYTE,NOEXTENTS:BYTE
EXTRN BADDRVM:BYTE,BADDRVM2:BYTE,BADIDBYT:BYTE
DIRBUF LABEL BYTE ;Entry buffer for searches
VOLID DB -1,0,0,0,0,0,8 ;Volume ID FCB
VOLNAM DB 0,"???????????"
DB 25 DUP(0)
ALLFILE DB -1,0,0,0,0,0,1EH ;Extended FCB
ALLDRV DB 0,"???????????"
DB 25 DUP (?)
ORPHFCB DB 0,"FILE0000"
ORPHEXT DB "CHK"
DB 25 DUP (?)
;Non-message data
SWITCHAR DB "-"
ROOTSTR LABEL BYTE
DIRCHAR DB "/"
NUL DB 0
PARSTR DB "..",0
DOTMES DB ".",0
DOTENT DB ". "
DDOTENT DB ".. "
HECODE DB ?
FIXMFLG DB 0 ;Flag for printing fixmes
ERRSUB DW 0 ;Flag for bad subdir error
FRAGMENT DB 0 ;Flag for extent processing
DIRTYFAT DB 0 ;Dirty flag for FAT
DIRCNT DW 0 ;# directories
DIRSIZ DW 0 ;# alloc units in directories
FILCNT DW 0 ;# reg files
FILSIZ DW 0 ;# alloc units in reg files
HIDCNT DW 0 ;# hidden files
HIDSIZ DW 0 ;# alloc units in hidden files
BADSIZ DW 0 ;# alloc units in bad sectors
ORPHCNT DW 0 ;# orphan files made
ORPHSIZ DW 0 ;# alloc units in orphan files
LCLUS DW 0 ;# alloc units in lost clusters
DISPFLG DB 0 ;used by number routines
CROSSCNT DW 0 ;# crosslinked files (first pass)
SECONDPASS DB 0 ;Pass flag
HAVFIX DB 0 ;non zero if any fixes
DOFIX DB 0 ;flag for F switch
NOISY DB 0 ;flag for V switch
USERDIR DB "/",0 ;Users current dir for drive
DB (DIRSTRLEN-1) DUP (?)
CONBUF DB 15,0 ;Input buffer
DB 15 DUP (?)
CONST ENDS
SUBTTL Un-initialized Data
PAGE
DATA SEGMENT PUBLIC WORD
PUBLIC ZEROTRUNC,NAMBUF,MCLUS,THISDPB,STACKLIM,ERRCNT
PUBLIC SRFCBPT,ISCROSS,CSIZE,DSIZE,SSIZE,FAT,FATMAP
PUBLIC HARDCH,CONTCH,USERDEV,SECBUF,DOTSNOGOOD
HARDCH DD ? ;Pointer to real INT 24 handler
CONTCH DD ? ;Pointer to real INT 23 handler
THISDPB DD ? ;Pointer to drive DPB
USERDEV DB ? ;Users current device
CSIZE DB ? ;Sectors per cluster
SSIZE DW ? ;bytes per sector
DSIZE DW ? ;# alloc units on disk
MCLUS DW ? ;DSIZE + 1
NAMBUF DB 14 DUP (?) ;Buffer
DOTSNOGOOD DB ? ;. or .. error flag
ZEROTRUNC DB ? ;Trimming flag
ISCROSS DB ? ;Crosslink flag
OLDCLUS DW ?
SRFCBPT DW ?
FATMAP DW OFFSET DG:FAT ;Offset of FATMAP table
SECBUF DW ? ;Offset of sector buffer
ERRCNT DB ? ;Used by FATread and write
STACKLIM DW ? ;Stack growth limit
INTERNATVARS internat_block <>
DB (internat_block_max - ($ - INTERNATVARS)) DUP (?)
FAT LABEL WORD
DATA ENDS
SUBTTL Start of CHKDSK
CODE SEGMENT PUBLIC
ASSUME CS:DG,DS:DG,ES:DG,SS:DG
PUBLIC SUBERRP,DOTCOMBMES,FIGREC,FCB_TO_ASCZ,PRTCHR,EPRINT
PUBLIC PRINT,DOCRLF,DISP16BITS,DISP32BITS,DISPCLUS,CHECKFILES
EXTRN RDSKERR:NEAR,SETSWITCH:NEAR,PROMPTYN:NEAR,REPORT:NEAR
EXTRN PRINTCURRDIRERR:NEAR,PRINTTHISEL2:NEAR,CHECKERR:NEAR
EXTRN INT_23:NEAR,INT_24:NEAR,FINDCHAIN:NEAR,DONE:NEAR,AMDONE:NEAR
EXTRN FATAL:NEAR,DIRPROC:NEAR,CHKMAP:NEAR,CHKCROSS:NEAR,UNPACK:NEAR
ORG 100H
CHKDSK:
JMP SHORT CHSTRT
HEADER DB "Ver 2.30"
CHSTRT:
;Code to print header.
; PUSH AX
; MOV DX,OFFSET DG:HEADER
; CALL PRINT
; POP AX
PUSH AX ;Save DRIVE validity info
MOV AH,GET_VERSION
INT 21H
XCHG AH,AL ;Turn it around to AH.AL
CMP AX,DOSVER_LOW
JB GOTBADDOS
CMP AX,DOSVER_HIGH
JBE OKDOS
GOTBADDOS:
MOV DX,OFFSET DG:BADVER
JMP CERROR
OKDOS:
POP AX ;Get back drive info
MOV BX,0FFF0H
MOV DX,SP
CMP DX,BX
JAE STACKOK ;Lots of stack
MOV DX,DS:[2] ;High break
MOV CX,CS
SUB DX,CX
CMP DX,0FFFH
JAE SETSTACK ;Lots to grab
MOV CX,4 ;Suck up more stack (blast command)
SHL DX,CL
MOV BX,DX
SETSTACK:
CLI
MOV SP,BX
STI
STACKOK:
PUSH AX
MOV AH,DISK_RESET ;Flush everything, and invalidate
INT 21H
POP AX
CMP AL,0FFH ;Illegal drive specifier?
JNZ FILECHK ;No -- check for filename
DRVERR:
MOV DX,OFFSET DG:BADDRV
CERROR:
PUSH CS ;Make sure DS is OK
POP DS
CALL PRINT ;Print error message
INT 20H
CERROR2:
PUSH DX
CALL DONE ;Reset users disk
POP DX
JMP SHORT CERROR
FILECHK:
MOV AX,(CHAR_OPER SHL 8)
INT 21H
MOV [SWITCHAR],DL
CMP DL,"/"
JNZ SLASHOK
MOV [DIRCHAR],"\"
MOV [USERDIR],"\"
SLASHOK:
CMP DS:(BYTE PTR FCB+1)," " ;Filename specified?
JZ DRVCHK ;No -- get the correct drive
MOV AL,[SWITCHAR]
CMP DS:(BYTE PTR FCB+1),AL ;Filename specified?
JZ DRVCHK ;No -- get the correct drive
MOV BYTE PTR [FRAGMENT],1 ;Set flag to perform fragment
;check on specified files
DRVCHK:
CALL SETSWITCH ;Look for switches
MOV AH,GET_DEFAULT_DRIVE ;Get current drive
INT 21H
MOV [USERDEV],AL ;Save for later
MOV AH,AL
INC AH ;A = 1
MOV BH,DS:(BYTE PTR FCB) ;See if drive specified
OR BH,BH
JZ SETDSK
MOV AL,BH
MOV AH,AL
DEC AL ;A = 0
SETDSK:
MOV [ALLDRV],AH ;Target drive
MOV [VOLNAM],AH ;A = 1
MOV [ORPHFCB],AH ;A = 1
ADD [BADDRVM],AL ;A = 0
ADD [BADDRVM2],AL ;A = 0
MOV DL,AH ;A = 1
MOV AH,GET_DPB ;Get the DPB
INT 21H
ASSUME DS:NOTHING
CMP AL,-1
JNZ DRVISOK ;Bad drive (should always be ok)
MOV DX,OFFSET DG:BADDRV
CERROR2J: JMP CERROR2
DRVISOK:
DEC DL ;A = 0
MOV AH,SET_DEFAULT_DRIVE ;Set Target
INT 21H
CMP [BX.dpb_current_dir],0
JZ CURRISROOT ;Save users current dir for target
MOV SI,BX
ADD SI,dpb_dir_text
MOV DI,OFFSET DG:USERDIR + 1
SETDIRLP:
LODSB
STOSB
OR AL,AL
JZ CURRISROOT
JMP SHORT SETDIRLP
CURRISROOT:
MOV WORD PTR [THISDPB+2],DS
PUSH CS
POP DS
ASSUME DS:DG
MOV WORD PTR [THISDPB],BX
MOV AX,(GET_INTERRUPT_VECTOR SHL 8) OR 23H
INT 21H
MOV WORD PTR [CONTCH],BX
MOV WORD PTR [CONTCH+2],ES
MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H
MOV DX,OFFSET DG:INT_23
INT 21H
MOV AX,(GET_INTERRUPT_VECTOR SHL 8) OR 24H
INT 21H
MOV WORD PTR [HARDCH],BX
MOV WORD PTR [HARDCH+2],ES
MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 24H
MOV DX,OFFSET DG:INT_24
INT 21H
PUSH CS
POP ES
MOV DX,OFFSET DG:ROOTSTR
MOV AH,CHDIR ;Start at root
INT 21H
MOV DX,OFFSET DG:BADCD
JC CERROR2J ;Couldn't get there
MOV DX,OFFSET DG:FAT ;Scratch space
MOV AH,SET_DMA
INT 21H
MOV DX,OFFSET DG:VOLID ;Look for VOL ID
MOV AH,DIR_SEARCH_FIRST
INT 21H
CMP AL,-1
JZ NOTVOLID
CALL PRINTID ;Have a VOL ID
NOTVOLID:
LDS BX,[THISDPB]
ASSUME DS:NOTHING
MOV AX,[BX.dpb_sector_size]
MOV [SSIZE],AX ;Sector size in bytes
MOV AL,[BX.dpb_cluster_mask]
INC AL
MOV [CSIZE],AL ;Sectros per cluster
MOV AX,[BX.dpb_max_cluster]
MOV [MCLUS],AX ;Bound for FAT searching
DEC AX
MOV [DSIZE],AX ;Total data clusters on disk
MOV AL,[BX.dpb_FAT_size] ;Sectors for one fat
XOR AH,AH
MOV CX,AX
MUL [SSIZE] ;Bytes for FAT
ADD [FATMAP],AX ;Allocate FAT space
MOV AX,[FATMAP]
ADD AX,[MCLUS]
ADD AX,2 ;Insurance
MOV [SECBUF],AX ;Allocate FATMAP space
ADD AX,[SSIZE]
ADD AX,20 ;Insurance
MOV [STACKLIM],AX ;Limit on recursion
MOV DI,CX
MOV CL,[BX.dpb_FAT_count] ;Number of FATs
MOV DX,[BX.dpb_first_FAT] ;First sector of FAT
PUSH CS
POP DS
ASSUME DS:DG
MOV BX,OFFSET DG:FAT
MOV AL,[ALLDRV]
DEC AL
MOV AH,'1'
RDLOOP:
XCHG CX,DI
PUSH DX
PUSH CX
PUSH DI
PUSH AX
INT 25H ;Read in the FAT
MOV [HECODE],AL
POP AX ;Flags
JNC RDOK
MOV DX,OFFSET DG:BADREAD_PRE ;Barfed
CALL PRINT
POP AX
PUSH AX
MOV DL,AH
CALL PRTCHR
MOV DX,OFFSET DG:BADREAD_POST
CALL PRINT
POP AX
POP CX
POP DI
POP DX
INC AH
ADD DX,DI
LOOP RDLOOP ;Try next FAT
CALL RDSKERR
JNZ NORETRY1
JMP NOTVOLID
NORETRY1:
MOV BX,OFFSET DG:BADRDMES
JMP FATAL ;Couldn't read any FAT, BARF
RDOK:
POP AX ;Clean up
POP AX
POP AX
POP AX
MOV SI,OFFSET DG:FAT
LODSB ;Check FAT ID byte
CMP AL,0F8H
JAE IDOK
MOV DX,OFFSET DG:BADIDBYT ;FAT ID bad
CALL PROMPTYN ;Ask user
JZ IDOK
JMP ALLDONE ;User said stop
IDOK:
MOV DI,[FATMAP]
MOV CX,[MCLUS]
INC CX
XOR AL,AL
REP STOSB ;Initialize FATMAP to all free
MOV DX,OFFSET DG:DIRBUF ;FOR ALL SEARCHING
MOV AH,SET_DMA
INT 21H
XOR AX,AX
PUSH AX ;I am root
PUSH AX ;Parent is root
CALL DIRPROC
CALL CHKMAP ;Look for badsectors, orphans
CALL CHKCROSS ;Check for second pass
CALL DOCRLF
CALL REPORT
ALLDONE:
CALL AMDONE
INT 20H ;Fini
ASSUME DS:DG
SUBTTL Check for extents in specified files
PAGE
CHECKFILES:
;Search the directory for the files specified on the command line
;and report the number of fragmented allocation units found in
;each one.
CALL DOCRLF
MOV AH,SET_DMA
MOV DX,[FATMAP] ;Use the first free space available
MOV BP,DX
ADD BP,27 ;cluster in the directory entry
INT 21H
MOV AH,DIR_SEARCH_FIRST ;Look for the first file
FRAGCHK:
MOV DX,FCB
INT 21H
OR AL,AL ;Did we find it?
JNZ MSGCHK ;No -- we're done
XOR AX,AX ;Initialize the fragment counter
MOV SI,[BP] ;Get the first cluster
CALL UNPACK
CMP DI,0FF8H ;End-of-file?
JAE NXTCHK ;Yes -- go report the results
INC SI
CMP SI,DI
JZ EACHCLUS
INC AX
EACHCLUS:
MOV [OLDCLUS],DI ;Save the last cluster found
MOV SI,DI ;Get the next cluster
CALL UNPACK
INC [OLDCLUS] ;Bump the old cluster
CMP DI,[OLDCLUS] ;Are they the same?
JNZ LASTCLUS ;No -- check for end-of-file
JMP SHORT EACHCLUS ;Continue processing
LASTCLUS:
CMP DI,0FF8H ;End-of-file?
JAE NXTCHK ;Yes -- go report the results
INC AX ;No -- found a fragement
JMP SHORT EACHCLUS ;Continue processing
NXTCHK:
OR AX,AX
JZ GETNXT
MOV [FRAGMENT],2 ;Signal that we output at least one file
PUSH AX ;Save count of fragments
MOV SI,[FATMAP]
INC SI
CALL PRINTTHISEL2
CALL DOCRLF
MOV DX,OFFSET DG:CONTAINS ;Print message
CALL PRINT
POP SI ;Number of fragments found
INC SI ;Number non-contig blocks
XOR DI,DI
MOV BX,OFFSET DG:EXTENTS
PUSH BP
CALL DISP16BITS
POP BP
GETNXT:
MOV AH,DIR_SEARCH_NEXT ;Look for the next file
JMP FRAGCHK
MSGCHK:
CMP AH,DIR_SEARCH_FIRST
JNZ FILSPOK
MOV SI,FCB + 1 ;File not found error
CALL PRINTTHISEL2
CALL DOCRLF
MOV DX,OFFSET DG:OPNERR
CALL PRINT ;Bad file spec
RET
FILSPOK:
CMP BYTE PTR [FRAGMENT],2
JZ CDONE
MOV DX,OFFSET DG:NOEXTENTS
CALL PRINT
CDONE:
RET
FIGREC:
;Convert cluster number in BX to sector # AH of cluster in DX
LDS DI,[THISDPB]
ASSUME DS:NOTHING
MOV CL,[DI.dpb_cluster_shift]
MOV DX,BX
DEC DX
DEC DX
SHL DX,CL
OR DL,AH
ADD DX,[DI.dpb_first_sector]
PUSH CS
POP DS
ASSUME DS:DG
RET
SUBTTL PRINTID - Print Volume ID info
PAGE
PRINTID:
ASSUME DS:DG
MOV DX,OFFSET DG:INTERNATVARS
MOV AX,INTERNATIONAL SHL 8
INT 21H
MOV [DISPFLG],1 ;Don't sub spaces for leading zeros
MOV SI,OFFSET DG:FAT + 8
MOV DI,OFFSET DG:VNAME
MOV CX,11
REP MOVSB
MOV DX,OFFSET DG:IDMES1
CALL PRINT ;Print ID message
ADD SI,13
LODSW ;Get date
PUSH SI
MOV DX,AX
MOV AX,[INTERNATVARS.Date_tim_format]
OR AX,AX
JZ USPDAT
DEC AX
JZ EUPDAT
CALL P_YR
CALL P_DSEP
CALL P_MON
CALL P_DSEP
MOV CX,1000H ;Do not supress leading zeroes
CALL P_DAY
JMP P_TIME
USPDAT:
CALL P_MONTH_NAM
MOV CX,1110H ;Supress at most 1 leading 0
CALL P_DAY
PUSH DX
MOV DL,','
CALL PRTCHR
MOV DL,' '
CALL PRTCHR
POP DX
PYA:
CALL P_YR
JMP P_TIME
EUPDAT:
MOV CX,1110H ;Supress at most 1 leading 0
CALL P_DAY
PUSH DX
MOV DL,' '
CALL PRTCHR
POP DX
CALL P_MONTH_NAM
JMP PYA
P_DSEP:
PUSH DX
MOV DL,[INTERNATVARS.Date_sep]
CALL PRTCHR
POP DX
RET
P_MONTH_NAM:
MOV AX,DX
PUSH DX
MOV CL,5
SHR AX,CL
AND AX,0FH ;Month in AX
DEC AX ;Make 0 indexed
MOV CX,AX
SHL AX,1
ADD AX,CX ;Mult by 3 chars/mo
MOV SI,OFFSET DG:MONTAB
ADD SI,AX
LODSB
MOV DL,AL
CALL PRTCHR
LODSB
MOV DL,AL
CALL PRTCHR
LODSB
MOV DL,AL
CALL PRTCHR
MOV DL,' '
CALL PRTCHR
POP DX
RET
P_MON:
MOV SI,DX
PUSH DX
MOV CL,5
SHR SI,CL
AND SI,0FH ;Month in SI
CALL CONVERT
MOV DL,AL
MOV CX,1000H ;Do not supress leading 0
CALL OUTBYTE ;Print month
POP DX
RET
P_DAY:
MOV SI,DX
PUSH DX
PUSH CX
AND SI,01FH ;SI has day
CALL CONVERT
POP CX
MOV DL,AL
CALL OUTBYTE ;Print day
POP DX
RET
P_YR:
MOV SI,DX
PUSH DX
MOV CL,9
SHR SI,CL
AND SI,07FH ;SI has raw year
ADD SI,1980 ;Real year
CALL CONVERT
MOV CX,1000H ;Do not supress leading zeros
CALL OUTWORD ;Print year
POP DX
RET
P_TIME:
MOV DL,' '
CALL PRTCHR
POP SI
ADD SI,-4
LODSW ;Get time
MOV DI,AX
MOV SI,DI
MOV CL,11
SHR SI,CL
AND SI,01FH ;SI has hour
CMP [INTERNATVARS.Time_24],0
JNZ ISOK2 ;24 hour time?
CMP SI,12
JB ISOK ;Is AM
MOV [TCHAR],'p'
JZ ISOK ;Is 12-1p
SUB SI,12 ;Is PM
ISOK:
OR SI,SI
JNZ ISOK2
MOV SI,12 ;0 is 12a
ISOK2:
CALL CONVERT
MOV CX,1110H ;Supress at most 1 leading 0
MOV DL,AL
CALL OUTBYTE ;Print hour
MOV DL,BYTE PTR [INTERNATVARS.Time_sep]
CALL PRTCHR
MOV SI,DI
MOV CL,5
SHR SI,CL
AND SI,03FH ;SI has minute
CALL CONVERT
MOV CX,1000H ;Do not supress leading zeroes
MOV DL,AL
CALL OUTBYTE ;Print minute
MOV DL,[TCHAR]
CMP [INTERNATVARS.Time_24],0
JNZ NOAP ;24 hour time, no a or p
CALL PRTCHR ;Print a or p
NOAP:
MOV DX,OFFSET DG:IDPOST
CALL PRINT
MOV [DISPFLG],0
RET
CONVERT:
MOV CX,16
XOR AX,AX
CNVLOOP:
SHL SI,1
CALL CONVWRD
CLC
LOOP CNVLOOP
RET
SUBTTL Misc Routines - Mostly I/O
PAGE
CONVWRD:
ADC AL,AL
DAA
XCHG AL,AH
ADC AL,AL
DAA
XCHG AL,AH
RET1: RET
UNSCALE:
SHR CX,1
JC RET1
SHL SI,1
RCL DI,1
JMP SHORT UNSCALE
DISP16BITS:
MOV BYTE PTR DISPFLG,1
JMP SHORT DISP32BITS
DISPCLUS:
MUL [SSIZE]
MOV CL,[CSIZE]
XOR CH,CH
MOV SI,AX
MOV DI,DX
CALL UNSCALE
DISP32BITS:
PUSH BP
PUSH BX
XOR AX,AX
MOV BX,AX
MOV BP,AX
MOV CX,32
CONVLP:
SHL SI,1
RCL DI,1
XCHG AX,BP
CALL CONVWRD
XCHG AX,BP
XCHG AX,BX
CALL CONVWRD
XCHG AX,BX
ADC AL,0
LOOP CONVLP
; Conversion complete
MOV CX,1310H ;Print 3-digit number with 2 leading blanks
CMP BYTE PTR DISPFLG,0
JNZ FOURDIG
MOV CX,1810H ;Print 8-digit number with 2 leading blanks
XCHG DX,AX
CALL DIGIT
XCHG AX,BX
CALL OUTWORD
FOURDIG:
MOV AX,BP
CALL OUTWORD
MOV BYTE PTR DISPFLG,0
POP DX
CALL PRINT
POP BP
RET
OUTWORD:
PUSH AX
MOV DL,AH
CALL OUTBYTE
POP DX
OUTBYTE:
MOV DH,DL
SHR DL,1
SHR DL,1
SHR DL,1
SHR DL,1
CALL DIGIT
MOV DL,DH
DIGIT:
AND DL,0FH
JZ BLANKZER
MOV CL,0
BLANKZER:
DEC CH
AND CL,CH
OR DL,30H
SUB DL,CL
CMP BYTE PTR DISPFLG,0
JZ PRTCHR
CMP DL,30H
JL RET2
PRTCHR:
MOV AH,STD_CON_OUTPUT
INT 21H
RET2: RET
PRINTCNT:
LODSB
MOV DL,AL
INT 21H
LOOP PRINTCNT
RET
EPRINT:
CALL CHECKERR
JNZ RET$1
JMP SHORT PRINT
DOCRLF:
MOV DX,OFFSET DG:CRLF
PRINT:
MOV AH,STD_CON_STRING_OUTPUT
INT 21H
RET$1: RET
DOTCOMBMES:
CMP [NOISY],0
JZ SUBERRP
PUSH DX
CALL PRINTCURRDIRERR
MOV DX,OFFSET DG:CENTRY
CALL EPRINT
POP DX
CALL EPRINT
CALL DOCRLF
RET
SUBERRP:
MOV AL,1
XCHG AL,[ERRSUB]
CMP AL,0
JNZ RET32
MOV SI,OFFSET DG:NUL
CALL PRINTCURRDIRERR
MOV DX,OFFSET DG:BADSUBDIR
CALL EPRINT
RET32: RET
FCB_TO_ASCZ: ;Convert DS:SI to ASCIIZ ES:DI
MOV CX,8
MAINNAME:
LODSB
CMP AL,' '
JZ SKIPSPC
STOSB
SKIPSPC:
LOOP MAINNAME
LODSB
CMP AL,' '
JZ GOTNAME
MOV AH,AL
MOV AL,'.'
STOSB
XCHG AL,AH
STOSB
MOV CL,2
EXTNAME:
LODSB
CMP AL,' '
JZ GOTNAME
STOSB
LOOP EXTNAME
GOTNAME:
XOR AL,AL
STOSB
RET
CODE ENDS
END CHKDSK

477
v2.0/source/CHKMES.ASM Normal file
View File

@ -0,0 +1,477 @@
TITLE CHKDSK Messages
FALSE EQU 0
TRUE EQU NOT FALSE
.xlist
.xcref
INCLUDE DOSSYM.ASM
;The DOST: prefix is a DEC TOPS/20 directory prefix. Remove it for
; assembly in MS-DOS assembly environments using MASM. The DOSSYM.ASM
; file must exist though, it is included with OEM distribution.
.cref
.list
CODE SEGMENT PUBLIC BYTE
CODE ENDS
CONST SEGMENT PUBLIC BYTE
EXTRN HIDSIZ:WORD,HIDCNT:WORD,DIRCNT:WORD,DIRSIZ:WORD,FILCNT:WORD
EXTRN FILSIZ:WORD,ORPHCNT:WORD,ORPHSIZ:WORD,BADSIZ:WORD,LCLUS:WORD
EXTRN DOFIX:BYTE
CONST ENDS
DATA SEGMENT PUBLIC BYTE
EXTRN DSIZE:WORD
DATA ENDS
DG GROUP CODE,CONST,DATA
CODE SEGMENT PUBLIC BYTE
ASSUME CS:DG,DS:DG,ES:DG,SS:DG
PUBLIC RDSKERR,WDSKERR,SETSWITCH,PROMPTYN,DOINT26,CHAINREPORT,REPORT
EXTRN RDONE:NEAR,PRTCHR:NEAR,PRINT:NEAR,DOCRLF:NEAR
EXTRN DISP16BITS:NEAR,FINDCHAIN:NEAR
EXTRN DISP32BITS:NEAR,DISPCLUS:NEAR
DOINT26:
PUSH CX
PUSH AX
PUSH DX
PUSH BX
INT 26H
MOV [HECODE],AL
POP AX ;FLAGS
POP BX
POP DX
POP AX
POP CX
JNC RET23
MOV SI,OFFSET DG:WRITING
CALL DSKERR
JZ DOINT26
RET23: RET
RDSKERR:
MOV SI,OFFSET DG:READING
JMP SHORT DSKERR
WDSKERR:
MOV SI,OFFSET DG:WRITING
DSKERR:
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH DI
PUSH ES
MOV AL,[HECODE]
CMP AL,12
JBE HAVCOD
MOV AL,12
HAVCOD:
XOR AH,AH
MOV DI,AX
SHL DI,1
MOV DX,WORD PTR [DI+MESBAS] ; Get pointer to error message
CALL PRINT ; Print error type
MOV DX,OFFSET DG:ERRMES
CALL PRINT
MOV DX,SI
CALL PRINT
MOV DX,OFFSET DG:DRVMES
CALL PRINT
ASK:
MOV DX,OFFSET DG:REQUEST
CALL PRINT
MOV AX,(STD_CON_INPUT_FLUSH SHL 8)+STD_CON_INPUT
INT 21H ; Get response
PUSH AX
CALL DOCRLF
POP AX
OR AL,20H ; Convert to lower case
CMP AL,"i" ; Ignore?
JZ EEXITNZ
CMP AL,"r" ; Retry?
JZ EEXIT
CMP AL,"a" ; Abort?
JNZ ASK
JMP RDONE
EEXITNZ:
OR AL,AL ; Resets zero flag
EEXIT:
POP ES
POP DI
POP DX
POP CX
POP BX
POP AX
RET
PROMPTYN:
;Prompt message in DX
;Prompt user for Y or N answer. Zero set if Y
PUSH SI
CALL PRINT
PAGAIN:
MOV DX,OFFSET DG:YES_NO
CALL PRINT
MOV DX,OFFSET DG:CONBUF
MOV AH,STD_CON_STRING_INPUT
INT 21H
CALL DOCRLF
MOV SI,OFFSET DG:CONBUF+2
CMP BYTE PTR [SI-1],0
JZ PAGAIN
LODSB
OR AL,20H ;Convert to lower case
CMP AL,'y'
JZ GOTANS
CMP AL,'n'
JZ GOTNANS
JMP PAGAIN
GOTNANS:
OR AL,AL ;Reset zero
GOTANS:
POP SI
RET
SETSWITCH:
;Look for F or V switch in command line
MOV SI,80H
LODSB
MOV DI,SI
MOV CL,AL
XOR CH,CH
JCXZ RET10 ;No parameters
MOV AL,[SWITCHAR]
MORESCAN:
REPNZ SCASB
JNZ RET10
JCXZ BADSWITCHA
MOV AH,[DI]
INC DI
OR AH,20H ;Convert to lower case
CMP AH,'f'
JNZ CHECKV
INC [DOFIX]
JMP SHORT CHEKMORE
CHECKV:
CMP AH,'v'
JZ SETNOISY
CALL BADSWITCH
JMP SHORT CHEKMORE
SETNOISY:
INC [NOISY]
CHEKMORE:
LOOP MORESCAN
RET
BADSWITCHA:
MOV AH,' ' ;Print a non switch
BADSWITCH:
PUSH AX
MOV DL,[SWITCHAR]
CALL PRTCHR
POP AX
PUSH AX
MOV DL,AH
CALL PRTCHR
MOV DX,OFFSET DG:BADSWMES
CALL PRINT
POP AX
RET10: RET
;**************************************
; Prints XXX lost clusters found in YYY chains message
; On entry SI is the XXX value and the YYY value is
; in ORPHCNT.
; NOTE:
; The DISP16BITS routine prints the number in DI:SI followed
; by the message pointed to by BX. If it is desired to
; print a message before the first number, point at the
; message with DX and call PRINT.
CHAINREPORT:
XOR DI,DI
MOV BX,OFFSET DG:ORPHMES2
CALL DISP16BITS
CALL FINDCHAIN
MOV BX,OFFSET DG:CHNUMMES
MOV SI,[ORPHCNT]
XOR DI,DI
CALL DISP16BITS ;Tell user how many chains found
RET
;*****************************************
;Prints all of the reporting data
;NOTE:
; The DISPCLUS, DISP16BITS and DISP32BITS routines
; print the number in DI:SI followed
; by the message pointed to by BX. If it is desired to
; print a message before the first number, point at the
; message with DX and call PRINT.
REPORT:
MOV AX,[DSIZE]
MOV BX,OFFSET DG:DSKSPC
CALL DISPCLUS ;Total size
CMP [HIDCNT],0
JZ USERLIN
MOV AX,[HIDSIZ] ;Hidden files
MOV BX,OFFSET DG:INMES
CALL DISPCLUS
MOV SI,[HIDCNT]
XOR DI,DI
MOV BX,OFFSET DG:HIDMES
CALL DISP16BITS
USERLIN:
CMP [DIRCNT],0
JZ DIRLIN
MOV AX,[DIRSIZ]
MOV BX,OFFSET DG:INMES
CALL DISPCLUS
MOV SI,[DIRCNT]
XOR DI,DI
MOV BX,OFFSET DG:DIRMES
CALL DISP16BITS
DIRLIN:
CMP [FILCNT],0
JZ ORPHLIN
MOV AX,[FILSIZ] ;Regular files
MOV BX,OFFSET DG:INMES
CALL DISPCLUS
MOV SI,[FILCNT]
XOR DI,DI
MOV BX,OFFSET DG:FILEMES
CALL DISP16BITS
ORPHLIN:
MOV AX,[ORPHSIZ]
OR AX,AX
JZ BADLIN
MOV BX,OFFSET DG:INMES ;Orphans
CMP [DOFIX],0
JNZ ALLSET1
MOV BX,OFFSET DG:INMES2 ;Orphans
ALLSET1:
CALL DISPCLUS
MOV SI,[ORPHCNT]
XOR DI,DI
MOV BX,OFFSET DG:ORPHMES
CALL DISP16BITS
BADLIN:
MOV AX,[BADSIZ]
OR AX,AX
JZ AVAILIN
MOV BX,OFFSET DG:BADSPC ;Bad sectors
CALL DISPCLUS
AVAILIN:
MOV AX,[DSIZE]
SUB AX,[DIRSIZ]
SUB AX,[FILSIZ]
SUB AX,[HIDSIZ]
SUB AX,[BADSIZ]
SUB AX,[ORPHSIZ]
SUB AX,[LCLUS]
MOV BX,OFFSET DG:FRESPC
CALL DISPCLUS ;Free space is whats left
MOV AX,DS:WORD PTR [2] ;Find out about memory
MOV DX,16
MUL DX
MOV SI,AX
MOV DI,DX
MOV BX,OFFSET DG:TOTMEM
CALL DISP32BITS
MOV AX,DS:WORD PTR [2]
MOV DX,CS
SUB AX,DX
MOV DX,16
MUL DX
MOV SI,AX
MOV DI,DX
MOV BX,OFFSET DG:FREMEM
CALL DISP32BITS
RET
CODE ENDS
CONST SEGMENT PUBLIC BYTE
EXTRN HECODE:BYTE,SWITCHAR:BYTE,NOISY:BYTE,DOFIX:BYTE,CONBUF:BYTE
PUBLIC CRLF2,CRLF,BADVER,BADDRV
PUBLIC BADSUBDIR,CENTRY,CLUSBAD,BADATT,BADSIZM
PUBLIC FIXMES,DIRECMES,CDDDMES
PUBLIC FREEBYMESF_PRE,FREEBYMES_PRE,FREEBYMESF_POST,FREEBYMES_POST
PUBLIC CREATMES,NDOTMES
PUBLIC BADTARG1,BADTARG2,BADCD,FATALMES,BADRDMES
PUBLIC BADDRVM,STACKMES,BADDPBDIR
PUBLIC BADDRVM2
PUBLIC NULNZ,NULDMES,BADCLUS,NORECDOT
PUBLIC NORECDDOT,IDMES1,IDPOST,VNAME,TCHAR
PUBLIC MONTAB,BADREAD_PRE,BADREAD_POST,BADWRITE_PRE
PUBLIC BADWRITE_POST,BADCHAIN,CROSSMES_PRE,CROSSMES_POST
PUBLIC FREEMES
PUBLIC OPNERR
PUBLIC CONTAINS,EXTENTS,NOEXTENTS,INDENT
PUBLIC BADIDBYT,PTRANDIR,PTRANDIR2
MESBAS DW OFFSET DG:ERR0
DW OFFSET DG:ERR1
DW OFFSET DG:ERR2
DW OFFSET DG:ERR3
DW OFFSET DG:ERR4
DW OFFSET DG:ERR5
DW OFFSET DG:ERR6
DW OFFSET DG:ERR7
DW OFFSET DG:ERR8
DW OFFSET DG:ERR9
DW OFFSET DG:ERR10
DW OFFSET DG:ERR11
DW OFFSET DG:ERR12
CRLF2 DB 13,10
CRLF DB 13,10,"$"
;Messages
BADVER DB "Incorrect DOS version",13,10,"$"
BADDRV DB "Invalid drive specification$"
BADSWMES DB " Invalid parameter",13,10,"$"
BADSUBDIR DB " Invalid sub-directory entry.",13,10,"$"
CENTRY DB " Entry has a bad $"
CLUSBAD DB " link$"
BADATT DB " attribute$"
BADSIZM DB " size$"
;"BADTARG1<name of dir followed by CR LF>BADTARG2"
BADTARG1 DB "Cannot CHDIR to $"
BADTARG2 DB " tree past this point not processed.",13,10,"$"
BADCD DB "Cannot CHDIR to root",13,10,"$"
FATALMES DB "Processing cannot continue.",13,10,"$"
BADRDMES DB "File allocation table bad drive "
BADDRVM DB "A.",13,10,"$"
STACKMES DB "Insufficient memory.",13,10,"$"
BADDPBDIR DB "Invalid current directory.",13,10,"$"
;INT 24 MESSAGE SHOULD AGREE WITH COMMAND
READING DB "read$"
WRITING DB "writ$"
ERRMES DB " error $"
DRVMES DB "ing drive "
BADDRVM2 DB "A",13,10,"$"
REQUEST DB "Abort, Retry, Ignore? $"
ERR0 DB "Write protect$"
ERR1 DB "Bad unit$"
ERR2 DB "Not ready$"
ERR3 DB "Bad command$"
ERR4 DB "Data$"
ERR5 DB "Bad call format$"
ERR6 DB "Seek$"
ERR7 DB "Non-DOS disk$"
ERR8 DB "Sector not found$"
ERR9 DB "No paper$"
ERR10 DB "Write fault$"
ERR11 DB "Read fault$"
ERR12 DB "Disk$"
NDOTMES DB " Does not exist.",13,10,"$"
NULNZ DB " First cluster number is invalid,",13,10
DB " entry truncated.",13,10,"$"
NULDMES DB " Directory is totally empty, no . or ..",13,10,"$"
BADCLUS DB " Allocation error, size adjusted.",13,10,"$"
NORECDOT DB " Cannot recover . entry, processing continued.",13,10,"$"
NORECDDOT DB " Cannot recover .. entry,"
;VOLUME ID
;"IDMES1/name at VNAME<date and time>IDPOST"
IDPOST DB 13,10,"$" ;WARNING this is currently the tail of
; the previos message!!!
IDMES1 DB "Volume "
VNAME DB 12 DUP(' ')
DB "created $"
TCHAR DB 'a'
MONTAB DB "JanFebMarAprMayJunJulAugSepOctNovDec"
;"BADREAD_PRE<# of FAT>BADREAD_POST"
BADREAD_PRE DB "Disk error reading FAT $"
;"BADWRITE_PRE<# of FAT>BADWRITE_POST"
BADWRITE_PRE DB "Disk error writing FAT $"
BADCHAIN DB " Has invalid cluster, file truncated."
BADREAD_POST LABEL BYTE
BADWRITE_POST LABEL BYTE
;"<name of file followed by CR LF>CROSSMES_PRE<# of cluster>CROSSMES_POST"
CROSSMES_POST DB 13,10,"$" ;WARNING Is tail of previos messages
CROSSMES_PRE DB " Is cross linked on cluster $"
;CHAINREPORT messages
ORPHMES2 DB " lost clusters found in $"
CHNUMMES DB " chains.",13,10,"$"
FREEMES DB "Convert lost chains to files $"
;REPORT messages
ORPHMES DB " recovered files",13,10,"$"
DSKSPC DB " bytes total disk space",13,10,"$"
INMES DB " bytes in $"
INMES2 DB " bytes would be in",13,10
DB " $"
FILEMES DB " user files",13,10,"$"
BADSPC DB " bytes in bad sectors",13,10,"$"
HIDMES DB " hidden files",13,10,"$"
DIRMES DB " directories",13,10,"$"
FRESPC DB " bytes available on disk",13,10,13,10,"$"
TOTMEM DB " bytes total memory",13,10,"$"
FREMEM DB " bytes free",13,10,13,10,"$"
;"<filename followed by CR LF>CONTAINS<# non-contig blocks>EXTENTS"
CONTAINS DB " Contains $"
EXTENTS DB " non-contiguous blocks.",13,10,"$"
NOEXTENTS DB "All specified file(s) are contiguous.",13,10,"$"
INDENT DB " $"
BADIDBYT DB "Probable non-DOS disk."
DB 13,10,"Continue $"
YES_NO DB "(Y/N)? $"
PTRANDIR DB " Unrecoverable error in directory.",13,10
PTRANDIR2 DB " Convert directory to file $"
FIXMES DB 13,10,"Errors found, F parameter not specified."
DB 13,10,"Corrections will not be written to disk.",13,10,13,10,"$"
DIRECMES DB "Directory $"
CDDDMES DB " CHDIR .. failed, trying alternate method.",13,10,"$"
FREEBYMESF_POST DB " bytes disk space freed.",13,10
FREEBYMESF_PRE DB "$"
FREEBYMES_POST DB " bytes disk space",13,10
DB " would be freed.",13,10
FREEBYMES_PRE DB "$"
CREATMES DB "Insufficient room in root directory."
DB 13,10,"Erase files in root and repeat CHKDSK.",13,10,"$"
OPNERR DB " File not found.",13,10,"$"
CONST ENDS
END

1408
v2.0/source/CHKPROC.ASM Normal file

File diff suppressed because it is too large Load Diff

33
v2.0/source/COMEQU.ASM Normal file
View File

@ -0,0 +1,33 @@
;*************************************
; COMMAND EQUs which are not switch dependant
IFDEF IBM
INCLUDE IFEQU.ASM
ENDIF
SYM EQU ">"
LINPERPAG EQU 23
NORMPERLIN EQU 1
WIDEPERLIN EQU 5
COMBUFLEN EQU 128 ; Length of commmand buffer
DRVCHAR EQU ":"
FCB EQU 5CH
VARSTRUC STRUC
ISDIR DB ?
SIZ DB ?
TTAIL DW ?
INFO DB ?
BUF DB DIRSTRLEN + 20 DUP (?)
VARSTRUC ENDS
WSWITCH EQU 1 ; Wide display during DIR
PSWITCH EQU 2 ; Pause (or Page) mode during DIR
ASWITCH EQU 4 ; ASCII mode during COPY
BSWITCH EQU 8 ; Binary mode during COPY
VSWITCH EQU 10H ; Verify switch
GOTSWITCH EQU 8000H ; Meta switch set if switch character encountered

BIN
v2.0/source/COMLINK Normal file

Binary file not shown.

788
v2.0/source/COMMAND.ASM Normal file
View File

@ -0,0 +1,788 @@
;
; This version of COMMAND is divided into three distinct parts. First is the
; resident portion, which includes handlers for interrupts 22H (terminate),
; 23H (Cntrl-C), 24H (fatal error), and 27H (stay resident); it also has code
; to test and, if necessary, reload the transient portion. Following the
; resident is the init code, which is overwritten after use. Then comes the
; transient portion, which includes all command processing (whether internal
; or external). The transient portion loads at the end of physical memory,
; and it may be overlayed by programs that need as much memory as possible.
; When the resident portion of command regains control from a user program, a
; checksum is performed on the transient portion to see if it must be
; reloaded. Thus programs which do not need maximum memory will save the time
; required to reload COMMAND when they terminate.
;
; REV 1.17
; 05/19/82 Fixed bug in BADEXE error (relocation error must return to
; resident since the EXELOAD may have overwritten the transient.
; REV 1.18
; 05/21/82 IBM version always looks on drive A
; MSVER always looks on default drive
;
; REV 1.19
; 06/03/82 Drive spec now entered in command line
; 06/07/82 Added VER command (print DOS version number) and VOL command
; (print volume label)
; REV 1.20
; 06/09/82 Prints "directory" after directories
; 06/13/82 MKDIR, CHDIR, PWD, RMDIR added
; REV 1.50
; Some code for new 2.0 DOS, sort of HACKey. Not enough time to
; do it right.
; REV 1.70
; EXEC used to fork off new processes
; REV 1.80
; C switch for single command execution
; REV 1.90
; Batch uses XENIX
; Rev 2.00
; Lots of neato stuff
; IBM 2.00 level
; Rev 2.01
; 'D' switch for date time suppression
; Rev 2.02
; Default userpath is NUL rather than BIN
; same as IBM
; COMMAND split into pieces
; Rev 2.10
; INTERNATIONAL SUPPORT
; Rev 2.11 COMMAND split into more pieces
INCLUDE DOSSYM.ASM
INCLUDE DEVSYM.ASM
INCLUDE COMSW.ASM
INCLUDE COMEQU.ASM
CODERES SEGMENT PUBLIC
CODERES ENDS
DATARES SEGMENT PUBLIC BYTE
EXTRN COMBAD:BYTE,NEEDCOM:BYTE,DRVMSG:BYTE
EXTRN DEFMSG:BYTE,PROMPT:BYTE,EXECEMES:BYTE,EXEBAD:BYTE
EXTRN TOOBIG:BYTE,NOCOM:BYTE,RBADNAM:BYTE,INT_2E_RET:DWORD
EXTRN NOHANDMES:BYTE,BMEMMES:BYTE,HALTMES:BYTE,FRETMES:BYTE
EXTRN PARENT:WORD,HANDLE01:WORD,LOADING:BYTE,BATCH:WORD
EXTRN TRNSEG:WORD,COMDRV:BYTE,MEMSIZ:WORD,SUM:WORD,EXTCOM:BYTE
EXTRN IO_SAVE:WORD,PERMCOM:BYTE,SINGLECOM:WORD,VERVAL:WORD
EXTRN PIPEFLAG:BYTE,SAVE_PDB:WORD,COMSPEC:BYTE,TRANS:WORD
EXTRN TRANVARS:BYTE,LTPA:WORD,RSWITCHAR:BYTE,RDIRCHAR:BYTE
EXTRN RETCODE:WORD,FORFLAG:BYTE
IF IBMVER
EXTRN SYS_CALL:DWORD,ZEXEC:WORD,EXESEG:WORD,EXESUM:WORD
EXTRN USER_SS:WORD,USER_SP:WORD
ENDIF
DATARES ENDS
ENVIRONMENT SEGMENT PUBLIC PARA ; Default COMMAND environment
ENVIRONMENT ENDS
INIT SEGMENT PUBLIC PARA
EXTRN CONPROC:NEAR
INIT ENDS
TAIL SEGMENT PUBLIC PARA
TAIL ENDS
TRANCODE SEGMENT PUBLIC PARA
TRANCODE ENDS
TRANDATA SEGMENT PUBLIC BYTE
EXTRN TRANDATAEND:BYTE
TRANDATA ENDS
TRANSPACE SEGMENT PUBLIC BYTE
EXTRN TRANSPACEEND:BYTE,HEADCALL:DWORD
TRANSPACE ENDS
TRANTAIL SEGMENT PUBLIC PARA
TRANTAIL ENDS
ZEXEC_CODE SEGMENT PUBLIC PARA
ZEXEC_CODE ENDS
ZEXEC_DATA SEGMENT PUBLIC BYTE
ZEXEC_DATA ENDS
RESGROUP GROUP CODERES,DATARES,ENVIRONMENT,INIT,TAIL
TRANGROUP GROUP TRANCODE,TRANDATA,TRANSPACE,TRANTAIL
EGROUP GROUP ZEXEC_CODE,ZEXEC_DATA
ENVIRONMENT SEGMENT PUBLIC PARA ; Default COMMAND environment
PUBLIC ECOMSPEC,ENVIREND,PATHSTRING
ORG 0
ENVARENA DB 10H DUP (?) ; Pad for mem arena
PATHSTRING DB "PATH="
USERPATH LABEL BYTE
DB 0 ; Null path
DB "COMSPEC="
ECOMSPEC DB "/COMMAND.COM"
DB 134 DUP (0)
ENVIREND LABEL BYTE
ENVIRONSIZ EQU $-PATHSTRING
ENVIRONSIZ2 EQU $-ECOMSPEC
ENVIRONMENT ENDS
; START OF RESIDENT PORTION
CODERES SEGMENT PUBLIC
PUBLIC GETCOMDSK2,LODCOM,THEADFIX,CONTCTERM,LOADCOM,INT_2E,LODCOM1
PUBLIC CHKSUM,SETVECT,EXT_EXEC,TREMCHECK,RESTHAND,CONTC,RSTACK
PUBLIC SAVHAND
IF IBMVER
PUBLIC EXECHK,SYSCALL,EXEC_WAIT
ENDIF
ASSUME CS:RESGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
EXTRN RPRINT:NEAR,ASKEND:NEAR,DSKERR:NEAR
ORG 0
ZERO = $
ORG 100H
PROGSTART:
JMP RESGROUP:CONPROC
DB (80H - 3) DUP (?)
RSTACK LABEL WORD
IF IBMVER
SYSCALL:
CMP AH,EXEC
JZ do_exec
JMP DWORD PTR [SYS_CALL]
do_exec:
PUSH ES
PUSH DS
PUSH BP
PUSH DI
PUSH SI
PUSH DX
PUSH CX
PUSH BX
PUSH AX
MOV [user_ss],SS
MOV [user_sp],SP
;
; are we running on RSTACK already?
;
PUSH CS
POP BX ; BX <- CS
PUSH SS
POP AX ; AX <- SS
CMP AX,BX ; IF AX == BX then no stack switch!
JZ Get_mem
MOV SS,BX
ASSUME SS:RESGROUP
MOV SP,OFFSET RESGROUP:RSTACK
Get_mem:
MOV BX,0FFFFH ; allocate all of memory
MOV AH,ALLOC
INT int_command
MOV AX,OFFSET EGROUP:ZEXECDATAEND + 15
MOV CL,4
SHR AX,CL
MOV CX,AX ; Save in CX
CMP BX,AX ; enough for EXEC?
JB EXECMER ; nope... cry
MOV AH,ALLOC
INT int_command
JC EXECMER ; Memory arenas probably trashed
ADD BX,AX
MOV [MEMSIZ],BX
SUB BX,CX
MOV [EXESEG],BX ; exec
MOV ES,AX
MOV AH,DEALLOC
INT int_command
PUSH CS
POP DS
ASSUME DS:RESGROUP
CALL EXECHK
CMP DX,[EXESUM]
JZ HAVEXEC ; EXEC OK
MOV DX,OFFSET RESGROUP:COMSPEC
MOV AX,OPEN SHL 8
INT int_command ; Open COMMAND.COM
JC EXECMER
MOV BX,AX ; Handle
MOV DX,OFFSET RESGROUP:TRANSTART
ADD DX,OFFSET TRANGROUP:EXECSTART - 100H
XOR CX,CX ; Seek loc
MOV AX,LSEEK SHL 8
INT int_command
MOV CX,OFFSET EGROUP:ZEXECCODEEND
MOV DS,[EXESEG]
ASSUME DS:NOTHING
MOV AH,READ
INT int_command
PUSH AX
MOV AH,CLOSE
INT int_command ; Close COMMAND.COM
POP CX
CMP CX,OFFSET EGROUP:ZEXECCODEEND
JNZ EXECMER ; Size matched
CALL EXECHK
CMP DX,[EXESUM]
JNZ EXECMER
HAVEXEC:
MOV [LOADING],0 ; Flag to DSKERR
CALL DWORD PTR [ZEXEC]
JMP SHORT EXECRET
execmer:
LDS SI,DWORD PTR [user_Sp]
MOV [SI.user_AX],exec_not_enough_memory
PUSH [SI.user_F]
POPF
STC
PUSHF
POP [SI.user_F]
execret:
MOV SS,[user_SS]
ASSUME SS:NOTHING
MOV SP,[user_SP]
POP AX ; PUSH ES
POP BX ; PUSH DS
POP CX ; PUSH BP
POP DX ; PUSH DI
POP SI ; PUSH SI
POP DI ; PUSH DX
POP BP ; PUSH CX
POP DS ; PUSH BX
POP ES ; PUSH AX
IRET
EXECHK:
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
PUSH DS
MOV DS,[EXESEG]
MOV CX,OFFSET EGROUP:ZEXECCODEEND
XOR SI,SI
JMP CHECK_SUM
ENDIF
EXEC_ERR: ; Select the correct error message
MOV DX,OFFSET RESGROUP:RBADNAM
CMP AX,exec_file_not_found
JZ GOTEXECEMES
CMP AX,error_access_denied
JZ GOTEXECEMES
MOV DX,OFFSET RESGROUP:TOOBIG
CMP AX,exec_not_enough_memory
JZ GOTEXECEMES
MOV DX,OFFSET RESGROUP:EXEBAD
CMP AX,exec_bad_format
JZ GOTEXECEMES
MOV DX,OFFSET RESGROUP:EXECEMES
GOTEXECEMES:
PUSH CS
POP DS
CALL RPRINT
JMP SHORT NOEXEC
EXT_EXEC:
;
; we are now running in free space. anything we do from here
; on may get trashed. Move the stack (also in free space) to
; allocated space because since EXEC restores the stack,
; somebody may trash what is on the stack.
;
MOV CX,CS
MOV SS,CX
MOV SP,OFFSET RESGROUP:RSTACK
;
; Oops!! We have to make sure that the EXEC code doesn't blop a newstack!
;
;
INT int_command ; Do the EXEC
JC EXEC_ERR ; EXEC failed
EXEC_WAIT:
MOV AH,WAIT
INT int_command ; Get the return code
MOV [RETCODE],AX
NOEXEC:
JMP LODCOM
CONTC:
STI
MOV AX,CS
MOV DS,AX
ASSUME DS:RESGROUP
MOV AH,DISK_RESET
INT int_command ; Reset disks in case files were open
TEST [BATCH],-1
JZ CONTCTERM
JMP ASKEND ; See if user wants to terminate batch
CONTCTERM:
XOR BP,BP ; Indicate no read
MOV [FORFLAG],0 ; Turn off for processing
MOV [PIPEFLAG],0 ; Turn off any pipe
CMP [SINGLECOM],0 ; See if we need to set SINGLECOM
JZ NOSETSING
MOV [SINGLECOM],-1 ; Cause termination on pipe, batch, for
NOSETSING:
CMP [EXTCOM],0
JNZ DODAB ; Internal ^C
JMP LODCOM1
DODAB:
STC ; Tell DOS to abort
ZZY PROC FAR
RET ; Leave flags on stack
ZZY ENDP
BADMEMERR: ; Allocation error loading transient
MOV DX,OFFSET RESGROUP:BMEMMES
FATALC:
PUSH CS
POP DS
CALL RPRINT
CMP [PERMCOM],0
JZ FATALRET
CMP [SINGLECOM],0 ; If PERMCOM and SINGLECOM
JNZ FATALRET ; Must take INT_2E exit
MOV DX,OFFSET RESGROUP:HALTMES
CALL RPRINT
STALL:
JMP STALL ; Crash the system nicely
FATALRET:
MOV DX,OFFSET RESGROUP:FRETMES
CALL RPRINT
FATALRET2:
CMP [PERMCOM],0 ; If we get here and PERMCOM,
JNZ RET_2E ; must be INT_2E
IF IBM
LDS DX,DWORD PTR [SYS_CALL]
ASSUME DS:NOTHING
MOV AX,(SET_INTERRUPT_VECTOR SHL 8) + INT_COMMAND
INT int_command
ENDIF
MOV AX,[PARENT]
MOV WORD PTR CS:[PDB_Parent_PID],AX
MOV AX,(EXIT SHL 8) ; Return to lower level
INT int_command
RET_2E:
PUSH CS
POP DS
ASSUME DS:RESGROUP,ES:NOTHING,SS:NOTHING
MOV [SINGLECOM],0 ; Turn off singlecom
MOV ES,[LTPA]
MOV AH,DEALLOC
INT int_command ; Free up space used by transient
MOV BX,[SAVE_PDB]
MOV AH,SET_CURRENT_PDB
INT int_command ; Current process is user
MOV AX,[RETCODE]
CMP [EXTCOM],0
JNZ GOTECODE
XOR AX,AX ; Internals always return 0
GOTECODE:
MOV [EXTCOM],1 ; Force external
JMP [INT_2E_RET] ;"IRET"
INT_2E: ; Magic command executer
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
POP WORD PTR [INT_2E_RET]
POP WORD PTR [INT_2E_RET+2] ;Get return address
POP AX ;Chuck flags
PUSH CS
POP ES
MOV DI,80H
MOV CX,64
REP MOVSW
MOV AH,GET_CURRENT_PDB
INT int_command ; Get user's header
MOV [SAVE_PDB],BX
MOV AH,SET_CURRENT_PDB
MOV BX,CS
INT int_command ; Current process is me
MOV [SINGLECOM],81H
MOV [EXTCOM],1 ; Make sure this case forced
LODCOM: ; Termination handler
CMP [EXTCOM],0
JZ LODCOM1 ; If internal, memory already allocated
MOV BX,0FFFFH
MOV AH,ALLOC
INT int_command
MOV AX,OFFSET TRANGROUP:TRANSPACEEND + 15
MOV CL,4
SHR AX,CL
IF IBM
PUSH AX
MOV AX,OFFSET EGROUP:ZEXECDATAEND + 15
MOV CL,4
SHR AX,CL
POP CX
ADD AX,CX
ENDIF
ADD AX,20H
CMP BX,AX ; Is less than 512 byte buffer worth it?
JNC MEMOK
BADMEMERRJ:
JMP BADMEMERR ; Not enough memory
MEMOK:
MOV AH,ALLOC
INT int_command
JC BADMEMERRJ ; Memory arenas probably trashed
MOV [EXTCOM],0 ; Flag not to ALLOC again
MOV [LTPA],AX ; New TPA is base just allocated
ADD BX,AX
MOV [MEMSIZ],BX
MOV AX,OFFSET TRANGROUP:TRANSPACEEND + 15
MOV CL,4
SHR AX,CL
IF IBM
PUSH AX
MOV AX,OFFSET EGROUP:ZEXECDATAEND + 15
MOV CL,4
SHR AX,CL
POP CX
ADD AX,CX
ENDIF
SUB BX,AX
MOV [TRNSEG],BX ; Transient starts here
LODCOM1:
MOV AX,CS
MOV SS,AX
ASSUME SS:RESGROUP
MOV SP,OFFSET RESGROUP:RSTACK
MOV DS,AX
ASSUME DS:RESGROUP
CALL HEADFIX ; Make sure files closed stdin and stdout restored
XOR BP,BP ; Flag command ok
MOV AX,-1
XCHG AX,[VERVAL]
CMP AX,-1
JZ NOSETVER
MOV AH,SET_VERIFY_ON_WRITE ; AL has correct value
INT int_command
NOSETVER:
CMP [SINGLECOM],-1
JNZ NOSNG
JMP FATALRET2 ; We have finished the single command
NOSNG:
CALL SETVECT
IF IBMVER
CALL EXECHK ; Check exe loader
CMP DX,[EXESUM]
JNZ BOGUS_COM
ENDIF
CALL CHKSUM ; Check the transient
CMP DX,[SUM]
JZ HAVCOM ; Transient OK
BOGUS_COM:
MOV [LOADING],1 ; Flag DSKERR routine
CALL LOADCOM
CHKSAME:
IF IBMVER
CALL EXECHK
CMP DX,[EXESUM]
JNZ ALSO_BOGUS
ENDIF
CALL CHKSUM
CMP DX,[SUM]
JZ HAVCOM ; Same COMMAND
ALSO_BOGUS:
CALL WRONGCOM
JMP SHORT CHKSAME
HAVCOM:
MOV AX,CHAR_OPER SHL 8
INT int_command
MOV [RSWITCHAR],DL
CMP DL,'/'
JNZ USESLASH
MOV [RDIRCHAR],'\' ; Select alt path separator
USESLASH:
MOV [LOADING],0 ; Flag to DSKERR
MOV SI,OFFSET RESGROUP:TRANVARS
MOV DI,OFFSET TRANGROUP:HEADCALL
MOV ES,[TRNSEG]
CLD
MOV CX,8
REP MOVSW ; Transfer INFO to transient
MOV AX,[MEMSIZ]
MOV WORD PTR DS:[PDB_block_len],AX ; Adjust my own header
JMP DWORD PTR [TRANS]
; Far call to REMCHECK for TRANSIENT
TREMCHECK PROC FAR
CALL REMCHECK
RET
TREMCHECK ENDP
REMCHECK:
;All registers preserved. Returns zero if media removable, NZ if fixed
; AL is drive (0=DEF, 1=A,...)
IF IBM
PUSH AX
OR AL,AL
JNZ GOTDRV2
MOV AH,GET_DEFAULT_DRIVE
INT int_command
INC AL ;A=1
GOTDRV2:
PUSH BX
MOV BL,AL
INT 11H ;IBM EQUIP CALL
ROL AL,1
ROL AL,1
AND AL,3
JNZ NOT_SINGLE
INC AL
NOT_SINGLE:
INC AL ; AL is now MAX floppy #
CMP BL,AL
POP BX
JBE SETREM ; Is an IBM floppy and so is removable
OR AL,AL ; Know AL is non-zero
JMP SHORT SETNREM
SETREM:
ELSE
PUSH AX
ENDIF
XOR AX,AX ;Zero
IF IBM
SETNREM:
ENDIF
POP AX
RET
; Far call to HEADFIX for TRANSIENT
THEADFIX PROC FAR
CALL HEADFIX
RET
THEADFIX ENDP
HEADFIX:
XOR BX,BX ; Clean up header
MOV CX,[IO_SAVE]
MOV DX,WORD PTR DS:[PDB_JFN_Table]
CMP CL,DL
JZ CHK1 ; Stdin matches
MOV AH,CLOSE
INT int_command
MOV DS:[PDB_JFN_Table],CL ; Restore stdin
CHK1:
INC BX
CMP CH,DH ; Stdout matches
JZ CHKOTHERHAND
MOV AH,CLOSE
INT int_command
MOV DS:[PDB_JFN_Table+1],CH ; Restore stdout
CHKOTHERHAND:
ADD BX,4 ; Skip 2,3,4
MOV CX,FilPerProc - 5 ; Already done 0,1,2,3,4
CLOSELOOP:
MOV AH,CLOSE
INT int_command
INC BX
LOOP CLOSELOOP
RET
SAVHAND:
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
PUSH DS
PUSH BX ; Set stdin to sterr, stdout to stderr
PUSH AX
MOV AH,GET_CURRENT_PDB
INT int_command ; Get user's header
MOV DS,BX
MOV AX,WORD PTR DS:[PDB_JFN_Table]
MOV [HANDLE01],AX ; Save user's stdin, stdout
MOV AL,DS:[PDB_JFN_Table+2]
MOV AH,AL
MOV WORD PTR DS:[PDB_JFN_Table],AX ; Dup stderr
POP AX
POP BX
POP DS
RET
ASSUME DS:RESGROUP
GETCOMDSK2:
CALL GETCOMDSK
JMP LODCOM1 ; Memory already allocated
RESTHAND:
PUSH DS
PUSH BX ; Restore stdin, stdout to user
PUSH AX
MOV AH,GET_CURRENT_PDB
INT int_command ; Point to user's header
MOV AX,[HANDLE01]
MOV DS,BX
ASSUME DS:NOTHING
MOV WORD PTR DS:[PDB_JFN_Table],AX ; Stuff his old 0 and 1
POP AX
POP BX
POP DS
RET
ASSUME DS:RESGROUP,SS:RESGROUP
HOPELESS:
MOV DX,OFFSET RESGROUP:NOCOM
JMP FATALC
GETCOMDSK:
MOV DX,OFFSET RESGROUP:NEEDCOM
GETCOMDSK3:
MOV AL,[COMDRV]
CALL REMCHECK
JNZ HOPELESS ;Non-removable media
CALL RPRINT
MOV DX,OFFSET RESGROUP:DRVMSG
CMP [COMDRV],0
JNZ GETCOM1
MOV DX,OFFSET RESGROUP:DEFMSG
GETCOM1:
CALL RPRINT
MOV DX,OFFSET RESGROUP:PROMPT
CALL RPRINT
CALL GetRawFlushedByte
RET
; flush world and get raw input
GetRawFlushedByte:
MOV AX,(STD_CON_INPUT_FLUSH SHL 8) OR RAW_CON_INPUT
INT int_command ; Get char without testing or echo
MOV AX,(STD_CON_INPUT_FLUSH SHL 8) + 0
INT int_command
return
LOADCOM: ; Load in transient
INC BP ; Flag command read
MOV DX,OFFSET RESGROUP:COMSPEC
MOV AX,OPEN SHL 8
INT int_command ; Open COMMAND.COM
JNC READCOM
CMP AX,open_too_many_open_files
JNZ TRYDOOPEN
MOV DX,OFFSET RESGROUP:NOHANDMES
JMP FATALC ; Fatal, will never find a handle
TRYDOOPEN:
CALL GETCOMDSK
JMP SHORT LOADCOM
READCOM:
MOV BX,AX ; Handle
MOV DX,OFFSET RESGROUP:TRANSTART
XOR CX,CX ; Seek loc
MOV AX,LSEEK SHL 8
INT int_command
JC WRONGCOM1
MOV CX,OFFSET TRANGROUP:TRANSPACEEND - 100H
IF IBM
ADD CX,15
AND CX,0FFF0H
ADD CX,OFFSET EGROUP:ZEXECCODEEND
ENDIF
PUSH DS
MOV DS,[TRNSEG]
ASSUME DS:NOTHING
MOV DX,100H
MOV AH,READ
INT int_command
POP DS
ASSUME DS:RESGROUP
WRONGCOM1:
PUSHF
PUSH AX
MOV AH,CLOSE
INT int_command ; Close COMMAND.COM
POP AX
POPF
JC WRONGCOM ; If error on READ
CMP AX,CX
JZ RET10 ; Size matched
WRONGCOM:
MOV DX,OFFSET RESGROUP:COMBAD
CALL GETCOMDSK3
JMP SHORT LOADCOM ; Try again
CHKSUM: ; Compute transient checksum
PUSH DS
MOV DS,[TRNSEG]
MOV SI,100H
MOV CX,OFFSET TRANGROUP:TRANDATAEND - 100H
CHECK_SUM:
CLD
SHR CX,1
XOR DX,DX
CHK:
LODSW
ADD DX,AX
LOOP CHK
POP DS
RET10: RET
SETVECT: ; Set useful vectors
MOV DX,OFFSET RESGROUP:LODCOM
MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 22H ; Set Terminate address
INT int_command
MOV DX,OFFSET RESGROUP:CONTC
MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H ; Set Ctrl-C address
INT int_command
MOV DX,OFFSET RESGROUP:DSKERR
MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 24H ; Set Hard Disk Error address
INT int_command
RET
CODERES ENDS
; This TAIL segment is used to produce a PARA aligned label in the resident
; group which is the location where the transient segments will be loaded
; initial.
TAIL SEGMENT PUBLIC PARA
ORG 0
TRANSTART LABEL WORD
TAIL ENDS
; This TAIL segment is used to produce a PARA aligned label in the transient
; group which is the location where the exec segments will be loaded
; initial.
TRANTAIL SEGMENT PUBLIC PARA
ORG 0
EXECSTART LABEL WORD
TRANTAIL ENDS
IF IBMVER
INCLUDE EXEC.ASM
ENDIF
END PROGSTART

38
v2.0/source/COMSEG.ASM Normal file
View File

@ -0,0 +1,38 @@
; The following are all of the segments used in the load order
CODERES SEGMENT PUBLIC
CODERES ENDS
DATARES SEGMENT PUBLIC
DATARES ENDS
ENVIRONMENT SEGMENT PUBLIC
ENVIRONMENT ENDS
INIT SEGMENT PUBLIC
INIT ENDS
TAIL SEGMENT PUBLIC
TAIL ENDS
TRANCODE SEGMENT PUBLIC
TRANCODE ENDS
TRANDATA SEGMENT PUBLIC
TRANDATA ENDS
TRANSPACE SEGMENT PUBLIC
TRANSPACE ENDS
TRANTAIL SEGMENT PUBLIC
TRANTAIL ENDS
ZEXEC_CODE SEGMENT PUBLIC
ZEXEC_CODE ENDS
ZEXEC_DATA SEGMENT PUBLIC
ZEXEC_DATA ENDS
RESGROUP GROUP CODERES,DATARES,ENVIRONMENT,INIT,TAIL
TRANGROUP GROUP TRANCODE,TRANDATA,TRANSPACE,TRANTAIL
EGROUP GROUP ZEXEC_CODE,ZEXEC_DATA

13
v2.0/source/COMSW.ASM Normal file
View File

@ -0,0 +1,13 @@
; Use the following booleans to set assembly flags
FALSE EQU 0
TRUE EQU NOT FALSE
IBMVER EQU true ; Switch to build IBM version of Command
IBM EQU IBMVER
MSVER EQU false ; Switch to build MS-DOS version of Command
HIGHMEM EQU FALSE ; Run resident part above transient (high memory)
KANJI EQU false ; Support for dual byte Microsoft KANJI standard
IBMJAPAN EQU FALSE ;MUST BE TRUE (along with IBM and KANJI)


BIN
v2.0/source/CONFIG.txt Normal file

Binary file not shown.

579
v2.0/source/COPY.ASM Normal file
View File

@ -0,0 +1,579 @@
TITLE COMMAND COPY routines.
INCLUDE COMSW.ASM
.xlist
.xcref
INCLUDE DOSSYM.ASM
INCLUDE DEVSYM.ASM
INCLUDE COMSEG.ASM
.list
.cref
INCLUDE COMEQU.ASM
DATARES SEGMENT PUBLIC
EXTRN VERVAL:WORD
DATARES ENDS
TRANDATA SEGMENT PUBLIC
EXTRN BADARGS:BYTE,BADCD:BYTE,BADSWT:BYTE,COPIED_PRE:BYTE
EXTRN COPIED_POST:BYTE
EXTRN INBDEV:BYTE,OVERWR:BYTE,FULDIR:BYTE,LOSTERR:BYTE
EXTRN NOSPACE:BYTE,DEVWMES:BYTE,NOTFND:BYTE
TRANDATA ENDS
TRANSPACE SEGMENT PUBLIC
EXTRN MELCOPY:BYTE,SRCPT:WORD,MELSTART:WORD,SCANBUF:BYTE
EXTRN DESTFCB2:BYTE,SDIRBUF:BYTE,SRCTAIL:WORD,CFLAG:BYTE
EXTRN NXTADD:WORD,DESTCLOSED:BYTE,ALLSWITCH:WORD,ARGC:BYTE
EXTRN PLUS:BYTE,BINARY:BYTE,ASCII:BYTE,FILECNT:WORD
EXTRN WRITTEN:BYTE,CONCAT:BYTE,DESTBUF:BYTE,SRCBUF:BYTE
EXTRN SDIRBUF:BYTE,DIRBUF:BYTE,DESTFCB:BYTE,FRSTSRCH:BYTE
EXTRN FIRSTDEST:BYTE,DESTISDIR:BYTE,DESTSWITCH:WORD,STARTEL:WORD
EXTRN DESTTAIL:WORD,DESTSIZ:BYTE,DESTINFO:BYTE,INEXACT:BYTE
EXTRN CURDRV:BYTE,DESTVARS:BYTE,RESSEG:WORD,SRCSIZ:BYTE
EXTRN SRCINFO:BYTE,SRCVARS:BYTE,USERDIR1:BYTE,NOWRITE:BYTE
EXTRN RDEOF:BYTE,SRCHAND:WORD,CPDATE:WORD,CPTIME:WORD
EXTRN SRCISDEV:BYTE,BYTCNT:WORD,TPA:WORD,TERMREAD:BYTE
EXTRN DESTHAND:WORD,DESTISDEV:BYTE,DIRCHAR:BYTE
TRANSPACE ENDS
; **************************************************
; COPY CODE
;
TRANCODE SEGMENT PUBLIC BYTE
EXTRN RESTUDIR:NEAR,CERROR:NEAR,SWITCH:NEAR,DISP32BITS:NEAR
EXTRN PRINT:NEAR,TCOMMAND:NEAR,ZPRINT:NEAR,ONESPC:NEAR
EXTRN RESTUDIR1:NEAR,FCB_TO_ASCZ:NEAR,CRLF2:NEAR,SAVUDIR1:NEAR
EXTRN SETREST1:NEAR,BADCDERR:NEAR,STRCOMP:NEAR,DELIM:NEAR
EXTRN UPCONV:NEAR,PATHCHRCMP:NEAR,SCANOFF:NEAR
EXTRN CPARSE:NEAR
EXTRN SEARCH:NEAR,SEARCHNEXT:NEAR,DOCOPY:NEAR,CLOSEDEST:NEAR
EXTRN FLSHFIL:NEAR,SETASC:NEAR,BUILDNAME:NEAR,COPERR:NEAR
PUBLIC COPY,BUILDPATH,COMPNAME,ENDCOPY
ASSUME CS:TRANGROUP,DS:TRANGROUP,ES:TRANGROUP,SS:NOTHING
DOMELCOPY:
cmp [MELCOPY],0FFH
jz CONTMEL
mov SI,[SRCPT]
mov [MELSTART],si
mov [MELCOPY],0FFH
CONTMEL:
xor BP,BP
mov si,[SRCPT]
mov bl,'+'
SCANSRC2:
mov di,OFFSET TRANGROUP:SCANBUF
call CPARSE
test bh,80H
jz NEXTMEL ; Go back to start
test bh,1 ; Switch ?
jnz SCANSRC2 ; Yes
call SOURCEPROC
call RESTUDIR1
mov di,OFFSET TRANGROUP:DESTFCB2
mov ax,PARSE_FILE_DESCRIPTOR SHL 8
INT int_command
mov bx,OFFSET TRANGROUP:SDIRBUF + 1
mov si,OFFSET TRANGROUP:DESTFCB2 + 1
mov di,[SRCTAIL]
call BUILDNAME
jmp MELDO
NEXTMEL:
call CLOSEDEST
xor ax,ax
mov [CFLAG],al
mov [NXTADD],ax
mov [DESTCLOSED],al
mov si,[MELSTART]
mov [SRCPT],si
call SEARCHNEXT
jz SETNMELJ
jmp ENDCOPY2
SETNMELJ:
jmp SETNMEL
COPY:
; First order of buisness is to find out about the destination
ASSUME DS:TRANGROUP,ES:TRANGROUP
xor ax,ax
mov [ALLSWITCH],AX ; no switches
mov [ARGC],al ; no arguments
mov [PLUS],al ; no concatination
mov [BINARY],al ; Binary not specifically specified
mov [ASCII],al ; ASCII not specifically specified
mov [FILECNT],ax ; No files yet
mov [WRITTEN],al ; Nothing written yet
mov [CONCAT],al ; No concatination
mov [MELCOPY],al ; Not a Mel Hallerman copy
mov word ptr [SCANBUF],ax ; Init buffer
mov word ptr [DESTBUF],ax ; Init buffer
mov word ptr [SRCBUF],ax ; Init buffer
mov word ptr [SDIRBUF],ax ; Init buffer
mov word ptr [DIRBUF],ax ; Init buffer
mov word ptr [DESTFCB],ax ; Init buffer
dec ax
mov [FRSTSRCH],al ; First search call
mov [FIRSTDEST],al ; First time
mov [DESTISDIR],al ; Don't know about dest
mov si,81H
mov bl,'+' ; include '+' as a delimiter
DESTSCAN:
xor bp,bp ; no switches
mov di,offset trangroup:SCANBUF
call CPARSE
PUSHF ; save flags
test bh,80H ; A '+' argument?
jz NOPLUS ; no
mov [PLUS],1 ; yes
NOPLUS:
POPF ; get flags back
jc CHECKDONE ; Hit CR?
test bh,1 ; Switch?
jz TESTP2 ; no
or [DESTSWITCH],BP ; Yes, assume destination
or [ALLSWITCH],BP ; keep tabs on all switches
jmp short DESTSCAN
TESTP2:
test bh,80H ; Plus?
jnz GOTPLUS ; Yes, not a separate arg
inc [ARGC] ; found a real arg
GOTPLUS:
push SI
mov ax,[STARTEL]
mov SI,offset trangroup:SCANBUF ; Adjust to copy
sub ax,SI
mov DI,offset trangroup:DESTBUF
add ax,DI
mov [DESTTAIL],AX
mov [DESTSIZ],cl ; Save its size
inc cx ; Include the NUL
rep movsb ; Save potential destination
mov [DESTINFO],bh ; Save info about it
mov [DESTSWITCH],0 ; reset switches
pop SI
jmp short DESTSCAN ; keep going
CHECKDONE:
mov al,[PLUS]
mov [CONCAT],al ; PLUS -> Concatination
shl al,1
shl al,1
mov [INEXACT],al ; CONCAT -> inexact copy
mov dx,offset trangroup:BADARGS
mov al,[ARGC]
or al,al ; Good number of args?
jz CERROR4J ; no, not enough
cmp al,2
jbe ACOUNTOK
CERROR4J:
jmp CERROR ; no, too many
ACOUNTOK:
mov bp,offset trangroup:DESTVARS
cmp al,1
jnz GOT2ARGS
mov al,[CURDRV] ; Dest is default drive:*.*
add al,'A'
mov ah,':'
mov [bp.SIZ],2
mov di,offset trangroup:DESTBUF
stosw
mov [DESTSWITCH],0 ; no switches on dest
mov [bp.INFO],2 ; Flag dest is ambig
mov [bp.ISDIR],0 ; Know destination specs file
call SETSTARS
GOT2ARGS:
cmp [bp.SIZ],2
jnz NOTSHORTDEST
cmp [DESTBUF+1],':'
jnz NOTSHORTDEST ; Two char file name
or [bp.INFO],2 ; Know dest is d:
mov di,offset trangroup:DESTBUF + 2
mov [bp.ISDIR],0 ; Know destination specs file
call SETSTARS
NOTSHORTDEST:
mov di,[bp.TTAIL]
cmp byte ptr [DI],0
jnz CHKSWTCHES
mov dx,offset trangroup:BADCD
cmp byte ptr [DI-2],':'
jnz CERROR4J ; Trailing '/' error
mov [bp.ISDIR],2 ; Know destination is d:/
or [bp.INFO],6
call SETSTARS
CHKSWTCHES:
mov dx,offset trangroup:BADSWT
mov ax,[ALLSWITCH]
cmp ax,GOTSWITCH
jz CERROR4J ; Switch specified which is not known
; Now know most of the information needed about the destination
TEST AX,VSWITCH ; Verify requested?
JZ NOVERIF ; No
MOV AH,GET_VERIFY_ON_WRITE
INT int_command ; Get current setting
PUSH DS
MOV DS,[RESSEG]
ASSUME DS:RESGROUP
XOR AH,AH
MOV [VERVAL],AX ; Save current setting
POP DS
ASSUME DS:TRANGROUP
MOV AX,(SET_VERIFY_ON_WRITE SHL 8) OR 1 ; Set verify
INT int_command
NOVERIF:
xor bp,bp ; no switches
mov si,81H
mov bl,'+' ; include '+' as a delimiter
SCANFSRC:
mov di,offset trangroup:SCANBUF
call CPARSE ; Parse first source name
test bh,1 ; Switch?
jnz SCANFSRC ; Yes, try again
or [DESTSWITCH],bp ; Include copy wide switches on DEST
test bp,BSWITCH
jnz NOSETCASC ; Binary explicit
cmp [CONCAT],0
JZ NOSETCASC ; Not Concat
mov [ASCII],ASWITCH ; Concat -> ASCII copy if no B switch
NOSETCASC:
push SI
mov ax,[STARTEL]
mov SI,offset trangroup:SCANBUF ; Adjust to copy
sub ax,SI
mov DI,offset trangroup:SRCBUF
add ax,DI
mov [SRCTAIL],AX
mov [SRCSIZ],cl ; Save its size
inc cx ; Include the NUL
rep movsb ; Save this source
mov [SRCINFO],bh ; Save info about it
pop SI
mov ax,bp ; Switches so far
call SETASC ; Set A,B switches accordingly
call SWITCH ; Get any more switches on this arg
call SETASC ; Set
call FRSTSRC
jmp FIRSTENT
ENDCOPY:
CALL CLOSEDEST
ENDCOPY2:
MOV DX,OFFSET TRANGROUP:COPIED_PRE
CALL PRINT
MOV SI,[FILECNT]
XOR DI,DI
CALL DISP32BITS
MOV DX,OFFSET TRANGROUP:COPIED_POST
CALL PRINT
JMP TCOMMAND ; Stack could be messed up
SRCNONEXIST:
cmp [CONCAT],0
jnz NEXTSRC ; If in concat mode, ignore error
mov dx,offset trangroup:SRCBUF
call zprint
CALL ONESPC
mov dx,offset trangroup:NOTFND
jmp COPERR
SOURCEPROC:
push SI
mov ax,[STARTEL]
mov SI,offset trangroup:SCANBUF ; Adjust to copy
sub ax,SI
mov DI,offset trangroup:SRCBUF
add ax,DI
mov [SRCTAIL],AX
mov [SRCSIZ],cl ; Save its size
inc cx ; Include the NUL
rep movsb ; Save this sorce
mov [SRCINFO],bh ; Save info about it
pop SI
mov ax,bp ; Switches so far
call SETASC ; Set A,B switches accordingly
call SWITCH ; Get any more switches on this arg
call SETASC ; Set
cmp [CONCAT],0
jnz LEAVECFLAG ; Leave CFLAG if concatination
FRSTSRC:
xor ax,ax
mov [CFLAG],al ; Flag destination not created
mov [NXTADD],ax ; Zero out buffer
mov [DESTCLOSED],al ; Not created -> not closed
LEAVECFLAG:
mov [SRCPT],SI ; remember where we are
mov di,offset trangroup:USERDIR1
mov bp,offset trangroup:SRCVARS
call BUILDPATH ; Figure out everything about the source
mov si,[SRCTAIL] ; Create the search FCB
return
NEXTSRC:
cmp [PLUS],0
jnz MORECP
ENDCOPYJ2:
jmp ENDCOPY ; Done
MORECP:
xor bp,bp ; no switches
mov si,[SRCPT]
mov bl,'+' ; include '+' as a delimiter
SCANSRC:
mov di,offset trangroup:SCANBUF
call CPARSE ; Parse first source name
JC EndCopyJ2 ; if error, then end (trailing + case)
test bh,80H
jz ENDCOPYJ2 ; If no '+' we're done
test bh,1 ; Switch?
jnz SCANSRC ; Yes, try again
call SOURCEPROC
FIRSTENT:
mov di,FCB
mov ax,PARSE_FILE_DESCRIPTOR SHL 8
INT int_command
mov ax,word ptr [SRCBUF] ; Get drive
cmp ah,':'
jz DRVSPEC1
mov al,'@'
DRVSPEC1:
sub al,'@'
mov ds:[FCB],al
mov ah,DIR_SEARCH_FIRST
call SEARCH
pushf ; Save result of search
call RESTUDIR1 ; Restore users dir
popf
jz NEXTAMBIG0
jmp SRCNONEXIST ; Failed
NEXTAMBIG0:
xor al,al
xchg al,[FRSTSRCH]
or al,al
jz NEXTAMBIG
SETNMEL:
mov cx,12
mov di,OFFSET TRANGROUP:SDIRBUF
mov si,OFFSET TRANGROUP:DIRBUF
rep movsb ; Save very first source name
NEXTAMBIG:
xor al,al
mov [NOWRITE],al ; Turn off NOWRITE
mov di,[SRCTAIL]
mov si,offset trangroup:DIRBUF + 1
call FCB_TO_ASCZ ; SRCBUF has complete name
MELDO:
cmp [CONCAT],0
jnz SHOWCPNAM ; Show name if concat
test [SRCINFO],2 ; Show name if multi
jz DOREAD
SHOWCPNAM:
mov dx,offset trangroup:SRCBUF
call ZPRINT
call CRLF2
DOREAD:
call DOCOPY
cmp [CONCAT],0
jnz NODCLOSE ; If concat, do not close
call CLOSEDEST ; else close current destination
jc NODCLOSE ; Concat flag got set, close didn't really happen
mov [CFLAG],0 ; Flag destination not created
NODCLOSE:
cmp [CONCAT],0 ; Check CONCAT again
jz NOFLUSH
CALL FLSHFIL ; Flush output between source files on CONCAT
; so LOSTERR stuff works correctly
TEST [MELCOPY],0FFH
jz NOFLUSH
jmp DOMELCOPY
NOFLUSH:
call SEARCHNEXT ; Try next match
jnz NEXTSRCJ ; Finished with this source spec
mov [DESTCLOSED],0 ; Not created or concat -> not closed
jmp NEXTAMBIG ; Do next ambig
NEXTSRCJ:
jmp NEXTSRC
BUILDPATH:
test [BP.INFO],2
jnz NOTPFILE ; If ambig don't bother with open
mov dx,bp
add dx,BUF ; Set DX to spec
mov ax,OPEN SHL 8
INT int_command
jc NOTPFILE
mov bx,ax ; Is pure file
mov ax,IOCTL SHL 8
INT int_command
mov ah,CLOSE
INT int_command
test dl,devid_ISDEV
jnz ISADEV ; If device, done
test [BP.INFO],4
jz ISSIMPFILE ; If no path seps, done
NOTPFILE:
mov dx,word ptr [BP.BUF]
cmp dh,':'
jz DRVSPEC5
mov dl,'@'
DRVSPEC5:
sub dl,'@' ; A = 1
call SAVUDIR1
mov dx,bp
add dx,BUF ; Set DX for upcomming CHDIRs
mov bh,[BP.INFO]
and bh,6
cmp bh,6 ; Ambig and path ?
jnz CHECKAMB ; jmp if no
mov si,[BP.TTAIL]
cmp byte ptr [si-2],':'
jnz KNOWNOTSPEC
mov [BP.ISDIR],2 ; Know is d:/file
jmp short DOPCDJ
KNOWNOTSPEC:
mov [BP.ISDIR],1 ; Know is path/file
dec si ; Point to the /
DOPCDJ:
jmp short DOPCD
CHECKAMB:
cmp bh,2
jnz CHECKCD
ISSIMPFILE:
ISADEV:
mov [BP.ISDIR],0 ; Know is file since ambig but no path
return
CHECKCD:
call SETREST1
mov ah,CHDIR
INT int_command
jc NOTPDIR
mov di,dx
xor ax,ax
mov cx,ax
dec cx
repne scasb
dec di
mov al,[DIRCHAR]
mov [bp.ISDIR],2 ; assume d:/file
cmp al,[di-1]
jz GOTSRCSLSH
stosb
mov [bp.ISDIR],1 ; know path/file
GOTSRCSLSH:
or [bp.INFO],6
call SETSTARS
return
NOTPDIR:
mov [bp.ISDIR],0 ; assume pure file
mov bh,[bp.INFO]
test bh,4
retz ; Know pure file, no path seps
mov [bp.ISDIR],2 ; assume d:/file
mov si,[bp.TTAIL]
cmp byte ptr [si],0
jz BADCDERRJ2 ; Trailing '/'
cmp byte ptr [si],'.'
jz BADCDERRJ2 ; If . or .. pure cd should have worked
cmp byte ptr [si-2],':'
jz DOPCD ; Know d:/file
mov [bp.ISDIR],1 ; Know path/file
dec si ; Point at last '/'
DOPCD:
xor bl,bl
xchg bl,[SI] ; Stick in a NUL
call SETREST1
mov ah,CHDIR
INT int_command
xchg bl,[SI]
retnc
BADCDERRJ2:
JMP BADCDERR
SETSTARS:
mov [bp.TTAIL],DI
add [bp.SIZ],12
mov ax,('.' SHL 8) OR '?'
mov cx,8
rep stosb
xchg al,ah
stosb
xchg al,ah
mov cl,3
rep stosb
xor al,al
stosb
return
COMPNAME:
PUSH CX
PUSH AX
MOV si,offset trangroup:SRCBUF
MOV di,offset trangroup:DESTBUF
MOV CL,[CURDRV]
MOV CH,CL
CMP BYTE PTR [SI+1],':'
JNZ NOSRCDRV
LODSW
SUB AL,'A'
MOV CL,AL
NOSRCDRV:
CMP BYTE PTR [DI+1],':'
JNZ NODSTDRV
MOV AL,[DI]
INC DI
INC DI
SUB AL,'A'
MOV CH,AL
NODSTDRV:
CMP CH,CL
jnz RET81P
call STRCOMP
jz RET81P
mov ax,[si-1]
mov cx,[di-1]
push ax
and al,cl
pop ax
jnz RET81P ; Niether of the mismatch chars was a NUL
; Know one of the mismatch chars is a NUL
; Check for ".NUL" compared with NUL
cmp al,'.'
jnz CHECKCL
or ah,ah
jmp short RET81P ; If NUL return match, else no match
CHECKCL:
cmp cl,'.'
jnz RET81P ; Mismatch
or ch,ch ; If NUL return match, else no match
RET81P:
POP AX
POP CX
return
TRANCODE ENDS
END

526
v2.0/source/COPYPROC.ASM Normal file
View File

@ -0,0 +1,526 @@
TITLE COPYRPOC ;Procedures called by COPY
INCLUDE COMSW.ASM
.xlist
.xcref
INCLUDE DOSSYM.ASM
INCLUDE DEVSYM.ASM
INCLUDE COMSEG.ASM
.list
.cref
INCLUDE COMEQU.ASM
DATARES SEGMENT PUBLIC
DATARES ENDS
TRANDATA SEGMENT PUBLIC
EXTRN OVERWR:BYTE,FULDIR:BYTE,LOSTERR:BYTE
EXTRN DEVWMES:BYTE,INBDEV:BYTE,NOSPACE:BYTE
TRANDATA ENDS
TRANSPACE SEGMENT PUBLIC
EXTRN CFLAG:BYTE,NXTADD:WORD,DESTCLOSED:BYTE
EXTRN PLUS:BYTE,BINARY:BYTE,ASCII:BYTE,FILECNT:WORD
EXTRN WRITTEN:BYTE,CONCAT:BYTE,DESTBUF:BYTE,SRCBUF:BYTE
EXTRN SDIRBUF:BYTE,DIRBUF:BYTE,DESTFCB:BYTE,MELCOPY:BYTE
EXTRN FIRSTDEST:BYTE,DESTISDIR:BYTE,DESTSWITCH:WORD
EXTRN DESTTAIL:WORD,DESTINFO:BYTE,INEXACT:BYTE
EXTRN DESTVARS:BYTE,SRCINFO:BYTE,RDEOF:BYTE
EXTRN USERDIR1:BYTE,NOWRITE:BYTE
EXTRN SRCHAND:WORD,CPDATE:WORD,CPTIME:WORD
EXTRN SRCISDEV:BYTE,BYTCNT:WORD,TPA:WORD,TERMREAD:BYTE
EXTRN DESTHAND:WORD,DESTISDEV:BYTE,DIRCHAR:BYTE
TRANSPACE ENDS
TRANCODE SEGMENT PUBLIC BYTE
PUBLIC SEARCH,SEARCHNEXT,DOCOPY,CLOSEDEST,FLSHFIL,SETASC
PUBLIC BUILDNAME,COPERR
EXTRN PRINT:NEAR,BUILDPATH:NEAR,RESTUDIR1:NEAR
EXTRN COMPNAME:NEAR,ENDCOPY:NEAR
ASSUME CS:TRANGROUP,DS:TRANGROUP,ES:TRANGROUP,SS:NOTHING
SEARCHNEXT:
MOV AH,DIR_SEARCH_NEXT
TEST [SRCINFO],2
JNZ SEARCH ; Do serach-next if ambig
OR AH,AH ; Reset zero flag
return
SEARCH:
PUSH AX
MOV AH,SET_DMA
MOV DX,OFFSET TRANGROUP:DIRBUF
INT int_command ; Put result of search in DIRBUF
POP AX ; Restore search first/next command
MOV DX,FCB
INT int_command ; Do the search
OR AL,AL
return
DOCOPY:
mov [RDEOF],0 ; No EOF yet
mov dx,offset trangroup:SRCBUF
mov ax,OPEN SHL 8
INT int_command
retc ; If open fails, ignore
mov bx,ax ; Save handle
mov [SRCHAND],bx ; Save handle
mov ax,(FILE_TIMES SHL 8)
INT int_command
mov [CPDATE],dx ; Save DATE
mov [CPTIME],cx ; Save TIME
mov ax,(IOCTL SHL 8)
INT int_command ; Get device stuff
and dl,devid_ISDEV
mov [SRCISDEV],dl ; Set source info
jz COPYLP ; Source not a device
cmp [BINARY],0
jz COPYLP ; ASCII device OK
mov dx,offset trangroup:INBDEV ; Cannot do binary input
jmp COPERR
COPYLP:
mov bx,[SRCHAND]
mov cx,[BYTCNT]
mov dx,[NXTADD]
sub cx,dx ; Compute available space
jnz GOTROOM
call FLSHFIL
CMP [TERMREAD],0
JNZ CLOSESRC ; Give up
mov cx,[BYTCNT]
GOTROOM:
push ds
mov ds,[TPA]
ASSUME DS:NOTHING
mov ah,READ
INT int_command
pop ds
ASSUME DS:TRANGROUP
jc CLOSESRC ; Give up if error
mov cx,ax ; Get count
jcxz CLOSESRC ; No more to read
cmp [SRCISDEV],0
jnz NOTESTA ; Is a device, ASCII mode
cmp [ASCII],0
jz BINREAD
NOTESTA:
MOV DX,CX
MOV DI,[NXTADD]
MOV AL,1AH
PUSH ES
MOV ES,[TPA]
REPNE SCASB ; Scan for EOF
POP ES
JNZ USEALL
INC [RDEOF]
INC CX
USEALL:
SUB DX,CX
MOV CX,DX
BINREAD:
ADD CX,[NXTADD]
MOV [NXTADD],CX
CMP CX,[BYTCNT] ; Is buffer full?
JB TESTDEV ; If not, we may have found EOF
CALL FLSHFIL
CMP [TERMREAD],0
JNZ CLOSESRC ; Give up
JMP SHORT COPYLP
TESTDEV:
cmp [SRCISDEV],0
JZ CLOSESRC ; If file then EOF
CMP [RDEOF],0
JZ COPYLP ; On device, go till ^Z
CLOSESRC:
mov bx,[SRCHAND]
mov ah,CLOSE
INT int_command
return
CLOSEDEST:
cmp [DESTCLOSED],0
retnz ; Don't double close
MOV AL,BYTE PTR [DESTSWITCH]
CALL SETASC ; Check for B or A switch on destination
JZ BINCLOS
MOV BX,[NXTADD]
CMP BX,[BYTCNT] ; Is memory full?
JNZ PUTZ
call TRYFLUSH ; Make room for one lousy byte
jz NOCONC
CONCHNG: ; Concat flag changed on us
stc
return
NOCONC:
XOR BX,BX
PUTZ:
PUSH DS
MOV DS,[TPA]
MOV WORD PTR [BX],1AH ; Add End-of-file mark (Ctrl-Z)
POP DS
INC [NXTADD]
MOV [NOWRITE],0 ; Make sure our ^Z gets written
MOV AL,[WRITTEN]
XOR AH,AH
ADD AX,[NXTADD]
JC BINCLOS ; > 1
CMP AX,1
JZ FORGETIT ; WRITTEN = 0 NXTADD = 1 (the ^Z)
BINCLOS:
call TRYFLUSH
jnz CONCHNG
cmp [WRITTEN],0
jz FORGETIT ; Never wrote nothin
MOV BX,[DESTHAND]
MOV CX,[CPTIME]
MOV DX,[CPDATE]
CMP [INEXACT],0 ; Copy not exact?
JZ DODCLOSE ; If no, copy date & time
MOV AH,GET_TIME
INT int_command
SHL CL,1
SHL CL,1 ; Left justify min in CL
SHL CX,1
SHL CX,1
SHL CX,1 ; hours to high 5 bits, min to 5-10
SHR DH,1 ; Divide seconds by 2 (now 5 bits)
OR CL,DH ; And stick into low 5 bits of CX
PUSH CX ; Save packed time
MOV AH,GET_DATE
INT int_command
SUB CX,1980
XCHG CH,CL
SHL CX,1 ; Year to high 7 bits
SHL DH,1 ; Month to high 3 bits
SHL DH,1
SHL DH,1
SHL DH,1
SHL DH,1 ; Most sig bit of month in carry
ADC CH,0 ; Put that bit next to year
OR DL,DH ; Or low three of month into day
MOV DH,CH ; Get year and high bit of month
POP CX ; Get time back
DODCLOSE:
MOV AX,(FILE_TIMES SHL 8) OR 1
INT int_command ; Set date and time
MOV AH,CLOSE
INT int_command
INC [FILECNT]
INC [DESTCLOSED]
RET50:
CLC
return
FORGETIT:
MOV BX,[DESTHAND]
CALL DODCLOSE ; Close the dest
MOV DX,OFFSET TRANGROUP:DESTBUF
MOV AH,UNLINK
INT int_command ; And delete it
MOV [FILECNT],0 ; No files transferred
JMP RET50
TRYFLUSH:
mov al,[CONCAT]
push ax
call FLSHFIL
pop ax
cmp al,[CONCAT]
return
FLSHFIL:
; Write out any data remaining in memory.
; Inputs:
; [NXTADD] = No. of bytes to write
; [CFLAG] <>0 if file has been created
; Outputs:
; [NXTADD] = 0
MOV [TERMREAD],0
cmp [CFLAG],0
JZ NOTEXISTS
JMP EXISTS
NOTEXISTS:
call BUILDDEST ; Find out all about the destination
CALL COMPNAME ; Source and dest. the same?
JNZ PROCDEST ; If not, go ahead
CMP [SRCISDEV],0
JNZ PROCDEST ; Same name on device OK
CMP [CONCAT],0 ; Concatenation?
MOV DX,OFFSET TRANGROUP:OVERWR
JZ COPERRJ ; If not, overwrite error
MOV [NOWRITE],1 ; Flag not writting (just seeking)
PROCDEST:
mov ax,(OPEN SHL 8) OR 1
CMP [NOWRITE],0
JNZ DODESTOPEN ; Don't actually create if NOWRITE set
mov ah,CREAT
xor cx,cx
DODESTOPEN:
mov dx,offset trangroup:DESTBUF
INT int_command
MOV DX,OFFSET TRANGROUP:FULDIR
JC COPERRJ
mov [DESTHAND],ax ; Save handle
mov [CFLAG],1 ; Destination now exists
mov bx,ax
mov ax,(IOCTL SHL 8)
INT int_command ; Get device stuff
mov [DESTISDEV],dl ; Set dest info
test dl,devid_ISDEV
jz EXISTS ; Dest not a device
mov al,BYTE PTR [DESTSWITCH]
AND AL,ASWITCH+BSWITCH
JNZ TESTBOTH
MOV AL,[ASCII] ; Neither set, use current setting
OR AL,[BINARY]
JZ EXSETA ; Neither set, default to ASCII
TESTBOTH:
JPE EXISTS ; Both are set, ignore
test AL,BSWITCH
jz EXISTS ; Leave in cooked mode
mov ax,(IOCTL SHL 8) OR 1
xor dh,dh
or dl,devid_RAW
mov [DESTISDEV],dl ; New value
INT int_command ; Set device to RAW mode
jmp short EXISTS
COPERRJ:
jmp SHORT COPERR
EXSETA:
; What we read in may have been in binary mode, flag zapped write OK
mov [ASCII],ASWITCH ; Set ASCII mode
or [INEXACT],ASWITCH ; ASCII -> INEXACT
EXISTS:
cmp [NOWRITE],0
jnz NOCHECKING ; If nowrite don't bother with name check
CALL COMPNAME ; Source and dest. the same?
JNZ NOCHECKING ; If not, go ahead
CMP [SRCISDEV],0
JNZ NOCHECKING ; Same name on device OK
; At this point we know in append (would have gotten overwrite error on first
; destination create otherwise), and user trying to specify destination which
; has been scribbled already (if dest had been named first, NOWRITE would
; be set).
MOV DX,OFFSET TRANGROUP:LOSTERR ; Tell him he's not going to get it
CALL PRINT
MOV [NXTADD],0 ; Set return
INC [TERMREAD] ; Tell Read to give up
RET60:
return
NOCHECKING:
mov bx,[DESTHAND] ; Get handle
XOR CX,CX
XCHG CX,[NXTADD]
JCXZ RET60 ; If Nothing to write, forget it
INC [WRITTEN] ; Flag that we wrote something
CMP [NOWRITE],0 ; If NOWRITE set, just seek CX bytes
JNZ SEEKEND
XOR DX,DX
PUSH DS
MOV DS,[TPA]
ASSUME DS:NOTHING
MOV AH,WRITE
INT int_command
POP DS
ASSUME DS:TRANGROUP
MOV DX,OFFSET TRANGROUP:NOSPACE
JC COPERR ; Failure
sub cx,ax
retz ; Wrote all supposed to
test [DESTISDEV],devid_ISDEV
jz COPERR ; Is a file, error
test [DESTISDEV],devid_RAW
jnz DEVWRTERR ; Is a raw device, error
cmp [INEXACT],0
retnz ; INEXACT so OK
dec cx
retz ; Wrote one byte less (the ^Z)
DEVWRTERR:
MOV DX,OFFSET TRANGROUP:DEVWMES
COPERR:
CALL PRINT
inc [DESTCLOSED]
cmp [CFLAG],0
jz ENDCOPYJ ; Never actually got it open
MOV bx,[DESTHAND]
MOV AH,CLOSE ; Close the file
INT int_command
MOV DX,OFFSET TRANGROUP:DESTBUF
MOV AH,UNLINK
INT int_command ; And delete it
MOV [CFLAG],0
ENDCOPYJ:
JMP ENDCOPY
SEEKEND:
xor dx,dx ; Zero high half of offset
xchg dx,cx ; cx:dx is seek location
mov ax,(LSEEK SHL 8) OR 1
INT int_command ; Seek ahead in the file
cmp [RDEOF],0
retz
; If a ^Z has been read we must set the file size to the current
; file pointer location
MOV AH,WRITE
INT int_command ; CX is zero, truncates file
return
SETASC:
; Given switch vector in AX,
; Set ASCII switch if A is set
; Clear ASCII switch if B is set
; BINARY set if B specified
; Leave ASCII unchanged if neither or both are set
; Also sets INEXACT if ASCII is ever set. AL = ASCII on exit, flags set
AND AL,ASWITCH+BSWITCH
JPE LOADSW ; PE means both or neither are set
PUSH AX
AND AL,BSWITCH
MOV [BINARY],AL
POP AX
AND AL,ASWITCH
MOV [ASCII],AL
OR [INEXACT],AL
LOADSW:
MOV AL,[ASCII]
OR AL,AL
return
BUILDDEST:
cmp [DESTISDIR],-1
jnz KNOWABOUTDEST ; Already done the figuring
MOV DI,OFFSET TRANGROUP:USERDIR1
mov bp,offset trangroup:DESTVARS
call BUILDPATH
call RESTUDIR1
; Now know all about the destination
KNOWABOUTDEST:
xor al,al
xchg al,[FIRSTDEST]
or al,al
jnz FIRSTDST
jmp NOTFIRSTDEST
FIRSTDST:
mov si,[DESTTAIL] ; Create an FCB of the original DEST
mov di,offset trangroup:DESTFCB
mov ax,PARSE_FILE_DESCRIPTOR SHL 8
INT int_command
mov ax,word ptr [DESTBUF] ; Get drive
cmp ah,':'
jz DRVSPEC4
mov al,'@'
DRVSPEC4:
MOV CL,[ASCII] ; Save current ASCII setting
sub al,'@'
mov [DESTFCB],al
mov al,[DESTINFO]
mov ah,[SRCINFO]
and ax,0202H
or al,al
jz NOTMELCOPY
cmp al,ah
jnz NOTMELCOPY
cmp [PLUS],0
jz NOTMELCOPY
inc [MELCOPY] ; ambig source, ambig dest, and pluses
xor al,al
jmp short SETCONC
NOTMELCOPY:
xor al,2 ; al=2 if unambig dest, =0 if ambig dest
and al,ah
shr al,1 ; al=1 if unambig dest AND ambig sorce
; Implies concatination
SETCONC:
or al,[PLUS] ; al=1 if concat
mov [CONCAT],al
shl al,1
shl al,1
mov [INEXACT],al ; Concat -> inexact copy
cmp [BINARY],0
jnz NOTFIRSTDEST ; Binary explicitly given, all OK
mov [ASCII],al ; Concat -> ASCII
or cl,cl
jnz NOTFIRSTDEST ; ASCII flag set before, DATA read correctly
or al,al
JZ NOTFIRSTDEST ; ASCII flag did not change states
; At this point there may already be binary read data in the read buffer.
; We need to find the first ^Z (if there is one) and trim the amount
; of data in the buffer correctly.
MOV CX,[NXTADD]
JCXZ NOTFIRSTDEST ; No data, everything OK
MOV AL,1AH
PUSH ES
XOR DI,DI
MOV ES,[TPA]
REPNE SCASB ; Scan for EOF
POP ES
JNZ NOTFIRSTDEST ; No ^Z in buffer, everything OK
DEC DI ; Point at ^Z
MOV [NXTADD],DI ; New buffer
NOTFIRSTDEST:
mov bx,offset trangroup:DIRBUF+1 ; Source of replacement chars
cmp [CONCAT],0
jz GOTCHRSRC ; Not a concat
mov bx,offset trangroup:SDIRBUF+1 ; Source of replacement chars
GOTCHRSRC:
mov si,offset trangroup:DESTFCB+1 ; Original dest name
mov di,[DESTTAIL] ; Where to put result
BUILDNAME:
mov cx,8
BUILDMAIN:
lodsb
cmp al,"?"
jnz NOTAMBIG
mov al,byte ptr [BX]
NOTAMBIG:
cmp al,' '
jz NOSTORE
stosb
NOSTORE:
inc bx
loop BUILDMAIN
mov cl,3
cmp byte ptr [SI],' '
jz ENDDEST ; No extension
mov al,'.'
stosb
BUILDEXT:
lodsb
cmp al,"?"
jnz NOTAMBIGE
mov al,byte ptr [BX]
NOTAMBIGE:
cmp al,' '
jz NOSTOREE
stosb
NOSTOREE:
inc bx
loop BUILDEXT
ENDDEST:
xor al,al
stosb ; NUL terminate
return
TRANCODE ENDS
END

291
v2.0/source/CPARSE.ASM Normal file
View File

@ -0,0 +1,291 @@
TITLE CPARSE
INCLUDE COMSW.ASM
.xlist
.xcref
INCLUDE DOSSYM.ASM
INCLUDE DEVSYM.ASM
INCLUDE COMSEG.ASM
.list
.cref
INCLUDE COMEQU.ASM
DATARES SEGMENT PUBLIC
DATARES ENDS
TRANDATA SEGMENT PUBLIC
EXTRN BADCPMES:BYTE
TRANDATA ENDS
TRANSPACE SEGMENT PUBLIC
EXTRN CURDRV:BYTE,ELPOS:BYTE,STARTEL:WORD
EXTRN SKPDEL:BYTE,SWITCHAR:BYTE,ELCNT:BYTE
TRANSPACE ENDS
TRANCODE SEGMENT PUBLIC BYTE
ASSUME CS:TRANGROUP,DS:TRANGROUP,ES:TRANGROUP
EXTRN DELIM:NEAR,UPCONV:NEAR,PATHCHRCMP:NEAR
EXTRN SWLIST:BYTE,BADCDERR:NEAR,SCANOFF:NEAR,CERROR:NEAR
if KANJI
EXTRN TESTKANJ:NEAR
endif
SWCOUNT EQU 5
PUBLIC CPARSE
CPARSE:
;-----------------------------------------------------------------------;
; ENTRY: ;
; DS:SI Points input buffer ;
; ES:DI Points to the token buffer ;
; BL Special delimiter for this call ;
; Always checked last ;
; set it to space if there is no special delimiter ;
; EXIT: ;
; DS:SI Points to next char in the input buffer ;
; ES:DI Points to the token buffer ;
; [STARTEL] Points to start of last element of path in token ;
; points to a NUL for no element strings 'd:' 'd:/' ;
; CX Character count ;
; BH Condition Code ;
; Bit 1H of BH set if switch character ;
; Token buffer contains char after ;
; switch character ;
; BP has switch bits set (ORing only) ;
; Bit 2H of BH set if ? or * in token ;
; if * found element ? filled ;
; Bit 4H of BH set if path sep in token ;
; Bit 80H of BH set if the special delimiter ;
; was skipped at the start of this token ;
; Token buffer always starts d: for non switch tokens ;
; CARRY SET ;
; if CR on input ;
; token buffer not altered ;
; ;
; DOES NOT RETURN ON BAD PATH ERROR ;
; MODIFIES: ;
; CX, SI, AX, BH, DX and the Carry Flag ; ;
; ;
; -----------------------------------------------------------------------;
xor ax,ax
mov [STARTEL],DI ; No path element (Is DI correct?)
mov [ELPOS],al ; Start in 8 char prefix
mov [SKPDEL],al ; No skip delimiter yet
mov bh,al ; Init nothing
pushf ; save flags
push di ; save the token buffer addrss
xor cx,cx ; no chars in token buffer
moredelim:
LODSB
CALL DELIM
JNZ SCANCDONE
CMP AL,' '
JZ moredelim
CMP AL,9
JZ moredelim
xchg al,[SKPDEL]
or al,al
jz moredelim ; One non space/tab delimiter allowed
JMP x_done ; Nul argument
SCANCDONE:
IF NOT KANJI
call UPCONV
ENDIF
cmp al,bl ; Special delimiter?
jnz nospec
or bh,80H
jmp short moredelim
nospec:
cmp al,0DH ; a CR?
jne ncperror
jmp cperror
ncperror:
cmp al,[SWITCHAR] ; is the char the switch char?
jne na_switch ; yes, process...
jmp a_switch
na_switch:
cmp byte ptr [si],':'
jne anum_chard ; Drive not specified
IF KANJI
call UPCONV
ENDIF
call move_char
lodsb ; Get the ':'
call move_char
mov [STARTEL],di
mov [ELCNT],0
jmp anum_test
anum_chard:
mov [STARTEL],di
mov [ELCNT],0 ; Store of this char sets it to one
call PATHCHRCMP ; Starts with a pathchar?
jnz anum_char ; no
push ax
mov al,[CURDRV] ; Insert drive spec
add al,'A'
call move_char
mov al,':'
call move_char
pop ax
mov [STARTEL],di
mov [ELCNT],0
anum_char:
IF KANJI
call TESTKANJ
jz TESTDOT
call move_char
lodsb
jmp short notspecial
TESTDOT:
ENDIF
cmp al,'.'
jnz testquest
inc [ELPOS] ; flag in extension
mov [ELCNT],0FFH ; Store of the '.' resets it to 0
testquest:
cmp al,'?'
jnz testsplat
or bh,2
testsplat:
cmp al,'*'
jnz testpath
or bh,2
mov ah,7
cmp [ELPOS],0
jz gotelcnt
mov ah,2
gotelcnt:
mov al,'?'
sub ah,[ELCNT]
jc badperr2
xchg ah,cl
jcxz testpathx
qmove:
xchg ah,cl
call move_char
xchg ah,cl
loop qmove
testpathx:
xchg ah,cl
testpath:
call PATHCHRCMP
jnz notspecial
or bh,4
test bh,2 ; If just hit a '/', cannot have ? or * yet
jnz badperr
mov [STARTEL],di ; New element
INC [STARTEL] ; Point to char after /
mov [ELCNT],0FFH ; Store of '/' sets it to 0
mov [ELPOS],0
notspecial:
call move_char ; just an alphanum string
anum_test:
lodsb
IF NOT KANJI
call UPCONV
ENDIF
call DELIM
je x_done
cmp al,0DH
je x_done
cmp al,[SWITCHAR]
je x_done
cmp al,bl
je x_done
cmp al,':' ; ':' allowed as trailer because
; of devices
IF KANJI
je FOO15
jmp anum_char
FOO15:
ELSE
jne anum_char
ENDIF
mov byte ptr [si-1],' ' ; Change the trailing ':' to a space
jmp short x_done
badperr2:
mov dx,offset trangroup:BADCPMES
jmp CERROR
badperr:
jmp BADCDERR
cperror:
dec si ; adjust the pointer
pop di ; retrive token buffer address
popf ; restore flags
stc ; set the carry bit
return
x_done:
dec si ; adjust for next round
jmp short out_token
a_switch:
OR BH,1 ; Indicate switch
OR BP,GOTSWITCH
CALL SCANOFF
INC SI
cmp al,0DH
je cperror
call move_char ; store the character
CALL UPCONV
PUSH ES
PUSH DI
PUSH CX
PUSH CS
POP ES
ASSUME ES:TRANGROUP
MOV DI,OFFSET TRANGROUP:SWLIST
MOV CX,SWCOUNT
REPNE SCASB
JNZ out_tokenp
MOV AX,1
SHL AX,CL
OR BP,AX
out_tokenp:
POP CX
POP DI
POP ES
ASSUME ES:NOTHING
out_token:
mov al,0
stosb ; null at the end
pop di ; restore token buffer pointer
popf
clc ; clear carry flag
return
move_char:
stosb ; store char in token buffer
inc cx ; increment char count
inc [ELCNT] ; increment element count for * substi
return
TRANCODE ENDS
END

468
v2.0/source/CTRLC.ASM Normal file
View File

@ -0,0 +1,468 @@
;
; ^C status routines for MSDOS
;
INCLUDE DOSSEG.ASM
CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME SS:DOSGROUP,CS:DOSGROUP
.xlist
.xcref
INCLUDE DOSSYM.ASM
INCLUDE DEVSYM.ASM
.cref
.list
i_need DevIOBuf,BYTE
i_need DidCTRLC,BYTE
i_need INDOS,BYTE
i_need DSKSTCOM,BYTE
i_need DSKSTCALL,BYTE
i_need DSKSTST,WORD
i_need BCON,DWORD
i_need DSKCHRET,BYTE
i_need DSKSTCNT,WORD
i_need IDLEINT,BYTE
i_need CONSWAP,BYTE
i_need user_SS,WORD
i_need user_SP,WORD
i_need ERRORMODE,BYTE
i_need ConC_spSave,WORD
i_need Exit_type,BYTE
i_need PFLAG,BYTE
i_need ExitHold,DWORD
i_need WPErr,BYTE
i_need ReadOp,BYTE
i_need CONTSTK,WORD
i_need Exit_Code,WORD
i_need CurrentPDB,WORD
i_need DIVMES,BYTE
i_need DivMesLen,BYTE
SUBTTL Checks for ^C in CON I/O
PAGE
ASSUME DS:NOTHING,ES:NOTHING
procedure DSKSTATCHK,NEAR ; Check for ^C if only one level in
CMP BYTE PTR [INDOS],1
retnz ; Do NOTHING
PUSH CX
PUSH ES
PUSH BX
PUSH DS
PUSH SI
PUSH CS
POP ES
PUSH CS
POP DS
ASSUME DS:DOSGROUP
XOR CX,CX
MOV BYTE PTR [DSKSTCOM],DEVRDND
MOV BYTE PTR [DSKSTCALL],DRDNDHL
MOV [DSKSTST],CX
MOV BX,OFFSET DOSGROUP:DSKSTCALL
LDS SI,[BCON]
ASSUME DS:NOTHING
invoke DEVIOCALL2
TEST [DSKSTST],STBUI
JNZ ZRET ; No characters available
MOV AL,BYTE PTR [DSKCHRET]
DSK1:
CMP AL,"C"-"@"
JNZ RET36
MOV BYTE PTR [DSKSTCOM],DEVRD
MOV BYTE PTR [DSKSTCALL],DRDWRHL
MOV BYTE PTR [DSKCHRET],CL
MOV [DSKSTST],CX
INC CX
MOV [DSKSTCNT],CX
invoke DEVIOCALL2 ; Eat the ^C
POP SI
POP DS
POP BX ; Clean stack
POP ES
POP CX
JMP SHORT CNTCHAND
ZRET:
XOR AL,AL ; Set zero
RET36:
POP SI
POP DS
POP BX
POP ES
POP CX
return
NOSTOP:
CMP AL,"P"-"@"
JZ INCHK
IF NOT TOGLPRN
CMP AL,"N"-"@"
JZ INCHK
ENDIF
CMP AL,"C"-"@"
JZ INCHK
return
DSKSTATCHK ENDP
procedure SPOOLINT,NEAR
PUSHF
CMP BYTE PTR [IDLEINT],0
JZ POPFRET
CMP BYTE PTR [ERRORMODE],0
JNZ POPFRET ;No spool ints in error mode
INT int_spooler
POPFRET:
POPF
RET18: return
SPOOLINT ENDP
procedure STATCHK,NEAR
invoke DSKSTATCHK ; Allows ^C to be detected under
; input redirection
PUSH BX
XOR BX,BX
invoke GET_IO_FCB
POP BX
JC RET18
MOV AH,1
invoke IOFUNC
JZ SPOOLINT
CMP AL,'S'-'@'
JNZ NOSTOP
XOR AH,AH
invoke IOFUNC ; Eat Cntrl-S
JMP SHORT PAUSOSTRT
PRINTOFF:
PRINTON:
NOT BYTE PTR [PFLAG]
return
PAUSOLP:
CALL SPOOLINT
PAUSOSTRT:
MOV AH,1
invoke IOFUNC
JZ PAUSOLP
INCHK:
PUSH BX
XOR BX,BX
invoke GET_IO_FCB
POP BX
JC RET18
XOR AH,AH
invoke IOFUNC
CMP AL,'P'-'@'
JZ PRINTON
IF NOT TOGLPRN
CMP AL,'N'-'@'
JZ PRINTOFF
ENDIF
CMP AL,'C'-'@'
retnz
STATCHK ENDP
procedure CNTCHAND,NEAR
; Ctrl-C handler.
; "^C" and CR/LF is printed. Then the user registers are restored and
; the user CTRL-C handler is executed. At this point the top of the stack
; has 1) the interrupt return address should the user CTRL-C handler wish
; to allow processing to continue; 2) the original interrupt return address
; to the code that performed the function call in the first place. If
; the user CTRL-C handler wishes to continue, it must leave all registers
; unchanged and RET (not IRET) with carry CLEAR. If carry is SET then
; an terminate system call is simulated.
MOV AL,3 ; Display "^C"
invoke BUFOUT
invoke CRLF
PUSH SS
POP DS
ASSUME DS:DOSGROUP
CMP BYTE PTR [CONSWAP],0
JZ NOSWAP
invoke SWAPBACK
NOSWAP:
CLI ; Prepare to play with stack
MOV SP,[user_SP]
MOV SS,[user_SS] ; User stack now restored
ASSUME SS:NOTHING
invoke restore_world ; User registers now restored
ASSUME DS:NOTHING
MOV BYTE PTR [INDOS],0 ; Go to known state
MOV BYTE PTR [ERRORMODE],0
MOV [ConC_spsave],SP ; save his SP
INT int_ctrl_c ; Execute user Ctrl-C handler
MOV [user_SS],AX ; save the AX
PUSHF ; and the flags (maybe new call)
POP AX
CMP SP,[ConC_spsave]
JNZ ctrlc_try_new ; new syscall maybe?
ctrlc_repeat:
MOV AX,[user_SS] ; no...
transfer COMMAND ; Repeat command otherwise
ctrlc_try_new:
SUB [ConC_spsave],2 ; Are there flags on the stack?
CMP SP,[ConC_spsave]
JZ ctrlc_new ; yes, new system call
ctrlc_abort:
MOV AX,(EXIT SHL 8) + 0
MOV BYTE PTR [DidCTRLC],0FFh
transfer COMMAND ; give up by faking $EXIT
ctrlc_new:
PUSH AX
POPF
POP [user_SS]
JNC ctrlc_repeat ; repeat operation
JMP ctrlc_abort ; indicate ^ced
CNTCHAND ENDP
SUBTTL DIVISION OVERFLOW INTERRUPT
PAGE
; Default handler for division overflow trap
procedure DIVOV,NEAR
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
MOV SI,OFFSET DOSGROUP:DIVMES
CALL RealDivOv
JMP ctrlc_abort ; Use Ctrl-C abort on divide overflow
DIVOV ENDP
;
; RealDivOv: perform actual divide overflow stuff.
; Inputs: none
; Outputs: message to BCON
;
procedure RealDivOv,NEAR ; Do divide overflow and clock process
PUSH CS ; get ES addressability
POP ES
PUSH CS ; get DS addressability
POP DS
ASSUME DS:DOSGROUP
MOV BYTE PTR [DskStCom],DevWrt
MOV BYTE PTR [DskStCall],DRdWrHL
MOV [DskSTST],0
MOV BL,[DivMesLen]
XOR BH,BH
MOV [DskStCnt],BX
MOV BX,OFFSET DOSGROUP:DskStCall
MOV WORD PTR [DskChRet+1],SI ; transfer address (need an EQU)
LDS SI,[BCON]
ASSUME DS:NOTHING
invoke DEVIOCALL2
MOV WORD PTR [DskChRet+1],OFFSET DOSGROUP:DevIOBuf
MOV [DskStCnt],1
return
RealDivOv ENDP
SUBTTL CHARHRD,HARDERR,ERROR -- HANDLE DISK ERRORS AND RETURN TO USER
PAGE
procedure CHARHARD,NEAR
ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGROUP
; Character device error handler
; Same function as HARDERR
MOV WORD PTR [EXITHOLD+2],ES
MOV WORD PTR [EXITHOLD],BP
PUSH SI
AND DI,STECODE
MOV BP,DS ;Device pointer is BP:SI
CALL FATALC
POP SI
return
CHARHARD ENDP
procedure HardErr,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Hard disk error handler. Entry conditions:
; DS:BX = Original disk transfer address
; DX = Original logical sector number
; CX = Number of sectors to go (first one gave the error)
; AX = Hardware error code
; DI = Original sector transfer count
; ES:BP = Base of drive parameters
; [READOP] = 0 for read, 1 for write
;
XCHG AX,DI ; Error code in DI, count in AX
AND DI,STECODE ; And off status bits
CMP DI,WRECODE ; Write Protect Error?
JNZ NOSETWRPERR
PUSH AX
MOV AL,ES:[BP.dpb_drive]
MOV BYTE PTR [WPERR],AL ; Flag drive with WP error
POP AX
NOSETWRPERR:
SUB AX,CX ; Number of sectors successfully transferred
ADD DX,AX ; First sector number to retry
PUSH DX
MUL ES:[BP.dpb_sector_size] ; Number of bytes transferred
POP DX
ADD BX,AX ; First address for retry
XOR AH,AH ; Flag disk section in error
CMP DX,ES:[BP.dpb_first_FAT] ; In reserved area?
JB ERRINT
INC AH ; Flag for FAT
CMP DX,ES:[BP.dpb_dir_sector] ; In FAT?
JB ERRINT
INC AH
CMP DX,ES:[BP.dpb_first_sector] ; In directory?
JB ERRINT
INC AH ; Must be in data area
ERRINT:
SHL AH,1 ; Make room for read/write bit
OR AH,BYTE PTR [READOP]
entry FATAL
MOV AL,ES:[BP.dpb_drive] ; Get drive number
entry FATAL1
MOV WORD PTR [EXITHOLD+2],ES
MOV WORD PTR [EXITHOLD],BP ; The only things we preserve
LES SI,ES:[BP.dpb_driver_addr]
MOV BP,ES ; BP:SI points to the device involved
FATALC:
CMP BYTE PTR [ERRORMODE],0
JNZ SETIGN ; No INT 24s if already INT 24
MOV [CONTSTK],SP
PUSH SS
POP ES
ASSUME ES:DOSGROUP
CLI ; Prepare to play with stack
INC BYTE PTR [ERRORMODE] ; Flag INT 24 in progress
DEC BYTE PTR [INDOS] ; INT 24 handler might not return
MOV SS,[user_SS]
ASSUME SS:NOTHING
MOV SP,ES:[user_SP] ; User stack pointer restored
INT int_fatal_abort ; Fatal error interrupt vector, must preserve ES
MOV ES:[user_SP],SP ; restore our stack
MOV ES:[user_SS],SS
MOV SP,ES
MOV SS,SP
ASSUME SS:DOSGROUP
MOV SP,[CONTSTK]
INC BYTE PTR [INDOS] ; Back in the DOS
MOV BYTE PTR [ERRORMODE],0 ; Back from INT 24
STI
IGNRET:
LES BP,[EXITHOLD]
ASSUME ES:NOTHING
CMP AL,2
JZ error_abort
MOV BYTE PTR [WPERR],-1 ;Forget about WP error
return
SETIGN:
XOR AL,AL ;Flag ignore
JMP SHORT IGNRET
error_abort:
PUSH SS
POP DS
ASSUME DS:DOSGROUP
CMP BYTE PTR [CONSWAP],0
JZ NOSWAP2
invoke SWAPBACK
NOSWAP2:
MOV BYTE PTR [exit_Type],Exit_hard_error
MOV DS,[CurrentPDB]
ASSUME DS:NOTHING
;
; reset_environment checks the DS value against the CurrentPDB. If they
; are different, then an old-style return is performed. If they are
; the same, then we release jfns and restore to parent. We still use
; the PDB at DS:0 as the source of the terminate addresses.
;
; output: none.
;
entry reset_environment
ASSUME DS:NOTHING,ES:NOTHING
PUSH DS ; save PDB of process
MOV AL,int_Terminate
invoke $Get_interrupt_vector ; and who to go to
MOV WORD PTR [EXITHOLD+2],ES ; save return address
MOV WORD PTR [EXITHOLD],BX
MOV BX,[CurrentPDB] ; get current process
MOV DS,BX ;
MOV AX,DS:[PDB_Parent_PID] ; get parent to return to
POP CX
;
; AX = parentPDB, BX = CurrentPDB, CX = ThisPDB
; Only free handles if AX <> BX and BX = CX and [exit_code].upper is not
; Exit_keep_process
;
CMP AX,BX
JZ reset_return ; parentPDB = CurrentPDB
CMP BX,CX
JNZ reset_return ; CurrentPDB <> ThisPDB
PUSH AX ; save parent
CMP BYTE PTR [exit_type],Exit_keep_process
JZ reset_to_parent ; keeping this process
invoke arena_free_process
; reset environment at [CurrentPDB]; close those handles
MOV CX,FilPerProc
reset_free_jfn:
MOV BX,CX
PUSH CX
DEC BX ; get jfn
invoke $CLOSE ; close it, ignore return
POP CX
LOOP reset_free_jfn ; and do 'em all
reset_to_parent:
POP [CurrentPDB] ; set up process as parent
reset_return: ; come here for normal return
PUSH CS
POP DS
ASSUME DS:DOSGROUP
MOV AL,-1
invoke FLUSHBUF ; make sure that everything is clean
CLI
MOV BYTE PTR [INDOS],0 ;Go to known state
MOV BYTE PTR [WPERR],-1 ;Forget about WP error
;
; Snake into multitasking... Get stack from CurrentPDB person
;
MOV DS,[CurrentPDB]
ASSUME DS:NOTHING
MOV SS,WORD PTR DS:[PDB_user_stack+2]
MOV SP,WORD PTR DS:[PDB_user_stack]
ASSUME SS:NOTHING
invoke restore_world
ASSUME ES:NOTHING
POP AX ; suck off CS:IP of interrupt...
POP AX
POP AX
MOV AX,0F202h ; STI
PUSH AX
PUSH WORD PTR [EXITHOLD+2]
PUSH WORD PTR [EXITHOLD]
STI
IRET ; Long return back to user terminate address
HardErr ENDP
ASSUME SS:DOSGROUP
do_ext
CODE ENDS
END

1264
v2.0/source/DEBASM.ASM Normal file

File diff suppressed because it is too large Load Diff

694
v2.0/source/DEBCOM1.ASM Normal file
View File

@ -0,0 +1,694 @@
TITLE PART1 DEBUGGER COMMANDS
; Routines to perform debugger commands except ASSEMble and UASSEMble
.xlist
.xcref
INCLUDE DEBEQU.ASM
INCLUDE DOSSYM.ASM
.cref
.list
CODE SEGMENT PUBLIC BYTE 'CODE'
CODE ENDS
CONST SEGMENT PUBLIC BYTE
EXTRN SYNERR:BYTE
EXTRN DISPB:WORD,DSIZ:BYTE,DSSAVE:WORD
if sysver
EXTRN CIN:DWORD,PFLAG:BYTE
endif
CONST ENDS
DATA SEGMENT PUBLIC BYTE
EXTRN DEFLEN:WORD,BYTEBUF:BYTE,DEFDUMP:BYTE
DATA ENDS
DG GROUP CODE,CONST,DATA
CODE SEGMENT PUBLIC BYTE 'CODE'
ASSUME CS:DG,DS:DG,ES:DG,SS:DG
PUBLIC HEXCHK,GETHEX1,PRINT,DSRANGE,ADDRESS,HEXIN,PERROR
PUBLIC GETHEX,GET_ADDRESS,GETEOL,GETHX,PERR
PUBLIC PERR,MOVE,DUMP,ENTER,FILL,SEARCH,DEFAULT
if sysver
PUBLIC IN
EXTRN DISPREG:NEAR,DEVIOCALL:NEAR
endif
EXTRN OUT:NEAR,CRLF:NEAR,OUTDI:NEAR,OUTSI:NEAR,SCANP:NEAR
EXTRN SCANB:NEAR,BLANK:NEAR,TAB:NEAR,PRINTMES:NEAR,COMMAND:NEAR
EXTRN HEX:NEAR,BACKUP:NEAR
DEBCOM1:
; RANGE - Looks for parameters defining an address range.
; The first parameter is the starting address. The second parameter
; may specify the ending address, or it may be preceded by
; "L" and specify a length (4 digits max), or it may be
; omitted and a length of 128 bytes is assumed. Returns with
; segment in AX, displacement in DX, and length in CX.
DSRANGE:
MOV BP,[DSSAVE] ; Set default segment to DS
MOV [DEFLEN],128 ; And default length to 128 bytes
RANGE:
CALL ADDRESS
PUSH AX ; Save segment
PUSH DX ; Save offset
CALL SCANP ; Get to next parameter
MOV AL,[SI]
CMP AL,"L" ; Length indicator?
JE GETLEN
MOV DX,[DEFLEN] ; Default length
CALL HEXIN ; Second parameter present?
JC GetDef ; If not, use default
MOV CX,4
CALL GETHEX ; Get ending address (same segment)
MOV CX,DX ; Low 16 bits of ending addr.
POP DX ; Low 16 bits of starting addr.
SUB CX,DX ; Compute range
JAE DSRNG2
DSRNG1: JMP PERROR ; Negative range
DSRNG2: INC CX ; Include last location
JCXZ DSRNG1 ; Wrap around error
POP AX ; Restore segment
RET
GetDef:
POP CX ; get original offset
PUSH CX ; save it
NEG CX ; rest of segment
JZ RngRet ; use default
CMP CX,DX ; more room in segment?
JAE RngRet ; yes, use default
JMP RngRet1 ; no, length is in CX
GETLEN:
INC SI ; Skip over "L" to length
MOV CX,4 ; Length may have 4 digits
CALL GETHEX ; Get the range
RNGRET:
MOV CX,DX ; Length
RngRet1:
POP DX ; Offset
MOV AX,CX
ADD AX,DX
JNC OKRET
CMP AX,1
JAE DSRNG1 ; Look for wrap error
OKRET:
POP AX ; Segment
RET
DEFAULT:
; DI points to default address and CX has default length
CALL SCANP
JZ USEDEF ; Use default if no parameters
MOV [DEFLEN],CX
CALL RANGE
JMP GETEOL
USEDEF:
MOV SI,DI
LODSW ; Get default displacement
MOV DX,AX
LODSW ; Get default segment
RET
; Dump an area of memory in both hex and ASCII
DUMP:
MOV BP,[DSSAVE]
MOV CX,DISPB
MOV DI,OFFSET DG:DEFDUMP
CALL DEFAULT ; Get range if specified
MOV DS,AX ; Set segment
MOV SI,DX ; SI has displacement in segment
IF ZIBO
PUSH SI ; save SI away
AND SI,0FFF0h ; convert to para number
CALL OutSI ; display location
POP SI ; get SI back
MOV AX,SI ; move offset
MOV AH,3 ; spaces per byte
AND AL,0Fh ; convert to real offset
MUL AH ; compute (AL+1)*3-1
OR AL,AL ; set flag
JZ InRow ; if xero go on
PUSH CX ; save count
MOV CX,AX ; move to convenient spot
CALL Tab ; move over
POP CX ; get back count
JMP InRow ; display line
ENDIF
ROW:
CALL OUTSI ; Print address at start of line
InRow:
PUSH SI ; Save address for ASCII dump
CALL BLANK
BYTE0:
CALL BLANK ; Space between bytes
BYTE1:
LODSB ; Get byte to dump
CALL HEX ; and display it
POP DX ; DX has start addr. for ASCII dump
DEC CX ; Drop loop count
JZ ToAscii ; If through do ASCII dump
MOV AX,SI
TEST AL,CS:(BYTE PTR DSIZ) ; On 16-byte boundary?
JZ ENDROW
PUSH DX ; Didn't need ASCII addr. yet
TEST AL,7 ; On 8-byte boundary?
JNZ BYTE0
MOV AL,"-" ; Mark every 8 bytes
CALL OUT
JMP SHORT BYTE1
ENDROW:
CALL ASCII ; Show it in ASCII
JMP SHORT ROW ; Loop until count is zero
ToAscii:
MOV AX,SI ; get offset
AND AL,0Fh ; real offset
JZ ASCII ; no loop if already there
SUB AL,10h ; remainder
NEG AL
MOV CL,3
MUL CL
MOV CX,AX ; number of chars to move
CALL Tab
ASCII:
PUSH CX ; Save byte count
MOV AX,SI ; Current dump address
MOV SI,DX ; ASCII dump address
SUB AX,DX ; AX=length of ASCII dump
IF NOT ZIBO
; Compute tab length. ASCII dump always appears on right side
; screen regardless of how many bytes were dumped. Figure 3
; characters for each byte dumped and subtract from 51, which
; allows a minimum of 3 blanks after the last byte dumped.
MOV BX,AX
SHL AX,1 ; Length times 2
ADD AX,BX ; Length times 3
MOV CX,51
SUB CX,AX ; Amount to tab in CX
CALL TAB
MOV CX,BX ; ASCII dump length back in CX
ELSE
MOV CX,SI ; get starting point
DEC CX
AND CX,0Fh
INC CX
AND CX,0Fh
ADD CX,3 ; we have the correct number to tab
PUSH AX ; save count
CALL TAB
POP CX ; get count back
ENDIF
ASCDMP:
LODSB ; Get ASCII byte to dump
AND AL,7FH ; ASCII uses 7 bits
CMP AL,7FH ; Don't try to print RUBOUT
JZ NOPRT
CMP AL," " ; Check for control characters
JNC PRIN
NOPRT:
MOV AL,"." ; If unprintable character
PRIN:
CALL OUT ; Print ASCII character
LOOP ASCDMP ; CX times
POP CX ; Restore overall dump length
MOV ES:WORD PTR [DEFDUMP],SI
MOV ES:WORD PTR [DEFDUMP+2],DS ; Save last address as default
CALL CRLF ; Print CR/LF and return
RET
; Block move one area of memory to another. Overlapping moves
; are performed correctly, i.e., so that a source byte is not
; overwritten until after it has been moved.
MOVE:
CALL DSRANGE ; Get range of source area
PUSH CX ; Save length
PUSH AX ; Save segment
PUSH DX ; Save source displacement
CALL ADDRESS ; Get destination address (same segment)
CALL GETEOL ; Check for errors
POP SI
MOV DI,DX ; Set dest. displacement
POP BX ; Source segment
MOV DS,BX
MOV ES,AX ; Destination segment
POP CX ; Length
CMP DI,SI ; Check direction of move
SBB AX,BX ; Extend the CMP to 32 bits
JB COPYLIST ; Move forward into lower mem.
; Otherwise, move backward. Figure end of source and destination
; areas and flip direction flag.
DEC CX
ADD SI,CX ; End of source area
ADD DI,CX ; End of destination area
STD ; Reverse direction
INC CX
COPYLIST:
MOVSB ; Do at least 1 - Range is 1-10000H not 0-FFFFH
DEC CX
REP MOVSB ; Block move
RET1: RET
; Fill an area of memory with a list values. If the list
; is bigger than the area, don't use the whole list. If the
; list is smaller, repeat it as many times as necessary.
FILL:
CALL DSRANGE ; Get range to fill
PUSH CX ; Save length
PUSH AX ; Save segment number
PUSH DX ; Save displacement
CALL LIST ; Get list of values to fill with
POP DI ; Displacement in segment
POP ES ; Segment
POP CX ; Length
CMP BX,CX ; BX is length of fill list
MOV SI,OFFSET DG:BYTEBUF ; List is in byte buffer
JCXZ BIGRNG
JAE COPYLIST ; If list is big, copy part of it
BIGRNG:
SUB CX,BX ; How much bigger is area than list?
XCHG CX,BX ; CX=length of list
PUSH DI ; Save starting addr. of area
REP MOVSB ; Move list into area
POP SI
; The list has been copied into the beginning of the
; specified area of memory. SI is the first address
; of that area, DI is the end of the copy of the list
; plus one, which is where the list will begin to repeat.
; All we need to do now is copy [SI] to [DI] until the
; end of the memory area is reached. This will cause the
; list to repeat as many times as necessary.
MOV CX,BX ; Length of area minus list
PUSH ES ; Different index register
POP DS ; requires different segment reg.
JMP SHORT COPYLIST ; Do the block move
; Search a specified area of memory for given list of bytes.
; Print address of first byte of each match.
SEARCH:
CALL DSRANGE ; Get area to be searched
PUSH CX ; Save count
PUSH AX ; Save segment number
PUSH DX ; Save displacement
CALL LIST ; Get search list
DEC BX ; No. of bytes in list-1
POP DI ; Displacement within segment
POP ES ; Segment
POP CX ; Length to be searched
SUB CX,BX ; minus length of list
SCAN:
MOV SI,OFFSET DG:BYTEBUF ; List kept in byte buffer
LODSB ; Bring first byte into AL
DOSCAN:
SCASB ; Search for first byte
LOOPNE DOSCAN ; Do at least once by using LOOP
JNZ RET1 ; Exit if not found
PUSH BX ; Length of list minus 1
XCHG BX,CX
PUSH DI ; Will resume search here
REPE CMPSB ; Compare rest of string
MOV CX,BX ; Area length back in CX
POP DI ; Next search location
POP BX ; Restore list length
JNZ TEST ; Continue search if no match
DEC DI ; Match address
CALL OUTDI ; Print it
INC DI ; Restore search address
CALL CRLF
TEST:
JCXZ RET1
JMP SHORT SCAN ; Look for next occurrence
; Get the next parameter, which must be a hex number.
; CX is maximum number of digits the number may have.
GETHX:
CALL SCANP
GETHX1:
XOR DX,DX ; Initialize the number
CALL HEXIN ; Get a hex digit
JC HXERR ; Must be one valid digit
MOV DL,AL ; First 4 bits in position
GETLP:
INC SI ; Next char in buffer
DEC CX ; Digit count
CALL HEXIN ; Get another hex digit?
JC RETHX ; All done if no more digits
STC
JCXZ HXERR ; Too many digits?
SHL DX,1 ; Multiply by 16
SHL DX,1
SHL DX,1
SHL DX,1
OR DL,AL ; and combine new digit
JMP SHORT GETLP ; Get more digits
GETHEX:
CALL GETHX ; Scan to next parameter
JMP SHORT GETHX2
GETHEX1:
CALL GETHX1
GETHX2: JC PERROR
RETHX: CLC
HXERR: RET
; Check if next character in the input buffer is a hex digit
; and convert it to binary if it is. Carry set if not.
HEXIN:
MOV AL,[SI]
; Check if AL has a hex digit and convert it to binary if it
; is. Carry set if not.
HEXCHK:
SUB AL,"0" ; Kill ASCII numeric bias
JC RET2
CMP AL,10
CMC
JNC RET2 ; OK if 0-9
AND AL,5FH
SUB AL,7 ; Kill A-F bias
CMP AL,10
JC RET2
CMP AL,16
CMC
RET2: RET
; Process one parameter when a list of bytes is
; required. Carry set if parameter bad. Called by LIST.
LISTITEM:
CALL SCANP ; Scan to parameter
CALL HEXIN ; Is it in hex?
JC STRINGCHK ; If not, could be a string
MOV CX,2 ; Only 2 hex digits for bytes
CALL GETHEX ; Get the byte value
MOV [BX],DL ; Add to list
INC BX
GRET: CLC ; Parameter was OK
RET
STRINGCHK:
MOV AL,[SI] ; Get first character of param
CMP AL,"'" ; String?
JZ STRING
CMP AL,'"' ; Either quote is all right
JZ STRING
STC ; Not string, not hex - bad
RET
STRING:
MOV AH,AL ; Save for closing quote
INC SI
STRNGLP:
LODSB ; Next char of string
CMP AL,13 ; Check for end of line
JZ PERR ; Must find a close quote
CMP AL,AH ; Check for close quote
JNZ STOSTRG ; Add new character to list
CMP AH,[SI] ; Two quotes in a row?
JNZ GRET ; If not, we're done
INC SI ; Yes - skip second one
STOSTRG:
MOV [BX],AL ; Put new char in list
INC BX
JMP SHORT STRNGLP ; Get more characters
; Get a byte list for ENTER, FILL or SEARCH. Accepts any number
; of 2-digit hex values or character strings in either single
; (') or double (") quotes.
LIST:
MOV BX,OFFSET DG:BYTEBUF ; Put byte list in the byte buffer
LISTLP:
CALL LISTITEM ; Process a parameter
JNC LISTLP ; If OK, try for more
SUB BX,OFFSET DG:BYTEBUF ; BX now has no. of bytes in list
JZ PERROR ; List must not be empty
; Make sure there is nothing more on the line except for
; blanks and carriage return. If there is, it is an
; unrecognized parameter and an error.
GETEOL:
CALL SCANB ; Skip blanks
JNZ PERROR ; Better be a RETURN
RET3: RET
; Command error. SI has been incremented beyond the
; command letter so it must decremented for the
; error pointer to work.
PERR:
DEC SI
; Syntax error. SI points to character in the input buffer
; which caused error. By subtracting from start of buffer,
; we will know how far to tab over to appear directly below
; it on the terminal. Then print "^ Error".
PERROR:
SUB SI,OFFSET DG:(BYTEBUF-1); How many char processed so far?
MOV CX,SI ; Parameter for TAB in CX
CALL TAB ; Directly below bad char
MOV SI,OFFSET DG:SYNERR ; Error message
; Print error message and abort to command level
PRINT:
CALL PRINTMES
JMP COMMAND
; Gets an address in Segment:Displacement format. Segment may be omitted
; and a default (kept in BP) will be used, or it may be a segment
; register (DS, ES, SS, CS). Returns with segment in AX, OFFSET in DX.
ADDRESS:
CALL GET_ADDRESS
JC PERROR
ADRERR: STC
RET
GET_ADDRESS:
CALL SCANP
MOV AL,[SI+1]
CMP AL,"S"
JZ SEGREG
MOV CX,4
CALL GETHX
JC ADRERR
MOV AX,BP ; Get default segment
CMP BYTE PTR [SI],":"
JNZ GETRET
PUSH DX
GETDISP:
INC SI ; Skip over ":"
MOV CX,4
CALL GETHX
POP AX
JC ADRERR
GETRET: CLC
RET
SEGREG:
MOV AL,[SI]
MOV DI,OFFSET DG:SEGLET
MOV CX,4
REPNE SCASB
JNZ ADRERR
INC SI
INC SI
SHL CX,1
MOV BX,CX
CMP BYTE PTR [SI],":"
JNZ ADRERR
PUSH [BX+DSSAVE]
JMP SHORT GETDISP
SEGLET DB "CSED"
; Short form of ENTER command. A list of values from the
; command line are put into memory without using normal
; ENTER mode.
GETLIST:
CALL LIST ; Get the bytes to enter
POP DI ; Displacement within segment
POP ES ; Segment to enter into
MOV SI,OFFSET DG:BYTEBUF ; List of bytes is in byte 2uffer
MOV CX,BX ; Count of bytes
REP MOVSB ; Enter that byte list
RET
; Enter values into memory at a specified address. If the
; line contains nothing but the address we go into "enter
; mode", where the address and its current value are printed
; and the user may change it if desired. To change, type in
; new value in hex. Backspace works to correct errors. If
; an illegal hex digit or too many digits are typed, the
; bell is sounded but it is otherwise ignored. To go to the
; next byte (with or without change), hit space bar. To
; back CLDto a previous address, type "-". On
; every 8-byte boundary a new line is started and the address
; is printed. To terminate command, type carriage return.
; Alternatively, the list of bytes to be entered may be
; included on the original command line immediately following
; the address. This is in regular LIST format so any number
; of hex values or strings in quotes may be entered.
ENTER:
MOV BP,[DSSAVE] ; Set default segment to DS
CALL ADDRESS
PUSH AX ; Save for later
PUSH DX
CALL SCANB ; Any more parameters?
JNZ GETLIST ; If not end-of-line get list
POP DI ; Displacement of ENTER
POP ES ; Segment
GETROW:
CALL OUTDI ; Print address of entry
CALL BLANK ; Leave a space
CALL BLANK
GETBYTE:
MOV AL,ES:[DI] ; Get current value
CALL HEX ; And display it
PUTDOT:
MOV AL,"."
CALL OUT ; Prompt for new value
MOV CX,2 ; Max of 2 digits in new value
MOV DX,0 ; Intial new value
GETDIG:
CALL IN ; Get digit from user
MOV AH,AL ; Save
CALL HEXCHK ; Hex digit?
XCHG AH,AL ; Need original for echo
JC NOHEX ; If not, try special command
MOV DH,DL ; Rotate new value
MOV DL,AH ; And include new digit
LOOP GETDIG ; At most 2 digits
; We have two digits, so all we will accept now is a command.
DWAIT:
CALL IN ; Get command character
NOHEX:
CMP AL,8 ; Backspace
JZ BS
CMP AL,7FH ; RUBOUT
JZ RUB
CMP AL,"-" ; Back CLDto previous address
JZ PREV
CMP AL,13 ; All done with command?
JZ EOL
CMP AL," " ; Go to next address
JZ NEXT
MOV AL,8
CALL OUT ; Back CLDover illegal character
CALL BACKUP
JCXZ DWAIT
JMP SHORT GETDIG
RUB:
MOV AL,8
CALL OUT
BS:
CMP CL,2 ; CX=2 means nothing typed yet
JZ PUTDOT ; Put back the dot we backed CLDover
INC CL ; Accept one more character
MOV DL,DH ; Rotate out last digit
MOV DH,CH ; Zero this digit
CALL BACKUP ; Physical backspace
JMP SHORT GETDIG ; Get more digits
; If new value has been entered, convert it to binary and
; put into memory. Always bump pointer to next location
STORE:
CMP CL,2 ; CX=2 means nothing typed yet
JZ NOSTO ; So no new value to store
; Rotate DH left 4 bits to combine with DL and make a byte value
PUSH CX
MOV CL,4
SHL DH,CL
POP CX
OR DL,DH ; Hex is now converted to binary
MOV ES:[DI],DL ; Store new value
NOSTO:
INC DI ; Prepare for next location
RET
NEXT:
CALL STORE ; Enter new value
INC CX ; Leave a space plus two for
INC CX ; each digit not entered
CALL TAB
MOV AX,DI ; Next memory address
AND AL,7 ; Check for 8-byte boundary
JNZ GETBYTE ; Take 8 per line
NEWROW:
CALL CRLF ; Terminate line
JMP GETROW ; Print address on new line
PREV:
CALL STORE ; Enter the new value
; DI has been bumped to next byte. Drop it 2 to go to previous addr
DEC DI
DEC DI
JMP SHORT NEWROW ; Terminate line after backing CLD
EOL:
CALL STORE ; Enter the new value
JMP CRLF ; CR/LF and terminate
; Console input of single character
IF SYSVER
IN:
PUSH DS
PUSH SI
LDS SI,CS:[CIN]
MOV AH,4
CALL DEVIOCALL
POP SI
POP DS
CMP AL,3
JNZ NOTCNTC
INT 23H
NOTCNTC:
CMP AL,'P'-'@'
JZ PRINTON
CMP AL,'N'-'@'
JZ PRINTOFF
CALL OUT
RET
PRINTOFF:
PRINTON:
NOT [PFLAG]
JMP SHORT IN
ELSE
IN:
MOV AH,1
INT 21H
RET
ENDIF
CODE ENDS
END DEBCOM1

1269
v2.0/source/DEBCOM2.ASM Normal file

File diff suppressed because it is too large Load Diff

1103
v2.0/source/DEBCONST.ASM Normal file

File diff suppressed because it is too large Load Diff

BIN
v2.0/source/DEBDATA.ASM Normal file

Binary file not shown.

32
v2.0/source/DEBEQU.ASM Normal file
View File

@ -0,0 +1,32 @@
FALSE EQU 0
TRUE EQU NOT FALSE
IBMVER EQU true ; Set conditional switches
MSVER EQU false
SYSVER EQU FALSE ; if true, i/o direct to bios
; so DOS can be debugged
IBMJAPAN EQU FALSE
SETCNTC EQU TRUE ; If this is FALSE, DEBUG will not set
; the Control C int vector
ZIBO EQU TRUE ; true if P traces over interrupts
; and calls and dump looks pretty
PROMPT EQU "-"
FCB EQU 5CH
EXEFCB EQU FCB
BUFLEN EQU 80 ; Maximum length of line input buffer
BPMAX EQU 10 ; Maximum number of breakpoints
BPLEN EQU 5*BPMAX ; Length of breakpoint table
REGTABLEN EQU 14 ; Number of registers
SEGDIF EQU 0
BUFSIZ EQU 512
BXREG EQU "B"+5800H ; "BX"
BPREG EQU "B"+5000H ; "BP"
SIREG EQU "S"+4900H ; "SI"
DIREG EQU "D"+4900H ; "DI"
COMMA EQU 2C00H
OPBUFLEN EQU 35


BIN
v2.0/source/DEBMES.ASM Normal file

Binary file not shown.

868
v2.0/source/DEBUASM.ASM Normal file
View File

@ -0,0 +1,868 @@
TITLE DEBUASM
; Code for the UASSEMble command in the debugger
.xlist
.xcref
INCLUDE DEBEQU.ASM
INCLUDE DOSSYM.ASM
.cref
.list
CODE SEGMENT PUBLIC BYTE 'CODE'
CODE ENDS
CONST SEGMENT PUBLIC BYTE
EXTRN SYNERR:BYTE
EXTRN NSEG:WORD,SISAVE:WORD,BPSAVE:WORD,DISAVE:WORD
EXTRN BXSAVE:WORD,DSSAVE:WORD,ESSAVE:WORD,CSSAVE:WORD,IPSAVE:WORD
EXTRN SSSAVE:WORD,CXSAVE:WORD,SPSAVE:WORD,FSAVE:WORD
EXTRN DISTAB:WORD,SHFTAB:WORD,IMMTAB:WORD,GRP1TAB:WORD,GRP2TAB:WORD
EXTRN DBMN:BYTE,ESCMN:BYTE,DISPB:WORD,STACK:BYTE,REG8:BYTE
EXTRN REG16:BYTE,SREG:BYTE,SIZ8:BYTE,SEGTAB:WORD,M8087_TAB:BYTE
EXTRN FI_TAB:BYTE,SIZE_TAB:BYTE,MD9_TAB:BYTE,MD9_TAB2:BYTE
EXTRN MDB_TAB:BYTE,MDB_TAB2:BYTE,MDD_TAB:BYTE,MDD_TAB2:BYTE
EXTRN MDF_TAB:BYTE
CONST ENDS
DATA SEGMENT PUBLIC BYTE
EXTRN DISADD:BYTE,DISCNT:WORD,BYTCNT:BYTE,TEMP:BYTE,AWORD:BYTE
EXTRN MIDFLD:BYTE,MODE:BYTE,REGMEM:BYTE,OPCODE:WORD,OPBUF:BYTE
EXTRN INDEX:WORD
DATA ENDS
DG GROUP CODE,CONST,DATA
CODE SEGMENT PUBLIC BYTE 'CODE'
ASSUME CS:DG,DS:DG,ES:DG,SS:DG
PUBLIC UNASSEM
PUBLIC DISASLN,MEMIMM,JMPCALL,SIGNIMM,ALUFROMREG,WORDTOALU
PUBLIC GRP2,PREFIX,OUTVARW,GRP1,SSPRE,MOVSEGTO,DSPRE,SHIFT
PUBLIC ESPRE,IMMED,CSPRE,OUTVARB,CHK10,ACCIMM,INT3,INVARB
PUBLIC MOVSEGFROM,LOADACC,OUTFIXB,XCHGAX,REGIMMW,SHORTJMP
PUBLIC SAV8,M8087,M8087_DB,M8087_DF,M8087_D9,M8087_DD
PUBLIC SAV16,SAVHEX,INFIXW,REGIMMB,OUTFIXW,SHIFTV,LONGJMP
PUBLIC INVARW,STOREACC,INFIXB,NOOPERANDS,ALUTOREG
PUBLIC SEGOP,REGOP,GETADDR
EXTRN CRLF:NEAR,PRINTMES:NEAR,BLANK:NEAR,TAB:NEAR,OUT:NEAR
EXTRN HEX:NEAR,DEFAULT:NEAR,OUTSI:NEAR,OUTDI:NEAR
UNASSEM:
MOV BP,[CSSAVE] ; Default code segment
MOV DI,OFFSET DG:DISADD ; Default address
MOV CX,DISPB ; Default length
SHR CX,1
SHR CX,1
CALL DEFAULT
MOV WORD PTR [DISADD],DX ; Displacement of disassembly
MOV WORD PTR [DISADD+2],AX ; Segment
MOV WORD PTR [DISCNT],CX ; No. of bytes (but whole instructions)
DISLP:
CALL DISASLN ; Disassemble one line
CALL CRLF
TEST [DISCNT],-1 ; See if we've used up the range
JNZ DISLP
RET
GOTDIS: PUSH DS ; RE-GET LAST BYTE
PUSH SI
LDS SI,DWORD PTR [DISADD]
MOV AL,[SI-1]
POP SI
POP DS
RET
GETDIS:
PUSH DS
LDS SI,DWORD PTR [DISADD]
LODSB ; Get the next byte of code
POP DS
MOV WORD PTR [DISADD],SI ; Update pointer
PUSH AX
CALL HEX ; Display each code byte
MOV SI,[DISCNT]
OR SI,SI ; Check if range exhausted
JZ ENDRNG ; If so, don't wrap around
DEC SI ; Count off the bytes
MOV [DISCNT],SI
ENDRNG:
INC BYTE PTR[BYTCNT] ; Keep track of no. of bytes per line
POP AX
RET
DSPRE: INC BYTE PTR [NSEG+1]
SSPRE: INC BYTE PTR [NSEG+1]
CSPRE: INC BYTE PTR [NSEG+1]
ESPRE: INC BYTE PTR [NSEG+1]
PREFIX:
POP BX ; Dump off return address
CALL FINLN
CALL CRLF
DISASLN:
PUSH DS
LDS SI,DWORD PTR [DISADD]
CALL OUTSI ; Show disassembly address
POP DS
CALL BLANK
DISASLN1:
MOV BYTE PTR [BYTCNT],0 ; Count of code bytes per line
MOV DI,OFFSET DG:OPBUF ; Point to operand buffer
MOV AL," "
MOV CX,OPBUFLEN-1 ; Don't do last byte which has end marker
REP STOSB ; Initialize operand buffer to blanks
MOV BYTE PTR [DI]," "+80H
CALL GETDIS ; Get opcode
MOV AH,0
MOV BX,AX
AND AL,1 ; Mask to "W" bit
MOV [AWORD],AL
MOV AL,BL ; Restore opcode
SHL BX,1
SHL BX,1 ; Multiply opcode by 4
ADD BX,OFFSET DG:DISTAB
MOV DX,[BX] ; Get pointer to mnemonic from table
MOV [OPCODE],DX ; Save it until line is complete
MOV DI,OFFSET DG:OPBUF ; Initialize for opcode routines
CALL WORD PTR [BX+2] ; Dispatch to opcode routine
FINLN:
MOV SI,OFFSET DG:DISADD
MOV AH,[BYTCNT] ; See how many bytes in this instruction
ADD AH,AH ; Each uses two characters
MOV AL,14 ; Amount of space we want to use
SUB AL,AH ; See how many fill characters needed
CBW
XCHG CX,AX ; Parameter for TAB needed in CX
CALL TAB
MOV SI,[OPCODE]
OR SI,SI ; MAKE SURE THERE IS SOMETHING TO PRINT
JZ NOOPC
CALL PRINTMES ; Print opcode mnemonic
MOV AL,9
CALL OUT ; and a tab
NOOPC: MOV SI,OFFSET DG:OPBUF
JMP PRINTMES ; and the operand buffer
GETMODE:
CALL GETDIS ; Get the address mode byte
MOV AH,AL
AND AL,7 ; Mask to "r/m" field
MOV [REGMEM],AL
SHR AH,1
SHR AH,1
SHR AH,1
MOV AL,AH
AND AL,7 ; Mask to center 3-bit field
MOV [MIDFLD],AL
SHR AH,1
SHR AH,1
SHR AH,1
MOV [MODE],AH ; Leaving 2-bit "MOD" field
RET
IMMED:
MOV BX,OFFSET DG:IMMTAB
CALL GETMNE
FINIMM:
CALL TESTREG
JMP SHORT IMM
MEMIMM:
CALL GETMODE
JMP SHORT FINIMM
ACCIMM:
XOR AL,AL
IMM1:
CALL SAVREG
IMM:
MOV AL,","
STOSB
TEST BYTE PTR [AWORD],-1
JNZ SAV16
SAV8:
CALL GETDIS
JMP SHORT SAVHEX
LONGJMP:
PUSH DI
MOV DI,OFFSET DG:TEMP
CALL SAV16
POP DI
CALL SAV16
MOV AL,":"
STOSB
MOV SI,OFFSET DG:TEMP
MOV CX,4
MOVDIG:
LODSB
STOSB
LOOP MOVDIG
RET
SAV16:
CALL GETDIS ; Get low byte
MOV DL,AL
CALL GETDIS ; Get high byte
MOV DH,AL
CALL SAVHEX ; Convert and store high byte
MOV AL,DL
SAVHEX:
MOV AH,AL
SHR AL,1
SHR AL,1
SHR AL,1
SHR AL,1
CALL SAVDIG
MOV AL,AH
SAVDIG:
AND AL,0FH
ADD AL,90H
DAA
ADC AL,40H
DAA
STOSB
RET
CHK10:
CALL GETDIS
CMP AL,10
JNZ SAVHEX
RET
SIGNIMM:
MOV BX,OFFSET DG:IMMTAB
CALL GETMNE
CALL TESTREG
MOV AL,","
STOSB
SAVD8:
CALL GETDIS ; Get signed 8-bit number
CBW
MOV DX,AX ; Save true 16-bit value in DX
MOV AH,AL
MOV AL,"+"
OR AH,AH
; JZ nosign
JNS POSITIV ; OK if positive
MOV AL,"-"
NEG AH ; Get magnitude if negative
POSITIV:
STOSB
; nosign:
MOV AL,AH
JMP SHORT SAVHEX
ALUFROMREG:
CALL GETADDR
MOV AL,","
STOSB
REGFLD:
MOV AL,[MIDFLD]
SAVREG:
MOV SI,OFFSET DG:REG8
CMP BYTE PTR [AWORD],1
JNE FNDREG
SAVREG16:
MOV SI,OFFSET DG:REG16
FNDREG:
CBW
ADD SI,AX
ADD SI,AX
MOVSW
RET
SEGOP:
SHR AL,1
SHR AL,1
SHR AL,1
SAVSEG:
AND AL,3
MOV SI,OFFSET DG:SREG
JMP SHORT FNDREG
REGOP:
AND AL,7
JMP SHORT SAVREG16
MOVSEGTO:
MOV BYTE PTR [AWORD],1
CALL GETADDR
MOV AL,","
STOSB
MOV AL,[MIDFLD]
JMP SHORT SAVSEG
MOVSEGFROM:
CALL GETMODE
CALL SAVSEG
MOV BYTE PTR [AWORD],1
JMP SHORT MEMOP2
GETADDR:
CALL GETMODE
JMP SHORT ADDRMOD
WORDTOALU:
MOV BYTE PTR [AWORD],1
ALUTOREG:
CALL GETMODE
CALL REGFLD
MEMOP2:
MOV AL,","
STOSB
ADDRMOD:
CMP BYTE PTR [MODE],3
MOV AL,[REGMEM]
JE SAVREG
XOR BX,BX
MOV BYTE PTR [NSEG],3
MOV BYTE PTR [DI],"["
INC DI
CMP AL,6
JNE NODRCT
CMP BYTE PTR [MODE],0
JE DIRECT ; Mode=0 and R/M=6 means direct addr.
NODRCT:
MOV DL,AL
CMP AL,1
JBE USEBX
CMP AL,7
JE USEBX
CMP AL,3
JBE USEBP
CMP AL,6
JNE CHKPLS
USEBP:
MOV BX,[BPSAVE]
MOV BYTE PTR [NSEG],2 ; Change default to Stack Segment
MOV AX,BPREG
SAVBASE:
STOSW
CHKPLS:
CMP DL,4
JAE NOPLUS
MOV AL,"+"
STOSB
NOPLUS:
CMP DL,6
JAE DOMODE ; No index register
AND DL,1 ; Even for SI, odd for DI
JZ USESI
ADD BX,[DISAVE]
MOV AX,DIREG
SAVINDX:
STOSW
DOMODE:
MOV AL,[MODE]
OR AL,AL
JZ CLOSADD ; If no displacement, then done
CMP AL,2
JZ ADDDIR
CALL SAVD8 ; Signed 8-bit displacement
ADDCLOS:
ADD BX,DX
CLOSADD:
MOV AL,"]"
STOSB
MOV [INDEX],BX
NOOPERANDS:
RET
ADDDIR:
MOV AL,"+"
STOSB
DIRECT:
CALL SAV16
JMP SHORT ADDCLOS
USEBX:
MOV BX,[BXSAVE]
MOV AX,BXREG
JMP SHORT SAVBASE
USESI:
ADD BX,[SISAVE]
MOV AX,SIREG
JMP SHORT SAVINDX
SHORTJMP:
CALL GETDIS
CBW
ADD AX,WORD PTR [DISADD]
XCHG DX,AX
SAVJMP:
MOV AL,DH
CALL SAVHEX
MOV AL,DL
JMP SAVHEX
JMPCALL:
CALL GETDIS
MOV DL,AL
CALL GETDIS
MOV DH,AL
ADD DX,WORD PTR [DISADD]
JMP SHORT SAVJMP
XCHGAX:
AND AL,7
CALL SAVREG16
MOV AL,","
STOSB
XOR AL,AL
JMP SAVREG16
LOADACC:
XOR AL,AL
CALL SAVREG
MOV AL,","
STOSB
MEMDIR:
MOV AL,"["
STOSB
XOR BX,BX
MOV BYTE PTR [NSEG],3
JMP DIRECT
STOREACC:
CALL MEMDIR
MOV AL,","
STOSB
XOR AL,AL
JMP SAVREG
REGIMMB:
MOV BYTE PTR [AWORD],0
JMP SHORT REGIMM
REGIMMW:
MOV BYTE PTR [AWORD],1
REGIMM:
AND AL,7
JMP IMM1
INT3:
MOV BYTE PTR [DI],"3"
RET
;
; 8087 instructions whose first byte is 0dfh
;
M8087_DF:
CALL GET64F
JZ ISDD3
MOV SI,OFFSET DG:MDF_TAB
JMP NODB3
;
; 8087 instructions whose first byte is 0ddh
;
M8087_DD:
CALL GET64F
JZ ISDD3
MOV SI,OFFSET DG:MDD_TAB
JMP NOD93
ISDD3:
MOV AL,DL
TEST AL,100B
JZ ISSTI
JMP ESC0
ISSTI: AND AL,11B
MOV SI,OFFSET DG:MDD_TAB2
MOV CL,AL
CALL MOVBYT
JMP PUTRST
;
; 8087 instructions whose first byte is 0dbh
;
M8087_DB:
CALL GET64F
JZ ISDB3
MOV SI,OFFSET DG:MDB_TAB
NODB3: CALL PUTOP
CALL PUTSIZE
JMP ADDRMOD
ISDB3:
MOV AL,DL
TEST AL,100B
JNZ ISDBIG
ESC0V: JMP ESC0
ISDBIG: CALL GOTDIS
AND AL,11111B
CMP AL,4
JAE ESC0V
MOV SI,OFFSET DG:MDB_TAB2
JMP DOBIG
;
; 8087 instructions whose first byte is 0d9h
;
M8087_D9:
CALL GET64F
JZ ISD93
MOV SI,OFFSET DG:MD9_TAB
NOD93: CALL PUTOP
AND AL,111B
CMP AL,3
JA NOSHO
MOV AL,DL
CALL PUTSIZE
NOSHO: JMP ADDRMOD
ISD93: MOV AL,DL
TEST AL,100B
JNZ ISD9BIG
AND AL,111B
OR AL,AL
JNZ NOTFLD
MOV AX,"DL"
STOSW
JMP SHORT PUTRST
NOTFLD: CMP AL,1
JNZ NOTFXCH
MOV AX,"CX"
STOSW
MOV AL,"H"
JMP SHORT PUTRST1
NOTFXCH:CMP AL,3
JNZ NOTFSTP
MOV AX,"TS"
STOSW
MOV AL,"P"
PUTRST1:STOSB
PUTRST: MOV AL,9
STOSB
JMP PUTST0
NOTFSTP:CALL GOTDIS
CMP AL,11010000B ; CHECK FOR FNOP
JZ GOTFNOP
JMP ESC0
GOTFNOP:MOV AX,"ON"
STOSW
MOV AL,"P"
STOSB
RET
ISD9BIG:
CALL GOTDIS ; GET THE MODE BYTE
MOV SI,OFFSET DG:MD9_TAB2
DOBIG: AND AL,11111B
MOV CL,AL
JMP MOVBYT
;
; entry point for the remaining 8087 instructions
;
M8087:
CALL GET64
CALL PUTFI ; PUT FIRST PART OF OPCODE
MOV AL,DL
CMP BYTE PTR [MODE],11B ; CHECK FOR REGISTER MODE
JZ MODEIS3
CALL PUTMN ; PUT MIDDLE PART OF OPCODE
NO3: MOV AL,9 ; OUTPUT A TAB
STOSB
MOV AL,DL
CALL PUTSIZE ; OUTPUT THE OPERAND SIZE
JMP ADDRMOD
MODEIS3:
TEST AL,100000B ; D BIT SET?
JZ MPUT ; NOPE...
TEST AL,000100B ; FDIV OR FSUB?
JZ MPUT ; NOPE...
XOR AL,1 ; REVERSE SENSE OF R
MOV DL,AL ; SAVE CHANGE
MPUT: CALL PUTMN ; PUT MIDDLE PART OF OPCODE
MOV AL,DL
TEST AL,010000B
JZ NOPSH
MOV AL,"P"
STOSB
NOPSH: MOV AL,9
STOSB
MOV AL,DL
AND AL,00000111B
CMP AL,2 ; FCOM
JZ PUTST0
CMP AL,3 ; FCOMP
JZ PUTST0
MOV AL,DL
TEST AL,100000B
JZ PUTSTST0
;
; output 8087 registers in the form st(n),st
;
PUTST0ST:
CALL PUTST0
MOV AL,','
ISCOMP: STOSB
PUTST: MOV AX,"TS"
STOSW
RET
;
; output 8087 registers in the form st,st(n)
;
PUTSTST0:
CALL PUTST
MOV AL,','
STOSB
PUTST0: CALL PUTST
MOV AL,"("
STOSB
MOV AL,[REGMEM]
ADD AL,"0"
STOSB
MOV AL,")"
STOSB
RET
;
; output an 8087 mnemonic
;
PUTMN: MOV SI,OFFSET DG:M8087_TAB
MOV CL,AL
AND CL,00000111B
JMP SHORT MOVBYT
;
; output either 'FI' or 'F' for first byte of opcode
;
PUTFI: MOV SI,OFFSET DG:FI_TAB
JMP SHORT PUTFI2
;
; output size (dword, tbyte, etc.)
;
PUTSIZE:MOV SI,OFFSET DG:SIZE_TAB
PUTFI2: CMP BYTE PTR [MODE],11B ; check if 8087 register
JNZ PUTFI3
AND AL,111000B ; LOOK FOR INVALID FORM OF 0DAH OPERANDS
CMP AL,010000B
JZ ESC0PJ
MOV AL,DL
CMP AL,110011B ; FCOMPP
JNZ GOFI
CMP BYTE PTR [REGMEM],1
JZ GOFI
ESC0PJ: JMP ESC0P
GOFI: XOR CL,CL
JMP SHORT MOVBYT
;
; Look for qword
;
PUTFI3: CMP AL,111101B
JZ GOTQU
CMP AL,111111B
JNZ NOTQU
GOTQU: MOV CL,2
JMP SHORT MOVBYT
;
; look for tbyte
;
NOTQU: CMP AL,011101B
JZ GOTTB
CMP AL,111100B
JZ GOTTB
CMP AL,111110B
JZ GOTTB
CMP AL,011111B
JNZ NOTTB
GOTTB: MOV CL,5
JMP SHORT MOVBYT
NOTTB: MOV CL,4
SHR AL,CL
MOV CL,AL
;
; SI POINTS TO A TABLE OF TEXT SEPARATED BY "$"
; CL = WHICH ELEMENT IN THE TABLE YOU WISH TO COPY TO [DI]
;
MOVBYT: PUSH AX
INC CL
MOVBYT1:DEC CL
JZ MOVBYT3
MOVBYT2:LODSB
CMP AL,'$'
JZ MOVBYT1
JMP MOVBYT2
MOVBYT3:LODSB
CMP AL,'$'
JZ MOVBYT5
CMP AL,'@' ; THIS MEANS RESVERED OP-CODE
JNZ MOVBYT4
POP AX
JMP SHORT ESC0P ; GO DO AN ESCAPE COMMAND
MOVBYT4:STOSB
JMP MOVBYT3
MOVBYT5:POP AX
RET
PUTOP: AND AL,111B
MOV CL,AL
CALL MOVBYT
MOV AL,9
STOSB
MOV AL,DL
RET
GET64F: CALL GET64
MOV AL,"F"
STOSB
CMP BYTE PTR [MODE],3
MOV AL,DL
RET
GET64:
AND AL,7
MOV DL,AL
CALL GETMODE
SHL DL,1
SHL DL,1
SHL DL,1
OR AL,DL
MOV DL,AL ; SAVE RESULT
RET
ESC0P: POP DI ; CLEAN UP STACK
ESC0: MOV WORD PTR [OPCODE],OFFSET DG:ESCMN
MOV AL,DL
MOV DI,OFFSET DG:OPBUF
JMP SHORT ESC1
ESC: CALL GET64
ESC1: CALL SAVHEX
CMP BYTE PTR [MODE],3
JZ SHRTESC
MOV BYTE PTR [AWORD],1
JMP MEMOP2
SHRTESC:
MOV AL,","
STOSB
MOV AL,[REGMEM]
AND AL,7
JMP SAVREG
INVARW:
CALL PUTAX
JMP SHORT INVAR
INVARB:
CALL PUTAL
INVAR: MOV AL,','
STOSB
JMP PUTDX
INFIXW:
CALL PUTAX
JMP SHORT INFIX
INFIXB:
CALL PUTAL
INFIX: MOV AL,','
STOSB
JMP SAV8
STOSW
RET
OUTVARB:
MOV BX,"LA"
JMP SHORT OUTVAR
OUTVARW:
MOV BX,"XA"
OUTVAR: CALL PUTDX
OUTFV: MOV AL,','
STOSB
MOV AX,BX
STOSW
RET
OUTFIXB:
MOV BX,"LA"
JMP SHORT OUTFIX
OUTFIXW:
MOV BX,"XA"
OUTFIX: CALL SAV8
JMP OUTFV
PUTAL: MOV AX,"A"+4C00H ; "AL"
JMP SHORT PUTX
PUTAX: MOV AX,"A"+5800H ; "AX"
JMP SHORT PUTX
PUTDX: MOV AX,"D"+5800H ; "DX"
PUTX: STOSW
RET
SHFT:
MOV BX,OFFSET DG:SHFTAB
CALL GETMNE
TESTREG:
CMP BYTE PTR [MODE],3
JZ NOFLG
MOV SI,OFFSET DG:SIZE_TAB
MOV CL,3
TEST BYTE PTR [AWORD],-1
JNZ TEST_1
INC CL
TEST_1: CALL MOVBYT
NOFLG:
JMP ADDRMOD
SHIFTV:
CALL SHFT
MOV AL,","
STOSB
MOV WORD PTR [DI],"C"+4C00H ; "CL"
RET
SHIFT:
CALL SHFT
MOV AX,"1,"
STOSW
RET
GETMNE:
CALL GETMODE
MOV DL,AL
CBW
SHL AX,1
ADD BX,AX
MOV AX,[BX]
MOV [OPCODE],AX
MOV AL,DL
RET
GRP1:
MOV BX,OFFSET DG:GRP1TAB
CALL GETMNE
OR AL,AL
JZ FINIMMJ
JMP TESTREG
FINIMMJ:
JMP FINIMM
GRP2:
MOV BX,OFFSET DG:GRP2TAB
CALL GETMNE
CMP AL,2
JB TESTREG
CMP AL,6
JAE INDIRECT
TEST AL,1
JZ INDIRECT
MOV AX,"AF" ; "FAR"
STOSW
MOV AX," R"
STOSW
INDIRECT:
JMP ADDRMOD
CODE ENDS
END UNASSEM

838
v2.0/source/DEBUG.ASM Normal file
View File

@ -0,0 +1,838 @@
TITLE DEBUGger for MS-DOS
; DEBUG-86 8086 debugger runs under 86-DOS version 2.30
;
; Modified 5/4/82 by AaronR to do all I/O direct to devices
; Runs on MS-DOS 1.28 and above
; REV 1.20
; Tab expansion
; New device interface (1.29 and above)
; REV 2.0
; line by line assembler added by C. Peters
; REV 2.1
; Uses EXEC system call
; REV 2.2
; Ztrace mode by zibo.
; Fix dump display to indent properly
; Parity nonsense by zibo
;
; REV 2.3
; Split into seperate modules to allow for
; assembly on an IBM PC
;
.xlist
.xcref
INCLUDE DEBEQU.ASM
INCLUDE DOSSYM.ASM
.cref
.list
IF SYSVER
; Structure for system call 72
SYSINITVAR STRUC
DPBHEAD DD ? ; Pointer to head of DPB-FAT list
sft_addr DD ? ; Pointer to first FCB table
; The following address points to the CLOCK device
BCLOCK DD ?
; The following address is used by DISKSTATCHK it is always
; points to the console input device header
BCON DD ? ; Console device entry points
NUMIO DB 0 ; Number of disk tables
MAXSEC DW 0 ; Maximum allowed sector size
BUFFHEAD DD ?
DEVHEAD DD ?
SYSINITVAR ENDS
ENDIF
CODE SEGMENT PUBLIC 'CODE'
CODE ENDS
CONST SEGMENT PUBLIC BYTE
EXTRN USER_PROC_PDB:WORD,STACK:BYTE,CSSAVE:WORD,DSSAVE:WORD
EXTRN SPSAVE:WORD,IPSAVE:WORD,LINEBUF:BYTE,QFLAG:BYTE
EXTRN NEWEXEC:BYTE,HEADSAVE:WORD,LBUFSIZ:BYTE,BACMES:BYTE
EXTRN BADVER:BYTE,ENDMES:BYTE,CARRET:BYTE,ParityMes:BYTE
IF IBMVER
EXTRN DSIZ:BYTE,NOREGL:BYTE,DISPB:WORD
ENDIF
IF SYSVER
EXTRN CONFCB:BYTE,POUT:DWORD,COUT:DWORD,CIN:DWORD,IOBUFF:BYTE
EXTRN IOADDR:DWORD,IOCALL:BYTE,IOCOM:BYTE,IOSTAT:WORD,IOCNT:WORD
EXTRN IOSEG:WORD,COLPOS:BYTE,BADDEV:BYTE,BADLSTMES:BYTE
EXTRN LBUFFCNT:BYTE,PFLAG:BYTE
ENDIF
CONST ENDS
DATA SEGMENT PUBLIC BYTE
EXTRN PARSERR:BYTE,DATAEND:WORD,ParityFlag:BYTE,DISADD:BYTE
EXTRN ASMADD:BYTE,DEFDUMP:BYTE,BYTEBUF:BYTE
DATA ENDS
DG GROUP CODE,CONST,DATA
CODE SEGMENT PUBLIC 'CODE'
ASSUME CS:DG,DS:DG,ES:DG,SS:DG
PUBLIC RESTART,SET_TERMINATE_VECTOR,DABORT,TERMINATE,COMMAND
PUBLIC FIND_DEBUG,CRLF,BLANK,TAB,OUT,INBUF,SCANB,SCANP
PUBLIC PRINTMES,RPRBUF,HEX,OUTSI,OUTDI,OUT16,DIGIT,BACKUP,RBUFIN
IF SYSVER
PUBLIC SETUDEV,DEVIOCALL
EXTRN DISPREG:NEAR,IN:NEAR
ENDIF
EXTRN PERR:NEAR,COMPARE:NEAR,DUMP:NEAR,ENTER:NEAR,FILL:NEAR
EXTRN GO:NEAR,INPUT:NEAR,LOAD:NEAR,MOVE:NEAR,NAME:NEAR
EXTRN REG:NEAR,SEARCH:NEAR,DWRITE:NEAR,UNASSEM:NEAR,ASSEM:NEAR
EXTRN OUTPUT:NEAR,ZTRACE:NEAR,TRACE:NEAR,GETHEX:NEAR,GETEOL:NEAR
EXTRN PREPNAME:NEAR,DEFIO:NEAR,SKIP_FILE:NEAR,DEBUG_FOUND:NEAR
EXTRN TrapParity:NEAR,ReleaseParity:NEAR
ORG 100H
START:
DEBUG:
JMP SHORT DSTRT
HEADER DB "Vers 2.30"
DSTRT:
DOSVER_HIGH EQU 0200H ; 2.00 in hex
MOV AH,GET_VERSION
INT 21H
XCHG AH,AL ; Turn it around to AH.AL
CMP AX,DOSVER_HIGH
JAE OKDOS
GOTBADDOS:
MOV DX,OFFSET DG:BADVER
MOV AH,STD_CON_STRING_OUTPUT
INT 21H
INT 20H
OKDOS:
CALL TrapParity ; scarf up those parity guys
MOV AH,GET_CURRENT_PDB
INT 21H
MOV [USER_PROC_PDB],BX ; Initially set to DEBUG
IF SYSVER
MOV [IOSEG],CS
ENDIF
MOV SP,OFFSET DG:STACK
MOV [PARSERR],AL
MOV AH,GET_IN_VARS
INT 21H
IF SYSVER
LDS SI,ES:[BX.BCON]
MOV WORD PTR CS:[CIN+2],DS
MOV WORD PTR CS:[CIN],SI
MOV WORD PTR CS:[COUT+2],DS
MOV WORD PTR CS:[COUT],SI
PUSH CS
POP DS
MOV DX,OFFSET DG:CONFCB
MOV AH,FCB_OPEN
INT 21H
OR AL,AL
JZ GOTLIST
MOV DX,OFFSET DG:BADLSTMES
CALL RPRBUF
CALL RBUFIN
CALL CRLF
MOV CL,[LBUFFCNT]
OR CL,CL
JZ NOLIST1 ; User didn't specify one
XOR CH,CH
MOV DI,OFFSET DG:(CONFCB + 1)
MOV SI,OFFSET DG:LINEBUF
REP MOVSB
MOV DX,OFFSET DG:CONFCB
MOV AH,FCB_OPEN
INT 21H
OR AL,AL
JZ GOTLIST ; GOOD
MOV DX,OFFSET DG:BADDEV
CALL RPRBUF
NOLIST1:
MOV WORD PTR [POUT+2],CS
MOV WORD PTR [POUT],OFFSET DG:LONGRET
JMP NOLIST
XXX PROC FAR
LONGRET:RET
XXX ENDP
ENDIF
GOTLIST:
IF SYSVER
MOV SI,DX
LDS SI,DWORD PTR DS:[SI.fcb_FIRCLUS]
MOV WORD PTR CS:[POUT+2],DS
MOV WORD PTR CS:[POUT],SI
ENDIF
NOLIST:
MOV AX,CS
MOV DS,AX
MOV ES,AX
; Code to print header
; MOV DX,OFFSET DG:HEADER
; CALL RPRBUF
CALL SET_TERMINATE_VECTOR
IF SETCNTC
MOV AL,23H ; Set vector 23H
MOV DX,OFFSET DG:DABORT
INT 21H
ENDIF
MOV DX,CS ; Get DEBUG's segment
MOV AX,OFFSET DG:DATAEND + 15 ; End of debug
SHR AX,1 ; Convert to segments
SHR AX,1
SHR AX,1
SHR AX,1
ADD DX,AX ; Add siz of debug in paragraphs
MOV AH,CREATE_PROCESS_DATA_BLOCK ; create program segment just after DEBUG
INT 21H
MOV AX,DX
MOV DI,OFFSET DG:DSSAVE
CLD
STOSW
STOSW
STOSW
STOSW
MOV WORD PTR [DISADD+2],AX
MOV WORD PTR [ASMADD+2],AX
MOV WORD PTR [DEFDUMP+2],AX
MOV AX,100H
MOV WORD PTR[DISADD],AX
MOV WORD PTR[ASMADD],AX
MOV WORD PTR [DEFDUMP],AX
MOV DS,DX
MOV ES,DX
MOV DX,80H
MOV AH,SET_DMA
INT 21H ; Set default DMA address to 80H
MOV AX,WORD PTR DS:[6]
MOV BX,AX
CMP AX,0FFF0H
PUSH CS
POP DS
JAE SAVSTK
MOV AX,WORD PTR DS:[6]
PUSH BX
MOV BX,OFFSET DG:DATAEND + 15
AND BX,0FFF0H ; Size of DEBUG in bytes (rounded up to PARA)
SUB AX,BX
POP BX
SAVSTK:
PUSH BX
DEC AX
DEC AX
MOV BX,AX
MOV WORD PTR [BX],0
POP BX
MOV SPSAVE,AX
DEC AH
MOV ES:WORD PTR [6],AX
SUB BX,AX
MOV CL,4
SHR BX,CL
ADD ES:WORD PTR [8],BX
IF IBMVER
; Get screen size and initialize display related variables
MOV AH,15
INT 10H
CMP AH,40
JNZ PARSCHK
MOV BYTE PTR DSIZ,7
MOV BYTE PTR NOREGL,4
MOV DISPB,64
ENDIF
PARSCHK:
; Copy rest of command line to test program's parameter area
MOV DI,FCB
MOV SI,81H
MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H
INT 21H
CALL SKIP_FILE ; Make sure si points to delimiter
CALL PREPNAME
PUSH CS
POP ES
FILECHK:
MOV DI,80H
CMP BYTE PTR ES:[DI],0 ; ANY STUFF FOUND?
JZ COMMAND ; NOPE
FILOOP: INC DI
CMP BYTE PTR ES:[DI],13 ; COMMAND LINE JUST SPACES?
JZ COMMAND
CMP BYTE PTR ES:[DI]," "
JZ FILOOP
CMP BYTE PTR ES:[DI],9
JZ FILOOP
CALL DEFIO ; WELL READ IT IN
MOV AX,CSSAVE
MOV WORD PTR DISADD+2,AX
MOV WORD PTR ASMADD+2,AX
MOV AX,IPSAVE
MOV WORD PTR DISADD,AX
MOV WORD PTR ASMADD,AX
COMMAND:
CLD
MOV AX,CS
MOV DS,AX
MOV ES,AX
MOV SS,AX
MOV SP,OFFSET DG:STACK
STI
CMP [ParityFlag],0 ; did we detect a parity error?
JZ GoPrompt ; nope, go prompt
MOV [ParityFlag],0 ; reset flag
MOV DX,OFFSET DG:ParityMes ; message to print
MOV AH,STD_CON_STRING_OUTPUT; easy way out
INT 21h ; blam
GoPrompt:
MOV AL,PROMPT
CALL OUT
CALL INBUF ; Get command line
; From now and throughout command line processing, DI points
; to next character in command line to be processed.
CALL SCANB ; Scan off leading blanks
JZ COMMAND ; Null command?
LODSB ; AL=first non-blank character
; Prepare command letter for table lookup
SUB AL,"A" ; Low end range check
JB ERR1
CMP AL,"Z"-"A" ; Upper end range check
JA ERR1
SHL AL,1 ; Times two
CBW ; Now a 16-bit quantity
XCHG BX,AX ; In BX we can address with it
CALL CS:[BX+COMTAB] ; Execute command
JMP SHORT COMMAND ; Get next command
ERR1: JMP PERR
SET_TERMINATE_VECTOR:
MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 22H ; Set vector 22H
MOV DX,OFFSET DG:TERMINATE
INT 21H
RET
TERMINATE:
CMP BYTE PTR CS:[QFLAG],0
JNZ QUITING
MOV CS:[USER_PROC_PDB],CS
CMP BYTE PTR CS:[NEWEXEC],0
JZ NORMTERM
MOV AX,CS
MOV DS,AX
MOV SS,AX
MOV SP,OFFSET DG:STACK
MOV AX,[HEADSAVE]
JMP DEBUG_FOUND
NORMTERM:
MOV DX,OFFSET DG:ENDMES
JMP SHORT RESTART
QUITING:
MOV AX,(EXIT SHL 8)
INT 21H
DABORT:
MOV DX,OFFSET DG:CARRET
RESTART:
MOV AX,CS
MOV DS,AX
MOV SS,AX
MOV SP,OFFSET DG:STACK
CALL RPRBUF
JMP COMMAND
IF SYSVER
SETUDEV:
MOV DI,OFFSET DG:CONFCB
MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H
INT 21H
CALL USERDEV
JMP DISPREG
USERDEV:
MOV DX,OFFSET DG:CONFCB
MOV AH,FCB_OPEN
INT 21H
OR AL,AL
JNZ OPENERR
MOV SI,DX
TEST BYTE PTR [SI.fcb_DEVID],080H ; Device?
JZ OPENERR ; NO
LDS SI,DWORD PTR [CONFCB.fcb_FIRCLUS]
MOV WORD PTR CS:[CIN],SI
MOV WORD PTR CS:[CIN+2],DS
MOV WORD PTR CS:[COUT],SI
MOV WORD PTR CS:[COUT+2],DS
PUSH CS
POP DS
RET
OPENERR:
MOV DX,OFFSET DG:BADDEV
CALL RPRBUF
RET
ENDIF
; Get input line. Convert all characters NOT in quotes to upper case.
INBUF:
CALL RBUFIN
MOV SI,OFFSET DG:LINEBUF
MOV DI,OFFSET DG:BYTEBUF
CASECHK:
LODSB
CMP AL,'a'
JB NOCONV
CMP AL,'z'
JA NOCONV
ADD AL,"A"-"a" ; Convert to upper case
NOCONV:
STOSB
CMP AL,13
JZ INDONE
CMP AL,'"'
JZ QUOTSCAN
CMP AL,"'"
JNZ CASECHK
QUOTSCAN:
MOV AH,AL
KILLSTR:
LODSB
STOSB
CMP AL,13
JZ INDONE
CMP AL,AH
JNZ KILLSTR
JMP SHORT CASECHK
INDONE:
MOV SI,OFFSET DG:BYTEBUF
; Output CR/LF sequence
CRLF:
MOV AL,13
CALL OUT
MOV AL,10
JMP OUT
; Physical backspace - blank, backspace, blank
BACKUP:
MOV SI,OFFSET DG:BACMES
; Print ASCII message. Last char has bit 7 set
PRINTMES:
LODS CS:BYTE PTR [SI] ; Get char to print
CALL OUT
SHL AL,1 ; High bit set?
JNC PRINTMES
RET
; Scan for parameters of a command
SCANP:
CALL SCANB ; Get first non-blank
CMP BYTE PTR [SI],"," ; One comma between params OK
JNE EOLCHK ; If not comma, we found param
INC SI ; Skip over comma
; Scan command line for next non-blank character
SCANB:
PUSH AX
SCANNEXT:
LODSB
CMP AL," "
JZ SCANNEXT
CMP AL,9
JZ SCANNEXT
DEC SI ; Back to first non-blank
POP AX
EOLCHK:
CMP BYTE PTR [SI],13
RET
; Hex addition and subtraction
HEXADD:
MOV CX,4
CALL GETHEX
MOV DI,DX
MOV CX,4
CALL GETHEX
CALL GETEOL
PUSH DX
ADD DX,DI
CALL OUT16
CALL BLANK
CALL BLANK
POP DX
SUB DI,DX
MOV DX,DI
CALL OUT16
JMP SHORT CRLF
; Print the hex address of DS:SI
OUTSI:
MOV DX,DS ; Put DS where we can work with it
CALL OUT16 ; Display segment
MOV AL,":"
CALL OUT
MOV DX,SI
JMP SHORT OUT16 ; Output displacement
; Print hex address of ES:DI
; Same as OUTSI above
OUTDI:
MOV DX,ES
CALL OUT16
MOV AL,":"
CALL OUT
MOV DX,DI
; Print out 16-bit value in DX in hex
OUT16:
MOV AL,DH ; High-order byte first
CALL HEX
MOV AL,DL ; Then low-order byte
; Output byte in AL as two hex digits
HEX:
MOV AH,AL ; Save for second digit
; Shift high digit into low 4 bits
PUSH CX
MOV CL,4
SHR AL,CL
POP CX
CALL DIGIT ; Output first digit
MOV AL,AH ; Now do digit saved in AH
DIGIT:
AND AL,0FH ; Mask to 4 bits
; Trick 6-byte hex conversion works on 8086 too.
ADD AL,90H
DAA
ADC AL,40H
DAA
; Console output of character in AL. No registers affected but bit 7
; is reset before output.
IF SYSVER
OUT:
PUSH AX
AND AL,7FH
CMP AL,7FH
JNZ NOTDEL
MOV AL,8 ; DELETE same as backspace
NOTDEL:
CMP AL,9
JZ TABDO
CALL DOCONOUT
CMP AL,0DH
JZ ZEROPOS
CMP AL,0AH
JZ ZEROPOS
CMP AL,8
JNZ OOKRET
MOV AL," "
CALL DOCONOUT
MOV AL,8
CALL DOCONOUT
CMP BYTE PTR CS:[COLPOS],0
JZ NOTINC
DEC BYTE PTR CS:[COLPOS]
JMP NOTINC
ZEROPOS:
MOV BYTE PTR CS:[COLPOS],0FFH
OOKRET:
INC BYTE PTR CS:[COLPOS]
NOTINC:
TEST BYTE PTR CS:[PFLAG],1
JZ POPRET
CALL LISTOUT
POPRET:
POP AX
RET
TABDO:
MOV AL,CS:[COLPOS]
OR AL,0F8H
NEG AL
PUSH CX
MOV CL,AL
XOR CH,CH
JCXZ POPTAB
TABLP:
MOV AL," "
CALL OUT
LOOP TABLP
POPTAB:
POP CX
POP AX
RET
DOCONOUT:
PUSH DS
PUSH SI
PUSH AX
CONOWAIT:
LDS SI,CS:[COUT]
MOV AH,10
CALL DEVIOCALL
MOV AX,CS:[IOSTAT]
AND AX,200H
JNZ CONOWAIT
POP AX
PUSH AX
MOV AH,8
CALL DEVIOCALL
POP AX
POP SI
POP DS
RET
LISTOUT:
PUSH DS
PUSH SI
PUSH AX
LISTWAIT:
LDS SI,CS:[POUT]
MOV AH,10
CALL DEVIOCALL
MOV AX,CS:[IOSTAT]
AND AX,200H
JNZ LISTWAIT
POP AX
PUSH AX
MOV AH,8
CALL DEVIOCALL
POP AX
POP SI
POP DS
RET
DEVIOCALL:
PUSH ES
PUSH BX
PUSH CS
POP ES
MOV BX,OFFSET DG:IOCALL
MOV CS:[IOCOM],AH
MOV WORD PTR CS:[IOSTAT],0
MOV WORD PTR CS:[IOCNT],1
MOV CS:[IOBUFF],AL
MOV WORD PTR CS:[IOADDR+2],DS
MOV AX,[SI+6]
MOV WORD PTR CS:[IOADDR],AX
CALL DWORD PTR CS:[IOADDR]
MOV AX,[SI+8]
MOV WORD PTR CS:[IOADDR],AX
CALL DWORD PTR CS:[IOADDR]
MOV AL,CS:[IOBUFF]
POP BX
POP ES
RET
ELSE
OUT:
PUSH DX
PUSH AX
AND AL,7FH
MOV DL,AL
MOV AH,2
INT 21H
POP AX
POP DX
RET
ENDIF
IF SYSVER
RBUFIN:
PUSH AX
PUSH ES
PUSH DI
PUSH CS
POP ES
MOV BYTE PTR [LBUFFCNT],0
MOV DI,OFFSET DG:LINEBUF
FILLBUF:
CALL IN
CMP AL,0DH
JZ BDONE
CMP AL,8
JZ ECHR
CMP AL,7FH
JZ ECHR
CMP BYTE PTR [LBUFFCNT],BUFLEN
JAE BFULL
STOSB
INC BYTE PTR [LBUFFCNT]
JMP SHORT FILLBUF
BDONE:
STOSB
POP DI
POP ES
POP AX
RET
BFULL:
MOV AL,8
CALL OUT
MOV AL,7
CALL OUT
JMP SHORT FILLBUF
ECHR:
CMP DI,OFFSET DG:LINEBUF
JZ FILLBUF
DEC DI
DEC BYTE PTR [LBUFFCNT]
JMP SHORT FILLBUF
ELSE
RBUFIN:
PUSH AX
PUSH DX
MOV AH,10
MOV DX,OFFSET DG:LBUFSIZ
INT 21H
POP DX
POP AX
RET
ENDIF
IF SYSVER
RPRBUF:
PUSHF
PUSH AX
PUSH SI
MOV SI,DX
PLOOP:
LODSB
CMP AL,"$"
JZ PRTDONE
CALL OUT
JMP SHORT PLOOP
PRTDONE:
POP SI
POP AX
POPF
RET
ELSE
RPRBUF:
MOV AH,9
INT 21H
RET
ENDIF
; Output one space
BLANK:
MOV AL," "
JMP OUT
; Output the number of blanks in CX
TAB:
CALL BLANK
LOOP TAB
RET
; Command Table. Command letter indexes into table to get
; address of command. PERR prints error for no such command.
COMTAB DW ASSEM ; A
DW PERR ; B
DW COMPARE ; C
DW DUMP ; D
DW ENTER ; E
DW FILL ; F
DW GO ; G
DW HEXADD ; H
DW INPUT ; I
DW PERR ; J
DW PERR ; K
DW LOAD ; L
DW MOVE ; M
DW NAME ; N
DW OUTPUT ; O
IF ZIBO
DW ZTRACE
ELSE
DW PERR ; P
ENDIF
DW QUIT ; Q (QUIT)
DW REG ; R
DW SEARCH ; S
DW TRACE ; T
DW UNASSEM ; U
DW PERR ; V
DW DWRITE ; W
IF SYSVER
DW SETUDEV ; X
ELSE
DW PERR
ENDIF
DW PERR ; Y
DW PERR ; Z
QUIT:
INC BYTE PTR [QFLAG]
MOV BX,[USER_PROC_PDB]
FIND_DEBUG:
IF NOT SYSVER
MOV AH,SET_CURRENT_PDB
INT 21H
ENDIF
CALL ReleaseParity ; let system do normal parity stuff
MOV AX,(EXIT SHL 8)
INT 21H
CODE ENDS
END START

439
v2.0/source/DEV.ASM Normal file
View File

@ -0,0 +1,439 @@
;
; Device call routines for MSDOS
;
INCLUDE DOSSEG.ASM
IFNDEF KANJI
KANJI EQU 0 ;FALSE
ENDIF
CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME SS:DOSGROUP,CS:DOSGROUP
.xlist
.xcref
INCLUDE DOSSYM.ASM
INCLUDE DEVSYM.ASM
.cref
.list
TITLE DEV - Device call routines
NAME Dev
i_need IOXAD,DWORD
i_need IOSCNT,WORD
i_need DEVIOBUF,4
i_need IOCALL,BYTE
i_need IOMED,BYTE
i_need IORCHR,BYTE
i_need CALLSCNT,WORD
i_need DMAAdd,DWORD
i_need NullDevPt,DWORD
i_need CallDevAd,DWORD
i_need Attrib,BYTE
i_need NULDEV,DWORD
i_need Name1,BYTE
i_need DevPt,DWORD
i_need DPBHead,DWORD
i_need NumIO,BYTE
i_need ThisDPB,DWORD
i_need DevCall,DWORD
i_need VerFlg,BYTE
SUBTTL IOFUNC -- DO FUNCTION 1-12 I/O
PAGE
IOFUNC_RETRY:
ASSUME DS:NOTHING,ES:NOTHING
invoke restore_world
procedure IOFUNC,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; DS:SI Points to FCB
; AH is function code
; = 0 Input
; = 1 Input Status
; = 2 Output
; = 3 Output Status
; = 4 Flush
; AL = character if output
; Function:
; Perform indicated I/O to device or file
; Outputs:
; AL is character if input
; If a status call
; zero set if not ready
; zero reset if ready (character in AL for input status)
; For regular files:
; Input Status
; Gets character but restores fcb_RR field
; Zero set on EOF
; Input
; Gets character advances fcb_RR field
; Returns ^Z on EOF
; Output Status
; Always ready
; AX altered, all other registers preserved
MOV WORD PTR [IOXAD+2],SS
MOV WORD PTR [IOXAD],OFFSET DOSGROUP:DEVIOBUF
MOV WORD PTR [IOSCNT],1
MOV WORD PTR [DEVIOBUF],AX
IOFUNC2:
TEST [SI.fcb_DEVID],080H
JNZ IOTODEV
JMP IOTOFILE
IOTODEV:
invoke save_world
PUSH DS
PUSH SS
POP ES
PUSH SS
POP DS
ASSUME DS:DOSGROUP
XOR BX,BX
MOV [IOCALL.REQSTAT],BX
MOV BYTE PTR [IOMED],BL
MOV BX,OFFSET DOSGROUP:IOCALL
MOV CX,(DEVRD SHL 8) OR DRDWRHL
OR AH,AH
JZ DCALLR
MOV CX,(DEVRDND SHL 8) OR DRDNDHL
DEC AH
JZ DCALLR
MOV CX,(DEVWRT SHL 8) OR DRDWRHL
DEC AH
JZ DCALLO
MOV CX,(DEVOST SHL 8) OR DSTATHL
DEC AH
JZ DCALLO
DFLUSH:
MOV CX,(DEVIFL SHL 8) OR DFLSHL
DCALLR:
MOV AH,86H
DCALL:
MOV [IOCALL.REQLEN],CL
MOV [IOCALL.REQFUNC],CH
MOV CL,AH
POP DS
ASSUME DS:NOTHING
CALL DEVIOCALL
MOV DI,[IOCALL.REQSTAT]
TEST DI,STERR
JZ OKDEVIO
MOV AH,CL
invoke CHARHARD
CMP AL,1
JZ IOFUNC_RETRY
;Know user must have wanted ignore. Make sure device shows ready so
;that DOS doesn't get caught in a status loop when user simply wants
;to ignore the error.
AND BYTE PTR [IOCALL.REQSTAT+1], NOT (STBUI SHR 8)
OKDEVIO:
PUSH SS
POP DS
ASSUME DS:DOSGROUP
CMP CH,DEVRDND
JNZ DNODRD
MOV AL,BYTE PTR [IORCHR]
MOV [DEVIOBUF],AL
DNODRD: MOV AH,BYTE PTR [IOCALL.REQSTAT+1]
NOT AH ; Zero = busy, not zero = ready
AND AH,STBUI SHR 8
invoke restore_world
ASSUME DS:NOTHING
MOV AX,WORD PTR [DEVIOBUF]
return
DCALLO:
MOV AH,87H
JMP SHORT DCALL
IOTOFILE:
ASSUME DS:NOTHING
OR AH,AH
JZ IOIN
DEC AH
JZ IOIST
DEC AH
JZ IOUT
return ; NON ZERO FLAG FOR OUTPUT STATUS
IOIST:
PUSH WORD PTR [SI.fcb_RR] ; Save position
PUSH WORD PTR [SI.fcb_RR+2]
CALL IOIN
POP WORD PTR [SI.fcb_RR+2] ; Restore position
POP WORD PTR [SI.fcb_RR]
return
IOUT:
CALL SETXADDR
invoke STORE
invoke FINNOSAV
CALL RESTXADDR ; If you change this into a jmp don't come
return ; crying to me when things don't work ARR
IOIN:
CALL SETXADDR
invoke LOAD
PUSH CX
invoke FINNOSAV
POP CX
OR CX,CX ; Check EOF
CALL RESTXADDR
MOV AL,[DEVIOBUF] ; Get byte from trans addr
retnz
MOV AL,1AH ; ^Z if EOF
return
SETXADDR:
POP WORD PTR [CALLSCNT] ; Return address
invoke save_world
PUSH WORD PTR [DMAADD] ; Save Disk trans addr
PUSH WORD PTR [DMAADD+2]
PUSH DS
PUSH SS
POP DS
ASSUME DS:DOSGROUP
MOV CX,WORD PTR [IOXAD+2]
MOV WORD PTR [DMAADD+2],CX
MOV CX,WORD PTR [IOXAD]
MOV WORD PTR [DMAADD],CX ; Set byte trans addr
MOV CX,[IOSCNT] ; ioscnt specifies length of buffer
POP DS
ASSUME DS:NOTHING
MOV [SI.fcb_RECSIZ],1 ; One byte per record
MOV DX,SI ; FCB to DS:DX
invoke GETRRPOS
JMP SHORT RESTRET ; RETURN ADDRESS
RESTXADDR:
POP WORD PTR [CALLSCNT] ; Return address
POP WORD PTR [DMAADD+2] ; Restore Disk trans addr
POP WORD PTR [DMAADD]
invoke restore_world
RESTRET:JMP WORD PTR [CALLSCNT] ; Return address
IOFUNC ENDP
SUBTTL DEVIOCALL, DEVIOCALL2 - CALL A DEVICE
PAGE
procedure DEVIOCALL,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; DS:SI Points to device FCB
; ES:BX Points to request data
; Function:
; Call the device
; Outputs:
; None
; DS:SI,AX destroyed, others preserved
LDS SI,DWORD PTR [SI.fcb_FIRCLUS]
entry DEVIOCALL2
; As above only DS:SI points to device header on entry, and DS:SI is preserved
MOV AX,[SI.SDEVSTRAT]
MOV WORD PTR [CALLDEVAD],AX
MOV WORD PTR [CALLDEVAD+2],DS
CALL DWORD PTR [CALLDEVAD]
MOV AX,[SI.SDEVINT]
MOV WORD PTR [CALLDEVAD],AX
CALL DWORD PTR [CALLDEVAD]
return
DEVIOCALL ENDP
SUBTTL DEVNAME - LOOK FOR NAME OF DEVICE
PAGE
procedure DEVNAME,NEAR
ASSUME DS:DOSGROUP,ES:DOSGROUP
; Inputs:
; DS,ES:DOSGROUP
; Filename in NAME1
; Function:
; Determine if file is in list of I/O drivers
; Outputs:
; Carry set if name not found
; ELSE
; Zero flag set
; BH = Bit 7,6 = 1, bit 5 = 0 (cooked mode)
; bits 0-4 set from low byte of attribute word
; DEVPT = DWORD pointer to Device header of device
; Registers BX destroyed
PUSH SI
PUSH DI
PUSH CX
IF KANJI
PUSH WORD PTR [NAME1]
CMP [NAME1],5
JNZ NOKTR
MOV [NAME1],0E5H
NOKTR:
ENDIF
TEST BYTE PTR [ATTRIB],attr_volume_id ; If looking for VOL id don't find devs
JNZ RET31
MOV SI,OFFSET DOSGROUP:NULDEV
LOOKIO:
ASSUME DS:NOTHING
TEST [SI.SDEVATT],DEVTYP
JZ SKIPDEV ; Skip block devices
PUSH SI
ADD SI,SDEVNAME
MOV DI,OFFSET DOSGROUP:NAME1
MOV CX,4 ; All devices are 8 letters
REPE CMPSW ; Check for name in list
POP SI
JZ IOCHK ; Found it?
SKIPDEV:
LDS SI,DWORD PTR [SI] ; Get address of next device
CMP SI,-1 ; At end of list?
JNZ LOOKIO
RET31: STC ; Not found
RETNV: PUSH SS
POP DS
ASSUME DS:DOSGROUP
IF KANJI
POP WORD PTR [NAME1]
ENDIF
POP CX
POP DI
POP SI
RET
IOCHK:
ASSUME DS:NOTHING
MOV WORD PTR [DEVPT+2],DS ; Save pointer to device
MOV BH,BYTE PTR [SI.SDEVATT]
OR BH,0C0H
AND BH,NOT 020H ;Clears Carry
MOV WORD PTR [DEVPT],SI
JMP RETNV
DevName ENDP
procedure GetBP,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Inputs:
; AL = Logical unit number (A = 0)
; Function:
; Find Drive Parameter Block
; Outputs:
; ES:BP points to DPB
; [THISDPB] = ES:BP
; Carry set if unit number bad
; No other registers altered
LES BP,[DPBHEAD] ; Just in case drive isn't valid
AND AL,3FH ; Mask out dirty and device bits
CMP AL,BYTE PTR [NUMIO]
CMC
JC GOTDPB ; Get drive A
FNDDPB:
CMP AL,ES:[BP.dpb_drive]
JZ GOTDPB ; Carry is clear if jump executed
LES BP,ES:[BP.dpb_next_dpb]
JMP SHORT FNDDPB
GOTDPB:
MOV WORD PTR [THISDPB],BP
MOV WORD PTR [THISDPB+2],ES
RET
GetBP ENDP
SUBTTL SETREAD, SETWRITE -- SET UP HEADER BLOCK
PAGE
procedure SETREAD,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; DS:BX = Transfer Address
; CX = Record Count
; DX = Starting Record
; AH = Media Byte
; AL = Unit Code
; Function:
; Set up the device call header at DEVCALL
; Output:
; ES:BX Points to DEVCALL
; No other registers effected
PUSH DI
PUSH CX
PUSH AX
MOV CL,DEVRD
SETCALLHEAD:
MOV AL,DRDWRHL
PUSH SS
POP ES
MOV DI,OFFSET DOSGROUP:DEVCALL
STOSB ; length
POP AX
STOSB ; Unit
PUSH AX
MOV AL,CL
STOSB ; Command code
XOR AX,AX
STOSW ; Status
ADD DI,8 ; Skip link fields
POP AX
XCHG AH,AL
STOSB ; Media byte
XCHG AL,AH
PUSH AX
MOV AX,BX
STOSW
MOV AX,DS
STOSW ; Transfer addr
POP CX ; Real AX
POP AX ; Real CX
STOSW ; Count
XCHG AX,DX ; AX=Real DX, DX=real CX, CX=real AX
STOSW ; Start
XCHG AX,CX
XCHG DX,CX
POP DI
MOV BX,OFFSET DOSGROUP:DEVCALL
RET
entry SETWRITE
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; DS:BX = Transfer Address
; CX = Record Count
; DX = Starting Record
; AH = Media Byte
; AL = Unit Code
; Function:
; Set up the device call header at DEVCALL
; Output:
; ES:BX Points to DEVCALL
; No other registers effected
PUSH DI
PUSH CX
PUSH AX
MOV CL,DEVWRT
ADD CL,[VERFLG]
JMP SHORT SETCALLHEAD
SETREAD ENDP
do_ext
CODE ENDS
END

802
v2.0/source/DEVDRIV.txt Normal file
View File

@ -0,0 +1,802 @@
MS-DOS 2.0 Device Drivers
INTRODUCTION
In the past, DOS-device driver (BIOS for those who are
familiar with CP/M) communication has been mediated with
registers and a fixed-address jump-table. This approach
has suffered heavily from the following two observations:
o The old jump-table ideas of the past are fixed in
scope and allow no extensibility.
o The past device driver interfaces have been written
without regard for the true power of the hardware.
When a multitasking system or interrupt driven
hardware is installed a new BIOS must be written
largely from scratch.
In MSDOS 2.0, the DOS-device driver interface has changed
from the old jump-table style to one in which the device
drivers are linked together in a list. This allows new
drivers for optional hardware to be installed (and even
written) in the field by other vendors or the user himself.
This flexibility is one of the major new features of MS-DOS
2.0.
Each driver in the chain defines two entry points; the
strategy routine and the interrupt routine. The 2.0 DOS
does not really make use of two entry points (it simply calls
strategy, then immediately calls interrupt). This dual entry
point scheme is designed to facilitate future multi-tasking
versions of MS-DOS. In multi-tasking environments I/O must
be asynchronous, to accomplish this the strategy routine
will be called to queue (internally) a request and return
quickly. It is then the responsibility of the interrupt
routine to perform the actual I/O at interrupt time by picking
requests off the internal queue (set up by the strategy
routine), and process them. When a request is complete,
it is flagged as "done" by the interrupt routine. The DOS
periodically scans the list of requests looking for ones
flagged as done, and "wakes up" the process waiting for the
completion of the request.
In order for requests to be queued as above it is no
longer sufficient to pass I/O information in registers, since
many requests may be pending at any one time. Therefore
the new device interface uses data "packets" to pass request
information. A device is called with a pointer to a packet,
this packet is linked into a global chain of all pending
I/O requests maintained by the DOS. The device then links
the packet into its own local chain of requests for this
particular device. The device interrupt routine picks
requests of the local chain for processing. The DOS scans
the global chain looking for completed requests. These
packets are composed of two pieces, a static piece which
has the same format for all requests (called the static
request header), which is followed by information specific
to the request. Thus packets have a variable size and format.
At this points it should be emphasized that MS-DOS 2.0
does not implement most of these features, as future versions
will. There is no global or local queue. Only one request
is pending at any one time, and the DOS waits for this current
request to be completed. For 2.0 it is sufficient for the
strategy routine to simply store the address of the packet
at a fixed location, and for the interrupt routine to then
process this packet by doing the request and returning.
Remember: the DOS just calls the strategy routine and then
immediately calls the interrupt routine, it is assumed that
the request is completed when the interrupt routine returns.
This additional functionality is defined at this time so
that people will be aware and thinking about the future.
FORMAT OF A DEVICE DRIVER
A device driver is simply a relocatable memory image
with all of the code in it to implement the device (like
a .COM file, but not ORGed at 100 Hex). In addition it has
a special header at the front of it which identifies it as
a device, defines the strategy and interrupt entry points,
and defines various attributes. It should also be noted
that there are two basic types of devices.
The first is character devices. These are devices which
are designed to do character I/O in a serial manner like
CON, AUX, and PRN. These devices are named (ie. CON, AUX,
CLOCK, etc.), and users may open channels (FCBs) to do I/O
to them.
The second class of devices is block devices. These
devices are the "disk drives" on the system, they can do
random I/O in pieces called blocks (usually the physical
sector size) and hence the name. These devices are not
"named" as the character devices are, and therefore cannot
be "opened" directly. Instead they are "mapped" via the
drive letters (A,B,C, etc.).
Block devices also have units. In other words a single
driver may be responsible for one or more disk drives. For
instance block device driver ALPHA (please note that we cannot
actually refer to block devices by a name!) may be
responsible for drives A,B,C and D, this simply means that
it has four units (0-3) defined and therefore takes up four
drive letters. Which units correspond to which drive letters
is determined by the position of the driver in the chain
of all drivers: if driver ALPHA is the first block driver
in the device chain, and it defines 4 units (0-3), then they
will be A,B,C and D. If BETA is the second block driver
and defines three units (0-2), then they will be E,F and
G and so on. MS-DOS 2.0 is not limited to 16 block device
units, as previous versions were. The theoretical limit
is 63 (2^6 - 1), but it should be noted that after 26 the
drive letters get a little strange (like ] \ and ^). NOTE:
Character devices cannot define multiple units (this because
they have only one name).
Here is what that special device header looks like:
+--------------------------------------+
| DWORD Pointer to next device |
| (Must be set to -1) |
+--------------------------------------+
| WORD Attributes |
| Bit 15 = 1 if char device 0 if blk |
| if bit 15 is 1 |
| Bit 0 = 1 if Current sti device |
| Bit 1 = 1 if Current sto output |
| Bit 2 = 1 if Current NUL device |
| Bit 3 = 1 if Current CLOCK dev |
| Bit 4 = 1 if SPECIAL |
| Bit 14 is the IOCTL bit (see below) |
| Bit 13 is the NON IBM FORMAT bit |
+--------------------------------------+
| WORD Pointer to Device strategy |
| entry point |
+--------------------------------------+
| WORD Pointer to Device interrupt |
| entry point |
+--------------------------------------+
| 8-BYTE character device name field |
| Character devices set a device name |
| For block devices the first byte is |
| The number of units |
+--------------------------------------+
Note that the device entry points are words. They must
be offsets from the same segment number used to point to
this table. Ie. if XXX.YYY points to the start of this
table, then XXX.strategy and XXX.interrupt are the entry
points.
A word about the Attribute field. This field is used
most importantly to tell the system whether this device is
a block or character device (bit 15). Most of other bits
are used to give selected character devices certain special
treatment (NOTE: these bits mean nothing on a block device).
Let's say a user has a new device driver which he wants to
be the standard input and output. Besides just installing
the driver he needs to tell SYSINIT (and the DOS) that he
wishes his new driver to override the current sti and sto
(the "CON" device). This is accomplished by setting the
attributes to the desired characteristics, so he would set
Bits 0 and 1 to 1 (note that they are separate!!). Similarly
a new CLOCK device could be installed by setting that
attribute, see the section at the end on the CLOCK device.
NOTE: that although there is a NUL device attribute, the
NUL device cannot be re-assigned. This attribute exists
for the DOS so that it can tell if the NUL device is being
used.
The NON IBM FORMAT bit applies only to block devices
and effects the operation of the get BPB device call (see
below).
The other bit of interest is the IOCTL bit which has
meaning on character or block devices. This bit tells the
DOS whether this device can handle control strings (via the
IOCTL system call).
If a driver cannot process control strings, it should
initially set this bit to 0. This tells the DOS to return
an error if an attempt is made (via IOCTL system call) to
send or receive control strings to this device. A device
which can process control strings should initialize it to
1. For drivers of this type, the DOS will make calls to
the IOCTL INPUT and OUTPUT device functions to send and
receive IOCTL strings (see IOCTL in the SYSTEM-CALLS
document).
The IOCTL functions allow data to be sent and received
by the device itself for its own use (to set baud rate, stop
bits, form length etc., etc.), instead of passing data over
the device channel as a normal read or write does. The
interpretation of the passed information is up to the device,
but it MUST NOT simply be treated as a normal I/O.
The SPECIAL bit applies only to character drivers and
more particularly to CON drivers. The new 2.0 interface
is a much more general and consistent interface than the
old 1.25 DOS interface. It allows for a number of additional
features of 2.0. It is also slower than 1.25 if old style
"single byte" system calls are made. To make most efficient
use of the interface all applications should block their
I/O as much as possible. This means make one XENIX style
system call to output X bytes rather than X system calls
to output one byte each. Also putting a device channel in
RAW mode (see IOCTL) provides a means of putting out
characters even FASTER than 1.25. To help alleviate the
CON output speed problem for older programs which use the
1 - 12 system calls to output large amounts of data the
SPECIAL bit has been implemented. If this bit is 1 it means
the device is the CON output device, and has implemented
an interrupt 29 Hex handler, where the 29 Hex handler is
defined as follows:
Interrupt 29h handlers
Input:
Character in AL
Function:
output the character in al to the user
screen.
Output:
None
Registers:
all registers except bx must be preserved.
No registers except for al have a known or
consistent value.
If a character device implements the SPECIAL bit, it
is the responsibility of the driver to install an address
at the correct location in the interrupt table for interrupt
29 Hex as part of its INIT code. IMPLICATION: There can
be only one device driver with the SPECIAL bit set in the
system. There is no check to insure this state.
WARNING: THIS FEATURE WILL NOT BE SUPPORTED IN FUTURE VERSIONS
OF THE OPERATING SYSTEM. IMPLICATION: Any application
(not device driver) which uses INT 29H directly will
not work on future versions, YOU HAVE BEEN WARNED.
In order to "make" a device driver that SYSINIT can
install, a memory image or .EXE (non-IBM only) format file
must be created with the above header at the start. The
link field should be initialized to -1 (SYSINIT fills it
in). The attribute field and entry points must be set
correctly, and if the device is a character device, the name
field must be filled in with the name (if a block device
SYSINIT will fill in the correct unit count). This name
can be any 8 character "legal" file name. In fact SYSINIT
always installs character devices at the start of the device
list, so if you want to install a new CON device all you
have to do is name it "CON". The new one is ahead of the
old one in the list and thus preempts the old one as the
search for devices stops on the first match. Be sure to
set the sti and sto bits on a new CON device!
NOTE: Since SYSINIT may install the driver anywhere, you
must be very careful about FAR memory references. You
should NOT expect that your driver will go in the same
place every time (The default BIOS drivers are exempted
from this of course).
INSTALLATION OF DEVICE DRIVERS
Unlike past versions MS-DOS 2.0 allows new device drivers
to be installed dynamically at boot time. This is
accomplished by the new SYSINIT module supplied by Microsoft,
which reads and processes the CONFIG.SYS file. This module
is linked together with the OEM default BIOS in a similar
manner to the way FORMAT is built.
One of the functions defined for each device is INIT.
This routine is called once when the device is installed,
and never again. The only thing returned by the init routine
is a location (DS:DX) which is a pointer to the first free
byte of memory after the device driver, (like a terminate
and stay resident). This pointer method can be used to "throw
away" initialization code that is only needed once, saving
on space.
Block devices are installed the same way and also return
a first free byte pointer as above, additional information
is also returned:
o The number of units is returned, this determines
logical device names. If the current maximum logical
device letter is F at the time of the install call,
and the init routine returns 4 as the number of units,
then they will have logical names G, H, I and J.
This mapping is determined by by the position of
the driver in the device list and the number of units
on the device (stored in the first byte of the device
name field).
o A pointer to a BPB (Bios Parameter Block) pointer
array is also returned. This will be similar to
the INIT table used in previous versions, but will
have more information in it. There is one table
for each unit defined. These blocks will be used
to build a DPB (Drive Parameter Block) for each of
the units. The pointer passed to the DOS from the
driver points to an array of n word pointers to BPBs
where n is the number of units defined. In this
way if all units are the same, all of the pointers
can point to the same BPB, saving space. NOTE: this
array must be protected (below the free pointer set
by the return) since the DPB will be built starting
at the byte pointed to by the free pointer. The
sector size defined must be less than or equal to
the maximum sector size defined at default BIOS init
time. If it isn't the install will fail. One new
piece of DPB info set from this table will be a "media
descriptor byte". This byte means nothing to the
DOS, but is passed to devices so that they know what
form of a DPB the DOS is currently using for a
particular Drive-Unit.
Block devices may take several approaches; they may be
dumb or smart. A dumb device would define a unit (and
therefore a DPB) for each possible media drive combination.
Unit 0 = drive 0 single side, unit 1 = drive 0 double side,
etc. For this approach media descriptor bytes would mean
nothing. A smart device would allow multiple media per unit,
in this case the BPB table returned at init must define space
large enough to accommodate the largest possible media
supported. Smart drivers will use the "media byte" to pass
around info about what media is currently in a unit. NOTE:
If the DPB is a "hybrid" made to get the right sizes, it
should give an invalid "media byte" back to the DOS.
The BOOT (default BIOS) drivers are installed pretty
much as above. The preset device list is scanned. If block
drivers are encountered they are installed as above (with
the exception that the break is not moved since the drivers
are already resident in the BIOS). Note that the logical
drive letters are assigned in list order, thus the driver
which is to have logical A must be the first unit of the
first block device in the list. The order of character
devices is also important. There must be at least 4 character
devices defined at boot which must be the first four devices
(of either type), the first will become standard input,
standard output, and standard error output. The second will
become standard auxiliary input and output, the third will
become standard list output, and the forth will become the
date/time (CLOCK) device. Thus the BIOS device list must
look like this:
->CON->AUX->PRN->CLOCK->any other block or character devices
THE DRIVER
A device driver will define the following functions:
Command Function
Code
0 INIT
1 MEDIA CHECK (Block only, NOP for character)
2 BUILD BPB " " " " "
3 IOCTL INPUT (Only called if device has IOCTL)
4 INPUT (read)
5 NON-DESTRUCTIVE INPUT NO WAIT (Char devs only)
6 INPUT STATUS " " "
7 INPUT FLUSH " " "
8 OUTPUT (write)
9 OUTPUT (Write) with verify
10 OUTPUT STATUS " " "
11 OUTPUT FLUSH " " "
12 IOCTL OUTPUT (Only called if device has IOCTL)
As mentioned before, the first entry point is the strategy
routine which is called with a pointer to a data block. This
call does not perform the request, all it does is queue it
(save the data block pointer). The second interrupt entry
point is called immediately after the strategy call. The
"interrupt" routine is called with no parameters, its primary
function is to perform the operation based on the queued
data block and set up any returns.
The "BUILD BPB" and "MEDIA CHECK" are the interesting
new ones, these are explained by examining the sequence of
events in the DOS which occurs when a drive access call (other
than read or write) is made:
I. Turn drive letter into DPB pointer by looking
for DPB with correct driver-unit number.
II. Call device driver and request media check for
Drive-Unit. DOS passes its current Media
descriptor byte (from DPB). Call returns:
Media Not Changed
Media Changed
Not Sure
Error
Error - If an error occurs the error code should
be set accordingly.
Media Not changed - Current DPB and media byte
are OK, done.
Media Changed - Current DPB and media are wrong,
invalidate any buffers for this unit, and
goto III.
Not Sure - If there are dirty buffers for this
unit, assume DPB and media byte are OK and
done. If nothing dirty, assume media changed,
invalidate any buffers for unit, and goto
III.
NOTE: If a hybrid DPB was built at init and
an invalid Media byte was set, the driver
should return media changed when this invalid
media byte is encountered.
III. Call device driver to build BPB with media byte
and buffer.
What the driver must do at step III is determine the
correct media that is currently in the unit, and return a
pointer to a BPB table (same as for the install call). This
table will be used as at init to build a correct DPB for
the unit If the determined media descriptor byte in the table
turns out to be the same as the one passed in, then the DOS
will not build a new table, but rather just use the old one.
Therefore in this case the driver doesn't have to correctly
fill in the other entries if desired.
The build BPB call also gets a pointer to a one sector
buffer. What this buffer contains is determined by the NON
IBM FORMAT bit in the attribute field. If the bit is zero
(device is IBM format compatible) then the buffer contains
the first sector of the first FAT, in particular the FAT
ID byte is the first byte of this buffer. NOTE: It must
be true that the BPB is the same, as far as location of the
FAT is concerned, for all possible media. This is because
this first FAT sector must be read BEFORE the actual BPB
is returned. If the NON IBM FORMAT bit is set then the
pointer points to one sector of scratch space which may be
used for anything.
CALL FORMAT
When the DOS calls a device driver to perform a finction,
it passes a structure (Drive Request Structure) in ES:BX
to perform operations and does a long call to the driver's
strategy entry point. This structure is a fixed length header
(Static Request Header) followed by data pertinent to the
operation being performed. NOTE: It is the drivers
responsibility to preserve machine state.
STATIC REQUEST HEADER ->
+-----------------------------+
| BYTE length of record |
| Length in bytes of this |
| Drive Request Structure |
+-----------------------------+
| BYTE unit code |
| The subunit the operation |
| is for (minor device) |
| (no meaning on character |
| devices) |
+-----------------------------+
| BYTE command code |
+-----------------------------+
| WORD Status |
+-----------------------------+
| 8 bytes reserved here for |
| two DWORD links. One will |
| be a link for the DOS queue |
| The other for the device |
| queue |
+-----------------------------+
STATUS WORD
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+---+---+--+--+--+--+---+---+--+--+--+--+--+--+--+--+
| E | | B | D | |
| R | RESERVED | U | O | ERROR CODE (bit 15 on)|
| R | | I | N | |
+---+---+--+--+--+--+---+---+--+--+--+--+--+--+--+--+
The status word is zero on entry and is set by the driver
interrupt routine on return.
Bit 8 is the done bit, it means the operation is complete.
For the moment the Driver just sets it to one when it exits,
in the future this will be set by the interrupt routine to
tell the DOS the operation is complete.
Bit 15 is the error bit, if it is set then the low 8
bits indicate the error:
0 Write Protect violation
(NEW) 1 Unknown Unit
2 Drive not ready
(NEW) 3 Unknown command
4 CRC error
(NEW) 5 Bad Drive Request Structure length
6 Seek error
(NEW) 7 Unknown media
8 Sector not found
(NEW) 9 Printer out of paper
A Write Fault
(NEW) B Read Fault
C General Failure
Bit 9 is the busy bit which is set only by status calls (see
STATUS CALL below).
Here is the data block format for each function:
READ or WRITE - ES:BX (Including IOCTL) ->
+------------------------------------+
| 13-BYTE Static Request Header |
+------------------------------------+
| BYTE Media descriptor from DPB |
+------------------------------------+
| DWORD transfer address |
+------------------------------------+
| WORD byte/sector Count |
---+------------------------------------+---
| WORD starting sector number |
| (ignored on Char Devs) |
+------------------------------------+
In addition to setting the status word, the driver must
set the Sector count to the actual number of sectors (or
bytes) transferred. NOTE: No error check is performed on
an IOCTL I/O call, driver MUST correctly set the return sector
(byte) count to the actual number of bytes transferred,
however.
NOTE: THE FOLLOWING APPLIES TO BLOCK DEVICE DRIVERS.
Under certain circumstances the BIOS may be asked to
do a write operation of 64K bytes which seems to be a "wrap
around" of the transfer address in the BIOS I/O packet. This
arises due to an optimization added to the write code in
MS-DOS. It will only manifest on user WRITEs which are within
a sector size of 64K bytes on files which are "growing" past
the current EOF. IT IS ALLOWABLE FOR THE BIOS TO IGNORE
THE BALANCE OF THE WRITE WHICH "WRAPS AROUND" IF IT SO
CHOOSES. For instance a WRITE of 10000H bytes worth of
sectors with a transfer address of XXX:1 could ignore the
last two bytes (remember that a user program can never request
an I/O of more than FFFFH bytes and cannot wrap around (even
to 0) in his transfer segment, so in this case the last two
bytes can be ignored).
NON DESRUCTIVE READ NO WAIT - ES:BX ->
+------------------------------------+
| 13-BYTE Static Request Header |
+------------------------------------+
| BYTE read from device |
+------------------------------------+
This call is analogous to the console input status call
on MS-DOS 1.25. If the character device returns Busy bit
= 0 (characters in buffer), then the next character that
would be read is returned. This character is NOT removed
from the input buffer (hence the term Non Destructive Read).
In essence this call allows the DOS to look ahead one input
character.
MEDIA CHECK - ES:BX ->
+------------------------------------+
| 13-BYTE Static Request Header |
+------------------------------------+
| BYTE Media Descriptor from DPB |
+------------------------------------+
| BYTE returned |
+------------------------------------+
In addition to setting status word, driver must set the
return byte.
Return Byte :
-1 Media has been changed
0 Don't know if media has been changed
1 Media has not been changed
If the driver can return -1 or 1 (by having a door-lock
or other interlock mechanism) the performance of MSDOS 2.0
is enhanced as the DOS need not reread the FAT for each
directory access.
BUILD BPB - ES:BX ->
+------------------------------------+
| 13-BYTE Static Request Header |
+------------------------------------+
| BYTE Media Descriptor from DPB |
+------------------------------------+
| DWORD Transfer Address |
| (points to one sectors worth of |
| scratch space or first sector |
| of FAT depending on the value |
| of the NON IBM FORMAT bit) |
+------------------------------------+
| DWORD Pointer to BPB |
+------------------------------------+
If the NON IBM FORMAT bit of the device is set, then
the DWORD Transfer Address points to a one sector buffer
which can be used for any purpose. If the NON IBM FORMAT
bit is 0, then this buffer contains the first sector of the
FAT; in this case the driver must not alter this buffer (this
mode is useful if all that is desired is to read the FAT
ID byte).
If IBM compatible format is used (NON IBM FORMAT BIT
= 0), then it must be true that the first sector of the first
FAT is located at the same sector on all possible media.
This is because the FAT sector will be read BEFORE the media
is actually determined.
In addition to setting status word, driver must set the
Pointer to the BPB on return.
In order to allow for many different OEMs to read each
other's disks, the following standard is suggested: The
information relating to the BPB for a particular piece of
media is kept in the boot sector for the media. In
particular, the format of the boot sector is:
+------------------------------------+
| 3 BYTE near JUMP to boot code |
+------------------------------------+
| 8 BYTES OEM name and version |
---+------------------------------------+---
B | WORD bytes per sector |
P +------------------------------------+
B | BYTE sectors per allocation unit |
+------------------------------------+
| | WORD reserved sectors |
V +------------------------------------+
| BYTE number of FATs |
+------------------------------------+
| WORD number of root dir entries |
+------------------------------------+
| WORD number of sectors in logical |
^ | image |
| +------------------------------------+
B | BYTE media descriptor |
P +------------------------------------+
B | WORD number of FAT sectors |
---+------------------------------------+---
| WORD sectors per track |
+------------------------------------+
| WORD number of heads |
+------------------------------------+
| WORD number of hidden sectors |
+------------------------------------+
The three words at the end are optional, the DOS doesn't
care about them (since they are not part of the BPB). They
are intended to help the BIOS understand the media. Sectors
per track may be redundant (could be figured out from total
size of the disk). Number of heads is useful for supporting
different multi-head drives which have the same storage
capacity, but a different number of surfaces. Number of
hidden sectors is useful for supporting drive partitioning
schemes.
Currently, the media descriptor byte has been defined
for a small range of media:
5 1/4" diskettes:
Flag bits:
01h - on -> 2 double sided
All other bits must be on.
8" disks:
FEh - IBM 3740 format, singled-sided, single-density,
128 bytes per sector, soft sectored, 4 sectors
per allocation unit, 1 reserved sector, 2 FATs,
68 directory entries, 77*26 sectors
FDh - 8" IBM 3740 format, singled-sided,
single-density, 128 bytes per sector, soft
sectored, 4 sectors per allocation unit, 4
reserved sectors, 2 FATs, 68 directory entries,
77*26 sectors
FEh - 8" Double-sided, double-density, 1024 bytes
per sector, soft sectored, 1 sector per allocation
unit, 1 reserved sector, 2 FATs, 192 directory
entries, 77*8*2 sectors
STATUS Calls - ES:BX ->
+------------------------------------+
| 13-BYTE Static Request Header |
+------------------------------------+
All driver must do is set status word accordingly and
set the busy bit as follows:
o For output on character devices: If it is 1 on
return, a write request (if made) would wait for
completion of a current request. If it is 0, there
is no current request and a write request (if made)
would start immediately.
o For input on character devices with a buffer a return
of 1 means, a read request (if made) would go to
the physical device. If it is 0 on return, then
there are characters in the devices buffer and a
read would return quickly, it also indicates that
the user has typed something. The DOS assumes all
character devices have an input type ahead buffer.
Devices which don't have them should always return
busy = 0 so that the DOS won't hang waiting for
something to get into a buffer which doesn't exist.
FLUSH Calls - ES:BX ->
+------------------------------------+
| 13-BYTE Static Request Header |
+------------------------------------+
This call tells the driver to flush (terminate) all
pending requests that it has knowledge of. Its primary use
is to flush the input queue on character devices.
INIT - ES:BX ->
+------------------------------------+
| 13-BYTE Static Request Header |
+------------------------------------+
| BYTE # of units |
+------------------------------------+
| DWORD Break Address |
---+------------------------------------+---
| DWORD Pointer to BPB array |
| (not set by Character devices) |
+------------------------------------+
The number of units, break address, and BPB pointer are
set by the driver.
FORMAT OF BPB (Bios Parameter Block) -
+------------------------------------+
| WORD Sector size in Bytes |
| Must be at least 32 |
+------------------------------------+
| BYTE Sectors/Allocation unit |
| Must be a power of 2 |
+------------------------------------+
| WORD Number of reserved sectors |
| May be zero |
+------------------------------------+
| BYTE Number of FATS |
+------------------------------------+
| WORD Number of directory entries |
+------------------------------------+
| WORD Total number of sectors |
+------------------------------------+
| BYTE Media descriptor |
+------------------------------------+
| WORD Number of sectors occupied by |
| FAT |
+------------------------------------+
THE CLOCK DEVICE
One of the most popular add on boards seems to be "Real
Time CLOCK Boards". To allow these boards to be integrated
into the system for TIME and DATE, there is a special device
(determined by the attribute word) which is the CLOCK device.
In all respects this device defines and performs functions
like any other character device (most functions will be "set
done bit, reset error bit, return). When a read or write
to this device occurs, exactly 6 bytes are transferred. This
I/O can be thought of as transferring 3 words which correspond
exactly to the values of AX, CX and DX which were used in
the old 1.25 DOS date and time routines. Thus the first
two bytes are a word which is the count of days since 1-1-80.
The third byte is minutes, the fourth hours, the fifth
hundredths of seconds, and the sixth seconds. Reading the
CLOCK device gets the date and time, writing to it sets the
date and time.

BIN
v2.0/source/DEVSYM.ASM Normal file

Binary file not shown.

1084
v2.0/source/DIR.ASM Normal file

File diff suppressed because it is too large Load Diff

507
v2.0/source/DIRCALL.ASM Normal file
View File

@ -0,0 +1,507 @@
TITLE DIRCALL - Directory manipulation internal calls
NAME DIRCALL
; $MKDIR
; $CHDIR
; $RMDIR
.xlist
INCLUDE DOSSEG.ASM
CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME SS:DOSGROUP,CS:DOSGROUP
.xcref
INCLUDE DOSSYM.ASM
INCLUDE DEVSYM.ASM
.cref
.list
ifndef Kanji
Kanji equ 0
endif
i_need AUXSTACK,BYTE
i_need NoSetDir,BYTE
i_need CURBUF, DWORD
i_need DIRSTART,WORD
i_need THISDPB,DWORD
i_need NAME1,BYTE
i_need LASTENT,WORD
i_need ATTRIB,BYTE
i_need THISFCB,DWORD
i_need AUXSTACK,BYTE
i_need CREATING,BYTE
i_need DRIVESPEC,BYTE
i_need ROOTSTART,BYTE
i_need SWITCH_CHARACTER,BYTE
extrn sys_ret_ok:near,sys_ret_err:near
; XENIX CALLS
BREAK <$MkDir - Make a directory entry>
MKNERRJ: JMP MKNERR
NODEEXISTSJ: JMP NODEEXISTS
procedure $MKDIR,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; DS:DX Points to asciz name
; Function:
; Make a new directory
; Returns:
; STD XENIX Return
; AX = mkdir_path_not_found if path bad
; AX = mkdir_access_denied If
; Directory cannot be created
; Node already exists
; Device name given
; Disk or directory(root) full
invoke validate_path
JC MKNERRJ
MOV SI,DX
MOV WORD PTR [THISFCB+2],SS
MOV WORD PTR [THISFCB],OFFSET DOSGROUP:AUXSTACK-40 ; Scratch space
MOV AL,attr_directory
MOV WORD PTR [CREATING],0E500h
invoke MAKENODE
ASSUME DS:DOSGROUP
MOV AL,mkdir_path_not_found
JC MKNERRJ
JNZ NODEEXISTSJ
LDS DI,[CURBUF]
ASSUME DS:NOTHING
SUB SI,DI
PUSH SI ; Pointer to fcb_FIRCLUS
PUSH [DI.BUFSECNO] ; Sector of new node
PUSH SS
POP DS
ASSUME DS:DOSGROUP
PUSH [DIRSTART] ; Parent for .. entry
XOR AX,AX
MOV [DIRSTART],AX ; Null directory
invoke NEWDIR
JC NODEEXISTSPOPDEL ; No room
invoke GETENT ; First entry
LES DI,[CURBUF]
MOV ES:[DI.BUFDIRTY],1
ADD DI,BUFINSIZ ; Point at buffer
MOV AX,202EH ; ". "
STOSW
MOV DX,[DIRSTART] ; Point at itself
invoke SETDOTENT
MOV AX,2E2EH ; ".."
STOSW
POP DX ; Parent
invoke SETDOTENT
LES BP,[THISDPB]
POP DX ; Entry sector
XOR AL,AL ; Pre read
invoke GETBUFFR
MOV DX,[DIRSTART]
LDS DI,[CURBUF]
ASSUME DS:NOTHING
ZAPENT:
POP SI ; fcb_Firclus pointer
ADD SI,DI
MOV [SI],DX
XOR DX,DX
MOV [SI+2],DX
MOV [SI+4],DX
DIRUP:
MOV [DI.BUFDIRTY],1
PUSH SS
POP DS
ASSUME DS:DOSGROUP
MOV AL,ES:[BP.dpb_drive]
invoke FLUSHBUF
SYS_RET_OKJ:
JMP SYS_RET_OK
NODEEXISTSPOPDEL:
POP DX ; Parent
POP DX ; Entry sector
LES BP,[THISDPB]
XOR AL,AL ; Pre read
invoke GETBUFFR
LDS DI,[CURBUF]
ASSUME DS:NOTHING
POP SI ; dir_first pointer
ADD SI,DI
SUB SI,dir_first ; Point back to start of dir entry
MOV BYTE PTR [SI],0E5H ; Free the entry
CALL DIRUP
NODEEXISTS:
MOV AL,mkdir_access_denied
MKNERR:
JMP SYS_RET_ERR
$MKDIR ENDP
BREAK <$ChDir -- Change current directory on a drive>
procedure $CHDIR,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; DS:DX Points to asciz name
; Function:
; Change current directory
; Returns:
; STD XENIX Return
; AX = chdir_path_not_found if error
invoke validate_path
JC PathTooLong
PUSH DS
PUSH DX
MOV SI,DX
invoke GETPATH
JC PATHNOGOOD
JNZ PATHNOGOOD
ASSUME DS:DOSGROUP
MOV AX,[DIRSTART]
MOV BX,AX
XCHG BX,ES:[BP.dpb_current_dir]
OR AX,AX
POP SI
POP DS
ASSUME DS:NOTHING
JZ SYS_RET_OKJ
MOV DI,BP
ADD DI,dpb_dir_text
MOV DX,DI
CMP [DRIVESPEC],0
JZ NODRIVESPEC
INC SI
INC SI
NODRIVESPEC:
MOV CX,SI
CMP [ROOTSTART],0
JZ NOTROOTPATH
INC SI
INC CX
JMP SHORT COPYTHESTRINGBXZ
NOTROOTPATH:
OR BX,BX ; Previous path root?
JZ COPYTHESTRING ; Yes
XOR BX,BX
ENDLOOP:
CMP BYTE PTR ES:[DI],0
JZ PATHEND
INC DI
INC BX
JMP SHORT ENDLOOP
PATHEND:
MOV AL,'/'
CMP AL,[switch_character]
JNZ SLASHOK
MOV AL,'\' ; Use the alternate character
SLASHOK:
STOSB
INC BX
JMP SHORT CHECK_LEN
PATHNOGOOD:
POP AX
POP AX
PATHTOOLONG:
error error_path_not_found
ASSUME DS:NOTHING
INCBXCHK:
INC BX
BXCHK:
CMP BX,DIRSTRLEN
return
COPYTHESTRINGBXZ:
XOR BX,BX
COPYTHESTRING:
LODSB
OR AL,AL
JNZ FOOB
JMP CPSTDONE
FOOB:
CMP AL,'.'
JZ SEEDOT
CALL COPYELEM
CHECK_LEN:
CMP BX,DIRSTRLEN
JB COPYTHESTRING
MOV AL,ES:[DI-1]
invoke PATHCHRCMP
JNZ OK_DI
DEC DI
OK_DI:
XOR AL,AL
STOSB ; Correctly terminate the path
MOV ES:[BP.dpb_current_dir],-1 ; Force re-validation
JMP SHORT PATHTOOLONG
SEEDOT:
LODSB
OR AL,AL ; Check for null
JZ CPSTDONEDEC
CMP AL,'.'
JNZ COPYTHESTRING ; eat ./
CALL DELELMES ; have ..
LODSB ; eat the /
OR AL,AL ; Check for null
JZ CPSTDONEDEC
JMP SHORT COPYTHESTRING
; Copy one element from DS:SI to ES:DI include trailing / not trailing null
; LODSB has already been done
COPYELEM:
PUSH DI ; Save in case too long
PUSH CX
MOV CX,800h ; length of filename
MOV AH,'.' ; char to stop on
CALL CopyPiece ; go for it!
CALL BXCHK ; did we go over?
JAE POPCXDI ; yep, go home
CMP AH,AL ; did we stop on .?
JZ CopyExt ; yes, go copy ext
OR AL,AL ; did we end on nul?
JZ DECSIRet ; yes, bye
CopyPathEnd:
STOSB ; save the path char
CALL INCBXCHK ; was there room for it?
JAE POPCXDI ; Nope
INC SI ; guard against following dec
DECSIRET:
DEC SI ; point back at null
POP CX
POP AX ; toss away saved DI
return
POPCXDI:
POP CX ; restore
POP DI ; point back...
return
CopyExt:
STOSB ; save the dot
CALL INCBXCHK ; room?
JAE POPCXDI ; nope.
LODSB ; get next char
XOR AH,AH ; NUL here
MOV CX,300h ; at most 3 chars
CALL CopyPiece ; go copy it
CALL BXCHK ; did we go over
JAE POPCXDI ; yep
OR AL,AL ; sucessful end?
JZ DECSIRET ; yes
JMP CopyPathEnd ; go stash path char
DELELMES:
; Delete one path element from ES:DI
DEC DI ; the '/'
DEC BX
IF KANJI
PUSH AX
PUSH CX
PUSH DI
PUSH DX
MOV CX,DI
MOV DI,DX
DELLOOP:
CMP DI,CX
JZ GOTDELE
MOV AL,ES:[DI]
INC DI
invoke TESTKANJ
JZ NOTKANJ11
INC DI
JMP DELLOOP
NOTKANJ11:
invoke PATHCHRCMP
JNZ DELLOOP
MOV DX,DI ; Point to char after '/'
JMP DELLOOP
GOTDELE:
MOV DI,DX
POP DX
POP AX ; Initial DI
SUB AX,DI ; Distance moved
SUB BX,AX ; Set correct BX
POP CX
POP AX
return
ELSE
DELLOOP:
CMP DI,DX
retz
PUSH AX
MOV AL,ES:[DI-1]
invoke PATHCHRCMP
POP AX
retz
DEC DI
DEC BX
JMP SHORT DELLOOP
ENDIF
CPSTDONEDEC:
DEC DI ; Back up over trailing /
CPSTDONE:
STOSB ; The NUL
JMP SYS_RET_OK
; copy a piece CH chars max until the char in AH (or path or NUL)
CopyPiece:
STOSB ; store the character
INC CL ; moved a byte
CALL INCBXCHK ; room enough?
JAE CopyPieceRet ; no, pop CX and DI
OR AL,AL ; end of string?
JZ CopyPieceRet ; yes, dec si and return
IF KANJI
CALL TestKanj ; was it kanji?
JZ NotKanj ; nope
MOVSB ; move the next byte
CALL INCBXCHK ; room for it?
JAE CopyPieceRet ; nope
INC CL ; moved a byte
NotKanj:
ENDIF
CMP CL,CH ; move too many?
JBE CopyPieceNext ; nope
IF KANJI
CALL TestKanj ; was the last byte kanji
JZ NotKanj2 ; no only single byte backup
DEC DI ; back up a char
DEC BX
NotKanj2:
ENDIF
DEC DI ; back up a char
DEC BX
CopyPieceNext:
LODSB ; get next character
invoke PathChrCmp ; end of road?
JZ CopyPieceRet ; yep, return and don't dec SI
CMP AL,AH ; end of filename?
JNZ CopyPiece ; go do name
CopyPieceRet:
return ; bye!
$CHDIR ENDP
BREAK <$RmDir -- Remove a directory>
NOPATHJ: JMP NOPATH
procedure $RMDIR,NEAR ; System call 47
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; DS:DX Points to asciz name
; Function:
; Delete directory if empty
; Returns:
; STD XENIX Return
; AX = rmdir_path_not_found If path bad
; AX = rmdir_access_denied If
; Directory not empty
; Path not directory
; Root directory specified
; Directory malformed (. and .. not first two entries)
; AX = rmdir_current_directory
invoke Validate_path
JC NoPathJ
MOV SI,DX
invoke GETPATH
JC NOPATHJ
ASSUME DS:DOSGROUP
JNZ NOTDIRPATH
MOV DI,[DIRSTART]
OR DI,DI
JZ NOTDIRPATH
MOV CX,ES:[BP.dpb_current_dir]
CMP CX,-1
JNZ rmdir_current_dir_check
invoke GetCurrDir
invoke Get_user_stack
MOV DX,[SI.user_DX]
MOV DS,[SI.user_DS]
JMP $RMDIR
NOTDIRPATHPOP:
POP AX
POP AX
NOTDIRPATH:
error error_access_denied
rmdir_current_dir_check:
CMP DI,CX
JNZ rmdir_get_buf
error error_current_directory
rmdir_get_buf:
LDS DI,[CURBUF]
ASSUME DS:NOTHING
SUB BX,DI
PUSH BX ; Save entry pointer
PUSH [DI.BUFSECNO] ; Save sector number
PUSH SS
POP DS
ASSUME DS:DOSGROUP
PUSH SS
POP ES
MOV DI,OFFSET DOSGROUP:NAME1
MOV AL,'?'
MOV CX,11
REP STOSB
XOR AL,AL
STOSB
invoke STARTSRCH
invoke GETENTRY
MOV DS,WORD PTR [CURBUF+2]
ASSUME DS:NOTHING
MOV SI,BX
LODSW
CMP AX,(' ' SHL 8) OR '.'
JNZ NOTDIRPATHPOP
ADD SI,32-2
LODSW
CMP AX,('.' SHL 8) OR '.'
JNZ NOTDIRPATHPOP
PUSH SS
POP DS
ASSUME DS:DOSGROUP
MOV [LASTENT],2 ; Skip . and ..
invoke GETENTRY
MOV [ATTRIB],attr_directory+attr_hidden+attr_system
invoke SRCH
JNC NOTDIRPATHPOP
LES BP,[THISDPB]
MOV BX,[DIRSTART]
invoke RELEASE
POP DX
XOR AL,AL
invoke GETBUFFR
LDS DI,[CURBUF]
ASSUME DS:NOTHING
POP BX
ADD BX,DI
MOV BYTE PTR [BX],0E5H ; Free the entry
JMP DIRUP
NOPATH:
error error_path_not_found
$RMDIR ENDP
do_ext
CODE ENDS
END

1302
v2.0/source/DISK.ASM Normal file

File diff suppressed because it is too large Load Diff

BIN
v2.0/source/DISKCOPY.ASM Normal file

Binary file not shown.

BIN
v2.0/source/DISKMES.ASM Normal file

Binary file not shown.

5
v2.0/source/DOSLINK Normal file
View File

@ -0,0 +1,5 @@
msdos mscode dosmes misc getset dircall alloc dev dir +
disk fat rom stdbuf stdcall stdctrlc stdfcb stdproc +
stdio time xenix xenix2;


BIN
v2.0/source/DOSMAC.ASM Normal file

Binary file not shown.

274
v2.0/source/DOSMAC_v211.ASM Normal file
View File

@ -0,0 +1,274 @@
;
; Macro file for MSDOS.
;
SUBTTL BREAK a listing into pages and give new subtitles
PAGE
BREAK MACRO subtitle
SUBTTL subtitle
PAGE
ENDM
BREAK <I_NEED: declare a variable external, if necessary, and allocate a size>
;
; declare a variable external and allocate a size
;
I_NEED MACRO sym,len
DATA SEGMENT BYTE PUBLIC 'DATA'
IFIDN <len>,<WORD>
EXTRN &sym:WORD
ELSE
IFIDN <len>,<DWORD>
EXTRN &sym:DWORD
ELSE
EXTRN &sym:BYTE
ENDIF
ENDIF
DATA ENDS
ENDM
;
; call a procedure that may be external. The call will be short.
;
invoke MACRO name
.xcref
IF2
IFNDEF name
EXTRN name:NEAR
ENDIF
ENDIF
.cref
CALL name
ENDM
PAGE
;
; jump to a label that may be external. The jump will be near.
;
transfer MACRO name
.xcref
IF2
IFNDEF name
EXTRN name:NEAR
ENDIF
ENDIF
.cref
JUMP name
ENDM
;
; get a short address in a word
;
short_addr MACRO name
IFDIF <name>,<?>
.xcref
IF2
IFNDEF name
EXTRN name:NEAR
ENDIF
ENDIF
.cref
DW OFFSET DOSGROUP:name
ELSE
DW ?
ENDIF
ENDM
;
; get a long address in a dword
;
long_addr MACRO name
.xcref
IF2
IFNDEF name
EXTRN name:NEAR
ENDIF
.cref
DD name
ENDM
;
; declare a PROC near or far but PUBLIC nonetheless
;
procedure MACRO name,distance
PUBLIC name
name PROC distance
ENDM
PAGE
;
; define a data item to be public and of an appropriate size/type
;
I_AM MACRO name,size
PUBLIC name
IFIDN <size>,<WORD>
name DW ?
ELSE
IFIDN <size>,<DWORD>
name DD ?
ELSE
IFIDN <size>,<BYTE>
name DB ?
ELSE
name DB size DUP (?)
ENDIF
ENDIF
ENDIF
ENDM
PAGE
;
; call the macro chain
;
do_ext macro
endm
PAGE
;
; define an entry in a procedure
;
entry macro name
PUBLIC name
name:
endm
BREAK <ERROR - print a message and then jump to a label>
error macro code
local a
.xcref
MOV AL,code
transfer SYS_RET_ERR
.cref
ENDM
BREAK <JUMP - real jump that links up shortwise>
;
; given a label <lbl> either 2 byte jump to another label <lbl>_J
; if it is near enough or 3 byte jump to <lbl>
;
jump macro lbl
local a
.xcref
a:
ifndef lbl&_J ;; is this the first invocation
JMP lbl
ELSE
IF lbl&_J GE $
JMP lbl
ELSE
IF ($-lbl&_J) GT 126 ;; is the jump too far away?
JMP lbl
ELSE ;; do the short one...
JMP lbl&_J
ENDIF
ENDIF
ENDIF
lbl&_j = a
.cref
endm
BREAK <RETURN - return from a function>
return macro
local a
.xcref
a:
RET
ret_l = a
.cref
endm
BREAK <CONDRET - conditional return>
makelab macro l,cc,ncc
local a
j&ncc a ;; j<NCC> a:
return ;; return
a: ;; a:
ret_&cc = ret_l ;; define ret_<CC> to be ret_l
endm
condret macro cc,ncc
local a,b
ifdef ret_l ;; if ret_l is defined
if (($ - ret_l) le 126) and ($ gt ret_l)
;; if ret_l is near enough then
a: j&cc ret_l ;; a: j<CC> to ret_l
ret_&cc = a ;; define ret_<CC> to be a:
else
makelab a,cc,ncc
endif
else
ifdef ret_&cc ;; if ret_<CC> defined
if (($ - ret_&cc) le 126) and ($ gt ret_&cc)
;; if ret_<CC> is near enough
a: j&cc ret_&cc ;; a: j<CC> to ret_<CC>
ret_&cc = a ;; define ret_<CC> to be a:
else
makelab a,cc,ncc
endif
else
makelab a,cc,ncc
endif
endif
endm
;condret macro cc,ncc
; local a,b
; ifdef ret_l ; if ret_l is defined
; if (($ - ret_l) le 126) and ($ gt ret_l)
; ; if ret_l is near enough then
; a: j&cc ret_l ; a: j<CC> to ret_l
; ret_&cc = a ; define ret_<CC> to be a:
; exitm
; endif
; endif
; ifdef ret_&cc ; if ret_<CC> defined
; if (($ - ret_&cc) le 126) and ($ gt ret_&cc)
; ; if ret_<CC> is near enough
; a: j&cc ret_&cc ; a: j<CC> to ret_<CC>
; ret_&cc = a ; define ret_<CC> to be a:
; exitm
; endif
; endif
; j&ncc a ; j<NCC> a:
; return ; return
; a: ; a:
; ret_&cc = ret_l ; define ret_<CC> to be ret_l
;endm
;
BREAK <RETZ - return if zero, links up shortwise if necessary>
retz macro
condret z,nz
endm
BREAK <RETNZ - return if not zero, links up shortwise if necessary>
retnz macro
condret nz,z
endm
BREAK <RETC - return if carry set, links up shortwise if necessary>
retc macro
condret c,nc
endm
BREAK <RETNC - return if not carry, links up shortwise if necessary>
retnc macro
condret nc,c
endm
BREAK <CONTEXT - set the DOS context to a particular register>
context macro r
PUSH SS
POP r
ASSUME r:DOSGROUP
endm

355
v2.0/source/DOSMES.ASM Normal file
View File

@ -0,0 +1,355 @@
INCLUDE STDSW.ASM
KANJI EQU FALSE
Rainbow EQU FALSE
INCLUDE DOSSYM.ASM
;
; segment ordering for MSDOS
;
CONSTANTS SEGMENT BYTE PUBLIC 'CONST'
CONSTANTS ENDS
DATA SEGMENT BYTE PUBLIC 'DATA'
DATA ENDS
CODE SEGMENT BYTE PUBLIC 'CODE'
CODE ENDS
LAST SEGMENT BYTE PUBLIC 'LAST'
LAST ENDS
DOSGROUP GROUP CODE,CONSTANTS,DATA,LAST
CONSTANTS SEGMENT BYTE PUBLIC 'CONST'
PUBLIC DIVMES
DIVMES DB 13,10,"Divide overflow",13,10
PUBLIC DivMesLen
DivMesLen DB $-DivMes ; Length of the above message in bytes
;
; The next variable points to the country table for the current country
; ( the table returned by the AL=0 INTERNATIONAL call).
;
PUBLIC Current_Country
IF KANJI
Current_Country DW OFFSET DOSGROUP:JAPTABLE
ELSE
Current_Country DW OFFSET DOSGROUP:USTABLE
ENDIF
;
; The international tabel(s).
; This is simply a sequence of tables of the following form:
;
; BYTE Size of this table excluding this byte and the next
; BYTE Country code represented by this table
; A sequence of n bytes, where n is the number specified
; by the first byte above and is not > internat_block_max,
; in the correct order for being returned by the
; INTERNATIONAL call as follows:
; WORD Date format 0=mdy, 1=dmy, 2=ymd
; 5 BYTE Currency symbol null terminated
; 2 BYTE thousands separator null terminated
; 2 BYTE Decimal point null terminated
; 2 BYTE Date separator null terminated
; 2 BYTE Time separator null terminated
; 1 BYTE Bit field. Currency format.
; Bit 0. =0 $ before # =1 $ after #
; Bit 1. no. of spaces between # and $ (0 or 1)
; 1 BYTE No. of significant decimal digits in currency
; 1 BYTE Bit field. Time format.
; Bit 0. =0 12 hour clock =1 24 hour
; WORD Segment offset for address of case conversion routine
; WORD RESERVED. Filled in by DOS. Segment value for above routine
; 2 BYTE Data list separator null terminated.
; NOTE: The segment part of the DWORD Map_call is set
; by the INTERNATIONAL call. Do not try to initialize
; it to anything meaningful.
;
; The list of tables is terminated by putting a byte of -1 after the last
; table (a table with length -1).
PUBLIC international_table
international_table LABEL BYTE
IF KANJI
DB SIZE internat_block ; Size in bytes of this table
DB 81 ; Country code
JAPTABLE internat_block <2,'\',0,0,0,0,',',0,'.',0,'-',0,':',0,0,0,1,OFFSET DOSGROUP:MAP_DCASE , 0,',',0>
ENDIF
DB SIZE internat_block ; Size in bytes of this table
DB 1 ; Country code
USTABLE internat_block <0,'$',0,0,0,0,',',0,'.',0,'-',0,':',0,0,2,0,OFFSET DOSGROUP:MAP_DCASE,0,',',0>
; Tables for the IBM PC character set follow. The values
; associated with some of the currency symbols may change with
; other character sets. You may wish to add or delete country
; entries. NOTE: It is not a mistake that the JAPANESE entry
; has different currency symbols for the KANJI and
; non-KANJI versions.
IF NOT KANJI
IF IBM
DB SIZE internat_block ; Size in bytes of this table
DB 44 ; Country code
UKTABLE internat_block <1,9Ch,0,0,0,0,',',0,'.',0,'-',0,':',0,0,2,0,OFFSET DOSGROUP:MAP_DCASE,0,',',0>
DB SIZE internat_block ; Size in bytes of this table
DB 49 ; Country code
GRMTABLE internat_block <1,'D','M',0,0,0,'.',0,',',0,'.',0,'.',0,3,2,1,OFFSET DOSGROUP:MAP_DCASE,0,';',0>
DB SIZE internat_block ; Size in bytes of this table
DB 33 ; Country code
FRNTABLE internat_block <1,'F',0,0,0,0,' ',0,',',0,'/',0,':',0,3,2,1,OFFSET DOSGROUP:MAP_DCASE,0,';',0>
DB SIZE internat_block ; Size in bytes of this table
DB 81 ; Country code
JAPTABLE internat_block <2,9DH,0,0,0,0,',',0,'.',0,'-',0,':',0,0,0,1,OFFSET DOSGROUP:MAP_DCASE , 0,',',0>
ENDIF
ENDIF
DB -1 ; End of tables
CONSTANTS ENDS
CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
;CASE MAPPER ROUTINE FOR 80H-FFH character range
; ENTRY: AL = Character to map
; EXIT: AL = The converted character
; Alters no registers except AL and flags.
; The routine should do nothing to chars below 80H.
;
; Example:
MAP_DCASE PROC FAR
IF NOT KANJI
IF IBM
CMP AL,80H
JB L_RET ;Map no chars below 80H ever
CMP AL,0A7H
JA L_RET ;This routine maps chars between 80H and A7H
SUB AL,80H ;Turn into index value
PUSH DS
PUSH BX
PUSH CS ;Move to DS
POP DS
MOV BX,OFFSET DOSGROUP:TABLE
XLAT ;Get upper case character
POP BX
POP DS
ENDIF
ENDIF
L_RET: RET
MAP_DCASE ENDP
IF NOT KANJI
IF IBM
TABLE: DB 80H,9AH,"E","A",8EH,"A",8FH,80H
DB "E","E","E","I","I","I",8EH,8FH
DB 90H,92H,92H,"O",99H,"O","U","U"
DB "Y",99H,9AH,9BH,9CH,9DH,9EH,9FH
DB "A","I","O","U",0A5H,0A5H,0A6H,0A7H
ENDIF
ENDIF
SUBTTL EDIT FUNCTION ASSIGNMENTS AND HEADERS
PAGE
; The following two tables implement the current buffered input editing
; routines. The tables are pairwise associated in reverse order for ease
; in indexing. That is; The first entry in ESCTAB corresponds to the last
; entry in ESCFUNC, and the last entry in ESCTAB to the first entry in ESCFUNC.
PUBLIC ESCCHAR
ESCCHAR DB ESCCH ;Lead-in character for escape sequences
IF NOT Rainbow
ESCTAB:
IF NOT IBM
IF WANG
DB 0C0h ; ^Z inserter
DB 0C1H ; Copy one char
DB 0C7H ; Skip one char
DB 08AH ; Copy to char
DB 088H ; Skip to char
DB 09AH ; Copy line
DB 0CBH ; Kill line (no change in template)
DB 08BH ; Reedit line (new template)
DB 0C3H ; Backspace
DB 0C6H ; Enter insert mode
IF NOT TOGLINS
DB 0D6H ; Exit insert mode
ENDIF
DB 0C6H ; Escape character
DB 0C6H ; End of table
ELSE
; VT52 equivalences
DB "Z" ; ^Z inserter
DB "S" ; F1 Copy one char
DB "V" ; F4 Skip one char
DB "T" ; F2 Copy to char
DB "W" ; F5 Skip to char
DB "U" ; F3 Copy line
DB "E" ; SHIFT ERASE Kill line (no change in template)
DB "J" ; ERASE Reedit line (new template)
DB "D" ; LEFT Backspace
DB "P" ; BLUE Enter insert mode
DB "Q" ; RED Exit insert mode
DB "R" ; GRAY Escape character
DB "R" ; End of table
ENDIF
ENDIF
IF IBM
DB 64 ; Ctrl-Z - F6
DB 77 ; Copy one char - -->
DB 59 ; Copy one char - F1
DB 83 ; Skip one char - DEL
DB 60 ; Copy to char - F2
DB 62 ; Skip to char - F4
DB 61 ; Copy line - F3
DB 61 ; Kill line (no change to template ) - Not used
DB 63 ; Reedit line (new template) - F5
DB 75 ; Backspace - <--
DB 82 ; Enter insert mode - INS (toggle)
DB 65 ; Escape character - F7
DB 65 ; End of table
ENDIF
ESCEND:
ESCTABLEN EQU ESCEND-ESCTAB
ESCFUNC LABEL WORD
short_addr GETCH ; Ignore the escape sequence
short_addr TWOESC
IF NOT TOGLINS
short_addr EXITINS
ENDIF
short_addr ENTERINS
short_addr BACKSP
short_addr REEDIT
short_addr KILNEW
short_addr COPYLIN
short_addr SKIPSTR
short_addr COPYSTR
short_addr SKIPONE
short_addr COPYONE
IF IBM
short_addr COPYONE
ENDIF
short_addr CTRLZ
ENDIF
;
; OEMFunction key is expected to process a single function
; key input from a device and dispatch to the proper
; routines leaving all registers UNTOUCHED.
;
; Inputs: CS, SS are DOSGROUP
; Outputs: None. This function is expected to JMP to onw of
; the following labels:
;
; GetCh - ignore the sequence
; TwoEsc - insert an ESCChar in the buffer
; ExitIns - toggle insert mode
; EnterIns - toggle insert mode
; BackSp - move backwards one space
; ReEdit - reedit the line with a new template
; KilNew - discard the current line and start from scratch
; CopyLin - copy the rest of the template into the line
; SkipStr - read the next character and skip to it in the template
; CopyStr - read next char and copy from template to line until char
; SkipOne - advance position in template one character
; CopyOne - copy next character in template into line
; CtrlZ - place a ^Z into the template
; Registers that are allowed to be modified by this function are:
; AX, CX, BP
PUBLIC OEMFunctionKey
OEMFunctionKey PROC NEAR
ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGROUP
invoke $STD_CON_INPUT_NO_ECHO ; Get the second byte of the sequence
IF NOT Rainbow
MOV CL,ESCTABLEN ; length of table for scan
PUSH DI ; save DI (cannot change it!)
MOV DI,OFFSET DOSGROUP:ESCTAB ; offset of second byte table
REPNE SCASB ; Look it up in the table
POP DI ; restore DI
SHL CX,1 ; convert byte offset to word
MOV BP,CX ; move to indexable register
JMP [BP+OFFSET DOSGROUP:ESCFUNC] ; Go to the right routine
ENDIF
IF Rainbow
TransferIf MACRO value,address
local a
CMP AL,value
JNZ a
transfer address
a:
ENDM
CMP AL,'[' ; is it second lead char
JZ EatParm ; yes, go walk tree
GoGetCh:
transfer GetCh ; no, ignore sequence
EatParm:
invoke $STD_CON_INPUT_NO_ECHO ; get argument
CMP AL,'A' ; is it alphabetic arg?
JAE EatAlpha ; yes, go snarf one up
XOR BP,BP ; init digit counter
JMP InDigit ; jump into internal eat digit routine
EatNum:
invoke $STD_CON_INPUT_NO_ECHO ; get next digit
InDigit:
CMP AL,'9' ; still a digit?
JA CheckNumEnd ; no, go check for end char
SUB AL,'0' ; turn into potential digit
JB GoGetCh ; oops, not a digit, ignore
MOV CX,BP ; save BP for 10 multiply
CBW ; make AL into AX
SHL BP,1 ; 2*BP
SHL BP,1 ; 4*BP
ADD BP,CX ; 5*BP
SHL BP,1 ; 10*BP
ADD BP,AX ; 10*BP + digit
JMP EatNum ; continue with number
CheckNumEnd:
CMP AL,7Eh ; is it end char ~
JNZ GoGetCh ; nope, ignore key sequence
MOV AX,BP
transferIf 1,SkipStr ; FIND key
transferIf 2,EnterIns ; INSERT HERE key
transferIf 3,SkipOne ; REMOVE
transferIf 4,CopyStr ; SELECT
transferIf 17,TwoEsc ; INTERRUPT
transferIf 18,ReEdit ; RESUME
transferIf 19,KilNew ; CANCEL
transferIf 21,CtrlZ ; EXIT
transferIf 29,CopyLin ; DO
JMP GoGetCh
EatAlpha:
CMP AL,'O' ; is it O?
JA GoGetCh ; no, after assume bogus
JZ EatPQRS ; eat the rest of the bogus key
transferIf 'C',CopyOne ; RIGHT
transferIf 'D',BackSp ; LEFT
JMP GoGetCh
EatPQRS:
invoke $STD_CON_INPUT_NO_ECHO ; eat char after O
JMP GoGetCh
ENDIF
OEMFunctionKey ENDP
CODE ENDS
do_ext
END


17
v2.0/source/DOSSEG.ASM Normal file
View File

@ -0,0 +1,17 @@
;
; segment ordering for MSDOS
;
CONSTANTS SEGMENT BYTE PUBLIC 'CONST'
CONSTANTS ENDS
DATA SEGMENT BYTE PUBLIC 'DATA'
DATA ENDS
CODE SEGMENT BYTE PUBLIC 'CODE'
CODE ENDS
LAST SEGMENT BYTE PUBLIC 'LAST'
LAST ENDS
DOSGROUP GROUP CODE,CONSTANTS,DATA,LAST

904
v2.0/source/DOSSYM.ASM Normal file
View File

@ -0,0 +1,904 @@
include DOSMAC.ASM
IF2
%OUT DOSSYM in Pass 2
ENDIF
IFNDEF ALTVECT
ALTVECT EQU 0 ;FALSE
ENDIF
BREAK <Control character definitions>
c_DEL EQU 7Fh ; ASCII rubout or delete previous char
c_BS EQU 08h ; ^H ASCII backspace
c_CR EQU 0Dh ; ^M ASCII carriage return
c_LF EQU 0Ah ; ^J ASCII linefeed
c_ETB EQU 17h ; ^W ASCII end of transmission
c_NAK EQU 15h ; ^U ASCII negative acknowledge
c_ETX EQU 03h ; ^C ASCII end of text
c_HT EQU 09h ; ^I ASCII tab
BREAK <BPB Definition>
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; ;
; C A V E A T P R O G R A M M E R ;
; ;
; Certain structures, constants and system calls below are private to ;
; the DOS and are extremely version-dependent. They may change at any ;
; time at the implementors' whim. As a result, they must not be ;
; documented to the general public. If an extreme case arises, they ;
; must be documented with this warning. ;
; ;
; Those structures and constants that are subject to the above will be ;
; marked and bracketed with the flag: ;
; ;
; C A V E A T P R O G R A M M E R ;
; ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
BREAK <Bios Parameter Block>
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
; Bios Parameter Block definition
; This structure is used to build a full DPB
BPBLOCK STRUC
BPSECSZ DW ? ; Size in bytes of physical sector
BPCLUS DB ? ; Sectors/Alloc unit
BPRES DW ? ; Number of reserved sectors
BPFTCNT DB ? ; Number of FATs
BPDRCNT DW ? ; Number of directory entries
BPSCCNT DW ? ; Total number of sectors
BPMEDIA DB ? ; Media descriptor byte
BPFTSEC DW ? ; Number of sectors taken up by one FAT
BPBLOCK ENDS
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
BREAK <Disk I/O Buffer Header>
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
; Field definition for I/O buffer information
BUFFINFO STRUC
NEXTBUF DD ? ; Pointer to next buffer in list
; The next two items are often refed as a word
BUFDRV DB ? ; Logical drive # assoc with buffer FF = free
BUFDIRTY DB ? ; Dirty flag
BUFPRI DB ? ; Buffer selection priority (see EQUs below)
VISIT DB ? ; Visit flag for buffer pool scans
BUFSECNO DW ? ; Sector number of buffer
; The next two items are often refed as a word
BUFWRTCNT DB ? ; For FAT sectors, # times sector written out
BUFWRTINC DB ? ; " " " , # sectors between each write
BUFDRVDP DD ? ; Pointer to drive parameters
BUFFINFO ENDS
BUFINSIZ EQU SIZE BUFFINFO
; Size of structure in bytes
FREEPRI EQU 0
LBRPRI EQU 2 ; Last byte of buffer read
LBWPRI EQU 4 ; Last byte written
RPRI EQU 6 ; Read but not last byte
WPRI EQU 8 ; Written but not last byte
DIRPRI EQU 15 ; Directory Sector
FATPRI EQU 30 ; FAT sector
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
BREAK <User stack inside of system call>
; Location of user registers relative user stack pointer
user_environ STRUC
user_AX DW ?
user_BX DW ?
user_CX DW ?
user_DX DW ?
user_SI DW ?
user_DI DW ?
user_BP DW ?
user_DS DW ?
user_ES DW ?
user_IP DW ?
user_CS DW ?
user_F DW ?
user_environ ENDS
BREAK <interrupt definitions>
INTTAB EQU 20H
INTBASE EQU 4 * inttab
ENTRYPOINT EQU INTBASE+40H
IF ALTVECT
ALTTAB EQU 0F0H
ALTBASE EQU 4 * ALTTAB
ENDIF
;
; interrupt assignments
;
IF NOT ALTVECT
int_abort EQU INTTAB ; abort process
int_command EQU int_abort+1 ; call MSDOS
int_terminate EQU int_abort+2 ; int to terminate address
int_ctrl_c EQU int_abort+3 ; ^c trapper
int_fatal_abort EQU int_abort+4 ; hard disk error
int_disk_read EQU int_abort+5 ; logical sector disk read
int_disk_write EQU int_abort+6 ; logical sector disk write
int_keep_process EQU int_abort+7 ; terminate program and stay resident
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
int_spooler EQU int_abort+8 ; spooler call
int_fastcon EQU int_abort+9 ; fast CON interrupt
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
ELSE
int_abort EQU INTTAB ; abort process
int_command EQU int_abort+1 ; call MSDOS
int_terminate EQU ALTTAB ; int to terminate address
int_ctrl_c EQU int_terminate+1 ; ^c trapper
int_fatal_abort EQU int_terminate+2 ; hard disk error
int_disk_read EQU int_abort+5 ; logical sector disk read
int_disk_write EQU int_abort+6 ; logical sector disk write
int_keep_process EQU int_abort+7 ; terminate program and stay resident
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
int_spooler EQU int_terminate+3 ; spooler call
int_fastcon EQU int_abort+9 ; fast CON interrupt
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
ENDIF
addr_int_abort EQU 4 * int_abort
addr_int_command EQU 4 * int_command
addr_int_terminate EQU 4 * int_terminate
addr_int_ctrl_c EQU 4 * int_ctrl_c
addr_int_fatal_abort EQU 4 * int_fatal_abort
addr_int_disk_read EQU 4 * int_disk_read
addr_int_disk_write EQU 4 * int_disk_write
addr_int_keep_process EQU 4 * int_keep_process
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
addr_int_spooler EQU 4 * int_spooler
addr_int_fastcon EQU 4 * int_fastcon
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
BREAK <Disk map>
; MSDOS partitions the disk into 4 sections:
;
; phys sector 0: +-------------------+
; | | boot/reserved |
; | +-------------------+
; | | File allocation |
; v | table(s) |
; | (multiple copies |
; | are kept) |
; +-------------------+
; | Directory |
; +-------------------+
; | File space |
; +-------------------+
; | Unaddressable |
; | (to end of disk) |
; +-------------------+
;
; All partition boundaries are sector boundaries. The size of the FAT is
; adjusted to maximize the file space addressable.
BREAK <Directory entry>
;
; +---------------------------+
; | (12 BYTE) filename/ext | 0 0
; +---------------------------+
; | (BYTE) attributes | 11 B
; +---------------------------+
; | (10 BYTE) reserved | 12 C
; +---------------------------+
; | (WORD) time of last write | 22 16
; +---------------------------+
; | (WORD) date of last write | 24 18
; +---------------------------+
; | (WORD) First cluster | 26 1A
; +---------------------------+
; | (DWORD) file size | 28 1C
; +---------------------------+
;
; First byte of filename = E5 -> free directory entry
; = 00 -> end of allocated directory
; Time: Bits 0-4=seconds/2, bits 5-10=minute, 11-15=hour
; Date: Bits 0-4=day, bits 5-8=month, bits 9-15=year-1980
;
dir_entry STRUC
dir_name DB 11 DUP (?) ; file name
dir_attr DB ? ; attribute bits
dir_pad DB 10 DUP (?) ; reserved for expansion
dir_time DW ? ; time of last write
dir_date DW ? ; date of last write
dir_first DW ? ; first allocation unit of file
dir_size_l DW ? ; low 16 bits of file size
dir_size_h DW ? ; high 16 bits of file size
dir_entry ENDS
attr_read_only EQU 1h
attr_hidden EQU 2h
attr_system EQU 4h
attr_volume_id EQU 8h
attr_directory EQU 10h
attr_archive EQU 20h
attr_all EQU attr_hidden+attr_system+attr_directory
; OR of hard attributes for FINDENTRY
attr_ignore EQU attr_read_only+attr_archive
; ignore this(ese) attribute(s)
; during search first/next
attr_changeable EQU attr_read_only+attr_hidden+attr_system+attr_archive
; changeable via CHMOD
BREAK <File allocation Table information>
;
; The File Allocation Table uses a 12-bit entry for each allocation unit on the
; disk. These entries are packed, two for every three bytes. The contents of
; entry number N is found by 1) multiplying N by 1.5; 2) adding the result to
; the base address of the Allocation Table; 3) fetching the 16-bit word at this
; address; 4) If N was odd (so that N*1.5 was not an integer), shift the word
; right four bits; 5) mask to 12 bits (AND with 0FFF hex). Entry number zero
; is used as an end-of-file trap in the OS and is passed to the BIOS to help
; determine disk format. Entry 1 is reserved for future use. The first
; available allocation unit is assigned entry number two, and even though it is
; the first, is called cluster 2. Entries greater than 0FF8H are end of file
; marks; entries of zero are unallocated. Otherwise, the contents of a FAT
; entry is the number of the next cluster in the file.
;
; Clusters with bad sectors are tagged with FF7H. Any non-zero number would do
; because these clusters show as allocated, but are not part of any allocation
; chain and thus will never be allocated to a file. A particular number is
; selected so that disk checking programs know what to do (ie. a cluster with
; entry FF7H which is not in a chain is not an error).
BREAK <DPB structure>
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
DIRSTRLEN EQU 64 ; Max length in bytes of directory strings
dpb STRUC
dpb_drive DB ? ; Logical drive # assoc with DPB (A=0,B=1,...)
dpb_UNIT DB ? ; Driver unit number of DPB
dpb_sector_size DW ? ; Size of physical sector in bytes
dpb_cluster_mask DB ? ; Sectors/cluster - 1
dpb_cluster_shift DB ? ; Log2 of sectors/cluster
dpb_first_FAT DW ? ; Starting record of FATs
dpb_FAT_count DB ? ; Number of FATs for this drive
dpb_root_entries DW ? ; Number of directory entries
dpb_first_sector DW ? ; First sector of first cluster
dpb_max_cluster DW ? ; Number of clusters on drive + 1
dpb_FAT_size DB ? ; Number of records occupied by FAT
dpb_dir_sector DW ? ; Starting record of directory
dpb_driver_addr DD ? ; Pointer to driver
dpb_media DB ? ; Media byte
dpb_first_access DB ? ; This is initialized to -1 to force a media
; check the first time this DPB is used
dpb_next_dpb DD ? ; Pointer to next Drive parameter block
dpb_current_dir DW ? ; Cluster number of start of current directory
; 0 indicates root, -1 indicates invalid
; (disk ? changed)
dpb_dir_text DB DIRSTRLEN DUP(?)
; ASCIZ string of current directory
dpb ENDS
DPBSIZ EQU SIZE dpb ; Size of the structure in bytes
DSKSIZ = dpb_max_cluster ; Size of disk (temp used during init only)
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
BREAK <File Control Block definition>
;
; Field definition for FCBs
; The FCB has the following structure:
;
; +---------------------------+
; | Drive indicator(byte) |
; +---------------------------+
; | Filename (8 chars) |
; +---------------------------+
; | Extension (3 chars) |
; +---------------------------+
; | Current Extent(word) |
; +---------------------------+
; | Record size (word) |
; +---------------------------+
; | File Size (2 words) |
; +---------------------------+
; | Date of write |
; +---------------------------+
; | Time of write |
; +---------------------------+
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
; | Flags: |
; | bit 7=0 file/1 device |
; | bit 6=0 if dirty |
; | bits 0-5 deviceid |
; +---------------------------+
; | first cluster in file |
; +---------------------------+
; | position of last cluster |
; +---------------------------+
; | last cluster accessed | 12 bit-+--- packed in 3 bytes
; +---------------------------+ |
; | parent directory | <------+
; +---------------------------+
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; | next record number |
; +---------------------------+
; | random record number |
; +---------------------------+
;
sys_fcb STRUC
fcb_drive DB ?
fcb_name DB 8 DUP (?)
fcb_ext DB 3 DUP (?)
fcb_EXTENT DW ?
fcb_RECSIZ DW ? ; Size of record (user settable)
fcb_FILSIZ DW ? ; Size of file in bytes; used with the following
; word
fcb_DRVBP DW ? ; BP for SEARCH FIRST and SEARCH NEXT
fcb_FDATE DW ? ; Date of last writing
fcb_FTIME DW ? ; Time of last writing
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
fcb_DEVID DB ? ; Device ID number, bits 0-5 if file.
; bit 7=0 for file, bit 7=1 for I/O device
; If file, bit 6=0 if dirty
; If I/O device, bit 6=0 if EOF (input)
; Bit 5=1 if Raw mode
; Bit 0=1 if console input device
; Bit 1=1 if console output device
; Bit 2=1 if null device
; Bit 3=1 if clock device
fcb_FIRCLUS DW ? ; First cluster of file
fcb_CLUSPOS DW ? ; Position of last cluster accessed
fcb_LSTCLUS DW ? ; Last cluster accessed and directory
DB ? ; pack 2 12 bit numbers into 24 bits...
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
fcb_NR DB ? ; Next record
fcb_RR DB 4 DUP (?) ; Random record
sys_fcb ENDS
FILDIRENT = fcb_FILSIZ ; Used only by SEARCH FIRST and
; SEARCH NEXT
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
devid_file_clean EQU 40h ; true if file and not written
devid_file_mask_drive EQU 3Fh ; mask for drive number
devid_device EQU 80h ; true if a device
devid_device_EOF EQU 40h ; true if end of file reached
devid_device_raw EQU 20h ; true if in raw mode
devid_device_special EQU 10h ; true if special device
devid_device_clock EQU 08h ; true if clock device
devid_device_null EQU 04h ; true if null device
devid_device_con_out EQU 02h ; true if console output
devid_device_con_in EQU 01h ; true if consle input
;
; structure of devid field as returned by IOCTL is:
;
; BIT 7 6 5 4 3 2 1 0
; |---|---|---|---|---|---|---|---|
; | I | E | R | S | I | I | I | I |
; | S | O | A | P | S | S | S | S |
; | D | F | W | E | C | N | C | C |
; | E | | | C | L | U | O | I |
; | V | | | L | K | L | T | N |
; |---|---|---|---|---|---|---|---|
; ISDEV = 1 if this channel is a device
; = 0 if this channel is a disk file
;
; If ISDEV = 1
;
; EOF = 0 if End Of File on input
; RAW = 1 if this device is in Raw mode
; = 0 if this device is cooked
; ISCLK = 1 if this device is the clock device
; ISNUL = 1 if this device is the null device
; ISCOT = 1 if this device is the console output
; ISCIN = 1 if this device is the console input
;
; If ISDEV = 0
; EOF = 0 if channel has been written
; Bits 0-5 are the block device number for
; the channel (0 = A, 1 = B, ...)
;
devid_ISDEV EQU 80h
devid_EOF EQU 40h
devid_RAW EQU 20h
devid_SPECIAL EQU 10H
devid_ISCLK EQU 08h
devid_ISNUL EQU 04h
devid_ISCOT EQU 02h
devid_ISCIN EQU 01h
devid_block_dev EQU 1Fh ; mask for block device number
;
; find first/next buffer
;
find_buf STRUC
find_buf_sattr DB ? ; attribute of search
find_buf_drive DB ? ; drive of search
find_buf_name DB 11 DUP (?) ; formatted name
find_buf_LastEnt DW ? ; LastEnt
find_buf_ThisDPB DD ? ; This DPB
find_buf_DirStart DW ? ; DirStart
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
find_buf_attr DB ? ; attribute found
find_buf_time DW ? ; time
find_buf_date DW ? ; date
find_buf_size_l DW ? ; low(size)
find_buf_size_h DW ? ; high(size)
find_buf_pname DB 13 DUP (?) ; packed name
find_buf ENDS
BREAK <Process data block>
;
; Process data block (otherwise known as program header)
;
FilPerProc EQU 20
Process_data_block STRUC
PDB_Exit_Call DW ? ; INT int_abort system terminate
PDB_block_len DW ? ; size of execution block
DB ?
PDB_CPM_Call DB 5 DUP (?) ; ancient call to system
PDB_Exit DD ? ; pointer to exit routine
PDB_Ctrl_C DD ? ; pointer to ^C routine
PDB_Fatal_abort DD ? ; pointer to fatal error
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
PDB_Parent_PID DW ? ; PID of parent (terminate PID)
PDB_JFN_Table DB FilPerProc DUP (?)
; indices into system table
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
PDB_environ DW ? ; seg addr of environment
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
PDB_User_stack DD ? ; stack of self during system calls
PDB_PAD1 DB 1Eh DUP (?)
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
PDB_Call_system DB 5 DUP (?) ; portable method of system call
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
PDB_PAD2 DB 6h DUP (?) ;
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
Process_data_block ENDS
BREAK <EXEC and EXE file structures>
;
; EXEC arg block - load/go program
;
;
; The following get used as arguments to the EXEC system call. They indicate
; whether or not the program is executed or whether or not a program header
; gets created.
;
exec_func_no_execute EQU 1 ; no execute bit
exec_func_overlay EQU 2 ; overlay bit
Exec0 STRUC
Exec0_environ DW ? ; seg addr of environment
Exec0_com_line DD ? ; pointer to asciz command line
Exec0_5C_FCB DD ? ; default fcb at 5C
Exec0_6C_FCB DD ? ; default fcb at 6C
Exec0 ENDS
Exec1 STRUC
Exec1_environ DW ? ; seg addr of environment
Exec1_com_line DD ? ; pointer to asciz command line
Exec1_5C_FCB DD ? ; default fcb at 5C
Exec1_6C_FCB DD ? ; default fcb at 6C
Exec1_SP DW ? ; stack pointer of program
Exec1_SS DW ? ; stack seg register of program
Exec1_IP DW ? ; entry point IP
Exec1_CS DW ? ; entry point CS
Exec1 ENDS
Exec3 STRUC
Exec3_load_addr DW ? ; seg address of load point
Exec3_reloc_fac DW ? ; relocation factor
Exec3 ENDS
;
; Exit codes in upper byte
;
Exit_terminate EQU 0
Exit_abort EQU 0
Exit_Ctrl_C EQU 1
Exit_Hard_Error EQU 2
Exit_Keep_process EQU 3
;
; EXE file header
;
EXE_file STRUC
exe_signature DW ? ; must contain 4D5A (yay zibo!)
exe_len_mod_512 DW ? ; low 9 bits of length
exe_pages DW ? ; number of 512b pages in file
exe_rle_count DW ? ; count of reloc entries
exe_par_dir DW ? ; number of paragraphs before image
exe_min_BSS DW ? ; minimum number of para of BSS
exe_max_BSS DW ? ; max number of para of BSS
exe_SS DW ? ; stack of image
exe_SP DW ? ; SP of image
exe_chksum DW ? ; checksum of file (ignored)
exe_IP DW ? ; IP of entry
exe_CS DW ? ; CS of entry
exe_rle_table DW ? ; byte offset of reloc table
exe_iov DW ? ; overlay number (0 for root)
exe_sym_tab DD ? ; offset of symbol table in file
EXE_file ENDS
exe_valid_signature EQU 5A4Dh
exe_valid_old_signature EQU 4D5Ah
symbol_entry STRUC
sym_value DD ?
sym_type DW ?
sym_len DB ?
sym_name DB 255 dup (?)
symbol_entry ENDS
BREAK <Internal system file table format>
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
;
; system file table
;
sft STRUC
sft_link DD ?
sft_count DW ? ; number of entries
sft_table DW ? ; beginning of array of the following
sft ENDS
;
; system file table entry
;
sf_entry STRUC
sf_ref_count DB ? ; number of processes sharing fcb
sf_mode DB ? ; mode of access
sf_attr DB ? ; attribute of file
sf_fcb DB (SIZE sys_fcb) DUP (?)
; actual FCB
sf_entry ENDS
sf_default_number EQU 5h
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
BREAK <Memory arena structure>
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
;
; arena item
;
arena STRUC
arena_signature DB ? ; 4D for valid item, 5A for last item
arena_owner DW ? ; owner of arena item
arena_size DW ? ; size in paragraphs of item
arena ENDS
arena_owner_system EQU 0 ; free block indication
arena_signature_normal EQU 4Dh ; valid signature, not end of arena
arena_signature_end EQU 5Ah ; valid signature, last block in arena
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
BREAK <Machine instruction definitions>
mi_INT EQU 0CDh
mi_Long_JMP EQU 0EAh
mi_Long_CALL EQU 09Ah
mi_Long_RET EQU 0CBh
BREAK <Standard I/O assignments>
stdin EQU 0
stdout EQU 1
stderr EQU 2
stdaux EQU 3
stdprn EQU 4
BREAK <Xenix subfunction assignments>
open_for_read EQU 0
open_for_write EQU 1
open_for_both EQU 2
BREAK <Xenix error codes>
;
; XENIX calls all return error codes through AX. If an error occurred then the
; carry bit will be set and the error code is in AX. If no error occurred then
; the carry bit is reset and AX contains returned info.
;
no_error_occurred EQU 0 ?
error_invalid_function EQU 1
error_file_not_found EQU 2
error_path_not_found EQU 3
error_too_many_open_files EQU 4
error_access_denied EQU 5
error_invalid_handle EQU 6
error_arena_trashed EQU 7
error_not_enough_memory EQU 8
error_invalid_block EQU 9
error_bad_environment EQU 10
error_bad_format EQU 11
error_invalid_access EQU 12
error_invalid_data EQU 13
;**** unused EQU 14
error_invalid_drive EQU 15
error_current_directory EQU 16
error_not_same_device EQU 17
error_no_more_files EQU 18
alloc_not_enough_memory EQU error_not_enough_memory
alloc_arena_trashed EQU error_arena_trashed
close_invalid_handle EQU error_invalid_handle
close_invalid_function EQU error_invalid_function
chdir_path_not_found EQU error_path_not_found
chmod_path_not_found EQU error_path_not_found
chmod_access_denied EQU error_access_denied
chmod_invalid_function EQU error_invalid_function
creat_access_denied EQU error_access_denied
creat_path_not_found EQU error_path_not_found
creat_too_many_open_files EQU error_too_many_open_files
curdir_invalid_drive EQU error_invalid_drive
dealloc_invalid_block EQU error_invalid_block
dealloc_arena_trashed EQU error_arena_trashed
dup_invalid_handle EQU error_invalid_handle
dup_too_many_open_files EQU error_too_many_open_files
dup2_invalid_handle EQU error_invalid_handle
exec_invalid_function EQU error_invalid_function
exec_bad_environment EQU error_bad_environment
exec_bad_format EQU error_bad_format
exec_not_enough_memory EQU error_not_enough_memory
exec_file_not_found EQU error_file_not_found
filetimes_invalid_function EQU error_invalid_function
filetimes_invalid_handle EQU error_invalid_handle
findfirst_file_not_found EQU error_file_not_found
findfirst_no_more_files EQU error_no_more_files
findnext_no_more_files EQU error_no_more_files
international_invalid_function EQU error_invalid_function
ioctl_invalid_handle EQU error_invalid_handle
ioctl_invalid_function EQU error_invalid_function
ioctl_invalid_data EQU error_invalid_data
lseek_invalid_handle EQU error_invalid_handle
lseek_invalid_function EQU error_invalid_function
mkdir_path_not_found EQU error_path_not_found
mkdir_access_denied EQU error_access_denied
open_invalid_access EQU error_invalid_access
open_file_not_found EQU error_file_not_found
open_access_denied EQU error_access_denied
open_too_many_open_files EQU error_too_many_open_files
read_invalid_handle EQU error_invalid_handle
read_access_denied EQU error_access_denied
rename_file_not_found EQU error_file_not_found
rename_not_same_device EQU error_not_same_device
rename_access_denied EQU error_access_denied
rmdir_path_not_found EQU error_path_not_found
rmdir_access_denied EQU error_access_denied
rmdir_current_directory EQU error_current_directory
setblock_invalid_block EQU error_invalid_block
setblock_arena_trashed EQU error_arena_trashed
setblock_not_enough_memory EQU error_not_enough_memory
setblock_invalid_function EQU error_invalid_function
unlink_file_not_found EQU error_file_not_found
unlink_access_denied EQU error_access_denied
write_invalid_handle EQU error_invalid_handle
write_access_denied EQU error_access_denied
BREAK <system call definitions>
ABORT EQU 0 ; 0 0
STD_CON_INPUT EQU 1 ; 1 1
STD_CON_OUTPUT EQU 2 ; 2 2
STD_AUX_INPUT EQU 3 ; 3 3
STD_AUX_OUTPUT EQU 4 ; 4 4
STD_PRINTER_OUTPUT EQU 5 ; 5 5
RAW_CON_IO EQU 6 ; 6 6
RAW_CON_INPUT EQU 7 ; 7 7
STD_CON_INPUT_NO_ECHO EQU 8 ; 8 8
STD_CON_STRING_OUTPUT EQU 9 ; 9 9
STD_CON_STRING_INPUT EQU 10 ; 10 A
STD_CON_INPUT_STATUS EQU 11 ; 11 B
STD_CON_INPUT_FLUSH EQU 12 ; 12 C
DISK_RESET EQU 13 ; 13 D
SET_DEFAULT_DRIVE EQU 14 ; 14 E
FCB_OPEN EQU 15 ; 15 F
FCB_CLOSE EQU 16 ; 16 10
DIR_SEARCH_FIRST EQU 17 ; 17 11
DIR_SEARCH_NEXT EQU 18 ; 18 12
FCB_DELETE EQU 19 ; 19 13
FCB_SEQ_READ EQU 20 ; 20 14
FCB_SEQ_WRITE EQU 21 ; 21 15
FCB_CREATE EQU 22 ; 22 16
FCB_RENAME EQU 23 ; 23 17
GET_DEFAULT_DRIVE EQU 25 ; 25 19
SET_DMA EQU 26 ; 26 1A
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
GET_DEFAULT_DPB EQU 31 ; 31 1F
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
FCB_RANDOM_READ EQU 33 ; 33 21
FCB_RANDOM_WRITE EQU 34 ; 34 22
GET_FCB_FILE_LENGTH EQU 35 ; 35 23
GET_FCB_POSITION EQU 36 ; 36 24
SET_INTERRUPT_VECTOR EQU 37 ; 37 25
CREATE_PROCESS_DATA_BLOCK EQU 38 ; 38 26
FCB_RANDOM_READ_BLOCK EQU 39 ; 39 27
FCB_RANDOM_WRITE_BLOCK EQU 40 ; 40 28
PARSE_FILE_DESCRIPTOR EQU 41 ; 41 29
GET_DATE EQU 42 ; 42 2A
SET_DATE EQU 43 ; 43 2B
GET_TIME EQU 44 ; 44 2C
SET_TIME EQU 45 ; 45 2D
SET_VERIFY_ON_WRITE EQU 46 ; 46 2E
; Extended functionality group
GET_DMA EQU 47 ; 47 2F
GET_VERSION EQU 48 ; 48 30
KEEP_PROCESS EQU 49 ; 49 31
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
GET_DPB EQU 50 ; 50 32
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
SET_CTRL_C_TRAPPING EQU 51 ; 51 33
GET_INDOS_FLAG EQU 52 ; 52 34
GET_INTERRUPT_VECTOR EQU 53 ; 53 35
GET_DRIVE_FREESPACE EQU 54 ; 54 36
CHAR_OPER EQU 55 ; 55 37
INTERNATIONAL EQU 56 ; 56 38
; XENIX CALLS
; Directory Group
MKDIR EQU 57 ; 57 39
RMDIR EQU 58 ; 58 3A
CHDIR EQU 59 ; 59 3B
; File Group
CREAT EQU 60 ; 60 3C
OPEN EQU 61 ; 61 3D
CLOSE EQU 62 ; 62 3E
READ EQU 63 ; 63 3F
WRITE EQU 64 ; 64 40
UNLINK EQU 65 ; 65 41
LSEEK EQU 66 ; 66 42
CHMOD EQU 67 ; 67 43
IOCTL EQU 68 ; 68 44
XDUP EQU 69 ; 69 45
XDUP2 EQU 70 ; 70 46
CURRENT_DIR EQU 71 ; 71 47
; Memory Group
ALLOC EQU 72 ; 72 48
DEALLOC EQU 73 ; 73 49
SETBLOCK EQU 74 ; 74 4A
; Process Group
EXEC EQU 75 ; 75 4B
EXIT EQU 76 ; 76 4C
WAIT EQU 77 ; 77 4D
FIND_FIRST EQU 78 ; 78 4E
; Special Group
FIND_NEXT EQU 79 ; 79 4F
; SPECIAL SYSTEM GROUP
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
SET_CURRENT_PDB EQU 80 ; 80 50
GET_CURRENT_PDB EQU 81 ; 81 51
GET_IN_VARS EQU 82 ; 82 52
SETDPB EQU 83 ; 83 53
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
GET_VERIFY_ON_WRITE EQU 84 ; 84 54
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
DUP_PDB EQU 85 ; 85 55
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
RENAME EQU 86 ; 86 56
FILE_TIMES EQU 87 ; 87 57
SET_OEM_HANDLER EQU 248 ; 248 F8
OEM_C1 EQU 249 ; 249 F9
OEM_C2 EQU 250 ; 250 FA
OEM_C3 EQU 251 ; 251 FB
OEM_C4 EQU 252 ; 252 FC
OEM_C5 EQU 253 ; 253 FD
OEM_C6 EQU 254 ; 254 FE
OEM_C7 EQU 255 ; 255 FF
SUBTTL

963
v2.0/source/DOSSYM_v211.ASM Normal file
View File

@ -0,0 +1,963 @@
include DOSMAC.ASM
IF2
%OUT DOSSYM in Pass 2
ENDIF
IFNDEF ALTVECT
ALTVECT EQU 0 ;FALSE
ENDIF
DOS_MAJOR_VERSION EQU 2
DOS_MINOR_VERSION EQU 11
BREAK <Control character definitions>
c_DEL EQU 7Fh ; ASCII rubout or delete previous char
c_BS EQU 08h ; ^H ASCII backspace
c_CR EQU 0Dh ; ^M ASCII carriage return
c_LF EQU 0Ah ; ^J ASCII linefeed
c_ETB EQU 17h ; ^W ASCII end of transmission
c_NAK EQU 15h ; ^U ASCII negative acknowledge
c_ETX EQU 03h ; ^C ASCII end of text
c_HT EQU 09h ; ^I ASCII tab
BREAK <BPB Definition>
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; ;
; C A V E A T P R O G R A M M E R ;
; ;
; Certain structures, constants and system calls below are private to ;
; the DOS and are extremely version-dependent. They may change at any ;
; time at the implementors' whim. As a result, they must not be ;
; documented to the general public. If an extreme case arises, they ;
; must be documented with this warning. ;
; ;
; Those structures and constants that are subject to the above will be ;
; marked and bracketed with the flag: ;
; ;
; C A V E A T P R O G R A M M E R ;
; ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
BREAK <Bios Parameter Block>
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
; Bios Parameter Block definition
; This structure is used to build a full DPB
BPBLOCK STRUC
BPSECSZ DW ? ; Size in bytes of physical sector
BPCLUS DB ? ; Sectors/Alloc unit
BPRES DW ? ; Number of reserved sectors
BPFTCNT DB ? ; Number of FATs
BPDRCNT DW ? ; Number of directory entries
BPSCCNT DW ? ; Total number of sectors
BPMEDIA DB ? ; Media descriptor byte
BPFTSEC DW ? ; Number of sectors taken up by one FAT
BPBLOCK ENDS
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
BREAK <Disk I/O Buffer Header>
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
; Field definition for I/O buffer information
BUFFINFO STRUC
NEXTBUF DD ? ; Pointer to next buffer in list
; The next two items are often refed as a word
BUFDRV DB ? ; Logical drive # assoc with buffer FF = free
BUFDIRTY DB ? ; Dirty flag
BUFPRI DB ? ; Buffer selection priority (see EQUs below)
VISIT DB ? ; Visit flag for buffer pool scans
BUFSECNO DW ? ; Sector number of buffer
; The next two items are often refed as a word
BUFWRTCNT DB ? ; For FAT sectors, # times sector written out
BUFWRTINC DB ? ; " " " , # sectors between each write
BUFDRVDP DD ? ; Pointer to drive parameters
BUFFINFO ENDS
BUFINSIZ EQU SIZE BUFFINFO
; Size of structure in bytes
FREEPRI EQU 0
LBRPRI EQU 2 ; Last byte of buffer read
LBWPRI EQU 4 ; Last byte written
RPRI EQU 6 ; Read but not last byte
WPRI EQU 8 ; Written but not last byte
DIRPRI EQU 15 ; Directory Sector
FATPRI EQU 30 ; FAT sector
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
BREAK <User stack inside of system call>
; Location of user registers relative user stack pointer
user_environ STRUC
user_AX DW ?
user_BX DW ?
user_CX DW ?
user_DX DW ?
user_SI DW ?
user_DI DW ?
user_BP DW ?
user_DS DW ?
user_ES DW ?
user_IP DW ?
user_CS DW ?
user_F DW ?
user_environ ENDS
BREAK <interrupt definitions>
INTTAB EQU 20H
INTBASE EQU 4 * inttab
ENTRYPOINT EQU INTBASE+40H
IF ALTVECT
ALTTAB EQU 0F0H
ALTBASE EQU 4 * ALTTAB
ENDIF
;
; interrupt assignments
;
IF NOT ALTVECT
int_abort EQU INTTAB ; abort process
int_command EQU int_abort+1 ; call MSDOS
int_terminate EQU int_abort+2 ; int to terminate address
int_ctrl_c EQU int_abort+3 ; ^c trapper
int_fatal_abort EQU int_abort+4 ; hard disk error
int_disk_read EQU int_abort+5 ; logical sector disk read
int_disk_write EQU int_abort+6 ; logical sector disk write
int_keep_process EQU int_abort+7 ; terminate program and stay
; resident
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
int_spooler EQU int_abort+8 ; spooler call
int_fastcon EQU int_abort+9 ; fast CON interrupt
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
ELSE
int_abort EQU INTTAB ; abort process
int_command EQU int_abort+1 ; call MSDOS
int_terminate EQU ALTTAB ; int to terminate address
int_ctrl_c EQU int_terminate+1 ; ^c trapper
int_fatal_abort EQU int_terminate+2 ; hard disk error
int_disk_read EQU int_abort+5 ; logical sector disk read
int_disk_write EQU int_abort+6 ; logical sector disk write
int_keep_process EQU int_abort+7 ; terminate program and stay
; resident
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
int_spooler EQU int_terminate+3 ; spooler call
int_fastcon EQU int_abort+9 ; fast CON interrupt
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
ENDIF
addr_int_abort EQU 4 * int_abort
addr_int_command EQU 4 * int_command
addr_int_terminate EQU 4 * int_terminate
addr_int_ctrl_c EQU 4 * int_ctrl_c
addr_int_fatal_abort EQU 4 * int_fatal_abort
addr_int_disk_read EQU 4 * int_disk_read
addr_int_disk_write EQU 4 * int_disk_write
addr_int_keep_process EQU 4 * int_keep_process
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
addr_int_spooler EQU 4 * int_spooler
addr_int_fastcon EQU 4 * int_fastcon
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
BREAK <Disk map>
; MSDOS partitions the disk into 4 sections:
;
; phys sector 0: +-------------------+
; | | boot/reserved |
; | +-------------------+
; | | File allocation |
; v | table(s) |
; | (multiple copies |
; | are kept) |
; +-------------------+
; | Directory |
; +-------------------+
; | File space |
; +-------------------+
; | Unaddressable |
; | (to end of disk) |
; +-------------------+
;
; All partition boundaries are sector boundaries. The size of the FAT is
; adjusted to maximize the file space addressable.
BREAK <Directory entry>
;
; +---------------------------+
; | (12 BYTE) filename/ext | 0 0
; +---------------------------+
; | (BYTE) attributes | 11 B
; +---------------------------+
; | (10 BYTE) reserved | 12 C
; +---------------------------+
; | (WORD) time of last write | 22 16
; +---------------------------+
; | (WORD) date of last write | 24 18
; +---------------------------+
; | (WORD) First cluster | 26 1A
; +---------------------------+
; | (DWORD) file size | 28 1C
; +---------------------------+
;
; First byte of filename = E5 -> free directory entry
; = 00 -> end of allocated directory
; Time: Bits 0-4=seconds/2, bits 5-10=minute, 11-15=hour
; Date: Bits 0-4=day, bits 5-8=month, bits 9-15=year-1980
;
dir_entry STRUC
dir_name DB 11 DUP (?) ; file name
dir_attr DB ? ; attribute bits
dir_pad DB 10 DUP (?) ; reserved for expansion
dir_time DW ? ; time of last write
dir_date DW ? ; date of last write
dir_first DW ? ; first allocation unit of file
dir_size_l DW ? ; low 16 bits of file size
dir_size_h DW ? ; high 16 bits of file size
dir_entry ENDS
attr_read_only EQU 1h
attr_hidden EQU 2h
attr_system EQU 4h
attr_volume_id EQU 8h
attr_directory EQU 10h
attr_archive EQU 20h
attr_all EQU attr_hidden+attr_system+attr_directory
; OR of hard attributes for FINDENTRY
attr_ignore EQU attr_read_only+attr_archive
; ignore this(ese) attribute(s) during
; search first/next
attr_changeable EQU attr_read_only+attr_hidden+attr_system+attr_archive
; changeable via CHMOD
BREAK <File allocation Table information>
;
; The File Allocation Table uses a 12-bit entry for each allocation unit on
; the disk. These entries are packed, two for every three bytes. The contents
; of entry number N is found by 1) multiplying N by 1.5; 2) adding the result
; to the base address of the Allocation Table; 3) fetching the 16-bit word
; at this address; 4) If N was odd (so that N*1.5 was not an integer), shift
; the word right four bits; 5) mask to 12 bits (AND with 0FFF hex). Entry
; number zero is used as an end-of-file trap in the OS and is passed to the
; BIOS to help determine disk format. Entry 1 is reserved for future use.
; The first available allocation unit is assigned entry number two, and even
; though it is the first, is called cluster 2. Entries greater than 0FF8H
; are end of file marks; entries of zero are unallocated. Otherwise, the
; contents of a FAT entry is the number of the next cluster in the file.
;
; Clusters with bad sectors are tagged with FF7H. Any non-zero number would
; do because these clusters show as allocated, but are not part of any
; allocation chain and thus will never be allocated to a file. A particular
; number is selected so that disk checking programs know what to do (ie. a
; cluster with entry FF7H which is not in a chain is not an error).
BREAK <DPB structure>
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
DIRSTRLEN EQU 64 ; Max length in bytes of directory strings
dpb STRUC
dpb_drive DB ? ; Logical drive # assoc with DPB (A=0,B=1,...)
dpb_UNIT DB ? ; Driver unit number of DPB
dpb_sector_size DW ? ; Size of physical sector in bytes
dpb_cluster_mask DB ? ; Sectors/cluster - 1
dpb_cluster_shift DB ? ; Log2 of sectors/cluster
dpb_first_FAT DW ? ; Starting record of FATs
dpb_FAT_count DB ? ; Number of FATs for this drive
dpb_root_entries DW ? ; Number of directory entries
dpb_first_sector DW ? ; First sector of first cluster
dpb_max_cluster DW ? ; Number of clusters on drive + 1
dpb_FAT_size DB ? ; Number of records occupied by FAT
dpb_dir_sector DW ? ; Starting record of directory
dpb_driver_addr DD ? ; Pointer to driver
dpb_media DB ? ; Media byte
dpb_first_access DB ? ; This is initialized to -1 to force a media
; check the first time this DPB is used
dpb_next_dpb DD ? ; Pointer to next Drive parameter block
dpb_current_dir DW ? ; Cluster number of start of current directory
; 0 indicates root, -1 indicates invalid (disk
; ? changed)
dpb_dir_text DB DIRSTRLEN DUP(?)
; ASCIZ string of current directory
dpb ENDS
DPBSIZ EQU SIZE dpb ; Size of the structure in bytes
DSKSIZ = dpb_max_cluster ; Size of disk (temp used during init only)
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
BREAK <File Control Block definition>
;
; Field definition for FCBs
; The FCB has the following structure:
;
; +---------------------------+
; | Drive indicator(byte) |
; +---------------------------+
; | Filename (8 chars) |
; +---------------------------+
; | Extension (3 chars) |
; +---------------------------+
; | Current Extent(word) |
; +---------------------------+
; | Record size (word) |
; +---------------------------+
; | File Size (2 words) |
; +---------------------------+
; | Date of write |
; +---------------------------+
; | Time of write |
; +---------------------------+
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
; | Flags: |
; | bit 7=0 file/1 device |
; | bit 6=0 if dirty |
; | bits 0-5 deviceid |
; +---------------------------+
; | first cluster in file |
; +---------------------------+
; | position of last cluster |
; +---------------------------+
; | last cluster accessed | 12 bit-+--- packed in 3 bytes
; +---------------------------+ |
; | parent directory | <------+
; +---------------------------+
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; | next record number |
; +---------------------------+
; | random record number |
; +---------------------------+
;
sys_fcb STRUC
fcb_drive DB ?
fcb_name DB 8 DUP (?)
fcb_ext DB 3 DUP (?)
fcb_EXTENT DW ?
fcb_RECSIZ DW ? ; Size of record (user settable)
fcb_FILSIZ DW ? ; Size of file in bytes; used with the following
; word
fcb_DRVBP DW ? ; BP for SEARCH FIRST and SEARCH NEXT
fcb_FDATE DW ? ; Date of last writing
fcb_FTIME DW ? ; Time of last writing
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
fcb_DEVID DB ? ; Device ID number, bits 0-5 if file.
; bit 7=0 for file, bit 7=1 for I/O device
; If file, bit 6=0 if dirty
; If I/O device, bit 6=0 if EOF (input)
; Bit 5=1 if Raw mode
; Bit 0=1 if console input device
; Bit 1=1 if console output device
; Bit 2=1 if null device
; Bit 3=1 if clock device
fcb_FIRCLUS DW ? ; First cluster of file
fcb_CLUSPOS DW ? ; Position of last cluster accessed
fcb_LSTCLUS DW ? ; Last cluster accessed and directory pack 2 12
DB ? ; bit numbers into 24 bits...
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
fcb_NR DB ? ; Next record
fcb_RR DB 4 DUP (?) ; Random record
sys_fcb ENDS
FILDIRENT = fcb_FILSIZ ; Used only by SEARCH FIRST and SEARCH
; NEXT
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
devid_file_clean EQU 40h ; true if file and not written
devid_file_mask_drive EQU 3Fh ; mask for drive number
devid_device EQU 80h ; true if a device
devid_device_EOF EQU 40h ; true if end of file reached
devid_device_raw EQU 20h ; true if in raw mode
devid_device_special EQU 10h ; true if special device
devid_device_clock EQU 08h ; true if clock device
devid_device_null EQU 04h ; true if null device
devid_device_con_out EQU 02h ; true if console output
devid_device_con_in EQU 01h ; true if consle input
;
; structure of devid field as returned by IOCTL is:
;
; BIT 7 6 5 4 3 2 1 0
; |---|---|---|---|---|---|---|---|
; | I | E | R | S | I | I | I | I |
; | S | O | A | P | S | S | S | S |
; | D | F | W | E | C | N | C | C |
; | E | | | C | L | U | O | I |
; | V | | | L | K | L | T | N |
; |---|---|---|---|---|---|---|---|
; ISDEV = 1 if this channel is a device
; = 0 if this channel is a disk file
;
; If ISDEV = 1
;
; EOF = 0 if End Of File on input
; RAW = 1 if this device is in Raw mode
; = 0 if this device is cooked
; ISCLK = 1 if this device is the clock device
; ISNUL = 1 if this device is the null device
; ISCOT = 1 if this device is the console output
; ISCIN = 1 if this device is the console input
;
; If ISDEV = 0
; EOF = 0 if channel has been written
; Bits 0-5 are the block device number for
; the channel (0 = A, 1 = B, ...)
;
devid_ISDEV EQU 80h
devid_EOF EQU 40h
devid_RAW EQU 20h
devid_SPECIAL EQU 10H
devid_ISCLK EQU 08h
devid_ISNUL EQU 04h
devid_ISCOT EQU 02h
devid_ISCIN EQU 01h
devid_block_dev EQU 1Fh ; mask for block device number
;
; find first/next buffer
;
find_buf STRUC
find_buf_sattr DB ? ; attribute of search
find_buf_drive DB ? ; drive of search
find_buf_name DB 11 DUP (?) ; formatted name
find_buf_LastEnt DW ? ; LastEnt
find_buf_ThisDPB DD ? ; This DPB
find_buf_DirStart DW ? ; DirStart
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
find_buf_attr DB ? ; attribute found
find_buf_time DW ? ; time
find_buf_date DW ? ; date
find_buf_size_l DW ? ; low(size)
find_buf_size_h DW ? ; high(size)
find_buf_pname DB 13 DUP (?) ; packed name
find_buf ENDS
BREAK <Process data block>
;
; Process data block (otherwise known as program header)
;
FilPerProc EQU 20
Process_data_block STRUC
PDB_Exit_Call DW ? ; INT int_abort system terminate
PDB_block_len DW ? ; size of execution block
DB ?
PDB_CPM_Call DB 5 DUP (?) ; ancient call to system
PDB_Exit DD ? ; pointer to exit routine
PDB_Ctrl_C DD ? ; pointer to ^C routine
PDB_Fatal_abort DD ? ; pointer to fatal error
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
PDB_Parent_PID DW ? ; PID of parent (terminate PID)
PDB_JFN_Table DB FilPerProc DUP (?)
; indices into system table
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
PDB_environ DW ? ; seg addr of environment
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
PDB_User_stack DD ? ; stack of self during system calls
PDB_PAD1 DB 1Eh DUP (?)
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
PDB_Call_system DB 5 DUP (?) ; portable method of system call
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
PDB_PAD2 DB 6h DUP (?) ;
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
Process_data_block ENDS
BREAK <EXEC and EXE file structures>
;
; EXEC arg block - load/go program
;
;
; The following get used as arguments to the EXEC system call. They indicate
; whether or not the program is executed or whether or not a program header
; gets created.
;
exec_func_no_execute EQU 1 ; no execute bit
exec_func_overlay EQU 2 ; overlay bit
Exec0 STRUC
Exec0_environ DW ? ; seg addr of environment
Exec0_com_line DD ? ; pointer to asciz command line
Exec0_5C_FCB DD ? ; default fcb at 5C
Exec0_6C_FCB DD ? ; default fcb at 6C
Exec0 ENDS
Exec1 STRUC
Exec1_environ DW ? ; seg addr of environment
Exec1_com_line DD ? ; pointer to asciz command line
Exec1_5C_FCB DD ? ; default fcb at 5C
Exec1_6C_FCB DD ? ; default fcb at 6C
Exec1_SP DW ? ; stack pointer of program
Exec1_SS DW ? ; stack seg register of program
Exec1_IP DW ? ; entry point IP
Exec1_CS DW ? ; entry point CS
Exec1 ENDS
Exec3 STRUC
Exec3_load_addr DW ? ; seg address of load point
Exec3_reloc_fac DW ? ; relocation factor
Exec3 ENDS
;
; Exit codes in upper byte
;
Exit_terminate EQU 0
Exit_abort EQU 0
Exit_Ctrl_C EQU 1
Exit_Hard_Error EQU 2
Exit_Keep_process EQU 3
;
; EXE file header
;
EXE_file STRUC
exe_signature DW ? ; must contain 4D5A (yay zibo!)
exe_len_mod_512 DW ? ; low 9 bits of length
exe_pages DW ? ; number of 512b pages in file
exe_rle_count DW ? ; count of reloc entries
exe_par_dir DW ? ; number of paragraphs before image
exe_min_BSS DW ? ; minimum number of para of BSS
exe_max_BSS DW ? ; max number of para of BSS
exe_SS DW ? ; stack of image
exe_SP DW ? ; SP of image
exe_chksum DW ? ; checksum of file (ignored)
exe_IP DW ? ; IP of entry
exe_CS DW ? ; CS of entry
exe_rle_table DW ? ; byte offset of reloc table
exe_iov DW ? ; overlay number (0 for root)
exe_sym_tab DD ? ; offset of symbol table in file
EXE_file ENDS
exe_valid_signature EQU 5A4Dh
exe_valid_old_signature EQU 4D5Ah
symbol_entry STRUC
sym_value DD ?
sym_type DW ?
sym_len DB ?
sym_name DB 255 dup (?)
symbol_entry ENDS
BREAK <Internal system file table format>
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
;
; system file table
;
sft STRUC
sft_link DD ?
sft_count DW ? ; number of entries
sft_table DW ? ; beginning of array of the following
sft ENDS
;
; system file table entry
;
sf_entry STRUC
sf_ref_count DB ? ; number of processes sharing fcb
sf_mode DB ? ; mode of access
sf_attr DB ? ; attribute of file
sf_fcb DB (SIZE sys_fcb) DUP (?)
; actual FCB
sf_entry ENDS
sf_default_number EQU 5h
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
BREAK <Memory arena structure>
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
;
; arena item
;
arena STRUC
arena_signature DB ? ; 4D for valid item, 5A for last item
arena_owner DW ? ; owner of arena item
arena_size DW ? ; size in paragraphs of item
arena ENDS
;
; Current structure of the data returned by the international call
;
internat_block STRUC
Date_tim_format DW ? ; 0-USA, 1-EUR, 2-JAP
Currency_sym DB ? ; Currency Symbol 5 bytes
DB ?
DB ?
DB ?
DB ?
Thous_sep DB ? ; Thousands separator 2 bytes
DB ?
Decimal_sep DB ? ; Decimal separator 2 bytes
DB ?
Date_sep DB ? ; Date separator 2 bytes
DB ?
Time_sep DB ? ; Decimal separator 2 bytes
DB ?
Bit_feild DB ? ; Bit values
; Bit 0 = 0 if currency symbol first
; = 1 if currency symbol last
; Bit 1 = 0 if No space after currency symbol
; = 1 if space after currency symbol
Currency_cents DB ? ; Number of places after currency dec point
Time_24 DB ? ; 1 if 24 hour time, 0 if 12 hour time
Map_call DW ? ; Address of case mapping call (DWORD)
DW ? ; THIS IS TWO WORDS SO IT CAN BE INITIALIZED
; in pieces.
Data_sep DB ? ; Data list separator character
DB ?
internat_block ENDS
;
; Max size of the block returned by the INTERNATIONAL call
;
internat_block_max EQU 32
;
; CAUTION: The routines in ALLOC.ASM rely on the fact that arena_signature
; and arena_owner_system are all equal to zero and are contained in DI. Change
; them and change ALLOC.ASM.
arena_owner_system EQU 0 ; free block indication
arena_signature_normal EQU 4Dh ; valid signature, not end of arena
arena_signature_end EQU 5Ah ; valid signature, last block in arena
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
BREAK <Machine instruction definitions>
mi_INT EQU 0CDh
mi_Long_JMP EQU 0EAh
mi_Long_CALL EQU 09Ah
mi_Long_RET EQU 0CBh
BREAK <Standard I/O assignments>
stdin EQU 0
stdout EQU 1
stderr EQU 2
stdaux EQU 3
stdprn EQU 4
BREAK <Xenix subfunction assignments>
open_for_read EQU 0
open_for_write EQU 1
open_for_both EQU 2
BREAK <Xenix error codes>
;
; XENIX calls all return error codes through AX. If an error occurred then
; the carry bit will be set and the error code is in AX. If no error occurred
; then the carry bit is reset and AX contains returned info.
;
no_error_occurred EQU 0 ?
error_invalid_function EQU 1
error_file_not_found EQU 2
error_path_not_found EQU 3
error_too_many_open_files EQU 4
error_access_denied EQU 5
error_invalid_handle EQU 6
error_arena_trashed EQU 7
error_not_enough_memory EQU 8
error_invalid_block EQU 9
error_bad_environment EQU 10
error_bad_format EQU 11
error_invalid_access EQU 12
error_invalid_data EQU 13
;**** unused EQU 14
error_invalid_drive EQU 15
error_current_directory EQU 16
error_not_same_device EQU 17
error_no_more_files EQU 18
country_not_found EQU error_file_not_found
alloc_not_enough_memory EQU error_not_enough_memory
alloc_arena_trashed EQU error_arena_trashed
close_invalid_handle EQU error_invalid_handle
close_invalid_function EQU error_invalid_function
chdir_path_not_found EQU error_path_not_found
chmod_path_not_found EQU error_path_not_found
chmod_access_denied EQU error_access_denied
chmod_invalid_function EQU error_invalid_function
creat_access_denied EQU error_access_denied
creat_path_not_found EQU error_path_not_found
creat_too_many_open_files EQU error_too_many_open_files
curdir_invalid_drive EQU error_invalid_drive
dealloc_invalid_block EQU error_invalid_block
dealloc_arena_trashed EQU error_arena_trashed
dup_invalid_handle EQU error_invalid_handle
dup_too_many_open_files EQU error_too_many_open_files
dup2_invalid_handle EQU error_invalid_handle
exec_invalid_function EQU error_invalid_function
exec_bad_environment EQU error_bad_environment
exec_bad_format EQU error_bad_format
exec_not_enough_memory EQU error_not_enough_memory
exec_file_not_found EQU error_file_not_found
filetimes_invalid_function EQU error_invalid_function
filetimes_invalid_handle EQU error_invalid_handle
findfirst_file_not_found EQU error_file_not_found
findfirst_no_more_files EQU error_no_more_files
findnext_no_more_files EQU error_no_more_files
international_invalid_function EQU error_invalid_function
ioctl_invalid_handle EQU error_invalid_handle
ioctl_invalid_function EQU error_invalid_function
ioctl_invalid_data EQU error_invalid_data
lseek_invalid_handle EQU error_invalid_handle
lseek_invalid_function EQU error_invalid_function
mkdir_path_not_found EQU error_path_not_found
mkdir_access_denied EQU error_access_denied
open_invalid_access EQU error_invalid_access
open_file_not_found EQU error_file_not_found
open_access_denied EQU error_access_denied
open_too_many_open_files EQU error_too_many_open_files
read_invalid_handle EQU error_invalid_handle
read_access_denied EQU error_access_denied
rename_file_not_found EQU error_file_not_found
rename_not_same_device EQU error_not_same_device
rename_access_denied EQU error_access_denied
rmdir_path_not_found EQU error_path_not_found
rmdir_access_denied EQU error_access_denied
rmdir_current_directory EQU error_current_directory
setblock_invalid_block EQU error_invalid_block
setblock_arena_trashed EQU error_arena_trashed
setblock_not_enough_memory EQU error_not_enough_memory
setblock_invalid_function EQU error_invalid_function
unlink_file_not_found EQU error_file_not_found
unlink_access_denied EQU error_access_denied
write_invalid_handle EQU error_invalid_handle
write_access_denied EQU error_access_denied
BREAK <system call definitions>
Abort EQU 0 ; 0 0
Std_Con_Input EQU 1 ; 1 1
Std_Con_Output EQU 2 ; 2 2
Std_Aux_Input EQU 3 ; 3 3
Std_Aux_Output EQU 4 ; 4 4
Std_Printer_Output EQU 5 ; 5 5
Raw_Con_IO EQU 6 ; 6 6
Raw_Con_Input EQU 7 ; 7 7
Std_Con_Input_No_Echo EQU 8 ; 8 8
Std_Con_String_Output EQU 9 ; 9 9
Std_Con_String_Input EQU 10 ; 10 A
Std_Con_Input_Status EQU 11 ; 11 B
Std_Con_Input_Flush EQU 12 ; 12 C
Disk_Reset EQU 13 ; 13 D
Set_Default_Drive EQU 14 ; 14 E
FCB_Open EQU 15 ; 15 F
FCB_Close EQU 16 ; 16 10
Dir_Search_First EQU 17 ; 17 11
Dir_Search_Next EQU 18 ; 18 12
FCB_Delete EQU 19 ; 19 13
FCB_Seq_Read EQU 20 ; 20 14
FCB_Seq_Write EQU 21 ; 21 15
FCB_Create EQU 22 ; 22 16
FCB_Rename EQU 23 ; 23 17
Get_Default_Drive EQU 25 ; 25 19
Set_DMA EQU 26 ; 26 1A
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
Get_Default_DPB EQU 31 ; 31 1F
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
FCB_Random_Read EQU 33 ; 33 21
FCB_Random_Write EQU 34 ; 34 22
Get_FCB_File_Length EQU 35 ; 35 23
Get_FCB_Position EQU 36 ; 36 24
Set_Interrupt_Vector EQU 37 ; 37 25
Create_Process_Data_Block EQU 38 ; 38 26
FCB_Random_Read_Block EQU 39 ; 39 27
FCB_Random_Write_Block EQU 40 ; 40 28
Parse_File_Descriptor EQU 41 ; 41 29
Get_Date EQU 42 ; 42 2A
Set_Date EQU 43 ; 43 2B
Get_Time EQU 44 ; 44 2C
Set_Time EQU 45 ; 45 2D
Set_Verify_On_Write EQU 46 ; 46 2E
; Extended functionality group
Get_DMA EQU 47 ; 47 2F
Get_Version EQU 48 ; 48 30
Keep_Process EQU 49 ; 49 31
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
Get_DPB EQU 50 ; 50 32
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
Set_CTRL_C_Trapping EQU 51 ; 51 33
Get_InDOS_Flag EQU 52 ; 52 34
Get_Interrupt_Vector EQU 53 ; 53 35
Get_Drive_Freespace EQU 54 ; 54 36
Char_Oper EQU 55 ; 55 37
International EQU 56 ; 56 38
; Directory Group
MKDir EQU 57 ; 57 39
RMDir EQU 58 ; 58 3A
CHDir EQU 59 ; 59 3B
; File Group
Creat EQU 60 ; 60 3C
Open EQU 61 ; 61 3D
Close EQU 62 ; 62 3E
Read EQU 63 ; 63 3F
Write EQU 64 ; 64 40
Unlink EQU 65 ; 65 41
LSeek EQU 66 ; 66 42
CHMod EQU 67 ; 67 43
IOCtl EQU 68 ; 68 44
XDup EQU 69 ; 69 45
XDup2 EQU 70 ; 70 46
Current_Dir EQU 71 ; 71 47
; Memory Group
Alloc EQU 72 ; 72 48
Dealloc EQU 73 ; 73 49
Setblock EQU 74 ; 74 4A
; Process Group
Exec EQU 75 ; 75 4B
Exit EQU 76 ; 76 4C
Wait EQU 77 ; 77 4D
Find_First EQU 78 ; 78 4E
; Special Group
Find_Next EQU 79 ; 79 4F
; SPECIAL SYSTEM GROUP
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
Set_Current_PDB EQU 80 ; 80 50
Get_Current_PDB EQU 81 ; 81 51
Get_In_Vars EQU 82 ; 82 52
SetDPB EQU 83 ; 83 53
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
Get_Verify_On_Write EQU 84 ; 84 54
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
Dup_PDB EQU 85 ; 85 55
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
Rename EQU 86 ; 86 56
File_Times EQU 87 ; 87 57
AllocOper EQU 88 ; 88 58
; Network extention system calls
GetExtendedError EQU 89 ; 89 59
CreateTempFile EQU 90 ; 90 5A
CreateNewFile EQU 91 ; 91 5B
LockOper EQU 92 ; 92 5C Lock and Unlock
ServerCall EQU 93 ; 93 5D CommitAll, ServerDOSCall,
; CloseByName, CloseUser,
; CloseUserProcess,
; GetOpenFileList
UserIDOper EQU 94 ; 94 5E Get and Set
AssignOper EQU 95 ; 95 5F On, Off, Get, Set, Cancel
Set_Oem_Handler EQU 248 ; 248 F8
OEM_C1 EQU 249 ; 249 F9
OEM_C2 EQU 250 ; 250 FA
OEM_C3 EQU 251 ; 251 FB
OEM_C4 EQU 252 ; 252 FC
OEM_C5 EQU 253 ; 253 FD
OEM_C6 EQU 254 ; 254 FE
OEM_C7 EQU 255 ; 255 FF
SUBTTL

1846
v2.0/source/EDLIN.ASM Normal file

File diff suppressed because it is too large Load Diff

BIN
v2.0/source/EDLMES.ASM Normal file

Binary file not shown.

531
v2.0/source/EDLPROC.ASM Normal file
View File

@ -0,0 +1,531 @@
FALSE EQU 0
TRUE EQU NOT FALSE
KANJI EQU FALSE
roprot equ FALSE ;set to TRUE if protection to r/o files
; desired.
FCB EQU 5CH
Comand_Line_Length equ 128
quote_char equ 16h ;quote character = ^V
PAGE
.xlist
INCLUDE DOSSYM.ASM
.list
SUBTTL Contants and Data areas
PAGE
PROMPT EQU "*"
STKSIZ EQU 80H
CODE SEGMENT PUBLIC
CODE ENDS
CONST SEGMENT PUBLIC WORD
EXTRN TXT1:BYTE,TXT2:BYTE,FUDGE:BYTE,HARDCH:DWORD,USERDIR:BYTE
CONST ENDS
DATA SEGMENT PUBLIC WORD
EXTRN OLDLEN:WORD,OLDDAT:BYTE,SRCHFLG:BYTE,COMLINE:WORD
EXTRN PARAM1:WORD,PARAM2:WORD,NEWLEN:WORD,SRCHMOD:BYTE
EXTRN CURRENT:WORD,POINTER:WORD,START:BYTE,ENDTXT:WORD
EXTRN USER_DRIVE:BYTE,LSTNUM:WORD,NUMPOS:WORD,LSTFND:WORD
EXTRN SRCHCNT:WORD
DATA ENDS
DG GROUP CODE,CONST,DATA
CODE SEGMENT PUBLIC
ASSUME CS:DG,DS:DG,SS:DG,ES:DG
PUBLIC REST_DIR,KILL_BL,INT_24,SCANLN,FINDLIN,SHOWNUM
PUBLIC FNDFIRST,FNDNEXT,CRLF,LF,OUT,UNQUOTE
if kanji
PUBLIC TESTKANJ
endif
EXTRN CHKRANGE:NEAR
EDLPROC:
RET1: RET
FNDFIRST:
MOV DI,1+OFFSET DG:TXT1
mov byte ptr[olddat],1 ;replace with old value if none new
CALL GETTEXT
OR AL,AL ;Reset zero flag in case CX is zero
JCXZ RET1
cmp al,1ah ;terminated with a ^Z ?
jne sj8
mov byte ptr[olddat],0 ;do not replace with old value
sj8:
MOV [OLDLEN],CX
XOR CX,CX
CMP AL,0DH
JZ SETBUF
CMP BYTE PTR [SRCHFLG],0
JZ NXTBUF
SETBUF:
DEC SI
NXTBUF:
MOV [COMLINE],SI
MOV DI,1+OFFSET DG:TXT2
CALL GETTEXT
CMP BYTE PTR [SRCHFLG],0
JNZ NOTREPL
CMP AL,0DH
JNZ HAVCHR
DEC SI
HAVCHR:
MOV [COMLINE],SI
NOTREPL:
MOV [NEWLEN],CX
MOV BX,[PARAM1]
OR BX,BX
JNZ CALLER
cmp byte ptr[srchmod],0
jne sj9
mov bx,1 ;start from line number 1
jmp short sj9a
sj9:
MOV BX,[CURRENT]
INC BX ;Default search and replace to current+1
sj9a:
CALL CHKRANGE
CALLER:
CALL FINDLIN
MOV [LSTFND],DI
MOV [NUMPOS],DI
MOV [LSTNUM],DX
MOV BX,[PARAM2]
CMP BX,1
SBB BX,-1 ;Decrement everything except zero
CALL FINDLIN
MOV CX,DI
SUB CX,[LSTFND]
OR AL,-1
JCXZ aret
CMP CX,[OLDLEN]
jae sj10
aret: ret
sj10:
MOV [SRCHCNT],CX
FNDNEXT:
; Inputs:
; [TXT1+1] has string to search for
; [OLDLEN] has length of the string
; [LSTFND] has starting position of search in text buffer
; [LSTNUM] has line number which has [LSTFND]
; [SRCHCNT] has length to be searched
; [NUMPOS] has beginning of line which has [LSTFND]
; Outputs:
; Zero flag set if match found
; [LSTFND],[LSTNUM],[SRCHCNT] updated for continuing the search
; [NUMPOS] has beginning of line in which match was made
MOV AL,[TXT1+1]
MOV CX,[SRCHCNT]
MOV DI,[LSTFND]
SCAN:
OR DI,DI ;Clear zero flag in case CX=0
REPNE SCASB
JNZ RET11
MOV DX,CX
MOV BX,DI ;Save search position
MOV CX,[OLDLEN]
DEC CX
MOV SI,2 + OFFSET DG:TXT1
CMP AL,AL ;Set zero flag in case CX=0
if kanji
dec si ;Want to look at the first character again
dec di
kanjchar:
lodsb
call testkanj
jz nxt_kj_char
xchg ah,al
lodsb
mov bx,[di]
add di,2
cmp ax,bx
jnz not_kj_match
dec cx
loop kanjchar
nxt_kj_char:
cmp al,byte ptr[di]
jnz not_kj_match
inc di
loop kanjchar
not_kj_match:
else
REPE CMPSB
endif
MOV CX,DX
MOV DI,BX
JNZ SCAN
MOV [SRCHCNT],CX
MOV CX,DI
MOV [LSTFND],DI
MOV DI,[NUMPOS]
SUB CX,DI
MOV AL,10
MOV DX,[LSTNUM]
;Determine line number of match
GETLIN:
INC DX
MOV BX,DI
REPNE SCASB
JZ GETLIN
DEC DX
MOV [LSTNUM],DX
MOV [NUMPOS],BX
XOR AL,AL
RET11: RET
GETTEXT:
; Inputs:
; SI points into command line buffer
; DI points to result buffer
; Function:
; Moves [SI] to [DI] until ctrl-Z (1AH) or
; RETURN (0DH) is found. Termination char not moved.
; Outputs:
; AL = Termination character
; CX = No of characters moved.
; SI points one past termination character
; DI points to next free location
XOR CX,CX
GETIT:
LODSB
;-----------------------------------------------------------------------
cmp al,quote_char ;a quote character?
jne sj101 ;no, skip....
lodsb ;yes, get quoted character
call make_cntrl
jmp short sj102
;-----------------------------------------------------------------------
sj101:
CMP AL,1AH
JZ DEFCHK
sj102:
CMP AL,0DH
JZ DEFCHK
STOSB
INC CX
JMP SHORT GETIT
DEFCHK:
OR CX,CX
JZ OLDTXT
PUSH DI
SUB DI,CX
MOV BYTE PTR [DI-1],cl
POP DI
RET
OLDTXT:
cmp byte ptr[olddat],1 ;replace with old text?
je sj11 ;yes...
mov byte ptr[di-1],cl ;zero text buffer char count
ret
sj11:
MOV CL,BYTE PTR [DI-1]
ADD DI,CX
RET
FINDLIN:
; Inputs
; BX = Line number to be located in buffer (0 means last line)
; Outputs:
; DX = Actual line found
; DI = Pointer to start of line DX
; Zero set if BX = DX
; AL,CX destroyed. No other registers affected.
MOV DX,[CURRENT]
MOV DI,[POINTER]
CMP BX,DX
JZ RET4
JA FINDIT
OR BX,BX
JZ FINDIT
MOV DX,1
MOV DI,OFFSET DG:START
CMP BX,DX
JZ RET4
FINDIT:
MOV CX,[ENDTXT]
SUB CX,DI
SCANLN:
MOV AL,10
OR AL,AL ;Clear zero flag
FINLIN:
JCXZ RET4
REPNE SCASB
INC DX
CMP BX,DX
JNZ FINLIN
RET4: RET
SHOWNUM:
; Inputs:
; BX = Line number to be displayed
; Function:
; Displays line number on terminal in 8-character
; format, suppressing leading zeros.
; AX, CX, DX destroyed. No other registers affected.
PUSH BX
MOV AL," "
CALL OUT
CALL CONV10
MOV AL,":"
CALL OUT
MOV AL,"*"
POP BX
CMP BX,[CURRENT]
JZ STARLIN
MOV AL," "
STARLIN:
JMP OUT
CONV10:
;Inputs:
; BX = Binary number to be displayed
; Function:
; Ouputs binary number. Five digits with leading
; zero suppression. Zero prints 5 blanks.
XOR AX,AX
MOV DL,AL
MOV CX,16
CONV:
SHL BX,1
ADC AL,AL
DAA
XCHG AL,AH
ADC AL,AL
DAA
XCHG AL,AH
ADC DL,DL
LOOP CONV
MOV BL,"0"-" "
XCHG AX,DX
CALL LDIG
MOV AL,DH
CALL DIGITS
MOV AL,DL
DIGITS:
MOV DH,AL
SHR AL,1
SHR AL,1
SHR AL,1
SHR AL,1
CALL LDIG
MOV AL,DH
LDIG:
AND AL,0FH
JZ ZERDIG
MOV BL,0
ZERDIG:
ADD AL,"0"
SUB AL,BL
JMP OUT
RET5: RET
CRLF:
MOV AL,13
CALL OUT
LF:
MOV AL,10
OUT:
PUSH DX
XCHG AX,DX
MOV AH,STD_CON_OUTPUT
INT 21H
XCHG AX,DX
POP DX
RET
;-----------------------------------------------------------------------;
; Will scan buffer given pointed to by SI and get rid of quote
;characters, compressing the line and adjusting the length at the
;begining of the line.
; Preserves al registers except flags and AX .
unquote:
push cx
push di
push si
mov di,si
mov cl,[si-1] ;length of buffer
xor ch,ch
mov al,quote_char
cld
unq_loop:
jcxz unq_done ;no more chars in the buffer, exit
repnz scasb ;search for quote character
jnz unq_done ;none found, exit
push cx ;save chars left in buffer
push di ;save pointer to quoted character
push ax ;save quote character
mov al,byte ptr[di] ;get quoted character
call make_cntrl
mov byte ptr[di],al
pop ax ;restore quote character
mov si,di
dec di ;points to the quote character
inc cx ;include the carriage return also
rep movsb ;compact line
pop di ;now points to after quoted character
pop cx
jcxz sj13 ;if quote char was last of line do not adjust
dec cx ;one less char left in the buffer
sj13: pop si
dec byte ptr[si-1] ;one less character in total buffer count also
push si
jmp short unq_loop
unq_done:
pop si
pop di
pop cx
ret
;-----------------------------------------------------------------------;
; Convert the character in AL to the corresponding control
; character. AL has to be between @ and _ to be converted. That is,
; it has to be a capital letter. All other letters are left unchanged.
make_cntrl:
push ax
and ax,11100000b
cmp ax,01000000b
pop ax
jne sj14
and ax,00011111b
sj14:
ret
;---- Kill spaces in buffer --------------------------------------------;
kill_bl:
lodsb ;get rid of blanks
cmp al,' '
je kill_bl
ret
;----- Restore INT 24 vector and old current directory -----------------;
rest_dir:
cmp [fudge],0
je no_fudge
mov ax,(set_interrupt_vector shl 8) or 24h
lds dx,[hardch]
int 21h
push cs
pop ds
mov dx,offset dg:userdir ;restore directory
mov ah,chdir
int 21h
mov dl,[user_drive] ;restore old current drive
mov ah,set_default_drive
int 21h
no_fudge:
ret
;----- INT 24 Processing -----------------------------------------------;
int_24_retaddr dw offset dg:int_24_back
int_24 proc far
assume ds:nothing,es:nothing,ss:nothing
pushf
push cs
push [int_24_retaddr]
push word ptr [hardch+2]
push word ptr [hardch]
ret
int_24 endp
int_24_back:
cmp al,2 ;abort?
jnz ireti
push cs
pop ds
assume ds:dg
call rest_dir
int 20h
ireti:
iret
IF KANJI
TESTKANJ:
CMP AL,81H
JB NOTLEAD
CMP AL,9FH
JBE ISLEAD
CMP AL,0E0H
JB NOTLEAD
CMP AL,0FCH
JBE ISLEAD
NOTLEAD:
PUSH AX
XOR AX,AX ;Set zero
POP AX
RET
ISLEAD:
PUSH AX
XOR AX,AX ;Set zero
INC AX ;Reset zero
POP AX
RET
ENDIF
;-----------------------------------------------------------------------;
CODE ENDS
END EDLPROC


514
v2.0/source/EXE2BIN.ASM Normal file
View File

@ -0,0 +1,514 @@
title LOCATE (EXE2BIN)
;Loader for EXE files under 86-DOS
;The following switch allows use with the "old linker", which put a version
;number where the new linker puts the number of bytes used in the last page.
;If enabled, this will cause a test for 0004 at this location (the old linker
;version number), and if equal, change it to 200H so all of the last page
;will be used.
;VER. 1.5
; 05/21/82 Added rev number
;
;VER. 1.6
; 07/01/82 A little less choosy about size matches
;
;VER. 2.0 Rev. 1 M.A.Ulloa
; 10/08/82 Modified to use new 2.0 system calls for file i/o
;
; Rev. 2 M.A.Ulloa
; 10/27/82 Added the DOS version check
FALSE EQU 0
TRUE EQU NOT FALSE
OLDLINK EQU 0 ;1 to enable, 0 to disable
.xlist
INCLUDE DOSSYM.ASM
.list
subttl Main Code Area
page
code segment byte
code ends
DATA SEGMENT PUBLIC BYTE
EXTRN bad_vers_err:BYTE,NOTFND:BYTE,NOROOM:BYTE,DIRFULL:BYTE
EXTRN CANTFIX:BYTE,RDBAD:BYTE,FULL:BYTE,PROMPT:BYTE,CRLF:BYTE
make db "MAUlloa/Microsoft/V20"
rev db "2"
file1_ext db ".EXE",00h
file2_ext db ".BIN",00h
per1 db 0
per2 db 0
file1 db 64 dup(?)
handle1 dw 1 dup(?)
file2 db 64 dup(?)
handle2 dw 1 dup(?)
INBUF DB 5,0
DB 5 DUP(?)
;The following locations must be defined for storing the header:
RUNVAR LABEL BYTE ;Start of RUN variables
RELPT DW ?
LASTP LABEL WORD
RELSEG DW ?
SIZ LABEL WORD ;Share these locations
PAGES DW ?
RELCNT DW ?
HEADSIZ DW ?
DW ?
LOADLOW DW ?
INITSS DW ?
INITSP DW ?
DW ?
INITIP DW ?
INITCS DW ?
RELTAB DW ?
RUNVARSIZ EQU $-RUNVAR
DATA ENDS
STACK SEGMENT WORD STACK
DB 80H DUP (?)
STACK ENDS
ZLOAD SEGMENT
ZLOAD ENDS
LOAD EQU ZLOAD
CODE SEGMENT BYTE
ASSUME CS:CODE
LOCATE PROC FAR
JMP SHORT LOCSTRT
HEADER DB "Vers 2.00"
LOCSTRT:
MOV SI,81H
PUSH DS
XOR AX,AX
PUSH AX ;Push return address to DS:0
;Code to print header
; PUSH DS
; MOV DX,DATA
; MOV DS,DX
; MOV DX,OFFSET HEADER
; MOV AH,STD_CON_STRING_OUTPUT
; INT 21H
; POP DS
;----- Check Version Number --------------------------------------------;
mov ah,Get_Version
int 21h
cmp al,2
jge vers_ok ; version >= 2, enter locate
push ds
mov dx,data
mov ds,dx
mov dx,offset bad_vers_err
MOV AH,STD_CON_STRING_OUTPUT
INT 21H
pop ds
ret ;long return to DOS
;-----------------------------------------------------------------------;
vers_ok:
MOV BX,WORD PTR DS:2 ;Get size of memory
MOV DX,DATA
MOV ES,DX
assume es:data
;-----------------------------------------------------------------------;
;----- Get the first file name
call kill_bl
jnc sj01
mov ds,dx
jmp bad_file
sj01:
mov di,offset file1
sj0:
lodsb ;get character of file name
cmp al,' '
je sj2
cmp al,0dh
je sj2
cmp al,'.' ;an extension separator found?
jne sj1
mov es:[per1],-1
sj1:
stosb
jmp short sj0
sj2:
dec si
mov byte ptr es:[di],00h ;nul terminate the filename
call kill_bl
jc no_second
;----- Get the second file name
mov di,offset file2
sj3:
lodsb ;get character of file name
cmp al,' '
je sj5
cmp al,0dh
je sj5
cmp al,'.' ;an extension separator found?
jne sj4
mov es:[per2],-1
sj4:
stosb
jmp short sj3
sj5:
mov byte ptr es:[di],00h ;nul terminate
jmp short check_ext
;----- Copy file1 to file2
no_second:
mov ds,dx
assume ds:data
mov si,offset file1
mov di,offset file2
sj6:
lodsb
cmp al,'.'
je sj7
cmp al,00h
je sj7
stosb
jmp short sj6
sj7:
mov byte ptr [di],00h
;----- Check that files have an extension, otherwise set default
check_ext:
mov ds,dx
assume ds:data
cmp [per1],-1
je file1_ok
mov si,offset file1
sj8:
lodsb
cmp al,00h
jne sj8
mov di,si
mov si,offset file1_ext
call put_ext
file1_ok:
cmp [per2],-1
je file2_ok
mov si,offset file2
sj9:
lodsb
cmp al,00h
jne sj9
mov di,si
mov si,offset file2_ext
call put_ext
jmp short file2_ok
;----- Fill in the default extent
put_ext proc near
dec di
mov cx,5 ;move extent: period,extent,null
rep movsb
ret
put_ext endp
;----- Find the first non-blank
kill_bl proc near
cld
sj10:
lodsb
cmp al,' '
je sj10
dec si
cmp al,0dh
clc
jne sj11
stc
sj11:
ret
kill_bl endp
file2_ok:
;-----------------------------------------------------------------------;
mov dx,offset file1
mov ah,open
mov al,0 ;ror reading only
INT 21H ;Open input file
jc bad_file
mov [handle1],ax
jmp exeload
bad_file:
MOV DX,OFFSET NOTFND
xERROR:
MOV AH,STD_CON_STRING_OUTPUT
INT 21H
RET ;FAR return to MS-DOS
TOOBIG:
MOV DX,OFFSET NOROOM
JMP xERROR
BADEXE:
MOV DX,OFFSET CANTFIX
ERRORJ: JMP xERROR
EXELOAD:
MOV DX,OFFSET RUNVAR ;Read header in here
MOV CX,RUNVARSIZ ;Amount of header info we need
push bx
mov bx,[handle1]
MOV AH,read
INT 21H ;Read in header
pop bx
CMP [RELPT],5A4DH ;Check signature word
JNZ BADEXE
MOV AX,[HEADSIZ] ;size of header in paragraphs
ADD AX,31 ;Round up first
CMP AX,1000H ;Must not be >=64K
JAE TOOBIG
AND AX,NOT 31
MOV CL,4
SHL AX,CL ;Header size in bytes
push dx
push cx
push ax
push bx
mov dx,ax
xor cx,cx
mov al,0
mov bx,[handle1]
mov ah,lseek
int 21h
pop bx
pop ax
pop cx
pop dx
XCHG AL,AH
SHR AX,1 ;Convert to pages
MOV DX,[PAGES] ;Total size of file in 512-byte pages
SUB DX,AX ;Size of program in pages
CMP DX,80H ;Fit in 64K?
JAE TOOBIG
XCHG DH,DL
SHL DX,1 ;Convert pages to bytes
MOV AX,[LASTP] ;Get count of bytes in last page
OR AX,AX ;If zero, use all of last page
JZ WHOLEP
IF OLDLINK
CMP AX,4 ;Produced by old linker?
JZ WHOLEP ;If so, use all of last page too
ENDIF
SUB DX,200H ;Subtract last page
ADD DX,AX ;Add in byte count for last page
WHOLEP:
MOV [SIZ],DX
ADD DX,15
SHR DX,CL ;Convert bytes to paragraphs
MOV BP,LOAD
ADD DX,BP ;Size + start = minimum memory (paragr.)
CMP DX,BX ;Enough memory?
JA TOOBIG
MOV DX,OFFSET CANTFIX
MOV AX,[INITSS]
OR AX,[INITSP]
OR AX,[INITCS]
ERRORNZ:
jz xj
JMP ERRORJ ;Must not have SS, SP, or CS to init.
xj: MOV AX,[INITIP]
OR AX,AX ;If IP=0, do binary fix
JZ BINFIX
CMP AX,100H ;COM file must be set up for CS:100
JNZ ERRORNZ
push dx
push cx
push ax
push bx
mov dx,100h ;chop off first 100h
xor cx,cx
mov al,1 ;seek from current position
mov bx,[handle1]
mov ah,lseek
int 21h
pop bx
pop ax
pop cx
pop dx
SUB [SIZ],AX ;And count decreased size
CMP [RELCNT],0 ;Must have no fixups
JNZ ERRORNZ
BINFIX:
XOR BX,BX ;Initialize fixup segment
;See if segment fixups needed
CMP [RELCNT],0
JZ LOADEXE
GETSEG:
MOV DX,OFFSET PROMPT
MOV AH,STD_CON_STRING_OUTPUT
INT 21H
MOV AH,STD_CON_STRING_INPUT
MOV DX,OFFSET INBUF
INT 21H ;Get user response
MOV DX,OFFSET CRLF
MOV AH,STD_CON_STRING_OUTPUT
INT 21H
MOV SI,OFFSET INBUF+2
MOV BYTE PTR [SI-1],0 ;Any digits?
JZ GETSEG
DIGLP:
LODSB
SUB AL,"0"
JC DIGERR
CMP AL,10
JB HAVDIG
AND AL,5FH ;Convert to upper case
SUB AL,7
CMP AL,10
JB DIGERR
CMP AL,10H
JAE DIGERR
HAVDIG:
SHL BX,1
SHL BX,1
SHL BX,1
SHL BX,1
OR BL,AL
JMP DIGLP
DIGERR:
CMP BYTE PTR [SI-1],0DH ;Is last char. a CR?
JNZ GETSEG
LOADEXE:
XCHG BX,BP ;BX has LOAD, BP has fixup
MOV CX,[SIZ]
MOV AH,read
push di
mov di,[handle1]
PUSH DS
MOV DS,BX
XOR DX,DX
push bx
mov bx,di
INT 21H ;Read in up to 64K
pop bx
POP DS
pop di
Jnc HAVEXE ;Did we get it all?
MOV DX,OFFSET RDBAD
jmp xERROR ;Non fatal, print warning
HAVEXE:
CMP [RELCNT],0 ;Any fixups to do?
JZ STORE
MOV AX,[RELTAB] ;Get position of table
push dx
push cx
push ax
push bx
mov dx,ax
xor cx,cx
mov al,0
mov bx,[handle1]
mov ah,lseek
int 21h
pop bx
pop ax
pop cx
pop dx
MOV DX,OFFSET RELPT ;4-byte buffer for relocation address
RELOC:
MOV DX,OFFSET RELPT ;4-byte buffer for relocation address
MOV CX,4
MOV AH,read
push bx
mov bx,[handle1]
INT 21H ;Read in one relocation pointer
pop bx
Jnc RDCMP
JMP BADEXE
RDCMP:
MOV DI,[RELPT] ;Get offset of relocation pointer
MOV AX,[RELSEG] ;Get segment
ADD AX,BX ;Bias segment with actual load segment
MOV ES,AX
ADD ES:[DI],BP ;Relocate
DEC [RELCNT] ;Count off
JNZ RELOC
STORE:
MOV AH,CREAT
MOV DX,OFFSET file2
xor cx,cx
INT 21H
Jc MKERR
mov [handle2],ax
MOV CX,[SIZ]
MOV AH,write
push di
mov di,[handle2]
PUSH DS
MOV DS,BX
XOR DX,DX ;Address 0 in segment
push bx
mov bx,di
INT 21H
pop bx
POP DS
pop di
Jc WRTERR ;Must be zero if more to come
MOV AH,CLOSE
push bx
mov bx,[handle2]
INT 21H
pop bx
RET
WRTERR:
MOV DX,OFFSET FULL
JMP xERROR
MKERR:
MOV DX,OFFSET DIRFULL
JMP xERROR
LOCATE ENDP
CODE ENDS
END LOCATE

1035
v2.0/source/EXEC.ASM Normal file

File diff suppressed because it is too large Load Diff

BIN
v2.0/source/EXEMES.ASM Normal file

Binary file not shown.

362
v2.0/source/FAT.ASM Normal file
View File

@ -0,0 +1,362 @@
;
; FAT operations for MSDOS
;
INCLUDE DOSSEG.ASM
CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME SS:DOSGROUP,CS:DOSGROUP
.xlist
.xcref
INCLUDE DOSSYM.ASM
INCLUDE DEVSYM.ASM
.cref
.list
TITLE FAT - FAT maintenance routines
NAME FAT
i_need CURBUF,DWORD
i_need CLUSSPLIT,BYTE
i_need CLUSSAVE,WORD
i_need CLUSSEC,WORD
i_need THISDRV,BYTE
i_need DEVCALL,BYTE
i_need CALLMED,BYTE
i_need CALLRBYT,BYTE
i_need BUFFHEAD,DWORD
i_need CALLXAD,DWORD
i_need CALLBPB,DWORD
SUBTTL UNPACK -- UNPACK FAT ENTRIES
PAGE
ASSUME SS:DOSGROUP
procedure UNPACK,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Inputs:
; BX = Cluster number
; ES:BP = Base of drive parameters
; Outputs:
; DI = Contents of FAT for given cluster
; Zero set means DI=0 (free cluster)
; SI Destroyed, No other registers affected. Fatal error if cluster too big.
CMP BX,ES:[BP.dpb_max_cluster]
JA HURTFAT
CALL MAPCLUSTER
ASSUME DS:NOTHING
MOV DI,[DI]
JNC HAVCLUS
PUSH CX
MOV CL,4
SHR DI,CL
POP CX
STC
HAVCLUS:
AND DI,0FFFH
PUSH SS
POP DS
return
HURTFAT:
PUSH AX
MOV AH,80H ; Signal Bad FAT to INT int_fatal_abort handler
MOV DI,0FFFH ; In case INT int_fatal_abort returns (it shouldn't)
invoke FATAL
POP AX ; Try to ignore bad FAT
return
UNPACK ENDP
SUBTTL PACK -- PACK FAT ENTRIES
PAGE
procedure PACK,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Inputs:
; BX = Cluster number
; DX = Data
; ES:BP = Pointer to drive DPB
; Outputs:
; The data is stored in the FAT at the given cluster.
; SI,DX,DI all destroyed
; No other registers affected
CALL MAPCLUSTER
ASSUME DS:NOTHING
MOV SI,[DI]
JNC ALIGNED
PUSH CX
MOV CL,4
SHL DX,CL
POP CX
AND SI,0FH
JMP SHORT PACKIN
ALIGNED:
AND SI,0F000H
PACKIN:
OR SI,DX
MOV [DI],SI
LDS SI,[CURBUF]
MOV [SI.BUFDIRTY],1
CMP BYTE PTR [CLUSSPLIT],0
PUSH SS
POP DS
ASSUME DS:DOSGROUP
retz
PUSH AX
PUSH BX
PUSH CX
MOV AX,[CLUSSAVE]
MOV DS,WORD PTR [CURBUF+2]
ASSUME DS:NOTHING
ADD SI,BUFINSIZ
MOV [SI],AH
PUSH SS
POP DS
ASSUME DS:DOSGROUP
PUSH AX
MOV DX,[CLUSSEC]
MOV SI,1
XOR AL,AL
invoke GETBUFFRB
LDS DI,[CURBUF]
ASSUME DS:NOTHING
MOV [DI.BUFDIRTY],1
ADD DI,BUFINSIZ
DEC DI
ADD DI,ES:[BP.dpb_sector_size]
POP AX
MOV [DI],AL
PUSH SS
POP DS
POP CX
POP BX
POP AX
return
PACK ENDP
SUBTTL MAPCLUSTER - BUFFER A FAT SECTOR
PAGE
procedure MAPCLUSTER,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Inputs:
; ES:BP Points to DPB
; BX Is cluster number
; Function:
; Get a pointer to the cluster
; Outputs:
; DS:DI Points to contents of FAT for given cluster
; DS:SI Points to start of buffer
; Carry set if cluster data is in high 12 bits of word
; No other registers effected
MOV BYTE PTR [CLUSSPLIT],0
PUSH AX
PUSH BX
PUSH CX
PUSH DX
MOV AX,BX
SHR AX,1
ADD AX,BX
XOR DX,DX
MOV CX,ES:[BP.dpb_sector_size]
DIV CX ; AX is FAT sector # DX is sector index
ADD AX,ES:[BP.dpb_first_FAT]
DEC CX
PUSH AX
PUSH DX
PUSH CX
MOV DX,AX
XOR AL,AL
MOV SI,1
invoke GETBUFFRB
LDS SI,[CURBUF]
ASSUME DS:NOTHING
LEA DI,[SI.BufInSiz]
POP CX
POP AX
POP DX
ADD DI,AX
CMP AX,CX
JNZ MAPRET
MOV AL,[DI]
PUSH SS
POP DS
ASSUME DS:DOSGROUP
INC BYTE PTR [CLUSSPLIT]
MOV BYTE PTR [CLUSSAVE],AL
MOV [CLUSSEC],DX
INC DX
XOR AL,AL
MOV SI,1
invoke GETBUFFRB
LDS SI,[CURBUF]
ASSUME DS:NOTHING
LEA DI,[SI.BufInSiz]
MOV AL,[DI]
PUSH SS
POP DS
ASSUME DS:DOSGROUP
MOV BYTE PTR [CLUSSAVE+1],AL
MOV DI,OFFSET DOSGROUP:CLUSSAVE
MAPRET:
POP DX
POP CX
POP BX
MOV AX,BX
SHR AX,1
POP AX
return
MAPCLUSTER ENDP
SUBTTL FATREAD -- CHECK DRIVE GET FAT
PAGE
ASSUME DS:DOSGROUP,ES:NOTHING
procedure FAT_operation,NEAR
FATERR:
AND DI,STECODE ; Put error code in DI
MOV AH,2 ; While trying to read FAT
MOV AL,BYTE PTR [THISDRV] ; Tell which drive
invoke FATAL1
entry FATREAD
ASSUME DS:DOSGROUP,ES:NOTHING
; Function:
; If disk may have been changed, FAT is read in and buffers are
; flagged invalid. If not, no action is taken.
; Outputs:
; ES:BP = Base of drive parameters
; All other registers destroyed
MOV AL,BYTE PTR [THISDRV]
invoke GETBP
MOV AL,DMEDHL
MOV AH,ES:[BP.dpb_UNIT]
MOV WORD PTR [DEVCALL],AX
MOV BYTE PTR [DEVCALL.REQFUNC],DEVMDCH
MOV [DEVCALL.REQSTAT],0
MOV AL,ES:[BP.dpb_media]
MOV BYTE PTR [CALLMED],AL
PUSH ES
PUSH DS
MOV BX,OFFSET DOSGROUP:DEVCALL
LDS SI,ES:[BP.dpb_driver_addr] ; DS:SI Points to device header
ASSUME DS:NOTHING
POP ES ; ES:BX Points to call header
invoke DEVIOCALL2
PUSH SS
POP DS
ASSUME DS:DOSGROUP
POP ES ; Restore ES:BP
MOV DI,[DEVCALL.REQSTAT]
TEST DI,STERR
JNZ FATERR
XOR AH,AH
XCHG AH,ES:[BP.dpb_first_access] ; Reset dpb_first_access
MOV AL,BYTE PTR [THISDRV] ; Use physical unit number
OR AH,BYTE PTR [CALLRBYT]
JS NEWDSK ; new disk or first access?
JZ CHKBUFFDIRT
return ; If Media not changed
CHKBUFFDIRT:
INC AH ; Here if ?Media..Check buffers
LDS DI,[BUFFHEAD]
ASSUME DS:NOTHING
NBUFFER: ; Look for dirty buffers
CMP AX,WORD PTR [DI.BUFDRV]
retz ; There is a dirty buffer, assume Media OK
LDS DI,[DI.NEXTBUF]
CMP DI,-1
JNZ NBUFFER
; If no dirty buffers, assume Media changed
NEWDSK:
invoke SETVISIT
NXBUFFER:
MOV [DI.VISIT],1
CMP AL,[DI.BUFDRV] ; For this drive?
JNZ SKPBUFF
MOV WORD PTR [DI.BUFDRV],00FFH ; Free up buffer
invoke SCANPLACE
SKPBUFF:
invoke SKIPVISIT
JNZ NXBUFFER
LDS DI,ES:[BP.dpb_driver_addr]
TEST [DI.SDEVATT],ISFATBYDEV
JNZ GETFREEBUF
context DS
MOV BX,2
CALL UNPACK ; Read the first FAT sector into CURBUF
LDS DI,[CURBUF]
JMP SHORT GOTGETBUF
GETFREEBUF:
ASSUME DS:NOTHING
PUSH ES ; Get a free buffer for BIOS to use
PUSH BP
LDS DI,[BUFFHEAD]
invoke BUFWRITE
POP BP
POP ES
GOTGETBUF:
ADD DI,BUFINSIZ
MOV WORD PTR [CALLXAD+2],DS
PUSH SS
POP DS
ASSUME DS:DOSGROUP
MOV WORD PTR [CALLXAD],DI
MOV AL,DBPBHL
MOV AH,BYTE PTR ES:[BP.dpb_UNIT]
MOV WORD PTR [DEVCALL],AX
MOV BYTE PTR [DEVCALL.REQFUNC],DEVBPB
MOV [DEVCALL.REQSTAT],0
MOV AL,BYTE PTR ES:[BP.dpb_media]
MOV [CALLMED],AL
PUSH ES
PUSH DS
PUSH WORD PTR ES:[BP.dpb_driver_addr+2]
PUSH WORD PTR ES:[BP.dpb_driver_addr]
MOV BX,OFFSET DOSGROUP:DEVCALL
POP SI
POP DS ; DS:SI Points to device header
ASSUME DS:NOTHING
POP ES ; ES:BX Points to call header
invoke DEVIOCALL2
POP ES ; Restore ES:BP
PUSH SS
POP DS
ASSUME DS:DOSGROUP
MOV DI,[DEVCALL.REQSTAT]
TEST DI,STERR
JNZ FATERRJ
MOV AL,BYTE PTR ES:[BP.dpb_media]
LDS SI,[CALLBPB]
ASSUME DS:NOTHING
CMP AL,BYTE PTR [SI.BPMEDIA]
JZ DPBOK
invoke $SETDPB
LDS DI,[CALLXAD] ; Get back buffer pointer
MOV AL,BYTE PTR ES:[BP.dpb_FAT_count]
MOV AH,BYTE PTR ES:[BP.dpb_FAT_size]
MOV WORD PTR [DI.BUFWRTCNT-BUFINSIZ],AX ;Correct buffer info
DPBOK:
context ds
MOV AX,-1
TEST ES:[BP.dpb_current_dir],AX
retz ; If root, leave as root
MOV ES:[BP.dpb_current_dir],AX ; Path may be bad, mark invalid
return
FATERRJ: JMP FATERR
FAT_operation ENDP
do_ext
CODE ENDS
END

1684
v2.0/source/FC.ASM Normal file

File diff suppressed because it is too large Load Diff

512
v2.0/source/FCB.ASM Normal file
View File

@ -0,0 +1,512 @@
;
; FCB management routines for MSDOS
;
INCLUDE DOSSEG.ASM
IFNDEF KANJI
KANJI EQU 0 ;FALSE
ENDIF
CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME SS:DOSGROUP,CS:DOSGROUP
.xlist
.xcref
INCLUDE DOSSYM.ASM
INCLUDE DEVSYM.ASM
.cref
.list
i_need Name1,BYTE
i_need NumIO,BYTE
i_need DevFCB,BYTE
i_need Creating,BYTE
i_need ExtFCB,BYTE
i_need Attrib,BYTE
i_need SpaceFlag,BYTE
i_need Current_Country,WORD
procedure MakeFcb,NEAR
DRVBIT EQU 2
NAMBIT EQU 4
EXTBIT EQU 8
MOV BYTE PTR [SpaceFlag],0
XOR DL,DL ; Flag--not ambiguous file name
TEST AL,DRVBIT ; Use current drive field if default?
JNZ DEFDRV
MOV BYTE PTR ES:[DI],0 ; No - use default drive
DEFDRV:
INC DI
MOV CX,8
TEST AL,NAMBIT ; Use current name fields as defualt?
XCHG AX,BX ; Save bits in BX
MOV AL," "
JZ FILLB ; If not, go fill with blanks
ADD DI,CX
XOR CX,CX ; Don't fill any
FILLB:
REP STOSB
MOV CL,3
TEST BL,EXTBIT ; Use current extension as default
JZ FILLB2
ADD DI,CX
XOR CX,CX
FILLB2:
REP STOSB
XCHG AX,CX ; Put zero in AX
STOSW
STOSW ; Initialize two words after to zero
SUB DI,16 ; Point back at start
TEST BL,1 ; Scan off separators if not zero
JZ SKPSPC
CALL SCANB ; Peel off blanks and tabs
CALL DELIM ; Is it a one-time-only delimiter?
JNZ NOSCAN
INC SI ; Skip over the delimiter
SKPSPC:
CALL SCANB ; Always kill preceding blanks and tabs
NOSCAN:
CALL GETLET
JBE NODRV ; Quit if termination character
CMP BYTE PTR[SI],":" ; Check for potential drive specifier
JNZ NODRV
INC SI ; Skip over colon
SUB AL,"@" ; Convert drive letter to binary drive number
JBE BADDRV ; Valid drive numbers are <= NUMIO
CMP AL,BYTE PTR [NUMIO]
JBE HAVDRV
BADDRV:
MOV DL,-1
HAVDRV:
STOSB ; Put drive specifier in first byte
INC SI
DEC DI ; Counteract next two instructions
NODRV:
DEC SI ; Back up
INC DI ; Skip drive byte
NORMSCAN:
MOV CX,8
CALL GETWORD ; Get 8-letter file name
CMP BYTE PTR [SI],"."
JNZ NODOT
INC SI ; Skip over dot if present
MOV CX,3 ; Get 3-letter extension
CALL MUSTGETWORD
NODOT:
MOV AL,DL
return
NONAM:
ADD DI,CX
DEC SI
return
GETWORD:
CALL GETLET
JBE NONAM ; Exit if invalid character
DEC SI
;
; UGH!!! Horrible bug here that should be fixed at some point:
; If the name we are scanning is longer than CX, we keep on reading!
;
MUSTGETWORD:
CALL GETLET
;
; If spaceFlag is set then we allow spaces in a pathname
;
JB FILLNAM
JNZ MustCheckCX
TEST BYTE PTR [SpaceFlag],0FFh
JZ FILLNAM
CMP AL," "
JNZ FILLNAM
MustCheckCX:
JCXZ MUSTGETWORD
DEC CX
CMP AL,"*" ; Check for ambiguous file specifier
JNZ NOSTAR
MOV AL,"?"
REP STOSB
NOSTAR:
STOSB
IF KANJI
CALL TESTKANJ
JZ NOTDUAL3
JCXZ BNDERR ; Attempt to straddle boundry
MOVSB ; Transfer second byte
DEC CX
JMP SHORT NOTDUAL3
BNDERR:
MOV BYTE PTR ES:[DI-1]," " ; patch up that space
JMP MustGetWord ; go back and scan until delim
NOTDUAL3:
ENDIF
CMP AL,"?"
JNZ MUSTGETWORD
OR DL,1 ; Flag ambiguous file name
JMP MUSTGETWORD
FILLNAM:
MOV AL," "
REP STOSB
DEC SI
return
SCANB:
LODSB
CALL SPCHK
JZ SCANB
DEC SI
return
MakeFCB ENDP
;
; NameTrans is used by FindPath to scan off an element
; of a path. We must allow spaces in pathnames
; Inputs: SS - DOSGROUP
; DS:SI name
; Outputs: DS:SI advanced over spot
; ES:DI point to after Name1
; registers modified: AX, BX, CX, DX
procedure NameTrans,near
MOV BYTE PTR [SpaceFlag],1
PUSH SS
POP ES
MOV DI,OFFSET DOSGROUP:NAME1
PUSH DI
MOV AL,' '
MOV CX,11
REP STOSB
XOR AL,AL
MOV DL,AL
STOSB
POP DI
CMP BYTE PTR [SI],'.'
IF KANJI
JZ FOOBAR
CALL NORMSCAN
CMP [NAME1],0E5H
retnz
MOV [NAME1],5
return
FOOBAR:
ELSE
JNZ NORMSCAN
ENDIF
MOVSB
LODSB
CALL PATHCHRCMP
JZ GOTDOTNAME
OR AL,AL
JZ GOTDOTNAME
CMP AL,'.'
JNZ BADDOTS
STOSB
LODSB
CALL PATHCHRCMP
JZ GOTDOTNAME
OR AL,AL
JZ GOTDOTNAME
DEC SI
BADDOTS:
DEC SI
GOTDOTNAME:
DEC SI
XOR AL,AL
return
nametrans ENDP
SUBTTL BUILDFCB -- MAKE A BLANK FCB FOR A DEVICE
PAGE
procedure BuildFCB,near
ASSUME DS:DOSGROUP,ES:DOSGROUP
; Function:
; Build a blank FCB for I/O to a device
; Outputs:
; Same as GETNAME
MOV AX," "
MOV DI,OFFSET DOSGROUP:DEVFCB+8 ; Point to extent field
STOSW
STOSB ; Blank out extent field
XOR AX,AX
MOV CX,10
REP STOSW ; Fill FCB with zeros
STOSB
invoke DATE16
MOV DI,OFFSET DOSGROUP:DEVFCB+22
XCHG AX,DX
STOSW
XCHG AX,DX
STOSW
XCHG AX,BX ; But device number in AH
MOV BX,OFFSET DOSGROUP:DEVFCB
MOV SI,DI
XOR AL,AL ; Set zero, clear carry
return
BuildFCB ENDP
SUBTTL MOVENAME, LODNAME -- EXAMINE FCB AND SETUP
PAGE
procedure FCB_move,NEAR
entry MOVNAMENOSET
MOV DI,1
JMP SHORT MOVSTART
entry MOVNAME
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; DS, DX point to FCB or extended FCB
; Outputs:
; DS:DX point to normal FCB
; DS:SI point after end of NAME/EXT in FCB
; ES = DOSGROUP
; If file name OK:
; [NAME1] has name in upper case
; All registers destroyed
; Carry set if bad file name or drive
XOR DI,DI
MOVSTART:
MOV WORD PTR [CREATING],0E500H ; Not creating, not DEL *.*
MOV SI,DX
LODSB
MOV [EXTFCB],AL ; Set flag if extended FCB in use
XOR AH,AH ; Set default attributes
CMP AL,-1 ; Is it an extended FCB?
JNZ HAVATTRB
ADD DX,7 ; Adjust to point to normal FCB
ADD SI,6
MOV AH,[SI-1] ; Attribute byte
LODSB ; Get drive select byte
HAVATTRB:
invoke GETTHISDRV
retc
PUSH DS
PUSH DX
PUSH SI
PUSH AX
;
; DS:DX is pointer to good FCB
; DS:SI is same
;
; Move the file into Name1 and UCASE it
;
PUSH DI
context ES
MOV DI,OFFSET DOSGROUP:NAME1
CALL LodName
POP DI
JC DrvNoSet
;
; are we setting current dir info?
;
OR DI,DI
JNZ DrvNoSet ; do not set dir info
;
; check for device name first, eliminating drive hits on devices
;
context DS
invoke DEVNAME
JNC DrvNoSet ; we have a device
;
; make sure that everything is current
;
invoke FATREAD
ASSUME DS:NOTHING,ES:NOTHING
MOV BYTE PTR [ATTRIB],attr_directory+attr_hidden+attr_system
invoke GETCURRDIR
DrvNoSet:
POP AX
MOV BYTE PTR [ATTRIB],AH
POP SI
POP DX
POP DS
context ES
MOV DI,OFFSET DOSGROUP:NAME1
entry LODNAME
; Inputs: DS:SI point to an FCB
; ES:DI point to an FCB
; Outputs: DS:SI point to after FCB
; ES:DI point to after FCB
; FCB from DS:SI copied and ucased to ES:DI
; Carry set if there was an error.
; Destroys AX,CX
CMP BYTE PTR [SI]," " ; Don't allow blank as first letter
STC ; In case of error
retz
IF KANJI
MOV CX,8
CMP BYTE PTR [SI],0E5H
JNZ MOVCHK
INC SI
MOV AL,5
STOSB
MOVSB
MOV CX,6
MOVCHK:
CALL GETLET
JB RET6
JNZ STOLET ; Is it a delimiter?
CMP AL," " ; This is the only delimiter allowed
STC ; In case of error
JNZ RET6
STOLET:
STOSB
CALL TESTKANJ
JZ MOVLP ;No
LODSB ;Get second byte
DEC CX
JZ BOUNDERR ;Attempt to cross boundry
STOSB
MOVLP:
LOOP MOVCHK
MOV CX,3
MOVCHK2:
CALL GETLET
JB RET6
JNZ STOLET2 ; Is it a delimiter?
CMP AL," " ; This is the only delimiter allowed
STC ; In case of error
retnz
STOLET2:
STOSB
CALL TESTKANJ
JZ MOVLP2 ;No
LODSB ;Get second byte
DEC CX
JNZ DOSTORE
BOUNDERR: ;Attempt to cross boundry
STC
return
DOSTORE:
STOSB
MOVLP2:
LOOP MOVCHK2
ELSE
MOV CX,11
MOVCHK:
CALL GETLET
JB RET6
JNZ STOLET ; Is it a delimiter?
CMP AL," " ; This is the only delimiter allowed
STC ; In case of error
retnz
STOLET:
STOSB
LOOP MOVCHK
ENDIF
CLC ; Got through whole name - no error
RET6: return
FCB_Move ENDP
SUBTTL GETLET, DELIM -- CHECK CHARACTERS AND CONVERT
PAGE
procedure GetLet,NEAR
; Get a byte from [SI], convert it to upper case, and compare for delimiter.
; ZF set if a delimiter, CY set if a control character (other than TAB).
LODSB
CMP AL,"a"
JB CHK1
CMP AL,"z"
JA CHK1
SUB AL,20H ; Convert to upper case
CHK1:
PUSH SI
MOV SI,[Current_Country]
ADD SI,Map_call
PUSH CS ; CS for long return
CALL WORD PTR CS:[SI]
POP SI
entry CHK
CMP AL,"."
retz
CMP AL,'"'
retz
CALL PATHCHRCMP
retz
CMP AL,"["
retz
CMP AL,"]"
retz
DELIM:
CMP AL,":" ; Allow ":" as separator in IBM version
retz
CMP AL,"<"
retz
CMP AL,"|"
retz
CMP AL,">"
retz
CMP AL,"+"
retz
CMP AL,"="
retz
CMP AL,";"
retz
CMP AL,","
retz
SPCHK:
CMP AL,9 ; Filter out tabs too
retz
; WARNING! " " MUST be the last compare
CMP AL," "
return
GetLet ENDP
procedure PATHCHRCMP,NEAR
CMP AL,'/'
retz
CMP AL,'\'
return
PathChrCMP ENDP
IF KANJI
procedure TESTKANJ,NEAR
CMP AL,81H
JB NOTLEAD
CMP AL,9FH
JBE ISLEAD
CMP AL,0E0H
JB NOTLEAD
CMP AL,0FCH
JBE ISLEAD
NOTLEAD:
PUSH AX
XOR AX,AX ;Set zero
POP AX
return
ISLEAD:
PUSH AX
XOR AX,AX ;Set zero
INC AX ;Reset zero
POP AX
return
TESTKANJ ENDP
ENDIF
do_ext
CODE ENDS
END

BIN
v2.0/source/FCMES.ASM Normal file

Binary file not shown.

932
v2.0/source/FIND.ASM Normal file
View File

@ -0,0 +1,932 @@
title MSDOS V2.0 FIND
;--------------------------------------------------------------------;
; Revision History: ;
; ;
; V1.1 8/23/82 M.A.Ulloa ;
; ;
; V1.2 9/22/82 M.A.Ulloa ;
; Added the -c and -n options ;
; ;
; 9/23/82 M.A.Ulloa ;
; Added DOS version number control ;
; ;
; 10/07/82 Rev.2 M.A.Ulloa ;
; Changed quote for double quotes, and added ;
; file name printing ;
; ;
; 10/20/82 Rev.3 M.A.Ulloa ;
; Modified IBM name to FIND, and changed the text ;
; of some messages. ;
; ;
; 10/25/82 Rev.4 M.A.Ulloa ;
; Changed name to FIND and all messages to the ;
; IBM form. ;
; ;
; 10/27/82 Rev.5 M.A.Ulloa ;
; Made the correct exit on version check in case ;
; of a 1.x DOS. ;
; ;
; 11/4/82 Rev. 5 A.R. Reynolds ;
; Messages moved to external module ;
; ;
; 11/10/82 Rev. 6 M.A. Ulloa ;
; Corrected problem with line numbers, and a problem ;
; with seeking for 0 chars. ;
; ;
; 03/30/83 Rev. 7 M.A. Ulloa ;
; Added patch area for bug fixing. ;
; ;
; 04/14/83 Rev. 8 M.A. Ulloa ;
; Made changes for Kanji characters. (uhg!) ;
; ;
;--------------------------------------------------------------------;
FALSE equ 0
TRUE equ NOT FALSE
KANJI equ FALSE ;set to true is kanji vers.
;--------------------------------------------------------------------;
; FIND program following the standart UNIX operation. ;
; ;
; FORMAT: ;
; find {option} string {filename {filename} {...}} ;
; ;
; NOTES: ;
; 1) String arguments HAVE to be enclosed ;
; in double quotes. (Two double quotes if a ;
; doble quote is to be included). Only ONE ;
; string argument is presently allowed. ;
; ;
; 2) Options are available: ;
; v All lines but those matching are considered ;
; c Only print a count of matching lines ;
; n Each line is preceded by its relative ;
; line number in the file. ;
; ;
; - Options can be Upper or lower case. ;
; - Format: The switch character followed by an options ;
; character. I.e.: In the IBM PC: /v ;
; ;
; 3) The program returns: ;
; 0 - OK, and some matches ;
; 2 - Some Error ;
; ;
; 4) The maximum line size is determined by ;
; buffer size. Bigger lines will bomb the program. ;
; ;
; 5) If no file name is given then it will asssume ;
; the input is comming from the Standart Input. NO ;
; errors are reported when reading from Standart Input. ;
;--------------------------------------------------------------------;
code segment public
assume cs:code,ss:code,ds:nothing,es:nothing
CR equ 0dh ;A Carriage Return
LF equ 0ah ;A Line Feed
quote_char equ 22h ;A double quote character
buffer_size equ 4096 ;file buffer size
st_buf_size equ 128 ;string arg. buffer size
fname_buf_size equ 64 ;file name buffer size
;----- DOS EQUATES --------------------------------------------------;
std_in equ 0 ;STD input handle
std_out equ 1 ;STD output handle
std_err equ 2 ;STD error handle
dos_ent equ 21h ;DOS entry point
std_con_string_output equ 9
get_version equ 48
char_oper equ 55 ;get configuration parameters
open equ 61 ;DOS std open code
close equ 62 ;DOS std close code
read equ 63 ;DOS std read code
write equ 64 ;DOS std write code
lseek equ 66 ;DOS file seek
exit equ 76 ;DOS process exit code
;----- Misc Data -----------------------------------------------;
make db "***MAUlloa/Microsoft/V12***"
rev db "8"
colon db ": "
n1_buf db "["
n2_buf db 8 dup(0) ;buffer for number conversion
;----- OPTION FLAGS -------------------------------------------------;
; If a flag is set (0ffh) then the option has been selected, if
;reset (0) then it has been not. All options are reset initially.
; NOTE: the order of this table has to remain consistent with the
;options dispatch code. If any changes are made they have to
;correspond with the code.
opt_tbl:
v_flg db 0
c_flg db 0
n_flg db 0
x_flg db 0 ;not used
l_flg db 0 ;not used
;----- LINE COUNTERS ------------------------------------------------;
mtch_cntr dw 0 ;matched lines counter
line_cntr dw 0 ;line counter
;----- MAIN ROUTINE -------------------------------------------------;
start:
;----- CHECK VERSION NUMBER -----------------------------------------;
mov ah,get_version
int 21h
cmp al,2
jge vers_ok
push cs
pop ds
mov dx,offset bad_vers
mov ah,std_con_string_output
int 21h
push es ;bad vers, exit a la 1.x
xor ax,ax
push ax
badfart proc far ;(what a hack!!)
ret
badfart endp
vers_ok:
push cs ;load ES to the right area,
pop es ; for use with DI register
assume es:code
;--------------------------------------------------------------------;
mov si,81h ;Start addrss. of commad line buf.
call kill_bl ;Get rid of blanks
or bx,bx ;A CR found?
jz find_opt ;no, first find the options
args_missing:
mov dx,offset errmsg1 ;empty command line, no args: error.
mov cl,cs:errlen1
call prt_err
mov al,2 ;error code for exit
jmp done
;----- FIND THE OPTION IF ANY ---------------------------------------;
find_opt:
mov ah,char_oper ;get the dos switch char.
mov al,0
int dos_ent ;switch char in DL
push dx
another_opt:
lodsb ;get the first char of command line
cmp al,' ' ;a blank?
je cont_scan
cmp al,CR ;a Carriage Return
je args_missing
pop dx ;get switch character
cmp al,dl ;is it the switch char?
jne find_str ;no, no options: get the string
push dx ;save for another round
lodsb ;get the option character
cmp al,' ' ;a blank?
je cont_scan ;yes, ignore and continue
cmp al,CR ;a CR?
je args_missing ;yes, error...
call make_caps ;Capitalize the character
mov bx,offset opt_tbl ;pointer to option flag table
cmp al,'V' ;the v option?
je opt_v
cmp al,'C' ;the c option?
je opt_c
cmp al,'N' ;the n option?
je opt_n
mov cs:errmsg5_opt,al ;save the option
mov dx,offset errmsg5 ;unknown option: error
mov cl,cs:errlen5
call prt_err
mov dx,offset crlf ;print a CRLF
mov cx,2
call prt_err
jmp another_opt ;process next option
opt_v:
mov di,0
jmp short opt_dispatch
opt_c:
mov di,1
jmp short opt_dispatch
opt_n:
mov di,2
opt_dispatch:
mov es:byte ptr[bx+di],0ffh ;set the corresponding flag
jmp another_opt ;process the rest of the options
cont_scan:
dec si ;adjust SI
call kill_bl ;get rid of blanks
or bx,bx ;A CR found?
jz another_opt ;no, test for other options
jmp args_missing ;yes, error...
;----- FIND STRING ARGUMENT -----------------------------------------;
find_str:
cmp al,quote_char ;string should start with a
jnz bad_str_err ; quote character, if not: error.
mov di,offset st_buffer ;String argument buffer addrss.
xor cx,cx ;Clear to keep string length.
move_str:
lodsb
cmp al,CR ;if a CR is found in the string
jnz str_ok ; then it's a bad string
bad_str_err:
mov dx,offset errmsg2 ;bad string error message
mov cl,cs:errlen2
call prt_err ;print the error.
mov al,2
jmp done
str_ok:
cmp al,quote_char ;look for a quote character
jnz move_char ;not an apost., move to buffer
lodsb ;an apost., check next char.
cmp al,quote_char ;another quote character?
je move_char ;yes, move it to the buffer
dec si ;no, adjust the pointer
mov es:st_length,cx ;store the string length
or cx,cx ;Is the string empty?
jnz other_args ;no: get the rest of the args.
mov al,1 ;empty: no matches(!?)
jmp done
move_char:
stosb ;put in buffer
inc cx ;increment string length
jmp move_str
;----- FIND THE FILE ARGUMENTS --------------------------------------;
other_args: ;Process the rest of the command
; line arguments.
call kill_bl ;get rid of leading blanks
or bx,bx ;At least one argument necessary,
jz further_args ; if a CR not found: ok.
;----- USE STD IN FOR INPUT -----------------------------------------;
push cs
pop ds
mov ax,std_in ;handle
jmp fill
further_args:
call clr_cntrs ;set all counters to zero
mov di,offset file_name_buf ;Set pointer to the name buffer
xor cx,cx ;zero file name length
move_fname:
lodsb
cmp al,' ' ;A blank: end of file name,
je done_move
cmp al,CR ;A CR: idem.
je done_move
stosb ;store in name buffer
inc cx ;increment file name length
jmp move_fname
done_move:
dec si ;Adjust pointer for next round.
mov es:byte ptr[di],00h ;File names are null terminated
push si ;Save SI to continue com. line scan.
push ds ;Save DS register contents for
; later because it points to the
; rest of the arguments.
mov es:file_name_len,cx ;save the name length
;----- OPEN FILE FOR READING ----------------------------------------;
push cs ;Load new DS with CS
pop ds
mov dx,offset file_name_buf ;addrss. of the file name
mov ah,open
mov al,0 ;file open for reading
int dos_ent ;call the DOS
jnc say_name ;if no carry then no errors
jmp open_error
;----- PRINT FILE NAME ----------------------------------------------;
say_name:
push ax ;save file handle
mov dx,offset heading
mov cl,cs:heading_len
xor ch,ch
call prout
mov dx,offset file_name_buf
mov cx,ds:file_name_len
call prout
cmp ds:c_flg,0ffh ;count only flag set?
je xx1
mov dx,offset crlf
mov cx,2
call prout
xx1:
pop ax
;----- Fill Buffer for Matching -------------------------------------;
fill:
mov bx,ax ;retrieve handle
refill:
mov dx,offset buffer ;data buffer addrss.
mov cx,buffer_size
mov ah,read
int dos_ent
jnc no_read_error ;if carry then read error
jmp read_error
no_read_error:
or ax,ax ;if ax=0 then all done
jnz go_match
cmp ds:c_flg,0ffh ;count only flag set?
jne sj2
call print_count
sj2:
cmp bx,std_in ;Using STD IN?
jnz regular
jmp foo ;if so: all done, exit
regular:
mov ah,close ;otherwise close the file
int dos_ent
jmp scan_rest ;get another file
;----- MATCH ROUTINE ------------------------------------------------;
;Note: If input is being taken from a file the stack contains
; (from top to bottom):
; - Pointer to the next command in the command line
; - Pointer to the program segment prefix (to be loaded into
; DS to access the command line.
; if the imput is from the standart input then NONE of it will be
; in the stack.
go_match:
push bx ;save the file handle
mov bp,offset buffer ;ptr to first line of file
mov di,ax ;dispalcement from beg of buffer
cmp ax,buffer_size-1 ;last line of the file?
jg no_last_line ;if yes, add a CRLF just in case
mov bx,bp
cmp byte ptr[bx+di-1],LF ;finished with a LF?
je no_last_line ;yes, it's an OK line.
mov byte ptr[bx+di],CR ;put a CR at the end of the data
inc di
mov byte ptr[bx+di],LF ;put a LF ...
inc di
no_last_line:
push di ;save the # of chars. in the buffer
push bp
mov dx,ds:st_length ;length of the string arg.
dec dx ;adjust for later use
jmp short try_again
more_stuff_o:
jmp more_stuff
;----- SCAN LINES IN THE BUFFER FOR A MATCH -------------------------;
;Note: at this point the stack contains (from top to bottom):
; - Stuff mentioned before
; - File Handle
; - Number of chars. left in the buffer from the next line.
; - Addrs. of the next line in the buffer.
;
; plus, DX has the adjusted length of the string argument.
try_again:
inc ds:line_cntr ;increment line counter
pop bp ;addrs. of next line in the buffer
mov di,bp ;points to beg. of a line
pop cx ;get # of chars left in the buffer
mov bx,cx ;save in case a non-complete line
mov al,LF ;search for a Line Feed
jcxz more_stuff_o ;no chars left in buffer
repnz scasb
jnz more_stuff_o ;no full line left in buffer
push cx ;save chars left in buffer
push di ;points to beg. of next line
mov cx,di
sub cx,bp ;length of the current line
mov bx,cx ;save in case it has a match
dec cx
dec cx ;CRLF characters discounted
jcxz try_again_opt ;if line empty go to next line
mov di,bp ;pointer to the beg. of current line
another_char:
;
; On entry:
; BX line length
; CX adjusted line length
; DX adjusted string argument length
; DI points to beg. of line
;
IF KANJI
push dx ;save for next line
lop:
pop dx
push dx
inc dx ;different algorithm!
mov si,offset st_buffer ;pointer to beg. of string argument
comp_next_char:
push di
mov di,si
call is_prefix ;check for a prefix char
pop di
jnc nopre
lodsw
cmp cx,1 ; Can not compare a two byte char
jz try_again_opt1 ; if there is only one available
cmp ax,word ptr [di]
jz kmatch1
call next_kchar ;no match, advance di to next kanji
jc try_again_opt1 ;not enough chars left in line
jmp short lop ;try another char in line
nopre:
lodsb
cmp al,byte ptr [di]
jz kmatch
call next_kchar ;no match, advance di to next kanji
jc try_again_opt1 ;not enough chars left in line
jmp short lop ;try another char in line
try_again_opt1:
pop dx
jmp try_again_opt
kmatch1:
dec dx ;last char had prefix so it was
; long.
kmatch:
dec dx
jz a_matchk ; no chars left: a match!
call next_kchar
jc try_again_opt1
jmp comp_next_char ; loop if chars left in arg.
a_matchk:
pop dx
ELSE
mov si,offset st_buffer ;pointer to beg. of string argument
lodsb ;get first character of the str. arg.
repnz scasb ;search for a match in current line
jnz try_again_opt ;no match, try the next line
cmp cx,dx ;compare lengths, a full match is not
jb try_again_opt ; possible if CX < DX.
push di ;save addrs. of next char. in the line
push cx ;save the # of chars. left in the line
mov cx,dx ;get the adjusted string arg. length
jcxz a_match ;if a single char string, then match!
repz cmpsb ;compare string with line
jz a_match ;a match found, hurrah!
pop cx ;no match, get # of chars remaining
; in the line.
pop di ;position of the next char. in the line
jmp another_char
;----- A MATCH: CHECK FOR THE v OPTION ------------------------------;
a_match:
pop ax ;adjust stack
pop ax
ENDIF
cmp ds:v_flg,0ffh ;is flag set?
jne prt_line ;no, print the line
jmp try_again
;----- NO MATCH: CHECK FOR THE v OPTION -----------------------------;
try_again_opt:
cmp ds:v_flg,0ffh ;is flag set?
jne try_again ;no goto next line
;----- PRINT THE LINE WITH THE MATCH --------------------------------;
;Note: at this point the stack contains (top to bottom)
; - Stuff mentioned before
;
; plus, BP points to begginig of the current line, BX has the length
;of the current line including the CRLF, and DX the adjusted length of
;the string argument.
prt_line:
cmp ds:c_flg,0ffh ;is count only flag set?
jne no_c_flg
inc ds:mtch_cntr ;yes, increment counter
jmp try_again
no_c_flg:
push dx ;save the adjusted string arg. length
cmp ds:n_flg,0ffh ;is line number flag set?
jne no_n_flg
call prt_lcntr
no_n_flg:
mov dx,bp
mov cx,bx
call prout
pop dx ;restore
jmp try_again
;----- READ MORE TEXT LINES INTO THE BUFFER -------------------------;
; The scanning routines have detected that the buffer does not
;contain a full line any more. More lines have to be read into the
;buffer. But first perform a seek on the file in order to re-read
;the non-complete line into the begining of the buffer.
; Uppon entry BP contains points to the begining of the non-complete
;line, and BX has the number of characters left in the buffer.
; The Stack contains (top to bottom):
; - Pointer to the next command in the command line
; - Pointer to the program segment prefix (to be loaded into
; DS to access the command line).
; - File handle.
more_stuff:
mov dx,bx ;get chars left in buffer
pop bx ;get the handle
or dx,dx ;are there 0 left?
jz no_seek ;yes, do not seek
neg dx ;form two's complement
mov cx,-1
mov al,1 ;seek from the current position
mov ah,lseek ;seek on file
int dos_ent
jc read_error
no_seek:
jmp refill ;no errors: refill the buffer
read_error:
cmp bx,std_in ;Using STD IN?
je foo ;if so: all done, exit
mov ah,close ;close the file
int dos_ent
mov dx,offset errmsg4_pre ;read error
mov cl,cs:errlen4_pre
call prt_file_name ;print the file name in error
mov dx,offset errmsg4_post ;read error
mov cl,cs:errlen4_post
jmp r_error
;----- PRINT ERRORS -------------------------------------------------;
open_error:
mov dx,offset errmsg3_pre ;error in open operation
mov cl,cs:errlen3_pre
call prt_err_2 ;print error message
call prt_file_name ;print the file name in error
mov dx,offset errmsg3_post ;error in open operation
mov cl,cs:errlen3_post
r_error:
call prt_err_2 ;print error message
;----- SCAN THE REST OF THE COMMAND LINE ----------------------------;
scan_rest:
pop ds ;restore pointer to comm. line
pop si ;restore pointer to next comm.
call kill_bl ;look for further args.
or bx,bx ;test for a CR
jnz foo
jmp further_args
foo:
mov al,0 ;Proper code
done:
mov ah,exit ;All done, exit with proper code.
int dos_ent
;--------------------------------------------------------------------;
; Get rid of blanks in command line. ;
; Advances the SI reg till the next non-blank character, if the ;
; character is a CR (0dh) then returns with BX non-zero, otherwise ;
; BX is zero. ;
; ;
; entry: ;
; SI points to the first character on the line to scan. ;
; ;
; exit: ;
; SI points to the first non-blank character found. ;
; BX contains 0D hex if the first non-blank found is ;
; a Carriage Return, otherwise it is 0. ;
; ;
; modifies: ;
; BX, SI, and AX ;
; ;
;--------------------------------------------------------------------;
kill_bl:
cld ;increment
xor bx,bx ;zero bx to start: no CR found
no_bl:
lodsb ;get rid of blanks
cmp al,' '
je no_bl
cmp al,CR
jnz no_cr
mov bx,ax ;make bx non-zero (actually 0dh)
no_cr:
dec si ;adjust pointer
ret
;--------------------------------------------------------------------;
; Clear Counters ;
;--------------------------------------------------------------------;
clr_cntrs:
mov byte ptr es:mtch_cntr,0
mov byte ptr es:line_cntr,0
ret
;--------------------------------------------------------------------;
; Print Count of Matched lines ;
; ;
; Modifies: AX,CX,DX and DI ;
;--------------------------------------------------------------------;
print_count:
push bx ;save handle
cmp bx,std_in ;using std_in?
jz sj3 ;if so do not print file name
mov dx,offset colon
mov cx,2
call prout ;print colon
sj3:
mov ax,ds:mtch_cntr
mov di,offset n2_buf ;buffer for characters
call bin2asc ;convert to ascii
mov dx,offset n2_buf
call prout ;print the number
mov dx,offset crlf
mov cx,2
call prout ;print an end of line
pop bx
ret
;--------------------------------------------------------------------;
; Print relative line number ;
; ;
; Modifies: AX,CX and DI ;
;--------------------------------------------------------------------;
prt_lcntr:
push bx
push dx
mov ax,ds:line_cntr
mov di,offset n2_buf
call bin2asc
mov byte ptr[di],"]"
inc cx
inc cx
mov dx,offset n1_buf
call prout
pop dx
pop bx
ret
;--------------------------------------------------------------------;
; Print string to STD_OUT ;
;--------------------------------------------------------------------;
prout:
mov bx,std_out
mov ah,write
int dos_ent
ret
;--------------------------------------------------------------------;
; Binary to Ascii conversion routine ;
; ;
; Entry: ;
; AX Binary number ;
; DI Points to one past the last char in the ;
; result buffer. ;
; ;
; Exit: ;
; Result in the buffer MSD first ;
; CX Digit count ;
; ;
; Modifies: ;
; AX,BX,CX,DX and DI ;
; ;
;--------------------------------------------------------------------;
bin2asc:
mov bx,0ah
xor cx,cx
go_div:
inc cx
cmp ax,bx
jb div_done
xor dx,dx
div bx
add dl,'0' ;convert to ASCII
push dx
jmp short go_div
div_done:
add al,'0'
push ax
mov bx,cx
deposit:
pop ax
stosb
loop deposit
mov cx,bx
ret
;--------------------------------------------------------------------;
; Print the current file name ;
; ;
; modifies: ;
; DX, CX, BX and AX ;
;--------------------------------------------------------------------;
prt_file_name:
mov dx,offset file_name_buf ;print the file name
mov cx,ds:file_name_len ;retrive file name length
jmp short prt_err_2
;--------------------------------------------------------------------;
; Print an error message to the Standart error ;
; ;
; entry: ;
; DX has the pointer to the message ;
; CX has the length of the message ;
; ;
; modifies: ;
; BX and AX ;
;--------------------------------------------------------------------;
prt_err:
push ds ;Save the current DS
push cs ;Make DS point to the right
pop ds ; place, for DOS use.
call prt_err_2
pop ds
ret
prt_err_2:
xor ch,ch
mov bx,std_err
mov ah,write
int dos_ent ;write error message
ret
;--------------------------------------------------------------------;
; CAPIALIZES THE CHARACTER IN AL ;
; ;
; entry: ;
; AL has the character to Capitalize ;
; ;
; exit: ;
; AL has the capitalized character ;
; ;
; modifies: ;
; AL ;
;--------------------------------------------------------------------;
make_caps:
cmp al,'a'
jb no_cap
cmp al,'z'
jg no_cap
and al,0dfh
no_cap:
ret
IF KANJI
;--------------------------------------------------------------------;
; ADVANCE POINTER TO NEXT KANJI CHARACTER ;
; ;
; entry: DI points to a Kanji string ;
; CX length in bytes of the string ;
; ;
; exit: DI points to next Kanji char ;
; CX has number of bytes left ;
; ;
; modifies: AX ;
; ;
;--------------------------------------------------------------------;
next_kchar:
jcxz no_kleft
call is_prefix
jnc no_p
inc di
dec cx
jcxz no_kleft ; for insurance
no_p:
inc di
dec cx
clc
ret
no_kleft:
stc
ret
;--------------------------------------------------------------------;
; FIND OUT IS THE BYTE IS A KANJI PREFIX ;
; ;
; entry: DI points to a kanji string ;
; ;
; exit: Carry set if it is a kanji prefix ;
; ;
; modifies: AX ;
; ;
;--------------------------------------------------------------------;
is_prefix:
mov al,byte ptr [di]
cmp al,81h
jb nok
cmp al,0a0h
jb isk
cmp al,0e0h
jb nok
cmp al,0fdh
jb isk
nok:
clc
ret
isk:
stc
ret
ENDIF
;----- PATCH AREA ---------------------------------------------------;
patch_area dw 100h dup(?)
;----- BUFFER AREA --------------------------------------------------;
st_length dw 0 ;String argumnet length
st_buffer db st_buf_size dup(?) ;String argument buffer
file_name_len dw 0 ;File name length
file_name_buf db fname_buf_size+1 dup(?) ;File name buffer,(allow for
; null at the end).
buffer db buffer_size+1 dup(?) ;file buffer, the last byte is
;a guard in case of forced insertion
;of a CRLF pair.
;----- ERROR MESSAGES -----------------------------------------------;
EXTRN bad_vers:byte,crlf:byte,errmsg1:byte,errlen1:byte,errmsg2:byte
EXTRN errmsg3_pre:byte,errlen3_pre:byte
EXTRN errmsg3_post:byte,errlen3_post:byte
EXTRN errmsg4_pre:byte,errlen4_pre:byte
EXTRN errmsg4_post:byte,errlen4_post:byte
EXTRN heading:byte,heading_len:byte,errlen2:byte
EXTRN errmsg5:byte,errmsg5_opt:byte,errlen5:byte
code ends
;----- STACK AREA ---------------------------------------------------;
stack segment stack
dw 64 dup(?,?)
stack_top equ $
stack ends
end start

BIN
v2.0/source/FINDMES.ASM Normal file

Binary file not shown.

1627
v2.0/source/FORMAT.ASM Normal file

File diff suppressed because it is too large Load Diff

393
v2.0/source/FORMAT.txt Normal file
View File

@ -0,0 +1,393 @@
FORMAT - formats a new disk, clears the FAT and DIRECTORY
and optionally copies the SYSTEM and COMMAND.COM to this
new disk.
Command syntax:
FORMAT [drive:][/switch1][/switch2]...[/switch16]
Where "drive:" is a legal drive specification and if
omitted indicates that the default drive will be used.
There may be up to 16 legal switches included in the
command line.
The OEM must supply five (NEAR) routines to the program
along with 6 data items. The names of the routines are INIT,
DISKFORMAT, BADSECTOR, WRTFAT and DONE, and their flow of
control (by the Microsoft module) is like this:
|
+---------+
| INIT |
+---------+
|
|<------------------------------+
+------------+ |
| DISKFORMAT | |
+------------+ |
|<-------+ |
+-----------+ |-This loop is done |- This loop done
| BADSECTOR | | for each group of | once for each disk
+-----------+ | bad sectors | to be formatted.
|----->--+ | If variable HARDFLAG
| | is set then the loop
+----------+ | is only performed
| | | once.
| WRTFAT | |
+----------+ |
| |
+------+ |
| DONE | |
+------+ |
+---->--------------------------+
The INIT, DISKFORMAT, and BADSECTOR routines are free
to use any MS-DOS system calls, except for calls that cause
disk accesses on the disk being formatted. DONE may use
ANY calls, since by the time it is called the new disk has
been formatted.
The following data must be declared PUBLIC in a module
provided by the OEM:
SWITCHLIST - A string of bytes. The first byte is count
N, followed by N characters which are the switches to
be accepted by the command line scanner. Alphabetic
characters must be in upper case (the numeric
characters 0-9 are allowed). The last three switches,
normally "O", "V" and "S", have pre-defined meanings.
The "S" switch is the switch which causes the
system files IO.SYS, MSDOS.SYS, and COMMAND.COM to be
transfered to the disk after it is formatted thus
making a "S"ystem disk. The switch can be some letter
other than "S", but the last switch in the list is
assumed to have the meaning "transfer system",
regardles of what the particular letter is.
The second to the last switch, "V", causes FORMAT
to prompt the user for a volume label after the disk
is formatted. Again, as with "S", the particular
letter is not important but rather the position in the
list.
The third to the last switch, "O", causes FORMAT to
produce an IBM Personal Computer DOS version 1.X
compatible disk. Normally FORMAT causes a 0 byte to
be placed in the first byte of each directory entry
instead of the 0E5 Hex free entry designator. This
results in a very marked directory search performance
increase due to an optimization in the DOS. Disks
made this way cause trouble on IBM PC DOS 1.X
versions, however, which did not have this
optimization. The 0 byte fools IBM 1.X versions into
thinking these entries are allocated instead of free,
NOTE that IBM Personnal Computer DOS version 2.00 and
MS-DOS version 1.25 will have no trouble with these
disks, since they have the same optimization. The "O"
switch causes FORMAT to re-do the directory with a 0E5
Hex byte at the start of each entry so that the disk
may be used with 1.X versions of IBM PC DOS, as well
as MS-DOS 1.25/2.00 and IBM PC DOS 2.00. This switch
should only be given when needed because it takes a
fair amount of time for FORMAT to perform the
conversion, and it noticably decreases 1.25 and 2.00
performance on disks with few directory entries.
Up to 16 switches are permitted. Normally a "C"
switch is specified for "Clear". This switch should
cause the formatting operation to be bypassed (within
DISKFORMAT or BADSECTOR). This is provided as a
time-saving convenience to the user, who may wish
to "start fresh" on a previosly formatted and used
disk.
HARDFLAG - BYTE location which specifies whether the
OEM routine is formatting a fixed disk or a a drive
with removable media. A zero indicates removable
media, any other value indicates a fixed disk. The
status of this byte only effect the messages printed
by the main format module. This value should be
set or reset by the OEM supplied INIT routine.
FATID - BYTE location containing the value to be used
in the first byte of the FAT. Must be in the range
F8 hex to FF hex.
STARTSECTOR - WORD location containing the sector number
of the first sector of the data area.
FATSPACE - WORD location containing the address of the
start of the FAT area. A FAT built in this area
will be written to disk using the OEM supplied WRTFAT
subroutine. 6k is sufficient to store any FAT. This
area must not overlap the FREESPACE area.
FREESPACE - WORD location which contains the address
of the start of free memory space. This is where
the system will be loaded, by the Microsoft module,
for transferring to the newly formatted disk. Memory
should be available from this address to the end
of memory, so it is typically the address of the
end of the OEM module.
The following routines must be declared PUBLIC in the
OEM-supplied module:
INIT - An initialization routine. This routine is called
once at the start of the FORMAT run after the switches
have been processed. This routine should perform
any functions that only need to be done once per
FORMAT run. An example of what this routine might
do is read the boot sector into a buffer so that
it can be transferred to the new disks by DISKFORMAT.
If this routine returns with the CARRY flag set it
indicates an error, and FORMAT will print "Format
failure" and quit. This feature can be used to detect
conflicting switches (like specifying both single
and double density) and cause FORMAT to quit without
doing anything.
DISKFORMAT - Formats the disk according to the options
indicated by the switches and the value of FATID
must be defined when it returns (although INIT may
have already done it). This routine is called once
for EACH disk to be formatted. If neccessary it
must transfer the Bootstrap loader. If any error
conditions are detected, set the CARRY flag and return
to FORMAT. FORMAT will report a 'Format failure'
and prompt for another disk. (If you only require
a clear directory and FAT then simply setting the
appropriate FATID, if not done by INIT, will be all
that DISKFORMAT must do.)
BADSECTOR - Reports the sector number of any bad sectors
that may have been found during the formatting of
the disk. This routine is called at least once for
EACH disk to be formatted, and is called repeatedly
until AX is zero or the carry flag is set. The carry
flag is used just as in DISKFORMAT to indicate an
error, and FORMAT handles it in the same way. The
first sector in the data area must be in STARTSECTOR
for the returns from this routine to be interpreted
correctly. If there are bad sectors, BADSECTOR must
return a sector number in in register BX, the number
of consecutive bad sectors in register AX, and carry
clear. FORMAT will then process the bad sectors
and call BADSECTOR again. When BADSECTOR returns
with AX = 0 this means there are no more bad sectors;
FORMAT clears the directory and goes on to DONE,
so for this last return BX need not contain anything
meaningful.
FORMAT processes bad sectors by determining their
corresponding allocation unit and marking that unit
with an FF7 hex in the File Allocation Table. CHKDSK
understands the FF7 mark as a flag for bad sectors
and accordingly reports the number of bytes marked
in this way.
NOTE: Actual formatting of the disk can be done in
BADSECTOR instead of DISKFORMAT on a "report as you
go" basis. Formatting goes until a group of bad
sectors is encountered, BADSECTOR then reports them
by returning with AX and BX set. FORMAT will then
call BADSECTOR again and formatting can continue.
WRTFAT - This routine is called after the disk is
formatted and bad sectors have been reported. Its
purpose is to write all copies of the FAT from the
area of memory referenced by FATSPACE to the drive
just formatted. It may be possible to use INT 26H
to perform the write, or a direct BIOS call. Whether
this is possible depends on whether the FAT ID byte
is used by the BIOS to determine the media in the
drive. If it is, these methods will probably fail
because there is no FAT ID byte on the disk yet (in
this case WRTFATs primary job is to get the FAT ID
byte out on the disk and thus solve the chicken and
egg problem).
DONE - This routine is called after the formatting is
complete, the disk directory has been initialized,
and the system has been transferred. It is called
once for EACH disk to be formatted. This gives the
chance for any finishing-up operations, if needed.
If the OEM desires certain extra files to be put
on the diskette by default, or according to a switch,
this could be done in DONE. Again, as in BADSECTOR
and DISKFORMAT, carry flag set on return means an
error has occurred: 'Format failure' will be printed
and FORMAT will prompt for another disk.
The following data is declared PUBLIC in Microsoft's FORMAT
module:
SWITCHMAP - A word with a bit vector indicating what
switches have been included in the command line. The
correspondence of the bits to the switches is
determined by SWITCHLIST. The right-most
(highest-addressed) switch in SWITCHLIST (which must
be the system transfer switch, normally "S")
corresponds to bit 0, the second from the right,
normally "V" to bit 1, etc. For example, if
SWITCHLIST is the string "7,'AGI2OVS'", and the user
specifies "/G/S" on the command line, then bit 6 will
be 0 (A not specified), bit 5 will be 1 (G specified),
bits 4,3,2 and 1 will be 0 (neither I,2,O or V
specified), and bit 0 will be 1 (S specified).
Bits 0,1 and 2 are the only switches used in
Microsoft's FORMAT module. These switches are used 1)
after INIT has been called, to determine if it is
necessary to load the system; 2) after the last
BADSECTOR call, to determine if the system is to be
written, E5 directory conversion is to be done, and/or
a volume label is to be asked for. INIT may force
these bits set or reset if desired (for example, some
drives may never be used as system disk, such as hard
disks). After INIT, the "S" bit may be turned off
(but not on, since the system was never read) if
something happens that means the system should not be
transferred.
After INIT, a second copy of SWITCHMAP is made
internally which is used to restore SWITCHMAP for
each disk to be formatted. FORMAT itself will turn
off the system bit if bad sectors are reported in
the system area; DISKFORMAT and BADSECTOR are also
allowed to change the map. However, these changes
affect only the current disk being formatted, since
SWITCHMAP is restored after each disk. (Changes
made to SWITCHMAP by INIT do affect ALL disks.)
DRIVE - A byte containing the drive specified in the
command line. 0=A, 1=B, etc.
Once the OEM-supplied module has been prepared, it must linked
with Microsoft's FORMAT.OBJ module and the FORMES.OBJ module.
If the OEM-supplied module is called OEMFOR.OBJ, then the
following linker command will do:
LINK FORMAT FORMES OEMFOR;
This command will produce a file called FORMAT.EXE. FORMAT
has been designed to run under MS-DOS as a simple binary
.COM file. This conversion is performed by LOCATE (EXE2BIN)
with the command
LOCATE FORMAT.EXE FORMAT.COM
which will produce the file FORMAT.COM.
;*****************************************
;
; A Sample OEM module
;
;*****************************************
CODE SEGMENT BYTE PUBLIC 'CODE'
; This segment must be
; named CODE, it must be
; PUBLIC, and it's
; classname must be 'CODE'
ASSUME CS:CODE,DS:CODE,ES:CODE
; Must declare data and routines PUBLIC
PUBLIC FATID,STARTSECTOR,SWITCHLIST,FREESPACE
PUBLIC INIT,DISKFORMAT,BADSECTOR,DONE,WRTFAT
PUBLIC FATSPACE,HARDFLAG
; This data defined in Microsoft-supplied module
EXTRN SWITCHMAP:WORD,DRIVE:BYTE
INIT:
; Read the boot sector into memory
CALL READBOOT
...
; Set FATID to double sided if "D" switch specified
TEST SWITCHMAP,10H
JNZ SETDBLSIDE
...
RET
DISKFORMAT:
...
; Use the bit map in SWITCHMAP to determine
; what switches are set
TEST SWITCHMAP,8 ;Is there a "/C"?
JNZ CLEAR ; Yes -- clear operation
; requested jump around the
; format code
< format the disk >
CLEAR:
...
; Transfer the boot from memory to the new disk
CALL TRANSBOOT
...
RET
; Error return - set carry
ERRET:
STC
RET
BADSECTOR:
...
RET
WRTFAT:
...
WRTFATLOOP:
< Set up call to write out a fat to disk>
...
MOV BX,[FATSPACE]
< Write out one fat to disk>
JC ERRET
...
< Decrement fat counter >
JNZ WRTFATLOOP
CLC ;Good return
RET
DONE:
...
RET
; Default Single sided
FATID DB 0FEH
HARDFLAG DB 0
STARTSECTOR DW 9
SWITCHLIST DB 5,"DCOVS" ; "OVS" must be the last
; switches in the list
FATSPACE DW FATBUF
FREESPACE DW ENDBOOT
BOOT DB BOOTSIZE DUP(?) ; Buffer for the
; boot sector
FATBUF DB 6 * 1024 DUP(?) ; Fat buffer
ENDBOOT LABEL BYTE
CODE ENDS
END

BIN
v2.0/source/FORMES.ASM Normal file

Binary file not shown.

BIN
v2.0/source/GENFOR.ASM Normal file

Binary file not shown.

627
v2.0/source/GETSET.ASM Normal file
View File

@ -0,0 +1,627 @@
TITLE GETSET - GETting and SETting MS-DOS system calls
NAME GETSET
;
; System Calls which get and set various things
;
; $GET_VERSION
; $GET_VERIFY_ON_WRITE
; $SET_VERIFY_ON_WRITE
; $SET_CTRL_C_TRAPPING
; $INTERNATIONAL
; $GET_DRIVE_FREESPACE
; $GET_DMA
; $SET_DMA
; $GET_DEFAULT_DRIVE
; $SET_DEFAULT_DRIVE
; $GET_INTERRUPT_VECTOR
; $SET_INTERRUPT_VECTOR
; RECSET
; $CHAR_OPER
;
.xlist
;
; get the appropriate segment definitions
;
INCLUDE DOSSEG.ASM
IFNDEF ALTVECT
ALTVECT EQU 0 ; FALSE
ENDIF
IFNDEF IBM
IBM EQU 0
ENDIF
CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME SS:DOSGROUP,CS:DOSGROUP
.xcref
INCLUDE DOSSYM.ASM
INCLUDE DEVSYM.ASM
.cref
.list
i_need VERFLG,BYTE
i_need CNTCFLAG,BYTE
i_need DMAADD,DWORD
i_need CURDRV,BYTE
i_need Current_Country,WORD
i_need international_table,BYTE
i_need INDOS,BYTE
i_need SYSINITVAR,WORD
i_need NUMIO,BYTE
i_need SWITCH_CHARACTER,BYTE
i_need DEVICE_AVAILABILITY,BYTE
USERNUM DW ? ; 24 bit user number
DB ?
IF IBM
OEMNUM DB 0 ; 8 bit OEM number
ELSE
OEMNUM DB 0FFH ; 8 bit OEM number
ENDIF
MSVERS EQU THIS WORD ; MS-DOS version in hex for $GET_VERSION
MSMAJOR DB DOS_MAJOR_VERSION
MSMINOR DB DOS_MINOR_VERSION
BREAK <$Get_Version -- Return MSDOS version number>
procedure $GET_VERSION,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; None
; Function:
; Return MS-DOS version number
; Outputs:
; OEM number in BH
; User number in BL:CX (24 bits)
; Version number as AL.AH in binary
; NOTE: On pre 1.28 DOSs AL will be zero
PUSH SS
POP DS
ASSUME DS:DOSGROUP
MOV BX,[USERNUM + 2]
MOV CX,[USERNUM]
MOV AX,[MSVERS]
invoke get_user_stack
ASSUME DS:NOTHING
MOV [SI.user_BX],BX
MOV [SI.user_CX],CX
MOV [SI.user_AX],AX ; Really only sets AH
return
$GET_VERSION ENDP
BREAK <$International - return country-dependent information>
;
; Inputs:
; DS:DX point to a block
; Function:
; give users an idea of what country the application is running
; Outputs:
; AX = number of bytes transferred
; DS:DX ->+---------------------------------+
; | WORD Date/time format |
; +---------------------------------+
; | BYTE ASCIZ currency symbol |
; +---------------------------------+
; | BYTE ASCIZ thousands separator |
; +---------------------------------+
; | BYTE ASCIZ decimal separator |
; +---------------------------------+
procedure $INTERNATIONAL,NEAR
ASSUME DS:NOTHING,ES:NOTHING
MOV BL,AL
PUSH DS
POP ES
PUSH DX
POP DI
PUSH SS
POP DS
ASSUME DS:DOSGROUP
CMP DI,-1
JZ international_set
OR BL,BL
JNZ international_find
MOV SI,[Current_Country]
MOV AX,WORD PTR [SI-2] ; Get size in AL, country code in AH
MOV BL,AH ; Set country code
JMP SHORT international_copy
international_find:
CALL international_get
JNC international_copy
error country_not_found
international_get:
MOV SI,OFFSET DOSGROUP:international_table
international_next:
LODSW ; Get size in AL, country code in AH
CMP AL,-1
JNZ check_code
STC
RET35:
RET
check_code:
CMP BL,AH
JZ RET35 ; Carry clear
XOR AH,AH
ADD SI,AX
JMP international_next
international_copy:
MOV CL,AL
XOR CH,CH
PUSH DI
REP MOVSB
POP DI
MOV WORD PTR ES:[DI.MAP_CALL + 2],CS ; Set segment for case map call
international_ok:
XOR AX,AX
MOV AL,BL ; Return country code in AX
transfer SYS_RET_OK
international_set:
CALL international_get
JNC international_store
error country_not_found
international_store:
MOV [Current_Country],SI
JMP international_ok
$INTERNATIONAL ENDP
BREAK <$Get_Verify_on_Write - return verify-after-write flag>
procedure $GET_VERIFY_ON_WRITE,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; none.
; Function:
; returns flag
; Returns:
; AL = value of VERIFY flag
MOV AL,[VERFLG]
return
$GET_VERIFY_ON_WRITE ENDP
BREAK <$Set_Verify_on_Write - Toggle verify-after-write flag>
procedure $SET_VERIFY_ON_WRITE,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; AL = desired value of VERIFY flag
; Function:
; Sets flag
; Returns:
; None
AND AL,1
MOV [VERFLG],AL
return
$SET_VERIFY_ON_WRITE ENDP
BREAK <$Set_CTRL_C_Trapping -- En/Disable ^C check in dispatcher>
procedure $SET_CTRL_C_TRAPPING,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; AL = 0 read ^C status
; AL = 1 Set ^C status, DL = 0/1 for ^C off/on
; Function:
; Enable disable ^C checking in dispatcher
; Outputs:
; If AL = 0 then DL = 0/1 for ^C off/on
OR AL,AL
JNZ CTRL_C_set
invoke get_user_stack
MOV AL,[CNTCFLAG]
MOV BYTE PTR [SI.user_DX],AL
return
CTRL_C_set:
DEC AL
JNZ bad_val
AND DL,01h
MOV [CNTCFLAG],DL
return
bad_val:
MOV AL,0FFH
return
$SET_CTRL_C_TRAPPING ENDP
BREAK <$Get_INDOS_Flag -- Return location of DOS critical-section flag>
procedure $GET_INDOS_FLAG,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; None
; Function:
; Returns location of DOS status for interrupt routines
; Returns:
; Flag location in ES:BX
invoke get_user_stack
MOV [SI.user_BX],OFFSET DOSGROUP:INDOS
MOV [SI.user_ES],SS
return
$GET_INDOS_FLAG ENDP
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
procedure $GET_IN_VARS,NEAR
; Return a pointer to interesting DOS variables This call is version
; dependent and is subject to change without notice in future versions.
; Use at risk.
invoke get_user_stack
MOV [SI.user_BX],OFFSET DOSGROUP:SYSINITVAR
MOV [SI.user_ES],SS
return
$GET_IN_VARS ENDP
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
BREAK <$Get_Drive_Freespace -- Return bytes of free disk space on a drive>
procedure $GET_DRIVE_FREESPACE,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; DL = Drive number
; Function:
; Return number of free allocation units on drive
; Outputs:
; BX = Number of free allocation units
; DX = Total Number of allocation units on disk
; CX = Sector size
; AX = Sectors per allocation unit
; = -1 if bad drive specified
; This call returns the same info in the same registers (except for FAT pointer)
; as the old FAT pointer calls
PUSH SS
POP DS
ASSUME DS:DOSGROUP
MOV AL,DL
invoke GETTHISDRV
MOV AX,-1
JC BADFRDRIVE
invoke FATREAD
XOR DX,DX
MOV BX,2
MOV CX,ES:[BP.dpb_max_cluster]
DEC CX
PUSH CX ; Save Total
SCANFREE:
invoke UNPACK
JNZ NOTFREECLUS
INC DX
NOTFREECLUS:
INC BX
LOOP SCANFREE
POP BX ; Remember Total
MOV AL,ES:[BP.dpb_cluster_mask]
INC AL
XOR AH,AH
MOV CX,ES:[BP.dpb_sector_size]
BADFRDRIVE:
invoke get_user_stack
ASSUME DS:NOTHING
MOV [SI. user_CX],CX
MOV [SI.user_DX],BX
MOV [SI.user_BX],DX
MOV [SI.user_AX],AX
return
$GET_DRIVE_FREESPACE ENDP
BREAK <$Get_DMA, $Set_DMA -- Get/Set current DMA address>
procedure $GET_DMA,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; None
; Function:
; Get DISK TRANSFER ADDRESS
; Returns:
; ES:BX is current transfer address
MOV BX,WORD PTR [DMAADD]
MOV CX,WORD PTR [DMAADD+2]
invoke get_user_stack
MOV [SI.user_BX],BX
MOV [SI.user_ES],CX
return
$GET_DMA ENDP
procedure $SET_DMA,NEAR ; System call 26
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; DS:DX is desired new disk transfer address
; Function:
; Set DISK TRANSFER ADDRESS
; Returns:
; None
MOV WORD PTR [DMAADD],DX
MOV WORD PTR [DMAADD+2],DS
return
$SET_DMA ENDP
BREAK <$Get_Default_DPB,$Get_DPB -- Return pointer to DPB>
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
procedure $GET_DEFAULT_DPB,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; DL = Drive number (always default drive for call 31)
; Function:
; Return pointer to drive parameter table for default drive
; Returns:
; DS:BX points to the DPB
; AL = 0 If OK, = -1 if bad drive (call 50 only)
MOV DL,0
entry $GET_DPB
PUSH SS
POP DS
ASSUME DS:DOSGROUP
MOV AL,DL
invoke GETTHISDRV
JC ISNODRV
invoke FATREAD
invoke get_user_stack
ASSUME DS:NOTHING
MOV [SI.user_BX],BP
MOV [SI.user_DS],ES
XOR AL,AL
return
ISNODRV:
MOV AL,-1
return
$GET_Default_dpb ENDP
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
BREAK <$Get_Default_Drive, $Set_Default_Drive -- Set/Get default drive>
procedure $GET_DEFAULT_DRIVE,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; None
; Function:
; Return current drive number
; Returns:
; AL = drive number
MOV AL,[CURDRV]
return
$GET_DEFAULT_DRIVE ENDP
procedure $SET_DEFAULT_DRIVE,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; DL = Drive number for new default drive
; Function:
; Set the default drive
; Returns:
; AL = Number of drives, NO ERROR RETURN IF DRIVE NUMBER BAD
MOV AL,[NUMIO]
CMP DL,AL
JNB RET17
MOV [CURDRV],DL
RET17: return
$SET_DEFAULT_DRIVE ENDP
BREAK <$Get_Interrupt_Vector - Get/Set interrupt vectors>
procedure $GET_INTERRUPT_VECTOR,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; AL = interrupt number
; Function:
; Get the interrupt vector
; Returns:
; ES:BX is current interrupt vector
CALL RECSET
LES BX,DWORD PTR ES:[BX]
invoke get_user_stack
MOV [SI.user_BX],BX
MOV [SI.user_ES],ES
return
$GET_INTERRUPT_VECTOR ENDP
procedure $SET_INTERRUPT_VECTOR,NEAR ; System call 37
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; AL = interrupt number
; DS:DX is desired new interrupt vector
; Function:
; Set the interrupt vector
; Returns:
; None
CALL RECSET
MOV ES:[BX],DX
MOV ES:[BX+2],DS
return
$SET_INTERRUPT_VECTOR ENDP
IF ALTVECT
VECIN: ; INPUT VECTORS
DB 22H ; Terminate
DB 23H ; ^C
DB 24H ; Hard error
DB 28H ; Spooler
LSTVEC DB ? ; ALL OTHER
VECOUT: ; GET MAPPED VECTOR
DB int_terminate
DB int_ctrl_c
DB int_fatal_abort
DB int_spooler
LSTVEC2 DB ? ; Map to itself
NUMVEC = VECOUT-VECIN
ENDIF
procedure RECSET,NEAR
IF ALTVECT
PUSH SS
POP ES
MOV [LSTVEC],AL ; Terminate list with real vector
MOV [LSTVEC2],AL ; Terminate list with real vector
MOV CX,NUMVEC ; Number of possible translations
MOV DI,OFFSET DOSGROUP:VECIN ; Point to vectors
REPNE SCASB
MOV AL,ES:[DI+NUMVEC-1] ; Get translation
ENDIF
XOR BX,BX
MOV ES,BX
MOV BL,AL
SHL BX,1
SHL BX,1
return
recset ENDP
BREAK <$Char_Oper - hack on paths, switches so that xenix can look like PCDOS>
;
; input: AL = function:
; 0 - read switch char
; 1 - set switch char (char in DL)
; 2 - read device availability
; 3 - set device availability (0/FF in DL)
; DL = 0 means /DEV/ must preceed device names
; DL = Non0 means /DEV/ need not preeceed
; output: (get) DL - character/flag
;
procedure $CHAR_OPER,NEAR
ASSUME DS:NOTHING,ES:NOTHING
PUSH SS
POP DS
ASSUME DS:DOSGROUP
OR AL,AL
JNZ char_oper_set_switch
MOV DL,[switch_character]
JMP SHORT char_oper_ret
char_oper_set_switch:
DEC AL
JNZ char_oper_read_avail
MOV [switch_character],DL
return
char_oper_read_avail:
DEC AL
JNZ char_oper_set_avail
MOV DL,[device_availability]
JMP SHORT char_oper_ret
char_oper_set_avail:
DEC AL
JNZ char_oper_bad_ret
MOV [device_availability],DL
return
char_oper_bad_ret:
MOV AL,0FFh
return
char_oper_ret:
invoke get_user_stack
MOV [SI.user_DX],DX
return
$CHAR_OPER ENDP
BREAK <$SetDPB - Create a valid DPB from a user-specified BPB>
procedure $SETDPB,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; ES:BP Points to DPB
; DS:SI Points to BPB
; Function:
; Build a correct DPB from the BPB
; Outputs:
; ES:BP and DS preserved all others destroyed
MOV DI,BP
ADD DI,2 ; Skip over dpb_drive and dpb_UNIT
LODSW
STOSW ; dpb_sector_size
MOV DX,AX
LODSB
DEC AL
STOSB ; dpb_cluster_mask
INC AL
XOR AH,AH
LOG2LOOP:
TEST AL,1
JNZ SAVLOG
INC AH
SHR AL,1
JMP SHORT LOG2LOOP
SAVLOG:
MOV AL,AH
STOSB ; dpb_cluster_shift
MOV BL,AL
MOVSW ; dpb_first_FAT Start of FAT (# of reserved sectors)
LODSB
STOSB ; dpb_FAT_count Number of FATs
MOV BH,AL
LODSW
STOSW ; dpb_root_entries Number of directory entries
MOV CL,5
SHR DX,CL ; Directory entries per sector
DEC AX
ADD AX,DX ; Cause Round Up
MOV CX,DX
XOR DX,DX
DIV CX
MOV CX,AX ; Number of directory sectors
INC DI
INC DI ; Skip dpb_first_sector
MOVSW ; Total number of sectors in DSKSIZ (temp as dpb_max_cluster)
LODSB
MOV ES:[BP.dpb_media],AL ; Media byte
LODSW ; Number of sectors in a FAT
STOSB ; dpb_FAT_size
MUL BH ; Space occupied by all FATs
ADD AX,ES:[BP.dpb_first_FAT]
STOSW ; dpb_dir_sector
ADD AX,CX ; Add number of directory sectors
MOV ES:[BP.dpb_first_sector],AX
SUB AX,ES:[BP.DSKSIZ]
NEG AX ; Sectors in data area
MOV CL,BL ; dpb_cluster_shift
SHR AX,CL ; Div by sectors/cluster
INC AX
MOV ES:[BP.dpb_max_cluster],AX
MOV ES:[BP.dpb_current_dir],0 ; Current directory is root
return
$SETDPB ENDP
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
do_ext
CODE ENDS
END

501
v2.0/source/HRDDRV.ASM Normal file
View File

@ -0,0 +1,501 @@
TITLE HRDDRV.SYS for the ALTOS ACS-86C.
; Hard Disk Drive for Version 2.x of MSDOS.
; Constants for commands in Altos ROM.
ROM_CONSTA EQU 01 ;Return status AL of console selected in CX.
ROM_CONIN EQU 02 ;Get char. from console in CX to AL
ROM_CONOUT EQU 03 ;Write char. in DL to console in CX.
ROM_PMSG EQU 07 ;Write string ES:DX to console in CX.
ROM_DISKIO EQU 08 ;Perform disk I/O from IOPB in ES:CX.
ROM_INIT EQU 10 ;Returns boot console and top memory ES:DX.
CODE SEGMENT
ASSUME CS:CODE,DS:CODE,ES:CODE,SS:CODE
ORG 0 ;Starts at an offset of zero.
PAGE
SUBTTL Device driver tables.
;-----------------------------------------------+
; DWORD pointer to next device | 1 word offset.
; (-1,-1 if last device) | 1 word segement.
;-----------------------------------------------+
; Device attribute WORD ; 1 word.
; Bit 15 = 1 for chacter devices. ;
; 0 for Block devices. ;
; ;
; Charcter devices. (Bit 15=1) ;
; Bit 0 = 1 current sti device. ;
; Bit 1 = 1 current sto device. ;
; Bit 2 = 1 current NUL device. ;
; Bit 3 = 1 current Clock device. ;
; ;
; Bit 13 = 1 for non IBM machines. ;
; 0 for IBM machines only. ;
; Bit 14 = 1 IOCTL control bit. ;
;-----------------------------------------------+
; Device strategy pointer. ; 1 word offset.
;-----------------------------------------------+
; Device interrupt pointer. ; 1 word offset.
;-----------------------------------------------+
; Device name field. ; 8 bytes.
; Character devices are any valid name ;
; left justified, in a space filled ;
; field. ;
; Block devices contain # of units in ;
; the first byte. ;
;-----------------------------------------------+
DSKDEV: ;Header for hard disk driver.
DW -1,-1 ;Last device
DW 2000H ;Is a block device
DW STRATEGY
DW DSK_INT
MEMMAX DB 1 ;Number of Units
PAGE
SUBTTL Dispatch tables for each device.
DSK_TBL:DW DSK_INI ;0 - Initialize Driver.
DW MEDIAC ;1 - Return current media code.
DW GET_BPB ;2 - Get Bios Parameter Block.
DW CMDERR ;3 - Reserved. (currently returns error)
DW DSK_RED ;4 - Block read.
DW BUS_EXIT ;5 - (Not used, return busy flag)
DW EXIT ;6 - Return status. (Not used)
DW EXIT ;7 - Flush input buffer. (Not used.)
DW DSK_WRT ;8 - Block write.
DW DSK_WRV ;9 - Block write with verify.
DW EXIT ;10 - Return output status.
DW EXIT ;11 - Flush output buffer. (Not used.)
DW EXIT ;12 - IO Control.
PAGE
SUBTTL Strategy and Software Interrupt routines.
;Define offsets for io data packet
IODAT STRUC
CMDLEN DB ? ;LENGTH OF THIS COMMAND
UNIT DB ? ;SUB UNIT SPECIFIER
CMD DB ? ;COMMAND CODE
STATUS DW ? ;STATUS
DB 8 DUP (?)
MEDIA DB ? ;MEDIA DESCRIPTOR
TRANS DD ? ;TRANSFER ADDRESS
COUNT DW ? ;COUNT OF BLOCKS OR CHARACTERS
START DW ? ;FIRST BLOCK TO TRANSFER
IODAT ENDS
PTRSAV DD 0 ;Strategy pointer save.
;
; Simplistic Strategy routine for non-multi-Tasking system.
;
; Currently just saves I/O packet pointers in PTRSAV for
; later processing by the individual interrupt routines.
;
STRATP PROC FAR
STRATEGY:
MOV WORD PTR CS:[PTRSAV],BX
MOV WORD PTR CS:[PTRSAV+2],ES
RET
STRATP ENDP
;
; Ram memory driver interrupt routine for processing I/O packets.
;
DSK_INT:
PUSH SI ;Save SI from caller.
MOV SI,OFFSET DSK_TBL
;
; Common program for handling the simplistic I/O packet
; processing scheme in MSDOS 2.0
;
ENTRY: PUSH AX ;Save all nessacary registers.
PUSH CX
PUSH DX
PUSH DI
PUSH BP
PUSH DS
PUSH ES
PUSH BX
LDS BX,CS:[PTRSAV] ;Retrieve pointer to I/O Packet.
MOV AL,[BX.UNIT] ;AL = Unit code.
MOV AH,[BX.MEDIA] ;AH = Media descriptor.
MOV CX,[BX.COUNT] ;CX = Contains byte/sector count.
MOV DX,[BX.START] ;DX = Starting Logical sector.
XCHG DI,AX ;Save Unit and Media Temporarily.
MOV AL,[BX.CMD] ;Retrieve Command type. (1 => 11)
XOR AH,AH ;Clear upper half of AX for calculation.
ADD SI,AX ;Compute entry pointer in dispatch table.
ADD SI,AX
CMP AL,11 ;Verify that not more than 11 commands.
JA CMDERR ;Ah, well, error out.
XCHG AX,DI
LES DI,[BX.TRANS] ;DI contains addess of Transfer address.
;ES contains segment.
PUSH CS
POP DS ;Data segment same as Code segment.
JMP [SI] ;Perform I/O packet command.
PAGE
SUBTTL Common error and exit points.
BUS_EXIT: ;Device busy exit.
MOV AH,00000011B ;Set busy and done bits.
JMP SHORT EXIT1
CMDERR: MOV AL,3 ;Set unknown command error #.
;
; Common error processing routine.
; AL contains actual error code.
;
; Error # 0 = Write Protect violation.
; 1 = Unkown unit.
; 2 = Drive not ready.
; 3 = Unknown command in I/O packet.
; 4 = CRC error.
; 5 = Bad drive request structure length.
; 6 = Seek error.
; 7 = Unknown media discovered.
; 8 = Sector not found.
; 9 = Printer out of paper.
; 10 = Write fault.
; 11 = Read fault.
; 12 = General failure.
;
ERR_EXIT:
MOV AH,10000001B ;Set error and done bits.
STC ;Set carry bit also.
JMP SHORT EXIT1 ;Quick way out.
EXITP PROC FAR ;Normal exit for device drivers.
EXIT: MOV AH,00000001B ;Set done bit for MSDOS.
EXIT1: LDS BX,CS:[PTRSAV]
MOV [BX.STATUS],AX ;Save operation compete and status.
POP BX ;Restore registers.
POP ES
POP DS
POP BP
POP DI
POP DX
POP CX
POP AX
POP SI
RET ;RESTORE REGS AND RETURN
EXITP ENDP
PAGE
subttl Hard Disk drive control.
;
; Read command = 09 hex.
; Write command = 02 hex.
; Seek command = 10 hex.
; Recal command = 20 hex.
; Rezero command = 40 hex.
; Reset command = 80 hex.
;
; Busy = 01 hex.
; Operation Complete = 02 hex.
; Bad Sector = 04 hex.
; Record Not found = 08 hex.
; CRC error = 10 hex.
; (not used) = 20 hex.
; Write fault = 40 hex.
; Drive Ready = 80 hex.
;
hd_read equ 09h
hd_writ equ 02h
hd_wmsk equ 5dh
hd_rmsk equ 9ch
page
SUBTTL Altos monitor ram and 8089 IOPB structures.
;
; Structure to reference 8089 and ROM command table.
;
SIOPB STRUC
DB 4 DUP (?) ;Monitor Use Only
OPCODE DB ? ;I/O operation code.
DRIVE DB ? ;Logical drive spec.
TRACK DW ? ;Logical track number.
HEAD DB ? ;Logical head number.
SECTOR DB ? ;Logical sector to start with.
SCOUNT DB ? ;Number of logical sectors in buffer.
RETCODE DB ? ;Error code after masking.
RETMASK DB ? ;Error mask.
RETRIES DB ? ;Number of retries before error exit.
DMAOFF DW ? ;Buffer offset address.
DMASEG DW ? ;Buffer segment.
SECLENG DW ? ;Sector Length.
DB 6 DUP (?) ;8089 use only.
SIOPB ENDS
IOPB SIOPB <,0,0,0,0,0,0,0,0,0,0,0,0,>
PAGE
SUBTTL Common Drive parameter block definitions on Altos.
DBP STRUC
JMPNEAR DB 3 DUP (?) ;Jmp Near xxxx for boot.
NAMEVER DB 8 DUP (?) ;Name / Version of OS.
;------- Start of Drive Parameter Block.
SECSIZE DW ? ;Sector size in bytes. (dpb)
ALLOC DB ? ;Number of sectors per alloc. block. (dpb)
RESSEC DW ? ;Reserved sectors. (dpb)
FATS DB ? ;Number of FAT's. (dpb)
MAXDIR DW ? ;Number of root directory entries. (dpb)
SECTORS DW ? ;Number of sectors per diskette. (dpb)
MEDIAID DB ? ;Media byte ID. (dpb)
FATSEC DW ? ;Number of FAT Sectors. (dpb)
;------- End of Drive Parameter Block.
SECTRK DW ? ;Number of Sectors per track.
HEADS DW ? ;Number of heads per cylinder.
HIDDEN DW ? ;Number of hidden sectors.
DBP ENDS
HDDRIVE DBP <,,512,4,0,2,256,4000,0F5H,3,12,4,0>
INI_TAB DW OFFSET HDDRIVE.SECSIZE
PAGE
SUBTTL Media check routine
;
; Media check routine.
; On entry:
; AL = memory driver unit number.
; AH = media byte
; On exit:
;
; [MEDIA FLAG] = -1 (FF hex) if disk is changed.
; [MEDIA FLAG] = 0 if don't know.
; [MEDIA FLAG] = 1 if not changed.
;
MEDIAC: LDS BX,CS:[PTRSAV]
MOV BYTE PTR [BX.TRANS],1
JMP EXIT
PAGE
SUBTTL Build and return Bios Parameter Block for a diskette.
;
; Build Bios Parameter Blocks.
;
; On entry: ES:BX contains the address of a scratch sector buffer.
; AL = Unit number.
; AH = Current media byte.
;
; On exit: Return a DWORD pointer to the associated BPB
; in the Request packet.
;
GET_BPB:
MOV SI,OFFSET HDDRIVE+11
LDS BX,CS:[PTRSAV]
MOV WORD PTR [BX.COUNT],SI
MOV WORD PTR [BX.COUNT+2],CS
JMP EXIT
PAGE
SUBTTL MSDOS 2.x Disk I/O drivers.
;
; Disk READ/WRITE functions.
;
; On entry:
; AL = Disk I/O driver number
; AH = Media byte.
; ES = Disk transfer segment.
; DI = Disk transfer offset in ES.
; CX = Number of sectors to transfer
; DX = Logical starting sector.
;
; On exit:
; Normal exit through common exit routine.
;
; Abnormal exit through common error routine.
;
DSK_RED:
MOV AH,HD_READ
JMP SHORT DSK_COM
DSK_WRV:
DSK_WRT:
MOV AH,HD_WRIT
DSK_COM:
MOV SI,OFFSET HDDRIVE ;Keeps code size down.
MOV [IOPB.DMASEG],ES
MOV [IOPB.DMAOFF],DI
MOV DI,[SI.SECSIZE]
MOV [IOPB.SECLENG],DI
MOV [IOPB.RETRIES],1
MOV [IOPB.RETMASK],05DH ;Error return mask.
MOV [IOPB.OPCODE],AH
MOV [IOPB.DRIVE],4 ;Drive 4 is only available.
ADD DX,[SI.HIDDEN] ;Account for invisible sectors.
MOV BP,CX ;Save number of sectors to R/W
DSK_IO1:
PUSH DX ;Save starting sector.
MOV AX,DX
MOV DX,0 ;32 bit divide coming up.
MOV CX,[SI.SECTRK]
DIV CX ;Get track+head and start sector.
MOV [IOPB.SECTOR],DL ;Starting sector.
MOV BL,DL ;Save starting sector for later.
MOV DX,0
MOV CX,[SI.HEADS]
DIV CX ;Compute head we are on.
MOV [IOPB.HEAD],DL
MOV [IOPB.TRACK],AX ;Track to read/write.
MOV AX,[SI.SECTRK] ;Now see how many sectors
INC AL ; we can burst read.
SUB AL,BL ;BL is the starting sector.
MOV AH,0
POP DX ;Retrieve logical sector start.
CMP AX,BP ;See if on last partial track+head.
JG DSK_IO2 ;Yes, on last track+head.
SUB BP,AX ;No, update number of sectors left.
ADD DX,AX ;Update next starting sector.
JMP SHORT DSK_IO3
DSK_IO2:MOV AX,BP ;Only read enough of sector
MOV BP,0 ;to finish buffer and clear # left.
DSK_IO3:MOV [IOPB.SCOUNT],AL
MOV DI,AX ;Save number sectors for later.
MOV BX,ROM_DISKIO
MOV CX,OFFSET IOPB
PUSH CS
POP ES
CALL ROM_CALL ;Do disk operation.
MOV AL,[IOPB.RETCODE] ;Get error code.
OR AL,AL
JNZ DERROR
MOV AX,DI ;Retrieve number of sectors read.
MOV CX,[SI.SECSIZE] ;Number of bytes per sector.
PUSH DX
MUL CX
POP DX
TEST AL,0FH ;Make sure no strange sizes.
JNZ SERR1
MOV CL,4
SHR AX,CL ;Convert number of bytes to para.
ADD AX,[IOPB.DMASEG]
MOV [IOPB.DMASEG],AX
OR BP,BP
JNZ DSK_IO1 ;Still more to do.
MOV AL,0
JMP EXIT ;All done.
SERR1: MOV AL,12
JMP ERR_EXIT
PAGE
SUBTTL Disk Error processing.
;
; Disk error routine.
;
DERROR:
LDS BX,CS:[PTRSAV]
MOV [BX.COUNT],0
PUSH CS
POP DS
MOV BL,-1
MOV AH,AL
MOV BH,14 ;Lenght of table.
MOV SI,OFFSET DERRTAB
DERROR2:INC BL ;Increment to next error code.
LODS BYTE PTR CS:[SI]
CMP AH,AL ;See if error code matches disk status.
JZ DERROR3 ;Got the right error, exit.
DEC BH
JNZ DERROR2 ;Keep checking table.
MOV BL,12 ;Set general type of error.
DERROR3:MOV AL,BL ;Now we've got the code.
JMP ERR_EXIT
DERRTAB DB 00H ; 0. Write protect error
DB 00H ; 1. Unknown unit.
DB 00H ; 2. Not ready error.
DB 00H ; 3. Unknown command.
DB 10H ; 4. CRC error
DB 00H ; 5. Bad drive request.
DB 00H ; 6. Seek error
DB 00H ; 7. Unknown media.
DB 08H ; 8. Sector not found
DB 00H ; 9. (Not used.)
DB 40H ;10. Write fault.
DB 04H ;11. Read fault.
DB 01H ;12. General type of failure.
PAGE
SUBTTL Common ROM call routine.
;
; Save all registers except CX, BX and AX.
ROMRTN DD 0FE000000H ;Main ROM entry point.
ROM_CALL:
PUSH DI
PUSH SI
PUSH BP
PUSH DX
PUSH ES
CALL CS:DWORD PTR [ROMRTN]
POP ES
POP DX
POP BP
POP SI
POP DI
RET
PAGE
SUBTTL Hard Disk Drive initalization routine.
DSK_INI:
LDS BX,CS:[PTRSAV]
MOV BYTE PTR [BX.MEDIA],1
MOV WORD PTR [BX.TRANS],OFFSET DSK_INI
MOV WORD PTR [BX.TRANS+2],CS
MOV WORD PTR [BX.COUNT],OFFSET INI_TAB
MOV WORD PTR [BX.COUNT+2],CS
JMP EXIT
CODE ENDS
END


18
v2.0/source/IFEQU.ASM Normal file
View File

@ -0,0 +1,18 @@
;*************************************
; COMMAND EQUs which are switch dependant
IF1
IF IBM
%OUT IBM version
ELSE
%OUT Normal version
ENDIF
IF HIGHMEM
%OUT Highmem version
ENDIF
IF KANJI
%OUT Kanji version
ENDIF
ENDIF

BIN
v2.0/source/INCOMP.txt Normal file

Binary file not shown.

939
v2.0/source/INIT.ASM Normal file
View File

@ -0,0 +1,939 @@
TITLE COMMAND Initialization
INCLUDE COMSW.ASM
.xlist
.xcref
INCLUDE DOSSYM.ASM
INCLUDE DEVSYM.ASM
INCLUDE COMSEG.ASM
.list
.cref
INCLUDE COMEQU.ASM
ENVIRONSIZ EQU 0A0H ;Must agree with values in EVIRONMENT segment
ENVIRONSIZ2 EQU 092H
CODERES SEGMENT PUBLIC
EXTRN RSTACK:WORD,SETVECT:NEAR,LODCOM:NEAR,CONTC:NEAR,INT_2E:NEAR
EXTRN LOADCOM:NEAR,CHKSUM:NEAR
IF IBMVER
EXTRN EXECHK:NEAR,SYSCALL:NEAR
ENDIF
CODERES ENDS
DATARES SEGMENT PUBLIC
EXTRN DATARESEND:BYTE,LTPA:WORD,MYSEG:WORD,MYSEG1:WORD,MYSEG2:WORD
EXTRN MEMSIZ:WORD,TRNSEG:WORD,ENVIRSEG:WORD,RSWITCHAR:BYTE
EXTRN COMDRV:BYTE,COMLET:BYTE,PERMCOM:BYTE,SINGLECOM:WORD
EXTRN PARENT:WORD,IO_SAVE:WORD,COM_PTR:DWORD,COM_FCB1:DWORD
EXTRN COM_FCB2:DWORD,SUM:WORD,BATCH:WORD,COMSPEC:BYTE
IF IBMVER
EXTRN SYS_CALL:DWORD,EXESEG:WORD,EXESUM:WORD
ENDIF
DATARES ENDS
ENVIRONMENT SEGMENT PUBLIC
EXTRN ENVIREND:BYTE,PATHSTRING:BYTE,ECOMSPEC:BYTE
ENVIRONMENT ENDS
TRANCODE SEGMENT PUBLIC
EXTRN DATINIT:FAR
TRANCODE ENDS
TRANSPACE SEGMENT PUBLIC
EXTRN TRANSPACEEND:BYTE
TRANSPACE ENDS
ZEXEC_DATA SEGMENT PUBLIC
IF IBM
EXTRN ZEXECDATAEND:BYTE
ENDIF
ZEXEC_DATA ENDS
; *******************************************************************
; START OF INIT PORTION
; This code is overlayed the first time the TPA is used.
INIT SEGMENT PUBLIC PARA
EXTRN HEADER:BYTE
EXTRN BADCOMLKMES:BYTE
PUBLIC CONPROC
ASSUME CS:RESGROUP,DS:RESGROUP,ES:RESGROUP,SS:RESGROUP
ORG 0
ZERO = $
CONPROC:
MOV SP,OFFSET RESGROUP:RSTACK
IF HIGHMEM
MOV BX,WORD PTR DS:[PDB_block_len]
MOV AX,OFFSET RESGROUP:ENVIREND + 15
MOV CL,4
SHR AX,CL
PUSH AX ; Save size to alloc
INC AX ; Plus one for arena
SUB BX,AX ; Subtract size of resident
MOV WORD PTR DS:[PDB_block_len],BX
MOV AX,CS
SUB BX,AX
MOV AH,SETBLOCK
INT 21H
POP BX ; Get back size to alloc
MOV AH,ALLOC
INT 21H
MOV [REALRES],AX
MOV ES,AX
XOR SI,SI
MOV DI,SI
MOV CX,OFFSET RESGROUP:ENVIREND
SHR CX,1 ; Length of resident and environment in words
; Last byte doesn't matter
REP MOVSW ; Move to end of memory
MOV DS,AX
MOV BX,AX
MOV AH,SET_CURRENT_PDB
INT 21H
MOV AX,BX
MOV BX,OFFSET RESGROUP:DATARESEND + 15
MOV CL,4
SHR BX,CL ; BX is size for SETBLOCK
MOV WORD PTR DS:[PDB_block_len],BX
ADD WORD PTR DS:[PDB_block_len],AX
MOV [LTPA],CS
MOV AH,SETBLOCK
INT 21H ;Shrink to not include environment
MOV BX,(ENVIRONSIZ + 15) / 16
MOV AH,ALLOC
INT 21H ;Allocate the environment
MOV [ENVIRSEG],AX
MOV CS:[ENVIRSEGSAV],AX
MOV ES,AX
ASSUME ES:ENVIRONMENT
XOR DI,DI
MOV SI,OFFSET RESGROUP:PATHSTRING
MOV CX,ENVIRONSIZ
REP MOVSB
MOV AX,WORD PTR CS:[PDB_block_len]
ENDIF
IF NOT HIGHMEM
MOV AX,OFFSET RESGROUP:ENVIREND + 15
MOV CL,4
SHR AX,CL
MOV CX,CS
ADD AX,CX ; Compute segment of TPA
MOV [LTPA],AX ; Good enough for the moment
MOV AX,WORD PTR DS:[PDB_block_len]
ENDIF
MOV [MYSEG1],DS
MOV [MYSEG2],DS
MOV [MYSEG],DS
MOV [MEMSIZ],AX
MOV DX,OFFSET TRANGROUP:TRANSPACEEND + 15
MOV CL,4
SHR DX,CL
IF IBM
PUSH DX
MOV DX,OFFSET EGROUP:ZEXECDATAEND + 15
MOV CL,4
SHR DX,CL
POP CX
ADD DX,CX
ENDIF
SUB AX,DX
MOV [TRNSEG],AX ; Read it in here
MOV AX,DS:[PDB_environ]
OR AX,AX
JZ BUILDENV ; Need to make an environment
IF HIGHMEM
INC BYTE PTR CS:[CHUCKENV] ; Flag no ENVIRONSEG
ELSE
INC BYTE PTR [CHUCKENV] ; Flag no ENVIRONSEG
ENDIF
JMP SHORT ENVIRONPASSED
BUILDENV:
IF NOT HIGHMEM
MOV AX,OFFSET RESGROUP:PATHSTRING ; Figure environment pointer
MOV CL,4
SHR AX,CL
MOV DX,DS
ADD AX,DX
ELSE
JMP SHORT GOTTHEENVIR
ENDIF
ENVIRONPASSED:
MOV [ENVIRSEG],AX
IF HIGHMEM
DEC AX
MOV ES,AX
INC AX
MOV ES:[arena_owner],DS ; Adjust owner of passed envir
ENDIF
MOV ES,AX
ASSUME ES:ENVIRONMENT
GOTTHEENVIR:
MOV AX,CHAR_OPER SHL 8
INT int_command
MOV [RSWITCHAR],DL
CMP DL,'/'
JNZ IUSESLASH
IF HIGHMEM
MOV CS:[COMSPECT],'\'
ELSE
MOV [COMSPECT],'\'
ENDIF
IF HIGHMEM
CMP BYTE PTR CS:[CHUCKENV],0
ELSE
CMP BYTE PTR [CHUCKENV],0
ENDIF
JNZ IUSESLASH
MOV ES:[ECOMSPEC-10H],'\'
IUSESLASH:
IF IBMVER
PUSH ES
MOV AX,(Get_interrupt_vector SHL 8) + int_command
INT int_command
MOV WORD PTR [SYS_CALL],BX
MOV WORD PTR [SYS_CALL+2],ES
MOV DX,OFFSET RESGROUP:SYSCALL
MOV AX,(Set_interrupt_vector SHL 8) + int_command
INT int_command
POP ES
ENDIF
MOV AL,BYTE PTR DS:[FCB] ; get drive spec for default
MOV AH,DRVCHAR
MOV [COMDRV],AL
ADD AL,40H ; Convert to letter
CMP AL,40H
JZ NOCOMDRV
STD
IF HIGHMEM
CMP BYTE PTR CS:[CHUCKENV],0
ELSE
CMP BYTE PTR [CHUCKENV],0
ENDIF
JNZ NOTWIDENV
PUSH DS
PUSH ES
POP DS
MOV DI,OFFSET ENVIRONMENT:ECOMSPEC + ENVIRONSIZ2 - 1 - 10H
MOV SI,OFFSET ENVIRONMENT:ECOMSPEC + ENVIRONSIZ2 - 3 - 10H
MOV CX,ENVIRONSIZ2 - 2
REP MOVSB
POP DS
MOV WORD PTR ES:[ECOMSPEC-10H],AX
NOTWIDENV:
CLD
IF HIGHMEM
MOV WORD PTR CS:[AUTOBAT],AX
ELSE
MOV WORD PTR [AUTOBAT],AX
ENDIF
MOV [COMLET],AL
NOCOMDRV:
CALL SETVECT ; Set the vectors
MOV SI,80H
LODSB
MOV CL,AL
XOR CH,CH
JCXZ COMRETURNSJ ; No parameters
MOV SI,81H ; Start of parms
CHKARG:
LODSB
CMP AL,' '
JZ NEXTCH
CMP AL,9 ; Tab only other delimiter
JZ NEXTCH
CMP AL,[RSWITCHAR] ; Switch?
JNZ CHKOTHERARGS ; No
DEC CX
JCXZ ARGSDONEJ ; oops
LODSB
OR AL,20H ; Lower case
CMP AL,'p' ; PERMCOM switch
JNZ NEXTCH
JMP SETPERM
NEXTCH:
CMP AL,'d'
JNZ NEXTCH3
IF HIGHMEM
MOV BYTE PTR CS:[PRDATTM],1 ; User explicitly says no date time
ELSE
MOV BYTE PTR [PRDATTM],1 ; User explicitly says no date time
ENDIF
LOOP CHKARG
JMP SHORT ARGSDONEJ
NEXTCH3:
CMP AL,'c'
JNZ NEXTCH2 ; SINGLECOM switch 2
MOV [SINGLECOM],SI ; Point to the rest of the command line
MOV [PERMCOM],0 ; A SINGLECOM must not be a PERMCOM
IF HIGHMEM
MOV BYTE PTR CS:[PRDATTM],1 ; No date or time either, explicit
ELSE
MOV BYTE PTR [PRDATTM],1 ; No date or time either, explicit
ENDIF
ARGSDONEJ:
JMP ARGSDONE
NEXTCH2:
LOOP CHKARG
COMRETURNSJ:
JMP COMRETURNS
CHKOTHERARGS:
DEC SI
MOV DX,SI
PUSH CX
PUSH SI
CONTRLOOP:
LODSB
DEC CX
CMP AL,' '
JZ SETCDEV
CMP AL,9
JZ SETCDEV
JCXZ SETCDEVA
JMP SHORT CONTRLOOP
SETCDEVA:
INC SI
SETCDEV:
MOV BYTE PTR [SI-1],0
MOV AX,(OPEN SHL 8) OR 2 ; Read and write
INT int_command
JC CHKSRCHSPEC ; Wasn't a file
MOV BX,AX
MOV AX,IOCTL SHL 8
INT int_command
TEST DL,80H
JNZ ISADEVICE
MOV AH,CLOSE ; Close initial handle, wasn't a device
INT int_command
JMP CHKSRCHSPEC
ISADEVICE:
XOR DH,DH
OR DL,3 ; Make sure has CON attributes
MOV AX,(IOCTL SHL 8) OR 1
INT int_command
MOV DX,BX ; Save new handle
POP BX ; Throw away saved SI
POP BX ; Throw away saved CX
PUSH CX
MOV CX,3
XOR BX,BX
RCCLLOOP: ; Close 0,1 and 2
MOV AH,CLOSE
INT int_command
INC BX
LOOP RCCLLOOP
MOV BX,DX ; New device handle
MOV AH,XDUP
INT int_command ; Dup to 0
MOV AH,XDUP
INT int_command ; Dup to 1
MOV AH,XDUP
INT int_command ; Dup to 2
MOV AH,CLOSE
INT int_command ; Close initial handle
POP CX
JCXZ ARGSDONEJ2
JMP CHKARG
CHKSRCHSPEC: ; Not a device, so must be directory spec
IF HIGHMEM
MOV BYTE PTR CS:[CHUCKENV],0 ; If search specified -- no inheritance
MOV AX,CS:[ENVIRSEGSAV]
MOV [ENVIRSEG],AX
ELSE
MOV BYTE PTR [CHUCKENV],0 ; If search specified -- no inheritance
MOV AX,OFFSET RESGROUP:PATHSTRING ; Figure environment pointer
MOV CL,4
SHR AX,CL
MOV DX,DS
ADD AX,DX
MOV [ENVIRSEG],AX
ENDIF
MOV ES,AX
MOV BYTE PTR [SI-1],' '
POP SI ; Remember location
POP CX ; and count
IF HIGHMEM
MOV DI,CS:[ECOMLOC]
ELSE
MOV DI,[ECOMLOC]
ENDIF
COMTRLOOP:
LODSB
DEC CX
CMP AL,' '
JZ SETCOMSR
CMP AL,9
JZ SETCOMSR
STOSB
IF KANJI
XOR AH,AH
ENDIF
JCXZ SETCOMSR
IF KANJI
CALL ITESTKANJ
JZ COMTRLOOP
DEC CX
MOVSB
INC AH
JCXZ SETCOMSR
ENDIF
JMP SHORT COMTRLOOP
SETCOMSR:
PUSH SI
PUSH CX
PUSH DS
IF HIGHMEM
PUSH CS
POP DS
ENDIF
MOV SI,OFFSET RESGROUP:COMSPECT
MOV CX,14
MOV AL,ES:[DI-1]
IF KANJI
OR AH,AH
JNZ INOTROOT ; Last char was KANJI second byte, might be '\'
ENDIF
CALL PATHCHRCMPR
JNZ INOTROOT
INC SI ; Don't make a double /
DEC CX
INOTROOT:
REP MOVSB
MOV DX,[ECOMLOC] ; Now lets make sure its good!
PUSH ES
POP DS
MOV AX,OPEN SHL 8
INT int_command ; Open COMMAND.COM
POP DS
JC SETCOMSRBAD ; No COMMAND.COM here
MOV BX,AX ; Handle
MOV AH,CLOSE
INT int_command ; Close COMMAND.COM
SETCOMSRRET:
POP CX
POP SI
ARGSDONEJ2:
JCXZ ARGSDONE
JMP CHKARG
SETCOMSRBAD:
IF HIGHMEM
PUSH DS
PUSH CS
POP DS
ENDIF
MOV DX,OFFSET RESGROUP:BADCOMLKMES
MOV AH,STD_CON_STRING_OUTPUT
INT int_command
MOV SI,OFFSET RESGROUP:COMSPECT
MOV DI,[ECOMLOC]
MOV CX,14
REP MOVSB ; Get my default back
IF HIGHMEM
POP DS
ENDIF
JMP SHORT SETCOMSRRET
CHKARGJ:
JMP CHKARG
SETPERM:
INC [PERMCOM]
IF HIGHMEM
CMP BYTE PTR CS:[PRDATTM],-1
ELSE
CMP BYTE PTR [PRDATTM],-1
ENDIF
JNZ LOOPIT
IF HIGHMEM
MOV BYTE PTR CS:[PRDATTM],0 ; If not set explicit, set to prompt
ELSE
MOV BYTE PTR [PRDATTM],0 ; If not set explicit, set to prompt
ENDIF
LOOPIT:
LOOP CHKARGJ
ARGSDONE:
CMP [PERMCOM],0
JZ COMRETURNS
PUSH ES ; Save environment pointer
MOV AH,SET_CURRENT_PDB
MOV BX,DS
MOV ES,BX
INT int_command ; Current process is me
MOV DI,PDB_Exit ; Diddle the addresses in my header
MOV AX,OFFSET RESGROUP:LODCOM
STOSW
MOV AX,DS
STOSW
MOV AX,OFFSET RESGROUP:CONTC
STOSW
MOV AX,DS
STOSW
MOV WORD PTR DS:[PDB_Parent_PID],DS ; Parent is me forever
MOV DX,OFFSET RESGROUP:INT_2E
MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 02EH
INT int_command ;Set magic interrupt
POP ES ;Remember environment
COMRETURNS:
MOV AX,WORD PTR DS:[PDB_Parent_PID]
MOV [PARENT],AX ; Save parent
MOV WORD PTR DS:[PDB_Parent_PID],DS ; Parent is me
MOV AX,WORD PTR DS:[PDB_JFN_Table]
MOV [IO_SAVE],AX ; Get the default stdin and out
MOV WORD PTR [COM_PTR+2],DS ; Set all these to resident
MOV WORD PTR [COM_FCB1+2],DS
MOV WORD PTR [COM_FCB2+2],DS
MOV DI,OFFSET RESGROUP:COMSPEC
IF HIGHMEM
MOV SI,CS:[ECOMLOC]
CMP BYTE PTR CS:[CHUCKENV],0
ELSE
MOV SI,[ECOMLOC]
CMP BYTE PTR [CHUCKENV],0
ENDIF
MOV AX,DS ; XCHG ES,DS
PUSH ES
POP DS
MOV ES,AX
JZ COPYCOMSP ; All set up for copy
PUSH CS
POP DS
MOV SI,OFFSET RESGROUP:COMSPSTRING
PUSH ES
PUSH DI
CALL IFINDE
MOV SI,DI
PUSH ES
POP DS
POP DI
POP ES
JNC COPYCOMSP
COMSPECNOFND:
IF HIGHMEM
MOV DS,CS:[ENVIRSEG]
MOV SI,CS:[ECOMLOC]
ELSE
MOV SI,[ECOMLOC]
ADD SI,OFFSET RESGROUP:PATHSTRING
PUSH CS
POP DS
ENDIF
COPYCOMSP:
LODSB
STOSB
OR AL,AL
JNZ COPYCOMSP
IF HIGHMEM
MOV DS,CS:[REALRES]
PUSH CS
POP ES
MOV AH,DEALLOC
INT 21H
CMP BYTE PTR CS:[CHUCKENV],0
JZ GOTENVIR ; Environment is ok
MOV ES,CS:[ENVIRSEGSAV]
MOV AH,DEALLOC
INT 21H
ELSE
PUSH CS
POP DS
MOV BX,OFFSET RESGROUP:DATARESEND + 15
MOV CL,4
SHR BX,CL
MOV AH,SETBLOCK
INT int_command ; Shrink me to the resident only
CMP BYTE PTR [CHUCKENV],0
JNZ GOTENVIR ; Environment was passed
MOV BX,(ENVIRONSIZ + 15) /16
MOV AH,ALLOC
INT int_command ; "ALLOCATE" the environment
MOV DS,[ENVIRSEG]
MOV [ENVIRSEG],AX
MOV ES,AX
XOR SI,SI
MOV DI,SI
MOV CX,ENVIRONSIZ
REP MOVSB
PUSH CS
POP DS
ENDIF
GOTENVIR:
CALL LOADCOM ; Load the transient in the right place
CALL CHKSUM ; Compute the checksum
MOV [SUM],DX ; Save it
IF IBM
MOV AX,[MEMSIZ]
MOV DX,OFFSET EGROUP:ZEXECDATAEND + 15
MOV CL,4
SHR DX,CL
SUB AX,DX
MOV [EXESEG],AX
CALL EXECHK
MOV [EXESUM],DX
ENDIF
IF MSVER
CMP [SINGLECOM],0
JNZ NOPHEAD ; Don't print header if SINGLECOM
IF HIGHMEM
PUSH DS
PUSH CS
POP DS
ENDIF
MOV DX,OFFSET RESGROUP:HEADER
MOV AH,STD_CON_STRING_OUTPUT
INT int_command
IF HIGHMEM
POP DS
ENDIF
NOPHEAD:
ENDIF
IF HIGHMEM
CMP BYTE PTR CS:[PRDATTM],0
ELSE
CMP BYTE PTR [PRDATTM],0
ENDIF
JNZ NODTTM ; Don't do AUTOEXEC or date time
MOV BX,3 ; 48 BYTES ENOUGH
MOV AH,ALLOC
INT int_command
JC DODTTM ; PRETEND NO BATCH
MOV [BATCH],AX
MOV ES,AX
XOR DI,DI
IF HIGHMEM
CMP BYTE PTR CS:[AUTOBAT],0
ELSE
CMP BYTE PTR [AUTOBAT],0
ENDIF
JNZ NOAUTSET
MOV AH,GET_DEFAULT_DRIVE
INT int_command
ADD AL,'A'
IF HIGHMEM
MOV CS:[AUTOBAT],AL
ELSE
MOV [AUTOBAT],AL
ENDIF
NOAUTSET:
IF HIGHMEM
PUSH DS
PUSH CS
POP DS
ENDIF
MOV SI,OFFSET RESGROUP:AUTOBAT
MOV CX,8
REP MOVSW ; NAME
MOV AX,-1
MOV CL,10
REP STOSW ; PARMS
MOV DX,OFFSET RESGROUP:AUTOBAT
MOV AX,OPEN SHL 8
INT int_command ; See if AUTOEXEC.BAT exists
JC NOABAT
MOV BX,AX
MOV AH,CLOSE
INT int_command
IF HIGHMEM
POP DS
ENDIF
JMP SHORT DRV0
NOABAT:
IF HIGHMEM
POP DS
ENDIF
MOV ES,[BATCH] ; Not found--turn off batch job
MOV AH,DEALLOC
INT int_command
MOV [BATCH],0 ; AFTER DEALLOC in case of ^C
DODTTM:
IF HIGHMEM
MOV AX,OFFSET TRANGROUP:DATINIT
MOV WORD PTR CS:[INITADD],AX
MOV AX,[TRNSEG]
MOV WORD PTR CS:[INITADD+2],AX
CALL DWORD PTR CS:[INITADD]
ELSE
MOV AX,OFFSET TRANGROUP:DATINIT
MOV WORD PTR[INITADD],AX
MOV AX,[TRNSEG]
MOV WORD PTR[INITADD+2],AX
CALL DWORD PTR [INITADD]
ENDIF
NODTTM:
IF IBMVER
CMP [SINGLECOM],0
JNZ DRV0 ; Don't print header if SINGLECOM
MOV DX,OFFSET RESGROUP:HEADER
MOV AH,STD_CON_STRING_OUTPUT
INT int_command
ENDIF
DRV0:
IF HIGHMEM
PUSH DS
MOV AX,OFFSET RESGROUP:LODCOM
PUSH AX
MQQ PROC FAR
RET
MQQ ENDP
ELSE
JMP LODCOM ; Allocate the transient
ENDIF
PATHCHRCMPR:
CMP [RSWITCHAR],'/'
JZ RNOSLASHT
CMP AL,'/'
JZ RET41
RNOSLASHT:
CMP AL,'\'
RET41:
RET
IFINDE:
CALL IFIND ; FIND THE NAME
JC IFIND2 ; CARRY MEANS NOT FOUND
JMP ISCASB1 ; SCAN FOR = SIGN
;
; On return of FIND1, ES:DI points to beginning of name
;
IFIND:
CLD
CALL ICOUNT0 ; CX = LENGTH OF NAME
IF HIGHMEM
MOV ES,CS:[REALRES]
ASSUME ES:RESGROUP
MOV ES,ES:[ENVIRSEG]
ASSUME ES:NOTHING
ELSE
MOV ES,[ENVIRSEG]
ENDIF
XOR DI,DI
IFIND1:
PUSH CX
PUSH SI
PUSH DI
IFIND11:
LODSB
IF KANJI
CALL ITESTKANJ
JZ NOTKANJ4
DEC SI
LODSW
INC DI
INC DI
CMP AX,ES:[DI-2]
JNZ IFIND12
DEC CX
LOOP IFIND11
JMP SHORT IFIND12
NOTKANJ4:
ENDIF
CALL IUPCONV
INC DI
CMP AL,ES:[DI-1]
JNZ IFIND12
LOOP IFIND11
IFIND12:
POP DI
POP SI
POP CX
JZ IFIND2
PUSH CX
CALL ISCASB2 ; SCAN FOR A NUL
POP CX
CMP BYTE PTR ES:[DI],0
JNZ IFIND1
STC ; INDICATE NOT FOUND
IFIND2:
RET
ICOUNT0:
PUSH DS
POP ES
MOV DI,SI
PUSH DI ; COUNT NUMBER OF CHARS UNTIL "="
CALL ISCASB1
JMP SHORT ICOUNTX
PUSH DI ; COUNT NUMBER OF CHARS UNTIL NUL
CALL ISCASB2
ICOUNTX:
POP CX
SUB DI,CX
XCHG DI,CX
RET
ISCASB1:
MOV AL,"=" ; SCAN FOR AN =
JMP SHORT ISCASBX
ISCASB2:
XOR AL,AL ; SCAN FOR A NUL
ISCASBX:
MOV CX,100H
REPNZ SCASB
RET
IF KANJI
ITESTKANJ:
CMP AL,81H
JB NOTLEAD
CMP AL,9FH
JBE ISLEAD
CMP AL,0E0H
JB NOTLEAD
CMP AL,0FCH
JBE ISLEAD
NOTLEAD:
PUSH AX
XOR AX,AX ;Set zero
POP AX
RET
ISLEAD:
PUSH AX
XOR AX,AX ;Set zero
INC AX ;Reset zero
POP AX
RET
ENDIF
IUPCONV:
CMP AL,"a"
JB IRET22
CMP AL,"z"
JA IRET22
SUB AL,20H ; Lower-case changed to upper-case
IRET22:
RET
ICONDEV LABEL BYTE
DB "/DEV/"
DB "CON",0,0,0,0,0,0 ; Room for 8 char device
BADCSPFL DB 0
COMSPECT DB "/COMMAND.COM",0,0
AUTOBAT DB 0,":\AUTOEXEC.BAT",0
PRDATTM DB -1 ;Init not to prompt for date time
INITADD DD ?
CHUCKENV DB 0
ECOMLOC DW OFFSET ENVIRONMENT:ECOMSPEC-10H
IF HIGHMEM
REALRES DW ?
ENVIRSEGSAV DW ?
ENDIF
COMSPSTRING DB "COMSPEC="
INIT ENDS
END

BIN
v2.0/source/INT24.txt Normal file

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More