--- /dev/null
+ MS-DOS 2.0 Device Drivers\r
+\r
+INTRODUCTION\r
+\r
+ In the past, DOS-device driver (BIOS for those who are\r
+familiar with CP/M) communication has been mediated with\r
+registers and a fixed-address jump-table. This approach\r
+has suffered heavily from the following two observations:\r
+\r
+ o The old jump-table ideas of the past are fixed in\r
+ scope and allow no extensibility.\r
+\r
+ o The past device driver interfaces have been written\r
+ without regard for the true power of the hardware.\r
+ When a multitasking system or interrupt driven\r
+ hardware is installed a new BIOS must be written\r
+ largely from scratch.\r
+\r
+ In MSDOS 2.0, the DOS-device driver interface has changed\r
+from the old jump-table style to one in which the device\r
+drivers are linked together in a list. This allows new\r
+drivers for optional hardware to be installed (and even\r
+written) in the field by other vendors or the user himself.\r
+This flexibility is one of the major new features of MS-DOS\r
+2.0.\r
+\r
+ Each driver in the chain defines two entry points; the\r
+strategy routine and the interrupt routine. The 2.0 DOS\r
+does not really make use of two entry points (it simply calls\r
+strategy, then immediately calls interrupt). This dual entry\r
+point scheme is designed to facilitate future multi-tasking\r
+versions of MS-DOS. In multi-tasking environments I/O must\r
+be asynchronous, to accomplish this the strategy routine\r
+will be called to queue (internally) a request and return\r
+quickly. It is then the responsibility of the interrupt\r
+routine to perform the actual I/O at interrupt time by picking\r
+requests off the internal queue (set up by the strategy\r
+routine), and process them. When a request is complete,\r
+it is flagged as "done" by the interrupt routine. The DOS\r
+periodically scans the list of requests looking for ones\r
+flagged as done, and "wakes up" the process waiting for the\r
+completion of the request.\r
+\r
+ In order for requests to be queued as above it is no\r
+longer sufficient to pass I/O information in registers, since\r
+many requests may be pending at any one time. Therefore\r
+the new device interface uses data "packets" to pass request\r
+information. A device is called with a pointer to a packet,\r
+this packet is linked into a global chain of all pending\r
+I/O requests maintained by the DOS. The device then links\r
+the packet into its own local chain of requests for this\r
+particular device. The device interrupt routine picks\r
+requests of the local chain for processing. The DOS scans\r
+the global chain looking for completed requests. These\r
+packets are composed of two pieces, a static piece which\r
+has the same format for all requests (called the static\r
+request header), which is followed by information specific\r
+to the request. Thus packets have a variable size and format.\r
+\r
+ At this points it should be emphasized that MS-DOS 2.0\r
+does not implement most of these features, as future versions\r
+will. There is no global or local queue. Only one request\r
+is pending at any one time, and the DOS waits for this current\r
+request to be completed. For 2.0 it is sufficient for the\r
+strategy routine to simply store the address of the packet\r
+at a fixed location, and for the interrupt routine to then\r
+process this packet by doing the request and returning.\r
+Remember: the DOS just calls the strategy routine and then\r
+immediately calls the interrupt routine, it is assumed that\r
+the request is completed when the interrupt routine returns.\r
+This additional functionality is defined at this time so\r
+that people will be aware and thinking about the future.\r
+\r
+\f\r
+FORMAT OF A DEVICE DRIVER\r
+\r
+ A device driver is simply a relocatable memory image\r
+with all of the code in it to implement the device (like\r
+a .COM file, but not ORGed at 100 Hex). In addition it has\r
+a special header at the front of it which identifies it as\r
+a device, defines the strategy and interrupt entry points,\r
+and defines various attributes. It should also be noted\r
+that there are two basic types of devices.\r
+\r
+ The first is character devices. These are devices which\r
+are designed to do character I/O in a serial manner like\r
+CON, AUX, and PRN. These devices are named (ie. CON, AUX,\r
+CLOCK, etc.), and users may open channels (FCBs) to do I/O\r
+to them.\r
+\r
+ The second class of devices is block devices. These\r
+devices are the "disk drives" on the system, they can do\r
+random I/O in pieces called blocks (usually the physical\r
+sector size) and hence the name. These devices are not\r
+"named" as the character devices are, and therefore cannot\r
+be "opened" directly. Instead they are "mapped" via the\r
+drive letters (A,B,C, etc.).\r
+\r
+ Block devices also have units. In other words a single\r
+driver may be responsible for one or more disk drives. For\r
+instance block device driver ALPHA (please note that we cannot\r
+actually refer to block devices by a name!) may be\r
+responsible for drives A,B,C and D, this simply means that\r
+it has four units (0-3) defined and therefore takes up four\r
+drive letters. Which units correspond to which drive letters\r
+is determined by the position of the driver in the chain\r
+of all drivers: if driver ALPHA is the first block driver\r
+in the device chain, and it defines 4 units (0-3), then they\r
+will be A,B,C and D. If BETA is the second block driver\r
+and defines three units (0-2), then they will be E,F and\r
+G and so on. MS-DOS 2.0 is not limited to 16 block device\r
+units, as previous versions were. The theoretical limit\r
+is 63 (2^6 - 1), but it should be noted that after 26 the\r
+drive letters get a little strange (like ] \ and ^). NOTE:\r
+Character devices cannot define multiple units (this because\r
+they have only one name).\r
+\r
+\f\r
+Here is what that special device header looks like:\r
+\r
+ +--------------------------------------+\r
+ | DWORD Pointer to next device |\r
+ | (Must be set to -1) |\r
+ +--------------------------------------+\r
+ | WORD Attributes |\r
+ | Bit 15 = 1 if char device 0 if blk |\r
+ | if bit 15 is 1 |\r
+ | Bit 0 = 1 if Current sti device |\r
+ | Bit 1 = 1 if Current sto output |\r
+ | Bit 2 = 1 if Current NUL device |\r
+ | Bit 3 = 1 if Current CLOCK dev |\r
+ | Bit 4 = 1 if SPECIAL |\r
+ | Bit 14 is the IOCTL bit (see below) |\r
+ | Bit 13 is the NON IBM FORMAT bit |\r
+ +--------------------------------------+\r
+ | WORD Pointer to Device strategy |\r
+ | entry point |\r
+ +--------------------------------------+\r
+ | WORD Pointer to Device interrupt |\r
+ | entry point |\r
+ +--------------------------------------+\r
+ | 8-BYTE character device name field |\r
+ | Character devices set a device name |\r
+ | For block devices the first byte is |\r
+ | The number of units |\r
+ +--------------------------------------+\r
+\r
+ Note that the device entry points are words. They must\r
+be offsets from the same segment number used to point to\r
+this table. Ie. if XXX.YYY points to the start of this\r
+table, then XXX.strategy and XXX.interrupt are the entry\r
+points.\r
+\r
+ A word about the Attribute field. This field is used\r
+most importantly to tell the system whether this device is\r
+a block or character device (bit 15). Most of other bits\r
+are used to give selected character devices certain special\r
+treatment (NOTE: these bits mean nothing on a block device).\r
+Let's say a user has a new device driver which he wants to\r
+be the standard input and output. Besides just installing\r
+the driver he needs to tell SYSINIT (and the DOS) that he\r
+wishes his new driver to override the current sti and sto\r
+(the "CON" device). This is accomplished by setting the\r
+attributes to the desired characteristics, so he would set\r
+Bits 0 and 1 to 1 (note that they are separate!!). Similarly\r
+a new CLOCK device could be installed by setting that\r
+attribute, see the section at the end on the CLOCK device.\r
+NOTE: that although there is a NUL device attribute, the\r
+NUL device cannot be re-assigned. This attribute exists\r
+for the DOS so that it can tell if the NUL device is being\r
+used.\r
+\r
+ The NON IBM FORMAT bit applies only to block devices\r
+and effects the operation of the get BPB device call (see\r
+below).\r
+\r
+ The other bit of interest is the IOCTL bit which has\r
+meaning on character or block devices. This bit tells the\r
+DOS whether this device can handle control strings (via the\r
+IOCTL system call).\r
+\r
+ If a driver cannot process control strings, it should\r
+initially set this bit to 0. This tells the DOS to return\r
+an error if an attempt is made (via IOCTL system call) to\r
+send or receive control strings to this device. A device\r
+which can process control strings should initialize it to\r
+1. For drivers of this type, the DOS will make calls to\r
+the IOCTL INPUT and OUTPUT device functions to send and\r
+receive IOCTL strings (see IOCTL in the SYSTEM-CALLS\r
+document).\r
+\r
+ The IOCTL functions allow data to be sent and received\r
+by the device itself for its own use (to set baud rate, stop\r
+bits, form length etc., etc.), instead of passing data over\r
+the device channel as a normal read or write does. The\r
+interpretation of the passed information is up to the device,\r
+but it MUST NOT simply be treated as a normal I/O.\r
+\r
+ The SPECIAL bit applies only to character drivers and\r
+more particularly to CON drivers. The new 2.0 interface\r
+is a much more general and consistent interface than the\r
+old 1.25 DOS interface. It allows for a number of additional\r
+features of 2.0. It is also slower than 1.25 if old style\r
+"single byte" system calls are made. To make most efficient\r
+use of the interface all applications should block their\r
+I/O as much as possible. This means make one XENIX style\r
+system call to output X bytes rather than X system calls\r
+to output one byte each. Also putting a device channel in\r
+RAW mode (see IOCTL) provides a means of putting out\r
+characters even FASTER than 1.25. To help alleviate the\r
+CON output speed problem for older programs which use the\r
+1 - 12 system calls to output large amounts of data the\r
+SPECIAL bit has been implemented. If this bit is 1 it means\r
+the device is the CON output device, and has implemented\r
+an interrupt 29 Hex handler, where the 29 Hex handler is\r
+defined as follows:\r
+\r
+ Interrupt 29h handlers\r
+\r
+ Input:\r
+ Character in AL\r
+\r
+ Function:\r
+ output the character in al to the user\r
+ screen.\r
+ Output:\r
+ None\r
+ Registers:\r
+ all registers except bx must be preserved.\r
+ No registers except for al have a known or\r
+ consistent value.\r
+\r
+ If a character device implements the SPECIAL bit, it\r
+is the responsibility of the driver to install an address\r
+at the correct location in the interrupt table for interrupt\r
+29 Hex as part of its INIT code. IMPLICATION: There can\r
+be only one device driver with the SPECIAL bit set in the\r
+system. There is no check to insure this state.\r
+\r
+WARNING: THIS FEATURE WILL NOT BE SUPPORTED IN FUTURE VERSIONS\r
+ OF THE OPERATING SYSTEM. IMPLICATION: Any application\r
+ (not device driver) which uses INT 29H directly will\r
+ not work on future versions, YOU HAVE BEEN WARNED.\r
+\f\r
+ In order to "make" a device driver that SYSINIT can\r
+install, a memory image or .EXE (non-IBM only) format file\r
+must be created with the above header at the start. The\r
+link field should be initialized to -1 (SYSINIT fills it\r
+in). The attribute field and entry points must be set\r
+correctly, and if the device is a character device, the name\r
+field must be filled in with the name (if a block device\r
+SYSINIT will fill in the correct unit count). This name\r
+can be any 8 character "legal" file name. In fact SYSINIT\r
+always installs character devices at the start of the device\r
+list, so if you want to install a new CON device all you\r
+have to do is name it "CON". The new one is ahead of the\r
+old one in the list and thus preempts the old one as the\r
+search for devices stops on the first match. Be sure to\r
+set the sti and sto bits on a new CON device!\r
+\r
+NOTE: Since SYSINIT may install the driver anywhere, you\r
+ must be very careful about FAR memory references. You\r
+ should NOT expect that your driver will go in the same\r
+ place every time (The default BIOS drivers are exempted\r
+ from this of course).\r
+\r
+\f\r
+INSTALLATION OF DEVICE DRIVERS\r
+\r
+ Unlike past versions MS-DOS 2.0 allows new device drivers\r
+to be installed dynamically at boot time. This is\r
+accomplished by the new SYSINIT module supplied by Microsoft,\r
+which reads and processes the CONFIG.SYS file. This module\r
+is linked together with the OEM default BIOS in a similar\r
+manner to the way FORMAT is built.\r
+\r
+ One of the functions defined for each device is INIT.\r
+This routine is called once when the device is installed,\r
+and never again. The only thing returned by the init routine\r
+is a location (DS:DX) which is a pointer to the first free\r
+byte of memory after the device driver, (like a terminate\r
+and stay resident). This pointer method can be used to "throw\r
+away" initialization code that is only needed once, saving\r
+on space.\r
+\r
+ Block devices are installed the same way and also return\r
+a first free byte pointer as above, additional information\r
+is also returned:\r
+\r
+ o The number of units is returned, this determines\r
+ logical device names. If the current maximum logical\r
+ device letter is F at the time of the install call,\r
+ and the init routine returns 4 as the number of units,\r
+ then they will have logical names G, H, I and J.\r
+ This mapping is determined by by the position of\r
+ the driver in the device list and the number of units\r
+ on the device (stored in the first byte of the device\r
+ name field).\r
+\r
+ o A pointer to a BPB (Bios Parameter Block) pointer\r
+ array is also returned. This will be similar to\r
+ the INIT table used in previous versions, but will\r
+ have more information in it. There is one table\r
+ for each unit defined. These blocks will be used\r
+ to build a DPB (Drive Parameter Block) for each of\r
+ the units. The pointer passed to the DOS from the\r
+ driver points to an array of n word pointers to BPBs\r
+ where n is the number of units defined. In this\r
+ way if all units are the same, all of the pointers\r
+ can point to the same BPB, saving space. NOTE: this\r
+ array must be protected (below the free pointer set\r
+ by the return) since the DPB will be built starting\r
+ at the byte pointed to by the free pointer. The\r
+ sector size defined must be less than or equal to\r
+ the maximum sector size defined at default BIOS init\r
+ time. If it isn't the install will fail. One new\r
+ piece of DPB info set from this table will be a "media\r
+ descriptor byte". This byte means nothing to the\r
+ DOS, but is passed to devices so that they know what\r
+ form of a DPB the DOS is currently using for a\r
+ particular Drive-Unit.\r
+\r
+ Block devices may take several approaches; they may be\r
+dumb or smart. A dumb device would define a unit (and\r
+therefore a DPB) for each possible media drive combination.\r
+Unit 0 = drive 0 single side, unit 1 = drive 0 double side,\r
+etc. For this approach media descriptor bytes would mean\r
+nothing. A smart device would allow multiple media per unit,\r
+in this case the BPB table returned at init must define space\r
+large enough to accommodate the largest possible media\r
+supported. Smart drivers will use the "media byte" to pass\r
+around info about what media is currently in a unit. NOTE:\r
+If the DPB is a "hybrid" made to get the right sizes, it\r
+should give an invalid "media byte" back to the DOS.\r
+\r
+ The BOOT (default BIOS) drivers are installed pretty\r
+much as above. The preset device list is scanned. If block\r
+drivers are encountered they are installed as above (with\r
+the exception that the break is not moved since the drivers\r
+are already resident in the BIOS). Note that the logical\r
+drive letters are assigned in list order, thus the driver\r
+which is to have logical A must be the first unit of the\r
+first block device in the list. The order of character\r
+devices is also important. There must be at least 4 character\r
+devices defined at boot which must be the first four devices\r
+(of either type), the first will become standard input,\r
+standard output, and standard error output. The second will\r
+become standard auxiliary input and output, the third will\r
+become standard list output, and the forth will become the\r
+date/time (CLOCK) device. Thus the BIOS device list must\r
+look like this:\r
+\r
+->CON->AUX->PRN->CLOCK->any other block or character devices\r
+\f\r
+THE DRIVER\r
+\r
+ A device driver will define the following functions:\r
+\r
+ Command Function\r
+ Code\r
+\r
+ 0 INIT\r
+ 1 MEDIA CHECK (Block only, NOP for character)\r
+ 2 BUILD BPB " " " " "\r
+ 3 IOCTL INPUT (Only called if device has IOCTL)\r
+ 4 INPUT (read)\r
+ 5 NON-DESTRUCTIVE INPUT NO WAIT (Char devs only)\r
+ 6 INPUT STATUS " " "\r
+ 7 INPUT FLUSH " " "\r
+ 8 OUTPUT (write)\r
+ 9 OUTPUT (Write) with verify\r
+ 10 OUTPUT STATUS " " "\r
+ 11 OUTPUT FLUSH " " "\r
+ 12 IOCTL OUTPUT (Only called if device has IOCTL)\r
+\r
+ As mentioned before, the first entry point is the strategy\r
+routine which is called with a pointer to a data block. This\r
+call does not perform the request, all it does is queue it\r
+(save the data block pointer). The second interrupt entry\r
+point is called immediately after the strategy call. The\r
+"interrupt" routine is called with no parameters, its primary\r
+function is to perform the operation based on the queued\r
+data block and set up any returns.\r
+\r
+ The "BUILD BPB" and "MEDIA CHECK" are the interesting\r
+new ones, these are explained by examining the sequence of\r
+events in the DOS which occurs when a drive access call (other\r
+than read or write) is made:\r
+\r
+ I. Turn drive letter into DPB pointer by looking\r
+ for DPB with correct driver-unit number.\r
+\r
+ II. Call device driver and request media check for\r
+ Drive-Unit. DOS passes its current Media\r
+ descriptor byte (from DPB). Call returns:\r
+\r
+ Media Not Changed\r
+ Media Changed\r
+ Not Sure\r
+ Error\r
+\r
+ Error - If an error occurs the error code should\r
+ be set accordingly.\r
+\r
+ Media Not changed - Current DPB and media byte\r
+ are OK, done.\r
+\r
+ Media Changed - Current DPB and media are wrong,\r
+ invalidate any buffers for this unit, and\r
+ goto III.\r
+\r
+ Not Sure - If there are dirty buffers for this\r
+ unit, assume DPB and media byte are OK and\r
+ done. If nothing dirty, assume media changed,\r
+ invalidate any buffers for unit, and goto\r
+ III.\r
+\r
+ NOTE: If a hybrid DPB was built at init and\r
+ an invalid Media byte was set, the driver\r
+ should return media changed when this invalid\r
+ media byte is encountered.\r
+\r
+ III. Call device driver to build BPB with media byte\r
+ and buffer.\r
+\r
+ What the driver must do at step III is determine the\r
+correct media that is currently in the unit, and return a\r
+pointer to a BPB table (same as for the install call). This\r
+table will be used as at init to build a correct DPB for\r
+the unit If the determined media descriptor byte in the table\r
+turns out to be the same as the one passed in, then the DOS\r
+will not build a new table, but rather just use the old one.\r
+Therefore in this case the driver doesn't have to correctly\r
+fill in the other entries if desired.\r
+\r
+ The build BPB call also gets a pointer to a one sector\r
+buffer. What this buffer contains is determined by the NON\r
+IBM FORMAT bit in the attribute field. If the bit is zero\r
+(device is IBM format compatible) then the buffer contains\r
+the first sector of the first FAT, in particular the FAT\r
+ID byte is the first byte of this buffer. NOTE: It must\r
+be true that the BPB is the same, as far as location of the\r
+FAT is concerned, for all possible media. This is because\r
+this first FAT sector must be read BEFORE the actual BPB\r
+is returned. If the NON IBM FORMAT bit is set then the\r
+pointer points to one sector of scratch space which may be\r
+used for anything.\r
+\f\r
+CALL FORMAT\r
+\r
+ When the DOS calls a device driver to perform a finction,\r
+it passes a structure (Drive Request Structure) in ES:BX\r
+to perform operations and does a long call to the driver's\r
+strategy entry point. This structure is a fixed length header\r
+(Static Request Header) followed by data pertinent to the\r
+operation being performed. NOTE: It is the drivers\r
+responsibility to preserve machine state.\r
+\r
+STATIC REQUEST HEADER ->\r
+ +-----------------------------+\r
+ | BYTE length of record |\r
+ | Length in bytes of this |\r
+ | Drive Request Structure |\r
+ +-----------------------------+\r
+ | BYTE unit code |\r
+ | The subunit the operation |\r
+ | is for (minor device) |\r
+ | (no meaning on character |\r
+ | devices) |\r
+ +-----------------------------+\r
+ | BYTE command code |\r
+ +-----------------------------+\r
+ | WORD Status |\r
+ +-----------------------------+\r
+ | 8 bytes reserved here for |\r
+ | two DWORD links. One will |\r
+ | be a link for the DOS queue |\r
+ | The other for the device |\r
+ | queue |\r
+ +-----------------------------+\r
+\r
+STATUS WORD\r
+\r
+ 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0\r
+ +---+---+--+--+--+--+---+---+--+--+--+--+--+--+--+--+\r
+ | E | | B | D | |\r
+ | R | RESERVED | U | O | ERROR CODE (bit 15 on)|\r
+ | R | | I | N | |\r
+ +---+---+--+--+--+--+---+---+--+--+--+--+--+--+--+--+\r
+\r
+ The status word is zero on entry and is set by the driver\r
+interrupt routine on return.\r
+\r
+ Bit 8 is the done bit, it means the operation is complete.\r
+For the moment the Driver just sets it to one when it exits,\r
+in the future this will be set by the interrupt routine to\r
+tell the DOS the operation is complete.\r
+\f\r
+ Bit 15 is the error bit, if it is set then the low 8\r
+bits indicate the error:\r
+\r
+ 0 Write Protect violation\r
+ (NEW) 1 Unknown Unit\r
+ 2 Drive not ready\r
+ (NEW) 3 Unknown command\r
+ 4 CRC error\r
+ (NEW) 5 Bad Drive Request Structure length\r
+ 6 Seek error\r
+ (NEW) 7 Unknown media\r
+ 8 Sector not found\r
+ (NEW) 9 Printer out of paper\r
+ A Write Fault\r
+ (NEW) B Read Fault\r
+ C General Failure\r
+\r
+Bit 9 is the busy bit which is set only by status calls (see\r
+STATUS CALL below).\r
+\r
+\f\r
+ Here is the data block format for each function:\r
+\r
+READ or WRITE - ES:BX (Including IOCTL) ->\r
+ +------------------------------------+\r
+ | 13-BYTE Static Request Header |\r
+ +------------------------------------+\r
+ | BYTE Media descriptor from DPB |\r
+ +------------------------------------+\r
+ | DWORD transfer address |\r
+ +------------------------------------+\r
+ | WORD byte/sector Count |\r
+ ---+------------------------------------+---\r
+ | WORD starting sector number |\r
+ | (ignored on Char Devs) |\r
+ +------------------------------------+\r
+\r
+ In addition to setting the status word, the driver must\r
+set the Sector count to the actual number of sectors (or\r
+bytes) transferred. NOTE: No error check is performed on\r
+an IOCTL I/O call, driver MUST correctly set the return sector\r
+(byte) count to the actual number of bytes transferred,\r
+however.\r
+\r
+NOTE: THE FOLLOWING APPLIES TO BLOCK DEVICE DRIVERS.\r
+\r
+ Under certain circumstances the BIOS may be asked to\r
+do a write operation of 64K bytes which seems to be a "wrap\r
+around" of the transfer address in the BIOS I/O packet. This\r
+arises due to an optimization added to the write code in\r
+MS-DOS. It will only manifest on user WRITEs which are within\r
+a sector size of 64K bytes on files which are "growing" past\r
+the current EOF. IT IS ALLOWABLE FOR THE BIOS TO IGNORE\r
+THE BALANCE OF THE WRITE WHICH "WRAPS AROUND" IF IT SO\r
+CHOOSES. For instance a WRITE of 10000H bytes worth of\r
+sectors with a transfer address of XXX:1 could ignore the\r
+last two bytes (remember that a user program can never request\r
+an I/O of more than FFFFH bytes and cannot wrap around (even\r
+to 0) in his transfer segment, so in this case the last two\r
+bytes can be ignored).\r
+\r
+\f\r
+NON DESRUCTIVE READ NO WAIT - ES:BX ->\r
+ +------------------------------------+\r
+ | 13-BYTE Static Request Header |\r
+ +------------------------------------+\r
+ | BYTE read from device |\r
+ +------------------------------------+\r
+\r
+ This call is analogous to the console input status call\r
+on MS-DOS 1.25. If the character device returns Busy bit\r
+= 0 (characters in buffer), then the next character that\r
+would be read is returned. This character is NOT removed\r
+from the input buffer (hence the term Non Destructive Read).\r
+In essence this call allows the DOS to look ahead one input\r
+character.\r
+\r
+\f\r
+MEDIA CHECK - ES:BX ->\r
+ +------------------------------------+\r
+ | 13-BYTE Static Request Header |\r
+ +------------------------------------+\r
+ | BYTE Media Descriptor from DPB |\r
+ +------------------------------------+\r
+ | BYTE returned |\r
+ +------------------------------------+\r
+\r
+ In addition to setting status word, driver must set the\r
+return byte.\r
+\r
+ Return Byte :\r
+ -1 Media has been changed\r
+ 0 Don't know if media has been changed\r
+ 1 Media has not been changed\r
+\r
+ If the driver can return -1 or 1 (by having a door-lock\r
+or other interlock mechanism) the performance of MSDOS 2.0\r
+is enhanced as the DOS need not reread the FAT for each\r
+directory access.\r
+\r
+\f\r
+BUILD BPB - ES:BX ->\r
+ +------------------------------------+\r
+ | 13-BYTE Static Request Header |\r
+ +------------------------------------+\r
+ | BYTE Media Descriptor from DPB |\r
+ +------------------------------------+\r
+ | DWORD Transfer Address |\r
+ | (points to one sectors worth of |\r
+ | scratch space or first sector |\r
+ | of FAT depending on the value |\r
+ | of the NON IBM FORMAT bit) |\r
+ +------------------------------------+\r
+ | DWORD Pointer to BPB |\r
+ +------------------------------------+\r
+\r
+ If the NON IBM FORMAT bit of the device is set, then\r
+the DWORD Transfer Address points to a one sector buffer\r
+which can be used for any purpose. If the NON IBM FORMAT\r
+bit is 0, then this buffer contains the first sector of the\r
+FAT; in this case the driver must not alter this buffer (this\r
+mode is useful if all that is desired is to read the FAT\r
+ID byte).\r
+\r
+ If IBM compatible format is used (NON IBM FORMAT BIT\r
+= 0), then it must be true that the first sector of the first\r
+FAT is located at the same sector on all possible media.\r
+This is because the FAT sector will be read BEFORE the media\r
+is actually determined.\r
+\r
+ In addition to setting status word, driver must set the\r
+Pointer to the BPB on return.\r
+\f\r
+\r
+ In order to allow for many different OEMs to read each\r
+other's disks, the following standard is suggested: The\r
+information relating to the BPB for a particular piece of\r
+media is kept in the boot sector for the media. In\r
+particular, the format of the boot sector is:\r
+\r
+ +------------------------------------+\r
+ | 3 BYTE near JUMP to boot code |\r
+ +------------------------------------+\r
+ | 8 BYTES OEM name and version |\r
+ ---+------------------------------------+---\r
+ B | WORD bytes per sector |\r
+ P +------------------------------------+\r
+ B | BYTE sectors per allocation unit |\r
+ +------------------------------------+\r
+ | | WORD reserved sectors |\r
+ V +------------------------------------+\r
+ | BYTE number of FATs |\r
+ +------------------------------------+\r
+ | WORD number of root dir entries |\r
+ +------------------------------------+\r
+ | WORD number of sectors in logical |\r
+ ^ | image |\r
+ | +------------------------------------+\r
+ B | BYTE media descriptor |\r
+ P +------------------------------------+\r
+ B | WORD number of FAT sectors |\r
+ ---+------------------------------------+---\r
+ | WORD sectors per track |\r
+ +------------------------------------+\r
+ | WORD number of heads |\r
+ +------------------------------------+\r
+ | WORD number of hidden sectors |\r
+ +------------------------------------+\r
+\r
+ The three words at the end are optional, the DOS doesn't\r
+care about them (since they are not part of the BPB). They\r
+are intended to help the BIOS understand the media. Sectors\r
+per track may be redundant (could be figured out from total\r
+size of the disk). Number of heads is useful for supporting\r
+different multi-head drives which have the same storage\r
+capacity, but a different number of surfaces. Number of\r
+hidden sectors is useful for supporting drive partitioning\r
+schemes.\r
+\f\r
+\r
+ Currently, the media descriptor byte has been defined\r
+for a small range of media:\r
+\r
+ 5 1/4" diskettes:\r
+\r
+ Flag bits:\r
+ 01h - on -> 2 double sided\r
+\r
+ All other bits must be on.\r
+\r
+ 8" disks:\r
+ FEh - IBM 3740 format, singled-sided, single-density,\r
+ 128 bytes per sector, soft sectored, 4 sectors\r
+ per allocation unit, 1 reserved sector, 2 FATs,\r
+ 68 directory entries, 77*26 sectors\r
+\r
+ FDh - 8" IBM 3740 format, singled-sided,\r
+ single-density, 128 bytes per sector, soft\r
+ sectored, 4 sectors per allocation unit, 4\r
+ reserved sectors, 2 FATs, 68 directory entries,\r
+ 77*26 sectors\r
+\r
+ FEh - 8" Double-sided, double-density, 1024 bytes\r
+ per sector, soft sectored, 1 sector per allocation\r
+ unit, 1 reserved sector, 2 FATs, 192 directory\r
+ entries, 77*8*2 sectors\r
+\r
+\f\r
+STATUS Calls - ES:BX ->\r
+ +------------------------------------+\r
+ | 13-BYTE Static Request Header |\r
+ +------------------------------------+\r
+\r
+ All driver must do is set status word accordingly and\r
+set the busy bit as follows:\r
+\r
+ o For output on character devices: If it is 1 on\r
+ return, a write request (if made) would wait for\r
+ completion of a current request. If it is 0, there\r
+ is no current request and a write request (if made)\r
+ would start immediately.\r
+\r
+ o For input on character devices with a buffer a return\r
+ of 1 means, a read request (if made) would go to\r
+ the physical device. If it is 0 on return, then\r
+ there are characters in the devices buffer and a\r
+ read would return quickly, it also indicates that\r
+ the user has typed something. The DOS assumes all\r
+ character devices have an input type ahead buffer.\r
+ Devices which don't have them should always return\r
+ busy = 0 so that the DOS won't hang waiting for\r
+ something to get into a buffer which doesn't exist.\r
+\r
+\f\r
+FLUSH Calls - ES:BX ->\r
+ +------------------------------------+\r
+ | 13-BYTE Static Request Header |\r
+ +------------------------------------+\r
+\r
+ This call tells the driver to flush (terminate) all\r
+pending requests that it has knowledge of. Its primary use\r
+is to flush the input queue on character devices.\r
+\r
+\f\r
+INIT - ES:BX ->\r
+ +------------------------------------+\r
+ | 13-BYTE Static Request Header |\r
+ +------------------------------------+\r
+ | BYTE # of units |\r
+ +------------------------------------+\r
+ | DWORD Break Address |\r
+ ---+------------------------------------+---\r
+ | DWORD Pointer to BPB array |\r
+ | (not set by Character devices) |\r
+ +------------------------------------+\r
+\r
+ The number of units, break address, and BPB pointer are\r
+set by the driver.\r
+\r
+\f\r
+FORMAT OF BPB (Bios Parameter Block) -\r
+\r
+ +------------------------------------+\r
+ | WORD Sector size in Bytes |\r
+ | Must be at least 32 |\r
+ +------------------------------------+\r
+ | BYTE Sectors/Allocation unit |\r
+ | Must be a power of 2 |\r
+ +------------------------------------+\r
+ | WORD Number of reserved sectors |\r
+ | May be zero |\r
+ +------------------------------------+\r
+ | BYTE Number of FATS |\r
+ +------------------------------------+\r
+ | WORD Number of directory entries |\r
+ +------------------------------------+\r
+ | WORD Total number of sectors |\r
+ +------------------------------------+\r
+ | BYTE Media descriptor |\r
+ +------------------------------------+\r
+ | WORD Number of sectors occupied by |\r
+ | FAT |\r
+ +------------------------------------+\r
+\r
+\f\r
+THE CLOCK DEVICE\r
+\r
+ One of the most popular add on boards seems to be "Real\r
+Time CLOCK Boards". To allow these boards to be integrated\r
+into the system for TIME and DATE, there is a special device\r
+(determined by the attribute word) which is the CLOCK device.\r
+In all respects this device defines and performs functions\r
+like any other character device (most functions will be "set\r
+done bit, reset error bit, return). When a read or write\r
+to this device occurs, exactly 6 bytes are transferred. This\r
+I/O can be thought of as transferring 3 words which correspond\r
+exactly to the values of AX, CX and DX which were used in\r
+the old 1.25 DOS date and time routines. Thus the first\r
+two bytes are a word which is the count of days since 1-1-80.\r
+The third byte is minutes, the fourth hours, the fifth\r
+hundredths of seconds, and the sixth seconds. Reading the\r
+CLOCK device gets the date and time, writing to it sets the\r
+date and time.\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+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
+
+\1a
\ No newline at end of file
--- /dev/null
+FORMAT - formats a new disk, clears the FAT and DIRECTORY\r
+and optionally copies the SYSTEM and COMMAND.COM to this\r
+new disk.\r
+\r
+Command syntax:\r
+\r
+ FORMAT [drive:][/switch1][/switch2]...[/switch16]\r
+\r
+ Where "drive:" is a legal drive specification and if\r
+ omitted indicates that the default drive will be used.\r
+ There may be up to 16 legal switches included in the\r
+ command line.\r
+\r
+\r
+ The OEM must supply five (NEAR) routines to the program\r
+along with 6 data items. The names of the routines are INIT,\r
+DISKFORMAT, BADSECTOR, WRTFAT and DONE, and their flow of\r
+control (by the Microsoft module) is like this:\r
+\r
+ |\r
+ +---------+\r
+ | INIT |\r
+ +---------+\r
+ |\r
+ |<------------------------------+\r
++------------+ |\r
+| DISKFORMAT | |\r
++------------+ |\r
+ |<-------+ |\r
++-----------+ |-This loop is done |- This loop done\r
+| BADSECTOR | | for each group of | once for each disk\r
++-----------+ | bad sectors | to be formatted.\r
+ |----->--+ | If variable HARDFLAG\r
+ | | is set then the loop\r
++----------+ | is only performed\r
+| | | once.\r
+| WRTFAT | |\r
++----------+ |\r
+ | |\r
+ +------+ |\r
+ | DONE | |\r
+ +------+ |\r
+ +---->--------------------------+\r
+\r
+ The INIT, DISKFORMAT, and BADSECTOR routines are free\r
+to use any MS-DOS system calls, except for calls that cause\r
+disk accesses on the disk being formatted. DONE may use\r
+ANY calls, since by the time it is called the new disk has\r
+been formatted.\r
+\r
+The following data must be declared PUBLIC in a module\r
+provided by the OEM:\r
+\r
+ SWITCHLIST - A string of bytes. The first byte is count\r
+ N, followed by N characters which are the switches to\r
+ be accepted by the command line scanner. Alphabetic\r
+ characters must be in upper case (the numeric\r
+ characters 0-9 are allowed). The last three switches,\r
+ normally "O", "V" and "S", have pre-defined meanings.\r
+\r
+ The "S" switch is the switch which causes the\r
+ system files IO.SYS, MSDOS.SYS, and COMMAND.COM to be\r
+ transfered to the disk after it is formatted thus\r
+ making a "S"ystem disk. The switch can be some letter\r
+ other than "S", but the last switch in the list is\r
+ assumed to have the meaning "transfer system",\r
+ regardles of what the particular letter is.\r
+\r
+ The second to the last switch, "V", causes FORMAT\r
+ to prompt the user for a volume label after the disk\r
+ is formatted. Again, as with "S", the particular\r
+ letter is not important but rather the position in the\r
+ list.\r
+\r
+ The third to the last switch, "O", causes FORMAT to\r
+ produce an IBM Personal Computer DOS version 1.X\r
+ compatible disk. Normally FORMAT causes a 0 byte to\r
+ be placed in the first byte of each directory entry\r
+ instead of the 0E5 Hex free entry designator. This\r
+ results in a very marked directory search performance\r
+ increase due to an optimization in the DOS. Disks\r
+ made this way cause trouble on IBM PC DOS 1.X\r
+ versions, however, which did not have this\r
+ optimization. The 0 byte fools IBM 1.X versions into\r
+ thinking these entries are allocated instead of free,\r
+ NOTE that IBM Personnal Computer DOS version 2.00 and\r
+ MS-DOS version 1.25 will have no trouble with these\r
+ disks, since they have the same optimization. The "O"\r
+ switch causes FORMAT to re-do the directory with a 0E5\r
+ Hex byte at the start of each entry so that the disk\r
+ may be used with 1.X versions of IBM PC DOS, as well\r
+ as MS-DOS 1.25/2.00 and IBM PC DOS 2.00. This switch\r
+ should only be given when needed because it takes a\r
+ fair amount of time for FORMAT to perform the\r
+ conversion, and it noticably decreases 1.25 and 2.00\r
+ performance on disks with few directory entries.\r
+\r
+ Up to 16 switches are permitted. Normally a "C"\r
+ switch is specified for "Clear". This switch should\r
+ cause the formatting operation to be bypassed (within\r
+ DISKFORMAT or BADSECTOR). This is provided as a\r
+ time-saving convenience to the user, who may wish\r
+ to "start fresh" on a previosly formatted and used\r
+ disk.\r
+\r
+ HARDFLAG - BYTE location which specifies whether the\r
+ OEM routine is formatting a fixed disk or a a drive\r
+ with removable media. A zero indicates removable\r
+ media, any other value indicates a fixed disk. The\r
+ status of this byte only effect the messages printed\r
+ by the main format module. This value should be\r
+ set or reset by the OEM supplied INIT routine.\r
+\r
+ FATID - BYTE location containing the value to be used\r
+ in the first byte of the FAT. Must be in the range\r
+ F8 hex to FF hex.\r
+\r
+ STARTSECTOR - WORD location containing the sector number\r
+ of the first sector of the data area.\r
+\r
+ FATSPACE - WORD location containing the address of the\r
+ start of the FAT area. A FAT built in this area\r
+ will be written to disk using the OEM supplied WRTFAT\r
+ subroutine. 6k is sufficient to store any FAT. This\r
+ area must not overlap the FREESPACE area.\r
+\r
+ FREESPACE - WORD location which contains the address\r
+ of the start of free memory space. This is where\r
+ the system will be loaded, by the Microsoft module,\r
+ for transferring to the newly formatted disk. Memory\r
+ should be available from this address to the end\r
+ of memory, so it is typically the address of the\r
+ end of the OEM module.\r
+\r
+The following routines must be declared PUBLIC in the\r
+OEM-supplied module:\r
+\r
+ INIT - An initialization routine. This routine is called\r
+ once at the start of the FORMAT run after the switches\r
+ have been processed. This routine should perform\r
+ any functions that only need to be done once per\r
+ FORMAT run. An example of what this routine might\r
+ do is read the boot sector into a buffer so that\r
+ it can be transferred to the new disks by DISKFORMAT.\r
+ If this routine returns with the CARRY flag set it\r
+ indicates an error, and FORMAT will print "Format\r
+ failure" and quit. This feature can be used to detect\r
+ conflicting switches (like specifying both single\r
+ and double density) and cause FORMAT to quit without\r
+ doing anything.\r
+\r
+ DISKFORMAT - Formats the disk according to the options\r
+ indicated by the switches and the value of FATID\r
+ must be defined when it returns (although INIT may\r
+ have already done it). This routine is called once\r
+ for EACH disk to be formatted. If neccessary it\r
+ must transfer the Bootstrap loader. If any error\r
+ conditions are detected, set the CARRY flag and return\r
+ to FORMAT. FORMAT will report a 'Format failure'\r
+ and prompt for another disk. (If you only require\r
+ a clear directory and FAT then simply setting the\r
+ appropriate FATID, if not done by INIT, will be all\r
+ that DISKFORMAT must do.)\r
+\r
+ BADSECTOR - Reports the sector number of any bad sectors\r
+ that may have been found during the formatting of\r
+ the disk. This routine is called at least once for\r
+ EACH disk to be formatted, and is called repeatedly\r
+ until AX is zero or the carry flag is set. The carry\r
+ flag is used just as in DISKFORMAT to indicate an\r
+ error, and FORMAT handles it in the same way. The\r
+ first sector in the data area must be in STARTSECTOR\r
+ for the returns from this routine to be interpreted\r
+ correctly. If there are bad sectors, BADSECTOR must\r
+ return a sector number in in register BX, the number\r
+ of consecutive bad sectors in register AX, and carry\r
+ clear. FORMAT will then process the bad sectors\r
+ and call BADSECTOR again. When BADSECTOR returns\r
+ with AX = 0 this means there are no more bad sectors;\r
+ FORMAT clears the directory and goes on to DONE,\r
+ so for this last return BX need not contain anything\r
+ meaningful.\r
+\r
+ FORMAT processes bad sectors by determining their\r
+ corresponding allocation unit and marking that unit\r
+ with an FF7 hex in the File Allocation Table. CHKDSK\r
+ understands the FF7 mark as a flag for bad sectors\r
+ and accordingly reports the number of bytes marked\r
+ in this way.\r
+\r
+ NOTE: Actual formatting of the disk can be done in\r
+ BADSECTOR instead of DISKFORMAT on a "report as you\r
+ go" basis. Formatting goes until a group of bad\r
+ sectors is encountered, BADSECTOR then reports them\r
+ by returning with AX and BX set. FORMAT will then\r
+ call BADSECTOR again and formatting can continue.\r
+\r
+ WRTFAT - This routine is called after the disk is\r
+ formatted and bad sectors have been reported. Its\r
+ purpose is to write all copies of the FAT from the\r
+ area of memory referenced by FATSPACE to the drive\r
+ just formatted. It may be possible to use INT 26H\r
+ to perform the write, or a direct BIOS call. Whether\r
+ this is possible depends on whether the FAT ID byte\r
+ is used by the BIOS to determine the media in the\r
+ drive. If it is, these methods will probably fail\r
+ because there is no FAT ID byte on the disk yet (in\r
+ this case WRTFATs primary job is to get the FAT ID\r
+ byte out on the disk and thus solve the chicken and\r
+ egg problem).\r
+\r
+ DONE - This routine is called after the formatting is\r
+ complete, the disk directory has been initialized,\r
+ and the system has been transferred. It is called\r
+ once for EACH disk to be formatted. This gives the\r
+ chance for any finishing-up operations, if needed.\r
+ If the OEM desires certain extra files to be put\r
+ on the diskette by default, or according to a switch,\r
+ this could be done in DONE. Again, as in BADSECTOR\r
+ and DISKFORMAT, carry flag set on return means an\r
+ error has occurred: 'Format failure' will be printed\r
+ and FORMAT will prompt for another disk.\r
+\r
+\r
+The following data is declared PUBLIC in Microsoft's FORMAT\r
+module:\r
+\r
+ SWITCHMAP - A word with a bit vector indicating what\r
+ switches have been included in the command line. The\r
+ correspondence of the bits to the switches is\r
+ determined by SWITCHLIST. The right-most\r
+ (highest-addressed) switch in SWITCHLIST (which must\r
+ be the system transfer switch, normally "S")\r
+ corresponds to bit 0, the second from the right,\r
+ normally "V" to bit 1, etc. For example, if\r
+ SWITCHLIST is the string "7,'AGI2OVS'", and the user\r
+ specifies "/G/S" on the command line, then bit 6 will\r
+ be 0 (A not specified), bit 5 will be 1 (G specified),\r
+ bits 4,3,2 and 1 will be 0 (neither I,2,O or V\r
+ specified), and bit 0 will be 1 (S specified).\r
+\r
+ Bits 0,1 and 2 are the only switches used in\r
+ Microsoft's FORMAT module. These switches are used 1)\r
+ after INIT has been called, to determine if it is\r
+ necessary to load the system; 2) after the last\r
+ BADSECTOR call, to determine if the system is to be\r
+ written, E5 directory conversion is to be done, and/or\r
+ a volume label is to be asked for. INIT may force\r
+ these bits set or reset if desired (for example, some\r
+ drives may never be used as system disk, such as hard\r
+ disks). After INIT, the "S" bit may be turned off\r
+ (but not on, since the system was never read) if\r
+ something happens that means the system should not be\r
+ transferred.\r
+\r
+ After INIT, a second copy of SWITCHMAP is made\r
+ internally which is used to restore SWITCHMAP for\r
+ each disk to be formatted. FORMAT itself will turn\r
+ off the system bit if bad sectors are reported in\r
+ the system area; DISKFORMAT and BADSECTOR are also\r
+ allowed to change the map. However, these changes\r
+ affect only the current disk being formatted, since\r
+ SWITCHMAP is restored after each disk. (Changes\r
+ made to SWITCHMAP by INIT do affect ALL disks.)\r
+\r
+ DRIVE - A byte containing the drive specified in the\r
+ command line. 0=A, 1=B, etc.\r
+\r
+Once the OEM-supplied module has been prepared, it must linked\r
+with Microsoft's FORMAT.OBJ module and the FORMES.OBJ module.\r
+If the OEM-supplied module is called OEMFOR.OBJ, then the\r
+following linker command will do:\r
+\r
+ LINK FORMAT FORMES OEMFOR;\r
+\r
+This command will produce a file called FORMAT.EXE. FORMAT\r
+has been designed to run under MS-DOS as a simple binary\r
+.COM file. This conversion is performed by LOCATE (EXE2BIN)\r
+with the command\r
+\r
+ LOCATE FORMAT.EXE FORMAT.COM\r
+\r
+which will produce the file FORMAT.COM.\r
+\r
+;*****************************************\r
+;\r
+; A Sample OEM module\r
+;\r
+;*****************************************\r
+\r
+CODE SEGMENT BYTE PUBLIC 'CODE'\r
+; This segment must be\r
+; named CODE, it must be\r
+; PUBLIC, and it's\r
+; classname must be 'CODE'\r
+ \r
+\r
+ ASSUME CS:CODE,DS:CODE,ES:CODE\r
+\r
+; Must declare data and routines PUBLIC\r
+ \r
+PUBLIC FATID,STARTSECTOR,SWITCHLIST,FREESPACE\r
+PUBLIC INIT,DISKFORMAT,BADSECTOR,DONE,WRTFAT\r
+PUBLIC FATSPACE,HARDFLAG\r
+\r
+; This data defined in Microsoft-supplied module\r
+\r
+ EXTRN SWITCHMAP:WORD,DRIVE:BYTE\r
+\r
+INIT:\r
+\r
+; Read the boot sector into memory\r
+ CALL READBOOT\r
+ ...\r
+; Set FATID to double sided if "D" switch specified\r
+ TEST SWITCHMAP,10H\r
+ JNZ SETDBLSIDE\r
+ ...\r
+ RET\r
+\r
+DISKFORMAT:\r
+ ...\r
+ \r
+; Use the bit map in SWITCHMAP to determine\r
+; what switches are set\r
+\r
+ TEST SWITCHMAP,8 ;Is there a "/C"?\r
+ JNZ CLEAR ; Yes -- clear operation\r
+ ; requested jump around the\r
+ ; format code\r
+ < format the disk >\r
+CLEAR:\r
+ ...\r
+; Transfer the boot from memory to the new disk\r
+ CALL TRANSBOOT\r
+ ...\r
+ RET\r
+\r
+; Error return - set carry\r
+\r
+ERRET:\r
+ STC\r
+ RET\r
+\r
+BADSECTOR:\r
+ ...\r
+ RET\r
+\r
+\r
+WRTFAT:\r
+ ...\r
+\r
+WRTFATLOOP:\r
+ < Set up call to write out a fat to disk>\r
+ ...\r
+ MOV BX,[FATSPACE]\r
+\r
+ < Write out one fat to disk>\r
+ JC ERRET\r
+ ...\r
+ < Decrement fat counter >\r
+ JNZ WRTFATLOOP\r
+ CLC ;Good return\r
+ RET\r
+\r
+\r
+DONE:\r
+ ...\r
+ RET\r
+\r
+; Default Single sided\r
+FATID DB 0FEH\r
+\r
+HARDFLAG DB 0\r
+\r
+STARTSECTOR DW 9\r
+\r
+SWITCHLIST DB 5,"DCOVS" ; "OVS" must be the last\r
+ ; switches in the list\r
+\r
+FATSPACE DW FATBUF\r
+\r
+FREESPACE DW ENDBOOT\r
+\r
+BOOT DB BOOTSIZE DUP(?) ; Buffer for the\r
+ ; boot sector\r
+\r
+FATBUF DB 6 * 1024 DUP(?) ; Fat buffer\r
+ENDBOOT LABEL BYTE\r
+\r
+CODE ENDS\r
+ END \r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+PROGRAM prohst(input,output);\r
+{$debug- $line- $symtab+}\r
+\r
+{**********************************************************************}\r
+{* *}\r
+{* prohst *}\r
+{* *}\r
+{* This program produces a histogram from the profile file produced *}\r
+{* by the MS-DOS profile utility. It optionally reads the map file *}\r
+{* generated when the program being profiled was linked, and writes *}\r
+{* either the module address or, if available, the line number as *}\r
+{* a prefix to the line of the graph which describes a particular *}\r
+{* bucket. *}\r
+{* *}\r
+{* After using filbm (derived from the Pascal and Fortran front end *}\r
+{* command scanner) to parse its parameters, prohst opens the map *}\r
+{* file if specified, searches for the heading line, and then reads *}\r
+{* the lines giving the names and positions of the modules. It builds *}\r
+{* a linked list of module names and start addresses. *}\r
+{* *}\r
+{* It then reads the bucket file header and and bucket array elements *}\r
+{* into a variable created on the heap. It simultaneously calculates *}\r
+{* a normalization factor. It writes the profile listing header and *}\r
+{* starts to write the profile lines. For each bucket, the address *}\r
+{* is calculated. The first entry in the address/name linked list *}\r
+{* is the lowest addressed module. This is initially the 'current' *}\r
+{* module. The bucket address is compared with the current module *}\r
+{* address. When it becomes the greater, the module name is written *}\r
+{* to the listing and the next entry in the address/name list becomes *}\r
+{* the current module. If line numbers are available, the bucket *}\r
+{* address is also compared to the current line/address. This is *}\r
+{* read and calculated directly from the file. Since there may be *}\r
+{* more than one line per bucket, several entries may be read until *}\r
+{* the addresses compare within the span of addresses encompassed by *}\r
+{* a bucket (its 'width'). Note that the idiosyncracies of Pascal i/o *}\r
+{* make it necessary to continually check for the end of the map file *}\r
+{* and the complexity of this code is mainly due to an attempt to *}\r
+{* make it reasonably resilient to changes in the format of the map *}\r
+{* file. *}\r
+{* *}\r
+{**********************************************************************}\r
+\r
+\r
+CONST\r
+ max_file = 32;\r
+\r
+\r
+TYPE\r
+ filenam = LSTRING (max_file);\r
+ sets = SET OF 0..31;\r
+ address_pointer = ^address_record;\r
+ address_record = RECORD\r
+ next: address_pointer;\r
+ name: STRING (15);\r
+ address: WORD;\r
+ END;\r
+\r
+ \r
+\r
+\r
+\r
+VAR\r
+\r
+ i: INTEGER;\r
+ bucket: FILE OF WORD;\r
+ hist: TEXT;\r
+ map: TEXT;\r
+\r
+ first_address,\r
+ this_address: address_pointer; \r
+ current_base: WORD;\r
+ bucket_name,\r
+ hist_name,\r
+ map_name: filenam;\r
+\r
+ switches: sets;\r
+\r
+ line: LSTRING (100);\r
+\r
+ map_avail: BOOLEAN;\r
+ line_nos_avail: BOOLEAN;\r
+\r
+ norm: REAL;\r
+ per_cent: INTEGER;\r
+ real_bucket,\r
+ norm_bucket: REAL;\r
+ cum_per_cent,\r
+ real_per_cent: REAL;\r
+\r
+ bucket_num,\r
+ clock_grain,\r
+ bucket_size,\r
+ prog_low_pa,\r
+ prog_high_pa,\r
+ dos_pa,\r
+ hit_io,\r
+ hit_dos,\r
+ hit_high: WORD;\r
+\r
+ seg,\r
+ offset,\r
+ parcel: WORD;\r
+\r
+ address: WORD;\r
+ new_line_no,\r
+ line_no: WORD;\r
+\r
+ dummy : LSTRING (8);\r
+ name: LSTRING (20);\r
+ line_no_part: LSTRING (17);\r
+ start: LSTRING (6);\r
+\r
+ buckets: ^SUPER ARRAY [1 .. *] OF REAL;\r
+\r
+ this_bucket: WORD;\r
+\r
+LABEL 1;\r
+\r
+\r
+PROCEDURE filbm (VAR prffil, hstfil, mapfil: filenam;\r
+ VAR switches: sets); EXTERN;\r
+\r
+FUNCTION realword (w: WORD): REAL;\r
+BEGIN\r
+ IF ORD (w) < 0 THEN BEGIN\r
+ realword := FLOAT (maxint) + FLOAT (ORD (w - maxint));\r
+ END\r
+ ELSE BEGIN\r
+ realword := FLOAT (ORD(w));\r
+ END {IF};\r
+END {realword};\r
+\r
+\r
+\r
+PROCEDURE skip_spaces;\r
+BEGIN\r
+ WHILE NOT eof(map) AND THEN map^ = ' ' DO BEGIN\r
+ get (map);\r
+ END {WHILE};\r
+END {skip_spaces};\r
+\r
+\r
+FUNCTION hex_char (ch: CHAR): WORD;\r
+BEGIN\r
+ IF ch >= '0' AND THEN ch <= '9' THEN BEGIN\r
+ hex_char := WRD (ch) - WRD ('0');\r
+ END\r
+ ELSE IF ch >= 'A' AND THEN ch <= 'F' THEN BEGIN\r
+ hex_char := WRD (ch) - WRD ('A') + 10;\r
+ END\r
+ ELSE BEGIN\r
+ WRITELN ('Invalid hex character');\r
+ hex_char := 0;\r
+ END {IF};\r
+END {hex_char};\r
+\r
+\r
+FUNCTION read_hex (i :WORD): WORD;\r
+VAR\r
+ hex_val: WORD;\r
+BEGIN\r
+ skip_spaces;\r
+ hex_val := 0;\r
+ WHILE NOT eof (map) AND THEN i <> 0 DO BEGIN\r
+ hex_val := hex_val * 16 + hex_char (map^);\r
+ GET (map);\r
+ i := i - 1;\r
+ END {WHILE};\r
+ read_hex := hex_val;\r
+END {read_hex};\r
+\r
+FUNCTION read_h: WORD;\r
+BEGIN\r
+ read_h := read_hex (4);\r
+ get (map);\r
+ get (map);\r
+END;\r
+\r
+FUNCTION read_word: WORD;\r
+VAR \r
+ int_value: WORD;\r
+BEGIN\r
+ int_value := 0;\r
+ IF NOT EOF (map) THEN BEGIN\r
+ READ (map, int_value);\r
+ END {IF};\r
+ read_word := int_value;\r
+END {read_word};\r
+\r
+\r
+FUNCTION map_digit: BOOLEAN;\r
+BEGIN\r
+ map_digit := (map^ >= '0') OR (map^ <= '9');\r
+END {map_digit};\r
+\r
+BEGIN {prohst}\r
+ writeln (output, ' Profile Histogram Utility - Version 1.0');\r
+ writeln (output);\r
+ writeln (output, ' Copyright - Microsoft, 1983');\r
+ \r
+ start := ' ';\r
+\r
+ filbm (bucket_name, hist_name, map_name, switches);\r
+\r
+ IF 31 IN switches THEN BEGIN\r
+ ABORT ('Map file must not be terminal', 0, 0);\r
+ END {IF};\r
+\r
+ IF NOT (28 IN switches) THEN BEGIN\r
+ ABORT ('No histogram file specified', 0, 0);\r
+ END {IF};\r
+\r
+ ASSIGN (bucket, bucket_name);\r
+ reset (bucket);\r
+ ASSIGN (hist, hist_name);\r
+ rewrite (hist);\r
+ \r
+ map_avail := 29 IN switches;\r
+ line_nos_avail := FALSE;\r
+\r
+ IF map_avail THEN BEGIN\r
+ ASSIGN (map, map_name);\r
+ RESET (map);\r
+ \r
+ WHILE NOT EOF (map) AND THEN start <> ' Start' DO BEGIN\r
+ READLN (map, start);\r
+ END {WHILE};\r
+ \r
+ NEW (first_address);\r
+ this_address := NIL;\r
+\r
+ WHILE NOT EOF(map) DO BEGIN\r
+ READLN (map, line);\r
+ IF line.len < 6 OR ELSE line [2] < '0' OR ELSE\r
+ line [2] > '9' THEN BEGIN\r
+ BREAK;\r
+ END {IF};\r
+\r
+ IF this_address <> NIL THEN BEGIN\r
+ NEW (this_address^.next);\r
+ this_address := this_address^.next;\r
+ END\r
+ ELSE BEGIN\r
+ this_address := first_address;\r
+ END {IF};\r
+ this_address^.next := NIL;\r
+\r
+ this_address^.address := (hex_char (line [2]) * 4096) + \r
+ (hex_char (line [3]) * 256) + \r
+ (hex_char (line [4]) * 16) + \r
+ hex_char (line [5]);\r
+\r
+ FOR i := 1 TO 15 DO BEGIN\r
+ this_address^.name [i] := line [22 + i];\r
+ END {FOR};\r
+\r
+ END {WHILE};\r
+\r
+ WHILE NOT EOF (map) DO BEGIN\r
+ READLN (map, line_no_part);\r
+ IF line_no_part = 'Line numbers for ' THEN BEGIN\r
+ line_nos_avail := TRUE;\r
+ BREAK;\r
+ END {IF};\r
+ END {WHILE};\r
+ \r
+ END {IF};\r
+\r
+ read (bucket, clock_grain, bucket_num, bucket_size,\r
+ prog_low_pa, prog_high_pa, dos_pa, hit_io, hit_dos, hit_high);\r
+\r
+ NEW (buckets,ORD (bucket_num));\r
+\r
+ norm := 0.0;\r
+ norm_bucket := 0.0;\r
+\r
+ FOR i := 1 TO ORD (bucket_num) DO BEGIN\r
+ read (bucket, this_bucket);\r
+ real_bucket := realword (this_bucket);\r
+\r
+ IF real_bucket > norm_bucket THEN BEGIN\r
+ norm_bucket := real_bucket;\r
+ END {IF};\r
+\r
+ norm := norm + real_bucket;\r
+ buckets^[i] := real_bucket;\r
+ END {FOR};\r
+ norm_bucket := 45.0/norm_bucket;\r
+ norm := 100.0/norm;\r
+\r
+ WRITELN (hist, 'Microsoft Profiler Output Listing');\r
+ \r
+ WRITELN (hist);\r
+ WRITELN (hist, ORD (bucket_num):6, bucket_size:4,'-byte buckets.');\r
+\r
+ WRITELN (hist);\r
+ WRITELN (hist, 'Profile taken between ', prog_low_pa*16::16,\r
+ ' and ', prog_high_pa*16::16, '.');\r
+\r
+ WRITELN (hist);\r
+ WRITELN (hist, 'DOS program address:', dos_pa::16);\r
+\r
+ WRITELN (hist);\r
+ WRITELN (hist, 'Number of hits in DOS: ', hit_dos:5, \r
+ ' or ', realword (hit_dos) * norm:4:1, '%.');\r
+ WRITELN (hist, 'Number of hits in I/O: ', hit_io:5,\r
+ ' or ', realword (hit_io) * norm:4:1, '%.');\r
+ WRITELN (hist, 'Number of hits high : ', hit_high:5,\r
+ ' or ', realword (hit_high) * norm:4:1, '%.');\r
+ WRITELN (hist);\r
+ WRITELN (hist, ' Hits Addr. Line/ Cumul. % 0.0 ',\r
+ ' ',\r
+ 1.0/norm:1:1);\r
+\r
+ WRITELN (hist, ' Offset +----------------',\r
+ '----------------------------');\r
+ WRITELN (hist, name);\r
+ i := 0;\r
+ parcel := 0;\r
+ current_base := 0;\r
+ line_no := 0;\r
+ new_line_no := 0;\r
+ cum_per_cent := 0.0;\r
+\r
+ WHILE i < ORD (bucket_num) DO BEGIN\r
+ i := i + 1;\r
+ IF buckets^[i] < 0.9 THEN BEGIN\r
+ WRITELN (hist);\r
+ REPEAT\r
+ i := i + 1;\r
+ UNTIL (i = ORD (bucket_num)) OR ELSE buckets^[i] > 0.0;\r
+ END {IF};\r
+\r
+ address := bucket_size * (WRD (i) - 1);\r
+ \r
+ WHILE map_avail AND THEN\r
+ address >= first_address^.address DO BEGIN\r
+ WRITELN (hist, ' ', first_address^.name);\r
+ current_base := first_address^.address;\r
+ first_address := first_address^.next;\r
+ END {WHILE};\r
+\r
+ WHILE line_nos_avail AND THEN NOT eof (map) AND THEN\r
+ address >= parcel DO BEGIN\r
+ skip_spaces;\r
+ WHILE (map^ < '0') OR (map^ > '9') DO BEGIN\r
+ \r
+ IF EOF (map) THEN BEGIN\r
+ goto 1;\r
+ END {IF};\r
+ READLN (map);\r
+ skip_spaces;\r
+ END {WHILE};\r
+\r
+\r
+ line_no := new_line_no;\r
+ new_line_no := read_word;\r
+ seg := read_hex (4);\r
+ IF EOF (map) THEN BEGIN\r
+ GOTO 1;\r
+ END {IF};\r
+ IF map^ <> ':' THEN BEGIN\r
+ WRITELN ('Invalid map file');\r
+ END {IF};\r
+ get (map);\r
+ IF EOF (map) THEN BEGIN\r
+ GOTO 1;\r
+ END {IF};\r
+ offset := read_hex (3) + WRD (hex_char (map^) > 0);\r
+ get (map);\r
+ IF map^ <> 'H' THEN BEGIN\r
+ WRITELN ('Invalid map file');\r
+ END {IF};\r
+ IF EOF (map) THEN BEGIN\r
+ GOTO 1;\r
+ END {IF};\r
+ get (map);\r
+ parcel := seg + offset;\r
+ END {WHILE};\r
+1: real_per_cent := buckets^[i] * norm;\r
+ cum_per_cent := cum_per_cent + real_per_cent;\r
+ per_cent := ROUND ( buckets^[i] * norm_bucket);\r
+\r
+ WRITE (hist, buckets^ [i]:6:0, ' ',\r
+ address*16:6:16);\r
+ IF line_no <> 0 THEN BEGIN \r
+ WRITE (hist, line_no:6);\r
+ line_no := 0;\r
+ END\r
+ ELSE IF map_avail AND THEN first_address <> NIL THEN BEGIN\r
+ WRITE (hist, ' #', address - first_address^.address:4:16);\r
+ END\r
+ ELSE BEGIN\r
+ WRITE (hist, ' ');\r
+ END {IF};\r
+ \r
+ WRITELN (hist, ' ', cum_per_cent:5:1, ' ', real_per_cent:4:1, ' |',\r
+ '*': per_cent);\r
+ END {WHILE};\r
+ WRITELN (hist, ' +-----------------',\r
+ '------------------');\r
+END.\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+ MSDOS 2.0 RELEASE\r
+\r
+\r
+The 2.0 Release of MSDOS includes five 5 1/4 double density single sided\r
+diskettes or three 8 iinch CP/M 80 format diskettes.\r
+\r
+The software/documentation on the five inch diskettes is arranged\r
+as follows:\r
+\r
+1. DOS distribution diskette. This diskette contains files which\r
+ should be distriibuted to all users. This allows the DOS distri-\r
+ bution diskette to meet the requirements of users of high level\r
+ language compilers as well as users running only applications.\r
+ Many compilers marketed independently through the retail channel\r
+ (including those of Microsoft) assume LINK comes with the DOS, as\r
+ in the case of IBM. How you choose to distrubute BASIC (contracted\r
+ for separately) is up to you.\r
+\r
+2. Assembly Language Development System diskette. This diskette\r
+ contains files of interest to assembly language programmers.\r
+ High level language programmers do not need these programs unless\r
+ they are writing assembly language subroutines. IBM chose to\r
+ unbundle this package from the DOS distribution diskette (except\r
+ for DEBUG), but you do not have to do so.\r
+\r
+3. PRINT and FORMAT diskette. This diskette contains .ASM source\r
+ files which are necessary to assemble the print spooler, which you\r
+ may wish to customize for greater performance. .OBJ files are also\r
+ included for the FORMAT utility.\r
+\r
+4. Skeltal BIOS and documentation diskette. This diskette contains\r
+ the skeltal BIOS source code and the SYSINIT and SYSIMES object\r
+ modules which must be linked with your BIOS module. The proper\r
+ sequence for linking is BIOS - SYSINIT - SYSIMES.\r
+ A profiler utiliity is also included on the diskette, but this\r
+ is not intended for end-users. This is distributed for use by\r
+ your development staff only and is not supported by Microsoft\r
+ If you do decide to distribute it, it is at your own risk!\r
+\r
+\r
+5. Documentation. Features of 2.0 are documented on this disk.\r
+\r
+The user manual contains some significant errors. Most of these are\r
+due to last minute changes to achieve a greater degree of compatibility\r
+with IBM's implementation of MS-DOS (PC DOS). This includes the use\r
+of "\" instead of "/" as the path separator, and "/" instead of "-"\r
+as the switch character. For transporting of batch files across\r
+machines, Microsoft encourages the use of "\" and "/" respectively\r
+in the U.S. market. (See DOSPATCH.TXT for how you can overide this.\r
+The user guide explains how the end-user can override this in CONFIG.SYS).\r
+Both the printer echo keys and insert mode keys have now been made to\r
+toggle. The default prompt (this may also be changed by the user\r
+with the PROMPT command) has been changed from "A:" to "A>".\r
+We apologize for any inconveniences these changes may have caused\r
+your technical publications staff.\r
+\r
+\r
+Here is what you need to do to MSDOS 2.0 to create a shipable product:\r
+(see "Making a Bootable Diskette" below)\r
+\r
+1. BIOS. If you have developed a BIOS for the Beta Test 2.0 version\r
+ You should link your BIOS module to SYSINIT.OBJ and SYSIMES.OBJ.\r
+ You must modify your BIOS to accomodate the call back to the BIOS\r
+ at the end of SYSINIT. If you have no need for this call, simply\r
+ find a far RET and label it RE_INIT and declare it public.\r
+ An example of this can be found in the skeletal BIOS. In addition\r
+ please add support for the new fast console output routine as\r
+ described in the device drivers document. We strongly recommend\r
+ that you adapt the standard boot sector format also described in\r
+ device drivers. Once again, please refer to the skeletal BIOS.\r
+ If you have not yet implemented version 2.0 please read the device\r
+ drivers document. Microsoft strongly recommends that machines\r
+ incorporating integrated display devices with memory mapped video\r
+ RAM implement some sort of terminal emulations through the use of\r
+ escape sequences. The skeletal BIOS includes a sample ANSI\r
+ terminal driver.\r
+\r
+2. Please refer to DOSPATCH.TXT for possible changes you might wish\r
+ to make. We strongly recommend that you not patch the switch\r
+ characters for the U.S. market. Your one byte serial number\r
+ will be issued upon signing the license agreement. Please patch\r
+ the DOS accordingly. If you wish to serialize the DOS, this is\r
+ described in DOSPATCH.TXT. Please patch the editing template\r
+ definitions. Please note the addition of the Control-Z entry\r
+ at the beginning of the table. Also note that the insert switches\r
+ have now both been made to toggle.\r
+\r
+3. Utilities. FORMAT must be configured for each specific system.\r
+ GENFOR is a generic example of a system independent format module,\r
+ but it is not recommended that this be distributed to your customers.\r
+ Link in the following order: FORMAT, FORMES, (your format module).\r
+ The print spooler is distributed as an executable file, which only\r
+ prints during wait for keyboard input. If you wish with your\r
+ implementation to steal some compute time when printing as well,\r
+ you will need to customize it and reassemble. Please note that\r
+ you can use a printer-ready or timer interrupt. The former is more\r
+ efficient, but ties the user to a specific device. Sample code\r
+ is conditionaled out for the IBM PC timer interrupt.\r
+\r
+The following problems are known to exist:\r
+\r
+1. Macro assembler does not support the initialization of 10-byte\r
+ floating point constants in 8087 emulation mode - the last two bytes\r
+ are zero filled.\r
+\r
+2. LIB has not been provided. The version which incorporates support\r
+ for 2.0 path names will be completed in a couple of weeks. The\r
+ 1.x version should work fine if you cannot wait. Because the library\r
+ manager acts as a counterpart to the linker, we recommend that it\r
+ be distributed with the DOS distribution diskette as opposed to the\r
+ assembly language development system.\r
+\r
+3. International (French, German, Japanese, and U.K.) versions will be\r
+ available in several months.\r
+\r
+4. COMMAND.ASM is currently too large to assemble on a micro. It is\r
+ being broken down into separate modules so it can be asembled on\r
+ a machine. Source licensees should realize that the resultant\r
+ binaries from the new version will not correspond exactly to the\r
+ old version.\r
+\r
+5. If you have any further questions regarding the MSDOS 2.0 distribution\r
+ please contact Don Immerwahr (OEM technical support (206) 828-8086).\r
+\r
+\r
+ Sincerely yours,\r
+\r
+\r
+ Chris Larson\r
+ MS-DOS Product Marketing Manager\r
+ (206) 828-8080\r
+\r
+\r
+\r
+ BUILDING A BOOTABLE (MSDOS FORMAT) DISKETTE\r
+\r
+\r
+1. In implementing MSDOS on a new machine, it is highly recommended\r
+ that an MSDOS machine be available for the development.\r
+ Please note that utilities shipped with MSDOS 2.0 use MSDOS 2.0\r
+ system calls and WILL NOT not run under MSDOS 1.25.\r
+\r
+2. Use your MSDOS development machine and EDLIN or a word processor\r
+ package to write BOOT.ASM, your bootstrap loader BIOS.ASM and\r
+ your Format module.\r
+\r
+3. Use MASM, the Microsoft Macro-86 Assembler, to assemble these\r
+ modules. LINK is then used to link together the .OBJ modules in\r
+ the order specified.\r
+\r
+4. Link creates .EXE format files which are not memory image files\r
+ and contain relocation information in their headers. Since your\r
+ BIOS and BOOT routines will not be loaded by the EXE loader in\r
+ MSDOS, they must first be turned into memory image files by\r
+ using the EXE2BIN utility.\r
+\r
+5. The easiest thing to do is to (using your development machine)\r
+ FORMAT a single sided diskette without the system. Use DEBUG\r
+ to load and write your BOOT.COM bootstrap loader to the BOOT\r
+ sector of that diskette. You may decide to have your bootstrap\r
+ load BIOS and let the BIOS load MSDOS or it may load both. Note that\r
+ the Bootstrap loader will have to know physically where to go on\r
+ the disk to get the BIOS and the DOS. COMMAND.COM is loaded\r
+ by the SYSINIT module.\r
+\r
+6. Use the COPY command to copy your IO.SYS file (what the\r
+ BIOS-SYSINIT-SYSIMES module is usually called) onto the disk\r
+ followed by MSDOS.SYS and COMMAND.COM. You may use DEBUG\r
+ to change the directory attribute bytes to make these files hidden.\r
+\r
+CAUTION:\r
+\r
+At all times, the BIOS writer should be careful to preserve the state\r
+of the DOS - including the flags. You should be also be cautioned that\r
+the MSDOS stack is not deep. You should not count on more than one or\r
+two pushes of the registers.\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ MS-DOS 2.0\r
+\r
+ System Calls Reference\r
+\f\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+| |\r
+| C A V E A T P R O G R A M M E R |\r
+| |\r
+| Certain structures, constants and system calls below |\r
+| are private to the DOS and are extremely |\r
+| version-dependent. They may change at any time at the |\r
+| implementors' whim. As a result, they must not be |\r
+| documented to the general public. If an extreme case |\r
+| arises, they must be documented with this warning. |\r
+| |\r
+| Those structures and constants that are subject to the |\r
+| above will be marked and bracketed with the flag: |\r
+| |\r
+| C A V E A T P R O G R A M M E R |\r
+| |\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+\f\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ Section 1\r
+\r
+ Extensions to existing call structure\r
+\f\r
+\r
+ Name: * Alloc - allocate memory\r
+\r
+ Assembler usage:\r
+ MOV BX,size\r
+ MOV AH,Alloc\r
+ INT 21h\r
+ ; AX:0 is pointer to allocated memory\r
+ ; if alloc fails, BX is the largest block available\r
+\r
+ Description:\r
+ Alloc returns a pointer to a free block of memory\r
+ that has the requested size in paragraphs.\r
+\r
+ Error return:\r
+ AX = error_not_enough_memory\r
+ The largest available free block is smaller\r
+ than that requested or there is no free block.\r
+ = error_arena_trashed\r
+ The internal consistency of the memory arena\r
+ has been destroyed. This is due to a user\r
+ program changing memory that does not belong\r
+ to it.\r
+\f\r
+\r
+ Name: * CharOper - change incompatible configuration\r
+ parameters\r
+\r
+ Assembler usage:\r
+ MOV AH, CharOper\r
+ MOV AL, func\r
+ MOV DL, data\r
+ INT 21h\r
+ ; on read functions, data is returned in DL\r
+\r
+ Description:\r
+ CharOper allows a program to change system\r
+ parameters to allow for switch indicators and whether\r
+ devices are available at every level of the directory\r
+ tree.\r
+\r
+ A function code is passed in AL:\r
+\r
+ AL Function\r
+ -- --------\r
+ 0 DL, on return, will contain the DOS switch\r
+ character. On most systems this will default to\r
+ '-'.\r
+ 1 Set the switch character to the character in DL.\r
+ 2 Read the device availability byte into DL. If\r
+ this byte is 0, then devices must be accessed in\r
+ file I/O calls by /dev/device. If this byte is\r
+ non-zero, then the devices are available at every\r
+ node of the directory tree (i.e. CON is the\r
+ console device not the file CON). This byte is\r
+ generally 0.\r
+ 3 Set the device availability byte to the value in\r
+ DL.\r
+\r
+ Error returns:\r
+ AL = FF\r
+ The function code specified in AL is not in\r
+ the range 0:3\r
+\f\r
+\r
+ Name: * CurrentDir - return text of current directory\r
+\r
+ Assembler usage:\r
+ MOV AH,CurrentDir\r
+ LDS SI,area\r
+ MOV DL,drive\r
+ INT 21h\r
+ ; DS:SI is a pointer to 64 byte area that contains\r
+ ; drive current directory.\r
+\r
+ Description:\r
+ CurrentDir returns the current directory for a\r
+ particular drive. The directory is root-relative and\r
+ does not contain the drive specifier. The drive code\r
+ passed in DL is 0=default, 1=A, 2=B, etc.\r
+\r
+ Error returns:\r
+ AX = error_invalid_drive\r
+ The drive specified in DL was invalid.\r
+\f\r
+\r
+ Name: * Dealloc - free allocated memory\r
+\r
+ Assembler usage:\r
+ MOV ES,block\r
+ MOV AH,dealloc\r
+ INT 21h\r
+\r
+ Description:\r
+ Dealloc returns a piece of memory to the system\r
+ pool that was allocated by alloc.\r
+\r
+ Error return:\r
+ AX = error_invalid_block\r
+ The block passed in ES is not one allocated\r
+ via Alloc.\r
+ = error_arena_trashed\r
+ The internal consistency of the memory arena\r
+ has been destroyed. This is due to a user\r
+ program changing memory that does not belong\r
+ to it.\r
+\f\r
+\r
+ Name: * FileTimes - get/set the write times of a\r
+ handle\r
+\r
+ Assembler usage:\r
+ MOV AH, FileTimes\r
+ MOV AL, func\r
+ MOV BX, handle\r
+ ; if AL = 1 then then next two are mandatory\r
+ MOV CX, time\r
+ MOV DX, date\r
+ INT 21h\r
+ ; if AL = 0 then CX/DX has the last write time/date\r
+ ; for the handle.\r
+\r
+ Description:\r
+ FileTimes returns or sets the last-write time for\r
+ a handle. These times are not recorded until the file\r
+ is closed.\r
+\r
+ A function code is passed in AL:\r
+\r
+ AL Function\r
+ -- --------\r
+ 0 Return the time/date of the handle in CX/DX\r
+ 1 Set the time/date of the handle to CX/DX\r
+\r
+ Error returns:\r
+ AX = error_invalid_function\r
+ The function passed in AL was not in the range\r
+ 0:1.\r
+ = error_invalid_handle\r
+ The handle passed in BX was not currently\r
+ open.\r
+\f\r
+\r
+ Name: * FindFirst - find matching file\r
+\r
+ Assembler usage:\r
+ MOV AH, FindFirst\r
+ LDS DX, pathname\r
+ MOV CX, attr\r
+ INT 21h\r
+ ; DMA address has datablock\r
+\r
+ Description:\r
+ FindFirst takes a pathname with wildcards in the\r
+ last component (passed in DS:DX), a set of attributes\r
+ (passed in CX) and attempts to find all files that\r
+ match the pathname and have a subset of the required\r
+ attributes. A datablock at the current DMA is written\r
+ that contains information in the following form:\r
+\r
+ find_buf STRUC\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+| C A V E A T P R O G R A M M E R |\r
+| |\r
+ find_buf_sattr DB ? ; attribute of search\r
+ find_buf_drive DB ? ; drive of search\r
+ find_buf_name DB 11 DUP (?); search name\r
+ find_buf_LastEnt DW ? ; LastEnt\r
+ find_buf_ThisDPB DD ? ; This DPB\r
+ find_buf_DirStart DW ? ; DirStart\r
+| |\r
+| C A V E A T P R O G R A M M E R |\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+\r
+ find_buf_attr DB ? ; attribute found\r
+ find_buf_time DW ? ; time\r
+ find_buf_date DW ? ; date\r
+ find_buf_size_l DW ? ; low(size)\r
+ find_buf_size_h DW ? ; high(size)\r
+ find_buf_pname DB 13 DUP (?) ; packed name\r
+ find_buf ENDS\r
+\r
+ To obtain the subsequent matches of the pathname,\r
+ see the description of FindNext\r
+\r
+ Error Returns:\r
+ AX = error_file_not_found\r
+ The path specified in DS:DX was an invalid\r
+ path.\r
+ = error_no_more_files\r
+ There were no files matching this\r
+ specification.\r
+\f\r
+\r
+ Name: * FindNext - step through a directory matching\r
+ files\r
+\r
+ Assembler usage:\r
+ ; DMA points at area returned by find_first\r
+ MOV AH, findnext\r
+ INT 21h\r
+ ; next entry is at dma\r
+\r
+ Description:\r
+ FindNext finds the next matching entry in a\r
+ directory. The current DMA address must point at a\r
+ block returned by FindFirst (see FindFirst).\r
+\r
+ Error Returns:\r
+ AX = error_no_more_files\r
+ There are no more files matching this pattern.\r
+\f\r
+\r
+ Name: * GetDMA - get current DMA transfer address\r
+\r
+ Assembler usage:\r
+ MOV AH,GetDMA\r
+ INT 21h\r
+ ; ES:BX has current DMA transfer address\r
+\r
+ Description:\r
+ Return DMA transfer address.\r
+\r
+ Error returns:\r
+ None.\r
+\f\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+| C A V E A T P R O G R A M M E R |\r
+| |\r
+\r
+ Name: * GetDSKPT(DL) - get pointer to drive parameter\r
+ block\r
+\r
+ Assembler usage:\r
+ MOV AH,GetDSKPT\r
+ INT 21h\r
+ ; DS:BX has address of drive parameter block\r
+\r
+ Description:\r
+ Return pointer to default drive parameter block.\r
+\r
+ Error returns:\r
+ None.\r
+\r
+ Assembler usage:\r
+ MOV DL,DrvNUM\r
+ MOV AH,GetDSKPTDL\r
+ INT 21h\r
+ ; DS:BX has address of drive parameter block\r
+\r
+ Description:\r
+ Return pointer to drive parameter block for drive\r
+ designated in DL (0=Default, A=1, B=2 ...)\r
+\r
+ Error returns:\r
+ AL = FF\r
+ The drive given in DL is invalid.\r
+| |\r
+| C A V E A T P R O G R A M M E R |\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+\f\r
+\r
+ Name: * GetFreespace - get Disk free space\r
+\r
+ Assembler usage:\r
+ MOV AH,GetFreespace\r
+ MOV DL,Drive ;0 = default, A = 1\r
+ INT 21h\r
+ ; BX = Number of free allocation units on drive\r
+ ; DX = Total number of allocation units on drive\r
+ ; CX = Bytes per sector\r
+ ; AX = Sectors per allocation unit\r
+\r
+ Description:\r
+ Return Free space on disk along with additional\r
+ information about the disk.\r
+\r
+ Error returns:\r
+ AX = FFFF\r
+ The drive number given in DL was invalid.\r
+\r
+ NOTE: This call returns the same information in the same\r
+ registers (except for the FAT pointer) as the get FAT\r
+ pointer calls did in previous versions of the DOS.\r
+\f\r
+\r
+ Name: * GetInDOSF - get DOS critical-section flag\r
+\r
+ Assembler usage:\r
+ MOV AH,GetInDOSF\r
+ INT 21h\r
+ ; ES:BX has location of the flag\r
+ MOV CritSEG, ES\r
+ MOV CritOFF, BX\r
+ ...\r
+ IntVec:\r
+ MOV AX, DWORD PTR Crit\r
+ CMP AX,0\r
+ JZ DoFunc\r
+ IRET\r
+ DoFunc: ...\r
+\r
+ Description:\r
+ Return location of indos flag. On return ES:BX is\r
+ the address of a byte memory cell inside the DOS. If\r
+ used in an interrupt service routine, it indicates\r
+ whether or not the DOS was interrupted in a critical\r
+ section. If the cell was zero, then the DOS was not\r
+ in a critical section and thus can be called by the\r
+ interrupt routine. If the cell was non-zero, the DOS\r
+ should be considered to be in an uninterruptable state\r
+ and for reliability, no DOS calls should be given.\r
+\r
+ Error returns:\r
+ None.\r
+\f\r
+\r
+ Name: * GetVector - get interrupt vector\r
+\r
+ Assembler usage:\r
+ MOV AH,GetVector\r
+ MOV AL,interrupt\r
+ INT 21h\r
+ ; ES:BX now has long pointer to interrupt routine\r
+\r
+ Description:\r
+ Return interrupt vector associated with an\r
+ interrupt.\r
+\r
+ Error returns:\r
+ None.\r
+\f\r
+\r
+ Name: * GetVerifyFlag - return current setting of the\r
+ verify after write flag.\r
+\r
+ Assembler usage:\r
+ MOV AH,GetVerifyFlag\r
+ INT 21h\r
+ ; AL is the current verify flag value\r
+\r
+ Description:\r
+ The current value of the verify flag is returned\r
+ in AL.\r
+\r
+ Error returns:\r
+ None.\r
+\f\r
+\r
+ Name: * GetVersion - get DOS version number\r
+\r
+ Assembler usage:\r
+ MOV AH,GetVersion\r
+ INT 21h\r
+ ; AL is the major version number\r
+ ; AH is the minor version number\r
+ ; BH is the OEM number\r
+ ; BL:CX is the (24 bit) user number\r
+\r
+ Description:\r
+ Return MS-DOS version number. On return AL.AH\r
+ will be the two part version designation, ie. for\r
+ MS-DOS 1.28 AL would be 1 and AH would be 28. For pre\r
+ 1.28 DOS AL = 0. Note that version 1.1 is the same as\r
+ 1.10, not the same as 1.01.\r
+\r
+ Error returns:\r
+ None.\r
+\f\r
+\r
+ Name: * International - return country dependent\r
+ information\r
+\r
+ Assembler usage:\r
+ LDS DX, blk\r
+ MOV AH, International\r
+ MOV AL, func\r
+ INT 21h\r
+\r
+ Description:\r
+ This call returns in the block of memory pointed\r
+ to by DS:DX, the following information pertinent to\r
+ international applications:\r
+\r
+ +---------------------------+\r
+ | WORD Date/time format |\r
+ +---------------------------+\r
+ | BYTE ASCIZ string |\r
+ | currency symbol |\r
+ +---------------------------+\r
+ | BYTE ASCIZ string |\r
+ | thousands separator |\r
+ +---------------------------+\r
+ | BYTE ASCIZ string decimal |\r
+ | separator |\r
+ +---------------------------+\r
+\r
+ The date/time format has the following values and\r
+ meanings:\r
+\r
+ 0 - USA standard h:m:s m/d/y\r
+ 1 - Europe standard h:m:s d/m/y\r
+ 2 - Japan standard y/m/d h:m:s\r
+\r
+ The value passed in AL is either 0 (for current\r
+ country) or a country code (to be defined later.\r
+ Currently the country code must be zero).\r
+\r
+ Error returns:\r
+ AX = error_invalid_function\r
+ The function passed in AL was not 0\r
+ (currently).\r
+\f\r
+\r
+ Name: * KeepProcess - terminate process and remain\r
+ resident\r
+\r
+ Assembler usage:\r
+ MOV AL, exitcode\r
+ MOV DX, parasize\r
+ MOV AH, KeepProcess\r
+ INT 21h\r
+\r
+ Description:\r
+ This call terminates the current process and\r
+ attempts to set the initial allocation block to a\r
+ specific size in paragraphs. It will not free up any\r
+ other allocation blocks belonging to that process.\r
+ The exit code passed in AX is retrievable by the\r
+ parent via Wait.\r
+\r
+ Error Returns:\r
+ None.\r
+\f\r
+\r
+ Name: * Rename - move a directory entry\r
+\r
+ Assembler usage:\r
+ LDS DX, source\r
+ LES DI, dest\r
+ MOV AH, Rename\r
+ INT 21h\r
+\r
+ Description:\r
+ Rename will attempt to rename a file into another\r
+ path. The paths must be on the same device.\r
+\r
+ Error returns:\r
+ AX = error_file_not_found\r
+ The file name specifed by DS:DX was not found.\r
+ = error_not_same_device\r
+ The source and destination are on different\r
+ drives.\r
+ = error_access_denied\r
+ The path specified in DS:DX was a directory or\r
+ the file specified by ES:DI exists or the\r
+ destination directory entry could not be\r
+ created.\r
+\f\r
+\r
+ Name: * SetBlock - modify allocated blocks\r
+\r
+ Assembler usage:\r
+ MOV ES,block\r
+ MOV BX,newsize\r
+ MOV AH,setblock\r
+ INT 21h\r
+ ; if setblock fails for growing, BX will have the\r
+ ; maximum size possible\r
+\r
+ Description:\r
+ Setblock will attempt to grow/shrink an allocated\r
+ block of memory.\r
+\r
+ Error return:\r
+ AX = error_invalid_block\r
+ The block passed in ES is not one allocated\r
+ via Alloc.\r
+ = error_arena_trashed\r
+ The internal consistency of the memory arena\r
+ has been destroyed. This is due to a user\r
+ program changing memory that does not belong\r
+ to it.\r
+ = error_not_enough_memory\r
+ There was not enough free memory after the\r
+ specified block to satisfy the grow request.\r
+\f\r
+\r
+ Name: * SetCtrlCTrapping - turn on/off broad ^C\r
+ checking\r
+\r
+ Assembler usage:\r
+ MOV DL,val\r
+ MOV AH,SetCtrlCTrapping\r
+ MOV AL,func\r
+ INT 21h\r
+ ; If AL was 0, then DL has the current value of the\r
+ ; ^C check\r
+\r
+ Description:\r
+ MSDOS ordinarily checks for a ^C on the\r
+ controlling device only when doing a function 1-12\r
+ operation to that device. SetCtrlCTrapping allows the\r
+ user to expand this checking to include any system\r
+ call. For example, with the ^C trapping off, all disk\r
+ I/O will proceed without interruption while with ^C\r
+ trapping on, the ^C interrupt is given at the system\r
+ call that initiates the disk operation.\r
+\r
+ Error return:\r
+ AL = FF\r
+ The function passed in AL was not in the range\r
+ 0:1.\r
+\f\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+| C A V E A T P R O G R A M M E R |\r
+| |\r
+\r
+ Name: * Set_OEM_Handler - set handler for OEM\r
+ specific INT 21H calls.\r
+\r
+ Assembler usage:\r
+ LDS DX,handler_address\r
+ MOV AH,Set_OEM_Handler\r
+ INT 21H\r
+\r
+ Description:\r
+ Set handler address for 0F9H-0FFH INT 21H system\r
+ calls to DS:DX. To return the 0F9H-0FFH calls to\r
+ the uninitialized state, give DS=DX=-1.\r
+\r
+ Error returns:\r
+ None.\r
+\r
+ Handler entry:\r
+ All registers as user set them when INT 21H\r
+ issued (including SS:SP). INT 21 return is on\r
+ stack, so the correct method for the OEM handler\r
+ to return to the user is to give an IRET. The\r
+ OEM handler is free to make any INT 21H system\r
+ call (including the 0F9H- 0FFH group if the OEM\r
+ handler is re-entrant).\r
+\r
+\r
+ The AH INT 21H function codes 0F8H through 0FFH are\r
+ reserved for OEM extensions to the INT 21H calling\r
+ convention. These calls have two states, initialized\r
+ and uninitialized. There will be one handler for all 7\r
+ (0F9-0FFH) functions. When the DOS is first\r
+ initialized, these calls are uninitialized. The AH=0F8H\r
+ call is the call which will set the handler address for\r
+ the 0F9-0FFH calls. If the 0F9-0FFH calls are\r
+ uninitialized, an attempt to call them results in the\r
+ normal invalid system call number return.\r
+ OEMs should NOT document the 0F8 call.\r
+| |\r
+| C A V E A T P R O G R A M M E R |\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+\f\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ Section 2\r
+\r
+ XENIX-compatible system calls\r
+\f\r
+\r
+\r
+ Previous to version 2.0, MSDOS had a simple single\r
+ directory structure that sufficed for small (160k to 320K)\r
+ diskettes. As the need for hard disk support grows, and\r
+ as MSDOS 2.0 will support a wide variety of hard disks,\r
+ the need for better disk organization also grows. Merely\r
+ expanding the directory is not an effective solution;\r
+ doing a 'DIR' on a directory with 1000 files is not a\r
+ user-friendly characteristic.\r
+\r
+ People, by nature, think in hierarchical terms:\r
+ organization charts and family trees, for example. It\r
+ would be nice to allow users to organize their files on\r
+ disk in a similar manner. Consider the following:\r
+\r
+ In a particular business, both sales and accounting\r
+ share a computer with a large disk and the individual\r
+ employees use it for preparation of reports and\r
+ maintaining accounting information. One would naturally\r
+ view the organization of files on the disk in this\r
+ fashion:\r
+\r
+ +-disk-+\r
+ / \\r
+ / \\r
+ / \\r
+ sales accounting\r
+ / | | \\r
+ / | | \\r
+ / | | \\r
+ John Mary Steve Sue\r
+ / | (A) | | | \\r
+ / | | | | \\r
+ / | | | | \\r
+ report accts. report accts. report report\r
+ receiv. receiv\r
+\r
+ In MSDOS 2.0 the user can arrange his files in such a\r
+ manner that files that are not part of his current task do\r
+ not interfere with that task. Pre-2.0 versions of MSDOS\r
+ has a single directory that contains files. MSDOS extends\r
+ this concept to allow a directory to contain both files\r
+ and directories and to introduce the notion of the\r
+ 'current' directory.\r
+\r
+ To specify a filename, the user could use one of two\r
+ methods, either specify a path from the root node to the\r
+ file, or specify a path from the current node to the file.\r
+ A path is a series of directory names separated by '/' and\r
+ ending with a filename. A path that starts at the root\r
+ begins with a '/'.\r
+\r
+ There is a special directory entry in each directory,\r
+ denoted by '..' that is the parent of the directory. The\r
+ root directory's parent is itself (who created God?).\r
+\r
+ Using a directory structure like the hierarchy above,\r
+ and assuming that the current directory is at point (D),\r
+ to reference the report under John, the following are all\r
+ equivalent:\r
+\r
+ report\r
+ /sales/John/report\r
+ ../John/report\r
+\r
+ To refer to the report under Mary, the following are\r
+ all equivalent:\r
+\r
+ ../Mary/report\r
+ /sales/Mary/report\r
+\r
+ To refer to the report under Sue, the following are\r
+ all equivalent.\r
+\r
+ ../../accounting/Sue/report\r
+ /accounting/Sue/report\r
+\r
+ There is no restriction in MSDOS 2.0 on the depth of a\r
+ tree (the length of the longest path from root to leaf)\r
+ except in the number of allocation units available. The\r
+ root directory will have a fixed number of entries, 64 for\r
+ the single sided diskettes to XXX for a large hard disk.\r
+ For non-root directories, there is no limit to the number\r
+ of files per directory excepting in the number of\r
+ allocation units available.\r
+\r
+ Old (pre-2.0) disks will appear to MSDOS 2.0 as having\r
+ only a root directory with files in it and no\r
+ subdirectories whatever.\r
+\r
+ Implementation of the tree-structure is simple. The\r
+ root directory is the pre-2.0 directory. Subdirectories\r
+ of the root have a special attribute set indicating that\r
+ they are directories. The subdirectories themselves are\r
+ files, linked through the FAT as usual. Their contents\r
+ are identical in character to the contents of the root\r
+ directory.\r
+\r
+ Pre-2.0 programs that use system calls not described\r
+ below will not be able to make use of files in other\r
+ directories. They will only be able to access files in\r
+ the current directory. This is no great loss of\r
+ functionality as users will aggregate their files into\r
+ sub-directories on basis of functionality; the files that\r
+ are being used will be found in the current directory.\r
+ Those that are not necessary for the current task will be\r
+ placed in other directories. Out of sight, out of mind.\r
+\r
+ There are also new attributes in 2.0. These and the\r
+ old attributes apply to the tree structured directories in\r
+ the following manner:\r
+\r
+ Attribute Meaning/Function Meaning/Function\r
+ for files for directories\r
+\r
+ volume_id Present at the root. Meaningless.\r
+ Only one file may have\r
+ this set.\r
+\r
+ directory Meaningless. Indicates that the\r
+ directory entry is a\r
+ directory. Cannot be\r
+ changed with ChMod.\r
+\r
+ read_only Old fcb-create, new Meaningless.\r
+ Creat, new open (for\r
+ write or read/write)\r
+ will fail.\r
+\r
+ archive Set when file is Meaningless.\r
+ written. Set/reset via\r
+ ChMod.\r
+\r
+ hidden/ Prevents file from Prevents directory\r
+ system being found in search entry from being\r
+ first/search next. found. ChDir to\r
+ New open will fail. directory will still\r
+ work.\r
+\f\r
+\r
+ Name: * ChDir - Change the current directory\r
+\r
+ Assembler usage:\r
+ LDS DX, name\r
+ MOV AH, ChDir\r
+ INT 21h\r
+\r
+ Description:\r
+ ChDir is given the ASCIZ name of the directory\r
+ which is to become the current directory. If any\r
+ member of the specified pathname does not exist, then\r
+ the current directory is unchanged. Otherwise, the\r
+ current directory is set to the string.\r
+\r
+ Error returns:\r
+ AX = error_path_not_found\r
+ The path specified in DS:DX either indicated a\r
+ file or the path was invalid.\r
+\f\r
+\r
+ Name: * ChMod - change write protection\r
+\r
+ Assembler usage:\r
+ LDS DX, name\r
+ MOV CX, attribute\r
+ MOV AL, func\r
+ MOV AH, ChMod\r
+ INT 21h\r
+\r
+ Description:\r
+ Given an ASCIZ name, ChMod will set/get the\r
+ attributes of the file to those given in CX.\r
+\r
+ A function code is passed in AL:\r
+\r
+ AL Function\r
+ -- --------\r
+ 0 Return the attributes of the file in CX\r
+ 1 Set the attributes of the file to those in CX\r
+\r
+ Error returns:\r
+ AX = error_path_not_found\r
+ The path specified was invalid.\r
+ = error_access_denied\r
+ The attributes specified in CX contained one\r
+ that could not be changed (directory, volume\r
+ ID).\r
+ = error_invalid_function\r
+ The function passed in AL was not in the range\r
+ 0:1.\r
+\f\r
+\r
+ Name: * Close - close a file handle\r
+\r
+ Assembler usage:\r
+ MOV BX, handle\r
+ MOV AH, Close\r
+ INT 21h\r
+\r
+ Description:\r
+ In BX is passed a file handle (like that returned\r
+ by Open, Creat or Dup); the Close call will close the\r
+ associated file. Internal buffers are flushed.\r
+\r
+ Error return:\r
+ AX = error_invalid_handle\r
+ The handle passed in BX was not currently\r
+ open.\r
+\f\r
+\r
+ Name: * Creat - create a file\r
+\r
+ Assembler usage:\r
+ LDS DX, name\r
+ MOV AH, Creat\r
+ MOV CX, attribute\r
+ INT 21h\r
+ ; AX now has the handle\r
+\r
+ Description:\r
+ Creat creates a new file or truncates an old file\r
+ to zero length in preparation for writing. If the\r
+ file did not exist, then the file is created in the\r
+ appropriate directory and the file is given the\r
+ read/write protection code of access.\r
+\r
+ CX contains the default attributes to be set for\r
+ the file. Currently, the read-only bit must be off.\r
+\r
+ Error returns:\r
+ AX = error_access_denied\r
+ The attributes specified in CX contained one\r
+ that could not be created (directory, volume\r
+ ID), a file already existed with a more\r
+ inclusive set of attributes, or a directory\r
+ existed with the same name.\r
+ = error_path_not_found\r
+ The path specified was invalid.\r
+ = error_too_many_open_files\r
+ The file was created with the specified\r
+ attributes, but there were no free handles\r
+ available for the process or that the internal\r
+ system tables were full.\r
+\f\r
+\r
+ Name: * Dup - duplicate a file handle\r
+\r
+ Assembler usage:\r
+ MOV BX, fh\r
+ MOV AH, Dup\r
+ INT 21h\r
+ ; AX has the returned handle\r
+\r
+ Description:\r
+ Dup takes an already opened file handle and\r
+ returns a new handle that refers to the same file at\r
+ the same position.\r
+\r
+ Error returns:\r
+ AX = error_invalid_handle\r
+ The handle passed in BX was not currently\r
+ open.\r
+ = error_too_many_open_files\r
+ There were no free handles available in the\r
+ current process or the internal system tables\r
+ were full.\r
+\f\r
+\r
+ Name: * Dup2 - force a duplicate of a handle\r
+\r
+ Assembler usage:\r
+ MOV BX, fh\r
+ MOV CX, newfh\r
+ MOV AH, Dup2\r
+ INT 21h\r
+\r
+ Description:\r
+ Dup2 will cause newfh to refer to the same stream\r
+ as fh. If there was an open file on newfh, then it is\r
+ closed first.\r
+\r
+ Error returns:\r
+ AX = error_invalid_handle\r
+ The handle passed in BX was not currently\r
+ open.\r
+\f\r
+\r
+ Name: * Exec - load / execute a program\r
+\r
+ Assembler usage:\r
+ LDS DX, name\r
+ LES BX, blk\r
+ MOV AH, Exec\r
+ MOV AL, func\r
+ INT 21h\r
+\r
+ Description:\r
+ This call allows a program to load another program\r
+ into memory and (default) begin execution of it.\r
+ DS:DX points to the ASCIZ name of the file to be\r
+ loaded. ES:BX points to a parameter block for the\r
+ load.\r
+\r
+ A function code is passed in AL:\r
+\r
+ AL Function\r
+ -- --------\r
+ 0 Load and execute the program. A program header is\r
+ established for the program and the terminate and\r
+ ^C addresses are set to the instruction after the\r
+ EXEC system call.\r
+\r
+ NOTE: When control is returned, via a ^C or\r
+ terminate, from the program being EXECed ALL\r
+ registers are altered including the stack.\r
+ This is because control is returned from the\r
+ EXECed program, not the system. To regain\r
+ your stack, store an SS:SP value in a data\r
+ location reachable from your CS.\r
+\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+| C A V E A T P R O G R A M M E R |\r
+| |\r
+ 1 Load, create the program header but do not begin\r
+ execution. The CS:IP/SS:SP of the program are\r
+ returned in the area provided by the user.\r
+| |\r
+| C A V E A T P R O G R A M M E R |\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+\r
+ 3 Load, do not create the program header, and do not\r
+ begin execution. This is useful in loading\r
+ program overlays.\r
+\r
+ For each value of AL, the block has the following\r
+ format:\r
+\r
+ AL = 0 -> load/execute program\r
+\r
+ +---------------------------+\r
+ | WORD segment address of |\r
+ | environment. |\r
+ +---------------------------+\r
+ | DWORD pointer to command |\r
+ | line at 80h |\r
+ +---------------------------+\r
+ | DWORD pointer to default |\r
+ | FCB to be passed at 5Ch |\r
+ +---------------------------+\r
+ | DWORD pointer to default |\r
+ | FCB to be passed at 6Ch |\r
+ +---------------------------+\r
+\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+| C A V E A T P R O G R A M M E R |\r
+| |\r
+ AL = 1 -> load program\r
+\r
+ +---------------------------+\r
+ | WORD segment address of |\r
+ | environment. |\r
+ +---------------------------+\r
+ | DWORD pointer to command |\r
+ | line at 80h |\r
+ +---------------------------+\r
+ | DWORD pointer to default |\r
+ | FCB to be passed at 5Ch |\r
+ +---------------------------+\r
+ | DWORD pointer to default |\r
+ | FCB to be passed at 6Ch |\r
+ +---------------------------+\r
+ | DWORD returned value of |\r
+ | SS:SP |\r
+ +---------------------------+\r
+ | DWORD returned value of |\r
+ | CS:IP |\r
+ +---------------------------+\r
+| |\r
+| C A V E A T P R O G R A M M E R |\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+\r
+ AL = 3 -> load overlay\r
+\r
+ +---------------------------+\r
+ | WORD segment address where|\r
+ | file will be loaded. |\r
+ +---------------------------+\r
+ | WORD relocation factor to |\r
+ | be applied to the image. |\r
+ +---------------------------+\r
+\r
+ Note that all open files of a process are\r
+ duplicated in the child process after an Exec. This\r
+ is extremely powerful; the parent process has control\r
+ over the meanings of stdin, stdout, stderr, stdaux and\r
+ stdprn. The parent could, for example, write a series\r
+ of records to a file, open the file as standard input,\r
+ open a listing file as standard output and then Exec a\r
+ sort program that takes its input from stdin and\r
+ writes to stdout.\r
+\r
+ Also inherited (or passed from the parent) is an\r
+ 'environment'. This is a block of text strings (less\r
+ than 32K bytes total) that convey various\r
+ configurations parameters. The format of the\r
+ environment is as follows:\r
+\r
+ (paragraph boundary)\r
+ +---------------------------+\r
+ | BYTE asciz string 1 |\r
+ +---------------------------+\r
+ | BYTE asciz string 2 |\r
+ +---------------------------+\r
+ | ... |\r
+ +---------------------------+\r
+ | BYTE asciz string n |\r
+ +---------------------------+\r
+ | BYTE of zero |\r
+ +---------------------------+\r
+\r
+ Typically the environment strings have the form:\r
+\r
+ parameter=value\r
+\r
+ for example, COMMAND.COM always passes its execution\r
+ search path as:\r
+\r
+ PATH=A:/BIN;B:/BASIC/LIB\r
+\r
+ A zero value of the environment address will cause the\r
+ child process to inherit the parent's environment\r
+ unchanged.\r
+\r
+ Note that on a successful return from EXEC, all\r
+ registers, except for CS:IP, are changed.\r
+\r
+ Error return:\r
+ AX = error_invalid_function\r
+ The function passed in AL was not 0, 1 or 3.\r
+ = error_bad_environment\r
+ The environment was larger than 32Kb.\r
+ = error_bad_format\r
+ The file pointed to by DS:DX was an EXE format\r
+ file and contained information that was\r
+ internally inconsistent.\r
+ = error_not_enough_memory\r
+ There was not enough memory for the process to\r
+ be created.\r
+ = error_file_not_found\r
+ The path specified was invalid or not found.\r
+\f\r
+\r
+ Name: * Exit - terminate a process\r
+\r
+ Assembler usage:\r
+ MOV AL, code\r
+ MOV AH, Exit\r
+ INT 21h\r
+\r
+ Description:\r
+ Exit will terminate the current process,\r
+ transferring control to the invoking process. In\r
+ addition, a return code may be sent. All files open\r
+ at the time are closed.\r
+\r
+ Error returns:\r
+ None.\r
+\f\r
+\r
+ Name: * Ioctl - I/O control for devices\r
+\r
+ Assembler usage:\r
+ MOV BX, Handle\r
+\r
+ (or MOV BL, drive for calls AL=4,5\r
+ 0=default,A=1...)\r
+\r
+ MOV DX, Data\r
+\r
+ (or LDS DX, buf and\r
+ MOV CX, count for calls AL=2,3,4,5)\r
+\r
+ MOV AH, Ioctl\r
+ MOV AL, func\r
+ INT 21h\r
+ ; For calls AL=2,3,4,5 AX is the number of bytes\r
+ ; transferred (same as READ and WRITE).\r
+ ; For calls AL=6,7 AL is status returned, AL=0 if\r
+ ; status is not ready, AL=0FFH otherwise.\r
+\r
+ Description:\r
+ Set or Get device information associated with open\r
+ Handle, or send/receive control string to device\r
+ Handle or device.\r
+\r
+ The following values are allowed for func:\r
+\r
+ Request Function\r
+ ------ --------\r
+ 0 Get device information (returned in DX)\r
+ 1 Set device information (as determined by DX)\r
+ 2 Read CX number of bytes into DS:DX from device\r
+ control channel.\r
+ 3 Write CX number of bytes from DS:DX to device\r
+ control channel.\r
+ 4 Same as 2 only drive number in BL\r
+ 0=default,A=1,B=2,...\r
+ 5 Same as 3 only drive number in BL\r
+ 0=default,A=1,B=2,...\r
+ 6 Get input status\r
+ 7 Get output status\r
+\r
+ Ioctl can be used to get information about device\r
+ channels. It is ok to make Ioctl calls on regular\r
+ files but only calls 0,6 and 7 are defined in that\r
+ case (AL=0,6,7), all other calls return an\r
+ error_invalid_function error.\r
+\r
+ CALLS AL=0 and AL=1\r
+\r
+ The bits of DX are defined as follows for calls\r
+ AL=0 and AL=1. Note that the upper byte MUST be zero\r
+ on a set call.\r
+\r
+ |\r
+ 15 14 13 12 11 10 9 8|7 6 5 4 3 2 1 0\r
+ +--+--+--+--+--+--+-+-+-+-+-+-+-+-+-+-+\r
+ | R| C| |I|E|R|S|I|I|I|I|\r
+ | e| T| |S|O|A|P|S|S|S|S|\r
+ | s| R| Reserved |D|F|W|E|C|N|C|C|\r
+ | | L| |E| | |C|L|U|O|I|\r
+ | | | |V| | |L|K|L|T|N|\r
+ +--+--+--+--+--+--+-+-+-+-+-+-+-+-+-+-+\r
+ |\r
+\r
+ ISDEV = 1 if this channel is a device\r
+ = 0 if this channel is a disk file (Bits 8-15 =\r
+ 0 in this case)\r
+\r
+ If ISDEV = 1\r
+\r
+ EOF = 0 if End Of File on input\r
+ RAW = 1 if this device is in Raw mode\r
+ = 0 if this device is cooked\r
+ ISCLK = 1 if this device is the clock device\r
+ ISNUL = 1 if this device is the null device\r
+ ISCOT = 1 if this device is the console output\r
+ ISCIN = 1 if this device is the console input\r
+ SPECL = 1 if this device is special\r
+\r
+ CTRL = 0 if this device can NOT do control strings\r
+ via calls AL=2 and AL=3.\r
+ CTRL = 1 if this device can process control\r
+ strings via calls AL=2 and AL=3.\r
+ NOTE that this bit cannot be set.\r
+\r
+ If ISDEV = 0\r
+ EOF = 0 if channel has been written\r
+ Bits 0-5 are the block device number for the\r
+ channel (0 = A, 1 = B, ...)\r
+\r
+ Bits 15,8-13,4 are reserved and should not be altered.\r
+\r
+ Calls 2..5:\r
+ These four calls allow arbitrary control strings to be\r
+ sent or received from a device. The Call syntax is\r
+ the same as the READ and WRITE calls, except for 4 and\r
+ 5 which take a drive number in BL instead of a handle\r
+ in BX.\r
+\r
+ An error_invalid_function error is returned if the\r
+ CTRL bit (see above) is 0.\r
+\r
+ An error_access_denied is returned by calls AL=4,5 if\r
+ the drive number is invalid.\r
+\r
+ Calls 6,7:\r
+ These two calls allow the user to check if a file\r
+ handle is ready for input or output. Status of\r
+ handles open to a device is the intended use of these\r
+ calls, but status of a handle open to a disk file is\r
+ OK and is defined as follows:\r
+\r
+ Input:\r
+ Always ready (AL=FF) until EOF reached, then\r
+ always not ready (AL=0) unless current\r
+ position changed via LSEEK.\r
+ Output:\r
+ Always ready (even if disk full).\r
+\r
+ IMPORTANT NOTE:\r
+ The status is defined at the time the system is\r
+ CALLED. On future versions, by the time control is\r
+ returned to the user from the system, the status\r
+ returned may NOT correctly reflect the true current\r
+ state of the device or file.\r
+\r
+ Error returns:\r
+ AX = error_invalid_handle\r
+ The handle passed in BX was not currently\r
+ open.\r
+ = error_invalid_function\r
+ The function passed in AL was not in the range\r
+ 0:7.\r
+ = error_invalid_data\r
+ = error_access_denied (calls AL=4..7)\r
+\f\r
+\r
+ Name: * LSeek - move file read/write pointer\r
+\r
+ Assembler usage:\r
+ MOV DX, offsetlow\r
+ MOV CX, offsethigh\r
+ MOV AL, method\r
+ MOV BX, handle\r
+ MOV AH, LSeek\r
+ INT 21h\r
+ ; DX:AX has the new location of the pointer\r
+\r
+ Description:\r
+ LSeek moves the read/write pointer according to\r
+ method:\r
+\r
+ Method Function\r
+ ------ --------\r
+ 0 The pointer is moved to offset bytes from the\r
+ beginning of the file.\r
+ 1 The pointer is moved to the current location\r
+ plus offset.\r
+ 2 The pointer is moved to the end of file plus\r
+ offset.\r
+\r
+ Offset should be regarded as a 32-bit integer with\r
+ CX occupying the most significant 16 bits.\r
+\r
+ Error returns:\r
+ AX = error_invalid_handle\r
+ The handle passed in BX was not currently\r
+ open.\r
+ = error_invalid_function\r
+ The function passed in AL was not in the range\r
+ 0:2.\r
+\f\r
+\r
+ Name: * MkDir - Create a directory entry\r
+\r
+ Assembler usage:\r
+ LDS DX, name\r
+ MOV AH, MkDir\r
+ INT 21h\r
+\r
+ Description:\r
+ Given a pointer to an ASCIZ name, create a new\r
+ directory entry at the end.\r
+\r
+ Error returns:\r
+ AX = error_path_not_found\r
+ The path specified was invalid or not found.\r
+ = error_access_denied\r
+ The directory could not be created (no room in\r
+ parent directory), the directory/file already\r
+ existed or a device name was specified.\r
+\f\r
+\r
+ Name: * Open - access a file\r
+\r
+ Assembler usage:\r
+ LDS DX, name\r
+ MOV AH, Open\r
+ MOV AL, access\r
+ INT 21h\r
+ ; AX has error or file handle\r
+ ; If successful open\r
+\r
+ Description:\r
+ Open associates a 16-bit file handle with a file.\r
+\r
+ The following values are allowed for access:\r
+\r
+ ACCESS Function\r
+ ------ --------\r
+ 0 file is opened for reading\r
+ 1 file is opened for writing\r
+ 2 file is opened for both reading and writing.\r
+\r
+ DS:DX point to an ASCIZ name of the file to be\r
+ opened.\r
+\r
+ The read/write pointer is set at the first byte of\r
+ the file and the record size of the file is 1 byte.\r
+ The returned file handle must be used for subsequent\r
+ I/O to the file.\r
+\r
+ The DOS, on initialization, will have a maximum\r
+ number of files. See the configuration file document\r
+ for information on changing this default.\r
+\r
+ Error returns:\r
+ AX = error_invalid_access\r
+ The access specified in AL was not in the\r
+ range 0:2.\r
+ = error_file_not_found\r
+ The path specified was invalid or not found.\r
+ = error_access_denied\r
+ The user attempted to open a directory or\r
+ volume-id, or open a read-only file for\r
+ writing.\r
+ = error_too_many_open_files\r
+ There were no free handles available in the\r
+ current process or the internal system tables\r
+ were full.\r
+\f\r
+\r
+ Name: * Read - Do file/device I/O\r
+\r
+ Assembler usage:\r
+ LDS DX, buf\r
+ MOV CX, count\r
+ MOV BX, handle\r
+ MOV AH, Read\r
+ INT 21h\r
+ ; AX has number of bytes read\r
+\r
+ Description:\r
+ Read transfers count bytes from a file into a\r
+ buffer location. It is not guaranteed that all count\r
+ bytes will be read; for example, reading from the\r
+ keyboard will read at most one line of text. If the\r
+ returned value is zero, then the program has tried to\r
+ read from the end of file.\r
+\r
+ All I/O is done using normalized pointers; no\r
+ segment wraparound will occur.\r
+\r
+ Error returns:\r
+ AX = error_invalid_handle\r
+ The handle passed in BX was not currently\r
+ open.\r
+ = error_access_denied\r
+ The handle passed in BX was opened in a mode\r
+ that did not allow reading.\r
+\f\r
+\r
+ Name: * RmDir - Remove a directory entry\r
+\r
+ Assembler usage:\r
+ LDS DX, name\r
+ MOV AH, RmDir\r
+ INT 21h\r
+\r
+ Description:\r
+ RmDir is given an asciz name of a directory. That\r
+ directory is removed from its parent\r
+\r
+ Error returns:\r
+ AX = error_path_not_found\r
+ The path specified was invalid or not found.\r
+ = error_access_denied\r
+ The path specified was not empty, not a\r
+ directory, the root directory or contained\r
+ invalid information.\r
+ = error_current_directory\r
+ The path specified was the current directory\r
+ on a drive.\r
+\f\r
+\r
+ Name: * Unlink - delete a directory entry\r
+\r
+ Assembler usage:\r
+ LDS DX, name\r
+ MOV AH, Unlink\r
+ INT 21h\r
+\r
+ Description:\r
+ Unlink removes a directory entry associated with a\r
+ filename. If the file is currently open on another\r
+ handle, then no removal will take place.\r
+\r
+ Error returns:\r
+ AX = error_file_not_found\r
+ The path specified was invalid or not found.\r
+ = error_access_denied\r
+ The path specified was a directory or\r
+ read-only.\r
+\f\r
+\r
+ Name: * Wait - retrieve the return code of a child\r
+\r
+ Assembler usage:\r
+ MOV AH, Wait\r
+ INT 21h\r
+ ; AX has the exit code\r
+\r
+ Description:\r
+ Wait will return the Exit code specified by a\r
+ child process. It will return this Exit code only\r
+ once. The low byte of this code is that sent by the\r
+ Exit routine. The high byte is one of the following:\r
+\r
+ 0 - terminate/abort\r
+ 1 - ^C\r
+ 2 - Hard error\r
+ 3 - Terminate and stay resident\r
+\r
+ Error returns:\r
+ None.\r
+\f\r
+\r
+ Name: * Write - write to a file\r
+\r
+ Assembler usage:\r
+ LDS DX, buf\r
+ MOV CX, count\r
+ MOV BX, handle\r
+ MOV AH, Write\r
+ INT 21h\r
+ ; AX has number of bytes written\r
+\r
+ Description:\r
+ Write transfers count bytes from a buffer into\r
+ a file. It should be regarded as an error if the\r
+ number of bytes written is not the same as the number\r
+ requested.\r
+\r
+ It is important to note that the write system\r
+ call with a count of zero (CX = 0) will truncate\r
+ the file at the current position.\r
+\r
+ All I/O is done using normalized pointers; no\r
+ segment wraparound will occur.\r
+\r
+ Error Returns:\r
+ AX = error_invalid_handle\r
+ The handle passed in BX was not currently\r
+ open.\r
+ = error_access_denied\r
+ The handle was not opened in a mode that\r
+ allowed writing.\r
+\f\r
+\r
+The following XENIX convention is followed for the new 2.0\r
+system calls:\r
+\r
+ o If no error occurred, then the carry flag will be\r
+ reset and register AX will contain the appropriate\r
+ information.\r
+\r
+ o If an error occurred, then the carry flag will be\r
+ set and register AX will contain the error code.\r
+\r
+The following code sample illustrates the recommended method\r
+of detecting these errors:\r
+\r
+ ...\r
+ MOV errno,0\r
+ INT 21h\r
+ JNC continue\r
+ MOV errno,AX\r
+continue:\r
+ ...\r
+\r
+The word variable errno will now have the correct error code\r
+for that system call.\r
+\r
+The current equates for the error codes are:\r
+\r
+no_error_occurred EQU 0\r
+\r
+error_invalid_function EQU 1\r
+error_file_not_found EQU 2\r
+error_path_not_found EQU 3\r
+error_too_many_open_files EQU 4\r
+error_access_denied EQU 5\r
+error_invalid_handle EQU 6\r
+error_arena_trashed EQU 7\r
+error_not_enough_memory EQU 8\r
+error_invalid_block EQU 9\r
+error_bad_environment EQU 10\r
+error_bad_format EQU 11\r
+error_invalid_access EQU 12\r
+error_invalid_data EQU 13\r
+error_invalid_drive EQU 15\r
+error_current_directory EQU 16\r
+error_not_same_device EQU 17\r
+error_no_more_files EQU 18\r
+\r
+\f\r
+System call assignments:\r
+\r
+ABORT EQU 0 ; 0 0\r
+STD_CON_INPUT EQU 1 ; 1 1\r
+STD_CON_OUTPUT EQU 2 ; 2 2\r
+STD_AUX_INPUT EQU 3 ; 3 3\r
+STD_AUX_OUTPUT EQU 4 ; 4 4\r
+STD_PRINTER_OUTPUT EQU 5 ; 5 5\r
+RAW_CON_IO EQU 6 ; 6 6\r
+RAW_CON_INPUT EQU 7 ; 7 7\r
+STD_CON_INPUT_NO_ECHO EQU 8 ; 8 8\r
+STD_CON_STRING_OUTPUT EQU 9 ; 9 9\r
+STD_CON_STRING_INPUT EQU 10 ; 10 A\r
+STD_CON_INPUT_STATUS EQU 11 ; 11 B\r
+STD_CON_INPUT_FLUSH EQU 12 ; 12 C\r
+DISK_RESET EQU 13 ; 13 D\r
+SET_DEFAULT_DRIVE EQU 14 ; 14 E\r
+FCB_OPEN EQU 15 ; 15 F\r
+FCB_CLOSE EQU 16 ; 16 10\r
+DIR_SEARCH_FIRST EQU 17 ; 17 11\r
+DIR_SEARCH_NEXT EQU 18 ; 18 12\r
+FCB_DELETE EQU 19 ; 19 13\r
+FCB_SEQ_READ EQU 20 ; 20 14\r
+FCB_SEQ_WRITE EQU 21 ; 21 15\r
+FCB_CREATE EQU 22 ; 22 16\r
+FCB_RENAME EQU 23 ; 23 17\r
+GET_DEFAULT_DRIVE EQU 25 ; 25 19\r
+SET_DMA EQU 26 ; 26 1A\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+| C A V E A T P R O G R A M M E R |\r
+| |\r
+GET_DEFAULT_DPB EQU 31 ; 31 1F\r
+| |\r
+| C A V E A T P R O G R A M M E R |\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+FCB_RANDOM_READ EQU 33 ; 33 21\r
+FCB_RANDOM_WRITE EQU 34 ; 34 22\r
+GET_FCB_FILE_LENGTH EQU 35 ; 35 23\r
+GET_FCB_POSITION EQU 36 ; 36 24\r
+SET_INTERRUPT_VECTOR EQU 37 ; 37 25\r
+CREATE_PROCESS_DATA_BLOCK EQU 38 ; 38 26\r
+FCB_RANDOM_READ_BLOCK EQU 39 ; 39 27\r
+FCB_RANDOM_WRITE_BLOCK EQU 40 ; 40 28\r
+PARSE_FILE_DESCRIPTOR EQU 41 ; 41 29\r
+GET_DATE EQU 42 ; 42 2A\r
+SET_DATE EQU 43 ; 43 2B\r
+GET_TIME EQU 44 ; 44 2C\r
+SET_TIME EQU 45 ; 45 2D\r
+SET_VERIFY_ON_WRITE EQU 46 ; 46 2E\r
+; Extended functionality group\r
+GET_DMA EQU 47 ; 47 2F\r
+GET_VERSION EQU 48 ; 48 30\r
+KEEP_PROCESS EQU 49 ; 49 31\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+| C A V E A T P R O G R A M M E R |\r
+| |\r
+GET_DPB EQU 50 ; 50 32\r
+| |\r
+| C A V E A T P R O G R A M M E R |\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+SET_CTRL_C_TRAPPING EQU 51 ; 51 33\r
+GET_INDOS_FLAG EQU 52 ; 52 34\r
+GET_INTERRUPT_VECTOR EQU 53 ; 53 35\r
+GET_DRIVE_FREESPACE EQU 54 ; 54 36\r
+CHAR_OPER EQU 55 ; 55 37\r
+INTERNATIONAL EQU 56 ; 56 38\r
+; XENIX CALLS\r
+; Directory Group\r
+MKDIR EQU 57 ; 57 39\r
+RMDIR EQU 58 ; 58 3A\r
+CHDIR EQU 59 ; 59 3B\r
+; File Group\r
+CREAT EQU 60 ; 60 3C\r
+OPEN EQU 61 ; 61 3D\r
+CLOSE EQU 62 ; 62 3E\r
+READ EQU 63 ; 63 3F\r
+WRITE EQU 64 ; 64 40\r
+UNLINK EQU 65 ; 65 41\r
+LSEEK EQU 66 ; 66 42\r
+CHMOD EQU 67 ; 67 43\r
+IOCTL EQU 68 ; 68 44\r
+XDUP EQU 69 ; 69 45\r
+XDUP2 EQU 70 ; 70 46\r
+CURRENT_DIR EQU 71 ; 71 47\r
+; Memory Group\r
+ALLOC EQU 72 ; 72 48\r
+DEALLOC EQU 73 ; 73 49\r
+SETBLOCK EQU 74 ; 74 4A\r
+; Process Group\r
+EXEC EQU 75 ; 75 4B\r
+EXIT EQU 76 ; 76 4C\r
+WAIT EQU 77 ; 77 4D\r
+FIND_FIRST EQU 78 ; 78 4E\r
+; Special Group\r
+FIND_NEXT EQU 79 ; 79 4F\r
+; SPECIAL SYSTEM GROUP\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+| C A V E A T P R O G R A M M E R |\r
+| |\r
+SET_CURRENT_PDB EQU 80 ; 80 50\r
+GET_CURRENT_PDB EQU 81 ; 81 51\r
+GET_IN_VARS EQU 82 ; 82 52\r
+SETDPB EQU 83 ; 83 53\r
+| |\r
+| C A V E A T P R O G R A M M E R |\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+GET_VERIFY_ON_WRITE EQU 84 ; 84 54\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+| C A V E A T P R O G R A M M E R |\r
+| |\r
+DUP_PDB EQU 85 ; 85 55\r
+| |\r
+| C A V E A T P R O G R A M M E R |\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+RENAME EQU 86 ; 86 56\r
+FILE_TIMES EQU 87 ; 87 57\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ MS-DOS 2.0\r
+\r
+ Utility Extensions\r
+\f\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ The following notation is used below:\r
+\r
+ [item] item is optional.\r
+ item* item is repeated 0 or more times.\r
+ item+ item is repeated 1 or more times.\r
+ {item1 | item2}\r
+ item1 is present or item 2 is present but\r
+ not both.\r
+ <object> indicates a syntactic variable.\r
+\f\r
+\r
+COMMAND invokation\r
+\r
+COMMAND [[<drive>:]<path>] [<cttydev>] [-D] [-P] [-C <string>]\r
+\r
+ -P If present COMMAND will be permanent, otherwise\r
+ this is a transient command.\r
+\r
+ -D If present COMMAND will not prompt for DATE and\r
+ TIME when it comes up.\r
+\r
+ d: Specifies device where command will look for\r
+ COMMAND.COM current default drive if absent.\r
+\r
+ <Path> Specifies a directory on device d: root\r
+ directory if absent.\r
+\r
+ <cttydev> Name of the CTTY device. /DEV/CON if absent\r
+ and command is permanent. The /DEV/ may be left\r
+ off if AVAILDEV is TRUE (see sysinit doc).\r
+\r
+ -C <string> If present -C must be the last switch.\r
+ This causes COMMAND to try to execute the string\r
+ as if the user had typed it at the standard input.\r
+ COMMAND executes this single command string and\r
+ then exits. If the -P switch is present it is\r
+ ignored (can't have a single command, permanent\r
+ COMMAND). NOTE: ALL of the text on the command\r
+ line after the -C is just passed on. It is not\r
+ processed for more arguments, this is why -C must\r
+ be last.\r
+\r
+COMMAND extensions\r
+\r
+IF <condition> <command>\r
+\r
+ where <condition> is one of the following:\r
+\r
+ ERRORLEVEL <number>\r
+ true if and only if the previous program EXECed by\r
+ COMMAND had an exit code of <number> or higher.\r
+\r
+ <string1> == <string2>\r
+ true if and only if <string1> and <string2> are\r
+ identical after parameter substitution. Strings\r
+ may not have embedded delimiters.\r
+\r
+ EXIST <filename>\r
+ true if and only if <filename> exists.\r
+\r
+ NOT <condition>\r
+ true if and only if <condition> is false.\r
+\r
+ The IF statement allows conditional execution of commands.\r
+ When the <condition> is true, then the <command> is\r
+ executed otherwise, the <command> is skipped.\r
+\r
+ Examples:\r
+\r
+ IF not exist /tmp/foo ECHO Can't find file /tmp/foo\r
+\r
+ IF $1x == x ECHO Need at least one parameter\r
+\r
+ IF NOT ERRORLEVEL 3 LINK $1,,;\r
+\r
+\r
+FOR %%<c> IN <set> DO <command>\r
+\r
+ <c> can be any character but 0,1,2,3,..,9 (so there is no\r
+ confusion with the %0 - %9 batch parameters).\r
+\r
+ <set> is ( <item>* )\r
+\r
+ The %%<c> variable is sequentially set to each member of\r
+ <set> and then <command> is evaluated. If a member of\r
+ <set> is an expression involving * and/or ?, then the\r
+ variable is set to each matching pattern from disk. In\r
+ this case only one such <item> may be in the set, any\r
+ <item>s after the first are ignored.\r
+\r
+ Example:\r
+\r
+ FOR %%f IN ( *.ASM ) DO MASM %%f;\r
+\r
+ for %%f in (FOO BAR BLECH) do REM %%f to you\r
+\r
+ NOTE: The '%%' is needed so that after Batch parameter\r
+ (%0 - %9) processing is done, there is one '%' left.\r
+ If only '%f' were there, the batch parameter processor\r
+ would see the '%' then look at 'f', decide that '%f'\r
+ was an error (bad parameter reference) and throw out\r
+ the '%f' so that FOR would never see it. If the FOR\r
+ is NOT in a batch file, then only ONE '%' should be\r
+ used.\r
+\f\r
+\r
+SHIFT\r
+\r
+ Currently, command files are limited to handling 10\r
+ parameters: %0 through %9. To allow access to more than\r
+ these, the command SHIFT will perform a 'pop' of the\r
+ command line parameters:\r
+\r
+ if %0 = "foo"\r
+ %1 = "bar"\r
+ %2 = "blech"\r
+ %3...%9 are empty\r
+\r
+ then a SHIFT will result in the following:\r
+\r
+ %0 = "bar"\r
+ %1 = "blech"\r
+ %2...%9 are empty\r
+\r
+ If there are more than 10 parameters given on a command\r
+ line, then the those that appear after the 10th (%9) will\r
+ be shifted one at a time into %9 by successive shifts.\r
+\r
+:<label>\r
+\r
+ This is essentially a no-op. It defines a label in the\r
+ batch file for a subsequent GOTO. It may also be used to\r
+ put comment lines in batch files since all lines that\r
+ start with ':' are ignored.\r
+\r
+GOTO <label>\r
+\r
+ Causes commands to be taken from the batch file beginning\r
+ with the line after the <label> definition. If no label\r
+ has been defined, the current batch file will terminate.\r
+\r
+ Example:\r
+\r
+ :foo\r
+ REM looping...\r
+ GOTO foo\r
+\r
+ will produce a infinite sequence of messages:\r
+ 'REM looping...'\r
+\r
+ NOTE: Labels are case insensitive, :FOO == :foo == :Foo\r
+\f\r
+\r
+ECHO [{ON | OFF | <message>}]\r
+\r
+ Normally, commands in a BATCH file are echoed onto the\r
+ standard output as they are seen by COMMAND. ECHO OFF\r
+ turns off this feature. ECHO ON turns echoing back on.\r
+ If ON or OFF is not specified and there is text following\r
+ the command, that text (a message) is echoed to standard\r
+ output. If there are no arguments at all, the current\r
+ setting of echo (on or off) is echoed to the standard\r
+ output in the form:\r
+\r
+ ECHO is xxx\r
+\r
+ Where xxx is "on" or "off".\r
+\r
+Redirection of standard input/standard output.\r
+\r
+ Programs that read from the keyboard and write to the\r
+ screen are said to be doing I/O to the standard input and\r
+ standard output. Using any of the following will result\r
+ in I/O to these standard devices:\r
+\r
+ Writing to default handles 1 / read from default\r
+ handle 0.\r
+\r
+ Doing byte I/O using system calls 1, 2, 6-12.\r
+\r
+ These standard devices may be redirected to/from files by\r
+ the following in command line arguments:\r
+\r
+ > <filename>\r
+ causes <filename> to be created (or truncated to\r
+ zero length) and then assigns standard output to\r
+ that file. All output from the command will be\r
+ placed in the file.\r
+\r
+ < <filename>\r
+ causes standard input to be assigned to\r
+ <filename>. All input to the command will come\r
+ from this file. If end-of-file is reached, then\r
+ system calls 1, 2, 6-12 will return ^Z , while\r
+ reading from handle 0 will return zero characters.\r
+\r
+ >> <filename>\r
+ causes <filename> to be opened (created if\r
+ necessary) and positions the write pointer at the\r
+ end of the file so that all output will be\r
+ appended to the file.\r
+\r
+ Note that the above will not appear in the command line\r
+ that the program being invoked sees.\r
+\r
+ Examples:\r
+\r
+ DIR *.ASM > FOO.LST\r
+ Sends the output of the dir command to the file\r
+ FOO.LST.\r
+\f\r
+\r
+ FOR %0 IN (*.ASM) DO MASM %0; >>ERRS.LST\r
+ Sends all error output from assembling every .ASM file\r
+ into the file ERRS.LST.\r
+\r
+Piping of standard I/O\r
+\r
+ It is often useful for the output of one program to be\r
+ sent as input to another program. A typical case is a\r
+ program that produces columnar output that must later be\r
+ sorted.\r
+\r
+ The pipe feature allows this to occur naturally is the\r
+ programs do all of their I/O to the standard devices.\r
+\r
+ For example, if we had a program SORT that read all of\r
+ it's standard input, sorted it and then wrote it to the\r
+ standard output, then we could get a sorted directory\r
+ listing as follows:\r
+\r
+ DIR | SORT\r
+\r
+ The | would cause all standard output generated by the\r
+ left-hand command to be sent to the standard input of the\r
+ right-hand command.\r
+\r
+ If we wanted the sorted directory to be sent to a file, we\r
+ type:\r
+\r
+ DIR | SORT >FILE\r
+\r
+ and away it goes.\r
+\r
+ The piping feature is implemented as sequential execution\r
+ of the procedures with redirection to and from temporary\r
+ files. In the example above, the following would be an\r
+ exact equivalent:\r
+\r
+ DIR >/tmp/std1\r
+ SORT </tmp/std1 >FILE\r
+\r
+\f\r
+\r
+ The pipe is not a real pipe but rather a quasi-pipe\r
+ that uses temporary files to hold the input and output as\r
+ it sequentially executes the elements of the pipe. These\r
+ files are created in the current directory, of the current\r
+ drive and have the form %PIPEx%.$$$, where x will be 1 or\r
+ 2. This means that any program that runs in the pipe must\r
+ be sure to restore the current directory and drive if it\r
+ has changed them, otherwise the pipe files will be lost.\r
+\r
+\r
+VER\r
+ Prints DOS version number.\r
+\r
+VOL [<drive>:]\r
+ Prints the volume ID of the disk in drive d:. No d: does\r
+ default drive.\r
+\r
+CHDIR [{<drive>: | <path>}]\r
+ Change directory, or print current. directory.If no\r
+ argument is given, the current directory on the default\r
+ drive is printed. If d: alone is given, the durrent\r
+ directory of drive d is printed. Otherwise the current\r
+ directory is set to path.\r
+\r
+ NOTE:"CD" is accepted as an abbreviation.\r
+\r
+MKDIR <path> - Make a directory.\r
+ "MD" is accepted as an abbreviation.\r
+\r
+RMDIR <path> - Remove a directory.\r
+ "RD" is accepted as an abbreviation.\r
+ The directory must be empty except for\r
+ '.' and '..'.\r
+\r
+ <path> - A standard XENIX style path with the optional\r
+ addition of a drive spec:\r
+\r
+ A:/FOO/BAR Full path\r
+ /FOO/BAR Full path, current drive\r
+ FOO/BAR Current dir relative\r
+ A:FOO/BAR " " "\r
+\r
+VERIFY [{ON | OFF}]\r
+ Select/deselect verify after write mode. This supliments\r
+ the V switch to the COPY command. Once turned ON, it\r
+ stays on until some program changes it (via the set verify\r
+ system call) or the VERIFY OFF command is given. If no\r
+ argument is given, the current setting of VERIFY is\r
+ printed to the standard output in the form:\r
+\r
+ VERIFY is xxx\r
+\r
+ Where xxx is "on" or "off".\r
+\r
+PATH [<path>{;<path>}*]\r
+ Set command search paths. This allows users to set\r
+ directories that should be searched for external commands\r
+ after a search of the current directory is made. The\r
+ default value is /bin. In addition there are two special\r
+ cases: PATH all by itself with no arguments will print\r
+ the current path. Path with the single argument ';' (ie.\r
+ "PATH ;") will set the NUL path (no directories other than\r
+ the current one searched). If no argument is given, the\r
+ current value of PATH is printed to the standard output in\r
+ the form:\r
+\r
+ PATH=text of path\r
+ or\r
+ No path\r
+\r
+ NOTE: On IBM systems, the default value of path is No\r
+ path.\r
+\r
+EXIT\r
+ For COMMANDs run without the P switch, this causes COMMAND\r
+ to return. For a normal COMMAND it causes a return to\r
+ itself.\r
+\r
+BREAK [{ON | OFF}]\r
+ Like in CONFIG.SYS, "BREAK ON" turns on the Control C\r
+ check in the DOS function dispatcher. "BREAK OFF" turns\r
+ it off. If no argument is given the setting of BREAK is\r
+ printed to the standard output in the form:\r
+\r
+ BREAK is xxx\r
+\r
+ Where xxx is "on" or "off".\r
+\r
+PROMPT [<prompt-text>]\r
+ Set the system prompt. MS-DOS prompts are now user\r
+ settable, all of the text on the command line is taken to\r
+ be the new prompt. If no text is present the prompt is\r
+ set to the default prompt. There are meta strings for\r
+ various special prompts. These are of the form '$c' where\r
+ c is one of the following:\r
+\r
+ $ - The '$' character.\r
+ t - The time.\r
+ d - The date.\r
+ p - The current directory of the default drive.\r
+ v - The version number.\r
+ n - The default drive.\r
+ g - The '>' character.\r
+ l - The '<' character.\r
+ b - The '|' character.\r
+ s - The ' ' character.\r
+ e - The ESC character.\r
+ _ - A CR LF sequence.\r
+\r
+ EXAMPLE:\r
+ PROMPT $n:\r
+ Would set the normal MS-DOS prompt.\r
+ PROMPT $n>\r
+ Would det the normal PC-DOS prompt.\r
+ PROMPT Time = $t$_Date = $d\r
+ Would set a two line prompt which printed\r
+ Time = (current time)\r
+ Date = (current date)\r
+\r
+ NOTE: For '$c' sequences, lower case = upper case, and\r
+ any character not on the above list is mapped to\r
+ nothing.\r
+\r
+SET (ENVNAME)=(ENVTEXT)\r
+ Set environment strings. This command inserts strings in\r
+ COMMAND's environment. For instance:\r
+\r
+ SET PROMPT=$n>\r
+ Duplicates the function of the PROMPT command.\r
+ SET PATH=p1;p2\r
+ Duplicates the function of the PATH command.\r
+ SET foo=bar\r
+ Puts the string FOO=bar into the environment (note the\r
+ case mapping of (ENVNAME)).\r
+\r
+ NOTE: Environments are very flexible, almost anything can\r
+ be put into the environment with the SET command; the\r
+ only requirement is that a single '=' be present in\r
+ the string.\r
+\r
+CLS\r
+ Clear screen, causes the ANSI escape sequence ESC[2J to be\r
+ sent to standard output.\r
+\r
+CTTY /DEV/dev - Change console TTY. For instance:\r
+\r
+ CTTY /DEV/AUX\r
+\r
+ Would move all command I/O to the AUX port.\r
+\r
+ CTTY /DEV/CON\r
+\r
+ Would move it back to the normal device. The\r
+ /dev/ prefix may be left off if AVAILDEV is\r
+ TRUE (see configuration-file doc).\r
+\r
+COMMAND internal commands take path arguments.\r
+\r
+ DIR <path>\r
+\r
+ COPY <path> <path>\r
+\r
+ DEL(ERASE) <path>\r
+ If the path is a dir, all files in that dir\r
+ are deleted.\r
+ NOTE: The "Are you sure (Y/N)" prompt for DEL and\r
+ ERASE now uses buffered standard input, so\r
+ users must type a return after their answer.\r
+ This gives them the chance to correct if they\r
+ type 'y' by mistake.\r
+\r
+ TYPE <path> (must specify a file)\r
+\r
+\f\r
+\r
+\r
+FILCOM - compare two files\r
+\r
+ The FILCOM program compares two files and produces a log\r
+ of differences between them. The comparison may be made\r
+ in two fashions; either on a line-by-line basis, or on a\r
+ byte-by-byte basis.\r
+\r
+ The line-by-line compare will isolate blocks of lines that\r
+ are different between the two files and will print the\r
+ blocks from each file. The line-by-line compare is the\r
+ default when neither of the two files being compared has\r
+ the extension .EXE, .COM, or .OBJ.\r
+\r
+ The byte-by-byte compare will display exactly which bytes\r
+ are different between the two files. If either file being\r
+ compared has extension .EXE, .COM, or .OBJ then the files\r
+ will be compared in byte-by-byte mode.\r
+\f\r
+\r
+\r
+RECOVER - recover files from a trashed disk.\r
+\r
+ If a sector on a disk goes bad, you can recover either the\r
+ file that contained that sector (without the sector) or\r
+ the entire disk (if the bad sector was in the directory).\r
+\r
+ To recover a particular file:\r
+\r
+ RECOVER <file-to-recover>\r
+\r
+ This will cause the file to be read sector by sector and\r
+ to be have the bad sector skipped. Note that this implies\r
+ that the allocation unit containing the bad sector will be\r
+ read as much as possible. When such a bad sector is\r
+ found, its containing allocation unit is marked as bad,\r
+ thus preventing future allocations of that bad sector.\r
+\r
+ To recover a particular disk:\r
+\r
+ RECOVER <drive-letter>:\r
+\r
+ This will cause a scan to be made of the drive's FAT for\r
+ chains of allocation units (files). A new root directory\r
+ is then written that has entries of the form FILEnnnn.\r
+ Each FILEnnnn will point to the head of one of the\r
+ allocation unit chains.\r
+\r
+ If there are more chains than directory entries in the\r
+ root, RECOVER prints a message and leaves the un-RECOVERED\r
+ chains in the FAT so that RECOVER can be run again once\r
+ some room has been made in the ROOT.\r
+\f\r
+\r
+\r
+DEBUG ON MS-DOS 2.0\r
+\r
+\r
+ When 2.0 DEBUG is invoked it sets up a program header\r
+atoffset 0 in its program work area. On previous versions it\r
+was OK to overwrite this header with impunity: this is true\r
+of the default header set up if no <filespec> is given to\r
+DEBUG. If DEBUGging a .COM or .EXE file, however, you must be\r
+careful not to tamper with the header of the program below\r
+address 5CH, to do this will probably result in a crash. It\r
+is also important that an attempt is not made to "restart" a\r
+program once the "program terminated normally" message is\r
+given. The program must be reloaded with the N and L commands\r
+in order for it to run properly.\r
+\r
+NEW FEATURES\r
+\r
+The A (Assemble) Command\r
+\r
+FORMAT: A [<address>]\r
+\r
+PURPOSE: To assemble 8086/8087/8088 mnemonics directly into\r
+ memory.\r
+\r
+o If a syntax error is encountered, DEBUG responds with\r
+\r
+ ^ Error\r
+\r
+ and redisplays the current assembly address.\r
+\r
+o All numeric values are hexadecimal and may be entered\r
+ as 1-4 characters.\r
+\r
+o Prefix mnemonics must be entered in front of the opcode\r
+ to which they refer. They may also be entered on a\r
+ separate line.\r
+\r
+o The segment override mnemonics are CS:, DS:, ES:, and\r
+ SS:\r
+\r
+o String manipulation mnemonics must explictly state the\r
+ string size. For example, the MOVSW must be used to\r
+ move word strings and MOVSB must be used to move byte\r
+ strings.\r
+\r
+\r
+o The mnemonic for the far return is RETF.\r
+\r
+o The assembler will automatically assemble short, near\r
+ or far jumps and calls depending on byte displacement\r
+ to the destination address. These may be overridden\r
+ with the NEAR or FAR prefix. For example:\r
+\r
+ 0100:0500 JMP 502 ; a 2 byte short jump\r
+ 0100:0502 JMP NEAR 505 ; a 3 byte near jump\r
+ 0100:0505 JMP FAR 50A ; a 5 byte far jump\r
+\r
+ The NEAR prefix may be abbreviated to NE but the FAR\r
+ prefix cannot be abbreviated.\r
+\r
+o DEBUG cannot tell whether some operands refer to a word\r
+ memory location or a byte memroy location. In this case\r
+ the data type must be explicity stated with the prefix\r
+ "WORD PTR" or "BYTE PTR". DEBUG will also except the\r
+ abbreviations "WO" and "BY". For example:\r
+\r
+ NEG BYTE PTR [128]\r
+ DEC WO [SI]\r
+\r
+o DEBUG also cannot tell whether an operand refers to a\r
+ memory location or to an immediate operand. DEBUG uses\r
+ the common convention that operands enclosed in square\r
+ brackets refer to memory. For example:\r
+\r
+ MOV AX,21 ;Load AX with 21H\r
+ MOV AX,[21] ;Load AX with the contents\r
+ ;of memory location 21H\r
+\r
+o Two popular pseudo-instructions have also been included.\r
+ The DB opcode will assemble byte values directly into\r
+ memory. The DW opcode will assemble word values directly\r
+ into memory. For example:\r
+\r
+ DB 1,2,3,4,"THIS IS AN EXAMPLE"\r
+ DB 'THIS IS A QUOTE: "'\r
+ DB "THIS IS A QUOTE: '"\r
+\r
+ DW 1000,2000,3000,"BACH"\r
+\r
+\r
+o All forms of the register indirect commands are supported.\r
+ For example:\r
+\r
+ ADD BX,34[BP+2].[SI-1]\r
+ POP [BP+DI]\r
+ PUSH [SI]\r
+\r
+o All opcode synonyms are supported, For example:\r
+\r
+ LOOPZ 100\r
+ LOOPE 100\r
+\r
+ JA 200\r
+ JNBE 200\r
+\r
+o For 8087 opcodes the WAIT or FWAIT prefix must be\r
+ explictly specified. For example:\r
+\r
+ FWAIT FADD ST,ST(3) ; This lines will assemble\r
+ ; a FWAIT prefix\r
+\r
+ FLD TBYTE PTR [BX] ; This line will not\r
+\f\r
+\r
+\r
+FORMAT enhancements\r
+\r
+ FORMAT will now install volume id's during the format\r
+ process. DIR and CHKDSK will display these volume id's.\r
+\r
+ User programs can read the volume id on a particular drive\r
+ by doing a 'search next' with the volume id attribute. It\r
+ is impossible, using normal DOS calls, to delete a volume\r
+ id or to create another one. The only way to create a\r
+ volume id is to reformat the disk.\r
+\r
+ NOTE: On IBM systems the V switch must be given to FORMAT\r
+ to have it do Volume IDs.\r
+\r
+\f\r
+\r
+\r
+CHKDSK FOR MS-DOS 2.0\r
+\r
+\r
+ MS-DOS 2.0 has a tree structured directory scheme which\r
+did not exist on previous versions of MS-DOS. As a result\r
+CHKDSK is a much more complex program than in previous\r
+versions since it must perform a tree traversal to find all of\r
+the files on a given disk. It employes a depth first\r
+traversal in order to accomplish this.\r
+\r
+ Previous versions of CHKDSK automatically "fixed"\r
+disks (regardless of whether it was appropriate). CHKDSK 2.00\r
+run normally will not alter the disk in any way, it simply\r
+reports on any inconsistencies found. To actually "fix" a\r
+disk CHKDSK must be run with the F switch (Fix). This allows\r
+you to perhaps take some alternate (to CHKDSK repairs) action\r
+before letting CHKDSK loose on your disk.\r
+\r
+ CHKDSK 2.00 will report on non-contiguous allocation units\r
+(extents) for specified files. This is handy for gaging how\r
+"fragmented" a disk volume has become. This is done by simply\r
+giving a filespec:\r
+\r
+ CHKDSK B:*.*\r
+\r
+This would report extents for all files in the current\r
+directory for drive B after doing a normal consistency check\r
+on drive B. Files which have many extents can be copied and\r
+renamed to restore them to a contiguous state, thus improving\r
+I/O performance to the files.\r
+\r
+ Previous versions of CHKDSK would simply free\r
+allocation units which were marked as used, but were not\r
+actually part of any file. CHKDSK 2.00 will recover these\r
+"orphan" allocation units if specified. If orphan allocation\r
+units are found, CHKDSK prompts for free or recover. Free\r
+just frees the orphans as previous versions did, recover will\r
+employ allocation chain analysis to create "orphan files" in\r
+the root directory of the disk. These files will have the\r
+form "%ORPHAN%.l$$" where l will take on some ASCII value\r
+greater than '@'. These files may then be inspected to see if\r
+valuable data was contained in them. If there is not enough\r
+room to make all of the "orphan" files, CHKDSK leaves the\r
+unrecovered chains in the FAT so that CHKDSK can be run again\r
+(once some entries in the ROOT have been deleted). NOTE:\r
+Making ORPHAN files is a SLOW process.\r
+\r
+ Verbose mode. CHKDSK 2.00 may be run with the V switch\r
+which causes a trace of the files and directories being\r
+processed to be printed as CHKDSK runs.\r
+\r
+\f\r
+FILTERS FOR MS-DOS 2.0\r
+\r
+ A filter is a utility that reads from standard input,\r
+modifies the information in some way, then writes the result\r
+to standard output. In this way the data is said to have been\r
+"filtered" by the program. Since different filters can be\r
+piped together in many different ways a few filters can take\r
+the place of a large number of specific purpose programs. The\r
+following describes the filters that are provided with MS-DOS\r
+2.0:\r
+\r
+CIPHER <key word>\r
+\r
+ Cipher reads a program from standard input, encrypts it\r
+using the key word provided by the user, then writes the\r
+result to standard output. To decrypt the file simply run\r
+CIPHER again using the same keyword. For example:\r
+\r
+A>CIPHER MYSTERY <NSA.CIA >SECRET.FIL\r
+\r
+ This command line will read file NSA.CIA, encrypt it using\r
+the key word "MYSTERY", then write the result to file\r
+SECRET.FIL To view the original file the following command\r
+line could be used:\r
+\r
+A>CIPHER MYSTERY <SECRET.FIL\r
+\r
+ This will read file SECRET.FIL, decrypt the file using the\r
+key word "MYSTERY", then write the result to standard output,\r
+which in this case is the console.\r
+\r
+FGREP\r
+\r
+ This filter takes as arguments a string and optionally a\r
+series of file names. It will send to standard output all\r
+lines from the files specified in the command line that\r
+contain the string.\r
+\r
+ If no files are specified FGREP will take the input from\r
+standard in. The format for the command line invocation of\r
+FGREP is:\r
+\r
+FGREP [<option>] <string> <filename>*\r
+\r
+ The options available are:\r
+\r
+ /v Will cause FGREP to output all lines NOT\r
+ containing the specified string.\r
+\r
+ /c Will cause FGREP to only print the count of\r
+ lines matched in each of the files.\r
+\r
+ /n Each line matched is preceded by its relative\r
+ line number in the file.\r
+\r
+ The string argument should be enclosed in double quotes.\r
+Two double quotes in succession are taken as a single double\r
+quote. So,\r
+\r
+A>FGREP "Fool""s Paradise" book1.txt book2.txt bible\r
+\r
+will output all lines from the book1.txt, book2.txt and bible\r
+(in that order that contain the string: Fool"s Paradise .\r
+And,\r
+\r
+A>dir b: | fgrep /v "DAT"\r
+\r
+will output all names of the files in disk b: which do not\r
+contain the string DAT .\r
+\r
+MORE\r
+\r
+ The filter MORE reads from standard input, sends one\r
+screen full of information to standard output and then pauses\r
+with message:\r
+\r
+-- More --\r
+\r
+ Pressing the RETURN key will cause another screen full of\r
+information to be written to standard output. This process\r
+continues until all the input data is read.\r
+\r
+SORT [/R] [/+n]\r
+\r
+ Sort reads from standard input, sorts the data, the writes\r
+the information to standard output. The sort is done using\r
+the ASCII collating sequence. There are switches which allow\r
+the user to select various options:\r
+\r
+ R - Reverse the sort, that is make "Z" come before "A"\r
+\r
+ +n - Sort starting with column "n" where n is some integer.\r
+ The default is start the comparisons with column 1,\r
+ this switch allows the user to start in any column.\r
+\r
+example:\r
+\r
+A>SORT /R <UNSORT.TXT >SORT.TXT\r
+\r
+This command line will read the file UNSORT.TXT, do a reverse\r
+sort, then write the output to file SORT.TXT\r
+\r
+A>DIR | SORT /+14\r
+\r
+ This command line will cause the output of the directory\r
+command to be piped to the sort filter, the sort filter will\r
+sort starting with column 14 (This is the column the file size\r
+starts), then send the output to the console. Thus a\r
+directory sorted by file size will be the result. To get real\r
+fancy:\r
+\r
+A>DIR | SORT /+14 | MORE\r
+\r
+will do the same thing except that MORE will give you a chance\r
+to read the directory before it scrolls off the screen.\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+;\r
+; xenix memory calls for MSDOS\r
+;\r
+; CAUTION: The following routines rely on the fact that arena_signature and\r
+; arena_owner_system are all equal to zero and are contained in DI.\r
+;\r
+INCLUDE DOSSEG.ASM\r
+\r
+CODE SEGMENT BYTE PUBLIC 'CODE'\r
+ ASSUME SS:DOSGROUP,CS:DOSGROUP\r
+\r
+.xlist\r
+.xcref\r
+INCLUDE DOSSYM.ASM\r
+INCLUDE DEVSYM.ASM\r
+.cref\r
+.list\r
+\r
+TITLE ALLOC.ASM - memory arena manager\r
+NAME Alloc\r
+\r
+SUBTTL memory allocation utility routines\r
+PAGE\r
+;\r
+; arena data\r
+;\r
+ i_need arena_head,WORD ; seg address of start of arena\r
+ i_need CurrentPDB,WORD ; current process data block addr\r
+ i_need FirstArena,WORD ; first free block found\r
+ i_need BestArena,WORD ; best free block found\r
+ i_need LastArena,WORD ; last free block found\r
+ i_need AllocMethod,BYTE ; how to alloc first(best)last\r
+\r
+;\r
+; arena_free_process\r
+; input: BX - PID of process\r
+; output: free all blocks allocated to that PID\r
+;\r
+ procedure arena_free_process,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ MOV DI,arena_signature\r
+ MOV AX,[arena_head]\r
+ CALL Check_Signature ; ES <- AX, check for valid block\r
+\r
+arena_free_process_loop:\r
+ retc\r
+ PUSH ES\r
+ POP DS\r
+ CMP DS:[arena_owner],BX ; is block owned by pid?\r
+ JNZ arena_free_next ; no, skip to next\r
+ MOV DS:[arena_owner],DI ; yes... free him\r
+\r
+arena_free_next:\r
+ CMP BYTE PTR DS:[DI],arena_signature_end\r
+ ; end of road, Jack?\r
+ retz ; never come back no more\r
+ CALL arena_next ; next item in ES/AX carry set if trash\r
+ JMP arena_free_process_loop\r
+\r
+arena_free_process ENDP\r
+\r
+;\r
+; arena_next\r
+; input: DS - pointer to block head\r
+; output: AX,ES - pointers to next head\r
+; carry set if trashed arena\r
+;\r
+ procedure arena_next,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ MOV AX,DS ; AX <- current block\r
+ ADD AX,DS:[arena_size] ; AX <- AX + current block length\r
+ INC AX ; remember that header!\r
+;\r
+; fall into check_signature and return\r
+;\r
+; CALL check_signature ; ES <- AX, carry set if error\r
+; RET\r
+arena_next ENDP\r
+\r
+;\r
+; check_signature\r
+; input: AX - address of block header\r
+; output: ES=AX, carry set if signature is bad\r
+;\r
+ procedure check_signature,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ MOV ES,AX ; ES <- AX\r
+ CMP BYTE PTR ES:[DI],arena_signature_normal\r
+ ; IF next signature = not_end THEN\r
+ JZ check_signature_ok ; GOTO ok\r
+ CMP BYTE PTR ES:[DI],arena_signature_end\r
+ ; IF next signature = end then\r
+ JZ check_signature_ok ; GOTO ok\r
+ STC ; set error\r
+ return\r
+\r
+check_signature_ok:\r
+ CLC\r
+ return\r
+Check_signature ENDP\r
+\r
+;\r
+; Coalesce - combine free blocks ahead with current block\r
+; input: DS - pointer to head of free block\r
+; output: updated head of block, AX is next block\r
+; carry set -> trashed arena\r
+;\r
+ procedure Coalesce,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ CMP BYTE PTR DS:[DI],arena_signature_end\r
+ ; IF current signature = END THEN\r
+ retz ; GOTO ok\r
+ CALL arena_next ; ES, AX <- next block, Carry set if error\r
+ retc ; IF no error THEN GOTO check\r
+\r
+coalesce_check:\r
+ CMP ES:[arena_owner],DI\r
+ retnz ; IF next block isnt free THEN return\r
+ MOV CX,ES:[arena_size] ; CX <- next block size\r
+ INC CX ; CX <- CX + 1 (for header size)\r
+ ADD DS:[arena_size],CX ; current size <- current size + CX\r
+ MOV CL,ES:[DI] ; move up signature\r
+ MOV DS:[DI],CL\r
+ JMP coalesce ; try again\r
+Coalesce ENDP\r
+\r
+SUBTTL $Alloc - allocate space in memory\r
+PAGE\r
+;\r
+; Assembler usage:\r
+; MOV BX,size\r
+; MOV AH,Alloc\r
+; INT 21h\r
+; AX:0 is pointer to allocated memory\r
+; BX is max size if not enough memory\r
+;\r
+; Description:\r
+; Alloc returns a pointer to a free block of\r
+; memory that has the requested size in paragraphs.\r
+;\r
+; Error return:\r
+; AX = error_not_enough_memory\r
+; = error_arena_trashed\r
+;\r
+ procedure $ALLOC,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+ XOR AX,AX\r
+ MOV DI,AX\r
+\r
+ MOV [FirstArena],AX ; init the options\r
+ MOV [BestArena],AX\r
+ MOV [LastArena],AX\r
+\r
+ PUSH AX ; alloc_max <- 0\r
+ MOV AX,[arena_head] ; AX <- beginning of arena\r
+ CALL Check_signature ; ES <- AX, carry set if error\r
+ JC alloc_err ; IF error THEN GOTO err\r
+\r
+alloc_scan:\r
+ PUSH ES\r
+ POP DS ; DS <- ES\r
+ CMP DS:[arena_owner],DI\r
+ JZ alloc_free ; IF current block is free THEN examine\r
+\r
+alloc_next:\r
+ CMP BYTE PTR DS:[DI],arena_signature_end\r
+ ; IF current block is last THEN\r
+ JZ alloc_end ; GOTO end\r
+ CALL arena_next ; AX, ES <- next block, Carry set if error\r
+ JNC alloc_scan ; IF no error THEN GOTO scan\r
+\r
+alloc_err:\r
+ POP AX\r
+\r
+alloc_trashed:\r
+ error error_arena_trashed\r
+\r
+alloc_end:\r
+ CMP [FirstArena],0\r
+ JNZ alloc_do_split\r
+\r
+alloc_fail:\r
+ invoke get_user_stack\r
+ POP BX\r
+ MOV [SI].user_BX,BX\r
+ error error_not_enough_memory\r
+\r
+alloc_free:\r
+ CALL coalesce ; add following free block to current\r
+ JC alloc_err ; IF error THEN GOTO err\r
+ MOV CX,DS:[arena_size]\r
+\r
+ POP DX ; check for max found size\r
+ CMP CX,DX\r
+ JNA alloc_test\r
+ MOV DX,CX\r
+\r
+alloc_test:\r
+ PUSH DX\r
+ CMP BX,CX ; IF BX > size of current block THEN\r
+ JA alloc_next ; GOTO next\r
+\r
+ CMP [FirstArena],0\r
+ JNZ alloc_best\r
+ MOV [FirstArena],DS ; save first one found\r
+alloc_best:\r
+ CMP [BestArena],0\r
+ JZ alloc_make_best ; initial best\r
+ PUSH ES\r
+ MOV ES,[BestArena]\r
+ CMP ES:[arena_size],CX ; is size of best larger than found?\r
+ POP ES\r
+ JBE alloc_last\r
+alloc_make_best:\r
+ MOV [BestArena],DS ; assign best\r
+alloc_last:\r
+ MOV [LastArena],DS ; assign last\r
+ JMP alloc_next\r
+\r
+;\r
+; split the block high\r
+;\r
+alloc_do_split_high:\r
+ MOV DS,[LastArena]\r
+ MOV CX,DS:[arena_size]\r
+ SUB CX,BX\r
+ MOV DX,DS\r
+ JE alloc_set_owner ; sizes are equal, no split\r
+ ADD DX,CX ; point to next block\r
+ MOV ES,DX ; no decrement!\r
+ DEC CX\r
+ XCHG BX,CX ; bx has size of lower block\r
+ JMP alloc_set_sizes ; cx has upper (requested) size\r
+\r
+;\r
+; we have scanned memory and have found all appropriate blocks\r
+; check for the type of allocation desired; first and best are identical\r
+; last must be split high\r
+;\r
+alloc_do_split:\r
+ CMP BYTE PTR [AllocMethod], 1\r
+ JA alloc_do_split_high\r
+ MOV DS,[FirstArena]\r
+ JB alloc_get_size\r
+ MOV DS,[BestArena]\r
+alloc_get_size:\r
+ MOV CX,DS:[arena_size]\r
+ SUB CX,BX ; get room left over\r
+ MOV AX,DS\r
+ MOV DX,AX ; save for owner setting\r
+ JE alloc_set_owner ; IF BX = size THEN (don't split)\r
+ ADD AX,BX\r
+ INC AX ; remember the header\r
+ MOV ES,AX ; ES <- DS + BX (new header location)\r
+ DEC CX ; CX <- size of split block\r
+alloc_set_sizes:\r
+ MOV DS:[arena_size],BX ; current size <- BX\r
+ MOV ES:[arena_size],CX ; split size <- CX\r
+ MOV BL,arena_signature_normal\r
+ XCHG BL,DS:[DI] ; current signature <- 4D\r
+ MOV ES:[DI],BL ; new block sig <- old block sig\r
+ MOV ES:[arena_owner],DI\r
+\r
+alloc_set_owner:\r
+ MOV DS,DX\r
+ MOV AX,[CurrentPDB]\r
+ MOV DS:[arena_owner],AX\r
+ MOV AX,DS\r
+ INC AX\r
+ POP BX\r
+ transfer SYS_RET_OK\r
+\r
+$alloc ENDP\r
+\r
+SUBTTL $SETBLOCK - change size of an allocated block (if possible)\r
+PAGE\r
+;\r
+; Assembler usage:\r
+; MOV ES,block\r
+; MOV BX,newsize\r
+; MOV AH,setblock\r
+; INT 21h\r
+; if setblock fails for growing, BX will have the maximum\r
+; size possible\r
+; Error return:\r
+; AX = error_invalid_block\r
+; = error_arena_trashed\r
+; = error_not_enough_memory\r
+; = error_invalid_function\r
+;\r
+ procedure $SETBLOCK,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ MOV DI,arena_signature\r
+ MOV AX,ES\r
+ DEC AX\r
+ CALL check_signature\r
+ JNC setblock_grab\r
+\r
+setblock_bad:\r
+ JMP alloc_trashed\r
+\r
+setblock_grab:\r
+ MOV DS,AX\r
+ CALL coalesce\r
+ JC setblock_bad\r
+ MOV CX,DS:[arena_size]\r
+ PUSH CX\r
+ CMP BX,CX\r
+ JBE alloc_get_size\r
+ JMP alloc_fail\r
+$setblock ENDP\r
+\r
+SUBTTL $DEALLOC - free previously allocated piece of memory\r
+PAGE\r
+;\r
+; Assembler usage:\r
+; MOV ES,block\r
+; MOV AH,dealloc\r
+; INT 21h\r
+;\r
+; Error return:\r
+; AX = error_invalid_block\r
+; = error_arena_trashed\r
+;\r
+ procedure $DEALLOC,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ MOV DI,arena_signature\r
+ MOV AX,ES\r
+ DEC AX\r
+ CALL check_signature\r
+ JC dealloc_err\r
+ MOV ES:[arena_owner],DI\r
+ transfer SYS_RET_OK\r
+\r
+dealloc_err:\r
+ error error_invalid_block\r
+$DEALLOC ENDP\r
+\r
+SUBTTL $AllocOper - get/set allocation mechanism\r
+PAGE\r
+;\r
+; Assembler usage:\r
+; MOV AH,AllocOper\r
+; MOV BX,method\r
+; MOV AL,func\r
+; INT 21h\r
+;\r
+; Error return:\r
+; AX = error_invalid_function\r
+;\r
+ procedure $AllocOper,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ CMP AL,1\r
+ JB AllocOperGet\r
+ JZ AllocOperSet\r
+ error error_invalid_function\r
+AllocOperGet:\r
+ MOV AL,BYTE PTR [AllocMethod]\r
+ XOR AH,AH\r
+ transfer SYS_RET_OK\r
+AllocOperSet:\r
+ MOV [AllocMethod],BL\r
+ transfer SYS_RET_OK\r
+$AllocOper ENDP\r
+\r
+do_ext\r
+\r
+CODE ENDS\r
+ END\r
+\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+;
+; 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
--- /dev/null
+TITLE CHKDSK - MS-DOS Disk consistancy checker\r
+\r
+; CHKDSK Version 2.30\r
+; Verifies and repairs MS-DOS disk directory.\r
+\r
+\r
+; To build CHKDSK you need three modules:\r
+; CHKDSK CHKPROC CHKMES\r
+; They should be linked the that order as well.\r
+\r
+\r
+; REVISION HISTORY\r
+\r
+;REV 1.1\r
+; 05/21/82 Added rev number\r
+\r
+;REV 1.5\r
+; Mod by NANCYP to report on extents\r
+; Mod by AARONR to report volume ID\r
+\r
+;REV 2.0\r
+; Total rewrite for directories\r
+\r
+;REV 2.1\r
+; Added ^C and INT 24H handlers\r
+\r
+;REV 2.2\r
+; INTERNATIONAL support\r
+\r
+;REV 2.3\r
+; Split into two modules to allow assembly on a PC\r
+; CHKDSK and CHKPROC\r
+\r
+FALSE EQU 0\r
+TRUE EQU NOT FALSE\r
+\r
+DRVCHAR EQU ":"\r
+\r
+;The following defines the ranges of DOS version numbers for which this CHKDSK\r
+; is good\r
+\r
+DOSVER_LOW EQU 0136H ;1.54 in hex\r
+DOSVER_HIGH EQU 020BH ;2.11 in hex\r
+\r
+\r
+ INCLUDE DOSSYM.ASM\r
+\r
+FCB EQU 5CH\r
+\r
+;Drive parameter block from DOS header\r
+\r
+SUBTTL Segments used in load order\r
+\r
+CODE SEGMENT PUBLIC\r
+CODE ENDS\r
+\r
+CONST SEGMENT PUBLIC BYTE\r
+CONST ENDS\r
+\r
+DATA SEGMENT PUBLIC WORD\r
+DATA ENDS\r
+\r
+DG GROUP CODE,CONST,DATA\r
+\r
+SUBTTL Initialized Data\r
+PAGE\r
+CONST SEGMENT PUBLIC BYTE\r
+\r
+ PUBLIC HECODE,SWITCHAR,NOISY,DOFIX,CONBUF,ORPHCNT,ORPHSIZ,DOFIX\r
+ PUBLIC HIDCNT,HIDSIZ,DIRCNT,DIRSIZ,FILCNT,FILSIZ,BADSIZ,LCLUS\r
+ PUBLIC DOTENT,HAVFIX,SECONDPASS,NUL,ALLFILE,PARSTR,ERRSUB,LCLUS\r
+ PUBLIC DIRTYFAT,BADSIZ,DDOTENT,CROSSCNT,ORPHFCB,ORPHEXT,ALLDRV\r
+ PUBLIC FRAGMENT,USERDIR,DIRBUF,USERDIR,FIXMFLG,DOTMES,DIRCHAR\r
+\r
+ EXTRN IDMES1:BYTE,IDPOST:BYTE,VNAME:BYTE,MONTAB:BYTE\r
+ EXTRN TCHAR:BYTE,BADREAD_PRE:BYTE,BADREAD_POST:BYTE\r
+ EXTRN CRLF:BYTE,BADVER:BYTE,BADSUBDIR:BYTE,CENTRY:BYTE\r
+ EXTRN BADDRV:BYTE,BADCD:BYTE,BADRDMES:BYTE,OPNERR:BYTE\r
+ EXTRN CONTAINS:BYTE,EXTENTS:BYTE,NOEXTENTS:BYTE\r
+ EXTRN BADDRVM:BYTE,BADDRVM2:BYTE,BADIDBYT:BYTE\r
+\r
+\r
+DIRBUF LABEL BYTE ;Entry buffer for searches\r
+VOLID DB -1,0,0,0,0,0,8 ;Volume ID FCB\r
+VOLNAM DB 0,"???????????"\r
+ DB 25 DUP(0)\r
+\r
+ALLFILE DB -1,0,0,0,0,0,1EH ;Extended FCB\r
+ALLDRV DB 0,"???????????"\r
+ DB 25 DUP (?)\r
+\r
+ORPHFCB DB 0,"FILE0000"\r
+ORPHEXT DB "CHK"\r
+ DB 25 DUP (?)\r
+\r
+\r
+;Non-message data\r
+\r
+SWITCHAR DB "-"\r
+ROOTSTR LABEL BYTE\r
+DIRCHAR DB "/"\r
+NUL DB 0\r
+PARSTR DB "..",0\r
+DOTMES DB ".",0\r
+DOTENT DB ". "\r
+DDOTENT DB ".. "\r
+HECODE DB ?\r
+FIXMFLG DB 0 ;Flag for printing fixmes\r
+ERRSUB DW 0 ;Flag for bad subdir error\r
+FRAGMENT DB 0 ;Flag for extent processing\r
+DIRTYFAT DB 0 ;Dirty flag for FAT\r
+DIRCNT DW 0 ;# directories\r
+DIRSIZ DW 0 ;# alloc units in directories\r
+FILCNT DW 0 ;# reg files\r
+FILSIZ DW 0 ;# alloc units in reg files\r
+HIDCNT DW 0 ;# hidden files\r
+HIDSIZ DW 0 ;# alloc units in hidden files\r
+BADSIZ DW 0 ;# alloc units in bad sectors\r
+ORPHCNT DW 0 ;# orphan files made\r
+ORPHSIZ DW 0 ;# alloc units in orphan files\r
+LCLUS DW 0 ;# alloc units in lost clusters\r
+DISPFLG DB 0 ;used by number routines\r
+CROSSCNT DW 0 ;# crosslinked files (first pass)\r
+SECONDPASS DB 0 ;Pass flag\r
+HAVFIX DB 0 ;non zero if any fixes\r
+DOFIX DB 0 ;flag for F switch\r
+NOISY DB 0 ;flag for V switch\r
+USERDIR DB "/",0 ;Users current dir for drive\r
+ DB (DIRSTRLEN-1) DUP (?)\r
+CONBUF DB 15,0 ;Input buffer\r
+ DB 15 DUP (?)\r
+\r
+CONST ENDS\r
+\r
+SUBTTL Un-initialized Data\r
+PAGE\r
+DATA SEGMENT PUBLIC WORD\r
+\r
+ PUBLIC ZEROTRUNC,NAMBUF,MCLUS,THISDPB,STACKLIM,ERRCNT\r
+ PUBLIC SRFCBPT,ISCROSS,CSIZE,DSIZE,SSIZE,FAT,FATMAP\r
+ PUBLIC HARDCH,CONTCH,USERDEV,SECBUF,DOTSNOGOOD\r
+\r
+HARDCH DD ? ;Pointer to real INT 24 handler\r
+CONTCH DD ? ;Pointer to real INT 23 handler\r
+THISDPB DD ? ;Pointer to drive DPB\r
+USERDEV DB ? ;Users current device\r
+CSIZE DB ? ;Sectors per cluster\r
+SSIZE DW ? ;bytes per sector\r
+DSIZE DW ? ;# alloc units on disk\r
+MCLUS DW ? ;DSIZE + 1\r
+NAMBUF DB 14 DUP (?) ;Buffer\r
+DOTSNOGOOD DB ? ;. or .. error flag\r
+ZEROTRUNC DB ? ;Trimming flag\r
+ISCROSS DB ? ;Crosslink flag\r
+OLDCLUS DW ?\r
+SRFCBPT DW ?\r
+FATMAP DW OFFSET DG:FAT ;Offset of FATMAP table\r
+SECBUF DW ? ;Offset of sector buffer\r
+ERRCNT DB ? ;Used by FATread and write\r
+STACKLIM DW ? ;Stack growth limit\r
+\r
+INTERNATVARS internat_block <>\r
+ DB (internat_block_max - ($ - INTERNATVARS)) DUP (?)\r
+\r
+FAT LABEL WORD\r
+DATA ENDS\r
+\r
+\r
+SUBTTL Start of CHKDSK\r
+\r
+CODE SEGMENT PUBLIC\r
+ASSUME CS:DG,DS:DG,ES:DG,SS:DG\r
+\r
+ PUBLIC SUBERRP,DOTCOMBMES,FIGREC,FCB_TO_ASCZ,PRTCHR,EPRINT\r
+ PUBLIC PRINT,DOCRLF,DISP16BITS,DISP32BITS,DISPCLUS,CHECKFILES\r
+\r
+ EXTRN RDSKERR:NEAR,SETSWITCH:NEAR,PROMPTYN:NEAR,REPORT:NEAR\r
+ EXTRN PRINTCURRDIRERR:NEAR,PRINTTHISEL2:NEAR,CHECKERR:NEAR\r
+ EXTRN INT_23:NEAR,INT_24:NEAR,FINDCHAIN:NEAR,DONE:NEAR,AMDONE:NEAR\r
+ EXTRN FATAL:NEAR,DIRPROC:NEAR,CHKMAP:NEAR,CHKCROSS:NEAR,UNPACK:NEAR\r
+\r
+ ORG 100H\r
+\r
+CHKDSK:\r
+ JMP SHORT CHSTRT\r
+\r
+HEADER DB "Ver 2.30"\r
+\r
+CHSTRT:\r
+\r
+;Code to print header.\r
+; PUSH AX\r
+; MOV DX,OFFSET DG:HEADER\r
+; CALL PRINT\r
+; POP AX\r
+\r
+ PUSH AX ;Save DRIVE validity info\r
+ MOV AH,GET_VERSION\r
+ INT 21H\r
+ XCHG AH,AL ;Turn it around to AH.AL\r
+ CMP AX,DOSVER_LOW\r
+ JB GOTBADDOS\r
+ CMP AX,DOSVER_HIGH\r
+ JBE OKDOS\r
+GOTBADDOS:\r
+ MOV DX,OFFSET DG:BADVER\r
+ JMP CERROR\r
+\r
+OKDOS:\r
+ POP AX ;Get back drive info\r
+ MOV BX,0FFF0H\r
+ MOV DX,SP\r
+ CMP DX,BX\r
+ JAE STACKOK ;Lots of stack\r
+ MOV DX,DS:[2] ;High break\r
+ MOV CX,CS\r
+ SUB DX,CX\r
+ CMP DX,0FFFH\r
+ JAE SETSTACK ;Lots to grab\r
+ MOV CX,4 ;Suck up more stack (blast command)\r
+ SHL DX,CL\r
+ MOV BX,DX\r
+SETSTACK:\r
+ CLI\r
+ MOV SP,BX\r
+ STI\r
+STACKOK:\r
+ PUSH AX\r
+ MOV AH,DISK_RESET ;Flush everything, and invalidate\r
+ INT 21H\r
+ POP AX\r
+ CMP AL,0FFH ;Illegal drive specifier?\r
+ JNZ FILECHK ;No -- check for filename\r
+\r
+DRVERR:\r
+ MOV DX,OFFSET DG:BADDRV\r
+CERROR:\r
+ PUSH CS ;Make sure DS is OK\r
+ POP DS\r
+ CALL PRINT ;Print error message\r
+ INT 20H\r
+\r
+CERROR2:\r
+ PUSH DX\r
+ CALL DONE ;Reset users disk\r
+ POP DX\r
+ JMP SHORT CERROR\r
+\r
+FILECHK:\r
+ MOV AX,(CHAR_OPER SHL 8)\r
+ INT 21H\r
+ MOV [SWITCHAR],DL\r
+ CMP DL,"/"\r
+ JNZ SLASHOK\r
+ MOV [DIRCHAR],"\"\r
+ MOV [USERDIR],"\"\r
+SLASHOK:\r
+ CMP DS:(BYTE PTR FCB+1)," " ;Filename specified?\r
+ JZ DRVCHK ;No -- get the correct drive\r
+ MOV AL,[SWITCHAR]\r
+ CMP DS:(BYTE PTR FCB+1),AL ;Filename specified?\r
+ JZ DRVCHK ;No -- get the correct drive\r
+ MOV BYTE PTR [FRAGMENT],1 ;Set flag to perform fragment\r
+ ;check on specified files\r
+DRVCHK:\r
+ CALL SETSWITCH ;Look for switches\r
+ MOV AH,GET_DEFAULT_DRIVE ;Get current drive\r
+ INT 21H\r
+ MOV [USERDEV],AL ;Save for later\r
+ MOV AH,AL\r
+ INC AH ;A = 1\r
+ MOV BH,DS:(BYTE PTR FCB) ;See if drive specified\r
+ OR BH,BH\r
+ JZ SETDSK\r
+ MOV AL,BH\r
+ MOV AH,AL\r
+ DEC AL ;A = 0\r
+SETDSK:\r
+ MOV [ALLDRV],AH ;Target drive\r
+ MOV [VOLNAM],AH ;A = 1\r
+ MOV [ORPHFCB],AH ;A = 1\r
+ ADD [BADDRVM],AL ;A = 0\r
+ ADD [BADDRVM2],AL ;A = 0\r
+ MOV DL,AH ;A = 1\r
+ MOV AH,GET_DPB ;Get the DPB\r
+ INT 21H\r
+ASSUME DS:NOTHING\r
+ CMP AL,-1\r
+ JNZ DRVISOK ;Bad drive (should always be ok)\r
+ MOV DX,OFFSET DG:BADDRV\r
+CERROR2J: JMP CERROR2\r
+\r
+DRVISOK:\r
+ DEC DL ;A = 0\r
+ MOV AH,SET_DEFAULT_DRIVE ;Set Target\r
+ INT 21H\r
+ CMP [BX.dpb_current_dir],0\r
+ JZ CURRISROOT ;Save users current dir for target\r
+ MOV SI,BX\r
+ ADD SI,dpb_dir_text\r
+ MOV DI,OFFSET DG:USERDIR + 1\r
+SETDIRLP:\r
+ LODSB\r
+ STOSB\r
+ OR AL,AL\r
+ JZ CURRISROOT\r
+ JMP SHORT SETDIRLP\r
+CURRISROOT:\r
+ MOV WORD PTR [THISDPB+2],DS\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:DG\r
+ MOV WORD PTR [THISDPB],BX\r
+ MOV AX,(GET_INTERRUPT_VECTOR SHL 8) OR 23H\r
+ INT 21H\r
+ MOV WORD PTR [CONTCH],BX\r
+ MOV WORD PTR [CONTCH+2],ES\r
+ MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H\r
+ MOV DX,OFFSET DG:INT_23\r
+ INT 21H\r
+ MOV AX,(GET_INTERRUPT_VECTOR SHL 8) OR 24H\r
+ INT 21H\r
+ MOV WORD PTR [HARDCH],BX\r
+ MOV WORD PTR [HARDCH+2],ES\r
+ MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 24H\r
+ MOV DX,OFFSET DG:INT_24\r
+ INT 21H\r
+ PUSH CS\r
+ POP ES\r
+ MOV DX,OFFSET DG:ROOTSTR\r
+ MOV AH,CHDIR ;Start at root\r
+ INT 21H\r
+ MOV DX,OFFSET DG:BADCD\r
+ JC CERROR2J ;Couldn't get there\r
+ MOV DX,OFFSET DG:FAT ;Scratch space\r
+ MOV AH,SET_DMA\r
+ INT 21H\r
+ MOV DX,OFFSET DG:VOLID ;Look for VOL ID\r
+ MOV AH,DIR_SEARCH_FIRST\r
+ INT 21H\r
+ CMP AL,-1\r
+ JZ NOTVOLID\r
+ CALL PRINTID ;Have a VOL ID\r
+NOTVOLID:\r
+ LDS BX,[THISDPB]\r
+ASSUME DS:NOTHING\r
+ MOV AX,[BX.dpb_sector_size]\r
+ MOV [SSIZE],AX ;Sector size in bytes\r
+ MOV AL,[BX.dpb_cluster_mask]\r
+ INC AL\r
+ MOV [CSIZE],AL ;Sectros per cluster\r
+ MOV AX,[BX.dpb_max_cluster]\r
+ MOV [MCLUS],AX ;Bound for FAT searching\r
+ DEC AX\r
+ MOV [DSIZE],AX ;Total data clusters on disk\r
+ MOV AL,[BX.dpb_FAT_size] ;Sectors for one fat\r
+ XOR AH,AH\r
+ MOV CX,AX\r
+ MUL [SSIZE] ;Bytes for FAT\r
+ ADD [FATMAP],AX ;Allocate FAT space\r
+ MOV AX,[FATMAP]\r
+ ADD AX,[MCLUS]\r
+ ADD AX,2 ;Insurance\r
+ MOV [SECBUF],AX ;Allocate FATMAP space\r
+ ADD AX,[SSIZE]\r
+ ADD AX,20 ;Insurance\r
+ MOV [STACKLIM],AX ;Limit on recursion\r
+ MOV DI,CX\r
+ MOV CL,[BX.dpb_FAT_count] ;Number of FATs\r
+ MOV DX,[BX.dpb_first_FAT] ;First sector of FAT\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:DG\r
+ MOV BX,OFFSET DG:FAT\r
+ MOV AL,[ALLDRV]\r
+ DEC AL\r
+ MOV AH,'1'\r
+RDLOOP:\r
+ XCHG CX,DI\r
+ PUSH DX\r
+ PUSH CX\r
+ PUSH DI\r
+ PUSH AX\r
+ INT 25H ;Read in the FAT\r
+ MOV [HECODE],AL\r
+ POP AX ;Flags\r
+ JNC RDOK\r
+ MOV DX,OFFSET DG:BADREAD_PRE ;Barfed\r
+ CALL PRINT\r
+ POP AX\r
+ PUSH AX\r
+ MOV DL,AH\r
+ CALL PRTCHR\r
+ MOV DX,OFFSET DG:BADREAD_POST\r
+ CALL PRINT\r
+ POP AX\r
+ POP CX\r
+ POP DI\r
+ POP DX\r
+ INC AH\r
+ ADD DX,DI\r
+ LOOP RDLOOP ;Try next FAT\r
+ CALL RDSKERR\r
+ JNZ NORETRY1\r
+ JMP NOTVOLID\r
+NORETRY1:\r
+ MOV BX,OFFSET DG:BADRDMES\r
+ JMP FATAL ;Couldn't read any FAT, BARF\r
+\r
+RDOK:\r
+ POP AX ;Clean up\r
+ POP AX\r
+ POP AX\r
+ POP AX\r
+ MOV SI,OFFSET DG:FAT\r
+ LODSB ;Check FAT ID byte\r
+ CMP AL,0F8H\r
+ JAE IDOK\r
+ MOV DX,OFFSET DG:BADIDBYT ;FAT ID bad\r
+ CALL PROMPTYN ;Ask user\r
+ JZ IDOK\r
+ JMP ALLDONE ;User said stop\r
+IDOK:\r
+ MOV DI,[FATMAP]\r
+ MOV CX,[MCLUS]\r
+ INC CX\r
+ XOR AL,AL\r
+ REP STOSB ;Initialize FATMAP to all free\r
+ MOV DX,OFFSET DG:DIRBUF ;FOR ALL SEARCHING\r
+ MOV AH,SET_DMA\r
+ INT 21H\r
+ XOR AX,AX\r
+ PUSH AX ;I am root\r
+ PUSH AX ;Parent is root\r
+ CALL DIRPROC\r
+ CALL CHKMAP ;Look for badsectors, orphans\r
+ CALL CHKCROSS ;Check for second pass\r
+ CALL DOCRLF\r
+ CALL REPORT\r
+\r
+ALLDONE:\r
+ CALL AMDONE\r
+ INT 20H ;Fini\r
+\r
+\r
+ASSUME DS:DG\r
+\r
+SUBTTL Check for extents in specified files\r
+PAGE\r
+CHECKFILES:\r
+;Search the directory for the files specified on the command line\r
+;and report the number of fragmented allocation units found in\r
+;each one.\r
+ CALL DOCRLF\r
+ MOV AH,SET_DMA\r
+ MOV DX,[FATMAP] ;Use the first free space available\r
+ MOV BP,DX\r
+ ADD BP,27 ;cluster in the directory entry\r
+ INT 21H\r
+ MOV AH,DIR_SEARCH_FIRST ;Look for the first file\r
+FRAGCHK:\r
+ MOV DX,FCB\r
+ INT 21H\r
+ OR AL,AL ;Did we find it?\r
+ JNZ MSGCHK ;No -- we're done\r
+ XOR AX,AX ;Initialize the fragment counter\r
+ MOV SI,[BP] ;Get the first cluster\r
+ CALL UNPACK\r
+ CMP DI,0FF8H ;End-of-file?\r
+ JAE NXTCHK ;Yes -- go report the results\r
+ INC SI\r
+ CMP SI,DI\r
+ JZ EACHCLUS\r
+ INC AX\r
+EACHCLUS:\r
+ MOV [OLDCLUS],DI ;Save the last cluster found\r
+ MOV SI,DI ;Get the next cluster\r
+ CALL UNPACK\r
+ INC [OLDCLUS] ;Bump the old cluster\r
+ CMP DI,[OLDCLUS] ;Are they the same?\r
+ JNZ LASTCLUS ;No -- check for end-of-file\r
+ JMP SHORT EACHCLUS ;Continue processing\r
+LASTCLUS:\r
+ CMP DI,0FF8H ;End-of-file?\r
+ JAE NXTCHK ;Yes -- go report the results\r
+ INC AX ;No -- found a fragement\r
+ JMP SHORT EACHCLUS ;Continue processing\r
+\r
+NXTCHK:\r
+ OR AX,AX\r
+ JZ GETNXT\r
+ MOV [FRAGMENT],2 ;Signal that we output at least one file\r
+ PUSH AX ;Save count of fragments\r
+ MOV SI,[FATMAP]\r
+ INC SI\r
+ CALL PRINTTHISEL2\r
+ CALL DOCRLF\r
+ MOV DX,OFFSET DG:CONTAINS ;Print message\r
+ CALL PRINT\r
+ POP SI ;Number of fragments found\r
+ INC SI ;Number non-contig blocks\r
+ XOR DI,DI\r
+ MOV BX,OFFSET DG:EXTENTS\r
+ PUSH BP\r
+ CALL DISP16BITS\r
+ POP BP\r
+GETNXT:\r
+ MOV AH,DIR_SEARCH_NEXT ;Look for the next file\r
+ JMP FRAGCHK\r
+\r
+MSGCHK:\r
+ CMP AH,DIR_SEARCH_FIRST\r
+ JNZ FILSPOK\r
+ MOV SI,FCB + 1 ;File not found error\r
+ CALL PRINTTHISEL2\r
+ CALL DOCRLF\r
+ MOV DX,OFFSET DG:OPNERR\r
+ CALL PRINT ;Bad file spec\r
+ RET\r
+FILSPOK:\r
+ CMP BYTE PTR [FRAGMENT],2\r
+ JZ CDONE\r
+ MOV DX,OFFSET DG:NOEXTENTS\r
+ CALL PRINT\r
+CDONE:\r
+ RET\r
+\r
+\r
+FIGREC:\r
+;Convert cluster number in BX to sector # AH of cluster in DX\r
+ LDS DI,[THISDPB]\r
+ASSUME DS:NOTHING\r
+ MOV CL,[DI.dpb_cluster_shift]\r
+ MOV DX,BX\r
+ DEC DX\r
+ DEC DX\r
+ SHL DX,CL\r
+ OR DL,AH\r
+ ADD DX,[DI.dpb_first_sector]\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:DG\r
+ RET\r
+\r
+\r
+SUBTTL PRINTID - Print Volume ID info\r
+PAGE\r
+PRINTID:\r
+ASSUME DS:DG\r
+ MOV DX,OFFSET DG:INTERNATVARS\r
+ MOV AX,INTERNATIONAL SHL 8\r
+ INT 21H\r
+ MOV [DISPFLG],1 ;Don't sub spaces for leading zeros\r
+ MOV SI,OFFSET DG:FAT + 8\r
+ MOV DI,OFFSET DG:VNAME\r
+ MOV CX,11\r
+ REP MOVSB\r
+ MOV DX,OFFSET DG:IDMES1\r
+ CALL PRINT ;Print ID message\r
+ ADD SI,13\r
+ LODSW ;Get date\r
+ PUSH SI\r
+ MOV DX,AX\r
+ MOV AX,[INTERNATVARS.Date_tim_format]\r
+ OR AX,AX\r
+ JZ USPDAT\r
+ DEC AX\r
+ JZ EUPDAT\r
+ CALL P_YR\r
+ CALL P_DSEP\r
+ CALL P_MON\r
+ CALL P_DSEP\r
+ MOV CX,1000H ;Do not supress leading zeroes\r
+ CALL P_DAY\r
+ JMP P_TIME\r
+\r
+USPDAT:\r
+ CALL P_MONTH_NAM\r
+ MOV CX,1110H ;Supress at most 1 leading 0\r
+ CALL P_DAY\r
+ PUSH DX\r
+ MOV DL,','\r
+ CALL PRTCHR\r
+ MOV DL,' '\r
+ CALL PRTCHR\r
+ POP DX\r
+PYA:\r
+ CALL P_YR\r
+ JMP P_TIME\r
+\r
+EUPDAT:\r
+ MOV CX,1110H ;Supress at most 1 leading 0\r
+ CALL P_DAY\r
+ PUSH DX\r
+ MOV DL,' '\r
+ CALL PRTCHR\r
+ POP DX\r
+ CALL P_MONTH_NAM\r
+ JMP PYA\r
+\r
+P_DSEP:\r
+ PUSH DX\r
+ MOV DL,[INTERNATVARS.Date_sep]\r
+ CALL PRTCHR\r
+ POP DX\r
+ RET\r
+\r
+P_MONTH_NAM:\r
+ MOV AX,DX\r
+ PUSH DX\r
+ MOV CL,5\r
+ SHR AX,CL\r
+ AND AX,0FH ;Month in AX\r
+ DEC AX ;Make 0 indexed\r
+ MOV CX,AX\r
+ SHL AX,1\r
+ ADD AX,CX ;Mult by 3 chars/mo\r
+ MOV SI,OFFSET DG:MONTAB\r
+ ADD SI,AX\r
+ LODSB\r
+ MOV DL,AL\r
+ CALL PRTCHR\r
+ LODSB\r
+ MOV DL,AL\r
+ CALL PRTCHR\r
+ LODSB\r
+ MOV DL,AL\r
+ CALL PRTCHR\r
+ MOV DL,' '\r
+ CALL PRTCHR\r
+ POP DX\r
+ RET\r
+\r
+P_MON:\r
+ MOV SI,DX\r
+ PUSH DX\r
+ MOV CL,5\r
+ SHR SI,CL\r
+ AND SI,0FH ;Month in SI\r
+ CALL CONVERT\r
+ MOV DL,AL\r
+ MOV CX,1000H ;Do not supress leading 0\r
+ CALL OUTBYTE ;Print month\r
+ POP DX\r
+ RET\r
+\r
+P_DAY:\r
+ MOV SI,DX\r
+ PUSH DX\r
+ PUSH CX\r
+ AND SI,01FH ;SI has day\r
+ CALL CONVERT\r
+ POP CX\r
+ MOV DL,AL\r
+ CALL OUTBYTE ;Print day\r
+ POP DX\r
+ RET\r
+\r
+P_YR:\r
+ MOV SI,DX\r
+ PUSH DX\r
+ MOV CL,9\r
+ SHR SI,CL\r
+ AND SI,07FH ;SI has raw year\r
+ ADD SI,1980 ;Real year\r
+ CALL CONVERT\r
+ MOV CX,1000H ;Do not supress leading zeros\r
+ CALL OUTWORD ;Print year\r
+ POP DX\r
+ RET\r
+\r
+P_TIME:\r
+ MOV DL,' '\r
+ CALL PRTCHR\r
+ POP SI\r
+ ADD SI,-4\r
+ LODSW ;Get time\r
+ MOV DI,AX\r
+ MOV SI,DI\r
+ MOV CL,11\r
+ SHR SI,CL\r
+ AND SI,01FH ;SI has hour\r
+ CMP [INTERNATVARS.Time_24],0\r
+ JNZ ISOK2 ;24 hour time?\r
+ CMP SI,12\r
+ JB ISOK ;Is AM\r
+ MOV [TCHAR],'p'\r
+ JZ ISOK ;Is 12-1p\r
+ SUB SI,12 ;Is PM\r
+ISOK:\r
+ OR SI,SI\r
+ JNZ ISOK2\r
+ MOV SI,12 ;0 is 12a\r
+ISOK2:\r
+ CALL CONVERT\r
+ MOV CX,1110H ;Supress at most 1 leading 0\r
+ MOV DL,AL\r
+ CALL OUTBYTE ;Print hour\r
+ MOV DL,BYTE PTR [INTERNATVARS.Time_sep]\r
+ CALL PRTCHR\r
+ MOV SI,DI\r
+ MOV CL,5\r
+ SHR SI,CL\r
+ AND SI,03FH ;SI has minute\r
+ CALL CONVERT\r
+ MOV CX,1000H ;Do not supress leading zeroes\r
+ MOV DL,AL\r
+ CALL OUTBYTE ;Print minute\r
+ MOV DL,[TCHAR]\r
+ CMP [INTERNATVARS.Time_24],0\r
+ JNZ NOAP ;24 hour time, no a or p\r
+ CALL PRTCHR ;Print a or p\r
+NOAP:\r
+ MOV DX,OFFSET DG:IDPOST\r
+ CALL PRINT\r
+ MOV [DISPFLG],0\r
+ RET\r
+\r
+CONVERT:\r
+ MOV CX,16\r
+ XOR AX,AX\r
+CNVLOOP:\r
+ SHL SI,1\r
+ CALL CONVWRD\r
+ CLC\r
+ LOOP CNVLOOP\r
+ RET\r
+\r
+SUBTTL Misc Routines - Mostly I/O\r
+PAGE\r
+CONVWRD:\r
+ ADC AL,AL\r
+ DAA\r
+ XCHG AL,AH\r
+ ADC AL,AL\r
+ DAA\r
+ XCHG AL,AH\r
+RET1: RET\r
+\r
+UNSCALE:\r
+ SHR CX,1\r
+ JC RET1\r
+ SHL SI,1\r
+ RCL DI,1\r
+ JMP SHORT UNSCALE\r
+\r
+DISP16BITS:\r
+ MOV BYTE PTR DISPFLG,1\r
+ JMP SHORT DISP32BITS\r
+\r
+DISPCLUS:\r
+ MUL [SSIZE]\r
+ MOV CL,[CSIZE]\r
+ XOR CH,CH\r
+ MOV SI,AX\r
+ MOV DI,DX\r
+ CALL UNSCALE\r
+\r
+DISP32BITS:\r
+ PUSH BP\r
+ PUSH BX\r
+ XOR AX,AX\r
+ MOV BX,AX\r
+ MOV BP,AX\r
+ MOV CX,32\r
+CONVLP:\r
+ SHL SI,1\r
+ RCL DI,1\r
+ XCHG AX,BP\r
+ CALL CONVWRD\r
+ XCHG AX,BP\r
+ XCHG AX,BX\r
+ CALL CONVWRD\r
+ XCHG AX,BX\r
+ ADC AL,0\r
+ LOOP CONVLP\r
+ ; Conversion complete\r
+ MOV CX,1310H ;Print 3-digit number with 2 leading blanks\r
+ CMP BYTE PTR DISPFLG,0\r
+ JNZ FOURDIG\r
+ MOV CX,1810H ;Print 8-digit number with 2 leading blanks\r
+ XCHG DX,AX\r
+ CALL DIGIT\r
+ XCHG AX,BX\r
+ CALL OUTWORD\r
+FOURDIG:\r
+ MOV AX,BP\r
+ CALL OUTWORD\r
+ MOV BYTE PTR DISPFLG,0\r
+ POP DX\r
+ CALL PRINT\r
+ POP BP\r
+ RET\r
+\r
+OUTWORD:\r
+ PUSH AX\r
+ MOV DL,AH\r
+ CALL OUTBYTE\r
+ POP DX\r
+OUTBYTE:\r
+ MOV DH,DL\r
+ SHR DL,1\r
+ SHR DL,1\r
+ SHR DL,1\r
+ SHR DL,1\r
+ CALL DIGIT\r
+ MOV DL,DH\r
+DIGIT:\r
+ AND DL,0FH\r
+ JZ BLANKZER\r
+ MOV CL,0\r
+BLANKZER:\r
+ DEC CH\r
+ AND CL,CH\r
+ OR DL,30H\r
+ SUB DL,CL\r
+ CMP BYTE PTR DISPFLG,0\r
+ JZ PRTCHR\r
+ CMP DL,30H\r
+ JL RET2\r
+PRTCHR:\r
+ MOV AH,STD_CON_OUTPUT\r
+ INT 21H\r
+RET2: RET\r
+\r
+PRINTCNT:\r
+ LODSB\r
+ MOV DL,AL\r
+ INT 21H\r
+ LOOP PRINTCNT\r
+ RET\r
+\r
+EPRINT:\r
+ CALL CHECKERR\r
+ JNZ RET$1\r
+ JMP SHORT PRINT\r
+\r
+DOCRLF:\r
+ MOV DX,OFFSET DG:CRLF\r
+PRINT:\r
+ MOV AH,STD_CON_STRING_OUTPUT\r
+ INT 21H\r
+RET$1: RET\r
+\r
+DOTCOMBMES:\r
+ CMP [NOISY],0\r
+ JZ SUBERRP\r
+ PUSH DX\r
+ CALL PRINTCURRDIRERR\r
+ MOV DX,OFFSET DG:CENTRY\r
+ CALL EPRINT\r
+ POP DX\r
+ CALL EPRINT\r
+ CALL DOCRLF\r
+ RET\r
+\r
+SUBERRP:\r
+ MOV AL,1\r
+ XCHG AL,[ERRSUB]\r
+ CMP AL,0\r
+ JNZ RET32\r
+ MOV SI,OFFSET DG:NUL\r
+ CALL PRINTCURRDIRERR\r
+ MOV DX,OFFSET DG:BADSUBDIR\r
+ CALL EPRINT\r
+RET32: RET\r
+\r
+\r
+FCB_TO_ASCZ: ;Convert DS:SI to ASCIIZ ES:DI\r
+ MOV CX,8\r
+MAINNAME:\r
+ LODSB\r
+ CMP AL,' '\r
+ JZ SKIPSPC\r
+ STOSB\r
+SKIPSPC:\r
+ LOOP MAINNAME\r
+ LODSB\r
+ CMP AL,' '\r
+ JZ GOTNAME\r
+ MOV AH,AL\r
+ MOV AL,'.'\r
+ STOSB\r
+ XCHG AL,AH\r
+ STOSB\r
+ MOV CL,2\r
+EXTNAME:\r
+ LODSB\r
+ CMP AL,' '\r
+ JZ GOTNAME\r
+ STOSB\r
+ LOOP EXTNAME\r
+\r
+GOTNAME:\r
+ XOR AL,AL\r
+ STOSB\r
+ RET\r
+\r
+CODE ENDS\r
+ END CHKDSK\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+TITLE CHKDSK Messages\r
+\r
+FALSE EQU 0\r
+TRUE EQU NOT FALSE\r
+\r
+.xlist\r
+.xcref\r
+ INCLUDE DOSSYM.ASM\r
+;The DOST: prefix is a DEC TOPS/20 directory prefix. Remove it for\r
+; assembly in MS-DOS assembly environments using MASM. The DOSSYM.ASM\r
+; file must exist though, it is included with OEM distribution.\r
+.cref\r
+.list\r
+CODE SEGMENT PUBLIC BYTE\r
+CODE ENDS\r
+\r
+CONST SEGMENT PUBLIC BYTE\r
+ EXTRN HIDSIZ:WORD,HIDCNT:WORD,DIRCNT:WORD,DIRSIZ:WORD,FILCNT:WORD\r
+ EXTRN FILSIZ:WORD,ORPHCNT:WORD,ORPHSIZ:WORD,BADSIZ:WORD,LCLUS:WORD\r
+ EXTRN DOFIX:BYTE\r
+CONST ENDS\r
+\r
+DATA SEGMENT PUBLIC BYTE\r
+ EXTRN DSIZE:WORD\r
+DATA ENDS\r
+\r
+DG GROUP CODE,CONST,DATA\r
+\r
+\r
+CODE SEGMENT PUBLIC BYTE\r
+ASSUME CS:DG,DS:DG,ES:DG,SS:DG\r
+\r
+ PUBLIC RDSKERR,WDSKERR,SETSWITCH,PROMPTYN,DOINT26,CHAINREPORT,REPORT\r
+ EXTRN RDONE:NEAR,PRTCHR:NEAR,PRINT:NEAR,DOCRLF:NEAR\r
+ EXTRN DISP16BITS:NEAR,FINDCHAIN:NEAR\r
+ EXTRN DISP32BITS:NEAR,DISPCLUS:NEAR\r
+\r
+DOINT26:\r
+ PUSH CX\r
+ PUSH AX\r
+ PUSH DX\r
+ PUSH BX\r
+ INT 26H\r
+ MOV [HECODE],AL\r
+ POP AX ;FLAGS\r
+ POP BX\r
+ POP DX\r
+ POP AX\r
+ POP CX\r
+ JNC RET23\r
+ MOV SI,OFFSET DG:WRITING\r
+ CALL DSKERR\r
+ JZ DOINT26\r
+RET23: RET\r
+\r
+RDSKERR:\r
+ MOV SI,OFFSET DG:READING\r
+ JMP SHORT DSKERR\r
+\r
+WDSKERR:\r
+ MOV SI,OFFSET DG:WRITING\r
+DSKERR:\r
+ PUSH AX\r
+ PUSH BX\r
+ PUSH CX\r
+ PUSH DX\r
+ PUSH DI\r
+ PUSH ES\r
+ MOV AL,[HECODE]\r
+ CMP AL,12\r
+ JBE HAVCOD\r
+ MOV AL,12\r
+HAVCOD:\r
+ XOR AH,AH\r
+ MOV DI,AX\r
+ SHL DI,1\r
+ MOV DX,WORD PTR [DI+MESBAS] ; Get pointer to error message\r
+ CALL PRINT ; Print error type\r
+ MOV DX,OFFSET DG:ERRMES\r
+ CALL PRINT\r
+ MOV DX,SI\r
+ CALL PRINT\r
+ MOV DX,OFFSET DG:DRVMES\r
+ CALL PRINT\r
+ASK:\r
+ MOV DX,OFFSET DG:REQUEST\r
+ CALL PRINT\r
+ MOV AX,(STD_CON_INPUT_FLUSH SHL 8)+STD_CON_INPUT\r
+ INT 21H ; Get response\r
+ PUSH AX\r
+ CALL DOCRLF\r
+ POP AX\r
+ OR AL,20H ; Convert to lower case\r
+ CMP AL,"i" ; Ignore?\r
+ JZ EEXITNZ\r
+ CMP AL,"r" ; Retry?\r
+ JZ EEXIT\r
+ CMP AL,"a" ; Abort?\r
+ JNZ ASK\r
+ JMP RDONE\r
+\r
+EEXITNZ:\r
+ OR AL,AL ; Resets zero flag\r
+EEXIT:\r
+ POP ES\r
+ POP DI\r
+ POP DX\r
+ POP CX\r
+ POP BX\r
+ POP AX\r
+ RET\r
+\r
+PROMPTYN:\r
+;Prompt message in DX\r
+;Prompt user for Y or N answer. Zero set if Y\r
+ PUSH SI\r
+ CALL PRINT\r
+PAGAIN:\r
+ MOV DX,OFFSET DG:YES_NO\r
+ CALL PRINT\r
+ MOV DX,OFFSET DG:CONBUF\r
+ MOV AH,STD_CON_STRING_INPUT\r
+ INT 21H\r
+ CALL DOCRLF\r
+ MOV SI,OFFSET DG:CONBUF+2\r
+ CMP BYTE PTR [SI-1],0\r
+ JZ PAGAIN\r
+ LODSB\r
+ OR AL,20H ;Convert to lower case\r
+ CMP AL,'y'\r
+ JZ GOTANS\r
+ CMP AL,'n'\r
+ JZ GOTNANS\r
+ JMP PAGAIN\r
+GOTNANS:\r
+ OR AL,AL ;Reset zero\r
+GOTANS:\r
+ POP SI\r
+ RET\r
+\r
+SETSWITCH:\r
+;Look for F or V switch in command line\r
+ MOV SI,80H\r
+ LODSB\r
+ MOV DI,SI\r
+ MOV CL,AL\r
+ XOR CH,CH\r
+ JCXZ RET10 ;No parameters\r
+ MOV AL,[SWITCHAR]\r
+MORESCAN:\r
+ REPNZ SCASB\r
+ JNZ RET10\r
+ JCXZ BADSWITCHA\r
+ MOV AH,[DI]\r
+ INC DI\r
+ OR AH,20H ;Convert to lower case\r
+ CMP AH,'f'\r
+ JNZ CHECKV\r
+ INC [DOFIX]\r
+ JMP SHORT CHEKMORE\r
+CHECKV:\r
+ CMP AH,'v'\r
+ JZ SETNOISY\r
+ CALL BADSWITCH\r
+ JMP SHORT CHEKMORE\r
+SETNOISY:\r
+ INC [NOISY]\r
+CHEKMORE:\r
+ LOOP MORESCAN\r
+ RET\r
+\r
+BADSWITCHA:\r
+ MOV AH,' ' ;Print a non switch\r
+BADSWITCH:\r
+ PUSH AX\r
+ MOV DL,[SWITCHAR]\r
+ CALL PRTCHR\r
+ POP AX\r
+ PUSH AX\r
+ MOV DL,AH\r
+ CALL PRTCHR\r
+ MOV DX,OFFSET DG:BADSWMES\r
+ CALL PRINT\r
+ POP AX\r
+RET10: RET\r
+\r
+\r
+;**************************************\r
+; Prints XXX lost clusters found in YYY chains message\r
+; On entry SI is the XXX value and the YYY value is\r
+; in ORPHCNT.\r
+; NOTE:\r
+; The DISP16BITS routine prints the number in DI:SI followed\r
+; by the message pointed to by BX. If it is desired to\r
+; print a message before the first number, point at the\r
+; message with DX and call PRINT.\r
+\r
+CHAINREPORT:\r
+ XOR DI,DI\r
+ MOV BX,OFFSET DG:ORPHMES2\r
+ CALL DISP16BITS\r
+ CALL FINDCHAIN\r
+ MOV BX,OFFSET DG:CHNUMMES\r
+ MOV SI,[ORPHCNT]\r
+ XOR DI,DI\r
+ CALL DISP16BITS ;Tell user how many chains found\r
+ RET\r
+\r
+;*****************************************\r
+;Prints all of the reporting data\r
+;NOTE:\r
+; The DISPCLUS, DISP16BITS and DISP32BITS routines\r
+; print the number in DI:SI followed\r
+; by the message pointed to by BX. If it is desired to\r
+; print a message before the first number, point at the\r
+; message with DX and call PRINT.\r
+\r
+REPORT:\r
+ MOV AX,[DSIZE]\r
+ MOV BX,OFFSET DG:DSKSPC\r
+ CALL DISPCLUS ;Total size\r
+ CMP [HIDCNT],0\r
+ JZ USERLIN\r
+ MOV AX,[HIDSIZ] ;Hidden files\r
+ MOV BX,OFFSET DG:INMES\r
+ CALL DISPCLUS\r
+ MOV SI,[HIDCNT]\r
+ XOR DI,DI\r
+ MOV BX,OFFSET DG:HIDMES\r
+ CALL DISP16BITS\r
+USERLIN:\r
+ CMP [DIRCNT],0\r
+ JZ DIRLIN\r
+ MOV AX,[DIRSIZ]\r
+ MOV BX,OFFSET DG:INMES\r
+ CALL DISPCLUS\r
+ MOV SI,[DIRCNT]\r
+ XOR DI,DI\r
+ MOV BX,OFFSET DG:DIRMES\r
+ CALL DISP16BITS\r
+DIRLIN:\r
+ CMP [FILCNT],0\r
+ JZ ORPHLIN\r
+ MOV AX,[FILSIZ] ;Regular files\r
+ MOV BX,OFFSET DG:INMES\r
+ CALL DISPCLUS\r
+ MOV SI,[FILCNT]\r
+ XOR DI,DI\r
+ MOV BX,OFFSET DG:FILEMES\r
+ CALL DISP16BITS\r
+ORPHLIN:\r
+ MOV AX,[ORPHSIZ]\r
+ OR AX,AX\r
+ JZ BADLIN\r
+ MOV BX,OFFSET DG:INMES ;Orphans\r
+ CMP [DOFIX],0\r
+ JNZ ALLSET1\r
+ MOV BX,OFFSET DG:INMES2 ;Orphans\r
+ALLSET1:\r
+ CALL DISPCLUS\r
+ MOV SI,[ORPHCNT]\r
+ XOR DI,DI\r
+ MOV BX,OFFSET DG:ORPHMES\r
+ CALL DISP16BITS\r
+BADLIN:\r
+ MOV AX,[BADSIZ]\r
+ OR AX,AX\r
+ JZ AVAILIN\r
+ MOV BX,OFFSET DG:BADSPC ;Bad sectors\r
+ CALL DISPCLUS\r
+AVAILIN:\r
+ MOV AX,[DSIZE]\r
+ SUB AX,[DIRSIZ]\r
+ SUB AX,[FILSIZ]\r
+ SUB AX,[HIDSIZ]\r
+ SUB AX,[BADSIZ]\r
+ SUB AX,[ORPHSIZ]\r
+ SUB AX,[LCLUS]\r
+ MOV BX,OFFSET DG:FRESPC\r
+ CALL DISPCLUS ;Free space is whats left\r
+ MOV AX,DS:WORD PTR [2] ;Find out about memory\r
+ MOV DX,16\r
+ MUL DX\r
+ MOV SI,AX\r
+ MOV DI,DX\r
+ MOV BX,OFFSET DG:TOTMEM\r
+ CALL DISP32BITS\r
+ MOV AX,DS:WORD PTR [2]\r
+ MOV DX,CS\r
+ SUB AX,DX\r
+ MOV DX,16\r
+ MUL DX\r
+ MOV SI,AX\r
+ MOV DI,DX\r
+ MOV BX,OFFSET DG:FREMEM\r
+ CALL DISP32BITS\r
+ RET\r
+\r
+CODE ENDS\r
+\r
+\r
+CONST SEGMENT PUBLIC BYTE\r
+\r
+ EXTRN HECODE:BYTE,SWITCHAR:BYTE,NOISY:BYTE,DOFIX:BYTE,CONBUF:BYTE\r
+\r
+ PUBLIC CRLF2,CRLF,BADVER,BADDRV\r
+ PUBLIC BADSUBDIR,CENTRY,CLUSBAD,BADATT,BADSIZM\r
+ PUBLIC FIXMES,DIRECMES,CDDDMES\r
+ PUBLIC FREEBYMESF_PRE,FREEBYMES_PRE,FREEBYMESF_POST,FREEBYMES_POST\r
+ PUBLIC CREATMES,NDOTMES\r
+ PUBLIC BADTARG1,BADTARG2,BADCD,FATALMES,BADRDMES\r
+ PUBLIC BADDRVM,STACKMES,BADDPBDIR\r
+ PUBLIC BADDRVM2\r
+ PUBLIC NULNZ,NULDMES,BADCLUS,NORECDOT\r
+ PUBLIC NORECDDOT,IDMES1,IDPOST,VNAME,TCHAR\r
+ PUBLIC MONTAB,BADREAD_PRE,BADREAD_POST,BADWRITE_PRE\r
+ PUBLIC BADWRITE_POST,BADCHAIN,CROSSMES_PRE,CROSSMES_POST\r
+ PUBLIC FREEMES\r
+ PUBLIC OPNERR\r
+ PUBLIC CONTAINS,EXTENTS,NOEXTENTS,INDENT\r
+ PUBLIC BADIDBYT,PTRANDIR,PTRANDIR2\r
+\r
+\r
+MESBAS DW OFFSET DG:ERR0\r
+ DW OFFSET DG:ERR1\r
+ DW OFFSET DG:ERR2\r
+ DW OFFSET DG:ERR3\r
+ DW OFFSET DG:ERR4\r
+ DW OFFSET DG:ERR5\r
+ DW OFFSET DG:ERR6\r
+ DW OFFSET DG:ERR7\r
+ DW OFFSET DG:ERR8\r
+ DW OFFSET DG:ERR9\r
+ DW OFFSET DG:ERR10\r
+ DW OFFSET DG:ERR11\r
+ DW OFFSET DG:ERR12\r
+\r
+CRLF2 DB 13,10\r
+CRLF DB 13,10,"$"\r
+\r
+;Messages\r
+\r
+BADVER DB "Incorrect DOS version",13,10,"$"\r
+BADDRV DB "Invalid drive specification$"\r
+\r
+BADSWMES DB " Invalid parameter",13,10,"$"\r
+\r
+BADSUBDIR DB " Invalid sub-directory entry.",13,10,"$"\r
+CENTRY DB " Entry has a bad $"\r
+CLUSBAD DB " link$"\r
+BADATT DB " attribute$"\r
+BADSIZM DB " size$"\r
+\r
+;"BADTARG1<name of dir followed by CR LF>BADTARG2"\r
+BADTARG1 DB "Cannot CHDIR to $"\r
+BADTARG2 DB " tree past this point not processed.",13,10,"$"\r
+\r
+BADCD DB "Cannot CHDIR to root",13,10,"$"\r
+\r
+FATALMES DB "Processing cannot continue.",13,10,"$"\r
+BADRDMES DB "File allocation table bad drive "\r
+BADDRVM DB "A.",13,10,"$"\r
+STACKMES DB "Insufficient memory.",13,10,"$"\r
+BADDPBDIR DB "Invalid current directory.",13,10,"$"\r
+\r
+;INT 24 MESSAGE SHOULD AGREE WITH COMMAND\r
+\r
+READING DB "read$"\r
+WRITING DB "writ$"\r
+ERRMES DB " error $"\r
+DRVMES DB "ing drive "\r
+BADDRVM2 DB "A",13,10,"$"\r
+REQUEST DB "Abort, Retry, Ignore? $"\r
+ERR0 DB "Write protect$"\r
+ERR1 DB "Bad unit$"\r
+ERR2 DB "Not ready$"\r
+ERR3 DB "Bad command$"\r
+ERR4 DB "Data$"\r
+ERR5 DB "Bad call format$"\r
+ERR6 DB "Seek$"\r
+ERR7 DB "Non-DOS disk$"\r
+ERR8 DB "Sector not found$"\r
+ERR9 DB "No paper$"\r
+ERR10 DB "Write fault$"\r
+ERR11 DB "Read fault$"\r
+ERR12 DB "Disk$"\r
+\r
+\r
+NDOTMES DB " Does not exist.",13,10,"$"\r
+NULNZ DB " First cluster number is invalid,",13,10\r
+ DB " entry truncated.",13,10,"$"\r
+NULDMES DB " Directory is totally empty, no . or ..",13,10,"$"\r
+BADCLUS DB " Allocation error, size adjusted.",13,10,"$"\r
+NORECDOT DB " Cannot recover . entry, processing continued.",13,10,"$"\r
+NORECDDOT DB " Cannot recover .. entry,"\r
+\r
+;VOLUME ID\r
+\r
+;"IDMES1/name at VNAME<date and time>IDPOST"\r
+IDPOST DB 13,10,"$" ;WARNING this is currently the tail of\r
+ ; the previos message!!!\r
+IDMES1 DB "Volume "\r
+VNAME DB 12 DUP(' ')\r
+ DB "created $"\r
+TCHAR DB 'a'\r
+MONTAB DB "JanFebMarAprMayJunJulAugSepOctNovDec"\r
+\r
+\r
+\r
+;"BADREAD_PRE<# of FAT>BADREAD_POST"\r
+BADREAD_PRE DB "Disk error reading FAT $"\r
+\r
+;"BADWRITE_PRE<# of FAT>BADWRITE_POST"\r
+BADWRITE_PRE DB "Disk error writing FAT $"\r
+\r
+BADCHAIN DB " Has invalid cluster, file truncated."\r
+\r
+BADREAD_POST LABEL BYTE\r
+BADWRITE_POST LABEL BYTE\r
+\r
+;"<name of file followed by CR LF>CROSSMES_PRE<# of cluster>CROSSMES_POST"\r
+CROSSMES_POST DB 13,10,"$" ;WARNING Is tail of previos messages\r
+CROSSMES_PRE DB " Is cross linked on cluster $"\r
+\r
+;CHAINREPORT messages\r
+ORPHMES2 DB " lost clusters found in $"\r
+CHNUMMES DB " chains.",13,10,"$"\r
+\r
+FREEMES DB "Convert lost chains to files $"\r
+\r
+;REPORT messages\r
+ORPHMES DB " recovered files",13,10,"$"\r
+DSKSPC DB " bytes total disk space",13,10,"$"\r
+INMES DB " bytes in $"\r
+INMES2 DB " bytes would be in",13,10\r
+ DB " $"\r
+FILEMES DB " user files",13,10,"$"\r
+BADSPC DB " bytes in bad sectors",13,10,"$"\r
+HIDMES DB " hidden files",13,10,"$"\r
+DIRMES DB " directories",13,10,"$"\r
+FRESPC DB " bytes available on disk",13,10,13,10,"$"\r
+TOTMEM DB " bytes total memory",13,10,"$"\r
+FREMEM DB " bytes free",13,10,13,10,"$"\r
+\r
+;"<filename followed by CR LF>CONTAINS<# non-contig blocks>EXTENTS"\r
+CONTAINS DB " Contains $"\r
+EXTENTS DB " non-contiguous blocks.",13,10,"$"\r
+\r
+NOEXTENTS DB "All specified file(s) are contiguous.",13,10,"$"\r
+INDENT DB " $"\r
+\r
+BADIDBYT DB "Probable non-DOS disk."\r
+ DB 13,10,"Continue $"\r
+YES_NO DB "(Y/N)? $"\r
+PTRANDIR DB " Unrecoverable error in directory.",13,10\r
+PTRANDIR2 DB " Convert directory to file $"\r
+FIXMES DB 13,10,"Errors found, F parameter not specified."\r
+ DB 13,10,"Corrections will not be written to disk.",13,10,13,10,"$"\r
+DIRECMES DB "Directory $"\r
+CDDDMES DB " CHDIR .. failed, trying alternate method.",13,10,"$"\r
+\r
+\r
+FREEBYMESF_POST DB " bytes disk space freed.",13,10\r
+FREEBYMESF_PRE DB "$"\r
+FREEBYMES_POST DB " bytes disk space",13,10\r
+ DB " would be freed.",13,10\r
+FREEBYMES_PRE DB "$"\r
+\r
+\r
+CREATMES DB "Insufficient room in root directory."\r
+ DB 13,10,"Erase files in root and repeat CHKDSK.",13,10,"$"\r
+OPNERR DB " File not found.",13,10,"$"\r
+\r
+\r
+CONST ENDS\r
+ END\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+TITLE CHKPROC - Procedures called from chkdsk\r
+\r
+FALSE EQU 0\r
+TRUE EQU NOT FALSE\r
+\r
+DRVCHAR EQU ":"\r
+\r
+ INCLUDE DOSSYM.ASM\r
+\r
+SUBTTL Segments used in load order\r
+\r
+CODE SEGMENT PUBLIC\r
+CODE ENDS\r
+\r
+CONST SEGMENT PUBLIC BYTE\r
+\r
+ EXTRN CLUSBAD:BYTE,BADATT:BYTE,BADSIZM:BYTE\r
+ EXTRN DIRECMES:BYTE,CDDDMES:BYTE,NDOTMES:BYTE\r
+ EXTRN BADTARG1:BYTE,BADTARG2:BYTE,FATALMES:BYTE\r
+ EXTRN STACKMES:BYTE,BADDPBDIR:BYTE,CREATMES:BYTE\r
+ EXTRN FREEBYMES_PRE:BYTE,FREEBYMESF_PRE:BYTE\r
+ EXTRN FREEBYMES_POST:BYTE,FREEBYMESF_POST:BYTE\r
+ EXTRN NULNZ:BYTE,NULDMES:BYTE,BADCLUS:BYTE\r
+ EXTRN NORECDDOT:BYTE,NORECDOT:BYTE,DOTMES:BYTE\r
+ EXTRN BADWRITE_PRE:BYTE,BADCHAIN:BYTE,CROSSMES_PRE:BYTE\r
+ EXTRN BADWRITE_POST:BYTE,CROSSMES_POST:BYTE,INDENT:BYTE\r
+ EXTRN PTRANDIR:BYTE,PTRANDIR2:BYTE,FREEMES:BYTE,FIXMES:BYTE\r
+\r
+ EXTRN NOISY:BYTE,DOFIX:BYTE,DIRBUF:WORD,DOTENT:BYTE,FIXMFLG:BYTE\r
+ EXTRN HAVFIX:BYTE,SECONDPASS:BYTE,LCLUS:WORD,DIRTYFAT:BYTE\r
+ EXTRN NUL:BYTE,ALLFILE:BYTE,PARSTR:BYTE,ERRSUB:WORD,USERDIR:BYTE\r
+ EXTRN HIDCNT:WORD,HIDSIZ:WORD,FILCNT:WORD,FILSIZ:WORD,DIRCHAR:BYTE\r
+ EXTRN DIRCNT:WORD,DIRSIZ:WORD,FRAGMENT:BYTE,HECODE:BYTE\r
+ EXTRN BADSIZ:WORD,ORPHSIZ:WORD,DDOTENT:BYTE,CROSSCNT:WORD\r
+ EXTRN ORPHCNT:WORD,ORPHFCB:BYTE,ORPHEXT:BYTE,ALLDRV:BYTE,DIRCHAR:BYTE\r
+\r
+CONST ENDS\r
+\r
+DATA SEGMENT PUBLIC WORD\r
+\r
+ EXTRN THISDPB:DWORD,HARDCH:DWORD,CONTCH:DWORD,USERDEV:BYTE\r
+ EXTRN CSIZE:BYTE,SSIZE:WORD,DSIZE:WORD,MCLUS:WORD,NAMBUF:BYTE\r
+ EXTRN DOTSNOGOOD:BYTE,ZEROTRUNC:BYTE,ISCROSS:BYTE,SRFCBPT:WORD\r
+ EXTRN FATMAP:WORD,SECBUF:WORD,ERRCNT:BYTE,STACKLIM:WORD,FAT:WORD\r
+\r
+DATA ENDS\r
+\r
+DG GROUP CODE,CONST,DATA\r
+\r
+SUBTTL Initialized Data\r
+PAGE\r
+\r
+\r
+CODE SEGMENT PUBLIC\r
+ASSUME CS:DG,DS:DG,ES:DG,SS:DG\r
+\r
+ PUBLIC INT_23,INT_24,FINDCHAIN,DONE,AMDONE,RDONE\r
+ PUBLIC FATAL,DIRPROC,CHKMAP,CHKCROSS,UNPACK\r
+ PUBLIC PRINTTHISEL2,CHECKERR,PRINTCURRDIRERR\r
+\r
+ EXTRN EPRINT:NEAR,DOCRLF:NEAR,PRINT:NEAR\r
+ EXTRN PROMPTYN:NEAR,DOINT26:NEAR,SUBERRP:NEAR\r
+ EXTRN DOTCOMBMES:NEAR,DISP16BITS:NEAR\r
+ EXTRN CHAINREPORT:NEAR,DISPCLUS:NEAR\r
+ EXTRN PRTCHR:NEAR,WDSKERR:NEAR,CHECKFILES:NEAR\r
+ EXTRN FCB_TO_ASCZ:NEAR,FIGREC:NEAR,RDSKERR:NEAR\r
+\r
+CHKPROC:\r
+\r
+SUBTTL DIRPROC -- Recursive directory processing\r
+\r
+; YOU ARE ADVISED NOT TO COPY THE FOLLOWING METHOD!!!\r
+\r
+DOTDOTHARDWAY:\r
+ LDS DI,[THISDPB]\r
+ASSUME DS:NOTHING\r
+ MOV [DI.dpb_current_dir],-1 ;Invalidate path\r
+ MOV SI,DI\r
+ ADD SI,dpb_dir_text\r
+ MOV CX,SI\r
+FINDEND:\r
+ LODSB ;Scan to end of current path\r
+ OR AL,AL\r
+ JNZ FINDEND\r
+ DEC SI ;Point at the NUL\r
+DELLOOP: ;Delete last element\r
+ CMP SI,CX\r
+ JZ SETROOT\r
+ CMP BYTE PTR [SI],"/"\r
+ JZ SETTERM\r
+ CMP BYTE PTR [SI],"\"\r
+ JZ SETTERM\r
+ DEC SI\r
+ JMP SHORT DELLOOP\r
+\r
+SETTERM:\r
+ MOV BYTE PTR [SI],0\r
+SETCURR:\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:DG\r
+ MOV DX,OFFSET DG:DOTMES\r
+ MOV AH,CHDIR ;Chdir to altered path\r
+ INT 21H\r
+ RET\r
+\r
+SETROOT:\r
+ASSUME DS:NOTHING\r
+ MOV [DI.dpb_current_dir],0 ;Set Path to Root\r
+ JMP SHORT SETCURR ;The CHDIR will fail, but who cares\r
+\r
+\r
+;Structures used by DIRPROC\r
+\r
+SRCHFCB STRUC\r
+ DB 44 DUP (?)\r
+SRCHFCB ENDS\r
+SFCBSIZ EQU SIZE SRCHFCB\r
+THISENT EQU 17H ;Relative entry number of current entry\r
+\r
+DIRENT STRUC\r
+ DB 7 DUP (?) ;Ext FCB junk\r
+ DB ? ;Drive\r
+DIRNAM DB 11 DUP (?)\r
+DIRATT DB ?\r
+ DB 10 DUP (?)\r
+DIRTIM DW ?\r
+DIRDAT DW ?\r
+DIRCLUS DW ?\r
+DIRESIZ DD ?\r
+DIRENT ENDS\r
+ENTSIZ EQU SIZE DIRENT\r
+\r
+;Attribute bits\r
+\r
+RDONLY EQU 1\r
+HIDDN EQU 2\r
+SYSTM EQU 4\r
+VOLIDA EQU 8\r
+ISDIR EQU 10H\r
+\r
+ASSUME DS:DG\r
+\r
+NODOT: ;No .\r
+ PUSH AX ;Return from SRCH\r
+ CMP [NOISY],0\r
+ JNZ DOEXTMES1\r
+ CALL SUBERRP\r
+ JMP SHORT MESD1\r
+DOEXTMES1:\r
+ MOV SI,OFFSET DG:DOTMES\r
+ CALL PRINTCURRDIRERR\r
+ MOV DX,OFFSET DG:NDOTMES\r
+ CALL EPRINT\r
+MESD1:\r
+ XOR AX,AX\r
+ PUSH BX\r
+ PUSH BP\r
+ CALL GETENT\r
+ POP BP\r
+ PUSH BP\r
+ CMP BYTE PTR [DI],0E5H ;Have place to put .?\r
+ JNZ CANTREC ;Nope\r
+ MOV SI,OFFSET DG:DOTENT\r
+ MOV CX,11\r
+ REP MOVSB ;Name\r
+ PUSH AX\r
+ MOV AL,ISDIR\r
+ STOSB ;Attribute\r
+ ADD DI,10\r
+ XOR AX,AX\r
+ STOSW ;Date = 0\r
+ STOSW ;Time = 0\r
+ MOV AX,[BP+6]\r
+ STOSW ;Alloc #\r
+ XOR AX,AX\r
+ STOSW\r
+ STOSW ;Size\r
+ POP AX\r
+ MOV [HAVFIX],1 ;Have a fix\r
+ CMP [DOFIX],0\r
+ JZ DOTGOON ;No fix if not F\r
+ MOV CX,1\r
+ CALL DOINT26\r
+ JMP SHORT DOTGOON\r
+\r
+CANTREC:\r
+ INC [DOTSNOGOOD]\r
+ CMP [NOISY],0\r
+ JZ DOTGOON\r
+ MOV DX,OFFSET DG:NORECDOT\r
+ CALL EPRINT\r
+DOTGOON:\r
+ POP BP\r
+ POP BX\r
+ POP AX\r
+ MOV SI,OFFSET DG:DIRBUF\r
+ JMP CHKDOTDOT ;Go look for ..\r
+\r
+NODDOT: ;No ..\r
+ PUSH AX ;Return from SRCH\r
+ CMP [NOISY],0\r
+ JNZ DOEXTMES2\r
+ CALL SUBERRP\r
+ JMP SHORT MESD2\r
+DOEXTMES2:\r
+ MOV SI,OFFSET DG:PARSTR\r
+ CALL PRINTCURRDIRERR\r
+ MOV DX,OFFSET DG:NDOTMES\r
+ CALL EPRINT\r
+MESD2:\r
+ MOV AX,1\r
+ PUSH BX\r
+ PUSH BP\r
+ CALL GETENT\r
+ POP BP\r
+ PUSH BP\r
+ CMP BYTE PTR [DI],0E5H ;Place to put it?\r
+ JNZ CANTREC2 ;Nope\r
+ MOV SI,OFFSET DG:DDOTENT\r
+ MOV CX,11\r
+ REP MOVSB ;Name\r
+ PUSH AX\r
+ MOV AL,ISDIR\r
+ STOSB ;Attribute\r
+ ADD DI,10\r
+ XOR AX,AX\r
+ STOSW ;Date\r
+ STOSW ;Time\r
+ MOV AX,[BP+4]\r
+ STOSW ;Alloc #\r
+ XOR AX,AX\r
+ STOSW\r
+ STOSW ;Size\r
+ POP AX\r
+ MOV [HAVFIX],1 ;Got a fix\r
+ CMP [DOFIX],0\r
+ JZ NFIX ;No fix if no F, carry clear\r
+ MOV CX,1\r
+ CALL DOINT26\r
+NFIX:\r
+ POP BP\r
+ POP BX\r
+ POP AX\r
+ MOV SI,OFFSET DG:DIRBUF\r
+ JMP ROOTDIR ;Process files\r
+\r
+CANTREC2:\r
+ POP BP\r
+ POP BX\r
+ POP AX\r
+ CMP [NOISY],0\r
+ JZ DOTSBAD\r
+ MOV DX,OFFSET DG:NORECDDOT\r
+ CALL EPRINT\r
+ JMP DOTSBAD\r
+\r
+NULLDIRERR:\r
+ CMP [NOISY],0\r
+ JNZ DOEXTMES3\r
+ CALL SUBERRP\r
+ JMP SHORT DOTSBAD\r
+DOEXTMES3:\r
+ MOV SI,OFFSET DG:NUL\r
+ CALL PRINTCURRDIRERR\r
+ MOV DX,OFFSET DG:NULDMES\r
+ CALL EPRINT\r
+DOTSBAD: ;Can't recover\r
+ MOV DX,OFFSET DG:BADTARG2\r
+ CALL EPRINT\r
+ CALL DOTDOTHARDWAY\r
+ INC [DOTSNOGOOD]\r
+ JMP DIRDONE ;Terminate tree walk at this level\r
+\r
+ROOTDIRJ: JMP ROOTDIR\r
+\r
+PAGE\r
+DIRPROC:\r
+;Recursive tree walker\r
+;dirproc(self,parent)\r
+ MOV [DOTSNOGOOD],0 ;Init to dots OK\r
+ MOV [ERRSUB],0 ;No subdir errors yet\r
+ PUSH BP ;Save frame pointer\r
+ MOV BP,SP\r
+ SUB SP,SFCBSIZ ;Only local var\r
+ CMP SP,[STACKLIM]\r
+ JA STACKISOK\r
+ MOV BX,OFFSET DG:STACKMES ;Out of stack\r
+ JMP FATAL\r
+STACKISOK:\r
+ CMP [NOISY],0\r
+ JZ NOPRINT\r
+ CMP [SECONDPASS],0\r
+ JNZ NOPRINT ;Don't do it again on second pass\r
+ MOV DX,OFFSET DG:DIRECMES ;Tell user where we are\r
+ CALL PRINT\r
+ MOV SI,OFFSET DG:NUL\r
+ CALL PRINTCURRDIR\r
+ CALL DOCRLF\r
+NOPRINT:\r
+ MOV SI,OFFSET DG:ALLFILE\r
+ MOV DI,SP\r
+ PUSH DI\r
+ MOV CX,SFCBSIZ\r
+ REP MOVSB ;Initialize search FCB\r
+ POP DX\r
+ MOV BX,DX ;BX points to SRCH FCB\r
+ MOV AH,DIR_SEARCH_FIRST\r
+ INT 21H\r
+ CMP WORD PTR [BP+6],0 ;Am I the root\r
+ JZ ROOTDIRJ ;Yes, no . or ..\r
+ OR AL,AL\r
+ JZ NONULLDERR\r
+ JMP NULLDIRERR ;Dir is empty!\r
+NONULLDERR:\r
+ MOV SI,OFFSET DG:DIRBUF + DIRNAM\r
+ MOV DI,OFFSET DG:DOTENT\r
+ MOV CX,11\r
+ REP CMPSB\r
+ JZ DOTOK ;Got a . as first entry\r
+ JMP NODOT ;No .\r
+DOTOK:\r
+ MOV SI,OFFSET DG:DIRBUF\r
+ MOV AL,[SI.DIRATT]\r
+ TEST AL,ISDIR\r
+ JNZ DATTOK\r
+ PUSH SI ;. not a dir?\r
+ MOV SI,OFFSET DG:DOTMES\r
+ MOV DX,OFFSET DG:BADATT\r
+ CALL DOTCOMBMES\r
+ POP SI\r
+ OR [SI.DIRATT],ISDIR\r
+ CALL FIXENT ;Fix it\r
+DATTOK:\r
+ MOV AX,[SI.DIRCLUS]\r
+ CMP AX,[BP+6] ;. link = MYSELF?\r
+ JZ DLINKOK\r
+ PUSH SI ;Link messed up\r
+ MOV SI,OFFSET DG:DOTMES\r
+ MOV DX,OFFSET DG:CLUSBAD\r
+ CALL DOTCOMBMES\r
+ POP SI\r
+ MOV AX,[BP+6]\r
+ MOV [SI.DIRCLUS],AX\r
+ CALL FIXENT ;Fix it\r
+DLINKOK:\r
+ MOV AX,WORD PTR [SI.DIRESIZ]\r
+ OR AX,AX\r
+ JNZ BADDSIZ\r
+ MOV AX,WORD PTR [SI.DIRESIZ+2]\r
+ OR AX,AX\r
+ JZ DSIZOK\r
+BADDSIZ: ;Size should be zero\r
+ PUSH SI\r
+ MOV SI,OFFSET DG:DOTMES\r
+ MOV DX,OFFSET DG:BADSIZM\r
+ CALL DOTCOMBMES\r
+ POP SI\r
+ XOR AX,AX\r
+ MOV WORD PTR [SI.DIRESIZ],AX\r
+ MOV WORD PTR [SI.DIRESIZ+2],AX\r
+ CALL FIXENT ;Fix it\r
+DSIZOK: ;Get next (should be ..)\r
+ MOV DX,BX\r
+ MOV AH,DIR_SEARCH_NEXT\r
+ INT 21H\r
+CHKDOTDOT: ;Come here after . failure\r
+ OR AL,AL\r
+ JZ DOTDOTOK\r
+NODDOTJ: JMP NODDOT ;No ..\r
+DOTDOTOK:\r
+ MOV SI,OFFSET DG:DIRBUF + DIRNAM\r
+ MOV DI,OFFSET DG:DDOTENT\r
+ MOV CX,11\r
+ REP CMPSB\r
+ JNZ NODDOTJ ;No ..\r
+ MOV SI,OFFSET DG:DIRBUF\r
+ MOV AL,[SI.DIRATT]\r
+ TEST AL,ISDIR\r
+ JNZ DDATTOK ;.. must be a dir\r
+ PUSH SI\r
+ MOV SI,OFFSET DG:PARSTR\r
+ MOV DX,OFFSET DG:BADATT\r
+ CALL DOTCOMBMES\r
+ POP SI\r
+ OR [SI.DIRATT],ISDIR\r
+ CALL FIXENT ;Fix it\r
+DDATTOK:\r
+ PUSH SI\r
+ MOV AX,[SI.DIRCLUS]\r
+ CMP AX,[BP+4] ;.. link must be PARENT\r
+ JZ DDLINKOK\r
+ MOV SI,OFFSET DG:PARSTR\r
+ MOV DX,OFFSET DG:CLUSBAD\r
+ CALL DOTCOMBMES\r
+ POP SI\r
+ MOV AX,[BP+4]\r
+ MOV [SI.DIRCLUS],AX\r
+ CALL FIXENT ;Fix it\r
+DDLINKOK:\r
+ MOV AX,WORD PTR [SI.DIRESIZ]\r
+ OR AX,AX\r
+ JNZ BADDDSIZ\r
+ MOV AX,WORD PTR [SI.DIRESIZ+2]\r
+ OR AX,AX\r
+ JZ DDSIZOK\r
+BADDDSIZ: ;.. size should be 0\r
+ PUSH SI\r
+ MOV SI,OFFSET DG:PARSTR\r
+ MOV DX,OFFSET DG:BADSIZM\r
+ CALL DOTCOMBMES\r
+ POP SI\r
+ XOR AX,AX\r
+ MOV WORD PTR [SI.DIRESIZ],AX\r
+ MOV WORD PTR [SI.DIRESIZ+2],AX\r
+ CALL FIXENT ;Fix it\r
+DDSIZOK:\r
+ MOV DX,BX ;Next entry\r
+ MOV AH,DIR_SEARCH_NEXT\r
+ INT 21H\r
+\r
+ROOTDIR: ;Come here after .. failure also\r
+ OR AL,AL\r
+ JZ MOREDIR ;More to go\r
+ CMP WORD PTR [BP+6],0 ;Am I the root?\r
+ JZ DIRDONE ;Yes, no chdir\r
+ MOV DX,OFFSET DG:PARSTR\r
+ MOV AH,CHDIR ;Chdir to parent (..)\r
+ INT 21H\r
+ JNC DIRDONE ;Worked\r
+ CMP [NOISY],0\r
+ JZ DODDH\r
+ MOV SI,OFFSET DG:NUL\r
+ CALL PRINTCURRDIRERR\r
+ MOV DX,OFFSET DG:CDDDMES\r
+ CALL EPRINT\r
+DODDH:\r
+ CALL DOTDOTHARDWAY ;Try again\r
+DIRDONE:\r
+ MOV SP,BP ;Pop local vars\r
+ POP BP ;Restore frame\r
+ RET 4 ;Pop args\r
+\r
+MOREDIR:\r
+ MOV SI,OFFSET DG:DIRBUF\r
+ TEST [SI.DIRATT],ISDIR\r
+ JNZ NEWDIR ;Is a new directory\r
+ CMP [SECONDPASS],0\r
+ JZ FPROC1 ;First pass\r
+ CALL CROSSLOOK ;Check for cross links\r
+ JMP DDSIZOK ;Next\r
+FPROC1:\r
+ CMP [NOISY],0\r
+ JZ NOPRINT2\r
+ MOV DX,OFFSET DG:INDENT ;Tell user where we are\r
+ CALL PRINT\r
+ PUSH BX\r
+ MOV BX,SI\r
+ CALL PRINTTHISEL\r
+ CALL DOCRLF\r
+ MOV SI,BX\r
+ POP BX\r
+NOPRINT2:\r
+ MOV AL,81H ;Head of file\r
+ CALL MARKFAT\r
+ TEST [SI.DIRATT],VOLIDA\r
+ JNZ HIDENFILE ;VOL ID counts as hidden\r
+ TEST [SI.DIRATT],HIDDN\r
+ JZ NORMFILE\r
+HIDENFILE:\r
+ INC [HIDCNT]\r
+ ADD [HIDSIZ],CX\r
+ JMP DDSIZOK ;Next\r
+NORMFILE:\r
+ INC [FILCNT]\r
+ ADD [FILSIZ],CX\r
+ JMP DDSIZOK ;Next\r
+\r
+NEWDIR:\r
+ CMP [SECONDPASS],0\r
+ JZ DPROC1\r
+ CALL CROSSLOOK ;Check for cross links\r
+ JMP SHORT DPROC2\r
+DPROC1:\r
+ MOV AL,82H ;Head of dir\r
+ CALL MARKFAT\r
+ INC [DIRCNT]\r
+ ADD [DIRSIZ],CX\r
+ CMP [ZEROTRUNC],0\r
+ JZ DPROC2 ;Dir not truncated\r
+CONVDIR:\r
+ AND [SI.DIRATT],NOT ISDIR ;Turn into file\r
+ CALL FIXENT\r
+ JMP DDSIZOK ;Next\r
+DPROC2:\r
+ PUSH [ERRSUB]\r
+ PUSH BX ;Save my srch FCB pointer\r
+ PUSH [SI.DIRCLUS] ;MYSELF for next directory\r
+ PUSH [BP+6] ;His PARENT is me\r
+ ADD SI,DIRNAM\r
+ MOV DI,OFFSET DG:NAMBUF\r
+ PUSH DI\r
+ CALL FCB_TO_ASCZ\r
+ POP DX\r
+ MOV AH,CHDIR ;CHDIR to new dir\r
+ INT 21H\r
+ JC CANTTARG ;Barfed\r
+ CALL DIRPROC\r
+ POP BX ;Get my SRCH FCB pointer back\r
+ POP [ERRSUB]\r
+ CMP [DOTSNOGOOD],0\r
+ JNZ ASKCONV\r
+ JMP DDSIZOK ;Next\r
+\r
+CANTTARG:\r
+ POP AX ;Clean stack\r
+ POP AX\r
+ POP AX\r
+ POP AX\r
+ PUSH DX ;Save pointer to bad DIR\r
+ MOV DX,OFFSET DG:BADTARG1\r
+ CALL EPRINT\r
+ POP SI ;Pointer to bad DIR\r
+ CALL PRINTCURRDIRERR\r
+ MOV DX,OFFSET DG:BADTARG2\r
+ CALL EPRINT\r
+DDSIZOKJ: JMP DDSIZOK ;Next\r
+\r
+ASKCONV:\r
+ CMP [SECONDPASS],0\r
+ JNZ DDSIZOKJ ;Leave on second pass\r
+ MOV DX,OFFSET DG:PTRANDIR\r
+ CMP [NOISY],0\r
+ JNZ PRINTTRMES\r
+ MOV DX,OFFSET DG:PTRANDIR2\r
+PRINTTRMES:\r
+ CALL PROMPTYN ;Ask user what to do\r
+ JNZ DDSIZOKJ ;User say leave alone\r
+ PUSH BP\r
+ PUSH BX\r
+ MOV AX,[BX+THISENT] ;Entry number\r
+ CALL GETENT ;Get the entry\r
+ MOV SI,DI\r
+ MOV DI,OFFSET DG:DIRBUF\r
+ PUSH DI\r
+ ADD DI,DIRNAM\r
+ MOV CX,32\r
+ REP MOVSB ;Transfer entry to DIRBUF\r
+ POP SI\r
+ PUSH SI\r
+ MOV SI,[SI.DIRCLUS] ;First cluster\r
+ CALL GETFILSIZ\r
+ POP SI\r
+ POP BX\r
+ POP BP\r
+ MOV WORD PTR [SI.DIRESIZ],AX ;Fix entry\r
+ MOV WORD PTR [SI.DIRESIZ+2],DX\r
+ JMP CONVDIR\r
+\r
+SUBTTL FAT Look routines\r
+PAGE\r
+CROSSLOOK:\r
+;Same as MRKFAT only simpler for pass 2\r
+ MOV [SRFCBPT],BX\r
+ MOV BX,SI\r
+ MOV SI,[BX.DIRCLUS]\r
+ CALL CROSSCHK\r
+ JNZ CROSSLINKJ\r
+CHLP:\r
+ PUSH BX\r
+ CALL UNPACK\r
+ POP BX\r
+ XCHG SI,DI\r
+ CMP SI,0FF8H\r
+ JAE CHAINDONEJ\r
+ CALL CROSSCHK\r
+ JZ CHLP\r
+CROSSLINKJ: JMP SHORT CROSSLINK\r
+\r
+CROSSCHK:\r
+ MOV DI,[FATMAP]\r
+ ADD DI,SI\r
+ MOV AH,[DI]\r
+ TEST AH,10H\r
+ RET\r
+\r
+NOCLUSTERSJ: JMP NOCLUSTERS\r
+\r
+MARKFAT:\r
+; Map the file and perform checks\r
+; SI points to dir entry\r
+; AL is head mark with app type\r
+; On return CX is number of clusters\r
+; BX,SI preserved\r
+; ZEROTRUNC is non zero if the file was trimmed to zero length\r
+; ISCROSS is non zero if the file is cross linked\r
+\r
+ MOV [ZEROTRUNC],0 ;Initialize\r
+ MOV [ISCROSS],0\r
+ MOV [SRFCBPT],BX\r
+ MOV BX,SI\r
+ XOR CX,CX\r
+ MOV SI,[BX.DIRCLUS]\r
+ CMP SI,2\r
+ JB NOCLUSTERSJ ;Bad cluster # or nul file (SI = 0)\r
+ CMP SI,[MCLUS]\r
+ JA NOCLUSTERSJ ;Bad cluster #\r
+ PUSH BX\r
+ CALL UNPACK\r
+ POP BX\r
+ JZ NOCLUSTERSJ ;Bad cluster (it is marked free)\r
+ CALL MARKMAP\r
+ JNZ CROSSLINK\r
+ AND AL,7FH ;Turn off head bit\r
+CHASELOOP:\r
+ PUSH BX\r
+ CALL UNPACK\r
+ POP BX\r
+ INC CX\r
+ XCHG SI,DI\r
+ CMP SI,0FF8H\r
+ JAE CHAINDONE\r
+ CMP SI,2\r
+ JB MRKBAD\r
+ CMP SI,[MCLUS]\r
+ JBE MRKOK\r
+MRKBAD: ;Bad cluster # in chain\r
+ PUSH CX\r
+ PUSH DI\r
+ CALL PRINTTHISELERR\r
+ MOV DX,OFFSET DG:BADCHAIN\r
+ CALL EPRINT\r
+ POP SI\r
+ MOV DX,0FFFH ;Insert EOF\r
+ PUSH BX\r
+ CALL PACK\r
+ POP BX\r
+ POP CX\r
+CHAINDONEJ: JMP SHORT CHAINDONE\r
+\r
+MRKOK:\r
+ CALL MARKMAP\r
+ JZ CHASELOOP\r
+CROSSLINK: ;File is cross linked\r
+ INC [ISCROSS]\r
+ CMP [SECONDPASS],0\r
+ JZ CHAINDONE ;Crosslinks only on second pass\r
+ PUSH SI ;Cluster number\r
+ CALL PRINTTHISEL\r
+ CALL DOCRLF\r
+ MOV DX,OFFSET DG:CROSSMES_PRE\r
+ CALL PRINT\r
+ POP SI\r
+ PUSH BX\r
+ PUSH CX\r
+ MOV BX,OFFSET DG:CROSSMES_POST\r
+ XOR DI,DI\r
+ CALL DISP16BITS\r
+ POP CX\r
+ POP BX\r
+CHAINDONE:\r
+ TEST [BX.DIRATT],ISDIR\r
+ JNZ NOSIZE ;Don't size dirs\r
+ CMP [ISCROSS],0\r
+ JNZ NOSIZE ;Don't size cross linked files\r
+ CMP [SECONDPASS],0\r
+ JNZ NOSIZE ;Don't size on pass 2 (CX garbage)\r
+ MOV AL,[CSIZE]\r
+ XOR AH,AH\r
+ MUL [SSIZE]\r
+ PUSH AX ;Size in bytes of one alloc unit\r
+ MUL CX\r
+ MOV DI,DX ;Save allocation size\r
+ MOV SI,AX\r
+ SUB AX,WORD PTR [BX.DIRESIZ]\r
+ SBB DX,WORD PTR [BX.DIRESIZ+2]\r
+ JC BADFSIZ ;Size to big\r
+ OR DX,DX\r
+ JNZ BADFSIZ ;Size to small\r
+ POP DX\r
+ CMP AX,DX\r
+ JB NOSIZE ;Size within one Alloc unit\r
+ PUSH DX ;Size to small\r
+BADFSIZ:\r
+ POP DX\r
+ PUSH CX ;Save size of file\r
+ MOV WORD PTR [BX.DIRESIZ],SI\r
+ MOV WORD PTR [BX.DIRESIZ+2],DI\r
+ CALL FIXENT2 ;Fix it\r
+ CALL PRINTTHISELERR\r
+ MOV DX,OFFSET DG:BADCLUS\r
+ CALL EPRINT\r
+ POP CX ;Restore size of file\r
+NOSIZE:\r
+ MOV SI,BX\r
+ MOV BX,[SRFCBPT]\r
+ RET\r
+\r
+NOCLUSTERS:\r
+;File is zero length\r
+ OR SI,SI\r
+ JZ CHKSIZ ;Firclus is OK, Check size\r
+ MOV DX,OFFSET DG:NULNZ\r
+ADJUST:\r
+ PUSH DX\r
+ CALL PRINTTHISELERR\r
+ POP DX\r
+ CALL EPRINT\r
+ XOR SI,SI\r
+ MOV [BX.DIRCLUS],SI ;Set it to 0\r
+ MOV WORD PTR [BX.DIRESIZ],SI ;Set size too\r
+ MOV WORD PTR [BX.DIRESIZ+2],SI\r
+ CALL FIXENT2 ;Fix it\r
+ INC [ZEROTRUNC] ;Indicate truncation\r
+ JMP CHAINDONE\r
+\r
+CHKSIZ:\r
+ MOV DX,OFFSET DG:BADCLUS\r
+ CMP WORD PTR [BX.DIRESIZ],0\r
+ JNZ ADJUST ;Size wrong\r
+ CMP WORD PTR [BX.DIRESIZ+2],0\r
+ JNZ ADJUST ;Size wrong\r
+ JMP CHAINDONE ;Size OK\r
+\r
+UNPACK:\r
+;Cluster number in SI, Return contents in DI, BX destroyed\r
+;ZERO SET IF CLUSTER IS FREE\r
+ MOV BX,OFFSET DG:FAT\r
+ MOV DI,SI\r
+ SHR DI,1\r
+ ADD DI,SI\r
+ MOV DI,WORD PTR [DI+BX]\r
+ TEST SI,1\r
+ JZ HAVCLUS\r
+ SHR DI,1\r
+ SHR DI,1\r
+ SHR DI,1\r
+ SHR DI,1\r
+HAVCLUS:\r
+ AND DI,0FFFH\r
+ RET\r
+\r
+PACK:\r
+; SI CLUSTER NUMBER TO BE PACKED\r
+; DX DATA TO BE PLACED IN CLUSTER (SI)\r
+; BX,DX DESTROYED\r
+ MOV [DIRTYFAT],1 ;Set FAT dirty byte\r
+ MOV [HAVFIX],1 ;Indicate a fix\r
+ MOV BX,OFFSET DG:FAT\r
+ PUSH SI\r
+ MOV DI,SI\r
+ SHR SI,1\r
+ ADD SI,BX\r
+ ADD SI,DI\r
+ SHR DI,1\r
+ MOV DI,[SI]\r
+ JNC ALIGNED\r
+ SHL DX,1\r
+ SHL DX,1\r
+ SHL DX,1\r
+ SHL DX,1\r
+ AND DI,0FH\r
+ JMP SHORT PACKIN\r
+ALIGNED:\r
+ AND DI,0F000H\r
+PACKIN:\r
+ OR DI,DX\r
+ MOV [SI],DI\r
+ POP SI\r
+ RET\r
+\r
+\r
+\r
+MARKMAP:\r
+; Mark in AL\r
+; Cluster in SI\r
+; AL,SI,CX preserved\r
+; ZERO RESET IF CROSSLINK, AH IS THE MARK THAT WAS THERE\r
+ MOV DI,[FATMAP]\r
+ ADD DI,SI\r
+ MOV AH,[DI]\r
+ OR AH,AH\r
+ PUSH AX\r
+ JZ SETMARK\r
+ MOV AL,AH\r
+ INC [CROSSCNT] ;Count the crosslink\r
+ OR AL,10H ;Resets zero\r
+SETMARK:\r
+ MOV [DI],AL\r
+ POP AX\r
+ RET\r
+\r
+\r
+CHKMAP:\r
+;Compare FAT and FATMAP looking for badsectors orphans\r
+ MOV SI,[FATMAP]\r
+ INC SI\r
+ INC SI\r
+ MOV DX,2\r
+ MOV CX,[DSIZE]\r
+CHKMAPLP:\r
+ LODSB\r
+ OR AL,AL\r
+ JNZ CONTLP ;Already seen this one\r
+ XCHG SI,DX\r
+ CALL UNPACK\r
+ XCHG SI,DX\r
+ JZ CONTLP ;Free cluster\r
+ CMP DI,0FF7H ;Bad sector?\r
+ JNZ ORPHAN ;No, found an orphan\r
+ INC [BADSIZ]\r
+ MOV BYTE PTR [SI-1],4 ;Flag it\r
+ JMP CONTLP\r
+ORPHAN:\r
+ INC [ORPHSIZ]\r
+ MOV BYTE PTR [SI-1],8 ;Flag it\r
+CONTLP:\r
+ INC DX ;Next cluster\r
+ LOOP CHKMAPLP\r
+ MOV SI,[ORPHSIZ]\r
+ OR SI,SI\r
+ JZ RET18 ;No orphans\r
+ CALL RECOVER\r
+RET18: RET\r
+\r
+RECOVER:\r
+;free orphans or do chain recovery\r
+ CALL CHECKNOFMES\r
+ CALL DOCRLF\r
+ CALL CHAINREPORT\r
+ MOV DX,OFFSET DG:FREEMES\r
+ CALL PROMPTYN ;Ask user\r
+ JNZ NOCHAINREC\r
+ JMP CHAINREC\r
+NOCHAINREC:\r
+ MOV SI,[FATMAP] ;Free all orphans\r
+ INC SI\r
+ INC SI\r
+ MOV DX,2\r
+ MOV CX,[DSIZE]\r
+CHKMAPLP2:\r
+ LODSB\r
+ TEST AL,8\r
+ JZ NEXTCLUS\r
+ XCHG SI,DX\r
+ PUSH DX\r
+ XOR DX,DX\r
+ CALL PACK ;Mark as free\r
+ POP DX\r
+ XCHG SI,DX\r
+NEXTCLUS:\r
+ INC DX\r
+ LOOP CHKMAPLP2\r
+ XOR AX,AX\r
+ XCHG AX,[ORPHSIZ]\r
+ PUSH AX\r
+ MOV DX,OFFSET DG:FREEBYMESF_PRE\r
+ CMP [DOFIX],0\r
+ JNZ PRINTFMES\r
+ MOV DX,OFFSET DG:FREEBYMES_PRE\r
+PRINTFMES:\r
+ CALL PRINT\r
+ POP AX\r
+ MOV BX,OFFSET DG:FREEBYMESF_POST\r
+ CMP [DOFIX],0\r
+ JNZ DISPFRB\r
+ MOV BX,OFFSET DG:FREEBYMES_POST\r
+ MOV [LCLUS],AX\r
+DISPFRB:\r
+ CALL DISPCLUS ;Tell how much freed\r
+ RET\r
+\r
+FINDCHAIN:\r
+;Do chain recovery on orphans\r
+ MOV SI,[FATMAP]\r
+ INC SI\r
+ INC SI\r
+ MOV DX,2\r
+ MOV CX,[DSIZE]\r
+CHKMAPLP3:\r
+ LODSB\r
+ TEST AL,8 ;Orphan?\r
+ JZ NEXTCLUS2 ;Nope\r
+ TEST AL,1 ;Seen before ?\r
+ JNZ NEXTCLUS2 ;Yup\r
+ PUSH SI ;Save search environment\r
+ PUSH CX\r
+ PUSH DX\r
+ DEC SI\r
+ OR BYTE PTR [SI],81H ;Mark as seen and head\r
+ INC [ORPHCNT] ;Found a chain\r
+ MOV SI,DX\r
+CHAINLP:\r
+ CALL UNPACK\r
+ XCHG SI,DI\r
+ CMP SI,0FF8H\r
+ JAE CHGOON ;EOF\r
+ PUSH DI\r
+ CMP SI,2\r
+ JB INSERTEOF ;Bad cluster number\r
+ CMP SI,[MCLUS]\r
+ JA INSERTEOF ;Bad cluster number\r
+ CMP SI,DI\r
+ JZ INSERTEOF ;Tight loop\r
+ CALL CROSSCHK\r
+ TEST AH,8 ;Points to a non-orphan?\r
+ JNZ CHKCHHEAD ;Nope\r
+INSERTEOF:\r
+ POP SI ;Need to stick EOF here\r
+ MOV DX,0FFFH\r
+ CALL PACK\r
+ JMP SHORT CHGOON\r
+CHKCHHEAD:\r
+ TEST AH,80H ;Previosly marked head?\r
+ JZ ADDCHAIN ;Nope\r
+ AND BYTE PTR [DI],NOT 80H ;Turn off head bit\r
+ DEC [ORPHCNT] ;Wasn't really a head\r
+ POP DI ;Clean stack\r
+ JMP SHORT CHGOON\r
+ADDCHAIN:\r
+ TEST AH,1 ;Previosly seen?\r
+ JNZ INSERTEOF ;Yup, don't make a cross link\r
+ OR BYTE PTR [DI],1 ;Mark as seen\r
+ POP DI ;Clean stack\r
+ JMP CHAINLP ;Follow chain\r
+\r
+CHGOON:\r
+ POP DX ;Restore search\r
+ POP CX\r
+ POP SI\r
+NEXTCLUS2:\r
+ INC DX\r
+ LOOP CHKMAPLP3\r
+ RET\r
+\r
+CHAINREC:\r
+ LDS DI,[THISDPB]\r
+ASSUME DS:NOTHING\r
+ MOV CX,[DI.dpb_root_entries]\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:DG\r
+ MOV SI,[FATMAP]\r
+ INC SI\r
+ INC SI\r
+ MOV DI,1\r
+ CALL NEXTORPH\r
+ PUSH SI\r
+ PUSH DI\r
+ MOV SI,DI\r
+ XOR AX,AX\r
+ MOV DX,[ORPHCNT]\r
+MAKFILLP:\r
+ PUSH AX\r
+ PUSH CX\r
+ PUSH DX\r
+ PUSH SI\r
+ CALL GETENT\r
+ POP SI\r
+ CMP BYTE PTR [DI],0E5H\r
+ JZ GOTENT\r
+ CMP BYTE PTR [DI],0\r
+ JNZ NEXTENT\r
+GOTENT:\r
+ MOV [HAVFIX],1 ;Making a fix\r
+ CMP [DOFIX],0\r
+ JZ ENTMADE ;Not supposed to, carry clear\r
+ MOV [DI+26],SI ;FIRCLUS Pointer\r
+ PUSH AX ;Save INT 26 data\r
+ PUSH DX\r
+ PUSH BX\r
+ MOV AH,DISK_RESET ;Force current state\r
+ INT 21H\r
+ MOV DX,OFFSET DG:ORPHFCB\r
+ MOV AH,FCB_OPEN\r
+OPAGAIN:\r
+ INT 21H\r
+ OR AL,AL\r
+ JNZ GOTORPHNAM\r
+ CALL MAKORPHNAM ;Try next name\r
+ JMP SHORT OPAGAIN\r
+\r
+GOTORPHNAM:\r
+ MOV SI,OFFSET DG:ORPHFCB + 1 ;ORPHFCB Now has good name\r
+ MOV CX,11\r
+ REP MOVSB\r
+ CALL MAKORPHNAM ;Make next name\r
+ XOR AX,AX\r
+ MOV CX,15\r
+ REP STOSB\r
+ MOV SI,[DI]\r
+ INC DI ;Skip FIRCLUS\r
+ INC DI\r
+ PUSH DI\r
+ CALL GETFILSIZ\r
+ POP DI\r
+ STOSW\r
+ MOV AX,DX\r
+ STOSW\r
+ POP BX\r
+ POP DX\r
+ POP AX\r
+ MOV CX,1\r
+ CALL DOINT26\r
+ENTMADE:\r
+ POP DX\r
+ POP CX\r
+ POP AX\r
+ POP DI\r
+ POP SI\r
+ DEC DX\r
+ OR DX,DX\r
+ JZ RET100\r
+ CALL NEXTORPH\r
+ PUSH SI\r
+ PUSH DI\r
+ MOV SI,DI\r
+ JMP SHORT NXTORP\r
+\r
+NEXTENT:\r
+ POP DX\r
+ POP CX\r
+ POP AX\r
+NXTORP:\r
+ INC AX\r
+ LOOP MAKFILLPJ\r
+ POP AX ;Clean Stack\r
+ POP AX\r
+ SUB [ORPHCNT],DX ;Couldn't make them all\r
+ MOV DX,OFFSET DG:CREATMES\r
+ CALL EPRINT\r
+RET100: RET\r
+\r
+MAKFILLPJ: JMP MAKFILLP\r
+\r
+NEXTORPH:\r
+ PUSH AX\r
+ LODSB\r
+ INC DI\r
+ CMP AL,89H\r
+ POP AX\r
+ JZ RET100\r
+ JMP SHORT NEXTORPH\r
+\r
+MAKORPHNAM:\r
+ PUSH SI\r
+ MOV SI,OFFSET DG:ORPHEXT - 1\r
+NAM0:\r
+ INC BYTE PTR [SI]\r
+ CMP BYTE PTR [SI],'9'\r
+ JLE NAMMADE\r
+ MOV BYTE PTR [SI],'0'\r
+ DEC SI\r
+ JMP NAM0\r
+\r
+NAMMADE:\r
+ POP SI\r
+ RET\r
+\r
+GETFILSIZ:\r
+;SI is start cluster, returns filesize as DX:AX\r
+ XOR AX,AX\r
+NCLUS:\r
+ CALL UNPACK\r
+ XCHG SI,DI\r
+ INC AX\r
+ CMP SI,0FF8H\r
+ JAE GOTEOF\r
+ CMP SI,2\r
+ JAE NCLUS\r
+GOTEOF:\r
+ MOV BL,[CSIZE]\r
+ XOR BH,BH\r
+ MUL BX\r
+ MUL [SSIZE]\r
+ RET\r
+\r
+\r
+\r
+CHKCROSS:\r
+;Check for Crosslinks, do second pass if any to find pairs\r
+ MOV SI,[CROSSCNT]\r
+ OR SI,SI\r
+ JZ RET8 ;None\r
+ CALL DOCRLF\r
+ INC [SECONDPASS]\r
+ XOR AX,AX\r
+ PUSH AX\r
+ PUSH AX\r
+ CALL DIRPROC ;Do it again\r
+RET8: RET\r
+\r
+SUBTTL AMDONE - Finish up routine\r
+PAGE\r
+AMDONE:\r
+ASSUME DS:NOTHING\r
+ CMP [DIRTYFAT],0\r
+ JZ NOWRITE ;FAT not dirty\r
+ CMP [DOFIX],0\r
+ JZ NOWRITE ;Not supposed to fix\r
+REWRITE:\r
+ LDS BX,[THISDPB]\r
+ASSUME DS:NOTHING\r
+ MOV CL,[BX.dpb_FAT_size] ;Sectors for one fat\r
+ XOR CH,CH\r
+ MOV DI,CX\r
+ MOV CL,[BX.dpb_FAT_count] ;Number of FATs\r
+ MOV DX,[BX.dpb_first_FAT] ;First sector of FAT\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:DG\r
+ MOV [ERRCNT],CH\r
+ MOV BX,OFFSET DG:FAT\r
+ MOV AL,[ALLDRV]\r
+ DEC AL\r
+ MOV AH,'1'\r
+ PUSH CX\r
+WRTLOOP:\r
+ XCHG CX,DI\r
+ PUSH DX\r
+ PUSH CX\r
+ PUSH DI\r
+ PUSH AX\r
+ INT 26H ;Write out the FAT\r
+ MOV [HECODE],AL\r
+ POP AX ;Flags\r
+ JNC WRTOK\r
+ INC [ERRCNT]\r
+ MOV DX,OFFSET DG:BADWRITE_PRE\r
+ CALL PRINT\r
+ POP AX\r
+ PUSH AX\r
+ MOV DL,AH\r
+ CALL PRTCHR\r
+ MOV DX,OFFSET DG:BADWRITE_POST\r
+ CALL PRINT\r
+WRTOK:\r
+ POP AX\r
+ POP CX\r
+ POP DI\r
+ POP DX\r
+ INC AH\r
+ ADD DX,DI\r
+ LOOP WRTLOOP ;Next FAT\r
+ POP CX ;Number of FATs\r
+ CMP CL,[ERRCNT] ;Error on all?\r
+ JNZ NOWRITE ;no\r
+ CALL WDSKERR\r
+ JZ REWRITE\r
+NOWRITE:\r
+ MOV AH,DISK_RESET ;Invalidate any buffers in system\r
+ INT 21H\r
+ MOV DX,OFFSET DG:USERDIR ;Recover users directory\r
+ MOV AH,CHDIR\r
+ INT 21H\r
+ CMP BYTE PTR [FRAGMENT],1 ;Check for any fragmented files?\r
+ JNZ DONE ;No -- we're finished\r
+ CALL CHECKFILES ;Yes -- report any fragments\r
+DONE:\r
+ASSUME DS:NOTHING\r
+ MOV DL,[USERDEV] ;Recover users drive\r
+ MOV AH,SET_DEFAULT_DRIVE\r
+ INT 21H\r
+ RET\r
+\r
+SUBTTL Routines for manipulating dir entries\r
+PAGE\r
+FIXENT2:\r
+;Same as FIXENT only [SRFCBPT] points to the search FCB, BX points to the entry\r
+ PUSH SI\r
+ PUSH BX\r
+ PUSH CX\r
+ MOV SI,BX\r
+ MOV BX,[SRFCBPT]\r
+ CALL FIXENT\r
+ POP CX\r
+ POP BX\r
+ POP SI\r
+RET20: RET\r
+\r
+FIXENT:\r
+;BX Points to search FCB\r
+;SI Points to Entry to fix\r
+ MOV [HAVFIX],1 ;Indicate a fix\r
+ CMP [DOFIX],0\r
+ JZ RET20 ;But don't do it!\r
+ PUSH BP\r
+ PUSH BX\r
+ PUSH SI\r
+ PUSH SI ;Entry pointer\r
+ MOV AX,[BX+THISENT] ;Entry number\r
+ CALL GETENT\r
+ POP SI ;Entry pointer\r
+ ADD SI,DIRNAM ;Point to start of entry\r
+ MOV CX,32\r
+ REP MOVSB\r
+ INC CL\r
+ CALL DOINT26\r
+ POP SI\r
+ POP BX\r
+ POP BP\r
+ RET\r
+\r
+GETENT:\r
+;AX is desired entry number (in current directory)\r
+;\r
+;DI points to entry in SECBUF\r
+;AX DX BX set to do an INT 26 to write it back out (CX must be reset to 1)\r
+;ALL registers destroyed (via int 25)\r
+ LDS DI,[THISDPB]\r
+ASSUME DS:NOTHING\r
+ MOV BX,[DI.dpb_current_dir]\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:DG\r
+ CMP BX,0FF8H\r
+ JB CLUSISOK\r
+ MOV BX,OFFSET DG:BADDPBDIR ;This should never happen\r
+ JMP FATAL\r
+CLUSISOK:\r
+ MOV CL,4\r
+ SHL AX,CL\r
+ XOR DX,DX\r
+ SHL AX,1\r
+ RCL DX,1 ;Account for overflow\r
+ MOV CX,[SSIZE]\r
+ AND CL,255-31 ;Must be a multiple of 32\r
+ DIV CX ;DX is position in sector, AX is dir sector #\r
+ OR BX,BX\r
+ JZ WANTROOT\r
+ DIV [CSIZE] ;AL # clusters to skip, AH position in cluster\r
+ MOV CL,AL\r
+ XOR CH,CH\r
+ JCXZ GOTCLUS\r
+ MOV SI,BX\r
+SKIPLP:\r
+ CALL UNPACK\r
+ XCHG SI,DI\r
+ LOOP SKIPLP\r
+ MOV BX,SI\r
+GOTCLUS:\r
+ PUSH DX ;Position in sector\r
+ CALL FIGREC ;Convert to sector #\r
+DOROOTDIR:\r
+ MOV BX,[SECBUF]\r
+ MOV AL,[ALLDRV]\r
+ DEC AL\r
+RDRETRY:\r
+ PUSH AX\r
+ PUSH DX\r
+ PUSH BX\r
+ MOV CX,1\r
+ INT 25H ;Read it\r
+ MOV [HECODE],AL\r
+ POP AX ;FLAGS\r
+ POP BX\r
+ POP DX\r
+ POP AX\r
+ JNC RDOK2\r
+ CALL RDSKERR\r
+ JZ RDRETRY\r
+RDOK2:\r
+ POP DI ;Offset into sector\r
+ ADD DI,BX ;Add sector base offset\r
+ RET\r
+\r
+WANTROOT:\r
+ PUSH DX\r
+ LDS DI,[THISDPB]\r
+ASSUME DS:NOTHING\r
+ MOV DX,AX\r
+ ADD DX,[DI.dpb_dir_sector]\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:DG\r
+ JMP DOROOTDIR\r
+\r
+CHECKNOFMES:\r
+ MOV AL,1\r
+ XCHG AL,[FIXMFLG]\r
+ OR AL,AL\r
+ JNZ RET14 ;Don't print it more than once\r
+ CMP [DOFIX],0\r
+ JNZ RET14 ;Don't print it if F switch specified\r
+ PUSH DX\r
+ MOV DX,OFFSET DG:FIXMES\r
+ CALL PRINT\r
+ POP DX\r
+ RET\r
+\r
+CHECKERR:\r
+ CALL CHECKNOFMES\r
+ CMP [SECONDPASS],0\r
+RET14: RET\r
+\r
+PRINTCURRDIRERR:\r
+ CALL CHECKERR\r
+ JNZ RET14\r
+ CALL PRINTCURRDIR\r
+ JMP SHORT ERREX\r
+\r
+PRINTTHISELERR:\r
+ CALL CHECKERR\r
+ JNZ RET14\r
+ CALL PRINTTHISEL\r
+ERREX:\r
+ CALL DOCRLF\r
+ RET\r
+\r
+PRINTTHISEL:\r
+ MOV SI,BX\r
+ ADD SI,DIRNAM\r
+PRINTTHISEL2:\r
+ MOV DI,OFFSET DG:NAMBUF\r
+ PUSH DI\r
+ CALL FCB_TO_ASCZ\r
+ POP SI\r
+PRINTCURRDIR:\r
+ PUSH SI\r
+ MOV DL,[ALLDRV]\r
+ ADD DL,'@'\r
+ CALL PRTCHR\r
+ MOV DL,DRVCHAR\r
+ CALL PRTCHR\r
+ LDS SI,[THISDPB]\r
+ASSUME DS:NOTHING\r
+ CMP [SI.dpb_current_dir],0\r
+ JZ CURISROOT\r
+ MOV DL,[DIRCHAR]\r
+ CALL PRTCHR\r
+ ADD SI,dpb_dir_text\r
+PCURRLP:\r
+ LODSB\r
+ OR AL,AL\r
+ JZ CURISROOT\r
+ MOV DL,AL\r
+ CALL PRTCHR\r
+ JMP PCURRLP\r
+\r
+CURISROOT:\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:DG\r
+ POP SI\r
+ CMP BYTE PTR [SI],0\r
+ JZ LPDONE ;If tail string NUL, no '/'\r
+ MOV DL,[DIRCHAR]\r
+ CALL PRTCHR\r
+ERRLOOP:\r
+ LODSB\r
+ OR AL,AL\r
+ JZ LPDONE\r
+ MOV DL,AL\r
+ CALL PRTCHR\r
+ JMP ERRLOOP\r
+LPDONE:\r
+ RET\r
+\r
+FATAL:\r
+;Unrecoverable error\r
+ MOV DX,OFFSET DG:FATALMES\r
+ CALL PRINT\r
+ MOV DX,BX\r
+ CALL PRINT\r
+ MOV DL,[USERDEV] ;At least leave on same drive\r
+ MOV AH,SET_DEFAULT_DRIVE\r
+ INT 21H\r
+ INT 20H\r
+\r
+\r
+INT_24_RETADDR DW OFFSET DG:INT_24_BACK\r
+\r
+INT_24 PROC FAR\r
+ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING\r
+ PUSHF\r
+ PUSH CS\r
+ PUSH [INT_24_RETADDR]\r
+ PUSH WORD PTR [HARDCH+2]\r
+ PUSH WORD PTR [HARDCH]\r
+ RET\r
+INT_24 ENDP\r
+\r
+INT_24_BACK:\r
+ CMP AL,2 ;Abort?\r
+ JNZ IRETI\r
+ CALL DONE ;Forget about directory, restore users drive\r
+ INT 20H\r
+IRETI:\r
+ IRET\r
+\r
+INT_23:\r
+ LDS DX,[HARDCH]\r
+ MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 24H\r
+ INT 21H\r
+ LDS DX,[CONTCH]\r
+ MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H\r
+ INT 21H\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:DG\r
+ MOV [FRAGMENT],0\r
+RDONE:\r
+ CALL NOWRITE ;Restore users drive and directory\r
+ INT 20H\r
+\r
+CODE ENDS\r
+ END CHKPROC\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+;*************************************
+; 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
--- /dev/null
+;\r
+; This version of COMMAND is divided into three distinct parts. First is the\r
+; resident portion, which includes handlers for interrupts 22H (terminate),\r
+; 23H (Cntrl-C), 24H (fatal error), and 27H (stay resident); it also has code\r
+; to test and, if necessary, reload the transient portion. Following the\r
+; resident is the init code, which is overwritten after use. Then comes the\r
+; transient portion, which includes all command processing (whether internal\r
+; or external). The transient portion loads at the end of physical memory,\r
+; and it may be overlayed by programs that need as much memory as possible.\r
+; When the resident portion of command regains control from a user program, a\r
+; checksum is performed on the transient portion to see if it must be\r
+; reloaded. Thus programs which do not need maximum memory will save the time\r
+; required to reload COMMAND when they terminate.\r
+\r
+;\r
+; REV 1.17\r
+; 05/19/82 Fixed bug in BADEXE error (relocation error must return to\r
+; resident since the EXELOAD may have overwritten the transient.\r
+; REV 1.18\r
+; 05/21/82 IBM version always looks on drive A\r
+; MSVER always looks on default drive\r
+;\r
+; REV 1.19\r
+; 06/03/82 Drive spec now entered in command line\r
+; 06/07/82 Added VER command (print DOS version number) and VOL command\r
+; (print volume label)\r
+; REV 1.20\r
+; 06/09/82 Prints "directory" after directories\r
+; 06/13/82 MKDIR, CHDIR, PWD, RMDIR added\r
+; REV 1.50\r
+; Some code for new 2.0 DOS, sort of HACKey. Not enough time to\r
+; do it right.\r
+; REV 1.70\r
+; EXEC used to fork off new processes\r
+; REV 1.80\r
+; C switch for single command execution\r
+; REV 1.90\r
+; Batch uses XENIX\r
+; Rev 2.00\r
+; Lots of neato stuff\r
+; IBM 2.00 level\r
+; Rev 2.01\r
+; 'D' switch for date time suppression\r
+; Rev 2.02\r
+; Default userpath is NUL rather than BIN\r
+; same as IBM\r
+; COMMAND split into pieces\r
+; Rev 2.10\r
+; INTERNATIONAL SUPPORT\r
+; Rev 2.11 COMMAND split into more pieces\r
+\r
+ INCLUDE DOSSYM.ASM\r
+ INCLUDE DEVSYM.ASM\r
+ INCLUDE COMSW.ASM\r
+ INCLUDE COMEQU.ASM\r
+\r
+CODERES SEGMENT PUBLIC\r
+CODERES ENDS\r
+\r
+DATARES SEGMENT PUBLIC BYTE\r
+ EXTRN COMBAD:BYTE,NEEDCOM:BYTE,DRVMSG:BYTE\r
+ EXTRN DEFMSG:BYTE,PROMPT:BYTE,EXECEMES:BYTE,EXEBAD:BYTE\r
+ EXTRN TOOBIG:BYTE,NOCOM:BYTE,RBADNAM:BYTE,INT_2E_RET:DWORD\r
+ EXTRN NOHANDMES:BYTE,BMEMMES:BYTE,HALTMES:BYTE,FRETMES:BYTE\r
+ EXTRN PARENT:WORD,HANDLE01:WORD,LOADING:BYTE,BATCH:WORD\r
+ EXTRN TRNSEG:WORD,COMDRV:BYTE,MEMSIZ:WORD,SUM:WORD,EXTCOM:BYTE\r
+ EXTRN IO_SAVE:WORD,PERMCOM:BYTE,SINGLECOM:WORD,VERVAL:WORD\r
+ EXTRN PIPEFLAG:BYTE,SAVE_PDB:WORD,COMSPEC:BYTE,TRANS:WORD\r
+ EXTRN TRANVARS:BYTE,LTPA:WORD,RSWITCHAR:BYTE,RDIRCHAR:BYTE\r
+ EXTRN RETCODE:WORD,FORFLAG:BYTE\r
+\r
+ IF IBMVER\r
+ EXTRN SYS_CALL:DWORD,ZEXEC:WORD,EXESEG:WORD,EXESUM:WORD\r
+ EXTRN USER_SS:WORD,USER_SP:WORD\r
+ ENDIF\r
+\r
+DATARES ENDS\r
+\r
+ENVIRONMENT SEGMENT PUBLIC PARA ; Default COMMAND environment\r
+ENVIRONMENT ENDS\r
+\r
+INIT SEGMENT PUBLIC PARA\r
+ EXTRN CONPROC:NEAR\r
+INIT ENDS\r
+\r
+TAIL SEGMENT PUBLIC PARA\r
+TAIL ENDS\r
+\r
+TRANCODE SEGMENT PUBLIC PARA\r
+TRANCODE ENDS\r
+\r
+TRANDATA SEGMENT PUBLIC BYTE\r
+ EXTRN TRANDATAEND:BYTE\r
+TRANDATA ENDS\r
+\r
+TRANSPACE SEGMENT PUBLIC BYTE\r
+ EXTRN TRANSPACEEND:BYTE,HEADCALL:DWORD\r
+TRANSPACE ENDS\r
+\r
+TRANTAIL SEGMENT PUBLIC PARA\r
+TRANTAIL ENDS\r
+\r
+ZEXEC_CODE SEGMENT PUBLIC PARA\r
+ZEXEC_CODE ENDS\r
+\r
+ZEXEC_DATA SEGMENT PUBLIC BYTE\r
+ZEXEC_DATA ENDS\r
+\r
+RESGROUP GROUP CODERES,DATARES,ENVIRONMENT,INIT,TAIL\r
+TRANGROUP GROUP TRANCODE,TRANDATA,TRANSPACE,TRANTAIL\r
+EGROUP GROUP ZEXEC_CODE,ZEXEC_DATA\r
+\r
+ENVIRONMENT SEGMENT PUBLIC PARA ; Default COMMAND environment\r
+\r
+ PUBLIC ECOMSPEC,ENVIREND,PATHSTRING\r
+\r
+ ORG 0\r
+ENVARENA DB 10H DUP (?) ; Pad for mem arena\r
+PATHSTRING DB "PATH="\r
+USERPATH LABEL BYTE\r
+\r
+ DB 0 ; Null path\r
+ DB "COMSPEC="\r
+ECOMSPEC DB "/COMMAND.COM"\r
+ DB 134 DUP (0)\r
+\r
+ENVIREND LABEL BYTE\r
+\r
+ENVIRONSIZ EQU $-PATHSTRING\r
+ENVIRONSIZ2 EQU $-ECOMSPEC\r
+ENVIRONMENT ENDS\r
+\r
+\r
+; START OF RESIDENT PORTION\r
+\r
+CODERES SEGMENT PUBLIC\r
+\r
+ PUBLIC GETCOMDSK2,LODCOM,THEADFIX,CONTCTERM,LOADCOM,INT_2E,LODCOM1\r
+ PUBLIC CHKSUM,SETVECT,EXT_EXEC,TREMCHECK,RESTHAND,CONTC,RSTACK\r
+ PUBLIC SAVHAND\r
+\r
+ IF IBMVER\r
+ PUBLIC EXECHK,SYSCALL,EXEC_WAIT\r
+ ENDIF\r
+\r
+ASSUME CS:RESGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING\r
+\r
+ EXTRN RPRINT:NEAR,ASKEND:NEAR,DSKERR:NEAR\r
+\r
+\r
+ ORG 0\r
+ZERO = $\r
+\r
+ ORG 100H\r
+\r
+PROGSTART:\r
+ JMP RESGROUP:CONPROC\r
+\r
+ DB (80H - 3) DUP (?)\r
+RSTACK LABEL WORD\r
+\r
+IF IBMVER\r
+SYSCALL:\r
+ CMP AH,EXEC\r
+ JZ do_exec\r
+ JMP DWORD PTR [SYS_CALL]\r
+\r
+do_exec:\r
+ PUSH ES\r
+ PUSH DS\r
+ PUSH BP\r
+ PUSH DI\r
+ PUSH SI\r
+ PUSH DX\r
+ PUSH CX\r
+ PUSH BX\r
+ PUSH AX\r
+ MOV [user_ss],SS\r
+ MOV [user_sp],SP\r
+;\r
+; are we running on RSTACK already?\r
+;\r
+ PUSH CS\r
+ POP BX ; BX <- CS\r
+ PUSH SS\r
+ POP AX ; AX <- SS\r
+ CMP AX,BX ; IF AX == BX then no stack switch!\r
+ JZ Get_mem\r
+ MOV SS,BX\r
+ASSUME SS:RESGROUP\r
+ MOV SP,OFFSET RESGROUP:RSTACK\r
+\r
+Get_mem:\r
+ MOV BX,0FFFFH ; allocate all of memory\r
+ MOV AH,ALLOC\r
+ INT int_command\r
+ MOV AX,OFFSET EGROUP:ZEXECDATAEND + 15\r
+ MOV CL,4\r
+ SHR AX,CL\r
+ MOV CX,AX ; Save in CX\r
+ CMP BX,AX ; enough for EXEC?\r
+ JB EXECMER ; nope... cry\r
+ MOV AH,ALLOC\r
+ INT int_command\r
+ JC EXECMER ; Memory arenas probably trashed\r
+ ADD BX,AX\r
+ MOV [MEMSIZ],BX\r
+ SUB BX,CX\r
+ MOV [EXESEG],BX ; exec\r
+ MOV ES,AX\r
+ MOV AH,DEALLOC\r
+ INT int_command\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:RESGROUP\r
+ CALL EXECHK\r
+ CMP DX,[EXESUM]\r
+ JZ HAVEXEC ; EXEC OK\r
+ MOV DX,OFFSET RESGROUP:COMSPEC\r
+ MOV AX,OPEN SHL 8\r
+ INT int_command ; Open COMMAND.COM\r
+ JC EXECMER\r
+ MOV BX,AX ; Handle\r
+ MOV DX,OFFSET RESGROUP:TRANSTART\r
+ ADD DX,OFFSET TRANGROUP:EXECSTART - 100H\r
+ XOR CX,CX ; Seek loc\r
+ MOV AX,LSEEK SHL 8\r
+ INT int_command\r
+ MOV CX,OFFSET EGROUP:ZEXECCODEEND\r
+ MOV DS,[EXESEG]\r
+ASSUME DS:NOTHING\r
+ MOV AH,READ\r
+ INT int_command\r
+ PUSH AX\r
+ MOV AH,CLOSE\r
+ INT int_command ; Close COMMAND.COM\r
+ POP CX\r
+ CMP CX,OFFSET EGROUP:ZEXECCODEEND\r
+ JNZ EXECMER ; Size matched\r
+\r
+ CALL EXECHK\r
+ CMP DX,[EXESUM]\r
+ JNZ EXECMER\r
+HAVEXEC:\r
+ MOV [LOADING],0 ; Flag to DSKERR\r
+ CALL DWORD PTR [ZEXEC]\r
+ JMP SHORT EXECRET\r
+execmer:\r
+ LDS SI,DWORD PTR [user_Sp]\r
+ MOV [SI.user_AX],exec_not_enough_memory\r
+ PUSH [SI.user_F]\r
+ POPF\r
+ STC\r
+ PUSHF\r
+ POP [SI.user_F]\r
+execret:\r
+ MOV SS,[user_SS]\r
+ASSUME SS:NOTHING\r
+ MOV SP,[user_SP]\r
+ POP AX ; PUSH ES\r
+ POP BX ; PUSH DS\r
+ POP CX ; PUSH BP\r
+ POP DX ; PUSH DI\r
+ POP SI ; PUSH SI\r
+ POP DI ; PUSH DX\r
+ POP BP ; PUSH CX\r
+ POP DS ; PUSH BX\r
+ POP ES ; PUSH AX\r
+ IRET\r
+\r
+EXECHK:\r
+ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING\r
+ PUSH DS\r
+ MOV DS,[EXESEG]\r
+ MOV CX,OFFSET EGROUP:ZEXECCODEEND\r
+ XOR SI,SI\r
+ JMP CHECK_SUM\r
+ENDIF\r
+\r
+EXEC_ERR: ; Select the correct error message\r
+ MOV DX,OFFSET RESGROUP:RBADNAM\r
+ CMP AX,exec_file_not_found\r
+ JZ GOTEXECEMES\r
+ CMP AX,error_access_denied\r
+ JZ GOTEXECEMES\r
+ MOV DX,OFFSET RESGROUP:TOOBIG\r
+ CMP AX,exec_not_enough_memory\r
+ JZ GOTEXECEMES\r
+ MOV DX,OFFSET RESGROUP:EXEBAD\r
+ CMP AX,exec_bad_format\r
+ JZ GOTEXECEMES\r
+ MOV DX,OFFSET RESGROUP:EXECEMES\r
+GOTEXECEMES:\r
+ PUSH CS\r
+ POP DS\r
+ CALL RPRINT\r
+ JMP SHORT NOEXEC\r
+\r
+EXT_EXEC:\r
+;\r
+; we are now running in free space. anything we do from here\r
+; on may get trashed. Move the stack (also in free space) to\r
+; allocated space because since EXEC restores the stack,\r
+; somebody may trash what is on the stack.\r
+;\r
+ MOV CX,CS\r
+ MOV SS,CX\r
+ MOV SP,OFFSET RESGROUP:RSTACK\r
+;\r
+; Oops!! We have to make sure that the EXEC code doesn't blop a newstack!\r
+;\r
+;\r
+ INT int_command ; Do the EXEC\r
+ JC EXEC_ERR ; EXEC failed\r
+EXEC_WAIT:\r
+ MOV AH,WAIT\r
+ INT int_command ; Get the return code\r
+ MOV [RETCODE],AX\r
+NOEXEC:\r
+ JMP LODCOM\r
+\r
+CONTC:\r
+ STI\r
+ MOV AX,CS\r
+ MOV DS,AX\r
+ASSUME DS:RESGROUP\r
+ MOV AH,DISK_RESET\r
+ INT int_command ; Reset disks in case files were open\r
+ TEST [BATCH],-1\r
+ JZ CONTCTERM\r
+ JMP ASKEND ; See if user wants to terminate batch\r
+CONTCTERM:\r
+ XOR BP,BP ; Indicate no read\r
+ MOV [FORFLAG],0 ; Turn off for processing\r
+ MOV [PIPEFLAG],0 ; Turn off any pipe\r
+ CMP [SINGLECOM],0 ; See if we need to set SINGLECOM\r
+ JZ NOSETSING\r
+ MOV [SINGLECOM],-1 ; Cause termination on pipe, batch, for\r
+NOSETSING:\r
+ CMP [EXTCOM],0\r
+ JNZ DODAB ; Internal ^C\r
+ JMP LODCOM1\r
+DODAB:\r
+ STC ; Tell DOS to abort\r
+ZZY PROC FAR\r
+ RET ; Leave flags on stack\r
+ZZY ENDP\r
+\r
+BADMEMERR: ; Allocation error loading transient\r
+ MOV DX,OFFSET RESGROUP:BMEMMES\r
+FATALC:\r
+ PUSH CS\r
+ POP DS\r
+ CALL RPRINT\r
+ CMP [PERMCOM],0\r
+ JZ FATALRET\r
+ CMP [SINGLECOM],0 ; If PERMCOM and SINGLECOM\r
+ JNZ FATALRET ; Must take INT_2E exit\r
+ MOV DX,OFFSET RESGROUP:HALTMES\r
+ CALL RPRINT\r
+STALL:\r
+ JMP STALL ; Crash the system nicely\r
+\r
+FATALRET:\r
+ MOV DX,OFFSET RESGROUP:FRETMES\r
+ CALL RPRINT\r
+FATALRET2:\r
+ CMP [PERMCOM],0 ; If we get here and PERMCOM,\r
+ JNZ RET_2E ; must be INT_2E\r
+IF IBM\r
+ LDS DX,DWORD PTR [SYS_CALL]\r
+ASSUME DS:NOTHING\r
+ MOV AX,(SET_INTERRUPT_VECTOR SHL 8) + INT_COMMAND\r
+ INT int_command\r
+ENDIF\r
+ MOV AX,[PARENT]\r
+ MOV WORD PTR CS:[PDB_Parent_PID],AX\r
+ MOV AX,(EXIT SHL 8) ; Return to lower level\r
+ INT int_command\r
+\r
+RET_2E:\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:RESGROUP,ES:NOTHING,SS:NOTHING\r
+ MOV [SINGLECOM],0 ; Turn off singlecom\r
+ MOV ES,[LTPA]\r
+ MOV AH,DEALLOC\r
+ INT int_command ; Free up space used by transient\r
+ MOV BX,[SAVE_PDB]\r
+ MOV AH,SET_CURRENT_PDB\r
+ INT int_command ; Current process is user\r
+ MOV AX,[RETCODE]\r
+ CMP [EXTCOM],0\r
+ JNZ GOTECODE\r
+ XOR AX,AX ; Internals always return 0\r
+GOTECODE:\r
+ MOV [EXTCOM],1 ; Force external\r
+ JMP [INT_2E_RET] ;"IRET"\r
+\r
+INT_2E: ; Magic command executer\r
+ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING\r
+ POP WORD PTR [INT_2E_RET]\r
+ POP WORD PTR [INT_2E_RET+2] ;Get return address\r
+ POP AX ;Chuck flags\r
+ PUSH CS\r
+ POP ES\r
+ MOV DI,80H\r
+ MOV CX,64\r
+ REP MOVSW\r
+ MOV AH,GET_CURRENT_PDB\r
+ INT int_command ; Get user's header\r
+ MOV [SAVE_PDB],BX\r
+ MOV AH,SET_CURRENT_PDB\r
+ MOV BX,CS\r
+ INT int_command ; Current process is me\r
+ MOV [SINGLECOM],81H\r
+ MOV [EXTCOM],1 ; Make sure this case forced\r
+\r
+LODCOM: ; Termination handler\r
+ CMP [EXTCOM],0\r
+ JZ LODCOM1 ; If internal, memory already allocated\r
+ MOV BX,0FFFFH\r
+ MOV AH,ALLOC\r
+ INT int_command\r
+ MOV AX,OFFSET TRANGROUP:TRANSPACEEND + 15\r
+ MOV CL,4\r
+ SHR AX,CL\r
+\r
+ IF IBM\r
+ PUSH AX\r
+ MOV AX,OFFSET EGROUP:ZEXECDATAEND + 15\r
+ MOV CL,4\r
+ SHR AX,CL\r
+ POP CX\r
+ ADD AX,CX\r
+ ENDIF\r
+\r
+ ADD AX,20H\r
+ CMP BX,AX ; Is less than 512 byte buffer worth it?\r
+ JNC MEMOK\r
+BADMEMERRJ:\r
+ JMP BADMEMERR ; Not enough memory\r
+MEMOK:\r
+ MOV AH,ALLOC\r
+ INT int_command\r
+ JC BADMEMERRJ ; Memory arenas probably trashed\r
+ MOV [EXTCOM],0 ; Flag not to ALLOC again\r
+ MOV [LTPA],AX ; New TPA is base just allocated\r
+ ADD BX,AX\r
+ MOV [MEMSIZ],BX\r
+\r
+ MOV AX,OFFSET TRANGROUP:TRANSPACEEND + 15\r
+ MOV CL,4\r
+ SHR AX,CL\r
+\r
+ IF IBM\r
+ PUSH AX\r
+ MOV AX,OFFSET EGROUP:ZEXECDATAEND + 15\r
+ MOV CL,4\r
+ SHR AX,CL\r
+ POP CX\r
+ ADD AX,CX\r
+ ENDIF\r
+\r
+ SUB BX,AX\r
+ MOV [TRNSEG],BX ; Transient starts here\r
+LODCOM1:\r
+ MOV AX,CS\r
+ MOV SS,AX\r
+ASSUME SS:RESGROUP\r
+ MOV SP,OFFSET RESGROUP:RSTACK\r
+ MOV DS,AX\r
+ASSUME DS:RESGROUP\r
+ CALL HEADFIX ; Make sure files closed stdin and stdout restored\r
+ XOR BP,BP ; Flag command ok\r
+ MOV AX,-1\r
+ XCHG AX,[VERVAL]\r
+ CMP AX,-1\r
+ JZ NOSETVER\r
+ MOV AH,SET_VERIFY_ON_WRITE ; AL has correct value\r
+ INT int_command\r
+NOSETVER:\r
+ CMP [SINGLECOM],-1\r
+ JNZ NOSNG\r
+ JMP FATALRET2 ; We have finished the single command\r
+NOSNG:\r
+ CALL SETVECT\r
+\r
+IF IBMVER\r
+ CALL EXECHK ; Check exe loader\r
+ CMP DX,[EXESUM]\r
+ JNZ BOGUS_COM\r
+ENDIF\r
+\r
+ CALL CHKSUM ; Check the transient\r
+ CMP DX,[SUM]\r
+ JZ HAVCOM ; Transient OK\r
+BOGUS_COM:\r
+ MOV [LOADING],1 ; Flag DSKERR routine\r
+ CALL LOADCOM\r
+CHKSAME:\r
+\r
+IF IBMVER\r
+ CALL EXECHK\r
+ CMP DX,[EXESUM]\r
+ JNZ ALSO_BOGUS\r
+ENDIF\r
+\r
+ CALL CHKSUM\r
+ CMP DX,[SUM]\r
+ JZ HAVCOM ; Same COMMAND\r
+ALSO_BOGUS:\r
+ CALL WRONGCOM\r
+ JMP SHORT CHKSAME\r
+HAVCOM:\r
+ MOV AX,CHAR_OPER SHL 8\r
+ INT int_command\r
+ MOV [RSWITCHAR],DL\r
+ CMP DL,'/'\r
+ JNZ USESLASH\r
+ MOV [RDIRCHAR],'\' ; Select alt path separator\r
+USESLASH:\r
+ MOV [LOADING],0 ; Flag to DSKERR\r
+ MOV SI,OFFSET RESGROUP:TRANVARS\r
+ MOV DI,OFFSET TRANGROUP:HEADCALL\r
+ MOV ES,[TRNSEG]\r
+ CLD\r
+ MOV CX,8\r
+ REP MOVSW ; Transfer INFO to transient\r
+ MOV AX,[MEMSIZ]\r
+ MOV WORD PTR DS:[PDB_block_len],AX ; Adjust my own header\r
+ JMP DWORD PTR [TRANS]\r
+\r
+; Far call to REMCHECK for TRANSIENT\r
+TREMCHECK PROC FAR\r
+ CALL REMCHECK\r
+ RET\r
+TREMCHECK ENDP\r
+\r
+REMCHECK:\r
+;All registers preserved. Returns zero if media removable, NZ if fixed\r
+; AL is drive (0=DEF, 1=A,...)\r
+ IF IBM\r
+ PUSH AX\r
+ OR AL,AL\r
+ JNZ GOTDRV2\r
+ MOV AH,GET_DEFAULT_DRIVE\r
+ INT int_command\r
+ INC AL ;A=1\r
+GOTDRV2:\r
+ PUSH BX\r
+ MOV BL,AL\r
+ INT 11H ;IBM EQUIP CALL\r
+ ROL AL,1\r
+ ROL AL,1\r
+ AND AL,3\r
+ JNZ NOT_SINGLE\r
+ INC AL\r
+NOT_SINGLE:\r
+ INC AL ; AL is now MAX floppy #\r
+ CMP BL,AL\r
+ POP BX\r
+ JBE SETREM ; Is an IBM floppy and so is removable\r
+ OR AL,AL ; Know AL is non-zero\r
+ JMP SHORT SETNREM\r
+SETREM:\r
+ ELSE\r
+ PUSH AX\r
+ ENDIF\r
+\r
+ XOR AX,AX ;Zero\r
+\r
+ IF IBM\r
+SETNREM:\r
+ ENDIF\r
+\r
+ POP AX\r
+ RET\r
+\r
+; Far call to HEADFIX for TRANSIENT\r
+THEADFIX PROC FAR\r
+ CALL HEADFIX\r
+ RET\r
+THEADFIX ENDP\r
+\r
+HEADFIX:\r
+ XOR BX,BX ; Clean up header\r
+ MOV CX,[IO_SAVE]\r
+ MOV DX,WORD PTR DS:[PDB_JFN_Table]\r
+ CMP CL,DL\r
+ JZ CHK1 ; Stdin matches\r
+ MOV AH,CLOSE\r
+ INT int_command\r
+ MOV DS:[PDB_JFN_Table],CL ; Restore stdin\r
+CHK1:\r
+ INC BX\r
+ CMP CH,DH ; Stdout matches\r
+ JZ CHKOTHERHAND\r
+ MOV AH,CLOSE\r
+ INT int_command\r
+ MOV DS:[PDB_JFN_Table+1],CH ; Restore stdout\r
+CHKOTHERHAND:\r
+ ADD BX,4 ; Skip 2,3,4\r
+ MOV CX,FilPerProc - 5 ; Already done 0,1,2,3,4\r
+CLOSELOOP:\r
+ MOV AH,CLOSE\r
+ INT int_command\r
+ INC BX\r
+ LOOP CLOSELOOP\r
+ RET\r
+\r
+SAVHAND:\r
+ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING\r
+ PUSH DS\r
+ PUSH BX ; Set stdin to sterr, stdout to stderr\r
+ PUSH AX\r
+ MOV AH,GET_CURRENT_PDB\r
+ INT int_command ; Get user's header\r
+ MOV DS,BX\r
+ MOV AX,WORD PTR DS:[PDB_JFN_Table]\r
+ MOV [HANDLE01],AX ; Save user's stdin, stdout\r
+ MOV AL,DS:[PDB_JFN_Table+2]\r
+ MOV AH,AL\r
+ MOV WORD PTR DS:[PDB_JFN_Table],AX ; Dup stderr\r
+ POP AX\r
+ POP BX\r
+ POP DS\r
+ RET\r
+\r
+ASSUME DS:RESGROUP\r
+GETCOMDSK2:\r
+ CALL GETCOMDSK\r
+ JMP LODCOM1 ; Memory already allocated\r
+\r
+RESTHAND:\r
+ PUSH DS\r
+ PUSH BX ; Restore stdin, stdout to user\r
+ PUSH AX\r
+ MOV AH,GET_CURRENT_PDB\r
+ INT int_command ; Point to user's header\r
+ MOV AX,[HANDLE01]\r
+ MOV DS,BX\r
+ASSUME DS:NOTHING\r
+ MOV WORD PTR DS:[PDB_JFN_Table],AX ; Stuff his old 0 and 1\r
+ POP AX\r
+ POP BX\r
+ POP DS\r
+ RET\r
+ASSUME DS:RESGROUP,SS:RESGROUP\r
+\r
+HOPELESS:\r
+ MOV DX,OFFSET RESGROUP:NOCOM\r
+ JMP FATALC\r
+\r
+GETCOMDSK:\r
+ MOV DX,OFFSET RESGROUP:NEEDCOM\r
+GETCOMDSK3:\r
+ MOV AL,[COMDRV]\r
+ CALL REMCHECK\r
+ JNZ HOPELESS ;Non-removable media\r
+ CALL RPRINT\r
+ MOV DX,OFFSET RESGROUP:DRVMSG\r
+ CMP [COMDRV],0\r
+ JNZ GETCOM1\r
+ MOV DX,OFFSET RESGROUP:DEFMSG\r
+GETCOM1:\r
+ CALL RPRINT\r
+ MOV DX,OFFSET RESGROUP:PROMPT\r
+ CALL RPRINT\r
+ CALL GetRawFlushedByte\r
+ RET\r
+\r
+; flush world and get raw input\r
+GetRawFlushedByte:\r
+ MOV AX,(STD_CON_INPUT_FLUSH SHL 8) OR RAW_CON_INPUT\r
+ INT int_command ; Get char without testing or echo\r
+ MOV AX,(STD_CON_INPUT_FLUSH SHL 8) + 0\r
+ INT int_command\r
+ return\r
+\r
+LOADCOM: ; Load in transient\r
+ INC BP ; Flag command read\r
+ MOV DX,OFFSET RESGROUP:COMSPEC\r
+ MOV AX,OPEN SHL 8\r
+ INT int_command ; Open COMMAND.COM\r
+ JNC READCOM\r
+ CMP AX,open_too_many_open_files\r
+ JNZ TRYDOOPEN\r
+ MOV DX,OFFSET RESGROUP:NOHANDMES\r
+ JMP FATALC ; Fatal, will never find a handle\r
+\r
+TRYDOOPEN:\r
+ CALL GETCOMDSK\r
+ JMP SHORT LOADCOM\r
+\r
+READCOM:\r
+ MOV BX,AX ; Handle\r
+ MOV DX,OFFSET RESGROUP:TRANSTART\r
+ XOR CX,CX ; Seek loc\r
+ MOV AX,LSEEK SHL 8\r
+ INT int_command\r
+ JC WRONGCOM1\r
+ MOV CX,OFFSET TRANGROUP:TRANSPACEEND - 100H\r
+\r
+ IF IBM\r
+ ADD CX,15\r
+ AND CX,0FFF0H\r
+ ADD CX,OFFSET EGROUP:ZEXECCODEEND\r
+ ENDIF\r
+\r
+ PUSH DS\r
+ MOV DS,[TRNSEG]\r
+ASSUME DS:NOTHING\r
+ MOV DX,100H\r
+ MOV AH,READ\r
+ INT int_command\r
+ POP DS\r
+ASSUME DS:RESGROUP\r
+WRONGCOM1:\r
+ PUSHF\r
+ PUSH AX\r
+ MOV AH,CLOSE\r
+ INT int_command ; Close COMMAND.COM\r
+ POP AX\r
+ POPF\r
+ JC WRONGCOM ; If error on READ\r
+ CMP AX,CX\r
+ JZ RET10 ; Size matched\r
+WRONGCOM:\r
+ MOV DX,OFFSET RESGROUP:COMBAD\r
+ CALL GETCOMDSK3\r
+ JMP SHORT LOADCOM ; Try again\r
+\r
+CHKSUM: ; Compute transient checksum\r
+ PUSH DS\r
+ MOV DS,[TRNSEG]\r
+ MOV SI,100H\r
+ MOV CX,OFFSET TRANGROUP:TRANDATAEND - 100H\r
+\r
+CHECK_SUM:\r
+ CLD\r
+ SHR CX,1\r
+ XOR DX,DX\r
+CHK:\r
+ LODSW\r
+ ADD DX,AX\r
+ LOOP CHK\r
+ POP DS\r
+RET10: RET\r
+\r
+SETVECT: ; Set useful vectors\r
+ MOV DX,OFFSET RESGROUP:LODCOM\r
+ MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 22H ; Set Terminate address\r
+ INT int_command\r
+ MOV DX,OFFSET RESGROUP:CONTC\r
+ MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H ; Set Ctrl-C address\r
+ INT int_command\r
+ MOV DX,OFFSET RESGROUP:DSKERR\r
+ MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 24H ; Set Hard Disk Error address\r
+ INT int_command\r
+ RET\r
+\r
+CODERES ENDS\r
+\r
+; This TAIL segment is used to produce a PARA aligned label in the resident\r
+; group which is the location where the transient segments will be loaded\r
+; initial.\r
+\r
+TAIL SEGMENT PUBLIC PARA\r
+ ORG 0\r
+TRANSTART LABEL WORD\r
+TAIL ENDS\r
+\r
+; This TAIL segment is used to produce a PARA aligned label in the transient\r
+; group which is the location where the exec segments will be loaded\r
+; initial.\r
+\r
+TRANTAIL SEGMENT PUBLIC PARA\r
+ ORG 0\r
+EXECSTART LABEL WORD\r
+TRANTAIL ENDS\r
+\r
+IF IBMVER\r
+ INCLUDE EXEC.ASM\r
+ENDIF\r
+\r
+ END PROGSTART\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+; 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
--- /dev/null
+; Use the following booleans to set assembly flags\r
+FALSE EQU 0\r
+TRUE EQU NOT FALSE\r
+\r
+IBMVER EQU true ; Switch to build IBM version of Command\r
+IBM EQU IBMVER\r
+MSVER EQU false ; Switch to build MS-DOS version of Command\r
+\r
+HIGHMEM EQU FALSE ; Run resident part above transient (high memory)\r
+KANJI EQU false ; Support for dual byte Microsoft KANJI standard\r
+IBMJAPAN EQU FALSE ;MUST BE TRUE (along with IBM and KANJI)\r
+\r
+\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a
\ No newline at end of file
--- /dev/null
+TITLE COMMAND COPY routines.\r
+\r
+ INCLUDE COMSW.ASM\r
+\r
+.xlist\r
+.xcref\r
+ INCLUDE DOSSYM.ASM\r
+ INCLUDE DEVSYM.ASM\r
+ INCLUDE COMSEG.ASM\r
+.list\r
+.cref\r
+\r
+ INCLUDE COMEQU.ASM\r
+\r
+DATARES SEGMENT PUBLIC\r
+ EXTRN VERVAL:WORD\r
+DATARES ENDS\r
+\r
+TRANDATA SEGMENT PUBLIC\r
+ EXTRN BADARGS:BYTE,BADCD:BYTE,BADSWT:BYTE,COPIED_PRE:BYTE\r
+ EXTRN COPIED_POST:BYTE\r
+ EXTRN INBDEV:BYTE,OVERWR:BYTE,FULDIR:BYTE,LOSTERR:BYTE\r
+ EXTRN NOSPACE:BYTE,DEVWMES:BYTE,NOTFND:BYTE\r
+TRANDATA ENDS\r
+\r
+TRANSPACE SEGMENT PUBLIC\r
+ EXTRN MELCOPY:BYTE,SRCPT:WORD,MELSTART:WORD,SCANBUF:BYTE\r
+ EXTRN DESTFCB2:BYTE,SDIRBUF:BYTE,SRCTAIL:WORD,CFLAG:BYTE\r
+ EXTRN NXTADD:WORD,DESTCLOSED:BYTE,ALLSWITCH:WORD,ARGC:BYTE\r
+ EXTRN PLUS:BYTE,BINARY:BYTE,ASCII:BYTE,FILECNT:WORD\r
+ EXTRN WRITTEN:BYTE,CONCAT:BYTE,DESTBUF:BYTE,SRCBUF:BYTE\r
+ EXTRN SDIRBUF:BYTE,DIRBUF:BYTE,DESTFCB:BYTE,FRSTSRCH:BYTE\r
+ EXTRN FIRSTDEST:BYTE,DESTISDIR:BYTE,DESTSWITCH:WORD,STARTEL:WORD\r
+ EXTRN DESTTAIL:WORD,DESTSIZ:BYTE,DESTINFO:BYTE,INEXACT:BYTE\r
+ EXTRN CURDRV:BYTE,DESTVARS:BYTE,RESSEG:WORD,SRCSIZ:BYTE\r
+ EXTRN SRCINFO:BYTE,SRCVARS:BYTE,USERDIR1:BYTE,NOWRITE:BYTE\r
+ EXTRN RDEOF:BYTE,SRCHAND:WORD,CPDATE:WORD,CPTIME:WORD\r
+ EXTRN SRCISDEV:BYTE,BYTCNT:WORD,TPA:WORD,TERMREAD:BYTE\r
+ EXTRN DESTHAND:WORD,DESTISDEV:BYTE,DIRCHAR:BYTE\r
+TRANSPACE ENDS\r
+\r
+\r
+; **************************************************\r
+; COPY CODE\r
+;\r
+\r
+TRANCODE SEGMENT PUBLIC BYTE\r
+\r
+ EXTRN RESTUDIR:NEAR,CERROR:NEAR,SWITCH:NEAR,DISP32BITS:NEAR\r
+ EXTRN PRINT:NEAR,TCOMMAND:NEAR,ZPRINT:NEAR,ONESPC:NEAR\r
+ EXTRN RESTUDIR1:NEAR,FCB_TO_ASCZ:NEAR,CRLF2:NEAR,SAVUDIR1:NEAR\r
+ EXTRN SETREST1:NEAR,BADCDERR:NEAR,STRCOMP:NEAR,DELIM:NEAR\r
+ EXTRN UPCONV:NEAR,PATHCHRCMP:NEAR,SCANOFF:NEAR\r
+\r
+ EXTRN CPARSE:NEAR\r
+\r
+ EXTRN SEARCH:NEAR,SEARCHNEXT:NEAR,DOCOPY:NEAR,CLOSEDEST:NEAR\r
+ EXTRN FLSHFIL:NEAR,SETASC:NEAR,BUILDNAME:NEAR,COPERR:NEAR\r
+\r
+ PUBLIC COPY,BUILDPATH,COMPNAME,ENDCOPY\r
+\r
+\r
+ASSUME CS:TRANGROUP,DS:TRANGROUP,ES:TRANGROUP,SS:NOTHING\r
+\r
+DOMELCOPY:\r
+ cmp [MELCOPY],0FFH\r
+ jz CONTMEL\r
+ mov SI,[SRCPT]\r
+ mov [MELSTART],si\r
+ mov [MELCOPY],0FFH\r
+CONTMEL:\r
+ xor BP,BP\r
+ mov si,[SRCPT]\r
+ mov bl,'+'\r
+SCANSRC2:\r
+ mov di,OFFSET TRANGROUP:SCANBUF\r
+ call CPARSE\r
+ test bh,80H\r
+ jz NEXTMEL ; Go back to start\r
+ test bh,1 ; Switch ?\r
+ jnz SCANSRC2 ; Yes\r
+ call SOURCEPROC\r
+ call RESTUDIR1\r
+ mov di,OFFSET TRANGROUP:DESTFCB2\r
+ mov ax,PARSE_FILE_DESCRIPTOR SHL 8\r
+ INT int_command\r
+ mov bx,OFFSET TRANGROUP:SDIRBUF + 1\r
+ mov si,OFFSET TRANGROUP:DESTFCB2 + 1\r
+ mov di,[SRCTAIL]\r
+ call BUILDNAME\r
+ jmp MELDO\r
+\r
+\r
+NEXTMEL:\r
+ call CLOSEDEST\r
+ xor ax,ax\r
+ mov [CFLAG],al\r
+ mov [NXTADD],ax\r
+ mov [DESTCLOSED],al\r
+ mov si,[MELSTART]\r
+ mov [SRCPT],si\r
+ call SEARCHNEXT\r
+ jz SETNMELJ\r
+ jmp ENDCOPY2\r
+SETNMELJ:\r
+ jmp SETNMEL\r
+\r
+COPY:\r
+; First order of buisness is to find out about the destination\r
+ASSUME DS:TRANGROUP,ES:TRANGROUP\r
+ xor ax,ax\r
+ mov [ALLSWITCH],AX ; no switches\r
+ mov [ARGC],al ; no arguments\r
+ mov [PLUS],al ; no concatination\r
+ mov [BINARY],al ; Binary not specifically specified\r
+ mov [ASCII],al ; ASCII not specifically specified\r
+ mov [FILECNT],ax ; No files yet\r
+ mov [WRITTEN],al ; Nothing written yet\r
+ mov [CONCAT],al ; No concatination\r
+ mov [MELCOPY],al ; Not a Mel Hallerman copy\r
+ mov word ptr [SCANBUF],ax ; Init buffer\r
+ mov word ptr [DESTBUF],ax ; Init buffer\r
+ mov word ptr [SRCBUF],ax ; Init buffer\r
+ mov word ptr [SDIRBUF],ax ; Init buffer\r
+ mov word ptr [DIRBUF],ax ; Init buffer\r
+ mov word ptr [DESTFCB],ax ; Init buffer\r
+ dec ax\r
+ mov [FRSTSRCH],al ; First search call\r
+ mov [FIRSTDEST],al ; First time\r
+ mov [DESTISDIR],al ; Don't know about dest\r
+ mov si,81H\r
+ mov bl,'+' ; include '+' as a delimiter\r
+DESTSCAN:\r
+ xor bp,bp ; no switches\r
+ mov di,offset trangroup:SCANBUF\r
+ call CPARSE\r
+ PUSHF ; save flags\r
+ test bh,80H ; A '+' argument?\r
+ jz NOPLUS ; no\r
+ mov [PLUS],1 ; yes\r
+NOPLUS:\r
+ POPF ; get flags back\r
+ jc CHECKDONE ; Hit CR?\r
+ test bh,1 ; Switch?\r
+ jz TESTP2 ; no\r
+ or [DESTSWITCH],BP ; Yes, assume destination\r
+ or [ALLSWITCH],BP ; keep tabs on all switches\r
+ jmp short DESTSCAN\r
+\r
+TESTP2:\r
+ test bh,80H ; Plus?\r
+ jnz GOTPLUS ; Yes, not a separate arg\r
+ inc [ARGC] ; found a real arg\r
+GOTPLUS:\r
+ push SI\r
+ mov ax,[STARTEL]\r
+ mov SI,offset trangroup:SCANBUF ; Adjust to copy\r
+ sub ax,SI\r
+ mov DI,offset trangroup:DESTBUF\r
+ add ax,DI\r
+ mov [DESTTAIL],AX\r
+ mov [DESTSIZ],cl ; Save its size\r
+ inc cx ; Include the NUL\r
+ rep movsb ; Save potential destination\r
+ mov [DESTINFO],bh ; Save info about it\r
+ mov [DESTSWITCH],0 ; reset switches\r
+ pop SI\r
+ jmp short DESTSCAN ; keep going\r
+\r
+CHECKDONE:\r
+ mov al,[PLUS]\r
+ mov [CONCAT],al ; PLUS -> Concatination\r
+ shl al,1\r
+ shl al,1\r
+ mov [INEXACT],al ; CONCAT -> inexact copy\r
+ mov dx,offset trangroup:BADARGS\r
+ mov al,[ARGC]\r
+ or al,al ; Good number of args?\r
+ jz CERROR4J ; no, not enough\r
+ cmp al,2\r
+ jbe ACOUNTOK\r
+CERROR4J:\r
+ jmp CERROR ; no, too many\r
+ACOUNTOK:\r
+ mov bp,offset trangroup:DESTVARS\r
+ cmp al,1\r
+ jnz GOT2ARGS\r
+ mov al,[CURDRV] ; Dest is default drive:*.*\r
+ add al,'A'\r
+ mov ah,':'\r
+ mov [bp.SIZ],2\r
+ mov di,offset trangroup:DESTBUF\r
+ stosw\r
+ mov [DESTSWITCH],0 ; no switches on dest\r
+ mov [bp.INFO],2 ; Flag dest is ambig\r
+ mov [bp.ISDIR],0 ; Know destination specs file\r
+ call SETSTARS\r
+GOT2ARGS:\r
+ cmp [bp.SIZ],2\r
+ jnz NOTSHORTDEST\r
+ cmp [DESTBUF+1],':'\r
+ jnz NOTSHORTDEST ; Two char file name\r
+ or [bp.INFO],2 ; Know dest is d:\r
+ mov di,offset trangroup:DESTBUF + 2\r
+ mov [bp.ISDIR],0 ; Know destination specs file\r
+ call SETSTARS\r
+NOTSHORTDEST:\r
+ mov di,[bp.TTAIL]\r
+ cmp byte ptr [DI],0\r
+ jnz CHKSWTCHES\r
+ mov dx,offset trangroup:BADCD\r
+ cmp byte ptr [DI-2],':'\r
+ jnz CERROR4J ; Trailing '/' error\r
+ mov [bp.ISDIR],2 ; Know destination is d:/\r
+ or [bp.INFO],6\r
+ call SETSTARS\r
+CHKSWTCHES:\r
+ mov dx,offset trangroup:BADSWT\r
+ mov ax,[ALLSWITCH]\r
+ cmp ax,GOTSWITCH\r
+ jz CERROR4J ; Switch specified which is not known\r
+\r
+; Now know most of the information needed about the destination\r
+\r
+ TEST AX,VSWITCH ; Verify requested?\r
+ JZ NOVERIF ; No\r
+ MOV AH,GET_VERIFY_ON_WRITE\r
+ INT int_command ; Get current setting\r
+ PUSH DS\r
+ MOV DS,[RESSEG]\r
+ASSUME DS:RESGROUP\r
+ XOR AH,AH\r
+ MOV [VERVAL],AX ; Save current setting\r
+ POP DS\r
+ASSUME DS:TRANGROUP\r
+ MOV AX,(SET_VERIFY_ON_WRITE SHL 8) OR 1 ; Set verify\r
+ INT int_command\r
+NOVERIF:\r
+ xor bp,bp ; no switches\r
+ mov si,81H\r
+ mov bl,'+' ; include '+' as a delimiter\r
+SCANFSRC:\r
+ mov di,offset trangroup:SCANBUF\r
+ call CPARSE ; Parse first source name\r
+ test bh,1 ; Switch?\r
+ jnz SCANFSRC ; Yes, try again\r
+ or [DESTSWITCH],bp ; Include copy wide switches on DEST\r
+ test bp,BSWITCH\r
+ jnz NOSETCASC ; Binary explicit\r
+ cmp [CONCAT],0\r
+ JZ NOSETCASC ; Not Concat\r
+ mov [ASCII],ASWITCH ; Concat -> ASCII copy if no B switch\r
+NOSETCASC:\r
+ push SI\r
+ mov ax,[STARTEL]\r
+ mov SI,offset trangroup:SCANBUF ; Adjust to copy\r
+ sub ax,SI\r
+ mov DI,offset trangroup:SRCBUF\r
+ add ax,DI\r
+ mov [SRCTAIL],AX\r
+ mov [SRCSIZ],cl ; Save its size\r
+ inc cx ; Include the NUL\r
+ rep movsb ; Save this source\r
+ mov [SRCINFO],bh ; Save info about it\r
+ pop SI\r
+ mov ax,bp ; Switches so far\r
+ call SETASC ; Set A,B switches accordingly\r
+ call SWITCH ; Get any more switches on this arg\r
+ call SETASC ; Set\r
+ call FRSTSRC\r
+ jmp FIRSTENT\r
+\r
+ENDCOPY:\r
+ CALL CLOSEDEST\r
+ENDCOPY2:\r
+ MOV DX,OFFSET TRANGROUP:COPIED_PRE\r
+ CALL PRINT\r
+ MOV SI,[FILECNT]\r
+ XOR DI,DI\r
+ CALL DISP32BITS\r
+ MOV DX,OFFSET TRANGROUP:COPIED_POST\r
+ CALL PRINT\r
+ JMP TCOMMAND ; Stack could be messed up\r
+\r
+SRCNONEXIST:\r
+ cmp [CONCAT],0\r
+ jnz NEXTSRC ; If in concat mode, ignore error\r
+ mov dx,offset trangroup:SRCBUF\r
+ call zprint\r
+ CALL ONESPC\r
+ mov dx,offset trangroup:NOTFND\r
+ jmp COPERR\r
+\r
+SOURCEPROC:\r
+ push SI\r
+ mov ax,[STARTEL]\r
+ mov SI,offset trangroup:SCANBUF ; Adjust to copy\r
+ sub ax,SI\r
+ mov DI,offset trangroup:SRCBUF\r
+ add ax,DI\r
+ mov [SRCTAIL],AX\r
+ mov [SRCSIZ],cl ; Save its size\r
+ inc cx ; Include the NUL\r
+ rep movsb ; Save this sorce\r
+ mov [SRCINFO],bh ; Save info about it\r
+ pop SI\r
+ mov ax,bp ; Switches so far\r
+ call SETASC ; Set A,B switches accordingly\r
+ call SWITCH ; Get any more switches on this arg\r
+ call SETASC ; Set\r
+ cmp [CONCAT],0\r
+ jnz LEAVECFLAG ; Leave CFLAG if concatination\r
+FRSTSRC:\r
+ xor ax,ax\r
+ mov [CFLAG],al ; Flag destination not created\r
+ mov [NXTADD],ax ; Zero out buffer\r
+ mov [DESTCLOSED],al ; Not created -> not closed\r
+LEAVECFLAG:\r
+ mov [SRCPT],SI ; remember where we are\r
+ mov di,offset trangroup:USERDIR1\r
+ mov bp,offset trangroup:SRCVARS\r
+ call BUILDPATH ; Figure out everything about the source\r
+ mov si,[SRCTAIL] ; Create the search FCB\r
+ return\r
+\r
+NEXTSRC:\r
+ cmp [PLUS],0\r
+ jnz MORECP\r
+ENDCOPYJ2:\r
+ jmp ENDCOPY ; Done\r
+MORECP:\r
+ xor bp,bp ; no switches\r
+ mov si,[SRCPT]\r
+ mov bl,'+' ; include '+' as a delimiter\r
+SCANSRC:\r
+ mov di,offset trangroup:SCANBUF\r
+ call CPARSE ; Parse first source name\r
+ JC EndCopyJ2 ; if error, then end (trailing + case)\r
+ test bh,80H\r
+ jz ENDCOPYJ2 ; If no '+' we're done\r
+ test bh,1 ; Switch?\r
+ jnz SCANSRC ; Yes, try again\r
+ call SOURCEPROC\r
+FIRSTENT:\r
+ mov di,FCB\r
+ mov ax,PARSE_FILE_DESCRIPTOR SHL 8\r
+ INT int_command\r
+ mov ax,word ptr [SRCBUF] ; Get drive\r
+ cmp ah,':'\r
+ jz DRVSPEC1\r
+ mov al,'@'\r
+DRVSPEC1:\r
+ sub al,'@'\r
+ mov ds:[FCB],al\r
+ mov ah,DIR_SEARCH_FIRST\r
+ call SEARCH\r
+ pushf ; Save result of search\r
+ call RESTUDIR1 ; Restore users dir\r
+ popf\r
+ jz NEXTAMBIG0\r
+ jmp SRCNONEXIST ; Failed\r
+NEXTAMBIG0:\r
+ xor al,al\r
+ xchg al,[FRSTSRCH]\r
+ or al,al\r
+ jz NEXTAMBIG\r
+SETNMEL:\r
+ mov cx,12\r
+ mov di,OFFSET TRANGROUP:SDIRBUF\r
+ mov si,OFFSET TRANGROUP:DIRBUF\r
+ rep movsb ; Save very first source name\r
+NEXTAMBIG:\r
+ xor al,al\r
+ mov [NOWRITE],al ; Turn off NOWRITE\r
+ mov di,[SRCTAIL]\r
+ mov si,offset trangroup:DIRBUF + 1\r
+ call FCB_TO_ASCZ ; SRCBUF has complete name\r
+MELDO:\r
+ cmp [CONCAT],0\r
+ jnz SHOWCPNAM ; Show name if concat\r
+ test [SRCINFO],2 ; Show name if multi\r
+ jz DOREAD\r
+SHOWCPNAM:\r
+ mov dx,offset trangroup:SRCBUF\r
+ call ZPRINT\r
+ call CRLF2\r
+DOREAD:\r
+ call DOCOPY\r
+ cmp [CONCAT],0\r
+ jnz NODCLOSE ; If concat, do not close\r
+ call CLOSEDEST ; else close current destination\r
+ jc NODCLOSE ; Concat flag got set, close didn't really happen\r
+ mov [CFLAG],0 ; Flag destination not created\r
+NODCLOSE:\r
+ cmp [CONCAT],0 ; Check CONCAT again\r
+ jz NOFLUSH\r
+ CALL FLSHFIL ; Flush output between source files on CONCAT\r
+ ; so LOSTERR stuff works correctly\r
+ TEST [MELCOPY],0FFH\r
+ jz NOFLUSH\r
+ jmp DOMELCOPY\r
+\r
+NOFLUSH:\r
+ call SEARCHNEXT ; Try next match\r
+ jnz NEXTSRCJ ; Finished with this source spec\r
+ mov [DESTCLOSED],0 ; Not created or concat -> not closed\r
+ jmp NEXTAMBIG ; Do next ambig\r
+\r
+NEXTSRCJ:\r
+ jmp NEXTSRC\r
+\r
+\r
+\r
+BUILDPATH:\r
+ test [BP.INFO],2\r
+ jnz NOTPFILE ; If ambig don't bother with open\r
+ mov dx,bp\r
+ add dx,BUF ; Set DX to spec\r
+ mov ax,OPEN SHL 8\r
+ INT int_command\r
+ jc NOTPFILE\r
+ mov bx,ax ; Is pure file\r
+ mov ax,IOCTL SHL 8\r
+ INT int_command\r
+ mov ah,CLOSE\r
+ INT int_command\r
+ test dl,devid_ISDEV\r
+ jnz ISADEV ; If device, done\r
+ test [BP.INFO],4\r
+ jz ISSIMPFILE ; If no path seps, done\r
+NOTPFILE:\r
+ mov dx,word ptr [BP.BUF]\r
+ cmp dh,':'\r
+ jz DRVSPEC5\r
+ mov dl,'@'\r
+DRVSPEC5:\r
+ sub dl,'@' ; A = 1\r
+ call SAVUDIR1\r
+ mov dx,bp\r
+ add dx,BUF ; Set DX for upcomming CHDIRs\r
+ mov bh,[BP.INFO]\r
+ and bh,6\r
+ cmp bh,6 ; Ambig and path ?\r
+ jnz CHECKAMB ; jmp if no\r
+ mov si,[BP.TTAIL]\r
+ cmp byte ptr [si-2],':'\r
+ jnz KNOWNOTSPEC\r
+ mov [BP.ISDIR],2 ; Know is d:/file\r
+ jmp short DOPCDJ\r
+\r
+KNOWNOTSPEC:\r
+ mov [BP.ISDIR],1 ; Know is path/file\r
+ dec si ; Point to the /\r
+DOPCDJ:\r
+ jmp short DOPCD\r
+\r
+CHECKAMB:\r
+ cmp bh,2\r
+ jnz CHECKCD\r
+ISSIMPFILE:\r
+ISADEV:\r
+ mov [BP.ISDIR],0 ; Know is file since ambig but no path\r
+ return\r
+\r
+CHECKCD:\r
+ call SETREST1\r
+ mov ah,CHDIR\r
+ INT int_command\r
+ jc NOTPDIR\r
+ mov di,dx\r
+ xor ax,ax\r
+ mov cx,ax\r
+ dec cx\r
+ repne scasb\r
+ dec di\r
+ mov al,[DIRCHAR]\r
+ mov [bp.ISDIR],2 ; assume d:/file\r
+ cmp al,[di-1]\r
+ jz GOTSRCSLSH\r
+ stosb\r
+ mov [bp.ISDIR],1 ; know path/file\r
+GOTSRCSLSH:\r
+ or [bp.INFO],6\r
+ call SETSTARS\r
+ return\r
+\r
+\r
+NOTPDIR:\r
+ mov [bp.ISDIR],0 ; assume pure file\r
+ mov bh,[bp.INFO]\r
+ test bh,4\r
+ retz ; Know pure file, no path seps\r
+ mov [bp.ISDIR],2 ; assume d:/file\r
+ mov si,[bp.TTAIL]\r
+ cmp byte ptr [si],0\r
+ jz BADCDERRJ2 ; Trailing '/'\r
+ cmp byte ptr [si],'.'\r
+ jz BADCDERRJ2 ; If . or .. pure cd should have worked\r
+ cmp byte ptr [si-2],':'\r
+ jz DOPCD ; Know d:/file\r
+ mov [bp.ISDIR],1 ; Know path/file\r
+ dec si ; Point at last '/'\r
+DOPCD:\r
+ xor bl,bl\r
+ xchg bl,[SI] ; Stick in a NUL\r
+ call SETREST1\r
+ mov ah,CHDIR\r
+ INT int_command\r
+ xchg bl,[SI]\r
+ retnc\r
+BADCDERRJ2:\r
+ JMP BADCDERR\r
+\r
+SETSTARS:\r
+ mov [bp.TTAIL],DI\r
+ add [bp.SIZ],12\r
+ mov ax,('.' SHL 8) OR '?'\r
+ mov cx,8\r
+ rep stosb\r
+ xchg al,ah\r
+ stosb\r
+ xchg al,ah\r
+ mov cl,3\r
+ rep stosb\r
+ xor al,al\r
+ stosb\r
+ return\r
+\r
+\r
+COMPNAME:\r
+ PUSH CX\r
+ PUSH AX\r
+ MOV si,offset trangroup:SRCBUF\r
+ MOV di,offset trangroup:DESTBUF\r
+ MOV CL,[CURDRV]\r
+ MOV CH,CL\r
+ CMP BYTE PTR [SI+1],':'\r
+ JNZ NOSRCDRV\r
+ LODSW\r
+ SUB AL,'A'\r
+ MOV CL,AL\r
+NOSRCDRV:\r
+ CMP BYTE PTR [DI+1],':'\r
+ JNZ NODSTDRV\r
+ MOV AL,[DI]\r
+ INC DI\r
+ INC DI\r
+ SUB AL,'A'\r
+ MOV CH,AL\r
+NODSTDRV:\r
+ CMP CH,CL\r
+ jnz RET81P\r
+ call STRCOMP\r
+ jz RET81P\r
+ mov ax,[si-1]\r
+ mov cx,[di-1]\r
+ push ax\r
+ and al,cl\r
+ pop ax\r
+ jnz RET81P ; Niether of the mismatch chars was a NUL\r
+; Know one of the mismatch chars is a NUL\r
+; Check for ".NUL" compared with NUL\r
+ cmp al,'.'\r
+ jnz CHECKCL\r
+ or ah,ah\r
+ jmp short RET81P ; If NUL return match, else no match\r
+CHECKCL:\r
+ cmp cl,'.'\r
+ jnz RET81P ; Mismatch\r
+ or ch,ch ; If NUL return match, else no match\r
+RET81P:\r
+ POP AX\r
+ POP CX\r
+ return\r
+\r
+TRANCODE ENDS\r
+\r
+ END\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+TITLE COPYRPOC ;Procedures called by COPY\r
+\r
+ INCLUDE COMSW.ASM\r
+\r
+.xlist\r
+.xcref\r
+ INCLUDE DOSSYM.ASM\r
+ INCLUDE DEVSYM.ASM\r
+ INCLUDE COMSEG.ASM\r
+.list\r
+.cref\r
+\r
+ INCLUDE COMEQU.ASM\r
+\r
+DATARES SEGMENT PUBLIC\r
+DATARES ENDS\r
+\r
+TRANDATA SEGMENT PUBLIC\r
+\r
+ EXTRN OVERWR:BYTE,FULDIR:BYTE,LOSTERR:BYTE\r
+ EXTRN DEVWMES:BYTE,INBDEV:BYTE,NOSPACE:BYTE\r
+\r
+TRANDATA ENDS\r
+\r
+TRANSPACE SEGMENT PUBLIC\r
+\r
+ EXTRN CFLAG:BYTE,NXTADD:WORD,DESTCLOSED:BYTE\r
+ EXTRN PLUS:BYTE,BINARY:BYTE,ASCII:BYTE,FILECNT:WORD\r
+ EXTRN WRITTEN:BYTE,CONCAT:BYTE,DESTBUF:BYTE,SRCBUF:BYTE\r
+ EXTRN SDIRBUF:BYTE,DIRBUF:BYTE,DESTFCB:BYTE,MELCOPY:BYTE\r
+ EXTRN FIRSTDEST:BYTE,DESTISDIR:BYTE,DESTSWITCH:WORD\r
+ EXTRN DESTTAIL:WORD,DESTINFO:BYTE,INEXACT:BYTE\r
+ EXTRN DESTVARS:BYTE,SRCINFO:BYTE,RDEOF:BYTE\r
+ EXTRN USERDIR1:BYTE,NOWRITE:BYTE\r
+ EXTRN SRCHAND:WORD,CPDATE:WORD,CPTIME:WORD\r
+ EXTRN SRCISDEV:BYTE,BYTCNT:WORD,TPA:WORD,TERMREAD:BYTE\r
+ EXTRN DESTHAND:WORD,DESTISDEV:BYTE,DIRCHAR:BYTE\r
+\r
+TRANSPACE ENDS\r
+\r
+TRANCODE SEGMENT PUBLIC BYTE\r
+\r
+ PUBLIC SEARCH,SEARCHNEXT,DOCOPY,CLOSEDEST,FLSHFIL,SETASC\r
+ PUBLIC BUILDNAME,COPERR\r
+\r
+ EXTRN PRINT:NEAR,BUILDPATH:NEAR,RESTUDIR1:NEAR\r
+ EXTRN COMPNAME:NEAR,ENDCOPY:NEAR\r
+\r
+ASSUME CS:TRANGROUP,DS:TRANGROUP,ES:TRANGROUP,SS:NOTHING\r
+\r
+\r
+SEARCHNEXT:\r
+ MOV AH,DIR_SEARCH_NEXT\r
+ TEST [SRCINFO],2\r
+ JNZ SEARCH ; Do serach-next if ambig\r
+ OR AH,AH ; Reset zero flag\r
+ return\r
+SEARCH:\r
+ PUSH AX\r
+ MOV AH,SET_DMA\r
+ MOV DX,OFFSET TRANGROUP:DIRBUF\r
+ INT int_command ; Put result of search in DIRBUF\r
+ POP AX ; Restore search first/next command\r
+ MOV DX,FCB\r
+ INT int_command ; Do the search\r
+ OR AL,AL\r
+ return\r
+\r
+DOCOPY:\r
+ mov [RDEOF],0 ; No EOF yet\r
+ mov dx,offset trangroup:SRCBUF\r
+ mov ax,OPEN SHL 8\r
+ INT int_command\r
+ retc ; If open fails, ignore\r
+ mov bx,ax ; Save handle\r
+ mov [SRCHAND],bx ; Save handle\r
+ mov ax,(FILE_TIMES SHL 8)\r
+ INT int_command\r
+ mov [CPDATE],dx ; Save DATE\r
+ mov [CPTIME],cx ; Save TIME\r
+ mov ax,(IOCTL SHL 8)\r
+ INT int_command ; Get device stuff\r
+ and dl,devid_ISDEV\r
+ mov [SRCISDEV],dl ; Set source info\r
+ jz COPYLP ; Source not a device\r
+ cmp [BINARY],0\r
+ jz COPYLP ; ASCII device OK\r
+ mov dx,offset trangroup:INBDEV ; Cannot do binary input\r
+ jmp COPERR\r
+\r
+COPYLP:\r
+ mov bx,[SRCHAND]\r
+ mov cx,[BYTCNT]\r
+ mov dx,[NXTADD]\r
+ sub cx,dx ; Compute available space\r
+ jnz GOTROOM\r
+ call FLSHFIL\r
+ CMP [TERMREAD],0\r
+ JNZ CLOSESRC ; Give up\r
+ mov cx,[BYTCNT]\r
+GOTROOM:\r
+ push ds\r
+ mov ds,[TPA]\r
+ASSUME DS:NOTHING\r
+ mov ah,READ\r
+ INT int_command\r
+ pop ds\r
+ASSUME DS:TRANGROUP\r
+ jc CLOSESRC ; Give up if error\r
+ mov cx,ax ; Get count\r
+ jcxz CLOSESRC ; No more to read\r
+ cmp [SRCISDEV],0\r
+ jnz NOTESTA ; Is a device, ASCII mode\r
+ cmp [ASCII],0\r
+ jz BINREAD\r
+NOTESTA:\r
+ MOV DX,CX\r
+ MOV DI,[NXTADD]\r
+ MOV AL,1AH\r
+ PUSH ES\r
+ MOV ES,[TPA]\r
+ REPNE SCASB ; Scan for EOF\r
+ POP ES\r
+ JNZ USEALL\r
+ INC [RDEOF]\r
+ INC CX\r
+USEALL:\r
+ SUB DX,CX\r
+ MOV CX,DX\r
+BINREAD:\r
+ ADD CX,[NXTADD]\r
+ MOV [NXTADD],CX\r
+ CMP CX,[BYTCNT] ; Is buffer full?\r
+ JB TESTDEV ; If not, we may have found EOF\r
+ CALL FLSHFIL\r
+ CMP [TERMREAD],0\r
+ JNZ CLOSESRC ; Give up\r
+ JMP SHORT COPYLP\r
+\r
+TESTDEV:\r
+ cmp [SRCISDEV],0\r
+ JZ CLOSESRC ; If file then EOF\r
+ CMP [RDEOF],0\r
+ JZ COPYLP ; On device, go till ^Z\r
+CLOSESRC:\r
+ mov bx,[SRCHAND]\r
+ mov ah,CLOSE\r
+ INT int_command\r
+ return\r
+\r
+CLOSEDEST:\r
+ cmp [DESTCLOSED],0\r
+ retnz ; Don't double close\r
+ MOV AL,BYTE PTR [DESTSWITCH]\r
+ CALL SETASC ; Check for B or A switch on destination\r
+ JZ BINCLOS\r
+ MOV BX,[NXTADD]\r
+ CMP BX,[BYTCNT] ; Is memory full?\r
+ JNZ PUTZ\r
+ call TRYFLUSH ; Make room for one lousy byte\r
+ jz NOCONC\r
+CONCHNG: ; Concat flag changed on us\r
+ stc\r
+ return\r
+NOCONC:\r
+ XOR BX,BX\r
+PUTZ:\r
+ PUSH DS\r
+ MOV DS,[TPA]\r
+ MOV WORD PTR [BX],1AH ; Add End-of-file mark (Ctrl-Z)\r
+ POP DS\r
+ INC [NXTADD]\r
+ MOV [NOWRITE],0 ; Make sure our ^Z gets written\r
+ MOV AL,[WRITTEN]\r
+ XOR AH,AH\r
+ ADD AX,[NXTADD]\r
+ JC BINCLOS ; > 1\r
+ CMP AX,1\r
+ JZ FORGETIT ; WRITTEN = 0 NXTADD = 1 (the ^Z)\r
+BINCLOS:\r
+ call TRYFLUSH\r
+ jnz CONCHNG\r
+ cmp [WRITTEN],0\r
+ jz FORGETIT ; Never wrote nothin\r
+ MOV BX,[DESTHAND]\r
+ MOV CX,[CPTIME]\r
+ MOV DX,[CPDATE]\r
+ CMP [INEXACT],0 ; Copy not exact?\r
+ JZ DODCLOSE ; If no, copy date & time\r
+ MOV AH,GET_TIME\r
+ INT int_command\r
+ SHL CL,1\r
+ SHL CL,1 ; Left justify min in CL\r
+ SHL CX,1\r
+ SHL CX,1\r
+ SHL CX,1 ; hours to high 5 bits, min to 5-10\r
+ SHR DH,1 ; Divide seconds by 2 (now 5 bits)\r
+ OR CL,DH ; And stick into low 5 bits of CX\r
+ PUSH CX ; Save packed time\r
+ MOV AH,GET_DATE\r
+ INT int_command\r
+ SUB CX,1980\r
+ XCHG CH,CL\r
+ SHL CX,1 ; Year to high 7 bits\r
+ SHL DH,1 ; Month to high 3 bits\r
+ SHL DH,1\r
+ SHL DH,1\r
+ SHL DH,1\r
+ SHL DH,1 ; Most sig bit of month in carry\r
+ ADC CH,0 ; Put that bit next to year\r
+ OR DL,DH ; Or low three of month into day\r
+ MOV DH,CH ; Get year and high bit of month\r
+ POP CX ; Get time back\r
+DODCLOSE:\r
+ MOV AX,(FILE_TIMES SHL 8) OR 1\r
+ INT int_command ; Set date and time\r
+ MOV AH,CLOSE\r
+ INT int_command\r
+ INC [FILECNT]\r
+ INC [DESTCLOSED]\r
+RET50:\r
+ CLC\r
+ return\r
+\r
+FORGETIT:\r
+ MOV BX,[DESTHAND]\r
+ CALL DODCLOSE ; Close the dest\r
+ MOV DX,OFFSET TRANGROUP:DESTBUF\r
+ MOV AH,UNLINK\r
+ INT int_command ; And delete it\r
+ MOV [FILECNT],0 ; No files transferred\r
+ JMP RET50\r
+\r
+TRYFLUSH:\r
+ mov al,[CONCAT]\r
+ push ax\r
+ call FLSHFIL\r
+ pop ax\r
+ cmp al,[CONCAT]\r
+ return\r
+\r
+FLSHFIL:\r
+; Write out any data remaining in memory.\r
+; Inputs:\r
+; [NXTADD] = No. of bytes to write\r
+; [CFLAG] <>0 if file has been created\r
+; Outputs:\r
+; [NXTADD] = 0\r
+\r
+ MOV [TERMREAD],0\r
+ cmp [CFLAG],0\r
+ JZ NOTEXISTS\r
+ JMP EXISTS\r
+NOTEXISTS:\r
+ call BUILDDEST ; Find out all about the destination\r
+ CALL COMPNAME ; Source and dest. the same?\r
+ JNZ PROCDEST ; If not, go ahead\r
+ CMP [SRCISDEV],0\r
+ JNZ PROCDEST ; Same name on device OK\r
+ CMP [CONCAT],0 ; Concatenation?\r
+ MOV DX,OFFSET TRANGROUP:OVERWR\r
+ JZ COPERRJ ; If not, overwrite error\r
+ MOV [NOWRITE],1 ; Flag not writting (just seeking)\r
+PROCDEST:\r
+ mov ax,(OPEN SHL 8) OR 1\r
+ CMP [NOWRITE],0\r
+ JNZ DODESTOPEN ; Don't actually create if NOWRITE set\r
+ mov ah,CREAT\r
+ xor cx,cx\r
+DODESTOPEN:\r
+ mov dx,offset trangroup:DESTBUF\r
+ INT int_command\r
+ MOV DX,OFFSET TRANGROUP:FULDIR\r
+ JC COPERRJ\r
+ mov [DESTHAND],ax ; Save handle\r
+ mov [CFLAG],1 ; Destination now exists\r
+ mov bx,ax\r
+ mov ax,(IOCTL SHL 8)\r
+ INT int_command ; Get device stuff\r
+ mov [DESTISDEV],dl ; Set dest info\r
+ test dl,devid_ISDEV\r
+ jz EXISTS ; Dest not a device\r
+ mov al,BYTE PTR [DESTSWITCH]\r
+ AND AL,ASWITCH+BSWITCH\r
+ JNZ TESTBOTH\r
+ MOV AL,[ASCII] ; Neither set, use current setting\r
+ OR AL,[BINARY]\r
+ JZ EXSETA ; Neither set, default to ASCII\r
+TESTBOTH:\r
+ JPE EXISTS ; Both are set, ignore\r
+ test AL,BSWITCH\r
+ jz EXISTS ; Leave in cooked mode\r
+ mov ax,(IOCTL SHL 8) OR 1\r
+ xor dh,dh\r
+ or dl,devid_RAW\r
+ mov [DESTISDEV],dl ; New value\r
+ INT int_command ; Set device to RAW mode\r
+ jmp short EXISTS\r
+\r
+COPERRJ:\r
+ jmp SHORT COPERR\r
+\r
+EXSETA:\r
+; What we read in may have been in binary mode, flag zapped write OK\r
+ mov [ASCII],ASWITCH ; Set ASCII mode\r
+ or [INEXACT],ASWITCH ; ASCII -> INEXACT\r
+EXISTS:\r
+ cmp [NOWRITE],0\r
+ jnz NOCHECKING ; If nowrite don't bother with name check\r
+ CALL COMPNAME ; Source and dest. the same?\r
+ JNZ NOCHECKING ; If not, go ahead\r
+ CMP [SRCISDEV],0\r
+ JNZ NOCHECKING ; Same name on device OK\r
+; At this point we know in append (would have gotten overwrite error on first\r
+; destination create otherwise), and user trying to specify destination which\r
+; has been scribbled already (if dest had been named first, NOWRITE would\r
+; be set).\r
+ MOV DX,OFFSET TRANGROUP:LOSTERR ; Tell him he's not going to get it\r
+ CALL PRINT\r
+ MOV [NXTADD],0 ; Set return\r
+ INC [TERMREAD] ; Tell Read to give up\r
+RET60:\r
+ return\r
+\r
+NOCHECKING:\r
+ mov bx,[DESTHAND] ; Get handle\r
+ XOR CX,CX\r
+ XCHG CX,[NXTADD]\r
+ JCXZ RET60 ; If Nothing to write, forget it\r
+ INC [WRITTEN] ; Flag that we wrote something\r
+ CMP [NOWRITE],0 ; If NOWRITE set, just seek CX bytes\r
+ JNZ SEEKEND\r
+ XOR DX,DX\r
+ PUSH DS\r
+ MOV DS,[TPA]\r
+ASSUME DS:NOTHING\r
+ MOV AH,WRITE\r
+ INT int_command\r
+ POP DS\r
+ASSUME DS:TRANGROUP\r
+ MOV DX,OFFSET TRANGROUP:NOSPACE\r
+ JC COPERR ; Failure\r
+ sub cx,ax\r
+ retz ; Wrote all supposed to\r
+ test [DESTISDEV],devid_ISDEV\r
+ jz COPERR ; Is a file, error\r
+ test [DESTISDEV],devid_RAW\r
+ jnz DEVWRTERR ; Is a raw device, error\r
+ cmp [INEXACT],0\r
+ retnz ; INEXACT so OK\r
+ dec cx\r
+ retz ; Wrote one byte less (the ^Z)\r
+DEVWRTERR:\r
+ MOV DX,OFFSET TRANGROUP:DEVWMES\r
+COPERR:\r
+ CALL PRINT\r
+ inc [DESTCLOSED]\r
+ cmp [CFLAG],0\r
+ jz ENDCOPYJ ; Never actually got it open\r
+ MOV bx,[DESTHAND]\r
+ MOV AH,CLOSE ; Close the file\r
+ INT int_command\r
+ MOV DX,OFFSET TRANGROUP:DESTBUF\r
+ MOV AH,UNLINK\r
+ INT int_command ; And delete it\r
+ MOV [CFLAG],0\r
+ENDCOPYJ:\r
+ JMP ENDCOPY\r
+\r
+\r
+SEEKEND:\r
+ xor dx,dx ; Zero high half of offset\r
+ xchg dx,cx ; cx:dx is seek location\r
+ mov ax,(LSEEK SHL 8) OR 1\r
+ INT int_command ; Seek ahead in the file\r
+ cmp [RDEOF],0\r
+ retz\r
+; If a ^Z has been read we must set the file size to the current\r
+; file pointer location\r
+ MOV AH,WRITE\r
+ INT int_command ; CX is zero, truncates file\r
+ return\r
+\r
+SETASC:\r
+; Given switch vector in AX,\r
+; Set ASCII switch if A is set\r
+; Clear ASCII switch if B is set\r
+; BINARY set if B specified\r
+; Leave ASCII unchanged if neither or both are set\r
+; Also sets INEXACT if ASCII is ever set. AL = ASCII on exit, flags set\r
+ AND AL,ASWITCH+BSWITCH\r
+ JPE LOADSW ; PE means both or neither are set\r
+ PUSH AX\r
+ AND AL,BSWITCH\r
+ MOV [BINARY],AL\r
+ POP AX\r
+ AND AL,ASWITCH\r
+ MOV [ASCII],AL\r
+ OR [INEXACT],AL\r
+LOADSW:\r
+ MOV AL,[ASCII]\r
+ OR AL,AL\r
+ return\r
+\r
+BUILDDEST:\r
+ cmp [DESTISDIR],-1\r
+ jnz KNOWABOUTDEST ; Already done the figuring\r
+ MOV DI,OFFSET TRANGROUP:USERDIR1\r
+ mov bp,offset trangroup:DESTVARS\r
+ call BUILDPATH\r
+ call RESTUDIR1\r
+\r
+; Now know all about the destination\r
+\r
+KNOWABOUTDEST:\r
+ xor al,al\r
+ xchg al,[FIRSTDEST]\r
+ or al,al\r
+ jnz FIRSTDST\r
+ jmp NOTFIRSTDEST\r
+FIRSTDST:\r
+ mov si,[DESTTAIL] ; Create an FCB of the original DEST\r
+ mov di,offset trangroup:DESTFCB\r
+ mov ax,PARSE_FILE_DESCRIPTOR SHL 8\r
+ INT int_command\r
+ mov ax,word ptr [DESTBUF] ; Get drive\r
+ cmp ah,':'\r
+ jz DRVSPEC4\r
+ mov al,'@'\r
+DRVSPEC4:\r
+ MOV CL,[ASCII] ; Save current ASCII setting\r
+ sub al,'@'\r
+ mov [DESTFCB],al\r
+ mov al,[DESTINFO]\r
+ mov ah,[SRCINFO]\r
+ and ax,0202H\r
+ or al,al\r
+ jz NOTMELCOPY\r
+ cmp al,ah\r
+ jnz NOTMELCOPY\r
+ cmp [PLUS],0\r
+ jz NOTMELCOPY\r
+ inc [MELCOPY] ; ambig source, ambig dest, and pluses\r
+ xor al,al\r
+ jmp short SETCONC\r
+\r
+NOTMELCOPY:\r
+ xor al,2 ; al=2 if unambig dest, =0 if ambig dest\r
+ and al,ah\r
+ shr al,1 ; al=1 if unambig dest AND ambig sorce\r
+ ; Implies concatination\r
+SETCONC:\r
+ or al,[PLUS] ; al=1 if concat\r
+ mov [CONCAT],al\r
+ shl al,1\r
+ shl al,1\r
+ mov [INEXACT],al ; Concat -> inexact copy\r
+ cmp [BINARY],0\r
+ jnz NOTFIRSTDEST ; Binary explicitly given, all OK\r
+ mov [ASCII],al ; Concat -> ASCII\r
+ or cl,cl\r
+ jnz NOTFIRSTDEST ; ASCII flag set before, DATA read correctly\r
+ or al,al\r
+ JZ NOTFIRSTDEST ; ASCII flag did not change states\r
+; At this point there may already be binary read data in the read buffer.\r
+; We need to find the first ^Z (if there is one) and trim the amount\r
+; of data in the buffer correctly.\r
+ MOV CX,[NXTADD]\r
+ JCXZ NOTFIRSTDEST ; No data, everything OK\r
+ MOV AL,1AH\r
+ PUSH ES\r
+ XOR DI,DI\r
+ MOV ES,[TPA]\r
+ REPNE SCASB ; Scan for EOF\r
+ POP ES\r
+ JNZ NOTFIRSTDEST ; No ^Z in buffer, everything OK\r
+ DEC DI ; Point at ^Z\r
+ MOV [NXTADD],DI ; New buffer\r
+NOTFIRSTDEST:\r
+ mov bx,offset trangroup:DIRBUF+1 ; Source of replacement chars\r
+ cmp [CONCAT],0\r
+ jz GOTCHRSRC ; Not a concat\r
+ mov bx,offset trangroup:SDIRBUF+1 ; Source of replacement chars\r
+GOTCHRSRC:\r
+ mov si,offset trangroup:DESTFCB+1 ; Original dest name\r
+ mov di,[DESTTAIL] ; Where to put result\r
+\r
+BUILDNAME:\r
+ mov cx,8\r
+BUILDMAIN:\r
+ lodsb\r
+ cmp al,"?"\r
+ jnz NOTAMBIG\r
+ mov al,byte ptr [BX]\r
+NOTAMBIG:\r
+ cmp al,' '\r
+ jz NOSTORE\r
+ stosb\r
+NOSTORE:\r
+ inc bx\r
+ loop BUILDMAIN\r
+ mov cl,3\r
+ cmp byte ptr [SI],' '\r
+ jz ENDDEST ; No extension\r
+ mov al,'.'\r
+ stosb\r
+BUILDEXT:\r
+ lodsb\r
+ cmp al,"?"\r
+ jnz NOTAMBIGE\r
+ mov al,byte ptr [BX]\r
+NOTAMBIGE:\r
+ cmp al,' '\r
+ jz NOSTOREE\r
+ stosb\r
+NOSTOREE:\r
+ inc bx\r
+ loop BUILDEXT\r
+ENDDEST:\r
+ xor al,al\r
+ stosb ; NUL terminate\r
+ return\r
+\r
+TRANCODE ENDS\r
+ END\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+TITLE CPARSE\r
+\r
+ INCLUDE COMSW.ASM\r
+\r
+.xlist\r
+.xcref\r
+ INCLUDE DOSSYM.ASM\r
+ INCLUDE DEVSYM.ASM\r
+ INCLUDE COMSEG.ASM\r
+.list\r
+.cref\r
+\r
+ INCLUDE COMEQU.ASM\r
+\r
+DATARES SEGMENT PUBLIC\r
+DATARES ENDS\r
+\r
+TRANDATA SEGMENT PUBLIC\r
+ EXTRN BADCPMES:BYTE\r
+TRANDATA ENDS\r
+\r
+TRANSPACE SEGMENT PUBLIC\r
+ EXTRN CURDRV:BYTE,ELPOS:BYTE,STARTEL:WORD\r
+ EXTRN SKPDEL:BYTE,SWITCHAR:BYTE,ELCNT:BYTE\r
+\r
+TRANSPACE ENDS\r
+\r
+TRANCODE SEGMENT PUBLIC BYTE\r
+\r
+ASSUME CS:TRANGROUP,DS:TRANGROUP,ES:TRANGROUP\r
+\r
+ EXTRN DELIM:NEAR,UPCONV:NEAR,PATHCHRCMP:NEAR\r
+ EXTRN SWLIST:BYTE,BADCDERR:NEAR,SCANOFF:NEAR,CERROR:NEAR\r
+\r
+ if KANJI\r
+ EXTRN TESTKANJ:NEAR\r
+ endif\r
+\r
+SWCOUNT EQU 5\r
+\r
+ PUBLIC CPARSE\r
+\r
+CPARSE:\r
+\r
+;-----------------------------------------------------------------------;\r
+; ENTRY: ;\r
+; DS:SI Points input buffer ;\r
+; ES:DI Points to the token buffer ;\r
+; BL Special delimiter for this call ;\r
+; Always checked last ;\r
+; set it to space if there is no special delimiter ;\r
+; EXIT: ;\r
+; DS:SI Points to next char in the input buffer ;\r
+; ES:DI Points to the token buffer ;\r
+; [STARTEL] Points to start of last element of path in token ;\r
+; points to a NUL for no element strings 'd:' 'd:/' ;\r
+; CX Character count ;\r
+; BH Condition Code ;\r
+; Bit 1H of BH set if switch character ;\r
+; Token buffer contains char after ;\r
+; switch character ;\r
+; BP has switch bits set (ORing only) ;\r
+; Bit 2H of BH set if ? or * in token ;\r
+; if * found element ? filled ;\r
+; Bit 4H of BH set if path sep in token ;\r
+; Bit 80H of BH set if the special delimiter ;\r
+; was skipped at the start of this token ;\r
+; Token buffer always starts d: for non switch tokens ;\r
+; CARRY SET ;\r
+; if CR on input ;\r
+; token buffer not altered ;\r
+; ;\r
+; DOES NOT RETURN ON BAD PATH ERROR ;\r
+; MODIFIES: ;\r
+; CX, SI, AX, BH, DX and the Carry Flag ; ;\r
+; ;\r
+; -----------------------------------------------------------------------;\r
+\r
+ xor ax,ax\r
+ mov [STARTEL],DI ; No path element (Is DI correct?)\r
+ mov [ELPOS],al ; Start in 8 char prefix\r
+ mov [SKPDEL],al ; No skip delimiter yet\r
+ mov bh,al ; Init nothing\r
+ pushf ; save flags\r
+ push di ; save the token buffer addrss\r
+ xor cx,cx ; no chars in token buffer\r
+moredelim:\r
+ LODSB\r
+ CALL DELIM\r
+ JNZ SCANCDONE\r
+ CMP AL,' '\r
+ JZ moredelim\r
+ CMP AL,9\r
+ JZ moredelim\r
+ xchg al,[SKPDEL]\r
+ or al,al\r
+ jz moredelim ; One non space/tab delimiter allowed\r
+ JMP x_done ; Nul argument\r
+\r
+SCANCDONE:\r
+\r
+ IF NOT KANJI\r
+ call UPCONV\r
+ ENDIF\r
+\r
+ cmp al,bl ; Special delimiter?\r
+ jnz nospec\r
+ or bh,80H\r
+ jmp short moredelim\r
+\r
+nospec:\r
+ cmp al,0DH ; a CR?\r
+ jne ncperror\r
+ jmp cperror\r
+ncperror:\r
+ cmp al,[SWITCHAR] ; is the char the switch char?\r
+ jne na_switch ; yes, process...\r
+ jmp a_switch\r
+na_switch:\r
+ cmp byte ptr [si],':'\r
+ jne anum_chard ; Drive not specified\r
+\r
+ IF KANJI\r
+ call UPCONV\r
+ ENDIF\r
+\r
+ call move_char\r
+ lodsb ; Get the ':'\r
+ call move_char\r
+ mov [STARTEL],di\r
+ mov [ELCNT],0\r
+ jmp anum_test\r
+\r
+anum_chard:\r
+ mov [STARTEL],di\r
+ mov [ELCNT],0 ; Store of this char sets it to one\r
+ call PATHCHRCMP ; Starts with a pathchar?\r
+ jnz anum_char ; no\r
+ push ax\r
+ mov al,[CURDRV] ; Insert drive spec\r
+ add al,'A'\r
+ call move_char\r
+ mov al,':'\r
+ call move_char\r
+ pop ax\r
+ mov [STARTEL],di\r
+ mov [ELCNT],0\r
+\r
+anum_char:\r
+\r
+ IF KANJI\r
+ call TESTKANJ\r
+ jz TESTDOT\r
+ call move_char\r
+ lodsb\r
+ jmp short notspecial\r
+\r
+TESTDOT:\r
+ ENDIF\r
+\r
+ cmp al,'.'\r
+ jnz testquest\r
+ inc [ELPOS] ; flag in extension\r
+ mov [ELCNT],0FFH ; Store of the '.' resets it to 0\r
+testquest:\r
+ cmp al,'?'\r
+ jnz testsplat\r
+ or bh,2\r
+testsplat:\r
+ cmp al,'*'\r
+ jnz testpath\r
+ or bh,2\r
+ mov ah,7\r
+ cmp [ELPOS],0\r
+ jz gotelcnt\r
+ mov ah,2\r
+gotelcnt:\r
+ mov al,'?'\r
+ sub ah,[ELCNT]\r
+ jc badperr2\r
+ xchg ah,cl\r
+ jcxz testpathx\r
+qmove:\r
+ xchg ah,cl\r
+ call move_char\r
+ xchg ah,cl\r
+ loop qmove\r
+testpathx:\r
+ xchg ah,cl\r
+testpath:\r
+ call PATHCHRCMP\r
+ jnz notspecial\r
+ or bh,4\r
+ test bh,2 ; If just hit a '/', cannot have ? or * yet\r
+ jnz badperr\r
+ mov [STARTEL],di ; New element\r
+ INC [STARTEL] ; Point to char after /\r
+ mov [ELCNT],0FFH ; Store of '/' sets it to 0\r
+ mov [ELPOS],0\r
+notspecial:\r
+ call move_char ; just an alphanum string\r
+anum_test:\r
+ lodsb\r
+\r
+ IF NOT KANJI\r
+ call UPCONV\r
+ ENDIF\r
+\r
+ call DELIM\r
+ je x_done\r
+ cmp al,0DH\r
+ je x_done\r
+ cmp al,[SWITCHAR]\r
+ je x_done\r
+ cmp al,bl\r
+ je x_done\r
+ cmp al,':' ; ':' allowed as trailer because\r
+ ; of devices\r
+ IF KANJI\r
+ je FOO15\r
+ jmp anum_char\r
+FOO15:\r
+ ELSE\r
+ jne anum_char\r
+ ENDIF\r
+\r
+ mov byte ptr [si-1],' ' ; Change the trailing ':' to a space\r
+ jmp short x_done\r
+\r
+badperr2:\r
+ mov dx,offset trangroup:BADCPMES\r
+ jmp CERROR\r
+\r
+badperr:\r
+ jmp BADCDERR\r
+\r
+cperror:\r
+ dec si ; adjust the pointer\r
+ pop di ; retrive token buffer address\r
+ popf ; restore flags\r
+ stc ; set the carry bit\r
+ return\r
+\r
+x_done:\r
+ dec si ; adjust for next round\r
+ jmp short out_token\r
+\r
+a_switch:\r
+ OR BH,1 ; Indicate switch\r
+ OR BP,GOTSWITCH\r
+ CALL SCANOFF\r
+ INC SI\r
+ cmp al,0DH\r
+ je cperror\r
+ call move_char ; store the character\r
+ CALL UPCONV\r
+ PUSH ES\r
+ PUSH DI\r
+ PUSH CX\r
+ PUSH CS\r
+ POP ES\r
+ASSUME ES:TRANGROUP\r
+ MOV DI,OFFSET TRANGROUP:SWLIST\r
+ MOV CX,SWCOUNT\r
+ REPNE SCASB\r
+ JNZ out_tokenp\r
+ MOV AX,1\r
+ SHL AX,CL\r
+ OR BP,AX\r
+out_tokenp:\r
+ POP CX\r
+ POP DI\r
+ POP ES\r
+ASSUME ES:NOTHING\r
+out_token:\r
+ mov al,0\r
+ stosb ; null at the end\r
+ pop di ; restore token buffer pointer\r
+ popf\r
+ clc ; clear carry flag\r
+ return\r
+\r
+move_char:\r
+ stosb ; store char in token buffer\r
+ inc cx ; increment char count\r
+ inc [ELCNT] ; increment element count for * substi\r
+ return\r
+\r
+TRANCODE ENDS\r
+ END\r
+\0\0\0\0\0\0\0\0\0\0\0\0\r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+;
+; ^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
--- /dev/null
+TITLE DEBASM\r
+\r
+; Code for the ASSEMble command in the debugger\r
+\r
+.xlist\r
+.xcref\r
+ INCLUDE DEBEQU.ASM\r
+ INCLUDE DOSSYM.ASM\r
+.cref\r
+.list\r
+\r
+\r
+CODE SEGMENT PUBLIC BYTE 'CODE'\r
+CODE ENDS\r
+\r
+CONST SEGMENT PUBLIC BYTE\r
+\r
+ EXTRN DBMN:BYTE,CSSAVE:WORD,REG8:BYTE,REG16:BYTE,SIZ8:BYTE\r
+ EXTRN SYNERR:BYTE,OPTAB:BYTE,MAXOP:ABS\r
+\r
+CONST ENDS\r
+\r
+DATA SEGMENT PUBLIC BYTE\r
+\r
+ EXTRN HINUM:WORD,LOWNUM:WORD,ASSEM_CNT:BYTE\r
+ EXTRN ASSEM1:BYTE,ASSEM2:BYTE,ASSEM3:BYTE,ASSEM4:BYTE,ASSEM5:BYTE\r
+ EXTRN ASSEM6:BYTE,OPBUF:BYTE,OPCODE:WORD,REGMEM:BYTE,INDEX:WORD\r
+ EXTRN ASMADD:BYTE,ASMSP:WORD,MOVFLG:BYTE,SEGFLG:BYTE,TSTFLG:BYTE\r
+ EXTRN NUMFLG:BYTE,DIRFLG:BYTE,BYTEBUF:BYTE,F8087:BYTE,DIFLG:BYTE\r
+ EXTRN SIFLG:BYTE,BXFLG:BYTE,BPFLG:BYTE,NEGFLG:BYTE,MEMFLG:BYTE\r
+ EXTRN REGFLG:BYTE,AWORD:BYTE,MIDFLD:BYTE,MODE:BYTE\r
+\r
+DATA ENDS\r
+\r
+DG GROUP CODE,CONST,DATA\r
+\r
+\r
+CODE SEGMENT PUBLIC BYTE 'CODE'\r
+ASSUME CS:DG,DS:DG,ES:DG,SS:DG\r
+\r
+ PUBLIC ASSEM\r
+ PUBLIC DB_OPER,DW_OPER,ASSEMLOOP,GROUP2,AA_OPER,DCINC_OPER\r
+ PUBLIC GROUP1,ESC_OPER,FGROUPP,FGROUPX,FDE_OPER,FGROUPZ\r
+ PUBLIC FD9_OPER,FGROUP,FDB_OPER,FGROUPB,FGROUP3,FGROUP3W\r
+ PUBLIC FGROUPDS,INT_OPER,IN_OPER,DISP8_OPER,JMP_OPER,NO_OPER\r
+ PUBLIC OUT_OPER,L_OPER,MOV_OPER,POP_OPER,PUSH_OPER,ROTOP\r
+ PUBLIC TST_OPER,EX_OPER,GET_DATA16,CALL_OPER\r
+\r
+ EXTRN INBUF:NEAR,SCANB:NEAR,SCANP:NEAR,GETHX:NEAR,GET_ADDRESS:NEAR\r
+ EXTRN DEFAULT:NEAR,OUTDI:NEAR,BLANK:NEAR,PRINTMES:NEAR,TAB:NEAR\r
+\r
+;\r
+; Line by line assembler\r
+;\r
+\r
+ASSEM:\r
+ MOV BP,[CSSAVE] ; Default code segment\r
+ MOV DI,OFFSET DG:ASMADD ; Default address\r
+ CALL DEFAULT\r
+ MOV WORD PTR [ASMADD],DX ; Displacement of disassembly\r
+ MOV WORD PTR [ASMADD+2],AX ; Segment\r
+ MOV [ASMSP],SP ; Save sp in case of error\r
+\r
+ASSEMLOOP:\r
+ MOV SP,[ASMSP] ; Restore sp in case of error\r
+ LES DI,DWORD PTR ASMADD ; GET PC\r
+ CALL OUTDI ; OUTPUT ADDRESS\r
+ CALL BLANK ; SKIP A SPACE\r
+ PUSH CS\r
+ POP ES\r
+ CALL INBUF ; GET A BUFFER\r
+ CALL SCANB\r
+ JNZ OPLOOK\r
+ RET ; IF EMPTY JUST RETURN\r
+;\r
+; At this point ds:si points to the opcode mnemonic...\r
+;\r
+OPLOOK: XOR CX,CX ; OP-CODE COUNT = 0\r
+ MOV DI,OFFSET DG:DBMN\r
+OPSCAN: XOR BX,BX\r
+OPLOOP: MOV AL,[DI+BX]\r
+ AND AL,7FH\r
+ CMP AL,[SI+BX]\r
+ JZ OPMATCH\r
+ INC CX ; INCREMENT OP-CODE COUNT\r
+ CMP CX,MAXOP ; CHECK FOR END OF LIST\r
+ JB OP1\r
+ JMP ASMERR\r
+OP1: INC DI ; SCAN FOR NEXT OP-CODE...\r
+ TEST BYTE PTR [DI-1],80H\r
+ JZ OP1\r
+ JMP OPSCAN\r
+\r
+OPMATCH:INC BX ; COMPARE NEXT CHAR\r
+ TEST BYTE PTR [DI+BX-1],80H ; ARE WE DONE?\r
+ JZ OPLOOP ; ..IF NOT KEEP COMPARING\r
+ XCHG BX,CX\r
+ MOV AX,BX\r
+ SHL AX,1\r
+ ADD AX,BX\r
+ ADD AX,OFFSET DG:OPTAB\r
+ MOV BX,AX\r
+;\r
+; CX = COUNT OF CHARS IN OPCODE\r
+; BX = POINTER INTO OPCODE TABLE\r
+;\r
+ XOR AX,AX\r
+ MOV BYTE PTR [AWORD],AL\r
+ MOV WORD PTR [MOVFLG],AX ; MOVFLG + TSTFLG\r
+ MOV BYTE PTR [SEGFLG],AL ; ZERO SEGMENT REGISTER FLAG\r
+ MOV AH,00001010B ; SET UP FOR AA_OPER\r
+ MOV AL,BYTE PTR [BX]\r
+ MOV WORD PTR [ASSEM1],AX\r
+ MOV BYTE PTR [ASSEM_CNT],1\r
+\r
+ ADD SI,CX ; SI POINTS TO OPERAND\r
+ JMP WORD PTR [BX+1]\r
+;\r
+; 8087 INSTRUCTIONS WITH NO OPERANDS\r
+;\r
+FDE_OPER:\r
+ MOV AH,0DEH\r
+ JMP SHORT FDX_OPER\r
+FDB_OPER:\r
+ MOV AH,0DBH\r
+ JMP SHORT FDX_OPER\r
+FD9_OPER:\r
+ MOV AH,0D9H\r
+FDX_OPER:\r
+ XCHG AL,AH\r
+ MOV WORD PTR [ASSEM1],AX\r
+;\r
+; aad and aam instrucions\r
+;\r
+AA_OPER:INC BYTE PTR [ASSEM_CNT]\r
+;\r
+; instructions with no operands\r
+;\r
+NO_OPER:\r
+ CALL STUFF_BYTES\r
+ CALL SCANP\r
+ PUSH CS\r
+ POP ES\r
+ JNZ OPLOOK\r
+ JMP ASSEMLOOP\r
+;\r
+; push instruction\r
+;\r
+PUSH_OPER:\r
+ MOV AH,11111111B\r
+ JMP SHORT POP1\r
+;\r
+; pop instruction\r
+;\r
+POP_OPER:\r
+ MOV AH,10001111B\r
+POP1: MOV [ASSEM1],AH\r
+ MOV [MIDFLD],AL\r
+ INC BYTE PTR [MOVFLG] ; ALLOW SEGMENT REGISTERS\r
+ MOV BYTE PTR [AWORD],2 ; MUST BE 16 BITS\r
+ CALL GETREGMEM\r
+ CALL BUILDIT\r
+ MOV AL,[DI+2]\r
+ CMP AL,11000000B\r
+ JB DATRET\r
+ MOV BYTE PTR [DI],1\r
+ CMP BYTE PTR [MOVFLG],2\r
+ JNZ POP2\r
+ AND AL,00011000B\r
+ OR AL,00000110B\r
+ CMP BYTE PTR [MIDFLD],0\r
+ JNZ POP3\r
+ OR AL,00000001B\r
+ JMP SHORT POP3\r
+\r
+POP2: AND AL,111B\r
+ OR AL,01010000B\r
+ CMP BYTE PTR [MIDFLD],0\r
+ JNZ POP3\r
+ OR AL,01011000B\r
+POP3: MOV BYTE PTR [DI+1],AL\r
+ JMP ASSEM_EXIT\r
+;\r
+; ret and retf instructions\r
+;\r
+GET_DATA16:\r
+ CALL SCANB\r
+ MOV CX,4\r
+ CALL GETHX\r
+ JC DATRET\r
+ DEC BYTE PTR [ASSEM1] ; CHANGE OP-CODE\r
+ ADD BYTE PTR [ASSEM_CNT],2 ; UPDATE LENGTH\r
+ MOV WORD PTR [ASSEM2],DX ; SAVE OFFSET\r
+DATRET: JMP ASSEM_EXIT\r
+;\r
+; int instruction\r
+;\r
+INT_OPER:\r
+ CALL SCANB\r
+ MOV CX,2\r
+ CALL GETHX\r
+ JC ERRV1\r
+ MOV AL,DL\r
+ CMP AL,3\r
+ JZ DATRET\r
+ INC BYTE PTR [ASSEM1]\r
+ JMP DISPX\r
+;\r
+; in instruction\r
+;\r
+IN_OPER:\r
+ CALL SCANB\r
+ LODSW\r
+ CMP AX,"A"+4C00H ; "AL"\r
+ JZ IN_1\r
+ CMP AX,"A"+5800H ; "AX"\r
+ JZ IN_0\r
+ERRV1: JMP ASMERR\r
+IN_0: INC BYTE PTR [ASSEM1]\r
+IN_1: CALL SCANP\r
+ CMP WORD PTR [SI],"D"+5800H ; "DX"\r
+ JZ DATRET\r
+ MOV CX,2\r
+ CALL GETHX\r
+ JC ERRV1\r
+ AND BYTE PTR [ASSEM1],11110111B\r
+ MOV AL,DL\r
+ JMP DISPX\r
+;\r
+; out instruction\r
+;\r
+OUT_OPER:\r
+ CALL SCANB\r
+ CMP WORD PTR [SI],"D"+5800H ; "DX"\r
+ JNZ OUT_0\r
+ INC SI\r
+ INC SI\r
+ JMP SHORT OUT_1\r
+OUT_0: AND BYTE PTR [ASSEM1],11110111B\r
+ MOV CX,2\r
+ CALL GETHX\r
+ JC ERRV1\r
+ INC BYTE PTR [ASSEM_CNT]\r
+ MOV BYTE PTR [ASSEM2],DL\r
+OUT_1: CALL SCANP\r
+ LODSW\r
+ CMP AX,"A"+4C00H ; "AL"\r
+ JZ DATRET\r
+ CMP AX,"A"+5800H ; "AX"\r
+ JNZ ERRV1\r
+ INC BYTE PTR [ASSEM1]\r
+ JMP DATRET\r
+\r
+;\r
+; jump instruction\r
+;\r
+JMP_OPER:\r
+ INC BYTE PTR [TSTFLG]\r
+;\r
+; call instruction\r
+;\r
+CALL_OPER:\r
+ MOV BYTE PTR [ASSEM1],11111111B\r
+ MOV BYTE PTR [MIDFLD],AL\r
+ CALL GETREGMEM\r
+ CALL BUILD3\r
+ CMP BYTE PTR [MEMFLG],0\r
+ JNZ CALLJ1\r
+ CMP BYTE PTR [REGMEM],-1\r
+ JZ CALLJ2\r
+;\r
+; INDIRECT JUMPS OR CALLS\r
+;\r
+CALLJ1: CMP BYTE PTR [AWORD],1\r
+ERRZ4: JZ ERRV1\r
+ CMP BYTE PTR [AWORD],4\r
+ JNZ ASMEX4\r
+ OR BYTE PTR [DI+2],1000B\r
+ JMP SHORT ASMEX4\r
+;\r
+; DIRECT JUMPS OR CALLS\r
+;\r
+CALLJ2: MOV AX,[LOWNUM]\r
+ MOV DX,[HINUM]\r
+ MOV BL,[AWORD]\r
+ CMP BYTE PTR [NUMFLG],0\r
+ JZ ERRZ4\r
+\r
+; BL = NUMBER OF BYTES IN JUMP\r
+; DX = OFFSET\r
+; AX = SEGMENT\r
+\r
+CALLJ3:\r
+ MOV BYTE PTR [DI],5\r
+ MOV [DI+2],AX\r
+ MOV [DI+4],DX\r
+\r
+ MOV AL,10011010B ; SET UP INTER SEGMENT CALL\r
+ CMP BYTE PTR [TSTFLG],0\r
+ JZ CALLJ5\r
+ MOV AL,11101010B ; FIX UP FOR JUMP\r
+CALLJ5: MOV BYTE PTR [DI+1],AL\r
+ CMP BL,4 ; FAR SPECIFIED?\r
+ JZ ASMEX4\r
+ OR BL,BL\r
+ JNZ CALLJ6\r
+ CMP DX,WORD PTR [ASMADD+2] ; DIFFERENT SEGMENT?\r
+ JNZ ASMEX4\r
+\r
+CALLJ6: MOV BYTE PTR [DI],3\r
+ MOV AL,11101000B ; SET UP FOR INTRASEGMENT\r
+ OR AL,[TSTFLG]\r
+ MOV BYTE PTR [DI+1],AL\r
+\r
+ MOV AX,[LOWNUM]\r
+ SUB AX,WORD PTR [ASMADD]\r
+ SUB AX,3\r
+ MOV [DI+2],AX\r
+ CMP BYTE PTR [TSTFLG],0\r
+ JZ ASMEX4\r
+ CMP BL,2\r
+ JZ ASMEX4\r
+\r
+ INC AX\r
+ MOV CX,AX\r
+ CBW\r
+ CMP AX,CX\r
+ JNZ ASMEX3\r
+ MOV BYTE PTR [DI+1],11101011B\r
+ MOV [DI+2],AX\r
+ DEC BYTE PTR [DI]\r
+ASMEX4: JMP ASSEM_EXIT\r
+;\r
+; conditional jumps and loop instructions\r
+;\r
+DISP8_OPER:\r
+ MOV BP,WORD PTR [ASMADD+2] ; GET DEFAULT DISPLACEMENT\r
+ CALL GET_ADDRESS\r
+ SUB DX,WORD PTR [ASMADD]\r
+ DEC DX\r
+ DEC DX\r
+ CALL CHKSIZ\r
+ CMP CL,1\r
+ JNZ ERRV2\r
+DISPX: INC [ASSEM_CNT]\r
+ MOV BYTE PTR [ASSEM2],AL\r
+ASMEX3: JMP ASSEM_EXIT\r
+;\r
+; lds, les, and lea instructions\r
+;\r
+L_OPER:\r
+ CALL SCANB\r
+ LODSW\r
+ MOV CX,8\r
+ MOV DI,OFFSET DG:REG16\r
+ CALL CHKREG\r
+ JZ ERRV2 ; CX = 0 MEANS NO REGISTER\r
+ SHL AL,1\r
+ SHL AL,1\r
+ SHL AL,1\r
+ MOV BYTE PTR [MIDFLD],AL\r
+ CALL SCANP\r
+ CALL GETREGMEM\r
+ CMP BYTE PTR [AWORD],0\r
+ JNZ ERRV2\r
+ CALL BUILD2\r
+ JMP SHORT ASEXV\r
+;\r
+; dec and inc instructions\r
+;\r
+DCINC_OPER:\r
+ MOV BYTE PTR [ASSEM1],11111110B\r
+ MOV BYTE PTR [MIDFLD],AL\r
+ CALL GETREGMEM\r
+ CALL BUILDIT\r
+ TEST BYTE PTR [DI+1],1\r
+ JZ ASEXV\r
+ MOV AL,[DI+2]\r
+ CMP AL,11000000B\r
+ JB ASEXV\r
+ AND AL,1111B\r
+ OR AL,01000000B\r
+ MOV [DI+1],AL\r
+ DEC BYTE PTR [DI]\r
+ASEXV: JMP ASSEM_EXIT\r
+\r
+ERRV2: JMP ASMERR\r
+;\r
+; esc instruction\r
+;\r
+ESC_OPER:\r
+ INC BYTE PTR [AWORD]\r
+ CALL SCANB\r
+ MOV CX,2\r
+ CALL GETHX\r
+ CMP DX,64\r
+ JAE ERRV2\r
+ CALL SCANP\r
+ MOV AX,DX\r
+ MOV CL,3\r
+ SHR DX,CL\r
+ OR [ASSEM1],DL\r
+ AND AL,111B\r
+ SHL AL,CL\r
+ JMP GROUPE\r
+;\r
+; 8087 arithmetic instuctions\r
+;\r
+\r
+;\r
+; OPERANDS THAT ALLOW THE REVERSE BIT\r
+;\r
+FGROUPDS:\r
+ CALL SETMID\r
+ CALL GETREGMEM2\r
+ CALL BUILD3\r
+ CMP BYTE PTR [MODE],11000000B\r
+ JNZ FGROUP1\r
+ MOV AL,[DIRFLG]\r
+ OR AL,AL\r
+ JZ FEXIT\r
+ OR [DI+1],AL ; IF D=1...\r
+ XOR BYTE PTR [DI+2],00001000B ; ...REVERSE THE SENSE OF R\r
+ JMP SHORT FEXIT\r
+\r
+;\r
+; Here when instruction could have memory or register operand\r
+;\r
+FGROUPX:\r
+ CALL SETMID ; THIS ENTRY POINT FOR 1 MEM OPER\r
+ MOV BYTE PTR [DIRFLG],0\r
+ JMP SHORT FGRP2\r
+FGROUP:\r
+ CALL SETMID\r
+FGRP2:\r
+ CALL GETREGMEM2\r
+ CALL BUILD3\r
+ CMP BYTE PTR [MODE],11000000B\r
+ JNZ FGROUP1\r
+ MOV AL,[DIRFLG]\r
+ OR [DI+1],AL\r
+ JMP SHORT FEXIT\r
+FGROUP1:CALL SETMF\r
+FEXIT: JMP ASSEM_EXIT\r
+;\r
+; These 8087 instructions require a memory operand\r
+;\r
+FGROUPB:\r
+ MOV AH,5 ; MUST BE TBYTE\r
+ JMP SHORT FGROUP3E\r
+FGROUP3W:\r
+ MOV AH,2 ; MUST BE WORD\r
+ JMP SHORT FGROUP3E\r
+FGROUP3:\r
+ MOV AH,-1 ; SIZE CANNOT BE SPECIFIED\r
+FGROUP3E:\r
+ MOV [AWORD],AH\r
+ CALL SETMID\r
+ CALL GETREGMEM\r
+ CMP BYTE PTR [MODE],11000000B\r
+ JZ FGRPERR\r
+FGRP:\r
+ CALL BUILD3\r
+ JMP FEXIT\r
+;\r
+; These 8087 instructions require a register operand\r
+;\r
+FGROUPP: ; 8087 POP OPERANDS\r
+ MOV BYTE PTR [AWORD],-1\r
+ CALL SETMID\r
+ CALL GETREGMEM2\r
+ CMP BYTE PTR [DIRFLG],0\r
+ JNZ FGRP\r
+FGRPERR:JMP ASMERR\r
+\r
+FGROUPZ: ; ENTRY POINT WHERE ARG MUST BE MEM\r
+ CALL SETMID\r
+ MOV BYTE PTR [DIRFLG],0\r
+ CALL GETREGMEM\r
+ CMP BYTE PTR [MODE],11000000B\r
+ JZ FGRPERR\r
+ CALL BUILD3\r
+ CALL SETMF\r
+ JMP FEXIT\r
+;\r
+; not, neg, mul, imul, div, and idiv instructions\r
+;\r
+GROUP1:\r
+ MOV [ASSEM1],11110110B\r
+GROUPE:\r
+ MOV BYTE PTR [MIDFLD],AL\r
+ CALL GETREGMEM\r
+ CALL BUILDIT\r
+ JMP FEXIT\r
+;\r
+; shift and rotate instructions\r
+;\r
+ROTOP:\r
+ MOV [ASSEM1],11010000B\r
+ MOV BYTE PTR [MIDFLD],AL\r
+ CALL GETREGMEM\r
+ CALL BUILDIT\r
+ CALL SCANP\r
+ CMP BYTE PTR [SI],"1"\r
+ JZ ASMEXV1\r
+ CMP WORD PTR [SI],"LC" ; CL\r
+ JZ ROTOP1\r
+ROTERR: JMP ASMERR\r
+ROTOP1: OR BYTE PTR [ASSEM1],10B\r
+ASMEXV1:JMP ASSEM_EXIT\r
+;\r
+; xchg instruction\r
+;\r
+EX_OPER:\r
+ INC BYTE PTR [TSTFLG]\r
+;\r
+; test instruction\r
+;\r
+TST_OPER:\r
+ INC BYTE PTR [TSTFLG]\r
+ JMP SHORT MOVOP\r
+;\r
+; mov instruction\r
+;\r
+MOV_OPER:\r
+ INC BYTE PTR [MOVFLG]\r
+MOVOP: XOR AX,AX\r
+ JMP SHORT GROUPM\r
+;\r
+; add, adc, sub, sbb, cmp, and, or, xor instructions\r
+;\r
+GROUP2:\r
+ MOV BYTE PTR [ASSEM1],10000000B\r
+GROUPM:\r
+ MOV BYTE PTR [MIDFLD],AL\r
+\r
+ PUSH AX\r
+ CALL GETREGMEM\r
+ CALL BUILD2\r
+ CALL SCANP ; POINT TO NEXT OPERAND\r
+ MOV AL,BYTE PTR [ASSEM_CNT]\r
+ PUSH AX\r
+ CALL GETREGMEM\r
+ POP AX\r
+ MOV BYTE PTR [DI],AL\r
+ POP AX\r
+ MOV BL,BYTE PTR [AWORD]\r
+ OR BL,BL\r
+ JZ ERRV5\r
+ DEC BL\r
+ AND BL,1\r
+ OR BYTE PTR [DI+1],BL\r
+\r
+ CMP BYTE PTR [MEMFLG],0\r
+ JNZ G21V\r
+ CMP BYTE PTR [NUMFLG],0 ; TEST FOR IMMEDIATE DATA\r
+ JZ G21V\r
+ CMP BYTE PTR [SEGFLG],0\r
+ JNZ ERRV5\r
+ CMP BYTE PTR [TSTFLG],2 ; XCHG?\r
+ JNZ IMMED1\r
+ERRV5: JMP ASMERR\r
+G21V: JMP GRP21\r
+;\r
+; SECOND OPERAND WAS IMMEDIATE\r
+;\r
+IMMED1: MOV AL,BYTE PTR [DI+2]\r
+ CMP BYTE PTR [MOVFLG],0\r
+ JZ NOTMOV1\r
+ AND AL,11000000B\r
+ CMP AL,11000000B\r
+ JNZ GRP23 ; not to a register\r
+ ; MOVE IMMEDIATE TO REGISTER\r
+ MOV AL,BYTE PTR [DI+1]\r
+ AND AL,1 ; SET SIZE\r
+ PUSHF\r
+ SHL AL,1\r
+ SHL AL,1\r
+ SHL AL,1\r
+ OR AL,BYTE PTR [DI+2] ; SET REGISTER\r
+ AND AL,00001111B\r
+ OR AL,10110000B\r
+ MOV BYTE PTR [DI+1],AL\r
+ MOV AX,WORD PTR [LOWNUM]\r
+ MOV WORD PTR [DI+2],AX\r
+ POPF\r
+ JZ EXVEC\r
+ INC BYTE PTR [DI]\r
+EXVEC: JMP GRPEX\r
+\r
+NOTMOV1:AND AL,11000111B\r
+ CMP AL,11000000B\r
+ JZ IMMACC ; IMMEDIATE TO ACC\r
+\r
+ CMP BYTE PTR [TSTFLG],0\r
+ JNZ GRP23\r
+ CMP BYTE PTR [MIDFLD],1*8 ; OR?\r
+ JZ GRP23\r
+ CMP BYTE PTR [MIDFLD],4*8 ; AND?\r
+ JZ GRP23\r
+ CMP BYTE PTR [MIDFLD],6*8 ; XOR?\r
+ JZ GRP23\r
+ TEST BYTE PTR [DI+1],1 ; TEST IF BYTE OPCODE\r
+ JZ GRP23\r
+\r
+ MOV AX,[LOWNUM]\r
+ MOV BX,AX\r
+ CBW\r
+ CMP AX,BX\r
+ JNZ GRP23 ; SMALL ENOUGH?\r
+\r
+ MOV BL,[DI]\r
+ DEC BYTE PTR [DI]\r
+ OR BYTE PTR [DI+1],10B\r
+ JMP SHORT GRP23X\r
+\r
+IMMACC: MOV AL,BYTE PTR [DI+1]\r
+ AND AL,1\r
+ CMP BYTE PTR [TSTFLG],0\r
+ JZ NOTTST\r
+ OR AL,10101000B\r
+ JMP SHORT TEST1\r
+NOTTST: OR AL,BYTE PTR [MIDFLD]\r
+ OR AL,100B\r
+TEST1: MOV BYTE PTR [DI+1],AL\r
+ DEC BYTE PTR [DI]\r
+\r
+GRP23: MOV BL,BYTE PTR [DI]\r
+GRP23X: XOR BH,BH\r
+ ADD BX,DI\r
+ INC BX\r
+ MOV AX,WORD PTR [LOWNUM]\r
+ MOV WORD PTR [BX],AX\r
+ INC BYTE PTR [DI]\r
+ TEST BYTE PTR [DI+1],1\r
+ JZ GRPEX1\r
+ INC BYTE PTR [DI]\r
+GRPEX1: JMP GRPEX\r
+;\r
+; SECOND OPERAND WAS MEMORY OR REGISTER\r
+;\r
+GRP21:\r
+ CMP BYTE PTR [SEGFLG],0\r
+ JZ GRP28 ; FIRST OPERAND WAS A SEGMENT REG\r
+ MOV AL,BYTE PTR [REGMEM]\r
+ TEST AL,10000B\r
+ JZ NOTSEG1\r
+ERRV3: JMP ASMERR\r
+NOTSEG1:AND AL,111B\r
+ OR BYTE PTR [DI+2],AL\r
+ AND BYTE PTR [DI+1],11111110B\r
+ CMP BYTE PTR [MEMFLG],0\r
+ JNZ G22V\r
+ JMP GRPEX\r
+\r
+GRP28: AND BYTE PTR [DI+2],11000111B\r
+ MOV AL,BYTE PTR [DI+1] ; GET FIRST OPCODE\r
+ AND AL,1B\r
+ CMP BYTE PTR [MOVFLG],0\r
+ JZ NOTMOV2\r
+ OR AL,10001000B\r
+ JMP SHORT MOV1\r
+NOTMOV2:CMP BYTE PTR [TSTFLG],0\r
+ JZ NOTTST2\r
+ OR AL,10000100B\r
+ CMP BYTE PTR [TSTFLG],2\r
+ JNZ NOTTST2\r
+ OR AL,10B\r
+NOTTST2:OR AL,BYTE PTR [MIDFLD] ; MIDFLD IS ZERO FOR TST\r
+MOV1: MOV BYTE PTR [DI+1],AL\r
+ CMP BYTE PTR [MEMFLG],0\r
+G22V: JNZ GRP22\r
+;\r
+; SECOND OPERAND WAS A REGISTER\r
+;\r
+ MOV AL,BYTE PTR [REGMEM]\r
+ TEST AL,10000B ; SEGMENT REGISTER?\r
+ JZ NOTSEG\r
+ CMP BYTE PTR [MOVFLG],0\r
+ JZ ERRV3\r
+ MOV BYTE PTR [DI+1],10001100B\r
+\r
+NOTSEG: AND AL,111B\r
+ SHL AL,1\r
+ SHL AL,1\r
+ SHL AL,1\r
+ OR BYTE PTR [DI+2],AL\r
+;\r
+; SPECIAL FORM OF THE EXCHANGE COMMAND\r
+;\r
+ CMP BYTE PTR [TSTFLG],2\r
+ JNZ GRPEX\r
+ TEST BYTE PTR [DI+1],1\r
+ JZ GRPEX\r
+ PUSH AX\r
+ MOV AL,BYTE PTR [DI+2]\r
+ AND AL,11000000B\r
+ CMP AL,11000000B ; MUST BE REGISTER TO REGISTER\r
+ POP AX\r
+ JB GRPEX\r
+ OR AL,AL\r
+ JZ SPECX\r
+ MOV AL,[DI+2]\r
+ AND AL,00000111B\r
+ JNZ GRPEX\r
+ MOV CL,3\r
+ SHR BYTE PTR [DI+2],CL\r
+SPECX: MOV AL,[DI+2]\r
+ AND AL,00000111B\r
+ OR AL,10010000B\r
+ MOV BYTE PTR [DI+1],AL\r
+ DEC BYTE PTR [DI]\r
+ JMP SHORT GRPEX\r
+;\r
+; SECOND OPERAND WAS A MEMORY REFERENCE\r
+;\r
+GRP22: CMP BYTE PTR [TSTFLG],0\r
+ JNZ TST2\r
+ OR BYTE PTR [DI+1],10B\r
+TST2: MOV AL,BYTE PTR [DI+2]\r
+ CMP AL,11000000B ; MUST BE A REGISTER\r
+ JB ASMERR\r
+ CMP BYTE PTR [SEGFLG],0\r
+ JZ GRP223\r
+ AND AL,00011000B\r
+ JMP SHORT GRP222\r
+GRP223: AND AL,111B\r
+ SHL AL,1\r
+ SHL AL,1\r
+ SHL AL,1\r
+GRP222: OR AL,BYTE PTR [MODE]\r
+ OR AL,BYTE PTR [REGMEM]\r
+ MOV BYTE PTR [DI+2],AL\r
+ MOV AX,WORD PTR [LOWNUM]\r
+ MOV WORD PTR [DI+3],AX\r
+GRPSIZ: MOV BYTE PTR [DI],2\r
+ MOV AL,BYTE PTR [DI+2]\r
+ AND AL,11000111B\r
+ CMP AL,00000110B\r
+ JZ GRP24\r
+ AND AL,11000000B\r
+ CMP AL,01000000B\r
+ JZ GRP25\r
+ CMP AL,10000000B\r
+ JNZ GRPEX\r
+GRP24: INC BYTE PTR [DI]\r
+GRP25: INC BYTE PTR [DI]\r
+\r
+GRPEX: CMP BYTE PTR [MOVFLG],0\r
+ JZ ASSEM_EXIT\r
+;\r
+; TEST FOR SPECIAL FORM OF MOV AX,[MEM] OR MOV [MEM],AX\r
+;\r
+ MOV AL,[DI+1] ; GET OP-CODE\r
+ AND AL,11111100B\r
+ CMP AL,10001000B\r
+ JNZ ASSEM_EXIT\r
+ CMP BYTE PTR [DI+2],00000110B ; MEM TO AX OR AX TO MEM\r
+ JNZ ASSEM_EXIT\r
+ MOV AL,BYTE PTR [DI+1]\r
+ AND AL,11B\r
+ XOR AL,10B\r
+ OR AL,10100000B\r
+ MOV BYTE PTR [DI+1],AL\r
+ DEC BYTE PTR [DI]\r
+ MOV AX,[DI+3]\r
+ MOV WORD PTR [DI+2],AX\r
+\r
+ASSEM_EXIT:\r
+ CALL STUFF_BYTES\r
+ JMP ASSEMLOOP\r
+\r
+; Assem error. SI points to character in the input buffer\r
+; which caused error. By subtracting from start of buffer,\r
+; we will know how far to tab over to appear directly below\r
+; it on the terminal. Then print "^ Error".\r
+\r
+ASMERR:\r
+ SUB SI,OFFSET DG:(BYTEBUF-10) ; How many char processed so far?\r
+ MOV CX,SI ; Parameter for TAB in CX\r
+ CALL TAB ; Directly below bad char\r
+ MOV SI,OFFSET DG:SYNERR ; Error message\r
+ CALL PRINTMES\r
+ JMP ASSEMLOOP\r
+;\r
+; assemble the different parts into an instruction\r
+;\r
+BUILDIT:\r
+ MOV AL,BYTE PTR [AWORD]\r
+ OR AL,AL\r
+ JNZ BUILD1\r
+BLDERR: JMP ASMERR\r
+\r
+BUILD1: DEC AL\r
+ OR BYTE PTR [DI+1],AL ; SET THE SIZE\r
+\r
+BUILD2: CMP BYTE PTR [NUMFLG],0 ; TEST FOR IMMEDIATE DATA\r
+ JZ BUILD3\r
+ CMP BYTE PTR [MEMFLG],0\r
+ JZ BLDERR\r
+\r
+BUILD3: MOV AL,BYTE PTR [REGMEM]\r
+ CMP AL,-1\r
+ JZ BLD1\r
+ TEST AL,10000B ; TEST IF SEGMENT REGISTER\r
+ JZ BLD1\r
+ CMP BYTE PTR [MOVFLG],0\r
+ JZ BLDERR\r
+ MOV WORD PTR [DI+1],10001110B\r
+ INC BYTE PTR [MOVFLG]\r
+ INC BYTE PTR [SEGFLG]\r
+ AND AL,00000011B\r
+ SHL AL,1\r
+ SHL AL,1\r
+ SHL AL,1\r
+ OR AL,BYTE PTR 11000000B\r
+ MOV BYTE PTR [DI+2],AL\r
+ RET\r
+\r
+BLD1: AND AL,00000111B\r
+BLD4: OR AL,BYTE PTR [MODE]\r
+ OR AL,BYTE PTR [MIDFLD]\r
+ MOV BYTE PTR [DI+2],AL\r
+ MOV AX,WORD PTR [LOWNUM]\r
+ MOV WORD PTR [DI+3],AX\r
+ RET\r
+\r
+GETREGMEM:\r
+ MOV BYTE PTR [F8087],0\r
+GETREGMEM2:\r
+ CALL SCANP\r
+ XOR AX,AX\r
+ MOV WORD PTR [LOWNUM],AX ; OFFSET\r
+ MOV WORD PTR [DIFLG],AX ; DIFLG+SIFLG\r
+ MOV WORD PTR [BXFLG],AX ; BXFLG+BPFLG\r
+ MOV WORD PTR [NEGFLG],AX ; NEGFLG+NUMFLG\r
+ MOV WORD PTR [MEMFLG],AX ; MEMFLG+REGFLG\r
+ DEC AL\r
+ CMP BYTE PTR [F8087],0\r
+ JZ PUTREG\r
+ MOV AL,1 ; DEFAULT 8087 REG IS 1\r
+PUTREG: MOV BYTE PTR [REGMEM],AL\r
+\r
+GETLOOP:MOV BYTE PTR [NEGFLG],0\r
+GETLOOP1:\r
+ MOV AX,WORD PTR [SI]\r
+ CMP AL,','\r
+ JZ GOMODE\r
+ CMP AL,13\r
+ JZ GOMODE\r
+ CMP AL,';'\r
+ JZ GOMODE\r
+ CMP AL,9\r
+ JZ GETTB\r
+ CMP AL,' '\r
+ JNZ GOGET\r
+GETTB: INC SI\r
+ JMP GETLOOP1\r
+GOGET: JMP GETINFO\r
+;\r
+; DETERMINE THE MODE BITS\r
+;\r
+GOMODE: MOV DI,OFFSET DG:ASSEM_CNT\r
+ MOV BYTE PTR [MODE],11000000B\r
+ MOV BYTE PTR [ASSEM_CNT],2\r
+ CMP BYTE PTR [MEMFLG],0\r
+ JNZ GOMODE1\r
+ MOV AL,[NUMFLG]\r
+ OR AL,[REGFLG]\r
+ JNZ MORET\r
+ OR AL,[F8087]\r
+ JZ ERRET\r
+ MOV AL,[DI+1]\r
+ OR AL,[DIRFLG]\r
+ CMP AL,0DCH ; ARITHMETIC?\r
+ JNZ MORET\r
+ MOV BYTE PTR [DI+1],0DEH ; ADD POP TO NULL ARG 8087\r
+MORET: RET\r
+ERRET: JMP ASMERR\r
+\r
+GOMODE1:MOV BYTE PTR [MODE],0\r
+ CMP BYTE PTR [NUMFLG],0\r
+ JZ GOREGMEM\r
+\r
+ MOV BYTE PTR [DI],4\r
+ MOV AX,WORD PTR [DIFLG]\r
+ OR AX,WORD PTR [BXFLG]\r
+ JNZ GOMODE2\r
+ MOV BYTE PTR [REGMEM],00000110B\r
+ RET\r
+\r
+GOMODE2:MOV BYTE PTR [MODE],10000000B\r
+ CALL CHKSIZ1\r
+ CMP CL,2\r
+ JZ GOREGMEM\r
+ DEC BYTE PTR [DI]\r
+ MOV BYTE PTR [MODE],01000000B\r
+;\r
+; DETERMINE THE REG-MEM BITS\r
+;\r
+GOREGMEM:\r
+ MOV BX,WORD PTR [BXFLG]\r
+ MOV CX,WORD PTR [DIFLG]\r
+ XOR DX,DX\r
+GOREG0:\r
+ MOV AL,BL ; BX\r
+ ADD AL,CH ; SI\r
+ CMP AL,2\r
+ JZ GOGO\r
+ INC DL\r
+ MOV AL,BL\r
+ ADD AL,CL\r
+ CMP AL,2\r
+ JZ GOGO\r
+ INC DL\r
+ MOV AL,BH\r
+ ADD AL,CH\r
+ CMP AL,2\r
+ JZ GOGO\r
+ INC DL\r
+ MOV AL,BH\r
+ ADD AL,CL\r
+ CMP AL,2\r
+ JZ GOGO\r
+ INC DL\r
+ OR CH,CH\r
+ JNZ GOGO\r
+ INC DL\r
+ OR CL,CL\r
+ JNZ GOGO\r
+ INC DL ; BP+DISP\r
+ OR BH,BH\r
+ JZ GOREG1\r
+ CMP BYTE PTR [MODE],0\r
+ JNZ GOGO\r
+ MOV BYTE PTR [MODE],01000000B\r
+ INC BYTE PTR [DI]\r
+ DEC DL\r
+GOREG1: INC DL ; BX+DISP\r
+GOGO: MOV BYTE PTR [REGMEM],DL\r
+ RET\r
+\r
+GETINFO:CMP AX,'EN' ; NEAR\r
+ JNZ GETREG3\r
+GETREG0:MOV DL,2\r
+GETRG01:CALL SETSIZ1\r
+GETREG1:CALL SCANS\r
+ MOV AX,WORD PTR [SI]\r
+ CMP AX,"TP" ; PTR\r
+ JZ GETREG1\r
+ JMP GETLOOP\r
+\r
+GETREG3:MOV CX,5\r
+ MOV DI,OFFSET DG:SIZ8\r
+ CALL CHKREG ; LOOK FOR BYTE, WORD, DWORD, ETC.\r
+ JZ GETREG41\r
+ INC AL\r
+ MOV DL,AL\r
+ JMP GETRG01\r
+\r
+GETREG41:\r
+ MOV AX,[SI]\r
+ CMP BYTE PTR [F8087],0\r
+ JZ GETREG5\r
+ CMP AX,"TS" ; 8087 STACK OPERAND\r
+ JNZ GETREG5\r
+ CMP BYTE PTR [SI+2],","\r
+ JNZ GETREG5\r
+ MOV BYTE PTR [DIRFLG],0\r
+ ADD SI,3\r
+ JMP GETLOOP\r
+\r
+GETREG5:CMP AX,"HS" ; SHORT\r
+ JZ GETREG1\r
+\r
+ CMP AX,"AF" ; FAR\r
+ JNZ GETRG51\r
+ CMP BYTE PTR [SI+2],"R"\r
+ JNZ GETRG51\r
+ ADD SI,3\r
+ MOV DL,4\r
+ JMP GETRG01\r
+\r
+GETRG51:CMP AL,'['\r
+ JNZ GETREG7\r
+GETREG6:INC BYTE PTR [MEMFLG]\r
+ INC SI\r
+ JMP GETLOOP\r
+\r
+GETREG7:CMP AL,']'\r
+ JZ GETREG6\r
+ CMP AL,'.'\r
+ JZ GETREG6\r
+ CMP AL,'+'\r
+ JZ GETREG6\r
+ CMP AL,'-'\r
+ JNZ GETREG8\r
+ INC BYTE PTR [NEGFLG]\r
+ INC SI\r
+ JMP GETLOOP1\r
+\r
+GETREG8: ; LOOK FOR A REGISTER\r
+ CMP BYTE PTR [F8087],0\r
+ JZ GETREGREG\r
+ CMP AX,"TS"\r
+ JNZ GETREGREG\r
+ CMP BYTE PTR [SI+2],"("\r
+ JNZ GETREGREG\r
+ CMP BYTE PTR [SI+4],")"\r
+ JNZ ASMPOP\r
+ MOV AL,[SI+3]\r
+ SUB AL,"0"\r
+ JB ASMPOP\r
+ CMP AL,7\r
+ JA ASMPOP\r
+ MOV [REGMEM],AL\r
+ INC BYTE PTR [REGFLG]\r
+ ADD SI,5\r
+ CMP WORD PTR [SI],"S,"\r
+ JNZ ZLOOP\r
+ CMP BYTE PTR [SI+2],"T"\r
+ JNZ ZLOOP\r
+ ADD SI,3\r
+ZLOOP: JMP GETLOOP\r
+\r
+GETREGREG:\r
+ MOV CX,20\r
+ MOV DI,OFFSET DG:REG8\r
+ CALL CHKREG\r
+ JZ GETREG12 ; CX = 0 MEANS NO REGISTER\r
+ MOV BYTE PTR [REGMEM],AL\r
+ INC BYTE PTR [REGFLG] ; TELL EVERYONE WE FOUND A REG\r
+ CMP BYTE PTR [MEMFLG],0\r
+ JNZ NOSIZE\r
+ CALL SETSIZ\r
+INCSI2: ADD SI,2\r
+ JMP GETLOOP\r
+\r
+NOSIZE: CMP AL,11 ; BX REGISTER?\r
+ JNZ GETREG9\r
+ CMP WORD PTR [BXFLG],0\r
+ JZ GETOK\r
+ASMPOP: JMP ASMERR\r
+\r
+GETOK: INC BYTE PTR [BXFLG]\r
+ JMP INCSI2\r
+GETREG9:\r
+ CMP AL,13 ; BP REGISTER?\r
+ JNZ GETREG10\r
+ CMP WORD PTR [BXFLG],0\r
+ JNZ ASMPOP\r
+ INC BYTE PTR [BPFLG]\r
+ JMP INCSI2\r
+GETREG10:\r
+ CMP AL,14 ; SI REGISTER?\r
+ JNZ GETREG11\r
+ CMP WORD PTR [DIFLG],0\r
+ JNZ ASMPOP\r
+ INC BYTE PTR [SIFLG]\r
+ JMP INCSI2\r
+GETREG11:\r
+ CMP AL,15 ; DI REGISTER?\r
+ JNZ ASMPOP ; *** error\r
+ CMP WORD PTR [DIFLG],0\r
+ JNZ ASMPOP\r
+ INC BYTE PTR [DIFLG]\r
+ JMP INCSI2\r
+\r
+GETREG12: ; BETTER BE A NUMBER!\r
+ MOV BP,WORD PTR [ASMADD+2]\r
+ CMP BYTE PTR [MEMFLG],0\r
+ JZ GTRG121\r
+GTRG119:MOV CX,4\r
+GTRG120:CALL GETHX\r
+ JMP SHORT GTRG122\r
+GTRG121:MOV CX,2\r
+ CMP BYTE PTR [AWORD],1\r
+ JZ GTRG120\r
+ CMP BYTE PTR [AWORD],CL\r
+ JZ GTRG119\r
+ CALL GET_ADDRESS\r
+GTRG122:JC ASMPOP\r
+ MOV [HINUM],AX\r
+ CMP BYTE PTR [NEGFLG],0\r
+ JZ GETREG13\r
+ NEG DX\r
+GETREG13:\r
+ ADD WORD PTR [LOWNUM],DX\r
+ INC BYTE PTR [NUMFLG]\r
+GETLOOPV:\r
+ JMP GETLOOP\r
+\r
+CHKREG: PUSH CX\r
+ INC CX\r
+ REPNZ SCASW\r
+ POP AX\r
+ SUB AX,CX\r
+ OR CX,CX\r
+ RET\r
+\r
+STUFF_BYTES:\r
+ PUSH SI\r
+ LES DI,DWORD PTR ASMADD\r
+ MOV SI,OFFSET DG:ASSEM_CNT\r
+ XOR AX,AX\r
+ LODSB\r
+ MOV CX,AX\r
+ JCXZ STUFFRET\r
+ REP MOVSB\r
+ MOV WORD PTR [ASMADD],DI\r
+STUFFRET:\r
+ POP SI\r
+ RET\r
+\r
+SETSIZ:\r
+ MOV DL,1\r
+ TEST AL,11000B ; 16 BIT OR SEGMENT REGISTER?\r
+ JZ SETSIZ1\r
+ INC DL\r
+SETSIZ1:\r
+ CMP BYTE PTR [AWORD],0\r
+ JZ SETSIZ2\r
+ CMP BYTE PTR [AWORD],DL\r
+ JZ SETSIZ2\r
+SETERR: POP DX\r
+ JMP ASMPOP\r
+SETSIZ2:MOV BYTE PTR [AWORD],DL\r
+ RET\r
+;\r
+; DETERMINE IF NUMBER IN AX:DX IS 8 BITS, 16 BITS, OR 32 BITS\r
+;\r
+CHKSIZ: MOV CL,4\r
+ CMP AX,BP\r
+ JNZ RETCHK\r
+CHKSIZ1:MOV CL,2\r
+ MOV AX,DX\r
+ CBW\r
+ CMP AX,DX\r
+ JNZ RETCHK\r
+ DEC CL\r
+RETCHK: RET\r
+;\r
+; get first character after first space\r
+;\r
+SCANS: CMP BYTE PTR [SI],13\r
+ JZ RETCHK\r
+ CMP BYTE PTR [SI],"["\r
+ JZ RETCHK\r
+ LODSB\r
+ CMP AL," "\r
+ JZ SCANBV\r
+ CMP AL,9\r
+ JNZ SCANS\r
+SCANBV: JMP SCANB\r
+;\r
+; Set up for 8087 op-codes\r
+;\r
+SETMID:\r
+ MOV BYTE PTR [ASSEM1],0D8H\r
+ MOV AH,AL\r
+ AND AL,111B ; SET MIDDLE BITS OF SECOND BYTE\r
+ SHL AL,1\r
+ SHL AL,1\r
+ SHL AL,1\r
+ MOV [MIDFLD],AL\r
+ MOV AL,AH ; SET LOWER BITS OF FIRST BYTE\r
+ SHR AL,1\r
+ SHR AL,1\r
+ SHR AL,1\r
+ OR [ASSEM1],AL\r
+ MOV BYTE PTR [F8087],1 ; INDICATE 8087 OPERAND\r
+ MOV BYTE PTR [DIRFLG],100B\r
+ RET\r
+;\r
+; Set MF bits for 8087 op-codes\r
+;\r
+SETMF: MOV AL,[AWORD]\r
+ TEST BYTE PTR [DI+1],10B\r
+ JNZ SETMFI\r
+ AND BYTE PTR [DI+1],11111001B ; CLEAR MF BITS\r
+ CMP AL,3 ; DWORD?\r
+ JZ SETMFRET\r
+ CMP AL,4 ; QWORD?\r
+ JZ SETMFRET2\r
+ TEST BYTE PTR [DI+1],1\r
+ JZ SETMFERR\r
+ CMP AL,5 ; TBYTE?\r
+ JZ SETMFRET3\r
+ JMP SHORT SETMFERR\r
+\r
+SETMFI: CMP AL,3 ; DWORD?\r
+ JZ SETMFRET\r
+ CMP AL,2 ; WORD?\r
+ JZ SETMFRET2\r
+ TEST BYTE PTR [DI+1],1\r
+ JZ SETMFERR\r
+ CMP AL,4 ; QWORD?\r
+ JNZ SETMFERR\r
+ OR BYTE PTR [DI+1],111B\r
+SETMFRET3:\r
+ OR BYTE PTR [DI+1],011B\r
+ OR BYTE PTR [DI+2],101000B\r
+ JMP SHORT SETMFRET\r
+SETMFRET2:\r
+ OR BYTE PTR [DI+1],100B\r
+SETMFRET:\r
+ RET\r
+\r
+SETMFERR:\r
+ JMP ASMPOP\r
+\r
+\r
+DW_OPER:\r
+ MOV BP,1\r
+ JMP SHORT DBEN\r
+\r
+DB_OPER:\r
+ XOR BP,BP\r
+DBEN: MOV DI,OFFSET DG:ASSEM_CNT\r
+ DEC BYTE PTR [DI]\r
+ INC DI\r
+DB0: XOR BL,BL\r
+ CALL SCANP\r
+ JNZ DB1\r
+DBEX: JMP ASSEM_EXIT\r
+DB1: OR BL,BL\r
+ JNZ DB3\r
+ MOV BH,BYTE PTR [SI]\r
+ CMP BH,"'"\r
+ JZ DB2\r
+ CMP BH,'"'\r
+ JNZ DB4\r
+DB2: INC SI\r
+ INC BL\r
+DB3: LODSB\r
+ CMP AL,13\r
+ JZ DBEX\r
+ CMP AL,BH\r
+ JZ DB0\r
+ STOSB\r
+ INC BYTE PTR [ASSEM_CNT]\r
+ JMP DB3\r
+DB4: MOV CX,2\r
+ CMP BP,0\r
+ JZ DB41\r
+ MOV CL,4\r
+DB41: PUSH BX\r
+ CALL GETHX\r
+ POP BX\r
+ JNC DB5\r
+ JMP ASMERR\r
+DB5: MOV AX,DX\r
+ CMP BP,0\r
+ JZ DB6\r
+ STOSW\r
+ INC BYTE PTR [ASSEM_CNT]\r
+ JMP SHORT DB7\r
+DB6: STOSB\r
+DB7: INC BYTE PTR [ASSEM_CNT]\r
+ JMP DB0\r
+\r
+CODE ENDS\r
+ END ASSEM\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+TITLE PART1 DEBUGGER COMMANDS\r
+\r
+; Routines to perform debugger commands except ASSEMble and UASSEMble\r
+\r
+.xlist\r
+.xcref\r
+ INCLUDE DEBEQU.ASM\r
+ INCLUDE DOSSYM.ASM\r
+.cref\r
+.list\r
+\r
+CODE SEGMENT PUBLIC BYTE 'CODE'\r
+CODE ENDS\r
+\r
+CONST SEGMENT PUBLIC BYTE\r
+\r
+ EXTRN SYNERR:BYTE\r
+\r
+ EXTRN DISPB:WORD,DSIZ:BYTE,DSSAVE:WORD\r
+ if sysver\r
+ EXTRN CIN:DWORD,PFLAG:BYTE\r
+ endif\r
+\r
+CONST ENDS\r
+\r
+DATA SEGMENT PUBLIC BYTE\r
+\r
+ EXTRN DEFLEN:WORD,BYTEBUF:BYTE,DEFDUMP:BYTE\r
+\r
+DATA ENDS\r
+\r
+DG GROUP CODE,CONST,DATA\r
+\r
+\r
+CODE SEGMENT PUBLIC BYTE 'CODE'\r
+ASSUME CS:DG,DS:DG,ES:DG,SS:DG\r
+\r
+\r
+ PUBLIC HEXCHK,GETHEX1,PRINT,DSRANGE,ADDRESS,HEXIN,PERROR\r
+ PUBLIC GETHEX,GET_ADDRESS,GETEOL,GETHX,PERR\r
+ PUBLIC PERR,MOVE,DUMP,ENTER,FILL,SEARCH,DEFAULT\r
+ if sysver\r
+ PUBLIC IN\r
+ EXTRN DISPREG:NEAR,DEVIOCALL:NEAR\r
+ endif\r
+\r
+ EXTRN OUT:NEAR,CRLF:NEAR,OUTDI:NEAR,OUTSI:NEAR,SCANP:NEAR\r
+ EXTRN SCANB:NEAR,BLANK:NEAR,TAB:NEAR,PRINTMES:NEAR,COMMAND:NEAR\r
+ EXTRN HEX:NEAR,BACKUP:NEAR\r
+\r
+\r
+DEBCOM1:\r
+\r
+; RANGE - Looks for parameters defining an address range.\r
+; The first parameter is the starting address. The second parameter\r
+; may specify the ending address, or it may be preceded by\r
+; "L" and specify a length (4 digits max), or it may be\r
+; omitted and a length of 128 bytes is assumed. Returns with\r
+; segment in AX, displacement in DX, and length in CX.\r
+\r
+DSRANGE:\r
+ MOV BP,[DSSAVE] ; Set default segment to DS\r
+ MOV [DEFLEN],128 ; And default length to 128 bytes\r
+RANGE:\r
+ CALL ADDRESS\r
+ PUSH AX ; Save segment\r
+ PUSH DX ; Save offset\r
+ CALL SCANP ; Get to next parameter\r
+ MOV AL,[SI]\r
+ CMP AL,"L" ; Length indicator?\r
+ JE GETLEN\r
+ MOV DX,[DEFLEN] ; Default length\r
+ CALL HEXIN ; Second parameter present?\r
+ JC GetDef ; If not, use default\r
+ MOV CX,4\r
+ CALL GETHEX ; Get ending address (same segment)\r
+ MOV CX,DX ; Low 16 bits of ending addr.\r
+ POP DX ; Low 16 bits of starting addr.\r
+ SUB CX,DX ; Compute range\r
+ JAE DSRNG2\r
+DSRNG1: JMP PERROR ; Negative range\r
+DSRNG2: INC CX ; Include last location\r
+ JCXZ DSRNG1 ; Wrap around error\r
+ POP AX ; Restore segment\r
+ RET\r
+GetDef:\r
+ POP CX ; get original offset\r
+ PUSH CX ; save it\r
+ NEG CX ; rest of segment\r
+ JZ RngRet ; use default\r
+ CMP CX,DX ; more room in segment?\r
+ JAE RngRet ; yes, use default\r
+ JMP RngRet1 ; no, length is in CX\r
+\r
+GETLEN:\r
+ INC SI ; Skip over "L" to length\r
+ MOV CX,4 ; Length may have 4 digits\r
+ CALL GETHEX ; Get the range\r
+RNGRET:\r
+ MOV CX,DX ; Length\r
+RngRet1:\r
+ POP DX ; Offset\r
+ MOV AX,CX\r
+ ADD AX,DX\r
+ JNC OKRET\r
+ CMP AX,1\r
+ JAE DSRNG1 ; Look for wrap error\r
+OKRET:\r
+ POP AX ; Segment\r
+ RET\r
+\r
+DEFAULT:\r
+; DI points to default address and CX has default length\r
+ CALL SCANP\r
+ JZ USEDEF ; Use default if no parameters\r
+ MOV [DEFLEN],CX\r
+ CALL RANGE\r
+ JMP GETEOL\r
+USEDEF:\r
+ MOV SI,DI\r
+ LODSW ; Get default displacement\r
+ MOV DX,AX\r
+ LODSW ; Get default segment\r
+ RET\r
+\r
+; Dump an area of memory in both hex and ASCII\r
+\r
+DUMP:\r
+ MOV BP,[DSSAVE]\r
+ MOV CX,DISPB\r
+ MOV DI,OFFSET DG:DEFDUMP\r
+ CALL DEFAULT ; Get range if specified\r
+ MOV DS,AX ; Set segment\r
+ MOV SI,DX ; SI has displacement in segment\r
+\r
+ IF ZIBO\r
+ PUSH SI ; save SI away\r
+ AND SI,0FFF0h ; convert to para number\r
+ CALL OutSI ; display location\r
+ POP SI ; get SI back\r
+ MOV AX,SI ; move offset\r
+ MOV AH,3 ; spaces per byte\r
+ AND AL,0Fh ; convert to real offset\r
+ MUL AH ; compute (AL+1)*3-1\r
+ OR AL,AL ; set flag\r
+ JZ InRow ; if xero go on\r
+ PUSH CX ; save count\r
+ MOV CX,AX ; move to convenient spot\r
+ CALL Tab ; move over\r
+ POP CX ; get back count\r
+ JMP InRow ; display line\r
+ ENDIF\r
+\r
+ROW:\r
+ CALL OUTSI ; Print address at start of line\r
+InRow:\r
+ PUSH SI ; Save address for ASCII dump\r
+ CALL BLANK\r
+BYTE0:\r
+ CALL BLANK ; Space between bytes\r
+BYTE1:\r
+ LODSB ; Get byte to dump\r
+ CALL HEX ; and display it\r
+ POP DX ; DX has start addr. for ASCII dump\r
+ DEC CX ; Drop loop count\r
+ JZ ToAscii ; If through do ASCII dump\r
+ MOV AX,SI\r
+ TEST AL,CS:(BYTE PTR DSIZ) ; On 16-byte boundary?\r
+ JZ ENDROW\r
+ PUSH DX ; Didn't need ASCII addr. yet\r
+ TEST AL,7 ; On 8-byte boundary?\r
+ JNZ BYTE0\r
+ MOV AL,"-" ; Mark every 8 bytes\r
+ CALL OUT\r
+ JMP SHORT BYTE1\r
+ENDROW:\r
+ CALL ASCII ; Show it in ASCII\r
+ JMP SHORT ROW ; Loop until count is zero\r
+ToAscii:\r
+ MOV AX,SI ; get offset\r
+ AND AL,0Fh ; real offset\r
+ JZ ASCII ; no loop if already there\r
+ SUB AL,10h ; remainder\r
+ NEG AL\r
+ MOV CL,3\r
+ MUL CL\r
+ MOV CX,AX ; number of chars to move\r
+ CALL Tab\r
+ASCII:\r
+ PUSH CX ; Save byte count\r
+ MOV AX,SI ; Current dump address\r
+ MOV SI,DX ; ASCII dump address\r
+ SUB AX,DX ; AX=length of ASCII dump\r
+ IF NOT ZIBO\r
+; Compute tab length. ASCII dump always appears on right side\r
+; screen regardless of how many bytes were dumped. Figure 3\r
+; characters for each byte dumped and subtract from 51, which\r
+; allows a minimum of 3 blanks after the last byte dumped.\r
+ MOV BX,AX\r
+ SHL AX,1 ; Length times 2\r
+ ADD AX,BX ; Length times 3\r
+ MOV CX,51\r
+ SUB CX,AX ; Amount to tab in CX\r
+ CALL TAB\r
+ MOV CX,BX ; ASCII dump length back in CX\r
+ ELSE\r
+ MOV CX,SI ; get starting point\r
+ DEC CX\r
+ AND CX,0Fh\r
+ INC CX\r
+ AND CX,0Fh\r
+ ADD CX,3 ; we have the correct number to tab\r
+ PUSH AX ; save count\r
+ CALL TAB\r
+ POP CX ; get count back\r
+ ENDIF\r
+ASCDMP:\r
+ LODSB ; Get ASCII byte to dump\r
+ AND AL,7FH ; ASCII uses 7 bits\r
+ CMP AL,7FH ; Don't try to print RUBOUT\r
+ JZ NOPRT\r
+ CMP AL," " ; Check for control characters\r
+ JNC PRIN\r
+NOPRT:\r
+ MOV AL,"." ; If unprintable character\r
+PRIN:\r
+ CALL OUT ; Print ASCII character\r
+ LOOP ASCDMP ; CX times\r
+ POP CX ; Restore overall dump length\r
+ MOV ES:WORD PTR [DEFDUMP],SI\r
+ MOV ES:WORD PTR [DEFDUMP+2],DS ; Save last address as default\r
+ CALL CRLF ; Print CR/LF and return\r
+ RET\r
+\r
+\r
+; Block move one area of memory to another. Overlapping moves\r
+; are performed correctly, i.e., so that a source byte is not\r
+; overwritten until after it has been moved.\r
+\r
+MOVE:\r
+ CALL DSRANGE ; Get range of source area\r
+ PUSH CX ; Save length\r
+ PUSH AX ; Save segment\r
+ PUSH DX ; Save source displacement\r
+ CALL ADDRESS ; Get destination address (same segment)\r
+ CALL GETEOL ; Check for errors\r
+ POP SI\r
+ MOV DI,DX ; Set dest. displacement\r
+ POP BX ; Source segment\r
+ MOV DS,BX\r
+ MOV ES,AX ; Destination segment\r
+ POP CX ; Length\r
+ CMP DI,SI ; Check direction of move\r
+ SBB AX,BX ; Extend the CMP to 32 bits\r
+ JB COPYLIST ; Move forward into lower mem.\r
+; Otherwise, move backward. Figure end of source and destination\r
+; areas and flip direction flag.\r
+ DEC CX\r
+ ADD SI,CX ; End of source area\r
+ ADD DI,CX ; End of destination area\r
+ STD ; Reverse direction\r
+ INC CX\r
+COPYLIST:\r
+ MOVSB ; Do at least 1 - Range is 1-10000H not 0-FFFFH\r
+ DEC CX\r
+ REP MOVSB ; Block move\r
+RET1: RET\r
+\r
+; Fill an area of memory with a list values. If the list\r
+; is bigger than the area, don't use the whole list. If the\r
+; list is smaller, repeat it as many times as necessary.\r
+\r
+FILL:\r
+ CALL DSRANGE ; Get range to fill\r
+ PUSH CX ; Save length\r
+ PUSH AX ; Save segment number\r
+ PUSH DX ; Save displacement\r
+ CALL LIST ; Get list of values to fill with\r
+ POP DI ; Displacement in segment\r
+ POP ES ; Segment\r
+ POP CX ; Length\r
+ CMP BX,CX ; BX is length of fill list\r
+ MOV SI,OFFSET DG:BYTEBUF ; List is in byte buffer\r
+ JCXZ BIGRNG\r
+ JAE COPYLIST ; If list is big, copy part of it\r
+BIGRNG:\r
+ SUB CX,BX ; How much bigger is area than list?\r
+ XCHG CX,BX ; CX=length of list\r
+ PUSH DI ; Save starting addr. of area\r
+ REP MOVSB ; Move list into area\r
+ POP SI\r
+; The list has been copied into the beginning of the\r
+; specified area of memory. SI is the first address\r
+; of that area, DI is the end of the copy of the list\r
+; plus one, which is where the list will begin to repeat.\r
+; All we need to do now is copy [SI] to [DI] until the\r
+; end of the memory area is reached. This will cause the\r
+; list to repeat as many times as necessary.\r
+ MOV CX,BX ; Length of area minus list\r
+ PUSH ES ; Different index register\r
+ POP DS ; requires different segment reg.\r
+ JMP SHORT COPYLIST ; Do the block move\r
+\r
+; Search a specified area of memory for given list of bytes.\r
+; Print address of first byte of each match.\r
+\r
+SEARCH:\r
+ CALL DSRANGE ; Get area to be searched\r
+ PUSH CX ; Save count\r
+ PUSH AX ; Save segment number\r
+ PUSH DX ; Save displacement\r
+ CALL LIST ; Get search list\r
+ DEC BX ; No. of bytes in list-1\r
+ POP DI ; Displacement within segment\r
+ POP ES ; Segment\r
+ POP CX ; Length to be searched\r
+ SUB CX,BX ; minus length of list\r
+SCAN:\r
+ MOV SI,OFFSET DG:BYTEBUF ; List kept in byte buffer\r
+ LODSB ; Bring first byte into AL\r
+DOSCAN:\r
+ SCASB ; Search for first byte\r
+ LOOPNE DOSCAN ; Do at least once by using LOOP\r
+ JNZ RET1 ; Exit if not found\r
+ PUSH BX ; Length of list minus 1\r
+ XCHG BX,CX\r
+ PUSH DI ; Will resume search here\r
+ REPE CMPSB ; Compare rest of string\r
+ MOV CX,BX ; Area length back in CX\r
+ POP DI ; Next search location\r
+ POP BX ; Restore list length\r
+ JNZ TEST ; Continue search if no match\r
+ DEC DI ; Match address\r
+ CALL OUTDI ; Print it\r
+ INC DI ; Restore search address\r
+ CALL CRLF\r
+TEST:\r
+ JCXZ RET1\r
+ JMP SHORT SCAN ; Look for next occurrence\r
+\r
+; Get the next parameter, which must be a hex number.\r
+; CX is maximum number of digits the number may have.\r
+\r
+GETHX:\r
+ CALL SCANP\r
+GETHX1:\r
+ XOR DX,DX ; Initialize the number\r
+ CALL HEXIN ; Get a hex digit\r
+ JC HXERR ; Must be one valid digit\r
+ MOV DL,AL ; First 4 bits in position\r
+GETLP:\r
+ INC SI ; Next char in buffer\r
+ DEC CX ; Digit count\r
+ CALL HEXIN ; Get another hex digit?\r
+ JC RETHX ; All done if no more digits\r
+ STC\r
+ JCXZ HXERR ; Too many digits?\r
+ SHL DX,1 ; Multiply by 16\r
+ SHL DX,1\r
+ SHL DX,1\r
+ SHL DX,1\r
+ OR DL,AL ; and combine new digit\r
+ JMP SHORT GETLP ; Get more digits\r
+\r
+GETHEX:\r
+ CALL GETHX ; Scan to next parameter\r
+ JMP SHORT GETHX2\r
+GETHEX1:\r
+ CALL GETHX1\r
+GETHX2: JC PERROR\r
+RETHX: CLC\r
+HXERR: RET\r
+\r
+\r
+; Check if next character in the input buffer is a hex digit\r
+; and convert it to binary if it is. Carry set if not.\r
+\r
+HEXIN:\r
+ MOV AL,[SI]\r
+\r
+; Check if AL has a hex digit and convert it to binary if it\r
+; is. Carry set if not.\r
+\r
+HEXCHK:\r
+ SUB AL,"0" ; Kill ASCII numeric bias\r
+ JC RET2\r
+ CMP AL,10\r
+ CMC\r
+ JNC RET2 ; OK if 0-9\r
+ AND AL,5FH\r
+ SUB AL,7 ; Kill A-F bias\r
+ CMP AL,10\r
+ JC RET2\r
+ CMP AL,16\r
+ CMC\r
+RET2: RET\r
+\r
+; Process one parameter when a list of bytes is\r
+; required. Carry set if parameter bad. Called by LIST.\r
+\r
+LISTITEM:\r
+ CALL SCANP ; Scan to parameter\r
+ CALL HEXIN ; Is it in hex?\r
+ JC STRINGCHK ; If not, could be a string\r
+ MOV CX,2 ; Only 2 hex digits for bytes\r
+ CALL GETHEX ; Get the byte value\r
+ MOV [BX],DL ; Add to list\r
+ INC BX\r
+GRET: CLC ; Parameter was OK\r
+ RET\r
+STRINGCHK:\r
+ MOV AL,[SI] ; Get first character of param\r
+ CMP AL,"'" ; String?\r
+ JZ STRING\r
+ CMP AL,'"' ; Either quote is all right\r
+ JZ STRING\r
+ STC ; Not string, not hex - bad\r
+ RET\r
+STRING:\r
+ MOV AH,AL ; Save for closing quote\r
+ INC SI\r
+STRNGLP:\r
+ LODSB ; Next char of string\r
+ CMP AL,13 ; Check for end of line\r
+ JZ PERR ; Must find a close quote\r
+ CMP AL,AH ; Check for close quote\r
+ JNZ STOSTRG ; Add new character to list\r
+ CMP AH,[SI] ; Two quotes in a row?\r
+ JNZ GRET ; If not, we're done\r
+ INC SI ; Yes - skip second one\r
+STOSTRG:\r
+ MOV [BX],AL ; Put new char in list\r
+ INC BX\r
+ JMP SHORT STRNGLP ; Get more characters\r
+\r
+; Get a byte list for ENTER, FILL or SEARCH. Accepts any number\r
+; of 2-digit hex values or character strings in either single\r
+; (') or double (") quotes.\r
+\r
+LIST:\r
+ MOV BX,OFFSET DG:BYTEBUF ; Put byte list in the byte buffer\r
+LISTLP:\r
+ CALL LISTITEM ; Process a parameter\r
+ JNC LISTLP ; If OK, try for more\r
+ SUB BX,OFFSET DG:BYTEBUF ; BX now has no. of bytes in list\r
+ JZ PERROR ; List must not be empty\r
+\r
+; Make sure there is nothing more on the line except for\r
+; blanks and carriage return. If there is, it is an\r
+; unrecognized parameter and an error.\r
+\r
+GETEOL:\r
+ CALL SCANB ; Skip blanks\r
+ JNZ PERROR ; Better be a RETURN\r
+RET3: RET\r
+\r
+; Command error. SI has been incremented beyond the\r
+; command letter so it must decremented for the\r
+; error pointer to work.\r
+\r
+PERR:\r
+ DEC SI\r
+\r
+; Syntax error. SI points to character in the input buffer\r
+; which caused error. By subtracting from start of buffer,\r
+; we will know how far to tab over to appear directly below\r
+; it on the terminal. Then print "^ Error".\r
+\r
+PERROR:\r
+ SUB SI,OFFSET DG:(BYTEBUF-1); How many char processed so far?\r
+ MOV CX,SI ; Parameter for TAB in CX\r
+ CALL TAB ; Directly below bad char\r
+ MOV SI,OFFSET DG:SYNERR ; Error message\r
+\r
+; Print error message and abort to command level\r
+\r
+PRINT:\r
+ CALL PRINTMES\r
+ JMP COMMAND\r
+\r
+; Gets an address in Segment:Displacement format. Segment may be omitted\r
+; and a default (kept in BP) will be used, or it may be a segment\r
+; register (DS, ES, SS, CS). Returns with segment in AX, OFFSET in DX.\r
+\r
+ADDRESS:\r
+ CALL GET_ADDRESS\r
+ JC PERROR\r
+ADRERR: STC\r
+ RET\r
+\r
+GET_ADDRESS:\r
+ CALL SCANP\r
+ MOV AL,[SI+1]\r
+ CMP AL,"S"\r
+ JZ SEGREG\r
+ MOV CX,4\r
+ CALL GETHX\r
+ JC ADRERR\r
+ MOV AX,BP ; Get default segment\r
+ CMP BYTE PTR [SI],":"\r
+ JNZ GETRET\r
+ PUSH DX\r
+GETDISP:\r
+ INC SI ; Skip over ":"\r
+ MOV CX,4\r
+ CALL GETHX\r
+ POP AX\r
+ JC ADRERR\r
+GETRET: CLC\r
+ RET\r
+SEGREG:\r
+ MOV AL,[SI]\r
+ MOV DI,OFFSET DG:SEGLET\r
+ MOV CX,4\r
+ REPNE SCASB\r
+ JNZ ADRERR\r
+ INC SI\r
+ INC SI\r
+ SHL CX,1\r
+ MOV BX,CX\r
+ CMP BYTE PTR [SI],":"\r
+ JNZ ADRERR\r
+ PUSH [BX+DSSAVE]\r
+ JMP SHORT GETDISP\r
+\r
+SEGLET DB "CSED"\r
+\r
+; Short form of ENTER command. A list of values from the\r
+; command line are put into memory without using normal\r
+; ENTER mode.\r
+\r
+GETLIST:\r
+ CALL LIST ; Get the bytes to enter\r
+ POP DI ; Displacement within segment\r
+ POP ES ; Segment to enter into\r
+ MOV SI,OFFSET DG:BYTEBUF ; List of bytes is in byte 2uffer\r
+ MOV CX,BX ; Count of bytes\r
+ REP MOVSB ; Enter that byte list\r
+ RET\r
+\r
+; Enter values into memory at a specified address. If the\r
+; line contains nothing but the address we go into "enter\r
+; mode", where the address and its current value are printed\r
+; and the user may change it if desired. To change, type in\r
+; new value in hex. Backspace works to correct errors. If\r
+; an illegal hex digit or too many digits are typed, the\r
+; bell is sounded but it is otherwise ignored. To go to the\r
+; next byte (with or without change), hit space bar. To\r
+; back CLDto a previous address, type "-". On\r
+; every 8-byte boundary a new line is started and the address\r
+; is printed. To terminate command, type carriage return.\r
+; Alternatively, the list of bytes to be entered may be\r
+; included on the original command line immediately following\r
+; the address. This is in regular LIST format so any number\r
+; of hex values or strings in quotes may be entered.\r
+\r
+ENTER:\r
+ MOV BP,[DSSAVE] ; Set default segment to DS\r
+ CALL ADDRESS\r
+ PUSH AX ; Save for later\r
+ PUSH DX\r
+ CALL SCANB ; Any more parameters?\r
+ JNZ GETLIST ; If not end-of-line get list\r
+ POP DI ; Displacement of ENTER\r
+ POP ES ; Segment\r
+GETROW:\r
+ CALL OUTDI ; Print address of entry\r
+ CALL BLANK ; Leave a space\r
+ CALL BLANK\r
+GETBYTE:\r
+ MOV AL,ES:[DI] ; Get current value\r
+ CALL HEX ; And display it\r
+PUTDOT:\r
+ MOV AL,"."\r
+ CALL OUT ; Prompt for new value\r
+ MOV CX,2 ; Max of 2 digits in new value\r
+ MOV DX,0 ; Intial new value\r
+GETDIG:\r
+ CALL IN ; Get digit from user\r
+ MOV AH,AL ; Save\r
+ CALL HEXCHK ; Hex digit?\r
+ XCHG AH,AL ; Need original for echo\r
+ JC NOHEX ; If not, try special command\r
+ MOV DH,DL ; Rotate new value\r
+ MOV DL,AH ; And include new digit\r
+ LOOP GETDIG ; At most 2 digits\r
+; We have two digits, so all we will accept now is a command.\r
+DWAIT:\r
+ CALL IN ; Get command character\r
+NOHEX:\r
+ CMP AL,8 ; Backspace\r
+ JZ BS\r
+ CMP AL,7FH ; RUBOUT\r
+ JZ RUB\r
+ CMP AL,"-" ; Back CLDto previous address\r
+ JZ PREV\r
+ CMP AL,13 ; All done with command?\r
+ JZ EOL\r
+ CMP AL," " ; Go to next address\r
+ JZ NEXT\r
+ MOV AL,8\r
+ CALL OUT ; Back CLDover illegal character\r
+ CALL BACKUP\r
+ JCXZ DWAIT\r
+ JMP SHORT GETDIG\r
+\r
+RUB:\r
+ MOV AL,8\r
+ CALL OUT\r
+BS:\r
+ CMP CL,2 ; CX=2 means nothing typed yet\r
+ JZ PUTDOT ; Put back the dot we backed CLDover\r
+ INC CL ; Accept one more character\r
+ MOV DL,DH ; Rotate out last digit\r
+ MOV DH,CH ; Zero this digit\r
+ CALL BACKUP ; Physical backspace\r
+ JMP SHORT GETDIG ; Get more digits\r
+\r
+; If new value has been entered, convert it to binary and\r
+; put into memory. Always bump pointer to next location\r
+\r
+STORE:\r
+ CMP CL,2 ; CX=2 means nothing typed yet\r
+ JZ NOSTO ; So no new value to store\r
+; Rotate DH left 4 bits to combine with DL and make a byte value\r
+ PUSH CX\r
+ MOV CL,4\r
+ SHL DH,CL\r
+ POP CX\r
+ OR DL,DH ; Hex is now converted to binary\r
+ MOV ES:[DI],DL ; Store new value\r
+NOSTO:\r
+ INC DI ; Prepare for next location\r
+ RET\r
+NEXT:\r
+ CALL STORE ; Enter new value\r
+ INC CX ; Leave a space plus two for\r
+ INC CX ; each digit not entered\r
+ CALL TAB\r
+ MOV AX,DI ; Next memory address\r
+ AND AL,7 ; Check for 8-byte boundary\r
+ JNZ GETBYTE ; Take 8 per line\r
+NEWROW:\r
+ CALL CRLF ; Terminate line\r
+ JMP GETROW ; Print address on new line\r
+PREV:\r
+ CALL STORE ; Enter the new value\r
+; DI has been bumped to next byte. Drop it 2 to go to previous addr\r
+ DEC DI\r
+ DEC DI\r
+ JMP SHORT NEWROW ; Terminate line after backing CLD\r
+\r
+EOL:\r
+ CALL STORE ; Enter the new value\r
+ JMP CRLF ; CR/LF and terminate\r
+\r
+; Console input of single character\r
+\r
+ IF SYSVER\r
+IN:\r
+ PUSH DS\r
+ PUSH SI\r
+ LDS SI,CS:[CIN]\r
+ MOV AH,4\r
+ CALL DEVIOCALL\r
+ POP SI\r
+ POP DS\r
+ CMP AL,3\r
+ JNZ NOTCNTC\r
+ INT 23H\r
+NOTCNTC:\r
+ CMP AL,'P'-'@'\r
+ JZ PRINTON\r
+ CMP AL,'N'-'@'\r
+ JZ PRINTOFF\r
+ CALL OUT\r
+ RET\r
+\r
+PRINTOFF:\r
+PRINTON:\r
+ NOT [PFLAG]\r
+ JMP SHORT IN\r
+\r
+ ELSE\r
+\r
+IN:\r
+ MOV AH,1\r
+ INT 21H\r
+ RET\r
+ ENDIF\r
+\r
+CODE ENDS\r
+ END DEBCOM1\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+TITLE PART2 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 NOTFND:BYTE,NOROOM:BYTE,DRVLET:BYTE,NOSPACE:BYTE,NAMBAD:BYTE
+ EXTRN TOOBIG:BYTE,ERRMES:BYTE
+ EXTRN EXEBAD:BYTE,HEXERR:BYTE,EXEWRT:BYTE,HEXWRT:BYTE
+ EXTRN EXECEMES:BYTE,WRTMES1:BYTE,WRTMES2:BYTE,ACCMES:BYTE
+
+ EXTRN FLAGTAB:WORD,EXEC_BLOCK:BYTE,COM_LINE:DWORD,COM_FCB1:DWORD
+ EXTRN COM_FCB2:DWORD,COM_SSSP:DWORD,COM_CSIP:DWORD,RETSAVE:WORD
+ EXTRN NEWEXEC:BYTE,HEADSAVE:WORD
+ EXTRN REGTAB:BYTE,TOTREG:BYTE,NOREGL:BYTE
+ EXTRN USER_PROC_PDB:WORD,STACK:BYTE,RSTACK:WORD,AXSAVE:WORD
+ EXTRN BXSAVE:WORD,DSSAVE:WORD,ESSAVE:WORD,CSSAVE:WORD,IPSAVE:WORD
+ EXTRN SSSAVE:WORD,CXSAVE:WORD,SPSAVE:WORD,FSAVE:WORD
+ EXTRN SREG:BYTE,SEGTAB:WORD,REGDIF:WORD,RDFLG:BYTE
+
+CONST ENDS
+
+DATA SEGMENT PUBLIC BYTE
+
+ EXTRN DEFDUMP:BYTE,TRANSADD:DWORD,INDEX:WORD,BUFFER:BYTE
+ EXTRN ASMADD:BYTE,DISADD:BYTE,NSEG:WORD,BPTAB:BYTE
+ EXTRN BRKCNT:WORD,TCOUNT:WORD,SWITCHAR:BYTE,XNXCMD:BYTE,XNXOPT:BYTE
+ EXTRN AWORD:BYTE,EXTPTR:WORD,HANDLE:WORD,PARSERR:BYTE
+
+DATA ENDS
+
+DG GROUP CODE,CONST,DATA
+
+
+CODE SEGMENT PUBLIC BYTE 'CODE'
+ASSUME CS:DG,DS:DG,ES:DG,SS:DG
+
+ PUBLIC DEFIO,SKIP_FILE,PREPNAME,DEBUG_FOUND
+ PUBLIC REG,COMPARE,GO,INPUT,LOAD
+ PUBLIC NAME,OUTPUT,TRACE,ZTRACE,DWRITE
+ if sysver
+ PUBLIC DISPREG
+ endif
+
+ EXTRN GETHEX:NEAR,GETEOL:NEAR
+ EXTRN CRLF:NEAR,BLANK:NEAR,OUT:NEAR
+ EXTRN OUTSI:NEAR,OUTDI:NEAR,INBUF:NEAR,SCANB:NEAR,SCANP:NEAR
+ EXTRN RPRBUF:NEAR,HEX:NEAR,OUT16:NEAR,DIGIT:NEAR
+ EXTRN COMMAND:NEAR,DISASLN:NEAR,SET_TERMINATE_VECTOR:NEAR
+ EXTRN RESTART:NEAR,DABORT:NEAR,TERMINATE:NEAR,DRVERR:NEAR
+ EXTRN FIND_DEBUG:NEAR,NMIInt:NEAR,NMIIntEnd:NEAR
+ EXTRN HEXCHK:NEAR,GETHEX1:NEAR,PRINT:NEAR,DSRANGE:NEAR
+ EXTRN ADDRESS:NEAR,HEXIN:NEAR,PERROR:NEAR
+
+
+DEBCOM2:
+DISPREG:
+ MOV SI,OFFSET DG:REGTAB
+ MOV BX,OFFSET DG:AXSAVE
+ MOV BYTE PTR TOTREG,13
+ MOV CH,0
+ MOV CL,NOREGL
+REPDISP:
+ SUB TOTREG,CL
+ CALL DISPREGLINE
+ CALL CRLF
+ MOV CH,0
+ MOV CL,NOREGL
+ CMP CL,TOTREG
+ JL REPDISP
+ MOV CL,TOTREG
+ CALL DISPREGLINE
+ CALL BLANK
+ CALL DISPFLAGS
+ CALL CRLF
+ MOV AX,[IPSAVE]
+ MOV WORD PTR [DISADD],AX
+ PUSH AX
+ MOV AX,[CSSAVE]
+ MOV WORD PTR [DISADD+2],AX
+ PUSH AX
+ MOV [NSEG],-1
+ CALL DISASLN
+ POP WORD PTR DISADD+2
+ POP WORD PTR DISADD
+ MOV AX,[NSEG]
+ CMP AL,-1
+ JZ CRLFJ
+ CMP AH,-1
+ JZ NOOVER
+ XCHG AL,AH
+NOOVER:
+ CBW
+ MOV BX,AX
+ SHL BX,1
+ MOV AX,WORD PTR [BX+SREG]
+ CALL OUT
+ XCHG AL,AH
+ CALL OUT
+ MOV AL,":"
+ CALL OUT
+ MOV DX,[INDEX]
+ CALL OUT16
+ MOV AL,"="
+ CALL OUT
+ MOV BX,[BX+SEGTAB]
+ PUSH DS
+ MOV DS,[BX]
+ MOV BX,DX
+ MOV DX,[BX]
+ POP DS
+ TEST BYTE PTR [AWORD],-1
+ JZ OUT8
+ CALL OUT16
+CRLFJ:
+ JMP CRLF
+OUT8:
+ MOV AL,DL
+ CALL HEX
+ JMP CRLF
+
+DISPREGJ:JMP DISPREG
+
+; Perform register dump if no parameters or set register if a
+; register designation is a parameter.
+
+REG:
+ CALL SCANP
+ JZ DISPREGJ
+ MOV DL,[SI]
+ INC SI
+ MOV DH,[SI]
+ CMP DH,13
+ JZ FLAG
+ INC SI
+ CALL GETEOL
+ CMP DH," "
+ JZ FLAG
+ MOV DI,OFFSET DG:REGTAB
+ XCHG AX,DX
+ PUSH CS
+ POP ES
+ MOV CX,REGTABLEN
+ REPNZ SCASW
+ JNZ BADREG
+ OR CX,CX
+ JNZ NOTPC
+ DEC DI
+ DEC DI
+ MOV AX,CS:[DI-2]
+NOTPC:
+ CALL OUT
+ MOV AL,AH
+ CALL OUT
+ CALL BLANK
+ PUSH DS
+ POP ES
+ LEA BX,[DI+REGDIF-2]
+ MOV DX,[BX]
+ CALL OUT16
+ CALL CRLF
+ MOV AL,":"
+ CALL OUT
+ CALL INBUF
+ CALL SCANB
+ JZ RET4
+ MOV CX,4
+ CALL GETHEX1
+ CALL GETEOL
+ MOV [BX],DX
+RET4: RET
+BADREG:
+ MOV AX,5200H+"B" ; BR ERROR
+ JMP ERR
+FLAG:
+ CMP DL,"F"
+ JNZ BADREG
+ CALL DISPFLAGS
+ MOV AL,"-"
+ CALL OUT
+ CALL INBUF
+ CALL SCANB
+ XOR BX,BX
+ MOV DX,[FSAVE]
+GETFLG:
+ LODSW
+ CMP AL,13
+ JZ SAVCHG
+ CMP AH,13
+ JZ FLGERR
+ MOV DI,OFFSET DG:FLAGTAB
+ MOV CX,32
+ PUSH CS
+ POP ES
+ REPNE SCASW
+ JNZ FLGERR
+ MOV CH,CL
+ AND CL,0FH
+ MOV AX,1
+ ROL AX,CL
+ TEST AX,BX
+ JNZ REPFLG
+ OR BX,AX
+ OR DX,AX
+ TEST CH,16
+ JNZ NEXFLG
+ XOR DX,AX
+NEXFLG:
+ CALL SCANP
+ JMP SHORT GETFLG
+DISPREGLINE:
+ LODS CS:WORD PTR [SI]
+ CALL OUT
+ MOV AL,AH
+ CALL OUT
+ MOV AL,"="
+ CALL OUT
+ MOV DX,[BX]
+ INC BX
+ INC BX
+ CALL OUT16
+ CALL BLANK
+ CALL BLANK
+ LOOP DISPREGLINE
+ RET
+REPFLG:
+ MOV AX,4600H+"D" ; DF ERROR
+FERR:
+ CALL SAVCHG
+ERR:
+ CALL OUT
+ MOV AL,AH
+ CALL OUT
+ MOV SI,OFFSET DG:ERRMES
+ JMP PRINT
+SAVCHG:
+ MOV [FSAVE],DX
+ RET
+FLGERR:
+ MOV AX,4600H+"B" ; BF ERROR
+ JMP SHORT FERR
+DISPFLAGS:
+ MOV SI,OFFSET DG:FLAGTAB
+ MOV CX,16
+ MOV DX,[FSAVE]
+DFLAGS:
+ LODS CS:WORD PTR [SI]
+ SHL DX,1
+ JC FLAGSET
+ MOV AX,CS:[SI+30]
+FLAGSET:
+ OR AX,AX
+ JZ NEXTFLG
+ CALL OUT
+ MOV AL,AH
+ CALL OUT
+ CALL BLANK
+NEXTFLG:
+ LOOP DFLAGS
+ RET
+
+; Input from the specified port and display result
+
+INPUT:
+ MOV CX,4 ; Port may have 4 digits
+ CALL GETHEX ; Get port number in DX
+ CALL GETEOL
+ IN AL,DX ; Variable port input
+ CALL HEX ; And display
+ JMP CRLF
+
+; Output a value to specified port.
+
+OUTPUT:
+ MOV CX,4 ; Port may have 4 digits
+ CALL GETHEX ; Get port number
+ PUSH DX ; Save while we get data
+ MOV CX,2 ; Byte output only
+ CALL GETHEX ; Get data to output
+ CALL GETEOL
+ XCHG AX,DX ; Output data in AL
+ POP DX ; Port in DX
+ OUT DX,AL ; Variable port output
+RET5: RET
+COMPARE:
+ CALL DSRANGE
+ PUSH CX
+ PUSH AX
+ PUSH DX
+ CALL ADDRESS ; Same segment
+ CALL GETEOL
+ POP SI
+ MOV DI,DX
+ MOV ES,AX
+ POP DS
+ POP CX ; Length
+ DEC CX
+ CALL COMP ; Do one less than total
+ INC CX ; CX=1 (do last one)
+COMP:
+ REPE CMPSB
+ JZ RET5
+; Compare error. Print address, value; value, address.
+ DEC SI
+ CALL OUTSI
+ CALL BLANK
+ CALL BLANK
+ LODSB
+ CALL HEX
+ CALL BLANK
+ CALL BLANK
+ DEC DI
+ MOV AL,ES:[DI]
+ CALL HEX
+ CALL BLANK
+ CALL BLANK
+ CALL OUTDI
+ INC DI
+ CALL CRLF
+ XOR AL,AL
+ JMP SHORT COMP
+
+ZTRACE:
+IF ZIBO
+; just like trace except skips OVER next INT or CALL.
+ CALL SETADD ; get potential starting point
+ CALL GETEOL ; check for end of line
+ MOV [TCOUNT],1 ; only a single go at it
+ MOV ES,[CSSAVE] ; point to instruction to execute
+ MOV DI,[IPSAVE] ; include offset in segment
+ XOR DX,DX ; where to place breakpoint
+ MOV AL,ES:[DI] ; get the opcode
+ CMP AL,11101000B ; direct intra call
+ JZ ZTrace3 ; yes, 3 bytes
+ CMP AL,10011010B ; direct inter call
+ JZ ZTrace5 ; yes, 5 bytes
+ CMP AL,11111111B ; indirect?
+ JZ ZTraceModRM ; yes, go figure length
+ CMP AL,11001100B ; short interrupt?
+ JZ ZTrace1 ; yes, 1 byte
+ CMP AL,11001101B ; long interrupt?
+ JZ ZTrace2 ; yes, 2 bytes
+ CMP AL,11100010B ; loop
+ JZ ZTrace2 ; 2 byter
+ CMP AL,11100001B ; loopz/loope
+ JZ ZTrace2 ; 2 byter
+ CMP AL,11100000B ; loopnz/loopne
+ JZ ZTrace2 ; 2 byter
+ AND AL,11111110B ; check for rep
+ CMP AL,11110010B ; perhaps?
+ JNZ Step ; can't do anything special, step
+ MOV AL,ES:[DI+1] ; next instruction
+ AND AL,11111110B ; ignore w bit
+ CMP AL,10100100B ; MOVS
+ JZ ZTrace2 ; two byte
+ CMP AL,10100110B ; CMPS
+ JZ ZTrace2 ; two byte
+ CMP AL,10101110B ; SCAS
+ JZ ZTrace2 ; two byte
+ CMP AL,10101100B ; LODS
+ JZ ZTrace2 ; two byte
+ CMP AL,10101010B ; STOS
+ JZ ZTrace2 ; two byte
+ JMP Step ; bogus, do single step
+
+ZTraceModRM:
+ MOV AL,ES:[DI+1] ; get next byte
+ AND AL,11111000B ; get mod and type
+ CMP AL,01010000B ; indirect intra 8 bit offset?
+ JZ ZTrace3 ; yes, three byte whammy
+ CMP AL,01011000B ; indirect inter 8 bit offset
+ JZ ZTrace3 ; yes, three byte guy
+ CMP AL,10010000B ; indirect intra 16 bit offset?
+ JZ ZTrace4 ; four byte offset
+ CMP AL,10011000B ; indirect inter 16 bit offset?
+ JZ ZTrace4 ; four bytes
+ JMP Step ; can't figger out what this is!
+ZTrace5:INC DX
+ZTrace4:INC DX
+ZTrace3:INC DX
+ZTrace2:INC DX
+ZTrace1:INC DX
+ ADD DI,DX ; offset to breakpoint instruction
+ MOV WORD PTR [BPTab],DI ; save offset
+ MOV WORD PTR [BPTab+2],ES ; save segment
+ MOV AL,ES:[DI] ; get next opcode byte
+ MOV BYTE PTR [BPTab+4],AL ; save it
+ MOV BYTE PTR ES:[DI],0CCh ; break point it
+ MOV [BrkCnt],1 ; only this breakpoint
+ JMP DExit ; start the operation!
+ ENDIF
+
+; Trace 1 instruction or the number of instruction specified
+; by the parameter using 8086 trace mode. Registers are all
+; set according to values in save area
+
+TRACE:
+ CALL SETADD
+ CALL SCANP
+ CALL HEXIN
+ MOV DX,1
+ JC STOCNT
+ MOV CX,4
+ CALL GETHEX
+STOCNT:
+ MOV [TCOUNT],DX
+ CALL GETEOL
+STEP:
+ MOV [BRKCNT],0
+ OR BYTE PTR [FSAVE+1],1
+DEXIT:
+IF NOT SYSVER
+ MOV BX,[USER_PROC_PDB]
+ MOV AH,SET_CURRENT_PDB
+ INT 21H
+ENDIF
+ PUSH DS
+ XOR AX,AX
+ MOV DS,AX
+ MOV WORD PTR DS:[12],OFFSET DG:BREAKFIX ; Set vector 3--breakpoint instruction
+ MOV WORD PTR DS:[14],CS
+ MOV WORD PTR DS:[4],OFFSET DG:REENTER ; Set vector 1--Single step
+ MOV WORD PTR DS:[6],CS
+ CLI
+
+ IF SETCNTC
+ MOV WORD PTR DS:[8CH],OFFSET DG:CONTC ; Set vector 23H (CTRL-C)
+ MOV WORD PTR DS:[8EH],CS
+ ENDIF
+
+ POP DS
+ MOV SP,OFFSET DG:STACK
+ POP AX
+ POP BX
+ POP CX
+ POP DX
+ POP BP
+ POP BP
+ POP SI
+ POP DI
+ POP ES
+ POP ES
+ POP SS
+ MOV SP,[SPSAVE]
+ PUSH [FSAVE]
+ PUSH [CSSAVE]
+ PUSH [IPSAVE]
+ MOV DS,[DSSAVE]
+ IRET
+STEP1:
+ CALL CRLF
+ CALL DISPREG
+ JMP SHORT STEP
+
+; Re-entry point from CTRL-C. Top of stack has address in 86-DOS for
+; continuing, so we must pop that off.
+
+CONTC:
+ ADD SP,6
+ JMP SHORT ReEnterReal
+
+; Re-entry point from breakpoint. Need to decrement instruction
+; pointer so it points to location where breakpoint actually
+; occured.
+
+BREAKFIX:
+ PUSH BP
+ MOV BP,SP
+ DEC WORD PTR [BP].OldIP
+ POP BP
+ JMP ReenterReal
+
+; Re-entry point from trace mode or interrupt during
+; execution. All registers are saved so they can be
+; displayed or modified.
+
+Interrupt_Frame STRUC
+OldBP DW ?
+OldIP DW ?
+OldCS DW ?
+OldF DW ?
+OlderIP DW ?
+OlderCS DW ?
+OlderF DW ?
+Interrupt_Frame ENDS
+
+REENTER:
+ PUSH BP
+ MOV BP,SP ; get a frame to address from
+ PUSH AX
+ MOV AX,CS
+ CMP AX,[BP].OldCS ; Did we interrupt ourselves?
+ JNZ GoReEnter ; no, go reenter
+ MOV AX,[BP].OldIP
+ CMP AX,OFFSET DG:NMIInt ; interrupt below NMI interrupt?
+ JB GoReEnter ; yes, go reenter
+ CMP [BP].OLDIP,OFFSET DG:NMIIntEnd
+ JAE GoReEnter ; interrupt above NMI interrupt?
+ POP AX ; restore state
+ POP BP
+ SUB SP,6 ; switch TRACE and NMI stack frames
+ PUSH BP
+ MOV BP,SP ; set up frame
+ PUSH AX ; get temp variable
+ MOV AX,[BP].OlderIP ; get NMI Vector
+ MOV [BP].OldIP,AX ; stuff in new NMI vector
+ MOV AX,[BP].OlderCS ; get NMI Vector
+ MOV [BP].OldCS,AX ; stuff in new NMI vector
+ MOV AX,[BP].OlderF ; get NMI Vector
+ AND AH,0FEh ; turn off Trace if present
+ MOV [BP].OldF,AX ; stuff in new NMI vector
+ MOV [BP].OlderF,AX
+ MOV [BP].OlderIP,OFFSET DG:ReEnter ; offset of routine
+ MOV [BP].OlderCS,CS ; and CS
+ POP AX
+ POP BP
+ IRET ; go try again
+GoReEnter:
+ POP AX
+ POP BP
+ReEnterReal:
+ MOV CS:[SPSAVE+SEGDIF],SP
+ MOV CS:[SSSAVE+SEGDIF],SS
+ MOV CS:[FSAVE],CS
+ MOV SS,CS:[FSAVE]
+ MOV SP,OFFSET DG:RSTACK
+ PUSH ES
+ PUSH DS
+ PUSH DI
+ PUSH SI
+ PUSH BP
+ DEC SP
+ DEC SP
+ PUSH DX
+ PUSH CX
+ PUSH BX
+ PUSH AX
+ PUSH SS
+ POP DS
+ MOV SS,[SSSAVE]
+ MOV SP,[SPSAVE]
+ POP [IPSAVE]
+ POP [CSSAVE]
+ POP AX
+ AND AH,0FEH ; turn off trace mode bit
+ MOV [FSAVE],AX
+ MOV [SPSAVE],SP
+ PUSH DS
+ POP ES
+ PUSH DS
+ POP SS
+ MOV SP,OFFSET DG:STACK
+ PUSH DS
+ XOR AX,AX
+ MOV DS,AX
+
+ IF SETCNTC
+ MOV WORD PTR DS:[8CH],OFFSET DG:DABORT ; Set Ctrl-C vector
+ MOV WORD PTR DS:[8EH],CS
+ ENDIF
+
+ POP DS
+ STI
+ CLD
+IF NOT SYSVER
+ MOV AH,GET_CURRENT_PDB
+ INT 21H
+ MOV [USER_PROC_PDB],BX
+ MOV BX,DS
+ MOV AH,SET_CURRENT_PDB
+ INT 21H
+ENDIF
+ DEC [TCOUNT]
+ JZ CheckDisp
+ JMP Step1
+CheckDisp:
+ MOV SI,OFFSET DG:BPTAB
+ MOV CX,[BRKCNT]
+ JCXZ SHOREG
+ PUSH ES
+CLEARBP:
+ LES DI,DWORD PTR [SI]
+ ADD SI,4
+ MOVSB
+ LOOP CLEARBP
+ POP ES
+SHOREG:
+ CALL CRLF
+ CALL DISPREG
+ JMP COMMAND
+
+SETADD:
+ MOV BP,[CSSAVE]
+ CALL SCANP
+ CMP BYTE PTR [SI],"="
+ JNZ RET$5
+ INC SI
+ CALL ADDRESS
+ MOV [CSSAVE],AX
+ MOV [IPSAVE],DX
+RET$5: RET
+
+; Jump to program, setting up registers according to the
+; save area. up to 10 breakpoint addresses may be specified.
+
+GO:
+ CALL SETADD
+ XOR BX,BX
+ MOV DI,OFFSET DG:BPTAB
+GO1:
+ CALL SCANP
+ JZ DEXEC
+ MOV BP,[CSSAVE]
+ CALL ADDRESS
+ MOV [DI],DX ; Save offset
+ MOV [DI+2],AX ; Save segment
+ ADD DI,5 ; Leave a little room
+ INC BX
+ CMP BX,1+BPMAX
+ JNZ GO1
+ MOV AX,5000H+"B" ; BP ERROR
+ JMP ERR
+DEXEC:
+ MOV [BRKCNT],BX
+ MOV CX,BX
+ JCXZ NOBP
+ MOV DI,OFFSET DG:BPTAB
+ PUSH DS
+SETBP:
+ LDS SI,ES:DWORD PTR [DI]
+ ADD DI,4
+ MOVSB
+ MOV BYTE PTR [SI-1],0CCH
+ LOOP SETBP
+ POP DS
+NOBP:
+ MOV [TCOUNT],1
+ JMP DEXIT
+
+SKIP_FILE:
+ MOV AH,CHAR_OPER
+ INT 21H
+ MOV [SWITCHAR],DL ; GET THE CURRENT SWITCH CHARACTER
+FIND_DELIM:
+ LODSB
+ CALL DELIM1
+ JZ GOTDELIM
+ CALL DELIM2
+ JNZ FIND_DELIM
+GOTDELIM:
+ DEC SI
+ RET
+
+PREPNAME:
+ MOV ES,DSSAVE
+ PUSH SI
+ MOV DI,81H
+COMTAIL:
+ LODSB
+ STOSB
+ CMP AL,13
+ JNZ COMTAIL
+ SUB DI,82H
+ XCHG AX,DI
+ MOV ES:(BYTE PTR [80H]),AL
+ POP SI
+ MOV DI,FCB
+ MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H
+ INT 21H
+ MOV BYTE PTR [AXSAVE],AL ; Indicate analysis of first parm
+ CALL SKIP_FILE
+ MOV DI,6CH
+ MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H
+ INT 21H
+ MOV BYTE PTR [AXSAVE+1],AL ; Indicate analysis of second parm
+RET23: RET
+
+
+; OPENS A XENIX PATHNAME SPECIFIED IN THE UNFORMATTED PARAMETERS
+; VARIABLE [XNXCMD] SPECIFIES WHICH COMMAND TO OPEN IT WITH
+;
+; VARIABLE [HANDLE] CONTAINS THE HANDLE
+; VARIABLE [EXTPTR] POINTS TO THE FILES EXTENSION
+
+DELETE_A_FILE:
+ MOV BYTE PTR [XNXCMD],UNLINK
+ JMP SHORT OC_FILE
+
+PARSE_A_FILE:
+ MOV BYTE PTR [XNXCMD],0
+ JMP SHORT OC_FILE
+
+EXEC_A_FILE:
+ MOV BYTE PTR [XNXCMD],EXEC
+ MOV BYTE PTR [XNXOPT],1
+ JMP SHORT OC_FILE
+
+OPEN_A_FILE:
+ MOV BYTE PTR [XNXCMD],OPEN
+ MOV BYTE PTR [XNXOPT],2 ; Try read write
+ CALL OC_FILE
+ JNC RET23
+ MOV BYTE PTR [XNXCMD],OPEN
+ MOV BYTE PTR [XNXOPT],0 ; Try read only
+ JMP SHORT OC_FILE
+
+CREATE_A_FILE:
+ MOV BYTE PTR [XNXCMD],CREAT
+
+OC_FILE:
+ PUSH DS
+ PUSH ES
+ PUSH AX
+ PUSH BX
+ PUSH CX
+ PUSH DX
+ PUSH SI
+ XOR AX,AX
+ MOV [EXTPTR],AX ; INITIALIZE POINTER TO EXTENSIONS
+ MOV AH,CHAR_OPER
+ INT 21H
+ MOV [SWITCHAR],DL ; GET THE CURRENT SWITCH CHARACTER
+
+ MOV SI,81H
+
+OPEN1: CALL GETCHRUP
+ CALL DELIM2 ; END OF LINE?
+ JZ OPEN4
+ CALL DELIM1 ; SKIP LEADING DELIMITERS
+ JZ OPEN1
+
+ MOV DX,SI ; SAVE POINTER TO BEGINNING
+ DEC DX
+OPEN2: CMP AL,"." ; LAST CHAR A "."?
+ JNZ OPEN3
+ MOV [EXTPTR],SI ; SAVE POINTER TO THE EXTENSION
+OPEN3: CALL GETCHRUP
+ CALL DELIM1 ; LOOK FOR END OF PATHNAME
+ JZ OPEN4
+ CALL DELIM2
+ JNZ OPEN2
+
+OPEN4: DEC SI ; POINT BACK TO LAST CHAR
+ PUSH [SI] ; SAVE TERMINATION CHAR
+ MOV BYTE PTR [SI],0 ; NULL TERMINATE THE STRING
+
+ MOV AL,[XNXOPT]
+ MOV AH,[XNXCMD] ; OPEN OR CREATE FILE
+ OR AH,AH
+ JZ OPNRET
+ MOV BX,OFFSET DG:EXEC_BLOCK
+ XOR CX,CX
+ INT 21H
+ MOV CS:[HANDLE],AX ; SAVE ERROR CODE OR HANDLE
+
+OPNRET: POP [SI]
+
+ POP SI
+ POP DX
+ POP CX
+ POP BX
+ POP AX
+ POP ES
+ POP DS
+ RET
+
+GETCHRUP:
+ LODSB
+ CMP AL,"a"
+ JB GCUR
+ CMP AL,"z"
+ JA GCUR
+ SUB AL,32
+ MOV [SI-1],AL
+GCUR: RET
+
+DELIM0: CMP AL,"["
+ JZ LIMRET
+DELIM1: CMP AL," " ; SKIP THESE GUYS
+ JZ LIMRET
+ CMP AL,";"
+ JZ LIMRET
+ CMP AL,"="
+ JZ LIMRET
+ CMP AL,9
+ JZ LIMRET
+ CMP AL,","
+ JMP SHORT LIMRET
+
+DELIM2: CMP AL,[SWITCHAR] ; STOP ON THESE GUYS
+ JZ LIMRET
+ CMP AL,13
+LIMRET: RET
+
+NAME:
+ CALL PREPNAME
+ MOV AL,BYTE PTR AXSAVE
+ MOV PARSERR,AL
+ PUSH ES
+ POP DS
+ PUSH CS
+ POP ES
+ MOV SI,FCB ; DS:SI points to user FCB
+ MOV DI,SI ; ES:DI points to DEBUG FCB
+ MOV CX,82
+ REP MOVSW
+RET6: RET
+
+BADNAM:
+ MOV DX,OFFSET DG:NAMBAD
+ JMP RESTART
+
+IFHEX:
+ CMP BYTE PTR [PARSERR],-1 ; Invalid drive specification?
+ JZ BADNAM
+ CALL PARSE_A_FILE
+ MOV BX,[EXTPTR]
+ CMP WORD PTR DS:[BX],"EH" ; "HE"
+ JNZ RET6
+ CMP BYTE PTR DS:[BX+2],"X"
+ RET
+
+IFEXE:
+ PUSH BX
+ MOV BX,[EXTPTR]
+ CMP WORD PTR DS:[BX],"XE" ; "EX"
+ JNZ RETIF
+ CMP BYTE PTR DS:[BX+2],"E"
+RETIF: POP BX
+ RET
+
+LOAD:
+ MOV BYTE PTR [RDFLG],READ
+ JMP SHORT DSKIO
+
+DWRITE:
+ MOV BYTE PTR [RDFLG],WRITE
+DSKIO:
+ MOV BP,[CSSAVE]
+ CALL SCANB
+ JNZ PRIMIO
+ JMP DEFIO
+PRIMIO: CALL ADDRESS
+ CALL SCANB
+ JNZ PRMIO
+ JMP FILEIO
+PRMIO: PUSH AX ; Save segment
+ MOV BX,DX ; Put displacement in proper register
+ MOV CX,1
+ CALL GETHEX ; Drive number must be 1 digit
+ PUSH DX
+ MOV CX,4
+ CALL GETHEX ; Logical record number
+ PUSH DX
+ MOV CX,3
+ CALL GETHEX ; Number of records
+ CALL GETEOL
+ MOV CX,DX
+ POP DX ; Logical record number
+ POP AX ; Drive number
+ CBW ; Turn off verify after write
+ MOV BYTE PTR DRVLET,AL ; Save drive in case of error
+ PUSH AX
+ PUSH BX
+ PUSH DX
+ MOV DL,AL
+ INC DL
+ MOV AH,GET_DPB
+ INT 21H
+ POP DX
+ POP BX
+ OR AL,AL
+ POP AX
+ POP DS ; Segment of transfer
+ JNZ DRVERRJ
+ CMP CS:BYTE PTR [RDFLG],WRITE
+ JZ ABSWRT
+ INT 25H ; Primitive disk read
+ JMP SHORT ENDABS
+
+ABSWRT:
+ INT 26H ; Primitive disk write
+ENDABS:
+ JNC RET0
+DRVERRJ: JMP DRVERR
+
+RET0:
+ POPF
+ RET
+
+DEFIO:
+ MOV AX,[CSSAVE] ; Default segment
+ MOV DX,100H ; Default file I/O offset
+ CALL IFHEX
+ JNZ EXECHK
+ XOR DX,DX ; If HEX file, default OFFSET is zero
+HEX2BINJ:JMP HEX2BIN
+
+FILEIO:
+; AX and DX have segment and offset of transfer, respectively
+ CALL IFHEX
+ JZ HEX2BINJ
+EXECHK:
+ CALL IFEXE
+ JNZ BINFIL
+ CMP BYTE PTR [RDFLG],READ
+ JZ EXELJ
+ MOV DX,OFFSET DG:EXEWRT
+ JMP RESTART ; Can't write .EXE files
+
+BINFIL:
+ CMP BYTE PTR [RDFLG],WRITE
+ JZ BINLOAD
+ CMP WORD PTR DS:[BX],4F00H + "C" ; "CO"
+ JNZ BINLOAD
+ CMP BYTE PTR DS:[BX+2],"M"
+ JNZ BINLOAD
+EXELJ:
+ DEC SI
+ CMP DX,100H
+ JNZ PRER
+ CMP AX,[CSSAVE]
+ JZ OAF
+PRER: JMP PERROR
+OAF: CALL OPEN_A_FILE
+ JNC GDOPEN
+ MOV AX,exec_file_not_found
+ JMP EXECERR
+
+GDOPEN: XOR DX,DX
+ XOR CX,CX
+ MOV BX,[HANDLE]
+ MOV AL,2
+ MOV AH,LSEEK
+ INT 21H
+ CALL IFEXE ; SUBTRACT 512 BYTES FOR EXE
+ JNZ BIN2 ; FILE LENGTH BECAUSE OF
+ SUB AX,512 ; THE HEADER
+BIN2: MOV [BXSAVE],DX ; SET UP FILE SIZE IN DX:AX
+ MOV [CXSAVE],AX
+ MOV AH,CLOSE
+ INT 21H
+ JMP EXELOAD
+
+NO_MEM_ERR:
+ MOV DX,OFFSET DG:TOOBIG
+ MOV AH,STD_CON_STRING_OUTPUT
+ INT 21H
+ JMP COMMAND
+
+WRTFILEJ: JMP WRTFILE
+NOFILEJ: JMP NOFILE
+
+BINLOAD:
+ PUSH AX
+ PUSH DX
+ CMP BYTE PTR [RDFLG],WRITE
+ JZ WRTFILEJ
+ CALL OPEN_A_FILE
+ JC NOFILEJ
+ MOV BX,[HANDLE]
+ MOV AX,(LSEEK SHL 8) OR 2
+ XOR DX,DX
+ MOV CX,DX
+ INT 21H ; GET SIZE OF FILE
+ MOV SI,DX
+ MOV DI,AX ; SIZE TO SI:DI
+ MOV AX,(LSEEK SHL 8) OR 0
+ XOR DX,DX
+ MOV CX,DX
+ INT 21H ; RESET POINTER BACK TO BEGINNING
+ POP AX
+ POP BX
+ PUSH BX
+ PUSH AX ; TRANS ADDR TO BX:AX
+ ADD AX,15
+ MOV CL,4
+ SHR AX,CL
+ ADD BX,AX ; Start of transfer rounded up to seg
+ MOV DX,SI
+ MOV AX,DI ; DX:AX is size
+ MOV CX,16
+ DIV CX
+ OR DX,DX
+ JZ NOREM
+ INC AX
+NOREM: ; AX is number of paras in transfer
+ ADD AX,BX ; AX is first seg that need not exist
+ CMP AX,CS:[PDB_block_len]
+ JA NO_MEM_ERR
+ MOV CXSAVE,DI
+ MOV BXSAVE,SI
+ POP DX
+ POP AX
+
+RDWR:
+; AX:DX is disk transfer address (segment:offset)
+; SI:DI is length (32-bit number)
+
+RDWRLOOP:
+ MOV BX,DX ; Make a copy of the offset
+ AND DX,000FH ; Establish the offset in 0H-FH range
+ MOV CL,4
+ SHR BX,CL ; Shift offset and
+ ADD AX,BX ; Add to segment register to get new Seg:offset
+ PUSH AX
+ PUSH DX ; Save AX,DX register pair
+ MOV WORD PTR [TRANSADD],DX
+ MOV WORD PTR [TRANSADD+2],AX
+ MOV CX,0FFF0H ; Keep request in segment
+ OR SI,SI ; Need > 64K?
+ JNZ BIGRDWR
+ MOV CX,DI ; Limit to amount requested
+BIGRDWR:
+ PUSH DS
+ PUSH BX
+ MOV BX,[HANDLE]
+ MOV AH,[RDFLG]
+ LDS DX,[TRANSADD]
+ INT 21H ; Perform read or write
+ POP BX
+ POP DS
+ JC BADWR
+ CMP BYTE PTR [RDFLG],WRITE
+ JNZ GOODR
+ CMP CX,AX
+ JZ GOODR
+BADWR: MOV CX,AX
+ STC
+ POP DX ; READ OR WRITE BOMBED OUT
+ POP AX
+ RET
+
+GOODR:
+ MOV CX,AX
+ SUB DI,CX ; Request minus amount transferred
+ SBB SI,0 ; Ripple carry
+ OR CX,CX ; End-of-file?
+ POP DX ; Restore DMA address
+ POP AX
+ JZ RET8
+ ADD DX,CX ; Bump DMA address by transfer length
+ MOV BX,SI
+ OR BX,DI ; Finished with request
+ JNZ RDWRLOOP
+RET8: CLC ; End-of-file not reached
+ RET
+
+NOFILE:
+ MOV DX,OFFSET DG:NOTFND
+RESTARTJMP:
+ JMP RESTART
+
+WRTFILE:
+ CALL CREATE_A_FILE ; Create file we want to write to
+ MOV DX,OFFSET DG:NOROOM ; Creation error - report error
+ JC RESTARTJMP
+ MOV SI,BXSAVE ; Get high order number of bytes to transfer
+ CMP SI,000FH
+ JLE WRTSIZE ; Is bx less than or equal to FH
+ XOR SI,SI ; Ignore BX if greater than FH - set to zero
+WRTSIZE:
+ MOV DX,OFFSET DG:WRTMES1 ; Print number bytes we are writing
+ CALL RPRBUF
+ OR SI,SI
+ JZ NXTBYT
+ MOV AX,SI
+ CALL DIGIT
+NXTBYT:
+ MOV DX,CXSAVE
+ MOV DI,DX
+ CALL OUT16 ; Amount to write is SI:DI
+ MOV DX,OFFSET DG:WRTMES2
+ CALL RPRBUF
+ POP DX
+ POP AX
+ CALL RDWR
+ JNC CLSFLE
+ CALL CLSFLE
+ CALL DELETE_A_FILE
+ MOV DX,OFFSET DG:NOSPACE
+ JMP RESTARTJMP
+ CALL CLSFLE
+ JMP COMMAND
+
+CLSFLE:
+ MOV AH,CLOSE
+ MOV BX,[HANDLE]
+ INT 21H
+ RET
+
+EXELOAD:
+ POP [RETSAVE] ; Suck up return addr
+ INC BYTE PTR [NEWEXEC]
+ MOV BX,[USER_PROC_PDB]
+ MOV AX,DS
+ CMP AX,BX
+ JZ DEBUG_CURRENT
+ JMP FIND_DEBUG
+
+DEBUG_CURRENT:
+ MOV AX,[DSSAVE]
+DEBUG_FOUND:
+ MOV BYTE PTR [NEWEXEC],0
+ MOV [HEADSAVE],AX
+ PUSH [RETSAVE] ; Get the return address back
+ PUSH AX
+ MOV BX,CS
+ SUB AX,BX
+ PUSH CS
+ POP ES
+ MOV BX,AX
+ ADD BX,10H ; RESERVE HEADER
+ MOV AH,SETBLOCK
+ INT 21H
+ POP AX
+ MOV WORD PTR [COM_LINE+2],AX
+ MOV WORD PTR [COM_FCB1+2],AX
+ MOV WORD PTR [COM_FCB2+2],AX
+
+ CALL EXEC_A_FILE
+ JC EXECERR
+ CALL SET_TERMINATE_VECTOR ; Reset int 22
+ MOV AH,GET_CURRENT_PDB
+ INT 21H
+ MOV [USER_PROC_PDB],BX
+ MOV [DSSAVE],BX
+ MOV [ESSAVE],BX
+ MOV ES,BX
+ MOV WORD PTR ES:[PDB_exit],OFFSET DG:TERMINATE
+ MOV WORD PTR ES:[PDB_exit+2],DS
+ LES DI,[COM_CSIP]
+ MOV [CSSAVE],ES
+ MOV [IPSAVE],DI
+ MOV WORD PTR [DISADD+2],ES
+ MOV WORD PTR [DISADD],DI
+ MOV WORD PTR [ASMADD+2],ES
+ MOV WORD PTR [ASMADD],DI
+ MOV WORD PTR [DEFDUMP+2],ES
+ MOV WORD PTR [DEFDUMP],DI
+ MOV BX,DS
+ MOV AH,SET_CURRENT_PDB
+ INT 21H
+ LES DI,[COM_SSSP]
+ MOV AX,ES:[DI]
+ INC DI
+ INC DI
+ MOV [AXSAVE],AX
+ MOV [SSSAVE],ES
+ MOV [SPSAVE],DI
+ RET
+
+EXECERR:
+ MOV DX,OFFSET DG:NOTFND
+ CMP AX,exec_file_not_found
+ JZ GOTEXECEMES
+ MOV DX,OFFSET DG:ACCMES
+ CMP AX,error_access_denied
+ JZ GOTEXECEMES
+ MOV DX,OFFSET DG:TOOBIG
+ CMP AX,exec_not_enough_memory
+ JZ GOTEXECEMES
+ MOV DX,OFFSET DG:EXEBAD
+ CMP AX,exec_bad_format
+ JZ GOTEXECEMES
+ MOV DX,OFFSET DG:EXECEMES
+GOTEXECEMES:
+ MOV AH,STD_CON_STRING_OUTPUT
+ INT 21H
+ JMP COMMAND
+
+HEX2BIN:
+ MOV [INDEX],DX
+ MOV DX,OFFSET DG:HEXWRT
+ CMP BYTE PTR [RDFLG],WRITE
+ JNZ RDHEX
+ JMP RESTARTJ2
+RDHEX:
+ MOV ES,AX
+ CALL OPEN_A_FILE
+ MOV DX,OFFSET DG:NOTFND
+ JNC HEXFND
+ JMP RESTART
+HEXFND:
+ XOR BP,BP
+ MOV SI,OFFSET DG:(BUFFER+BUFSIZ) ; Flag input buffer as empty
+READHEX:
+ CALL GETCH
+ CMP AL,":" ; Search for : to start line
+ JNZ READHEX
+ CALL GETBYT ; Get byte count
+ MOV CL,AL
+ MOV CH,0
+ JCXZ HEXDONE
+ CALL GETBYT ; Get high byte of load address
+ MOV BH,AL
+ CALL GETBYT ; Get low byte of load address
+ MOV BL,AL
+ ADD BX,[INDEX] ; Add in offset
+ MOV DI,BX
+ CALL GETBYT ; Throw away type byte
+READLN:
+ CALL GETBYT ; Get data byte
+ STOSB
+ CMP DI,BP ; Check if this is the largest address so far
+ JBE HAVBIG
+ MOV BP,DI ; Save new largest
+HAVBIG:
+ LOOP READLN
+ JMP SHORT READHEX
+
+GETCH:
+ CMP SI,OFFSET DG:(BUFFER+BUFSIZ)
+ JNZ NOREAD
+ MOV DX,OFFSET DG:BUFFER
+ MOV SI,DX
+ MOV AH,READ
+ PUSH BX
+ PUSH CX
+ MOV CX,BUFSIZ
+ MOV BX,[HANDLE]
+ INT 21H
+ POP CX
+ POP BX
+ OR AX,AX
+ JZ HEXDONE
+NOREAD:
+ LODSB
+ CMP AL,1AH
+ JZ HEXDONE
+ OR AL,AL
+ JNZ RET7
+HEXDONE:
+ MOV [CXSAVE],BP
+ MOV BXSAVE,0
+ RET
+
+HEXDIG:
+ CALL GETCH
+ CALL HEXCHK
+ JNC RET7
+ MOV DX,OFFSET DG:HEXERR
+RESTARTJ2:
+ JMP RESTART
+
+GETBYT:
+ CALL HEXDIG
+ MOV BL,AL
+ CALL HEXDIG
+ SHL BL,1
+ SHL BL,1
+ SHL BL,1
+ SHL BL,1
+ OR AL,BL
+RET7: RET
+
+
+CODE ENDS
+ END DEBCOM2
--- /dev/null
+.xlist\r
+.xcref\r
+INCLUDE debequ.asm\r
+INCLUDE dossym.asm\r
+.list\r
+.cref\r
+\r
+CODE SEGMENT PUBLIC BYTE 'CODE'\r
+CODE ENDS\r
+\r
+CONST SEGMENT PUBLIC BYTE\r
+CONST ENDS\r
+\r
+DATA SEGMENT PUBLIC BYTE\r
+DATA ENDS\r
+\r
+DG GROUP CODE,CONST,DATA\r
+\r
+CODE SEGMENT PUBLIC BYTE 'CODE'\r
+\r
+ EXTRN ALUFROMREG:NEAR,ALUTOREG:NEAR,ACCIMM:NEAR\r
+ EXTRN SEGOP:NEAR,ESPRE:NEAR,SSPRE:NEAR,CSPRE:NEAR\r
+ EXTRN DSPRE:NEAR,REGOP:NEAR,NOOPERANDS:NEAR\r
+ EXTRN SAVHEX:NEAR,SHORTJMP:NEAR,MOVSEGTO:NEAR\r
+ EXTRN WORDTOALU:NEAR,MOVSEGFROM:NEAR,GETADDR:NEAR\r
+ EXTRN XCHGAX:NEAR,LONGJMP:NEAR,LOADACC:NEAR,STOREACC:NEAR\r
+ EXTRN REGIMMB:NEAR,SAV16:NEAR,MEMIMM:NEAR,INT3:NEAR,SAV8:NEAR\r
+ EXTRN CHK10:NEAR,M8087:NEAR,M8087_D9:NEAR,M8087_DB:NEAR\r
+ EXTRN M8087_DD:NEAR,M8087_DF:NEAR,INFIXB:NEAR,INFIXW:NEAR\r
+ EXTRN OUTFIXB:NEAR,OUTFIXW:NEAR,JMPCALL:NEAR,INVARB:NEAR\r
+ EXTRN INVARW:NEAR,OUTVARB:NEAR,OUTVARW:NEAR,PREFIX:NEAR\r
+ EXTRN IMMED:NEAR,SIGNIMM:NEAR,SHIFT:NEAR,SHIFTV:NEAR\r
+ EXTRN GRP1:NEAR,GRP2:NEAR,REGIMMW:NEAR\r
+\r
+\r
+ EXTRN DB_OPER:NEAR,DW_OPER:NEAR,ASSEMLOOP:NEAR,GROUP2:NEAR\r
+ EXTRN NO_OPER:NEAR,GROUP1:NEAR,FGROUPP:NEAR,FGROUPX:NEAR\r
+ EXTRN FGROUPZ:NEAR,FD9_OPER:NEAR,FGROUPB:NEAR,FGROUP:NEAR\r
+ EXTRN FGROUPDS:NEAR,DCINC_OPER:NEAR,INT_OPER:NEAR,IN_OPER:NEAR\r
+ EXTRN DISP8_OPER:NEAR,JMP_OPER:NEAR,L_OPER:NEAR,MOV_OPER:NEAR\r
+ EXTRN OUT_OPER:NEAR,PUSH_OPER:NEAR,GET_DATA16:NEAR\r
+ EXTRN FGROUP3:NEAR,FGROUP3W:NEAR,FDE_OPER:NEAR,ESC_OPER:NEAR\r
+ EXTRN AA_OPER:NEAR,CALL_OPER:NEAR,FDB_OPER:NEAR,POP_OPER:NEAR\r
+ EXTRN ROTOP:NEAR,TST_OPER:NEAR,EX_OPER:NEAR\r
+\r
+CODE ENDS\r
+\r
+CONST SEGMENT PUBLIC BYTE\r
+\r
+ PUBLIC REG8,REG16,SREG,SIZ8,DISTAB,DBMN,ADDMN,ADCMN,SUBMN\r
+ PUBLIC SBBMN,XORMN,ORMN,ANDMN,AAAMN,AADMN,AASMN,CALLMN,CBWMN\r
+ PUBLIC UPMN,DIMN,CMCMN,CMPMN,CWDMN,DAAMN,DASMN,DECMN,DIVMN\r
+ PUBLIC ESCMN,HLTMN,IDIVMN,IMULMN,INCMN,INTOMN,INTMN,INMN,IRETMN\r
+ PUBLIC JAMN,JCXZMN,JNCMN,JBEMN,JZMN,JGEMN,JGMN,JLEMN,JLMN,JMPMN\r
+ PUBLIC JNZMN,JPEMN,JNZMN,JPEMN,JPOMN,JNSMN,JNOMN,JOMN,JSMN,LAHFMN\r
+ PUBLIC LDSMN,LEAMN,LESMN,LOCKMN,LODBMN,LODWMN,LOOPNZMN,LOOPZMN\r
+ PUBLIC LOOPMN,MOVBMN,MOVWMN,MOVMN,MULMN,NEGMN,NOPMN,NOTMN,OUTMN\r
+ PUBLIC POPFMN,POPMN,PUSHFMN,PUSHMN,RCLMN,RCRMN,REPZMN,REPNZMN\r
+ PUBLIC RETFMN,RETMN,ROLMN,RORMN,SAHFMN,SARMN,SCABMN,SCAWMN,SHLMN\r
+ PUBLIC SHRMN,STCMN,DOWNMN,EIMN,STOBMN,STOWMN,TESTMN,WAITMN,XCHGMN\r
+ PUBLIC XLATMN,ESSEGMN,CSSEGMN,SSSEGMN,DSSEGMN,BADMN\r
+\r
+ PUBLIC M8087_TAB,FI_TAB,SIZE_TAB,MD9_TAB,MD9_TAB2,MDB_TAB\r
+ PUBLIC MDB_TAB2,MDD_TAB,MDD_TAB2,MDF_TAB,OPTAB,MAXOP,SHFTAB,IMMTAB\r
+ PUBLIC GRP1TAB,GRP2TAB,SEGTAB,REGTAB,FLAGTAB,STACK\r
+\r
+ PUBLIC AXSAVE,BXSAVE,CXSAVE,DXSAVE,BPSAVE,SPSAVE,SISAVE\r
+ PUBLIC DISAVE,DSSAVE,ESSAVE,SSSAVE,CSSAVE,IPSAVE,FSAVE,RSTACK\r
+ PUBLIC REGDIF,RDFLG,TOTREG,DSIZ,NOREGL,DISPB,LBUFSIZ,LBUFFCNT\r
+ PUBLIC LINEBUF,PFLAG,COLPOS\r
+\r
+ IF SYSVER\r
+ PUBLIC CONFCB,POUT,COUT,CIN,IOBUFF,IOADDR,IOCALL,IOCOM,IOSTAT\r
+ PUBLIC IOCHRET,IOSEG,IOCNT\r
+ ENDIF\r
+\r
+ PUBLIC QFLAG,NEWEXEC,RETSAVE,USER_PROC_PDB,HEADSAVE,EXEC_BLOCK\r
+ PUBLIC COM_LINE,COM_FCB1,COM_FCB2,COM_SSSP,COM_CSIP\r
+\r
+REG8 DB "ALCLDLBLAHCHDHBH"\r
+REG16 DB "AXCXDXBXSPBPSIDI"\r
+SREG DB "ESCSSSDS",0,0\r
+SIZ8 DB "BYWODWQWTB",0,0\r
+; 0\r
+DISTAB DW OFFSET DG:ADDMN,ALUFROMREG\r
+ DW OFFSET DG:ADDMN,ALUFROMREG\r
+ DW OFFSET DG:ADDMN,ALUTOREG\r
+ DW OFFSET DG:ADDMN,ALUTOREG\r
+ DW OFFSET DG:ADDMN,ACCIMM\r
+ DW OFFSET DG:ADDMN,ACCIMM\r
+ DW OFFSET DG:PUSHMN,SEGOP\r
+ DW OFFSET DG:POPMN,SEGOP\r
+ DW OFFSET DG:ORMN,ALUFROMREG\r
+ DW OFFSET DG:ORMN,ALUFROMREG\r
+ DW OFFSET DG:ORMN,ALUTOREG\r
+ DW OFFSET DG:ORMN,ALUTOREG\r
+ DW OFFSET DG:ORMN,ACCIMM\r
+ DW OFFSET DG:ORMN,ACCIMM\r
+ DW OFFSET DG:PUSHMN,SEGOP\r
+ DW OFFSET DG:POPMN,SEGOP\r
+; 10H\r
+ DW OFFSET DG:ADCMN,ALUFROMREG\r
+ DW OFFSET DG:ADCMN,ALUFROMREG\r
+ DW OFFSET DG:ADCMN,ALUTOREG\r
+ DW OFFSET DG:ADCMN,ALUTOREG\r
+ DW OFFSET DG:ADCMN,ACCIMM\r
+ DW OFFSET DG:ADCMN,ACCIMM\r
+ DW OFFSET DG:PUSHMN,SEGOP\r
+ DW OFFSET DG:POPMN,SEGOP\r
+ DW OFFSET DG:SBBMN,ALUFROMREG\r
+ DW OFFSET DG:SBBMN,ALUFROMREG\r
+ DW OFFSET DG:SBBMN,ALUTOREG\r
+ DW OFFSET DG:SBBMN,ALUTOREG\r
+ DW OFFSET DG:SBBMN,ACCIMM\r
+ DW OFFSET DG:SBBMN,ACCIMM\r
+ DW OFFSET DG:PUSHMN,SEGOP\r
+ DW OFFSET DG:POPMN,SEGOP\r
+; 20H\r
+ DW OFFSET DG:ANDMN,ALUFROMREG\r
+ DW OFFSET DG:ANDMN,ALUFROMREG\r
+ DW OFFSET DG:ANDMN,ALUTOREG\r
+ DW OFFSET DG:ANDMN,ALUTOREG\r
+ DW OFFSET DG:ANDMN,ACCIMM\r
+ DW OFFSET DG:ANDMN,ACCIMM\r
+ DW OFFSET DG:ESSEGMN,ESPRE\r
+ DW OFFSET DG:DAAMN,NOOPERANDS\r
+ DW OFFSET DG:SUBMN,ALUFROMREG\r
+ DW OFFSET DG:SUBMN,ALUFROMREG\r
+ DW OFFSET DG:SUBMN,ALUTOREG\r
+ DW OFFSET DG:SUBMN,ALUTOREG\r
+ DW OFFSET DG:SUBMN,ACCIMM\r
+ DW OFFSET DG:SUBMN,ACCIMM\r
+ DW OFFSET DG:CSSEGMN,CSPRE\r
+ DW OFFSET DG:DASMN,NOOPERANDS\r
+; 30H\r
+ DW OFFSET DG:XORMN,ALUFROMREG\r
+ DW OFFSET DG:XORMN,ALUFROMREG\r
+ DW OFFSET DG:XORMN,ALUTOREG\r
+ DW OFFSET DG:XORMN,ALUTOREG\r
+ DW OFFSET DG:XORMN,ACCIMM\r
+ DW OFFSET DG:XORMN,ACCIMM\r
+ DW OFFSET DG:SSSEGMN,SSPRE\r
+ DW OFFSET DG:AAAMN,NOOPERANDS\r
+ DW OFFSET DG:CMPMN,ALUFROMREG\r
+ DW OFFSET DG:CMPMN,ALUFROMREG\r
+ DW OFFSET DG:CMPMN,ALUTOREG\r
+ DW OFFSET DG:CMPMN,ALUTOREG\r
+ DW OFFSET DG:CMPMN,ACCIMM\r
+ DW OFFSET DG:CMPMN,ACCIMM\r
+ DW OFFSET DG:DSSEGMN,DSPRE\r
+ DW OFFSET DG:AASMN,NOOPERANDS\r
+; 40H\r
+ DW OFFSET DG:INCMN,REGOP\r
+ DW OFFSET DG:INCMN,REGOP\r
+ DW OFFSET DG:INCMN,REGOP\r
+ DW OFFSET DG:INCMN,REGOP\r
+ DW OFFSET DG:INCMN,REGOP\r
+ DW OFFSET DG:INCMN,REGOP\r
+ DW OFFSET DG:INCMN,REGOP\r
+ DW OFFSET DG:INCMN,REGOP\r
+ DW OFFSET DG:DECMN,REGOP\r
+ DW OFFSET DG:DECMN,REGOP\r
+ DW OFFSET DG:DECMN,REGOP\r
+ DW OFFSET DG:DECMN,REGOP\r
+ DW OFFSET DG:DECMN,REGOP\r
+ DW OFFSET DG:DECMN,REGOP\r
+ DW OFFSET DG:DECMN,REGOP\r
+ DW OFFSET DG:DECMN,REGOP\r
+; 50H\r
+ DW OFFSET DG:PUSHMN,REGOP\r
+ DW OFFSET DG:PUSHMN,REGOP\r
+ DW OFFSET DG:PUSHMN,REGOP\r
+ DW OFFSET DG:PUSHMN,REGOP\r
+ DW OFFSET DG:PUSHMN,REGOP\r
+ DW OFFSET DG:PUSHMN,REGOP\r
+ DW OFFSET DG:PUSHMN,REGOP\r
+ DW OFFSET DG:PUSHMN,REGOP\r
+ DW OFFSET DG:POPMN,REGOP\r
+ DW OFFSET DG:POPMN,REGOP\r
+ DW OFFSET DG:POPMN,REGOP\r
+ DW OFFSET DG:POPMN,REGOP\r
+ DW OFFSET DG:POPMN,REGOP\r
+ DW OFFSET DG:POPMN,REGOP\r
+ DW OFFSET DG:POPMN,REGOP\r
+ DW OFFSET DG:POPMN,REGOP\r
+; 60H\r
+ DW OFFSET DG:DBMN,SAVHEX\r
+ DW OFFSET DG:DBMN,SAVHEX\r
+ DW OFFSET DG:DBMN,SAVHEX\r
+ DW OFFSET DG:DBMN,SAVHEX\r
+ DW OFFSET DG:DBMN,SAVHEX\r
+ DW OFFSET DG:DBMN,SAVHEX\r
+ DW OFFSET DG:DBMN,SAVHEX\r
+ DW OFFSET DG:DBMN,SAVHEX\r
+ DW OFFSET DG:DBMN,SAVHEX\r
+ DW OFFSET DG:DBMN,SAVHEX\r
+ DW OFFSET DG:DBMN,SAVHEX\r
+ DW OFFSET DG:DBMN,SAVHEX\r
+ DW OFFSET DG:DBMN,SAVHEX\r
+ DW OFFSET DG:DBMN,SAVHEX\r
+ DW OFFSET DG:DBMN,SAVHEX\r
+ DW OFFSET DG:DBMN,SAVHEX\r
+; 70H\r
+ DW OFFSET DG:JOMN,SHORTJMP\r
+ DW OFFSET DG:JNOMN,SHORTJMP\r
+ DW OFFSET DG:JCMN,SHORTJMP\r
+ DW OFFSET DG:JNCMN,SHORTJMP\r
+ DW OFFSET DG:JZMN,SHORTJMP\r
+ DW OFFSET DG:JNZMN,SHORTJMP\r
+ DW OFFSET DG:JBEMN,SHORTJMP\r
+ DW OFFSET DG:JAMN,SHORTJMP\r
+ DW OFFSET DG:JSMN,SHORTJMP\r
+ DW OFFSET DG:JNSMN,SHORTJMP\r
+ DW OFFSET DG:JPEMN,SHORTJMP\r
+ DW OFFSET DG:JPOMN,SHORTJMP\r
+ DW OFFSET DG:JLMN,SHORTJMP\r
+ DW OFFSET DG:JGEMN,SHORTJMP\r
+ DW OFFSET DG:JLEMN,SHORTJMP\r
+ DW OFFSET DG:JGMN,SHORTJMP\r
+; 80H\r
+ DW 0,IMMED\r
+ DW 0,IMMED\r
+ DW 0,IMMED\r
+ DW 0,SIGNIMM\r
+ DW OFFSET DG:TESTMN,ALUFROMREG\r
+ DW OFFSET DG:TESTMN,ALUFROMREG\r
+ DW OFFSET DG:XCHGMN,ALUFROMREG\r
+ DW OFFSET DG:XCHGMN,ALUFROMREG\r
+ DW OFFSET DG:MOVMN,ALUFROMREG\r
+ DW OFFSET DG:MOVMN,ALUFROMREG\r
+ DW OFFSET DG:MOVMN,ALUTOREG\r
+ DW OFFSET DG:MOVMN,ALUTOREG\r
+ DW OFFSET DG:MOVMN,MOVSEGTO\r
+ DW OFFSET DG:LEAMN,WORDTOALU\r
+ DW OFFSET DG:MOVMN,MOVSEGFROM\r
+ DW OFFSET DG:POPMN,GETADDR\r
+; 90H\r
+ DW OFFSET DG:NOPMN,NOOPERANDS\r
+ DW OFFSET DG:XCHGMN,XCHGAX\r
+ DW OFFSET DG:XCHGMN,XCHGAX\r
+ DW OFFSET DG:XCHGMN,XCHGAX\r
+ DW OFFSET DG:XCHGMN,XCHGAX\r
+ DW OFFSET DG:XCHGMN,XCHGAX\r
+ DW OFFSET DG:XCHGMN,XCHGAX\r
+ DW OFFSET DG:XCHGMN,XCHGAX\r
+ DW OFFSET DG:CBWMN,NOOPERANDS\r
+ DW OFFSET DG:CWDMN,NOOPERANDS\r
+ DW OFFSET DG:CALLMN,LONGJMP\r
+ DW OFFSET DG:WAITMN,NOOPERANDS\r
+ DW OFFSET DG:PUSHFMN,NOOPERANDS\r
+ DW OFFSET DG:POPFMN,NOOPERANDS\r
+ DW OFFSET DG:SAHFMN,NOOPERANDS\r
+ DW OFFSET DG:LAHFMN,NOOPERANDS\r
+; A0H\r
+ DW OFFSET DG:MOVMN,LOADACC\r
+ DW OFFSET DG:MOVMN,LOADACC\r
+ DW OFFSET DG:MOVMN,STOREACC\r
+ DW OFFSET DG:MOVMN,STOREACC\r
+ DW OFFSET DG:MOVBMN,NOOPERANDS\r
+ DW OFFSET DG:MOVWMN,NOOPERANDS\r
+ DW OFFSET DG:CMPBMN,NOOPERANDS\r
+ DW OFFSET DG:CMPWMN,NOOPERANDS\r
+ DW OFFSET DG:TESTMN,ACCIMM\r
+ DW OFFSET DG:TESTMN,ACCIMM\r
+ DW OFFSET DG:STOBMN,NOOPERANDS\r
+ DW OFFSET DG:STOWMN,NOOPERANDS\r
+ DW OFFSET DG:LODBMN,NOOPERANDS\r
+ DW OFFSET DG:LODWMN,NOOPERANDS\r
+ DW OFFSET DG:SCABMN,NOOPERANDS\r
+ DW OFFSET DG:SCAWMN,NOOPERANDS\r
+; B0H\r
+ DW OFFSET DG:MOVMN,REGIMMB\r
+ DW OFFSET DG:MOVMN,REGIMMB\r
+ DW OFFSET DG:MOVMN,REGIMMB\r
+ DW OFFSET DG:MOVMN,REGIMMB\r
+ DW OFFSET DG:MOVMN,REGIMMB\r
+ DW OFFSET DG:MOVMN,REGIMMB\r
+ DW OFFSET DG:MOVMN,REGIMMB\r
+ DW OFFSET DG:MOVMN,REGIMMB\r
+ DW OFFSET DG:MOVMN,REGIMMW\r
+ DW OFFSET DG:MOVMN,REGIMMW\r
+ DW OFFSET DG:MOVMN,REGIMMW\r
+ DW OFFSET DG:MOVMN,REGIMMW\r
+ DW OFFSET DG:MOVMN,REGIMMW\r
+ DW OFFSET DG:MOVMN,REGIMMW\r
+ DW OFFSET DG:MOVMN,REGIMMW\r
+ DW OFFSET DG:MOVMN,REGIMMW\r
+; C0H\r
+ DW OFFSET DG:DBMN,SAVHEX\r
+ DW OFFSET DG:DBMN,SAVHEX\r
+ DW OFFSET DG:RETMN,SAV16\r
+ DW OFFSET DG:RETMN,NOOPERANDS\r
+ DW OFFSET DG:LESMN,WORDTOALU\r
+ DW OFFSET DG:LDSMN,WORDTOALU\r
+ DW OFFSET DG:MOVMN,MEMIMM\r
+ DW OFFSET DG:MOVMN,MEMIMM\r
+ DW OFFSET DG:DBMN,SAVHEX\r
+ DW OFFSET DG:DBMN,SAVHEX\r
+ DW OFFSET DG:RETFMN,SAV16\r
+ DW OFFSET DG:RETFMN,NOOPERANDS\r
+ DW OFFSET DG:INTMN,INT3\r
+ DW OFFSET DG:INTMN,SAV8\r
+ DW OFFSET DG:INTOMN,NOOPERANDS\r
+ DW OFFSET DG:IRETMN,NOOPERANDS\r
+; D0H\r
+ DW 0,SHIFT\r
+ DW 0,SHIFT\r
+ DW 0,SHIFTV\r
+ DW 0,SHIFTV\r
+ DW OFFSET DG:AAMMN,CHK10\r
+ DW OFFSET DG:AADMN,CHK10\r
+ DW OFFSET DG:DBMN,SAVHEX\r
+ DW OFFSET DG:XLATMN,NOOPERANDS\r
+ DW 0,M8087 ; d8\r
+ DW 0,M8087_D9 ; d9\r
+ DW 0,M8087 ; da\r
+ DW 0,M8087_DB ; db\r
+ DW 0,M8087 ; dc\r
+ DW 0,M8087_DD ; dd\r
+ DW 0,M8087 ; de\r
+ DW 0,M8087_DF ; df\r
+; E0H\r
+ DW OFFSET DG:LOOPNZMN,SHORTJMP\r
+ DW OFFSET DG:LOOPZMN,SHORTJMP\r
+ DW OFFSET DG:LOOPMN,SHORTJMP\r
+ DW OFFSET DG:JCXZMN,SHORTJMP\r
+ DW OFFSET DG:INMN,INFIXB\r
+ DW OFFSET DG:INMN,INFIXW\r
+ DW OFFSET DG:OUTMN,OUTFIXB\r
+ DW OFFSET DG:OUTMN,OUTFIXW\r
+ DW OFFSET DG:CALLMN,JMPCALL\r
+ DW OFFSET DG:JMPMN,JMPCALL\r
+ DW OFFSET DG:JMPMN,LONGJMP\r
+ DW OFFSET DG:JMPMN,SHORTJMP\r
+ DW OFFSET DG:INMN,INVARB\r
+ DW OFFSET DG:INMN,INVARW\r
+ DW OFFSET DG:OUTMN,OUTVARB\r
+ DW OFFSET DG:OUTMN,OUTVARW\r
+; F0H\r
+ DW OFFSET DG:LOCKMN,PREFIX\r
+ DW OFFSET DG:DBMN,SAVHEX\r
+ DW OFFSET DG:REPNZMN,PREFIX\r
+ DW OFFSET DG:REPZMN,PREFIX\r
+ DW OFFSET DG:HLTMN,NOOPERANDS\r
+ DW OFFSET DG:CMCMN,NOOPERANDS\r
+ DW 0,GRP1\r
+ DW 0,GRP1\r
+ DW OFFSET DG:CLCMN,NOOPERANDS\r
+ DW OFFSET DG:STCMN,NOOPERANDS\r
+ DW OFFSET DG:DIMN,NOOPERANDS\r
+ DW OFFSET DG:EIMN,NOOPERANDS\r
+ DW OFFSET DG:UPMN,NOOPERANDS\r
+ DW OFFSET DG:DOWNMN,NOOPERANDS\r
+ DW 0,GRP2\r
+ DW 0,GRP2\r
+\r
+DBMN DB "D","B"+80H\r
+ DB "D","W"+80H\r
+ DB ";"+80H\r
+ADDMN DB "AD","D"+80H\r
+ADCMN DB "AD","C"+80H\r
+SUBMN DB "SU","B"+80H\r
+SBBMN DB "SB","B"+80H\r
+XORMN DB "XO","R"+80H\r
+ORMN DB "O","R"+80H\r
+ANDMN DB "AN","D"+80H\r
+AAAMN DB "AA","A"+80H\r
+AADMN DB "AA","D"+80H\r
+AAMMN DB "AA","M"+80H\r
+AASMN DB "AA","S"+80H\r
+CALLMN DB "CAL","L"+80H\r
+CBWMN DB "CB","W"+80H\r
+CLCMN DB "CL","C"+80H\r
+UPMN DB "CL","D"+80H ; CLD+80H\r
+DIMN DB "CL","I"+80H\r
+CMCMN DB "CM","C"+80H\r
+CMPBMN DB "CMPS","B"+80H ; CMPSB\r
+CMPWMN DB "CMPS","W"+80H ; CMPSW+80H\r
+CMPMN DB "CM","P"+80H\r
+CWDMN DB "CW","D"+80H\r
+DAAMN DB "DA","A"+80H\r
+DASMN DB "DA","S"+80H\r
+DECMN DB "DE","C"+80H\r
+DIVMN DB "DI","V"+80H\r
+ESCMN DB "ES","C"+80H\r
+ DB "FXC","H"+80H\r
+ DB "FFRE","E"+80H\r
+ DB "FCOMP","P"+80H\r
+ DB "FCOM","P"+80H\r
+ DB "FCO","M"+80H\r
+ DB "FICOM","P"+80H\r
+ DB "FICO","M"+80H\r
+ DB "FNO","P"+80H\r
+ DB "FCH","S"+80H\r
+ DB "FAB","S"+80H\r
+ DB "FTS","T"+80H\r
+ DB "FXA","M"+80H\r
+ DB "FLDL2","T"+80H\r
+ DB "FLDL2","E"+80H\r
+ DB "FLDLG","2"+80H\r
+ DB "FLDLN","2"+80H\r
+ DB "FLDP","I"+80H\r
+ DB "FLD","1"+80H\r
+ DB "FLD","Z"+80H\r
+ DB "F2XM","1"+80H\r
+ DB "FYL2XP","1"+80H\r
+ DB "FYL2","X"+80H\r
+ DB "FPTA","N"+80H\r
+ DB "FPATA","N"+80H\r
+ DB "FXTRAC","T"+80H\r
+ DB "FDECST","P"+80H\r
+ DB "FINCST","P"+80H\r
+ DB "FPRE","M"+80H\r
+ DB "FSQR","T"+80H\r
+ DB "FRNDIN","T"+80H\r
+ DB "FSCAL","E"+80H\r
+ DB "FINI","T"+80H\r
+ DB "FDIS","I"+80H\r
+ DB "FEN","I"+80H\r
+ DB "FCLE","X"+80H\r
+ DB "FBL","D"+80H\r
+ DB "FBST","P"+80H\r
+ DB "FLDC","W"+80H\r
+ DB "FSTC","W"+80H\r
+ DB "FSTS","W"+80H\r
+ DB "FSTEN","V"+80H\r
+ DB "FLDEN","V"+80H\r
+ DB "FSAV","E"+80H\r
+ DB "FRSTO","R"+80H\r
+ DB "FADD","P"+80H\r
+ DB "FAD","D"+80H\r
+ DB "FIAD","D"+80H\r
+ DB "FSUBR","P"+80H\r
+ DB "FSUB","R"+80H\r
+ DB "FSUB","P"+80H\r
+ DB "FSU","B"+80H\r
+ DB "FISUB","R"+80H\r
+ DB "FISU","B"+80H\r
+ DB "FMUL","P"+80H\r
+ DB "FMU","L"+80H\r
+ DB "FIMU","L"+80H\r
+ DB "FDIVR","P"+80H\r
+ DB "FDIV","R"+80H\r
+ DB "FDIV","P"+80H\r
+ DB "FDI","V"+80H\r
+ DB "FIDIV","R"+80H\r
+ DB "FIDI","V"+80H\r
+ DB "FWAI","T"+80H\r
+ DB "FIL","D"+80H\r
+ DB "FL","D"+80H\r
+ DB "FST","P"+80H\r
+ DB "FS","T"+80H\r
+ DB "FIST","P"+80H\r
+ DB "FIS","T"+80H\r
+HLTMN DB "HL","T"+80H\r
+IDIVMN DB "IDI","V"+80H\r
+IMULMN DB "IMU","L"+80H\r
+INCMN DB "IN","C"+80H\r
+INTOMN DB "INT","O"+80H\r
+INTMN DB "IN","T"+80H\r
+INMN DB "I","N"+80H ; IN\r
+IRETMN DB "IRE","T"+80H\r
+ DB "JNB","E"+80H\r
+ DB "JA","E"+80H\r
+JAMN DB "J","A"+80H\r
+JCXZMN DB "JCX","Z"+80H\r
+JNCMN DB "JN","B"+80H\r
+JBEMN DB "JB","E"+80H\r
+JCMN DB "J","B"+80H\r
+ DB "JN","C"+80H\r
+ DB "J","C"+80H\r
+ DB "JNA","E"+80H\r
+ DB "JN","A"+80H\r
+JZMN DB "J","Z"+80H\r
+ DB "J","E"+80H\r
+JGEMN DB "JG","E"+80H\r
+JGMN DB "J","G"+80H\r
+ DB "JNL","E"+80H\r
+ DB "JN","L"+80H\r
+JLEMN DB "JL","E"+80H\r
+JLMN DB "J","L"+80H\r
+ DB "JNG","E"+80H\r
+ DB "JN","G"+80H\r
+JMPMN DB "JM","P"+80H\r
+JNZMN DB "JN","Z"+80H\r
+ DB "JN","E"+80H\r
+JPEMN DB "JP","E"+80H\r
+JPOMN DB "JP","O"+80H\r
+ DB "JN","P"+80H\r
+JNSMN DB "JN","S"+80H\r
+JNOMN DB "JN","O"+80H\r
+JOMN DB "J","O"+80H\r
+JSMN DB "J","S"+80H\r
+ DB "J","P"+80H\r
+LAHFMN DB "LAH","F"+80H\r
+LDSMN DB "LD","S"+80H\r
+LEAMN DB "LE","A"+80H\r
+LESMN DB "LE","S"+80H\r
+LOCKMN DB "LOC","K"+80H\r
+LODBMN DB "LODS","B"+80H ; LODSB\r
+LODWMN DB "LODS","W"+80H ; LODSW+80H\r
+LOOPNZMN DB "LOOPN","Z"+80H\r
+LOOPZMN DB "LOOP","Z"+80H\r
+ DB "LOOPN","E"+80H\r
+ DB "LOOP","E"+80H\r
+LOOPMN DB "LOO","P"+80H\r
+MOVBMN DB "MOVS","B"+80H ; MOVSB\r
+MOVWMN DB "MOVS","W"+80H ; MOVSW+80H\r
+MOVMN DB "MO","V"+80H\r
+MULMN DB "MU","L"+80H\r
+NEGMN DB "NE","G"+80H\r
+NOPMN DB "NO","P"+80H\r
+NOTMN DB "NO","T"+80H\r
+OUTMN DB "OU","T"+80H ; OUT\r
+POPFMN DB "POP","F"+80H\r
+POPMN DB "PO","P"+80H\r
+PUSHFMN DB "PUSH","F"+80H\r
+PUSHMN DB "PUS","H"+80H\r
+RCLMN DB "RC","L"+80H\r
+RCRMN DB "RC","R"+80H\r
+REPZMN DB "REP","Z"+80H\r
+REPNZMN DB "REPN","Z"+80H\r
+ DB "REP","E"+80H\r
+ DB "REPN","E"+80H\r
+ DB "RE","P"+80H\r
+RETFMN DB "RET","F"+80H\r
+RETMN DB "RE","T"+80H\r
+ROLMN DB "RO","L"+80H\r
+RORMN DB "RO","R"+80H\r
+SAHFMN DB "SAH","F"+80H\r
+SARMN DB "SA","R"+80H\r
+SCABMN DB "SCAS","B"+80H ; SCASB\r
+SCAWMN DB "SCAS","W"+80H ; SCASW+80H\r
+SHLMN DB "SH","L"+80H\r
+SHRMN DB "SH","R"+80H\r
+STCMN DB "ST","C"+80H\r
+DOWNMN DB "ST","D"+80H ; STD\r
+EIMN DB "ST","I"+80H ; STI\r
+STOBMN DB "STOS","B"+80H ; STOSB\r
+STOWMN DB "STOS","W"+80H ; STOSW+80H\r
+TESTMN DB "TES","T"+80H\r
+WAITMN DB "WAI","T"+80H\r
+XCHGMN DB "XCH","G"+80H\r
+XLATMN DB "XLA","T"+80H\r
+ESSEGMN DB "ES",":"+80H\r
+CSSEGMN DB "CS",":"+80H\r
+SSSEGMN DB "SS",":"+80H\r
+DSSEGMN DB "DS",":"+80H\r
+BADMN DB "??","?"+80H\r
+\r
+M8087_TAB DB "ADD$MUL$COM$COMP$SUB$SUBR$DIV$DIVR$"\r
+FI_TAB DB "F$FI$F$FI$"\r
+SIZE_TAB DB "DWORD PTR $DWORD PTR $QWORD PTR $WORD PTR $"\r
+ DB "BYTE PTR $TBYTE PTR $"\r
+\r
+MD9_TAB DB "LD$@$ST$STP$LDENV$LDCW$STENV$STCW$"\r
+MD9_TAB2 DB "CHS$ABS$@$@$TST$XAM$@$@$LD1$LDL2T$LDL2E$"\r
+ DB "LDPI$LDLG2$LDLN2$LDZ$@$2XM1$YL2X$PTAN$PATAN$XTRACT$"\r
+ DB "@$DECSTP$INCSTP$PREM$YL2XP1$SQRT$@$RNDINT$SCALE$@$@$"\r
+\r
+MDB_TAB DB "ILD$@$IST$ISTP$@$LD$@$STP$"\r
+MDB_TAB2 DB "ENI$DISI$CLEX$INIT$"\r
+\r
+MDD_TAB DB "LD$@$ST$STP$RSTOR$@$SAVE$STSW$"\r
+MDD_TAB2 DB "FREE$XCH$ST$STP$"\r
+\r
+MDF_TAB DB "ILD$@$IST$ISTP$BLD$ILD$BSTP$ISTP$"\r
+\r
+\r
+OPTAB DB 11111111B ; DB\r
+ DW DB_OPER\r
+ DB 11111111B ; DW\r
+ DW DW_OPER\r
+ DB 11111111B ; COMMENT\r
+ DW ASSEMLOOP\r
+ DB 0 * 8 ; ADD\r
+ DW GROUP2\r
+ DB 2 * 8 ; ADC\r
+ DW GROUP2\r
+ DB 5 * 8 ; SUB\r
+ DW GROUP2\r
+ DB 3 * 8 ; SBB\r
+ DW GROUP2\r
+ DB 6 * 8 ; XOR\r
+ DW GROUP2\r
+ DB 1 * 8 ; OR\r
+ DW GROUP2\r
+ DB 4 * 8 ; AND\r
+ DW GROUP2\r
+ DB 00110111B ; AAA\r
+ DW NO_OPER\r
+ DB 11010101B ; AAD\r
+ DW AA_OPER\r
+ DB 11010100B ; AAM\r
+ DW AA_OPER\r
+ DB 00111111B ; AAS\r
+ DW NO_OPER\r
+ DB 2 * 8 ; CALL\r
+ DW CALL_OPER\r
+ DB 10011000B ; CBW\r
+ DW NO_OPER\r
+ DB 11111000B ; CLC\r
+ DW NO_OPER\r
+ DB 11111100B ; CLD\r
+ DW NO_OPER\r
+ DB 11111010B ; DIM\r
+ DW NO_OPER\r
+ DB 11110101B ; CMC\r
+ DW NO_OPER\r
+ DB 10100110B ; CMPB\r
+ DW NO_OPER\r
+ DB 10100111B ; CMPW\r
+ DW NO_OPER\r
+ DB 7 * 8 ; CMP\r
+ DW GROUP2\r
+ DB 10011001B ; CWD\r
+ DW NO_OPER\r
+ DB 00100111B ; DAA\r
+ DW NO_OPER\r
+ DB 00101111B ; DAS\r
+ DW NO_OPER\r
+ DB 1 * 8 ; DEC\r
+ DW DCINC_OPER\r
+ DB 6 * 8 ; DIV\r
+ DW GROUP1\r
+ DB 11011000B ; ESC\r
+ DW ESC_OPER\r
+ DB 00001001B ; FXCH\r
+ DW FGROUPP\r
+ DB 00101000B ; FFREE\r
+ DW FGROUPP\r
+ DB 11011001B ; FCOMPP\r
+ DW FDE_OPER\r
+ DB 00000011B ; FCOMP\r
+ DW FGROUPX ; Exception to normal P instructions\r
+ DB 00000010B ; FCOM\r
+ DW FGROUPX\r
+ DB 00010011B ; FICOMP\r
+ DW FGROUPZ\r
+ DB 00010010B ; FICOM\r
+ DW FGROUPZ\r
+ DB 11010000B ; FNOP\r
+ DW FD9_OPER\r
+ DB 11100000B ; FCHS\r
+ DW FD9_OPER\r
+ DB 11100001B ; FABS\r
+ DW FD9_OPER\r
+ DB 11100100B ; FTST\r
+ DW FD9_OPER\r
+ DB 11100101B ; FXAM\r
+ DW FD9_OPER\r
+ DB 11101001B ; FLDL2T\r
+ DW FD9_OPER\r
+ DB 11101010B ; FLDL2E\r
+ DW FD9_OPER\r
+ DB 11101100B ; FLDLG2\r
+ DW FD9_OPER\r
+ DB 11101101B ; FLDLN2\r
+ DW FD9_OPER\r
+ DB 11101011B ; FLDPI\r
+ DW FD9_OPER\r
+ DB 11101000B ; FLD1\r
+ DW FD9_OPER\r
+ DB 11101110B ; FLDZ\r
+ DW FD9_OPER\r
+ DB 11110000B ; F2XM1\r
+ DW FD9_OPER\r
+ DB 11111001B ; FYL2XP1\r
+ DW FD9_OPER\r
+ DB 11110001B ; FYL2X\r
+ DW FD9_OPER\r
+ DB 11110010B ; FPTAN\r
+ DW FD9_OPER\r
+ DB 11110011B ; FPATAN\r
+ DW FD9_OPER\r
+ DB 11110100B ; FXTRACT\r
+ DW FD9_OPER\r
+ DB 11110110B ; FDECSTP\r
+ DW FD9_OPER\r
+ DB 11110111B ; FINCSTP\r
+ DW FD9_OPER\r
+ DB 11111000B ; FPREM\r
+ DW FD9_OPER\r
+ DB 11111010B ; FSQRT\r
+ DW FD9_OPER\r
+ DB 11111100B ; FRNDINT\r
+ DW FD9_OPER\r
+ DB 11111101B ; FSCALE\r
+ DW FD9_OPER\r
+ DB 11100011B ; FINIT\r
+ DW FDB_OPER\r
+ DB 11100001B ; FDISI\r
+ DW FDB_OPER\r
+ DB 11100000B ; FENI\r
+ DW FDB_OPER\r
+ DB 11100010B ; FCLEX\r
+ DW FDB_OPER\r
+ DB 00111100B ; FBLD\r
+ DW FGROUPB\r
+ DB 00111110B ; FBSTP\r
+ DW FGROUPB\r
+ DB 00001101B ; FLDCW\r
+ DW FGROUP3W\r
+ DB 00001111B ; FSTCW\r
+ DW FGROUP3W\r
+ DB 00101111B ; FSTSW\r
+ DW FGROUP3W\r
+ DB 00001110B ; FSTENV\r
+ DW FGROUP3\r
+ DB 00001100B ; FLDENV\r
+ DW FGROUP3\r
+ DB 00101110B ; FSAVE\r
+ DW FGROUP3\r
+ DB 00101100B ; FRSTOR\r
+ DW FGROUP3\r
+ DB 00110000B ; FADDP\r
+ DW FGROUPP\r
+ DB 00000000B ; FADD\r
+ DW FGROUP\r
+ DB 00010000B ; FIADD\r
+ DW FGROUPZ\r
+ DB 00110100B ; FSUBRP\r
+ DW FGROUPP\r
+ DB 00000101B ; FSUBR\r
+ DW FGROUPDS\r
+ DB 00110101B ; FSUBP\r
+ DW FGROUPP\r
+ DB 00000100B ; FSUB\r
+ DW FGROUPDS\r
+ DB 00010101B ; FISUBR\r
+ DW FGROUPZ\r
+ DB 00010100B ; FISUB\r
+ DW FGROUPZ\r
+ DB 00110001B ; FMULP\r
+ DW FGROUPP\r
+ DB 00000001B ; FMUL\r
+ DW FGROUP\r
+ DB 00010001B ; FIMUL\r
+ DW FGROUPZ\r
+ DB 00110110B ; FDIVRP\r
+ DW FGROUPP\r
+ DB 00000111B ; FDIVR\r
+ DW FGROUPDS\r
+ DB 00110111B ; FDIVP\r
+ DW FGROUPP\r
+ DB 00000110B ; FDIV\r
+ DW FGROUPDS\r
+ DB 00010111B ; FIDIVR\r
+ DW FGROUPZ\r
+ DB 00010110B ; FIDIV\r
+ DW FGROUPZ\r
+ DB 10011011B ; FWAIT\r
+ DW NO_OPER\r
+ DB 00011000B ; FILD\r
+ DW FGROUPZ\r
+ DB 00001000B ; FLD\r
+ DW FGROUPX\r
+ DB 00001011B ; FSTP\r
+ DW FGROUPX\r
+ DB 00101010B ; FST\r
+ DW FGROUPX\r
+ DB 00011011B ; FISTP\r
+ DW FGROUPZ\r
+ DB 00011010B ; FIST\r
+ DW FGROUPZ\r
+ DB 11110100B ; HLT\r
+ DW NO_OPER\r
+ DB 7 * 8 ; IDIV\r
+ DW GROUP1\r
+ DB 5 * 8 ; IMUL\r
+ DW GROUP1\r
+ DB 0 * 8 ; INC\r
+ DW DCINC_OPER\r
+ DB 11001110B ; INTO\r
+ DW NO_OPER\r
+ DB 11001100B ; INTM\r
+ DW INT_OPER\r
+ DB 11101100B ; IN\r
+ DW IN_OPER\r
+ DB 11001111B ; IRET\r
+ DW NO_OPER\r
+ DB 01110111B ; JNBE\r
+ DW DISP8_OPER\r
+ DB 01110011B ; JAE\r
+ DW DISP8_OPER\r
+ DB 01110111B ; JA\r
+ DW DISP8_OPER\r
+ DB 11100011B ; JCXZ\r
+ DW DISP8_OPER\r
+ DB 01110011B ; JNB\r
+ DW DISP8_OPER\r
+ DB 01110110B ; JBE\r
+ DW DISP8_OPER\r
+ DB 01110010B ; JB\r
+ DW DISP8_OPER\r
+ DB 01110011B ; JNC\r
+ DW DISP8_OPER\r
+ DB 01110010B ; JC\r
+ DW DISP8_OPER\r
+ DB 01110010B ; JNAE\r
+ DW DISP8_OPER\r
+ DB 01110110B ; JNA\r
+ DW DISP8_OPER\r
+ DB 01110100B ; JZ\r
+ DW DISP8_OPER\r
+ DB 01110100B ; JE\r
+ DW DISP8_OPER\r
+ DB 01111101B ; JGE\r
+ DW DISP8_OPER\r
+ DB 01111111B ; JG\r
+ DW DISP8_OPER\r
+ DB 01111111B ; JNLE\r
+ DW DISP8_OPER\r
+ DB 01111101B ; JNL\r
+ DW DISP8_OPER\r
+ DB 01111110B ; JLE\r
+ DW DISP8_OPER\r
+ DB 01111100B ; JL\r
+ DW DISP8_OPER\r
+ DB 01111100B ; JNGE\r
+ DW DISP8_OPER\r
+ DB 01111110B ; JNG\r
+ DW DISP8_OPER\r
+ DB 4 * 8 ; JMP\r
+ DW JMP_OPER\r
+ DB 01110101B ; JNZ\r
+ DW DISP8_OPER\r
+ DB 01110101B ; JNE\r
+ DW DISP8_OPER\r
+ DB 01111010B ; JPE\r
+ DW DISP8_OPER\r
+ DB 01111011B ; JPO\r
+ DW DISP8_OPER\r
+ DB 01111011B ; JNP\r
+ DW DISP8_OPER\r
+ DB 01111001B ; JNS\r
+ DW DISP8_OPER\r
+ DB 01110001B ; JNO\r
+ DW DISP8_OPER\r
+ DB 01110000B ; JO\r
+ DW DISP8_OPER\r
+ DB 01111000B ; JS\r
+ DW DISP8_OPER\r
+ DB 01111010B ; JP\r
+ DW DISP8_OPER\r
+ DB 10011111B ; LAHF\r
+ DW NO_OPER\r
+ DB 11000101B ; LDS\r
+ DW L_OPER\r
+ DB 10001101B ; LEA\r
+ DW L_OPER\r
+ DB 11000100B ; LES\r
+ DW L_OPER\r
+ DB 11110000B ; LOCK\r
+ DW NO_OPER\r
+ DB 10101100B ; LODB\r
+ DW NO_OPER\r
+ DB 10101101B ; LODW\r
+ DW NO_OPER\r
+ DB 11100000B ; LOOPNZ\r
+ DW DISP8_OPER\r
+ DB 11100001B ; LOOPZ\r
+ DW DISP8_OPER\r
+ DB 11100000B ; LOOPNE\r
+ DW DISP8_OPER\r
+ DB 11100001B ; LOOPE\r
+ DW DISP8_OPER\r
+ DB 11100010B ; LOOP\r
+ DW DISP8_OPER\r
+ DB 10100100B ; MOVB\r
+ DW NO_OPER\r
+ DB 10100101B ; MOVW\r
+ DW NO_OPER\r
+ DB 11000110B ; MOV\r
+ DW MOV_OPER\r
+ DB 4 * 8 ; MUL\r
+ DW GROUP1\r
+ DB 3 * 8 ; NEG\r
+ DW GROUP1\r
+ DB 10010000B ; NOP\r
+ DW NO_OPER\r
+ DB 2 * 8 ; NOT\r
+ DW GROUP1\r
+ DB 11101110B ; OUT\r
+ DW OUT_OPER\r
+ DB 10011101B ; POPF\r
+ DW NO_OPER\r
+ DB 0 * 8 ; POP\r
+ DW POP_OPER\r
+ DB 10011100B ; PUSHF\r
+ DW NO_OPER\r
+ DB 6 * 8 ; PUSH\r
+ DW PUSH_OPER\r
+ DB 2 * 8 ; RCL\r
+ DW ROTOP\r
+ DB 3 * 8 ; RCR\r
+ DW ROTOP\r
+ DB 11110011B ; REPZ\r
+ DW NO_OPER\r
+ DB 11110010B ; REPNZ\r
+ DW NO_OPER\r
+ DB 11110011B ; REPE\r
+ DW NO_OPER\r
+ DB 11110010B ; REPNE\r
+ DW NO_OPER\r
+ DB 11110011B ; REP\r
+ DW NO_OPER\r
+ DB 11001011B ; RETF\r
+ DW GET_DATA16\r
+ DB 11000011B ; RET\r
+ DW GET_DATA16\r
+ DB 0 * 8 ; ROL\r
+ DW ROTOP\r
+ DB 1 * 8 ; ROR\r
+ DW ROTOP\r
+ DB 10011110B ; SAHF\r
+ DW NO_OPER\r
+ DB 7 * 8 ; SAR\r
+ DW ROTOP\r
+ DB 10101110B ; SCAB\r
+ DW NO_OPER\r
+ DB 10101111B ; SCAW\r
+ DW NO_OPER\r
+ DB 4 * 8 ; SHL\r
+ DW ROTOP\r
+ DB 5 * 8 ; SHR\r
+ DW ROTOP\r
+ DB 11111001B ; STC\r
+ DW NO_OPER\r
+ DB 11111101B ; STD\r
+ DW NO_OPER\r
+ DB 11111011B ; EI\r
+ DW NO_OPER\r
+ DB 10101010B ; STOB\r
+ DW NO_OPER\r
+ DB 10101011B ; STOW\r
+ DW NO_OPER\r
+ DB 11110110B ; TEST\r
+ DW TST_OPER\r
+ DB 10011011B ; WAIT\r
+ DW NO_OPER\r
+ DB 10000110B ; XCHG\r
+ DW EX_OPER\r
+ DB 11010111B ; XLAT\r
+ DW NO_OPER\r
+ DB 00100110B ; ESSEG\r
+ DW NO_OPER\r
+ DB 00101110B ; CSSEG\r
+ DW NO_OPER\r
+ DB 00110110B ; SSSEG\r
+ DW NO_OPER\r
+ DB 00111110B ; DSSEG\r
+ DW NO_OPER\r
+\r
+zzopcode label byte\r
+MAXOP = (zzopcode-optab)/3\r
+\r
+SHFTAB DW OFFSET DG:ROLMN,OFFSET DG:RORMN,OFFSET DG:RCLMN\r
+ DW OFFSET DG:RCRMN,OFFSET DG:SHLMN,OFFSET DG:SHRMN\r
+ DW OFFSET DG:BADMN,OFFSET DG:SARMN\r
+\r
+IMMTAB DW OFFSET DG:ADDMN,OFFSET DG:ORMN,OFFSET DG:ADCMN\r
+ DW OFFSET DG:SBBMN,OFFSET DG:ANDMN,OFFSET DG:SUBMN\r
+ DW OFFSET DG:XORMN,OFFSET DG:CMPMN\r
+\r
+GRP1TAB DW OFFSET DG:TESTMN,OFFSET DG:BADMN,OFFSET DG:NOTMN\r
+ DW OFFSET DG:NEGMN,OFFSET DG:MULMN,OFFSET DG:IMULMN\r
+ DW OFFSET DG:DIVMN,OFFSET DG:IDIVMN\r
+\r
+GRP2TAB DW OFFSET DG:INCMN,OFFSET DG:DECMN,OFFSET DG:CALLMN\r
+ DW OFFSET DG:CALLMN,OFFSET DG:JMPMN,OFFSET DG:JMPMN\r
+ DW OFFSET DG:PUSHMN,OFFSET DG:BADMN\r
+\r
+SEGTAB DW OFFSET DG:ESSAVE,OFFSET DG:CSSAVE,OFFSET DG:SSSAVE\r
+ DW OFFSET DG:DSSAVE\r
+\r
+REGTAB DB "AXBXCXDXSPBPSIDIDSESSSCSIPPC"\r
+\r
+; Flags are ordered to correspond with the bits of the flag\r
+; register, most significant bit first, zero if bit is not\r
+; a flag. First 16 entries are for bit set, second 16 for\r
+; bit reset.\r
+\r
+FLAGTAB DW 0\r
+ DW 0\r
+ DW 0\r
+ DW 0\r
+ DB "OV"\r
+ DB "DN"\r
+ DB "EI" ; "STI"\r
+ DW 0\r
+ DB "NG"\r
+ DB "ZR"\r
+ DW 0\r
+ DB "AC"\r
+ DW 0\r
+ DB "PE"\r
+ DW 0\r
+ DB "CY"\r
+ DW 0\r
+ DW 0\r
+ DW 0\r
+ DW 0\r
+ DB "NV"\r
+ DB "UP" ; "CLD"\r
+ DB "DI"\r
+ DW 0\r
+ DB "PL"\r
+ DB "NZ"\r
+ DW 0\r
+ DB "NA"\r
+ DW 0\r
+ DB "PO"\r
+ DW 0\r
+ DB "NC"\r
+\r
+ DB 80H DUP(?)\r
+STACK LABEL BYTE\r
+\r
+\r
+; Register save area\r
+\r
+AXSAVE DW 0\r
+BXSAVE DW 0\r
+CXSAVE DW 0\r
+DXSAVE DW 0\r
+SPSAVE DW 5AH\r
+BPSAVE DW 0\r
+SISAVE DW 0\r
+DISAVE DW 0\r
+DSSAVE DW 0\r
+ESSAVE DW 0\r
+RSTACK LABEL WORD ; Stack set here so registers can be saved by pushing\r
+SSSAVE DW 0\r
+CSSAVE DW 0\r
+IPSAVE DW 100H\r
+FSAVE DW 0\r
+\r
+REGDIF EQU AXSAVE-REGTAB\r
+\r
+; RAM area.\r
+\r
+RDFLG DB READ\r
+TOTREG DB 13\r
+DSIZ DB 0FH\r
+NOREGL DB 8\r
+DISPB DW 128\r
+\r
+LBUFSIZ DB BUFLEN\r
+LBUFFCNT DB 0\r
+LINEBUF DB 0DH\r
+ DB BUFLEN DUP (?)\r
+PFLAG DB 0\r
+COLPOS DB 0\r
+\r
+ IF SYSVER\r
+CONFCB DB 0\r
+ DB "PRN "\r
+ DB 25 DUP(0)\r
+\r
+POUT DD ?\r
+COUT DD ?\r
+CIN DD ?\r
+IOBUFF DB 3 DUP (?)\r
+IOADDR DD ?\r
+\r
+IOCALL DB 22\r
+ DB 0\r
+IOCOM DB 0\r
+IOSTAT DW 0\r
+ DB 8 DUP (0)\r
+IOCHRET DB 0\r
+ DW OFFSET DG:IOBUFF\r
+IOSEG DW ?\r
+IOCNT DW 1\r
+ DW 0\r
+ ENDIF\r
+\r
+QFLAG DB 0\r
+NEWEXEC DB 0\r
+RETSAVE DW ?\r
+\r
+USER_PROC_PDB DW ?\r
+\r
+HEADSAVE DW ?\r
+\r
+EXEC_BLOCK LABEL BYTE\r
+ DW 0\r
+COM_LINE LABEL DWORD\r
+ DW 80H\r
+ DW ?\r
+COM_FCB1 LABEL DWORD\r
+ DW FCB\r
+ DW ?\r
+COM_FCB2 LABEL DWORD\r
+ DW FCB + 10H\r
+ DW ?\r
+COM_SSSP DD ?\r
+COM_CSIP DD ?\r
+\r
+CONST ENDS\r
+ END\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+FALSE EQU 0\r
+TRUE EQU NOT FALSE\r
+\r
+IBMVER EQU true ; Set conditional switches\r
+MSVER EQU false\r
+\r
+SYSVER EQU FALSE ; if true, i/o direct to bios\r
+ ; so DOS can be debugged\r
+IBMJAPAN EQU FALSE\r
+\r
+SETCNTC EQU TRUE ; If this is FALSE, DEBUG will not set\r
+ ; the Control C int vector\r
+\r
+ZIBO EQU TRUE ; true if P traces over interrupts\r
+ ; and calls and dump looks pretty\r
+PROMPT EQU "-"\r
+FCB EQU 5CH\r
+EXEFCB EQU FCB\r
+BUFLEN EQU 80 ; Maximum length of line input buffer\r
+BPMAX EQU 10 ; Maximum number of breakpoints\r
+BPLEN EQU 5*BPMAX ; Length of breakpoint table\r
+REGTABLEN EQU 14 ; Number of registers\r
+SEGDIF EQU 0\r
+BUFSIZ EQU 512\r
+\r
+BXREG EQU "B"+5800H ; "BX"\r
+BPREG EQU "B"+5000H ; "BP"\r
+SIREG EQU "S"+4900H ; "SI"\r
+DIREG EQU "D"+4900H ; "DI"\r
+COMMA EQU 2C00H\r
+OPBUFLEN EQU 35\r
+\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a
\ No newline at end of file
--- /dev/null
+TITLE DEBUASM\r
+\r
+; Code for the UASSEMble command in the debugger\r
+\r
+.xlist\r
+.xcref\r
+ INCLUDE DEBEQU.ASM\r
+ INCLUDE DOSSYM.ASM\r
+.cref\r
+.list\r
+\r
+\r
+CODE SEGMENT PUBLIC BYTE 'CODE'\r
+CODE ENDS\r
+\r
+CONST SEGMENT PUBLIC BYTE\r
+\r
+ EXTRN SYNERR:BYTE\r
+ EXTRN NSEG:WORD,SISAVE:WORD,BPSAVE:WORD,DISAVE:WORD\r
+ EXTRN BXSAVE:WORD,DSSAVE:WORD,ESSAVE:WORD,CSSAVE:WORD,IPSAVE:WORD\r
+ EXTRN SSSAVE:WORD,CXSAVE:WORD,SPSAVE:WORD,FSAVE:WORD\r
+ EXTRN DISTAB:WORD,SHFTAB:WORD,IMMTAB:WORD,GRP1TAB:WORD,GRP2TAB:WORD\r
+ EXTRN DBMN:BYTE,ESCMN:BYTE,DISPB:WORD,STACK:BYTE,REG8:BYTE\r
+ EXTRN REG16:BYTE,SREG:BYTE,SIZ8:BYTE,SEGTAB:WORD,M8087_TAB:BYTE\r
+ EXTRN FI_TAB:BYTE,SIZE_TAB:BYTE,MD9_TAB:BYTE,MD9_TAB2:BYTE\r
+ EXTRN MDB_TAB:BYTE,MDB_TAB2:BYTE,MDD_TAB:BYTE,MDD_TAB2:BYTE\r
+ EXTRN MDF_TAB:BYTE\r
+\r
+CONST ENDS\r
+\r
+DATA SEGMENT PUBLIC BYTE\r
+\r
+ EXTRN DISADD:BYTE,DISCNT:WORD,BYTCNT:BYTE,TEMP:BYTE,AWORD:BYTE\r
+ EXTRN MIDFLD:BYTE,MODE:BYTE,REGMEM:BYTE,OPCODE:WORD,OPBUF:BYTE\r
+ EXTRN INDEX:WORD\r
+\r
+DATA ENDS\r
+\r
+DG GROUP CODE,CONST,DATA\r
+\r
+\r
+CODE SEGMENT PUBLIC BYTE 'CODE'\r
+ASSUME CS:DG,DS:DG,ES:DG,SS:DG\r
+\r
+\r
+ PUBLIC UNASSEM\r
+ PUBLIC DISASLN,MEMIMM,JMPCALL,SIGNIMM,ALUFROMREG,WORDTOALU\r
+ PUBLIC GRP2,PREFIX,OUTVARW,GRP1,SSPRE,MOVSEGTO,DSPRE,SHIFT\r
+ PUBLIC ESPRE,IMMED,CSPRE,OUTVARB,CHK10,ACCIMM,INT3,INVARB\r
+ PUBLIC MOVSEGFROM,LOADACC,OUTFIXB,XCHGAX,REGIMMW,SHORTJMP\r
+ PUBLIC SAV8,M8087,M8087_DB,M8087_DF,M8087_D9,M8087_DD\r
+ PUBLIC SAV16,SAVHEX,INFIXW,REGIMMB,OUTFIXW,SHIFTV,LONGJMP\r
+ PUBLIC INVARW,STOREACC,INFIXB,NOOPERANDS,ALUTOREG\r
+ PUBLIC SEGOP,REGOP,GETADDR\r
+\r
+ EXTRN CRLF:NEAR,PRINTMES:NEAR,BLANK:NEAR,TAB:NEAR,OUT:NEAR\r
+ EXTRN HEX:NEAR,DEFAULT:NEAR,OUTSI:NEAR,OUTDI:NEAR\r
+\r
+UNASSEM:\r
+ MOV BP,[CSSAVE] ; Default code segment\r
+ MOV DI,OFFSET DG:DISADD ; Default address\r
+ MOV CX,DISPB ; Default length\r
+ SHR CX,1\r
+ SHR CX,1\r
+ CALL DEFAULT\r
+ MOV WORD PTR [DISADD],DX ; Displacement of disassembly\r
+ MOV WORD PTR [DISADD+2],AX ; Segment\r
+ MOV WORD PTR [DISCNT],CX ; No. of bytes (but whole instructions)\r
+DISLP:\r
+ CALL DISASLN ; Disassemble one line\r
+ CALL CRLF\r
+ TEST [DISCNT],-1 ; See if we've used up the range\r
+ JNZ DISLP\r
+ RET\r
+\r
+GOTDIS: PUSH DS ; RE-GET LAST BYTE\r
+ PUSH SI\r
+ LDS SI,DWORD PTR [DISADD]\r
+ MOV AL,[SI-1]\r
+ POP SI\r
+ POP DS\r
+ RET\r
+\r
+GETDIS:\r
+ PUSH DS\r
+ LDS SI,DWORD PTR [DISADD]\r
+ LODSB ; Get the next byte of code\r
+ POP DS\r
+ MOV WORD PTR [DISADD],SI ; Update pointer\r
+ PUSH AX\r
+ CALL HEX ; Display each code byte\r
+ MOV SI,[DISCNT]\r
+ OR SI,SI ; Check if range exhausted\r
+ JZ ENDRNG ; If so, don't wrap around\r
+ DEC SI ; Count off the bytes\r
+ MOV [DISCNT],SI\r
+ENDRNG:\r
+ INC BYTE PTR[BYTCNT] ; Keep track of no. of bytes per line\r
+ POP AX\r
+ RET\r
+\r
+DSPRE: INC BYTE PTR [NSEG+1]\r
+SSPRE: INC BYTE PTR [NSEG+1]\r
+CSPRE: INC BYTE PTR [NSEG+1]\r
+ESPRE: INC BYTE PTR [NSEG+1]\r
+\r
+PREFIX:\r
+ POP BX ; Dump off return address\r
+ CALL FINLN\r
+ CALL CRLF\r
+DISASLN:\r
+ PUSH DS\r
+ LDS SI,DWORD PTR [DISADD]\r
+ CALL OUTSI ; Show disassembly address\r
+ POP DS\r
+ CALL BLANK\r
+DISASLN1:\r
+ MOV BYTE PTR [BYTCNT],0 ; Count of code bytes per line\r
+ MOV DI,OFFSET DG:OPBUF ; Point to operand buffer\r
+ MOV AL," "\r
+ MOV CX,OPBUFLEN-1 ; Don't do last byte which has end marker\r
+ REP STOSB ; Initialize operand buffer to blanks\r
+ MOV BYTE PTR [DI]," "+80H\r
+ CALL GETDIS ; Get opcode\r
+ MOV AH,0\r
+ MOV BX,AX\r
+ AND AL,1 ; Mask to "W" bit\r
+ MOV [AWORD],AL\r
+ MOV AL,BL ; Restore opcode\r
+ SHL BX,1\r
+ SHL BX,1 ; Multiply opcode by 4\r
+ ADD BX,OFFSET DG:DISTAB\r
+ MOV DX,[BX] ; Get pointer to mnemonic from table\r
+ MOV [OPCODE],DX ; Save it until line is complete\r
+ MOV DI,OFFSET DG:OPBUF ; Initialize for opcode routines\r
+ CALL WORD PTR [BX+2] ; Dispatch to opcode routine\r
+FINLN:\r
+ MOV SI,OFFSET DG:DISADD\r
+ MOV AH,[BYTCNT] ; See how many bytes in this instruction\r
+ ADD AH,AH ; Each uses two characters\r
+ MOV AL,14 ; Amount of space we want to use\r
+ SUB AL,AH ; See how many fill characters needed\r
+ CBW\r
+ XCHG CX,AX ; Parameter for TAB needed in CX\r
+ CALL TAB\r
+ MOV SI,[OPCODE]\r
+ OR SI,SI ; MAKE SURE THERE IS SOMETHING TO PRINT\r
+ JZ NOOPC\r
+ CALL PRINTMES ; Print opcode mnemonic\r
+ MOV AL,9\r
+ CALL OUT ; and a tab\r
+NOOPC: MOV SI,OFFSET DG:OPBUF\r
+ JMP PRINTMES ; and the operand buffer\r
+\r
+GETMODE:\r
+ CALL GETDIS ; Get the address mode byte\r
+ MOV AH,AL\r
+ AND AL,7 ; Mask to "r/m" field\r
+ MOV [REGMEM],AL\r
+ SHR AH,1\r
+ SHR AH,1\r
+ SHR AH,1\r
+ MOV AL,AH\r
+ AND AL,7 ; Mask to center 3-bit field\r
+ MOV [MIDFLD],AL\r
+ SHR AH,1\r
+ SHR AH,1\r
+ SHR AH,1\r
+ MOV [MODE],AH ; Leaving 2-bit "MOD" field\r
+ RET\r
+\r
+IMMED:\r
+ MOV BX,OFFSET DG:IMMTAB\r
+ CALL GETMNE\r
+FINIMM:\r
+ CALL TESTREG\r
+ JMP SHORT IMM\r
+\r
+MEMIMM:\r
+ CALL GETMODE\r
+ JMP SHORT FINIMM\r
+\r
+ACCIMM:\r
+ XOR AL,AL\r
+IMM1:\r
+ CALL SAVREG\r
+IMM:\r
+ MOV AL,","\r
+ STOSB\r
+ TEST BYTE PTR [AWORD],-1\r
+ JNZ SAV16\r
+SAV8:\r
+ CALL GETDIS\r
+ JMP SHORT SAVHEX\r
+\r
+LONGJMP:\r
+ PUSH DI\r
+ MOV DI,OFFSET DG:TEMP\r
+ CALL SAV16\r
+ POP DI\r
+ CALL SAV16\r
+ MOV AL,":"\r
+ STOSB\r
+ MOV SI,OFFSET DG:TEMP\r
+ MOV CX,4\r
+MOVDIG:\r
+ LODSB\r
+ STOSB\r
+ LOOP MOVDIG\r
+ RET\r
+SAV16:\r
+ CALL GETDIS ; Get low byte\r
+ MOV DL,AL\r
+ CALL GETDIS ; Get high byte\r
+ MOV DH,AL\r
+ CALL SAVHEX ; Convert and store high byte\r
+ MOV AL,DL\r
+SAVHEX:\r
+ MOV AH,AL\r
+ SHR AL,1\r
+ SHR AL,1\r
+ SHR AL,1\r
+ SHR AL,1\r
+ CALL SAVDIG\r
+ MOV AL,AH\r
+SAVDIG:\r
+ AND AL,0FH\r
+ ADD AL,90H\r
+ DAA\r
+ ADC AL,40H\r
+ DAA\r
+ STOSB\r
+ RET\r
+\r
+CHK10:\r
+ CALL GETDIS\r
+ CMP AL,10\r
+ JNZ SAVHEX\r
+ RET\r
+\r
+SIGNIMM:\r
+ MOV BX,OFFSET DG:IMMTAB\r
+ CALL GETMNE\r
+ CALL TESTREG\r
+ MOV AL,","\r
+ STOSB\r
+SAVD8:\r
+ CALL GETDIS ; Get signed 8-bit number\r
+ CBW\r
+ MOV DX,AX ; Save true 16-bit value in DX\r
+ MOV AH,AL\r
+ MOV AL,"+"\r
+ OR AH,AH\r
+; JZ nosign\r
+ JNS POSITIV ; OK if positive\r
+ MOV AL,"-"\r
+ NEG AH ; Get magnitude if negative\r
+POSITIV:\r
+ STOSB\r
+; nosign:\r
+ MOV AL,AH\r
+ JMP SHORT SAVHEX\r
+\r
+ALUFROMREG:\r
+ CALL GETADDR\r
+ MOV AL,","\r
+ STOSB\r
+REGFLD:\r
+ MOV AL,[MIDFLD]\r
+SAVREG:\r
+ MOV SI,OFFSET DG:REG8\r
+ CMP BYTE PTR [AWORD],1\r
+ JNE FNDREG\r
+SAVREG16:\r
+ MOV SI,OFFSET DG:REG16\r
+FNDREG:\r
+ CBW\r
+ ADD SI,AX\r
+ ADD SI,AX\r
+ MOVSW\r
+ RET\r
+\r
+SEGOP:\r
+ SHR AL,1\r
+ SHR AL,1\r
+ SHR AL,1\r
+SAVSEG:\r
+ AND AL,3\r
+ MOV SI,OFFSET DG:SREG\r
+ JMP SHORT FNDREG\r
+\r
+REGOP:\r
+ AND AL,7\r
+ JMP SHORT SAVREG16\r
+\r
+MOVSEGTO:\r
+ MOV BYTE PTR [AWORD],1\r
+ CALL GETADDR\r
+ MOV AL,","\r
+ STOSB\r
+ MOV AL,[MIDFLD]\r
+ JMP SHORT SAVSEG\r
+\r
+MOVSEGFROM:\r
+ CALL GETMODE\r
+ CALL SAVSEG\r
+ MOV BYTE PTR [AWORD],1\r
+ JMP SHORT MEMOP2\r
+\r
+GETADDR:\r
+ CALL GETMODE\r
+ JMP SHORT ADDRMOD\r
+\r
+WORDTOALU:\r
+ MOV BYTE PTR [AWORD],1\r
+ALUTOREG:\r
+ CALL GETMODE\r
+ CALL REGFLD\r
+MEMOP2:\r
+ MOV AL,","\r
+ STOSB\r
+ADDRMOD:\r
+ CMP BYTE PTR [MODE],3\r
+ MOV AL,[REGMEM]\r
+ JE SAVREG\r
+ XOR BX,BX\r
+ MOV BYTE PTR [NSEG],3\r
+ MOV BYTE PTR [DI],"["\r
+ INC DI\r
+ CMP AL,6\r
+ JNE NODRCT\r
+ CMP BYTE PTR [MODE],0\r
+ JE DIRECT ; Mode=0 and R/M=6 means direct addr.\r
+NODRCT:\r
+ MOV DL,AL\r
+ CMP AL,1\r
+ JBE USEBX\r
+ CMP AL,7\r
+ JE USEBX\r
+ CMP AL,3\r
+ JBE USEBP\r
+ CMP AL,6\r
+ JNE CHKPLS\r
+USEBP:\r
+ MOV BX,[BPSAVE]\r
+ MOV BYTE PTR [NSEG],2 ; Change default to Stack Segment\r
+ MOV AX,BPREG\r
+SAVBASE:\r
+ STOSW\r
+CHKPLS:\r
+ CMP DL,4\r
+ JAE NOPLUS\r
+ MOV AL,"+"\r
+ STOSB\r
+NOPLUS:\r
+ CMP DL,6\r
+ JAE DOMODE ; No index register\r
+ AND DL,1 ; Even for SI, odd for DI\r
+ JZ USESI\r
+ ADD BX,[DISAVE]\r
+ MOV AX,DIREG\r
+SAVINDX:\r
+ STOSW\r
+DOMODE:\r
+ MOV AL,[MODE]\r
+ OR AL,AL\r
+ JZ CLOSADD ; If no displacement, then done\r
+ CMP AL,2\r
+ JZ ADDDIR\r
+ CALL SAVD8 ; Signed 8-bit displacement\r
+ADDCLOS:\r
+ ADD BX,DX\r
+CLOSADD:\r
+ MOV AL,"]"\r
+ STOSB\r
+ MOV [INDEX],BX\r
+NOOPERANDS:\r
+ RET\r
+\r
+ADDDIR:\r
+ MOV AL,"+"\r
+ STOSB\r
+DIRECT:\r
+ CALL SAV16\r
+ JMP SHORT ADDCLOS\r
+\r
+USEBX:\r
+ MOV BX,[BXSAVE]\r
+ MOV AX,BXREG\r
+ JMP SHORT SAVBASE\r
+\r
+USESI:\r
+ ADD BX,[SISAVE]\r
+ MOV AX,SIREG\r
+ JMP SHORT SAVINDX\r
+\r
+SHORTJMP:\r
+ CALL GETDIS\r
+ CBW\r
+ ADD AX,WORD PTR [DISADD]\r
+ XCHG DX,AX\r
+SAVJMP:\r
+ MOV AL,DH\r
+ CALL SAVHEX\r
+ MOV AL,DL\r
+ JMP SAVHEX\r
+\r
+JMPCALL:\r
+ CALL GETDIS\r
+ MOV DL,AL\r
+ CALL GETDIS\r
+ MOV DH,AL\r
+ ADD DX,WORD PTR [DISADD]\r
+ JMP SHORT SAVJMP\r
+\r
+XCHGAX:\r
+ AND AL,7\r
+ CALL SAVREG16\r
+ MOV AL,","\r
+ STOSB\r
+ XOR AL,AL\r
+ JMP SAVREG16\r
+\r
+LOADACC:\r
+ XOR AL,AL\r
+ CALL SAVREG\r
+ MOV AL,","\r
+ STOSB\r
+MEMDIR:\r
+ MOV AL,"["\r
+ STOSB\r
+ XOR BX,BX\r
+ MOV BYTE PTR [NSEG],3\r
+ JMP DIRECT\r
+\r
+STOREACC:\r
+ CALL MEMDIR\r
+ MOV AL,","\r
+ STOSB\r
+ XOR AL,AL\r
+ JMP SAVREG\r
+\r
+REGIMMB:\r
+ MOV BYTE PTR [AWORD],0\r
+ JMP SHORT REGIMM\r
+REGIMMW:\r
+ MOV BYTE PTR [AWORD],1\r
+REGIMM:\r
+ AND AL,7\r
+ JMP IMM1\r
+\r
+INT3:\r
+ MOV BYTE PTR [DI],"3"\r
+ RET\r
+;\r
+; 8087 instructions whose first byte is 0dfh\r
+;\r
+M8087_DF:\r
+ CALL GET64F\r
+ JZ ISDD3\r
+ MOV SI,OFFSET DG:MDF_TAB\r
+ JMP NODB3\r
+;\r
+; 8087 instructions whose first byte is 0ddh\r
+;\r
+M8087_DD:\r
+ CALL GET64F\r
+ JZ ISDD3\r
+ MOV SI,OFFSET DG:MDD_TAB\r
+ JMP NOD93\r
+\r
+ISDD3:\r
+ MOV AL,DL\r
+ TEST AL,100B\r
+ JZ ISSTI\r
+ JMP ESC0\r
+ISSTI: AND AL,11B\r
+ MOV SI,OFFSET DG:MDD_TAB2\r
+ MOV CL,AL\r
+ CALL MOVBYT\r
+ JMP PUTRST\r
+;\r
+; 8087 instructions whose first byte is 0dbh\r
+;\r
+M8087_DB:\r
+ CALL GET64F\r
+ JZ ISDB3\r
+ MOV SI,OFFSET DG:MDB_TAB\r
+NODB3: CALL PUTOP\r
+ CALL PUTSIZE\r
+ JMP ADDRMOD\r
+\r
+ISDB3:\r
+ MOV AL,DL\r
+ TEST AL,100B\r
+ JNZ ISDBIG\r
+ESC0V: JMP ESC0\r
+ISDBIG: CALL GOTDIS\r
+ AND AL,11111B\r
+ CMP AL,4\r
+ JAE ESC0V\r
+ MOV SI,OFFSET DG:MDB_TAB2\r
+ JMP DOBIG\r
+;\r
+; 8087 instructions whose first byte is 0d9h\r
+;\r
+M8087_D9:\r
+ CALL GET64F\r
+ JZ ISD93\r
+\r
+ MOV SI,OFFSET DG:MD9_TAB\r
+NOD93: CALL PUTOP\r
+ AND AL,111B\r
+ CMP AL,3\r
+ JA NOSHO\r
+ MOV AL,DL\r
+ CALL PUTSIZE\r
+NOSHO: JMP ADDRMOD\r
+\r
+ISD93: MOV AL,DL\r
+ TEST AL,100B\r
+ JNZ ISD9BIG\r
+ AND AL,111B\r
+ OR AL,AL\r
+ JNZ NOTFLD\r
+ MOV AX,"DL"\r
+ STOSW\r
+ JMP SHORT PUTRST\r
+NOTFLD: CMP AL,1\r
+ JNZ NOTFXCH\r
+ MOV AX,"CX"\r
+ STOSW\r
+ MOV AL,"H"\r
+ JMP SHORT PUTRST1\r
+NOTFXCH:CMP AL,3\r
+ JNZ NOTFSTP\r
+ MOV AX,"TS"\r
+ STOSW\r
+ MOV AL,"P"\r
+PUTRST1:STOSB\r
+PUTRST: MOV AL,9\r
+ STOSB\r
+ JMP PUTST0\r
+\r
+NOTFSTP:CALL GOTDIS\r
+ CMP AL,11010000B ; CHECK FOR FNOP\r
+ JZ GOTFNOP\r
+ JMP ESC0\r
+GOTFNOP:MOV AX,"ON"\r
+ STOSW\r
+ MOV AL,"P"\r
+ STOSB\r
+ RET\r
+\r
+ISD9BIG:\r
+ CALL GOTDIS ; GET THE MODE BYTE\r
+ MOV SI,OFFSET DG:MD9_TAB2\r
+DOBIG: AND AL,11111B\r
+ MOV CL,AL\r
+ JMP MOVBYT\r
+;\r
+; entry point for the remaining 8087 instructions\r
+;\r
+M8087:\r
+ CALL GET64\r
+ CALL PUTFI ; PUT FIRST PART OF OPCODE\r
+ MOV AL,DL\r
+ CMP BYTE PTR [MODE],11B ; CHECK FOR REGISTER MODE\r
+ JZ MODEIS3\r
+ CALL PUTMN ; PUT MIDDLE PART OF OPCODE\r
+NO3: MOV AL,9 ; OUTPUT A TAB\r
+ STOSB\r
+ MOV AL,DL\r
+ CALL PUTSIZE ; OUTPUT THE OPERAND SIZE\r
+ JMP ADDRMOD\r
+\r
+MODEIS3:\r
+ TEST AL,100000B ; D BIT SET?\r
+ JZ MPUT ; NOPE...\r
+ TEST AL,000100B ; FDIV OR FSUB?\r
+ JZ MPUT ; NOPE...\r
+ XOR AL,1 ; REVERSE SENSE OF R\r
+ MOV DL,AL ; SAVE CHANGE\r
+MPUT: CALL PUTMN ; PUT MIDDLE PART OF OPCODE\r
+ MOV AL,DL\r
+ TEST AL,010000B\r
+ JZ NOPSH\r
+ MOV AL,"P"\r
+ STOSB\r
+NOPSH: MOV AL,9\r
+ STOSB\r
+ MOV AL,DL\r
+ AND AL,00000111B\r
+ CMP AL,2 ; FCOM\r
+ JZ PUTST0\r
+ CMP AL,3 ; FCOMP\r
+ JZ PUTST0\r
+ MOV AL,DL\r
+ TEST AL,100000B\r
+ JZ PUTSTST0\r
+;\r
+; output 8087 registers in the form st(n),st\r
+;\r
+PUTST0ST:\r
+ CALL PUTST0\r
+ MOV AL,','\r
+ISCOMP: STOSB\r
+\r
+PUTST: MOV AX,"TS"\r
+ STOSW\r
+ RET\r
+;\r
+; output 8087 registers in the form st,st(n)\r
+;\r
+PUTSTST0:\r
+ CALL PUTST\r
+ MOV AL,','\r
+ STOSB\r
+\r
+PUTST0: CALL PUTST\r
+ MOV AL,"("\r
+ STOSB\r
+ MOV AL,[REGMEM]\r
+ ADD AL,"0"\r
+ STOSB\r
+ MOV AL,")"\r
+ STOSB\r
+ RET\r
+;\r
+; output an 8087 mnemonic\r
+;\r
+PUTMN: MOV SI,OFFSET DG:M8087_TAB\r
+ MOV CL,AL\r
+ AND CL,00000111B\r
+ JMP SHORT MOVBYT\r
+;\r
+; output either 'FI' or 'F' for first byte of opcode\r
+;\r
+PUTFI: MOV SI,OFFSET DG:FI_TAB\r
+ JMP SHORT PUTFI2\r
+;\r
+; output size (dword, tbyte, etc.)\r
+;\r
+PUTSIZE:MOV SI,OFFSET DG:SIZE_TAB\r
+PUTFI2: CMP BYTE PTR [MODE],11B ; check if 8087 register\r
+ JNZ PUTFI3\r
+ AND AL,111000B ; LOOK FOR INVALID FORM OF 0DAH OPERANDS\r
+ CMP AL,010000B\r
+ JZ ESC0PJ\r
+ MOV AL,DL\r
+ CMP AL,110011B ; FCOMPP\r
+ JNZ GOFI\r
+ CMP BYTE PTR [REGMEM],1\r
+ JZ GOFI\r
+ESC0PJ: JMP ESC0P\r
+GOFI: XOR CL,CL\r
+ JMP SHORT MOVBYT\r
+;\r
+; Look for qword\r
+;\r
+PUTFI3: CMP AL,111101B\r
+ JZ GOTQU\r
+ CMP AL,111111B\r
+ JNZ NOTQU\r
+GOTQU: MOV CL,2\r
+ JMP SHORT MOVBYT\r
+;\r
+; look for tbyte\r
+;\r
+NOTQU: CMP AL,011101B\r
+ JZ GOTTB\r
+ CMP AL,111100B\r
+ JZ GOTTB\r
+ CMP AL,111110B\r
+ JZ GOTTB\r
+ CMP AL,011111B\r
+ JNZ NOTTB\r
+GOTTB: MOV CL,5\r
+ JMP SHORT MOVBYT\r
+\r
+NOTTB: MOV CL,4\r
+ SHR AL,CL\r
+ MOV CL,AL\r
+;\r
+; SI POINTS TO A TABLE OF TEXT SEPARATED BY "$"\r
+; CL = WHICH ELEMENT IN THE TABLE YOU WISH TO COPY TO [DI]\r
+;\r
+MOVBYT: PUSH AX\r
+ INC CL\r
+MOVBYT1:DEC CL\r
+ JZ MOVBYT3\r
+MOVBYT2:LODSB\r
+ CMP AL,'$'\r
+ JZ MOVBYT1\r
+ JMP MOVBYT2\r
+MOVBYT3:LODSB\r
+ CMP AL,'$'\r
+ JZ MOVBYT5\r
+ CMP AL,'@' ; THIS MEANS RESVERED OP-CODE\r
+ JNZ MOVBYT4\r
+ POP AX\r
+ JMP SHORT ESC0P ; GO DO AN ESCAPE COMMAND\r
+MOVBYT4:STOSB\r
+ JMP MOVBYT3\r
+MOVBYT5:POP AX\r
+ RET\r
+\r
+PUTOP: AND AL,111B\r
+ MOV CL,AL\r
+ CALL MOVBYT\r
+ MOV AL,9\r
+ STOSB\r
+ MOV AL,DL\r
+ RET\r
+\r
+GET64F: CALL GET64\r
+ MOV AL,"F"\r
+ STOSB\r
+ CMP BYTE PTR [MODE],3\r
+ MOV AL,DL\r
+ RET\r
+\r
+GET64:\r
+ AND AL,7\r
+ MOV DL,AL\r
+ CALL GETMODE\r
+ SHL DL,1\r
+ SHL DL,1\r
+ SHL DL,1\r
+ OR AL,DL\r
+ MOV DL,AL ; SAVE RESULT\r
+ RET\r
+\r
+ESC0P: POP DI ; CLEAN UP STACK\r
+ESC0: MOV WORD PTR [OPCODE],OFFSET DG:ESCMN\r
+ MOV AL,DL\r
+ MOV DI,OFFSET DG:OPBUF\r
+ JMP SHORT ESC1\r
+\r
+ESC: CALL GET64\r
+ESC1: CALL SAVHEX\r
+ CMP BYTE PTR [MODE],3\r
+ JZ SHRTESC\r
+ MOV BYTE PTR [AWORD],1\r
+ JMP MEMOP2\r
+\r
+SHRTESC:\r
+ MOV AL,","\r
+ STOSB\r
+ MOV AL,[REGMEM]\r
+ AND AL,7\r
+ JMP SAVREG\r
+\r
+INVARW:\r
+ CALL PUTAX\r
+ JMP SHORT INVAR\r
+INVARB:\r
+ CALL PUTAL\r
+INVAR: MOV AL,','\r
+ STOSB\r
+ JMP PUTDX\r
+\r
+INFIXW:\r
+ CALL PUTAX\r
+ JMP SHORT INFIX\r
+INFIXB:\r
+ CALL PUTAL\r
+INFIX: MOV AL,','\r
+ STOSB\r
+ JMP SAV8\r
+ STOSW\r
+ RET\r
+\r
+OUTVARB:\r
+ MOV BX,"LA"\r
+ JMP SHORT OUTVAR\r
+OUTVARW:\r
+ MOV BX,"XA"\r
+OUTVAR: CALL PUTDX\r
+OUTFV: MOV AL,','\r
+ STOSB\r
+ MOV AX,BX\r
+ STOSW\r
+ RET\r
+\r
+OUTFIXB:\r
+ MOV BX,"LA"\r
+ JMP SHORT OUTFIX\r
+OUTFIXW:\r
+ MOV BX,"XA"\r
+OUTFIX: CALL SAV8\r
+ JMP OUTFV\r
+\r
+PUTAL: MOV AX,"A"+4C00H ; "AL"\r
+ JMP SHORT PUTX\r
+PUTAX: MOV AX,"A"+5800H ; "AX"\r
+ JMP SHORT PUTX\r
+PUTDX: MOV AX,"D"+5800H ; "DX"\r
+PUTX: STOSW\r
+ RET\r
+\r
+SHFT:\r
+ MOV BX,OFFSET DG:SHFTAB\r
+ CALL GETMNE\r
+TESTREG:\r
+ CMP BYTE PTR [MODE],3\r
+ JZ NOFLG\r
+ MOV SI,OFFSET DG:SIZE_TAB\r
+ MOV CL,3\r
+ TEST BYTE PTR [AWORD],-1\r
+ JNZ TEST_1\r
+ INC CL\r
+TEST_1: CALL MOVBYT\r
+NOFLG:\r
+ JMP ADDRMOD\r
+\r
+SHIFTV:\r
+ CALL SHFT\r
+ MOV AL,","\r
+ STOSB\r
+ MOV WORD PTR [DI],"C"+4C00H ; "CL"\r
+ RET\r
+\r
+SHIFT:\r
+ CALL SHFT\r
+ MOV AX,"1,"\r
+ STOSW\r
+ RET\r
+\r
+GETMNE:\r
+ CALL GETMODE\r
+ MOV DL,AL\r
+ CBW\r
+ SHL AX,1\r
+ ADD BX,AX\r
+ MOV AX,[BX]\r
+ MOV [OPCODE],AX\r
+ MOV AL,DL\r
+ RET\r
+\r
+GRP1:\r
+ MOV BX,OFFSET DG:GRP1TAB\r
+ CALL GETMNE\r
+ OR AL,AL\r
+ JZ FINIMMJ\r
+ JMP TESTREG\r
+FINIMMJ:\r
+ JMP FINIMM\r
+\r
+GRP2:\r
+ MOV BX,OFFSET DG:GRP2TAB\r
+ CALL GETMNE\r
+ CMP AL,2\r
+ JB TESTREG\r
+ CMP AL,6\r
+ JAE INDIRECT\r
+ TEST AL,1\r
+ JZ INDIRECT\r
+ MOV AX,"AF" ; "FAR"\r
+ STOSW\r
+ MOV AX," R"\r
+ STOSW\r
+INDIRECT:\r
+ JMP ADDRMOD\r
+\r
+CODE ENDS\r
+ END UNASSEM\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+TITLE DEBUGger for MS-DOS\r
+; DEBUG-86 8086 debugger runs under 86-DOS version 2.30\r
+;\r
+; Modified 5/4/82 by AaronR to do all I/O direct to devices\r
+; Runs on MS-DOS 1.28 and above\r
+; REV 1.20\r
+; Tab expansion\r
+; New device interface (1.29 and above)\r
+; REV 2.0\r
+; line by line assembler added by C. Peters\r
+; REV 2.1\r
+; Uses EXEC system call\r
+; REV 2.2\r
+; Ztrace mode by zibo.\r
+; Fix dump display to indent properly\r
+; Parity nonsense by zibo\r
+;\r
+; REV 2.3\r
+; Split into seperate modules to allow for\r
+; assembly on an IBM PC\r
+;\r
+\r
+\r
+\r
+.xlist\r
+.xcref\r
+ INCLUDE DEBEQU.ASM\r
+ INCLUDE DOSSYM.ASM\r
+.cref\r
+.list\r
+\r
+ IF SYSVER\r
+\r
+; Structure for system call 72\r
+\r
+SYSINITVAR STRUC\r
+DPBHEAD DD ? ; Pointer to head of DPB-FAT list\r
+sft_addr DD ? ; Pointer to first FCB table\r
+; The following address points to the CLOCK device\r
+BCLOCK DD ?\r
+; The following address is used by DISKSTATCHK it is always\r
+; points to the console input device header\r
+BCON DD ? ; Console device entry points\r
+NUMIO DB 0 ; Number of disk tables\r
+MAXSEC DW 0 ; Maximum allowed sector size\r
+BUFFHEAD DD ?\r
+DEVHEAD DD ?\r
+SYSINITVAR ENDS\r
+\r
+ ENDIF\r
+\r
+\r
+CODE SEGMENT PUBLIC 'CODE'\r
+CODE ENDS\r
+\r
+CONST SEGMENT PUBLIC BYTE\r
+\r
+ EXTRN USER_PROC_PDB:WORD,STACK:BYTE,CSSAVE:WORD,DSSAVE:WORD\r
+ EXTRN SPSAVE:WORD,IPSAVE:WORD,LINEBUF:BYTE,QFLAG:BYTE\r
+ EXTRN NEWEXEC:BYTE,HEADSAVE:WORD,LBUFSIZ:BYTE,BACMES:BYTE\r
+ EXTRN BADVER:BYTE,ENDMES:BYTE,CARRET:BYTE,ParityMes:BYTE\r
+\r
+ IF IBMVER\r
+ EXTRN DSIZ:BYTE,NOREGL:BYTE,DISPB:WORD\r
+ ENDIF\r
+\r
+ IF SYSVER\r
+ EXTRN CONFCB:BYTE,POUT:DWORD,COUT:DWORD,CIN:DWORD,IOBUFF:BYTE\r
+ EXTRN IOADDR:DWORD,IOCALL:BYTE,IOCOM:BYTE,IOSTAT:WORD,IOCNT:WORD\r
+ EXTRN IOSEG:WORD,COLPOS:BYTE,BADDEV:BYTE,BADLSTMES:BYTE\r
+ EXTRN LBUFFCNT:BYTE,PFLAG:BYTE\r
+ ENDIF\r
+\r
+CONST ENDS\r
+\r
+DATA SEGMENT PUBLIC BYTE\r
+\r
+ EXTRN PARSERR:BYTE,DATAEND:WORD,ParityFlag:BYTE,DISADD:BYTE\r
+ EXTRN ASMADD:BYTE,DEFDUMP:BYTE,BYTEBUF:BYTE\r
+\r
+DATA ENDS\r
+\r
+DG GROUP CODE,CONST,DATA\r
+\r
+\r
+CODE SEGMENT PUBLIC 'CODE'\r
+ASSUME CS:DG,DS:DG,ES:DG,SS:DG\r
+\r
+ PUBLIC RESTART,SET_TERMINATE_VECTOR,DABORT,TERMINATE,COMMAND\r
+ PUBLIC FIND_DEBUG,CRLF,BLANK,TAB,OUT,INBUF,SCANB,SCANP\r
+ PUBLIC PRINTMES,RPRBUF,HEX,OUTSI,OUTDI,OUT16,DIGIT,BACKUP,RBUFIN\r
+\r
+ IF SYSVER\r
+ PUBLIC SETUDEV,DEVIOCALL\r
+ EXTRN DISPREG:NEAR,IN:NEAR\r
+ ENDIF\r
+\r
+ EXTRN PERR:NEAR,COMPARE:NEAR,DUMP:NEAR,ENTER:NEAR,FILL:NEAR\r
+ EXTRN GO:NEAR,INPUT:NEAR,LOAD:NEAR,MOVE:NEAR,NAME:NEAR\r
+ EXTRN REG:NEAR,SEARCH:NEAR,DWRITE:NEAR,UNASSEM:NEAR,ASSEM:NEAR\r
+ EXTRN OUTPUT:NEAR,ZTRACE:NEAR,TRACE:NEAR,GETHEX:NEAR,GETEOL:NEAR\r
+\r
+ EXTRN PREPNAME:NEAR,DEFIO:NEAR,SKIP_FILE:NEAR,DEBUG_FOUND:NEAR\r
+ EXTRN TrapParity:NEAR,ReleaseParity:NEAR\r
+\r
+ ORG 100H\r
+\r
+START:\r
+DEBUG:\r
+ JMP SHORT DSTRT\r
+\r
+HEADER DB "Vers 2.30"\r
+\r
+DSTRT:\r
+DOSVER_HIGH EQU 0200H ; 2.00 in hex\r
+ MOV AH,GET_VERSION\r
+ INT 21H\r
+ XCHG AH,AL ; Turn it around to AH.AL\r
+ CMP AX,DOSVER_HIGH\r
+ JAE OKDOS\r
+GOTBADDOS:\r
+ MOV DX,OFFSET DG:BADVER\r
+ MOV AH,STD_CON_STRING_OUTPUT\r
+ INT 21H\r
+ INT 20H\r
+\r
+OKDOS:\r
+ CALL TrapParity ; scarf up those parity guys\r
+ MOV AH,GET_CURRENT_PDB\r
+ INT 21H\r
+ MOV [USER_PROC_PDB],BX ; Initially set to DEBUG\r
+\r
+ IF SYSVER\r
+ MOV [IOSEG],CS\r
+ ENDIF\r
+\r
+ MOV SP,OFFSET DG:STACK\r
+ MOV [PARSERR],AL\r
+ MOV AH,GET_IN_VARS\r
+ INT 21H\r
+\r
+\r
+ IF SYSVER\r
+ LDS SI,ES:[BX.BCON]\r
+ MOV WORD PTR CS:[CIN+2],DS\r
+ MOV WORD PTR CS:[CIN],SI\r
+ MOV WORD PTR CS:[COUT+2],DS\r
+ MOV WORD PTR CS:[COUT],SI\r
+ PUSH CS\r
+ POP DS\r
+ MOV DX,OFFSET DG:CONFCB\r
+ MOV AH,FCB_OPEN\r
+ INT 21H\r
+ OR AL,AL\r
+ JZ GOTLIST\r
+ MOV DX,OFFSET DG:BADLSTMES\r
+ CALL RPRBUF\r
+ CALL RBUFIN\r
+ CALL CRLF\r
+ MOV CL,[LBUFFCNT]\r
+ OR CL,CL\r
+ JZ NOLIST1 ; User didn't specify one\r
+ XOR CH,CH\r
+ MOV DI,OFFSET DG:(CONFCB + 1)\r
+ MOV SI,OFFSET DG:LINEBUF\r
+ REP MOVSB\r
+ MOV DX,OFFSET DG:CONFCB\r
+ MOV AH,FCB_OPEN\r
+ INT 21H\r
+ OR AL,AL\r
+ JZ GOTLIST ; GOOD\r
+ MOV DX,OFFSET DG:BADDEV\r
+ CALL RPRBUF\r
+NOLIST1:\r
+ MOV WORD PTR [POUT+2],CS\r
+ MOV WORD PTR [POUT],OFFSET DG:LONGRET\r
+ JMP NOLIST\r
+\r
+XXX PROC FAR\r
+LONGRET:RET\r
+XXX ENDP\r
+ ENDIF\r
+\r
+GOTLIST:\r
+ IF SYSVER\r
+ MOV SI,DX\r
+ LDS SI,DWORD PTR DS:[SI.fcb_FIRCLUS]\r
+ MOV WORD PTR CS:[POUT+2],DS\r
+ MOV WORD PTR CS:[POUT],SI\r
+ ENDIF\r
+NOLIST:\r
+ MOV AX,CS\r
+ MOV DS,AX\r
+ MOV ES,AX\r
+\r
+; Code to print header\r
+; MOV DX,OFFSET DG:HEADER\r
+; CALL RPRBUF\r
+\r
+ CALL SET_TERMINATE_VECTOR\r
+\r
+ IF SETCNTC\r
+ MOV AL,23H ; Set vector 23H\r
+ MOV DX,OFFSET DG:DABORT\r
+ INT 21H\r
+ ENDIF\r
+\r
+ MOV DX,CS ; Get DEBUG's segment\r
+ MOV AX,OFFSET DG:DATAEND + 15 ; End of debug\r
+ SHR AX,1 ; Convert to segments\r
+ SHR AX,1\r
+ SHR AX,1\r
+ SHR AX,1\r
+ ADD DX,AX ; Add siz of debug in paragraphs\r
+ MOV AH,CREATE_PROCESS_DATA_BLOCK ; create program segment just after DEBUG\r
+ INT 21H\r
+ MOV AX,DX\r
+ MOV DI,OFFSET DG:DSSAVE\r
+ CLD\r
+ STOSW\r
+ STOSW\r
+ STOSW\r
+ STOSW\r
+ MOV WORD PTR [DISADD+2],AX\r
+ MOV WORD PTR [ASMADD+2],AX\r
+ MOV WORD PTR [DEFDUMP+2],AX\r
+ MOV AX,100H\r
+ MOV WORD PTR[DISADD],AX\r
+ MOV WORD PTR[ASMADD],AX\r
+ MOV WORD PTR [DEFDUMP],AX\r
+ MOV DS,DX\r
+ MOV ES,DX\r
+ MOV DX,80H\r
+ MOV AH,SET_DMA\r
+ INT 21H ; Set default DMA address to 80H\r
+ MOV AX,WORD PTR DS:[6]\r
+ MOV BX,AX\r
+ CMP AX,0FFF0H\r
+ PUSH CS\r
+ POP DS\r
+ JAE SAVSTK\r
+ MOV AX,WORD PTR DS:[6]\r
+ PUSH BX\r
+ MOV BX,OFFSET DG:DATAEND + 15\r
+ AND BX,0FFF0H ; Size of DEBUG in bytes (rounded up to PARA)\r
+ SUB AX,BX\r
+ POP BX\r
+SAVSTK:\r
+ PUSH BX\r
+ DEC AX\r
+ DEC AX\r
+ MOV BX,AX\r
+ MOV WORD PTR [BX],0\r
+ POP BX\r
+ MOV SPSAVE,AX\r
+ DEC AH\r
+ MOV ES:WORD PTR [6],AX\r
+ SUB BX,AX\r
+ MOV CL,4\r
+ SHR BX,CL\r
+ ADD ES:WORD PTR [8],BX\r
+\r
+ IF IBMVER\r
+ ; Get screen size and initialize display related variables\r
+ MOV AH,15\r
+ INT 10H\r
+ CMP AH,40\r
+ JNZ PARSCHK\r
+ MOV BYTE PTR DSIZ,7\r
+ MOV BYTE PTR NOREGL,4\r
+ MOV DISPB,64\r
+ ENDIF\r
+\r
+PARSCHK:\r
+; Copy rest of command line to test program's parameter area\r
+ MOV DI,FCB\r
+ MOV SI,81H\r
+ MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H\r
+ INT 21H\r
+ CALL SKIP_FILE ; Make sure si points to delimiter\r
+ CALL PREPNAME\r
+ PUSH CS\r
+ POP ES\r
+FILECHK:\r
+ MOV DI,80H\r
+ CMP BYTE PTR ES:[DI],0 ; ANY STUFF FOUND?\r
+ JZ COMMAND ; NOPE\r
+FILOOP: INC DI\r
+ CMP BYTE PTR ES:[DI],13 ; COMMAND LINE JUST SPACES?\r
+ JZ COMMAND\r
+ CMP BYTE PTR ES:[DI]," "\r
+ JZ FILOOP\r
+ CMP BYTE PTR ES:[DI],9\r
+ JZ FILOOP\r
+\r
+ CALL DEFIO ; WELL READ IT IN\r
+ MOV AX,CSSAVE\r
+ MOV WORD PTR DISADD+2,AX\r
+ MOV WORD PTR ASMADD+2,AX\r
+ MOV AX,IPSAVE\r
+ MOV WORD PTR DISADD,AX\r
+ MOV WORD PTR ASMADD,AX\r
+COMMAND:\r
+ CLD\r
+ MOV AX,CS\r
+ MOV DS,AX\r
+ MOV ES,AX\r
+ MOV SS,AX\r
+ MOV SP,OFFSET DG:STACK\r
+ STI\r
+ CMP [ParityFlag],0 ; did we detect a parity error?\r
+ JZ GoPrompt ; nope, go prompt\r
+ MOV [ParityFlag],0 ; reset flag\r
+ MOV DX,OFFSET DG:ParityMes ; message to print\r
+ MOV AH,STD_CON_STRING_OUTPUT; easy way out\r
+ INT 21h ; blam\r
+GoPrompt:\r
+ MOV AL,PROMPT\r
+ CALL OUT\r
+ CALL INBUF ; Get command line\r
+; From now and throughout command line processing, DI points\r
+; to next character in command line to be processed.\r
+ CALL SCANB ; Scan off leading blanks\r
+ JZ COMMAND ; Null command?\r
+ LODSB ; AL=first non-blank character\r
+; Prepare command letter for table lookup\r
+ SUB AL,"A" ; Low end range check\r
+ JB ERR1\r
+ CMP AL,"Z"-"A" ; Upper end range check\r
+ JA ERR1\r
+ SHL AL,1 ; Times two\r
+ CBW ; Now a 16-bit quantity\r
+ XCHG BX,AX ; In BX we can address with it\r
+ CALL CS:[BX+COMTAB] ; Execute command\r
+ JMP SHORT COMMAND ; Get next command\r
+ERR1: JMP PERR\r
+\r
+SET_TERMINATE_VECTOR:\r
+ MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 22H ; Set vector 22H\r
+ MOV DX,OFFSET DG:TERMINATE\r
+ INT 21H\r
+ RET\r
+\r
+TERMINATE:\r
+ CMP BYTE PTR CS:[QFLAG],0\r
+ JNZ QUITING\r
+ MOV CS:[USER_PROC_PDB],CS\r
+ CMP BYTE PTR CS:[NEWEXEC],0\r
+ JZ NORMTERM\r
+ MOV AX,CS\r
+ MOV DS,AX\r
+ MOV SS,AX\r
+ MOV SP,OFFSET DG:STACK\r
+ MOV AX,[HEADSAVE]\r
+ JMP DEBUG_FOUND\r
+\r
+NORMTERM:\r
+ MOV DX,OFFSET DG:ENDMES\r
+ JMP SHORT RESTART\r
+\r
+QUITING:\r
+ MOV AX,(EXIT SHL 8)\r
+ INT 21H\r
+\r
+DABORT:\r
+ MOV DX,OFFSET DG:CARRET\r
+RESTART:\r
+ MOV AX,CS\r
+ MOV DS,AX\r
+ MOV SS,AX\r
+ MOV SP,OFFSET DG:STACK\r
+ CALL RPRBUF\r
+ JMP COMMAND\r
+\r
+ IF SYSVER\r
+SETUDEV:\r
+ MOV DI,OFFSET DG:CONFCB\r
+ MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H\r
+ INT 21H\r
+ CALL USERDEV\r
+ JMP DISPREG\r
+\r
+USERDEV:\r
+ MOV DX,OFFSET DG:CONFCB\r
+ MOV AH,FCB_OPEN\r
+ INT 21H\r
+ OR AL,AL\r
+ JNZ OPENERR\r
+ MOV SI,DX\r
+ TEST BYTE PTR [SI.fcb_DEVID],080H ; Device?\r
+ JZ OPENERR ; NO\r
+ LDS SI,DWORD PTR [CONFCB.fcb_FIRCLUS]\r
+ MOV WORD PTR CS:[CIN],SI\r
+ MOV WORD PTR CS:[CIN+2],DS\r
+ MOV WORD PTR CS:[COUT],SI\r
+ MOV WORD PTR CS:[COUT+2],DS\r
+ PUSH CS\r
+ POP DS\r
+ RET\r
+\r
+\r
+OPENERR:\r
+ MOV DX,OFFSET DG:BADDEV\r
+ CALL RPRBUF\r
+ RET\r
+ ENDIF\r
+\r
+; Get input line. Convert all characters NOT in quotes to upper case.\r
+\r
+INBUF:\r
+ CALL RBUFIN\r
+ MOV SI,OFFSET DG:LINEBUF\r
+ MOV DI,OFFSET DG:BYTEBUF\r
+CASECHK:\r
+ LODSB\r
+ CMP AL,'a'\r
+ JB NOCONV\r
+ CMP AL,'z'\r
+ JA NOCONV\r
+ ADD AL,"A"-"a" ; Convert to upper case\r
+NOCONV:\r
+ STOSB\r
+ CMP AL,13\r
+ JZ INDONE\r
+ CMP AL,'"'\r
+ JZ QUOTSCAN\r
+ CMP AL,"'"\r
+ JNZ CASECHK\r
+QUOTSCAN:\r
+ MOV AH,AL\r
+KILLSTR:\r
+ LODSB\r
+ STOSB\r
+ CMP AL,13\r
+ JZ INDONE\r
+ CMP AL,AH\r
+ JNZ KILLSTR\r
+ JMP SHORT CASECHK\r
+\r
+INDONE:\r
+ MOV SI,OFFSET DG:BYTEBUF\r
+\r
+; Output CR/LF sequence\r
+\r
+CRLF:\r
+ MOV AL,13\r
+ CALL OUT\r
+ MOV AL,10\r
+ JMP OUT\r
+\r
+; Physical backspace - blank, backspace, blank\r
+\r
+BACKUP:\r
+ MOV SI,OFFSET DG:BACMES\r
+\r
+; Print ASCII message. Last char has bit 7 set\r
+\r
+PRINTMES:\r
+ LODS CS:BYTE PTR [SI] ; Get char to print\r
+ CALL OUT\r
+ SHL AL,1 ; High bit set?\r
+ JNC PRINTMES\r
+ RET\r
+\r
+; Scan for parameters of a command\r
+\r
+SCANP:\r
+ CALL SCANB ; Get first non-blank\r
+ CMP BYTE PTR [SI],"," ; One comma between params OK\r
+ JNE EOLCHK ; If not comma, we found param\r
+ INC SI ; Skip over comma\r
+\r
+; Scan command line for next non-blank character\r
+\r
+SCANB:\r
+ PUSH AX\r
+SCANNEXT:\r
+ LODSB\r
+ CMP AL," "\r
+ JZ SCANNEXT\r
+ CMP AL,9\r
+ JZ SCANNEXT\r
+ DEC SI ; Back to first non-blank\r
+ POP AX\r
+EOLCHK:\r
+ CMP BYTE PTR [SI],13\r
+ RET\r
+\r
+; Hex addition and subtraction\r
+\r
+HEXADD:\r
+ MOV CX,4\r
+ CALL GETHEX\r
+ MOV DI,DX\r
+ MOV CX,4\r
+ CALL GETHEX\r
+ CALL GETEOL\r
+ PUSH DX\r
+ ADD DX,DI\r
+ CALL OUT16\r
+ CALL BLANK\r
+ CALL BLANK\r
+ POP DX\r
+ SUB DI,DX\r
+ MOV DX,DI\r
+ CALL OUT16\r
+ JMP SHORT CRLF\r
+\r
+; Print the hex address of DS:SI\r
+\r
+OUTSI:\r
+ MOV DX,DS ; Put DS where we can work with it\r
+ CALL OUT16 ; Display segment\r
+ MOV AL,":"\r
+ CALL OUT\r
+ MOV DX,SI\r
+ JMP SHORT OUT16 ; Output displacement\r
+\r
+; Print hex address of ES:DI\r
+; Same as OUTSI above\r
+\r
+OUTDI:\r
+ MOV DX,ES\r
+ CALL OUT16\r
+ MOV AL,":"\r
+ CALL OUT\r
+ MOV DX,DI\r
+\r
+; Print out 16-bit value in DX in hex\r
+\r
+OUT16:\r
+ MOV AL,DH ; High-order byte first\r
+ CALL HEX\r
+ MOV AL,DL ; Then low-order byte\r
+\r
+; Output byte in AL as two hex digits\r
+\r
+HEX:\r
+ MOV AH,AL ; Save for second digit\r
+; Shift high digit into low 4 bits\r
+ PUSH CX\r
+ MOV CL,4\r
+ SHR AL,CL\r
+ POP CX\r
+\r
+ CALL DIGIT ; Output first digit\r
+ MOV AL,AH ; Now do digit saved in AH\r
+DIGIT:\r
+ AND AL,0FH ; Mask to 4 bits\r
+; Trick 6-byte hex conversion works on 8086 too.\r
+ ADD AL,90H\r
+ DAA\r
+ ADC AL,40H\r
+ DAA\r
+\r
+; Console output of character in AL. No registers affected but bit 7\r
+; is reset before output.\r
+\r
+ IF SYSVER\r
+OUT:\r
+ PUSH AX\r
+ AND AL,7FH\r
+ CMP AL,7FH\r
+ JNZ NOTDEL\r
+ MOV AL,8 ; DELETE same as backspace\r
+NOTDEL:\r
+ CMP AL,9\r
+ JZ TABDO\r
+ CALL DOCONOUT\r
+ CMP AL,0DH\r
+ JZ ZEROPOS\r
+ CMP AL,0AH\r
+ JZ ZEROPOS\r
+ CMP AL,8\r
+ JNZ OOKRET\r
+ MOV AL," "\r
+ CALL DOCONOUT\r
+ MOV AL,8\r
+ CALL DOCONOUT\r
+ CMP BYTE PTR CS:[COLPOS],0\r
+ JZ NOTINC\r
+ DEC BYTE PTR CS:[COLPOS]\r
+ JMP NOTINC\r
+ZEROPOS:\r
+ MOV BYTE PTR CS:[COLPOS],0FFH\r
+OOKRET:\r
+ INC BYTE PTR CS:[COLPOS]\r
+NOTINC:\r
+ TEST BYTE PTR CS:[PFLAG],1\r
+ JZ POPRET\r
+ CALL LISTOUT\r
+POPRET:\r
+ POP AX\r
+ RET\r
+\r
+TABDO:\r
+ MOV AL,CS:[COLPOS]\r
+ OR AL,0F8H\r
+ NEG AL\r
+ PUSH CX\r
+ MOV CL,AL\r
+ XOR CH,CH\r
+ JCXZ POPTAB\r
+TABLP:\r
+ MOV AL," "\r
+ CALL OUT\r
+ LOOP TABLP\r
+POPTAB:\r
+ POP CX\r
+ POP AX\r
+ RET\r
+\r
+\r
+DOCONOUT:\r
+ PUSH DS\r
+ PUSH SI\r
+ PUSH AX\r
+CONOWAIT:\r
+ LDS SI,CS:[COUT]\r
+ MOV AH,10\r
+ CALL DEVIOCALL\r
+ MOV AX,CS:[IOSTAT]\r
+ AND AX,200H\r
+ JNZ CONOWAIT\r
+ POP AX\r
+ PUSH AX\r
+ MOV AH,8\r
+ CALL DEVIOCALL\r
+ POP AX\r
+ POP SI\r
+ POP DS\r
+ RET\r
+\r
+\r
+LISTOUT:\r
+ PUSH DS\r
+ PUSH SI\r
+ PUSH AX\r
+LISTWAIT:\r
+ LDS SI,CS:[POUT]\r
+ MOV AH,10\r
+ CALL DEVIOCALL\r
+ MOV AX,CS:[IOSTAT]\r
+ AND AX,200H\r
+ JNZ LISTWAIT\r
+ POP AX\r
+ PUSH AX\r
+ MOV AH,8\r
+ CALL DEVIOCALL\r
+ POP AX\r
+ POP SI\r
+ POP DS\r
+ RET\r
+\r
+DEVIOCALL:\r
+ PUSH ES\r
+ PUSH BX\r
+ PUSH CS\r
+ POP ES\r
+ MOV BX,OFFSET DG:IOCALL\r
+ MOV CS:[IOCOM],AH\r
+ MOV WORD PTR CS:[IOSTAT],0\r
+ MOV WORD PTR CS:[IOCNT],1\r
+ MOV CS:[IOBUFF],AL\r
+ MOV WORD PTR CS:[IOADDR+2],DS\r
+ MOV AX,[SI+6]\r
+ MOV WORD PTR CS:[IOADDR],AX\r
+ CALL DWORD PTR CS:[IOADDR]\r
+ MOV AX,[SI+8]\r
+ MOV WORD PTR CS:[IOADDR],AX\r
+ CALL DWORD PTR CS:[IOADDR]\r
+ MOV AL,CS:[IOBUFF]\r
+ POP BX\r
+ POP ES\r
+ RET\r
+ ELSE\r
+\r
+OUT:\r
+ PUSH DX\r
+ PUSH AX\r
+ AND AL,7FH\r
+ MOV DL,AL\r
+ MOV AH,2\r
+ INT 21H\r
+ POP AX\r
+ POP DX\r
+ RET\r
+ ENDIF\r
+\r
+\r
+ IF SYSVER\r
+RBUFIN:\r
+ PUSH AX\r
+ PUSH ES\r
+ PUSH DI\r
+ PUSH CS\r
+ POP ES\r
+ MOV BYTE PTR [LBUFFCNT],0\r
+ MOV DI,OFFSET DG:LINEBUF\r
+FILLBUF:\r
+ CALL IN\r
+ CMP AL,0DH\r
+ JZ BDONE\r
+ CMP AL,8\r
+ JZ ECHR\r
+ CMP AL,7FH\r
+ JZ ECHR\r
+ CMP BYTE PTR [LBUFFCNT],BUFLEN\r
+ JAE BFULL\r
+ STOSB\r
+ INC BYTE PTR [LBUFFCNT]\r
+ JMP SHORT FILLBUF\r
+\r
+BDONE:\r
+ STOSB\r
+ POP DI\r
+ POP ES\r
+ POP AX\r
+ RET\r
+\r
+BFULL:\r
+ MOV AL,8\r
+ CALL OUT\r
+ MOV AL,7\r
+ CALL OUT\r
+ JMP SHORT FILLBUF\r
+\r
+ECHR:\r
+ CMP DI,OFFSET DG:LINEBUF\r
+ JZ FILLBUF\r
+ DEC DI\r
+ DEC BYTE PTR [LBUFFCNT]\r
+ JMP SHORT FILLBUF\r
+ ELSE\r
+\r
+RBUFIN:\r
+ PUSH AX\r
+ PUSH DX\r
+ MOV AH,10\r
+ MOV DX,OFFSET DG:LBUFSIZ\r
+ INT 21H\r
+ POP DX\r
+ POP AX\r
+ RET\r
+ ENDIF\r
+\r
+\r
+ IF SYSVER\r
+RPRBUF:\r
+ PUSHF\r
+ PUSH AX\r
+ PUSH SI\r
+ MOV SI,DX\r
+PLOOP:\r
+ LODSB\r
+ CMP AL,"$"\r
+ JZ PRTDONE\r
+ CALL OUT\r
+ JMP SHORT PLOOP\r
+PRTDONE:\r
+ POP SI\r
+ POP AX\r
+ POPF\r
+ RET\r
+ ELSE\r
+\r
+RPRBUF:\r
+ MOV AH,9\r
+ INT 21H\r
+ RET\r
+ ENDIF\r
+\r
+; Output one space\r
+\r
+BLANK:\r
+ MOV AL," "\r
+ JMP OUT\r
+\r
+; Output the number of blanks in CX\r
+\r
+TAB:\r
+ CALL BLANK\r
+ LOOP TAB\r
+ RET\r
+\r
+; Command Table. Command letter indexes into table to get\r
+; address of command. PERR prints error for no such command.\r
+\r
+COMTAB DW ASSEM ; A\r
+ DW PERR ; B\r
+ DW COMPARE ; C\r
+ DW DUMP ; D\r
+ DW ENTER ; E\r
+ DW FILL ; F\r
+ DW GO ; G\r
+ DW HEXADD ; H\r
+ DW INPUT ; I\r
+ DW PERR ; J\r
+ DW PERR ; K\r
+ DW LOAD ; L\r
+ DW MOVE ; M\r
+ DW NAME ; N\r
+ DW OUTPUT ; O\r
+ IF ZIBO\r
+ DW ZTRACE\r
+ ELSE\r
+ DW PERR ; P\r
+ ENDIF\r
+ DW QUIT ; Q (QUIT)\r
+ DW REG ; R\r
+ DW SEARCH ; S\r
+ DW TRACE ; T\r
+ DW UNASSEM ; U\r
+ DW PERR ; V\r
+ DW DWRITE ; W\r
+ IF SYSVER\r
+ DW SETUDEV ; X\r
+ ELSE\r
+ DW PERR\r
+ ENDIF\r
+ DW PERR ; Y\r
+ DW PERR ; Z\r
+\r
+QUIT:\r
+ INC BYTE PTR [QFLAG]\r
+ MOV BX,[USER_PROC_PDB]\r
+FIND_DEBUG:\r
+IF NOT SYSVER\r
+ MOV AH,SET_CURRENT_PDB\r
+ INT 21H\r
+ENDIF\r
+ CALL ReleaseParity ; let system do normal parity stuff\r
+ MOV AX,(EXIT SHL 8)\r
+ INT 21H\r
+\r
+CODE ENDS\r
+ END START\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+;\r
+; Device call routines for MSDOS\r
+;\r
+\r
+INCLUDE DOSSEG.ASM\r
+\r
+IFNDEF KANJI\r
+KANJI EQU 0 ;FALSE\r
+ENDIF\r
+\r
+CODE SEGMENT BYTE PUBLIC 'CODE'\r
+ ASSUME SS:DOSGROUP,CS:DOSGROUP\r
+\r
+.xlist\r
+.xcref\r
+INCLUDE DOSSYM.ASM\r
+INCLUDE DEVSYM.ASM\r
+.cref\r
+.list\r
+\r
+TITLE DEV - Device call routines\r
+NAME Dev\r
+\r
+ i_need IOXAD,DWORD\r
+ i_need IOSCNT,WORD\r
+ i_need DEVIOBUF,4\r
+ i_need IOCALL,BYTE\r
+ i_need IOMED,BYTE\r
+ i_need IORCHR,BYTE\r
+ i_need CALLSCNT,WORD\r
+ i_need DMAAdd,DWORD\r
+ i_need NullDevPt,DWORD\r
+ i_need CallDevAd,DWORD\r
+ i_need Attrib,BYTE\r
+ i_need NULDEV,DWORD\r
+ i_need Name1,BYTE\r
+ i_need DevPt,DWORD\r
+ i_need DPBHead,DWORD\r
+ i_need NumIO,BYTE\r
+ i_need ThisDPB,DWORD\r
+ i_need DevCall,DWORD\r
+ i_need VerFlg,BYTE\r
+\r
+SUBTTL IOFUNC -- DO FUNCTION 1-12 I/O\r
+PAGE\r
+IOFUNC_RETRY:\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+ invoke restore_world\r
+\r
+ procedure IOFUNC,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DS:SI Points to FCB\r
+; AH is function code\r
+; = 0 Input\r
+; = 1 Input Status\r
+; = 2 Output\r
+; = 3 Output Status\r
+; = 4 Flush\r
+; AL = character if output\r
+; Function:\r
+; Perform indicated I/O to device or file\r
+; Outputs:\r
+; AL is character if input\r
+; If a status call\r
+; zero set if not ready\r
+; zero reset if ready (character in AL for input status)\r
+; For regular files:\r
+; Input Status\r
+; Gets character but restores fcb_RR field\r
+; Zero set on EOF\r
+; Input\r
+; Gets character advances fcb_RR field\r
+; Returns ^Z on EOF\r
+; Output Status\r
+; Always ready\r
+; AX altered, all other registers preserved\r
+\r
+ MOV WORD PTR [IOXAD+2],SS\r
+ MOV WORD PTR [IOXAD],OFFSET DOSGROUP:DEVIOBUF\r
+ MOV WORD PTR [IOSCNT],1\r
+ MOV WORD PTR [DEVIOBUF],AX\r
+\r
+IOFUNC2:\r
+ TEST [SI.fcb_DEVID],080H\r
+ JNZ IOTODEV\r
+ JMP IOTOFILE\r
+\r
+IOTODEV:\r
+ invoke save_world\r
+ PUSH DS\r
+ PUSH SS\r
+ POP ES\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ XOR BX,BX\r
+ MOV [IOCALL.REQSTAT],BX\r
+ MOV BYTE PTR [IOMED],BL\r
+\r
+ MOV BX,OFFSET DOSGROUP:IOCALL\r
+\r
+ MOV CX,(DEVRD SHL 8) OR DRDWRHL\r
+ OR AH,AH\r
+ JZ DCALLR\r
+ MOV CX,(DEVRDND SHL 8) OR DRDNDHL\r
+ DEC AH\r
+ JZ DCALLR\r
+ MOV CX,(DEVWRT SHL 8) OR DRDWRHL\r
+ DEC AH\r
+ JZ DCALLO\r
+ MOV CX,(DEVOST SHL 8) OR DSTATHL\r
+ DEC AH\r
+ JZ DCALLO\r
+DFLUSH:\r
+ MOV CX,(DEVIFL SHL 8) OR DFLSHL\r
+DCALLR:\r
+ MOV AH,86H\r
+DCALL:\r
+ MOV [IOCALL.REQLEN],CL\r
+ MOV [IOCALL.REQFUNC],CH\r
+ MOV CL,AH\r
+ POP DS\r
+ASSUME DS:NOTHING\r
+ CALL DEVIOCALL\r
+ MOV DI,[IOCALL.REQSTAT]\r
+ TEST DI,STERR\r
+ JZ OKDEVIO\r
+ MOV AH,CL\r
+ invoke CHARHARD\r
+ CMP AL,1\r
+ JZ IOFUNC_RETRY\r
+;Know user must have wanted ignore. Make sure device shows ready so\r
+;that DOS doesn't get caught in a status loop when user simply wants\r
+;to ignore the error.\r
+ AND BYTE PTR [IOCALL.REQSTAT+1], NOT (STBUI SHR 8)\r
+OKDEVIO:\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ CMP CH,DEVRDND\r
+ JNZ DNODRD\r
+ MOV AL,BYTE PTR [IORCHR]\r
+ MOV [DEVIOBUF],AL\r
+\r
+DNODRD: MOV AH,BYTE PTR [IOCALL.REQSTAT+1]\r
+ NOT AH ; Zero = busy, not zero = ready\r
+ AND AH,STBUI SHR 8\r
+\r
+ invoke restore_world\r
+ASSUME DS:NOTHING\r
+ MOV AX,WORD PTR [DEVIOBUF]\r
+ return\r
+\r
+DCALLO:\r
+ MOV AH,87H\r
+ JMP SHORT DCALL\r
+\r
+IOTOFILE:\r
+ASSUME DS:NOTHING\r
+ OR AH,AH\r
+ JZ IOIN\r
+ DEC AH\r
+ JZ IOIST\r
+ DEC AH\r
+ JZ IOUT\r
+ return ; NON ZERO FLAG FOR OUTPUT STATUS\r
+\r
+IOIST:\r
+ PUSH WORD PTR [SI.fcb_RR] ; Save position\r
+ PUSH WORD PTR [SI.fcb_RR+2]\r
+ CALL IOIN\r
+ POP WORD PTR [SI.fcb_RR+2] ; Restore position\r
+ POP WORD PTR [SI.fcb_RR]\r
+ return\r
+\r
+IOUT:\r
+ CALL SETXADDR\r
+ invoke STORE\r
+ invoke FINNOSAV\r
+ CALL RESTXADDR ; If you change this into a jmp don't come\r
+ return ; crying to me when things don't work ARR\r
+\r
+IOIN:\r
+ CALL SETXADDR\r
+ invoke LOAD\r
+ PUSH CX\r
+ invoke FINNOSAV\r
+ POP CX\r
+ OR CX,CX ; Check EOF\r
+ CALL RESTXADDR\r
+ MOV AL,[DEVIOBUF] ; Get byte from trans addr\r
+ retnz\r
+ MOV AL,1AH ; ^Z if EOF\r
+ return\r
+\r
+SETXADDR:\r
+ POP WORD PTR [CALLSCNT] ; Return address\r
+ invoke save_world\r
+ PUSH WORD PTR [DMAADD] ; Save Disk trans addr\r
+ PUSH WORD PTR [DMAADD+2]\r
+ PUSH DS\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ MOV CX,WORD PTR [IOXAD+2]\r
+ MOV WORD PTR [DMAADD+2],CX\r
+ MOV CX,WORD PTR [IOXAD]\r
+ MOV WORD PTR [DMAADD],CX ; Set byte trans addr\r
+ MOV CX,[IOSCNT] ; ioscnt specifies length of buffer\r
+ POP DS\r
+ASSUME DS:NOTHING\r
+ MOV [SI.fcb_RECSIZ],1 ; One byte per record\r
+ MOV DX,SI ; FCB to DS:DX\r
+ invoke GETRRPOS\r
+ JMP SHORT RESTRET ; RETURN ADDRESS\r
+\r
+RESTXADDR:\r
+ POP WORD PTR [CALLSCNT] ; Return address\r
+ POP WORD PTR [DMAADD+2] ; Restore Disk trans addr\r
+ POP WORD PTR [DMAADD]\r
+ invoke restore_world\r
+RESTRET:JMP WORD PTR [CALLSCNT] ; Return address\r
+IOFUNC ENDP\r
+\r
+SUBTTL DEVIOCALL, DEVIOCALL2 - CALL A DEVICE\r
+PAGE\r
+ procedure DEVIOCALL,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DS:SI Points to device FCB\r
+; ES:BX Points to request data\r
+; Function:\r
+; Call the device\r
+; Outputs:\r
+; None\r
+; DS:SI,AX destroyed, others preserved\r
+\r
+ LDS SI,DWORD PTR [SI.fcb_FIRCLUS]\r
+\r
+ entry DEVIOCALL2\r
+; As above only DS:SI points to device header on entry, and DS:SI is preserved\r
+ MOV AX,[SI.SDEVSTRAT]\r
+ MOV WORD PTR [CALLDEVAD],AX\r
+ MOV WORD PTR [CALLDEVAD+2],DS\r
+ CALL DWORD PTR [CALLDEVAD]\r
+ MOV AX,[SI.SDEVINT]\r
+ MOV WORD PTR [CALLDEVAD],AX\r
+ CALL DWORD PTR [CALLDEVAD]\r
+ return\r
+DEVIOCALL ENDP\r
+\r
+SUBTTL DEVNAME - LOOK FOR NAME OF DEVICE\r
+PAGE\r
+ procedure DEVNAME,NEAR\r
+ASSUME DS:DOSGROUP,ES:DOSGROUP\r
+\r
+; Inputs:\r
+; DS,ES:DOSGROUP\r
+; Filename in NAME1\r
+; Function:\r
+; Determine if file is in list of I/O drivers\r
+; Outputs:\r
+; Carry set if name not found\r
+; ELSE\r
+; Zero flag set\r
+; BH = Bit 7,6 = 1, bit 5 = 0 (cooked mode)\r
+; bits 0-4 set from low byte of attribute word\r
+; DEVPT = DWORD pointer to Device header of device\r
+; Registers BX destroyed\r
+\r
+ PUSH SI\r
+ PUSH DI\r
+ PUSH CX\r
+\r
+ IF KANJI\r
+ PUSH WORD PTR [NAME1]\r
+ CMP [NAME1],5\r
+ JNZ NOKTR\r
+ MOV [NAME1],0E5H\r
+NOKTR:\r
+ ENDIF\r
+\r
+ TEST BYTE PTR [ATTRIB],attr_volume_id ; If looking for VOL id don't find devs\r
+ JNZ RET31\r
+ MOV SI,OFFSET DOSGROUP:NULDEV\r
+LOOKIO:\r
+ASSUME DS:NOTHING\r
+ TEST [SI.SDEVATT],DEVTYP\r
+ JZ SKIPDEV ; Skip block devices\r
+ PUSH SI\r
+ ADD SI,SDEVNAME\r
+ MOV DI,OFFSET DOSGROUP:NAME1\r
+ MOV CX,4 ; All devices are 8 letters\r
+ REPE CMPSW ; Check for name in list\r
+ POP SI\r
+ JZ IOCHK ; Found it?\r
+SKIPDEV:\r
+ LDS SI,DWORD PTR [SI] ; Get address of next device\r
+ CMP SI,-1 ; At end of list?\r
+ JNZ LOOKIO\r
+RET31: STC ; Not found\r
+RETNV: PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+\r
+ IF KANJI\r
+ POP WORD PTR [NAME1]\r
+ ENDIF\r
+\r
+ POP CX\r
+ POP DI\r
+ POP SI\r
+ RET\r
+\r
+IOCHK:\r
+ASSUME DS:NOTHING\r
+ MOV WORD PTR [DEVPT+2],DS ; Save pointer to device\r
+ MOV BH,BYTE PTR [SI.SDEVATT]\r
+ OR BH,0C0H\r
+ AND BH,NOT 020H ;Clears Carry\r
+ MOV WORD PTR [DEVPT],SI\r
+ JMP RETNV\r
+DevName ENDP\r
+\r
+ procedure GetBP,NEAR\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+; Inputs:\r
+; AL = Logical unit number (A = 0)\r
+; Function:\r
+; Find Drive Parameter Block\r
+; Outputs:\r
+; ES:BP points to DPB\r
+; [THISDPB] = ES:BP\r
+; Carry set if unit number bad\r
+; No other registers altered\r
+\r
+ LES BP,[DPBHEAD] ; Just in case drive isn't valid\r
+ AND AL,3FH ; Mask out dirty and device bits\r
+ CMP AL,BYTE PTR [NUMIO]\r
+ CMC\r
+ JC GOTDPB ; Get drive A\r
+FNDDPB:\r
+ CMP AL,ES:[BP.dpb_drive]\r
+ JZ GOTDPB ; Carry is clear if jump executed\r
+ LES BP,ES:[BP.dpb_next_dpb]\r
+ JMP SHORT FNDDPB\r
+GOTDPB:\r
+ MOV WORD PTR [THISDPB],BP\r
+ MOV WORD PTR [THISDPB+2],ES\r
+ RET\r
+GetBP ENDP\r
+\r
+SUBTTL SETREAD, SETWRITE -- SET UP HEADER BLOCK\r
+PAGE\r
+ procedure SETREAD,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DS:BX = Transfer Address\r
+; CX = Record Count\r
+; DX = Starting Record\r
+; AH = Media Byte\r
+; AL = Unit Code\r
+; Function:\r
+; Set up the device call header at DEVCALL\r
+; Output:\r
+; ES:BX Points to DEVCALL\r
+; No other registers effected\r
+\r
+ PUSH DI\r
+ PUSH CX\r
+ PUSH AX\r
+ MOV CL,DEVRD\r
+SETCALLHEAD:\r
+ MOV AL,DRDWRHL\r
+ PUSH SS\r
+ POP ES\r
+ MOV DI,OFFSET DOSGROUP:DEVCALL\r
+ STOSB ; length\r
+ POP AX\r
+ STOSB ; Unit\r
+ PUSH AX\r
+ MOV AL,CL\r
+ STOSB ; Command code\r
+ XOR AX,AX\r
+ STOSW ; Status\r
+ ADD DI,8 ; Skip link fields\r
+ POP AX\r
+ XCHG AH,AL\r
+ STOSB ; Media byte\r
+ XCHG AL,AH\r
+ PUSH AX\r
+ MOV AX,BX\r
+ STOSW\r
+ MOV AX,DS\r
+ STOSW ; Transfer addr\r
+ POP CX ; Real AX\r
+ POP AX ; Real CX\r
+ STOSW ; Count\r
+ XCHG AX,DX ; AX=Real DX, DX=real CX, CX=real AX\r
+ STOSW ; Start\r
+ XCHG AX,CX\r
+ XCHG DX,CX\r
+ POP DI\r
+ MOV BX,OFFSET DOSGROUP:DEVCALL\r
+ RET\r
+\r
+ entry SETWRITE\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DS:BX = Transfer Address\r
+; CX = Record Count\r
+; DX = Starting Record\r
+; AH = Media Byte\r
+; AL = Unit Code\r
+; Function:\r
+; Set up the device call header at DEVCALL\r
+; Output:\r
+; ES:BX Points to DEVCALL\r
+; No other registers effected\r
+\r
+ PUSH DI\r
+ PUSH CX\r
+ PUSH AX\r
+ MOV CL,DEVWRT\r
+ ADD CL,[VERFLG]\r
+ JMP SHORT SETCALLHEAD\r
+SETREAD ENDP\r
+\r
+do_ext\r
+\r
+CODE ENDS\r
+ END\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\r\0\0\0
\ No newline at end of file
--- /dev/null
+ MS-DOS 2.0 Device Drivers\r
+\r
+INTRODUCTION\r
+\r
+ In the past, DOS-device driver (BIOS for those who are\r
+familiar with CP/M) communication has been mediated with\r
+registers and a fixed-address jump-table. This approach\r
+has suffered heavily from the following two observations:\r
+\r
+ o The old jump-table ideas of the past are fixed in\r
+ scope and allow no extensibility.\r
+\r
+ o The past device driver interfaces have been written\r
+ without regard for the true power of the hardware.\r
+ When a multitasking system or interrupt driven\r
+ hardware is installed a new BIOS must be written\r
+ largely from scratch.\r
+\r
+ In MSDOS 2.0, the DOS-device driver interface has changed\r
+from the old jump-table style to one in which the device\r
+drivers are linked together in a list. This allows new\r
+drivers for optional hardware to be installed (and even\r
+written) in the field by other vendors or the user himself.\r
+This flexibility is one of the major new features of MS-DOS\r
+2.0.\r
+\r
+ Each driver in the chain defines two entry points; the\r
+strategy routine and the interrupt routine. The 2.0 DOS\r
+does not really make use of two entry points (it simply calls\r
+strategy, then immediately calls interrupt). This dual entry\r
+point scheme is designed to facilitate future multi-tasking\r
+versions of MS-DOS. In multi-tasking environments I/O must\r
+be asynchronous, to accomplish this the strategy routine\r
+will be called to queue (internally) a request and return\r
+quickly. It is then the responsibility of the interrupt\r
+routine to perform the actual I/O at interrupt time by picking\r
+requests off the internal queue (set up by the strategy\r
+routine), and process them. When a request is complete,\r
+it is flagged as "done" by the interrupt routine. The DOS\r
+periodically scans the list of requests looking for ones\r
+flagged as done, and "wakes up" the process waiting for the\r
+completion of the request.\r
+\r
+ In order for requests to be queued as above it is no\r
+longer sufficient to pass I/O information in registers, since\r
+many requests may be pending at any one time. Therefore\r
+the new device interface uses data "packets" to pass request\r
+information. A device is called with a pointer to a packet,\r
+this packet is linked into a global chain of all pending\r
+I/O requests maintained by the DOS. The device then links\r
+the packet into its own local chain of requests for this\r
+particular device. The device interrupt routine picks\r
+requests of the local chain for processing. The DOS scans\r
+the global chain looking for completed requests. These\r
+packets are composed of two pieces, a static piece which\r
+has the same format for all requests (called the static\r
+request header), which is followed by information specific\r
+to the request. Thus packets have a variable size and format.\r
+\r
+ At this points it should be emphasized that MS-DOS 2.0\r
+does not implement most of these features, as future versions\r
+will. There is no global or local queue. Only one request\r
+is pending at any one time, and the DOS waits for this current\r
+request to be completed. For 2.0 it is sufficient for the\r
+strategy routine to simply store the address of the packet\r
+at a fixed location, and for the interrupt routine to then\r
+process this packet by doing the request and returning.\r
+Remember: the DOS just calls the strategy routine and then\r
+immediately calls the interrupt routine, it is assumed that\r
+the request is completed when the interrupt routine returns.\r
+This additional functionality is defined at this time so\r
+that people will be aware and thinking about the future.\r
+\r
+\f\r
+FORMAT OF A DEVICE DRIVER\r
+\r
+ A device driver is simply a relocatable memory image\r
+with all of the code in it to implement the device (like\r
+a .COM file, but not ORGed at 100 Hex). In addition it has\r
+a special header at the front of it which identifies it as\r
+a device, defines the strategy and interrupt entry points,\r
+and defines various attributes. It should also be noted\r
+that there are two basic types of devices.\r
+\r
+ The first is character devices. These are devices which\r
+are designed to do character I/O in a serial manner like\r
+CON, AUX, and PRN. These devices are named (ie. CON, AUX,\r
+CLOCK, etc.), and users may open channels (FCBs) to do I/O\r
+to them.\r
+\r
+ The second class of devices is block devices. These\r
+devices are the "disk drives" on the system, they can do\r
+random I/O in pieces called blocks (usually the physical\r
+sector size) and hence the name. These devices are not\r
+"named" as the character devices are, and therefore cannot\r
+be "opened" directly. Instead they are "mapped" via the\r
+drive letters (A,B,C, etc.).\r
+\r
+ Block devices also have units. In other words a single\r
+driver may be responsible for one or more disk drives. For\r
+instance block device driver ALPHA (please note that we cannot\r
+actually refer to block devices by a name!) may be\r
+responsible for drives A,B,C and D, this simply means that\r
+it has four units (0-3) defined and therefore takes up four\r
+drive letters. Which units correspond to which drive letters\r
+is determined by the position of the driver in the chain\r
+of all drivers: if driver ALPHA is the first block driver\r
+in the device chain, and it defines 4 units (0-3), then they\r
+will be A,B,C and D. If BETA is the second block driver\r
+and defines three units (0-2), then they will be E,F and\r
+G and so on. MS-DOS 2.0 is not limited to 16 block device\r
+units, as previous versions were. The theoretical limit\r
+is 63 (2^6 - 1), but it should be noted that after 26 the\r
+drive letters get a little strange (like ] \ and ^). NOTE:\r
+Character devices cannot define multiple units (this because\r
+they have only one name).\r
+\r
+\f\r
+Here is what that special device header looks like:\r
+\r
+ +--------------------------------------+\r
+ | DWORD Pointer to next device |\r
+ | (Must be set to -1) |\r
+ +--------------------------------------+\r
+ | WORD Attributes |\r
+ | Bit 15 = 1 if char device 0 if blk |\r
+ | if bit 15 is 1 |\r
+ | Bit 0 = 1 if Current sti device |\r
+ | Bit 1 = 1 if Current sto output |\r
+ | Bit 2 = 1 if Current NUL device |\r
+ | Bit 3 = 1 if Current CLOCK dev |\r
+ | Bit 4 = 1 if SPECIAL |\r
+ | Bit 14 is the IOCTL bit (see below) |\r
+ | Bit 13 is the NON IBM FORMAT bit |\r
+ +--------------------------------------+\r
+ | WORD Pointer to Device strategy |\r
+ | entry point |\r
+ +--------------------------------------+\r
+ | WORD Pointer to Device interrupt |\r
+ | entry point |\r
+ +--------------------------------------+\r
+ | 8-BYTE character device name field |\r
+ | Character devices set a device name |\r
+ | For block devices the first byte is |\r
+ | The number of units |\r
+ +--------------------------------------+\r
+\r
+ Note that the device entry points are words. They must\r
+be offsets from the same segment number used to point to\r
+this table. Ie. if XXX.YYY points to the start of this\r
+table, then XXX.strategy and XXX.interrupt are the entry\r
+points.\r
+\r
+ A word about the Attribute field. This field is used\r
+most importantly to tell the system whether this device is\r
+a block or character device (bit 15). Most of other bits\r
+are used to give selected character devices certain special\r
+treatment (NOTE: these bits mean nothing on a block device).\r
+Let's say a user has a new device driver which he wants to\r
+be the standard input and output. Besides just installing\r
+the driver he needs to tell SYSINIT (and the DOS) that he\r
+wishes his new driver to override the current sti and sto\r
+(the "CON" device). This is accomplished by setting the\r
+attributes to the desired characteristics, so he would set\r
+Bits 0 and 1 to 1 (note that they are separate!!). Similarly\r
+a new CLOCK device could be installed by setting that\r
+attribute, see the section at the end on the CLOCK device.\r
+NOTE: that although there is a NUL device attribute, the\r
+NUL device cannot be re-assigned. This attribute exists\r
+for the DOS so that it can tell if the NUL device is being\r
+used.\r
+\r
+ The NON IBM FORMAT bit applies only to block devices\r
+and effects the operation of the get BPB device call (see\r
+below).\r
+\r
+ The other bit of interest is the IOCTL bit which has\r
+meaning on character or block devices. This bit tells the\r
+DOS whether this device can handle control strings (via the\r
+IOCTL system call).\r
+\r
+ If a driver cannot process control strings, it should\r
+initially set this bit to 0. This tells the DOS to return\r
+an error if an attempt is made (via IOCTL system call) to\r
+send or receive control strings to this device. A device\r
+which can process control strings should initialize it to\r
+1. For drivers of this type, the DOS will make calls to\r
+the IOCTL INPUT and OUTPUT device functions to send and\r
+receive IOCTL strings (see IOCTL in the SYSTEM-CALLS\r
+document).\r
+\r
+ The IOCTL functions allow data to be sent and received\r
+by the device itself for its own use (to set baud rate, stop\r
+bits, form length etc., etc.), instead of passing data over\r
+the device channel as a normal read or write does. The\r
+interpretation of the passed information is up to the device,\r
+but it MUST NOT simply be treated as a normal I/O.\r
+\r
+ The SPECIAL bit applies only to character drivers and\r
+more particularly to CON drivers. The new 2.0 interface\r
+is a much more general and consistent interface than the\r
+old 1.25 DOS interface. It allows for a number of additional\r
+features of 2.0. It is also slower than 1.25 if old style\r
+"single byte" system calls are made. To make most efficient\r
+use of the interface all applications should block their\r
+I/O as much as possible. This means make one XENIX style\r
+system call to output X bytes rather than X system calls\r
+to output one byte each. Also putting a device channel in\r
+RAW mode (see IOCTL) provides a means of putting out\r
+characters even FASTER than 1.25. To help alleviate the\r
+CON output speed problem for older programs which use the\r
+1 - 12 system calls to output large amounts of data the\r
+SPECIAL bit has been implemented. If this bit is 1 it means\r
+the device is the CON output device, and has implemented\r
+an interrupt 29 Hex handler, where the 29 Hex handler is\r
+defined as follows:\r
+\r
+ Interrupt 29h handlers\r
+\r
+ Input:\r
+ Character in AL\r
+\r
+ Function:\r
+ output the character in al to the user\r
+ screen.\r
+ Output:\r
+ None\r
+ Registers:\r
+ all registers except bx must be preserved.\r
+ No registers except for al have a known or\r
+ consistent value.\r
+\r
+ If a character device implements the SPECIAL bit, it\r
+is the responsibility of the driver to install an address\r
+at the correct location in the interrupt table for interrupt\r
+29 Hex as part of its INIT code. IMPLICATION: There can\r
+be only one device driver with the SPECIAL bit set in the\r
+system. There is no check to insure this state.\r
+\r
+WARNING: THIS FEATURE WILL NOT BE SUPPORTED IN FUTURE VERSIONS\r
+ OF THE OPERATING SYSTEM. IMPLICATION: Any application\r
+ (not device driver) which uses INT 29H directly will\r
+ not work on future versions, YOU HAVE BEEN WARNED.\r
+\f\r
+ In order to "make" a device driver that SYSINIT can\r
+install, a memory image or .EXE (non-IBM only) format file\r
+must be created with the above header at the start. The\r
+link field should be initialized to -1 (SYSINIT fills it\r
+in). The attribute field and entry points must be set\r
+correctly, and if the device is a character device, the name\r
+field must be filled in with the name (if a block device\r
+SYSINIT will fill in the correct unit count). This name\r
+can be any 8 character "legal" file name. In fact SYSINIT\r
+always installs character devices at the start of the device\r
+list, so if you want to install a new CON device all you\r
+have to do is name it "CON". The new one is ahead of the\r
+old one in the list and thus preempts the old one as the\r
+search for devices stops on the first match. Be sure to\r
+set the sti and sto bits on a new CON device!\r
+\r
+NOTE: Since SYSINIT may install the driver anywhere, you\r
+ must be very careful about FAR memory references. You\r
+ should NOT expect that your driver will go in the same\r
+ place every time (The default BIOS drivers are exempted\r
+ from this of course).\r
+\r
+\f\r
+INSTALLATION OF DEVICE DRIVERS\r
+\r
+ Unlike past versions MS-DOS 2.0 allows new device drivers\r
+to be installed dynamically at boot time. This is\r
+accomplished by the new SYSINIT module supplied by Microsoft,\r
+which reads and processes the CONFIG.SYS file. This module\r
+is linked together with the OEM default BIOS in a similar\r
+manner to the way FORMAT is built.\r
+\r
+ One of the functions defined for each device is INIT.\r
+This routine is called once when the device is installed,\r
+and never again. The only thing returned by the init routine\r
+is a location (DS:DX) which is a pointer to the first free\r
+byte of memory after the device driver, (like a terminate\r
+and stay resident). This pointer method can be used to "throw\r
+away" initialization code that is only needed once, saving\r
+on space.\r
+\r
+ Block devices are installed the same way and also return\r
+a first free byte pointer as above, additional information\r
+is also returned:\r
+\r
+ o The number of units is returned, this determines\r
+ logical device names. If the current maximum logical\r
+ device letter is F at the time of the install call,\r
+ and the init routine returns 4 as the number of units,\r
+ then they will have logical names G, H, I and J.\r
+ This mapping is determined by by the position of\r
+ the driver in the device list and the number of units\r
+ on the device (stored in the first byte of the device\r
+ name field).\r
+\r
+ o A pointer to a BPB (Bios Parameter Block) pointer\r
+ array is also returned. This will be similar to\r
+ the INIT table used in previous versions, but will\r
+ have more information in it. There is one table\r
+ for each unit defined. These blocks will be used\r
+ to build a DPB (Drive Parameter Block) for each of\r
+ the units. The pointer passed to the DOS from the\r
+ driver points to an array of n word pointers to BPBs\r
+ where n is the number of units defined. In this\r
+ way if all units are the same, all of the pointers\r
+ can point to the same BPB, saving space. NOTE: this\r
+ array must be protected (below the free pointer set\r
+ by the return) since the DPB will be built starting\r
+ at the byte pointed to by the free pointer. The\r
+ sector size defined must be less than or equal to\r
+ the maximum sector size defined at default BIOS init\r
+ time. If it isn't the install will fail. One new\r
+ piece of DPB info set from this table will be a "media\r
+ descriptor byte". This byte means nothing to the\r
+ DOS, but is passed to devices so that they know what\r
+ form of a DPB the DOS is currently using for a\r
+ particular Drive-Unit.\r
+\r
+ Block devices may take several approaches; they may be\r
+dumb or smart. A dumb device would define a unit (and\r
+therefore a DPB) for each possible media drive combination.\r
+Unit 0 = drive 0 single side, unit 1 = drive 0 double side,\r
+etc. For this approach media descriptor bytes would mean\r
+nothing. A smart device would allow multiple media per unit,\r
+in this case the BPB table returned at init must define space\r
+large enough to accommodate the largest possible media\r
+supported. Smart drivers will use the "media byte" to pass\r
+around info about what media is currently in a unit. NOTE:\r
+If the DPB is a "hybrid" made to get the right sizes, it\r
+should give an invalid "media byte" back to the DOS.\r
+\r
+ The BOOT (default BIOS) drivers are installed pretty\r
+much as above. The preset device list is scanned. If block\r
+drivers are encountered they are installed as above (with\r
+the exception that the break is not moved since the drivers\r
+are already resident in the BIOS). Note that the logical\r
+drive letters are assigned in list order, thus the driver\r
+which is to have logical A must be the first unit of the\r
+first block device in the list. The order of character\r
+devices is also important. There must be at least 4 character\r
+devices defined at boot which must be the first four devices\r
+(of either type), the first will become standard input,\r
+standard output, and standard error output. The second will\r
+become standard auxiliary input and output, the third will\r
+become standard list output, and the forth will become the\r
+date/time (CLOCK) device. Thus the BIOS device list must\r
+look like this:\r
+\r
+->CON->AUX->PRN->CLOCK->any other block or character devices\r
+\f\r
+THE DRIVER\r
+\r
+ A device driver will define the following functions:\r
+\r
+ Command Function\r
+ Code\r
+\r
+ 0 INIT\r
+ 1 MEDIA CHECK (Block only, NOP for character)\r
+ 2 BUILD BPB " " " " "\r
+ 3 IOCTL INPUT (Only called if device has IOCTL)\r
+ 4 INPUT (read)\r
+ 5 NON-DESTRUCTIVE INPUT NO WAIT (Char devs only)\r
+ 6 INPUT STATUS " " "\r
+ 7 INPUT FLUSH " " "\r
+ 8 OUTPUT (write)\r
+ 9 OUTPUT (Write) with verify\r
+ 10 OUTPUT STATUS " " "\r
+ 11 OUTPUT FLUSH " " "\r
+ 12 IOCTL OUTPUT (Only called if device has IOCTL)\r
+\r
+ As mentioned before, the first entry point is the strategy\r
+routine which is called with a pointer to a data block. This\r
+call does not perform the request, all it does is queue it\r
+(save the data block pointer). The second interrupt entry\r
+point is called immediately after the strategy call. The\r
+"interrupt" routine is called with no parameters, its primary\r
+function is to perform the operation based on the queued\r
+data block and set up any returns.\r
+\r
+ The "BUILD BPB" and "MEDIA CHECK" are the interesting\r
+new ones, these are explained by examining the sequence of\r
+events in the DOS which occurs when a drive access call (other\r
+than read or write) is made:\r
+\r
+ I. Turn drive letter into DPB pointer by looking\r
+ for DPB with correct driver-unit number.\r
+\r
+ II. Call device driver and request media check for\r
+ Drive-Unit. DOS passes its current Media\r
+ descriptor byte (from DPB). Call returns:\r
+\r
+ Media Not Changed\r
+ Media Changed\r
+ Not Sure\r
+ Error\r
+\r
+ Error - If an error occurs the error code should\r
+ be set accordingly.\r
+\r
+ Media Not changed - Current DPB and media byte\r
+ are OK, done.\r
+\r
+ Media Changed - Current DPB and media are wrong,\r
+ invalidate any buffers for this unit, and\r
+ goto III.\r
+\r
+ Not Sure - If there are dirty buffers for this\r
+ unit, assume DPB and media byte are OK and\r
+ done. If nothing dirty, assume media changed,\r
+ invalidate any buffers for unit, and goto\r
+ III.\r
+\r
+ NOTE: If a hybrid DPB was built at init and\r
+ an invalid Media byte was set, the driver\r
+ should return media changed when this invalid\r
+ media byte is encountered.\r
+\r
+ III. Call device driver to build BPB with media byte\r
+ and buffer.\r
+\r
+ What the driver must do at step III is determine the\r
+correct media that is currently in the unit, and return a\r
+pointer to a BPB table (same as for the install call). This\r
+table will be used as at init to build a correct DPB for\r
+the unit If the determined media descriptor byte in the table\r
+turns out to be the same as the one passed in, then the DOS\r
+will not build a new table, but rather just use the old one.\r
+Therefore in this case the driver doesn't have to correctly\r
+fill in the other entries if desired.\r
+\r
+ The build BPB call also gets a pointer to a one sector\r
+buffer. What this buffer contains is determined by the NON\r
+IBM FORMAT bit in the attribute field. If the bit is zero\r
+(device is IBM format compatible) then the buffer contains\r
+the first sector of the first FAT, in particular the FAT\r
+ID byte is the first byte of this buffer. NOTE: It must\r
+be true that the BPB is the same, as far as location of the\r
+FAT is concerned, for all possible media. This is because\r
+this first FAT sector must be read BEFORE the actual BPB\r
+is returned. If the NON IBM FORMAT bit is set then the\r
+pointer points to one sector of scratch space which may be\r
+used for anything.\r
+\f\r
+CALL FORMAT\r
+\r
+ When the DOS calls a device driver to perform a finction,\r
+it passes a structure (Drive Request Structure) in ES:BX\r
+to perform operations and does a long call to the driver's\r
+strategy entry point. This structure is a fixed length header\r
+(Static Request Header) followed by data pertinent to the\r
+operation being performed. NOTE: It is the drivers\r
+responsibility to preserve machine state.\r
+\r
+STATIC REQUEST HEADER ->\r
+ +-----------------------------+\r
+ | BYTE length of record |\r
+ | Length in bytes of this |\r
+ | Drive Request Structure |\r
+ +-----------------------------+\r
+ | BYTE unit code |\r
+ | The subunit the operation |\r
+ | is for (minor device) |\r
+ | (no meaning on character |\r
+ | devices) |\r
+ +-----------------------------+\r
+ | BYTE command code |\r
+ +-----------------------------+\r
+ | WORD Status |\r
+ +-----------------------------+\r
+ | 8 bytes reserved here for |\r
+ | two DWORD links. One will |\r
+ | be a link for the DOS queue |\r
+ | The other for the device |\r
+ | queue |\r
+ +-----------------------------+\r
+\r
+STATUS WORD\r
+\r
+ 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0\r
+ +---+---+--+--+--+--+---+---+--+--+--+--+--+--+--+--+\r
+ | E | | B | D | |\r
+ | R | RESERVED | U | O | ERROR CODE (bit 15 on)|\r
+ | R | | I | N | |\r
+ +---+---+--+--+--+--+---+---+--+--+--+--+--+--+--+--+\r
+\r
+ The status word is zero on entry and is set by the driver\r
+interrupt routine on return.\r
+\r
+ Bit 8 is the done bit, it means the operation is complete.\r
+For the moment the Driver just sets it to one when it exits,\r
+in the future this will be set by the interrupt routine to\r
+tell the DOS the operation is complete.\r
+\f\r
+ Bit 15 is the error bit, if it is set then the low 8\r
+bits indicate the error:\r
+\r
+ 0 Write Protect violation\r
+ (NEW) 1 Unknown Unit\r
+ 2 Drive not ready\r
+ (NEW) 3 Unknown command\r
+ 4 CRC error\r
+ (NEW) 5 Bad Drive Request Structure length\r
+ 6 Seek error\r
+ (NEW) 7 Unknown media\r
+ 8 Sector not found\r
+ (NEW) 9 Printer out of paper\r
+ A Write Fault\r
+ (NEW) B Read Fault\r
+ C General Failure\r
+\r
+Bit 9 is the busy bit which is set only by status calls (see\r
+STATUS CALL below).\r
+\r
+\f\r
+ Here is the data block format for each function:\r
+\r
+READ or WRITE - ES:BX (Including IOCTL) ->\r
+ +------------------------------------+\r
+ | 13-BYTE Static Request Header |\r
+ +------------------------------------+\r
+ | BYTE Media descriptor from DPB |\r
+ +------------------------------------+\r
+ | DWORD transfer address |\r
+ +------------------------------------+\r
+ | WORD byte/sector Count |\r
+ ---+------------------------------------+---\r
+ | WORD starting sector number |\r
+ | (ignored on Char Devs) |\r
+ +------------------------------------+\r
+\r
+ In addition to setting the status word, the driver must\r
+set the Sector count to the actual number of sectors (or\r
+bytes) transferred. NOTE: No error check is performed on\r
+an IOCTL I/O call, driver MUST correctly set the return sector\r
+(byte) count to the actual number of bytes transferred,\r
+however.\r
+\r
+NOTE: THE FOLLOWING APPLIES TO BLOCK DEVICE DRIVERS.\r
+\r
+ Under certain circumstances the BIOS may be asked to\r
+do a write operation of 64K bytes which seems to be a "wrap\r
+around" of the transfer address in the BIOS I/O packet. This\r
+arises due to an optimization added to the write code in\r
+MS-DOS. It will only manifest on user WRITEs which are within\r
+a sector size of 64K bytes on files which are "growing" past\r
+the current EOF. IT IS ALLOWABLE FOR THE BIOS TO IGNORE\r
+THE BALANCE OF THE WRITE WHICH "WRAPS AROUND" IF IT SO\r
+CHOOSES. For instance a WRITE of 10000H bytes worth of\r
+sectors with a transfer address of XXX:1 could ignore the\r
+last two bytes (remember that a user program can never request\r
+an I/O of more than FFFFH bytes and cannot wrap around (even\r
+to 0) in his transfer segment, so in this case the last two\r
+bytes can be ignored).\r
+\r
+\f\r
+NON DESRUCTIVE READ NO WAIT - ES:BX ->\r
+ +------------------------------------+\r
+ | 13-BYTE Static Request Header |\r
+ +------------------------------------+\r
+ | BYTE read from device |\r
+ +------------------------------------+\r
+\r
+ This call is analogous to the console input status call\r
+on MS-DOS 1.25. If the character device returns Busy bit\r
+= 0 (characters in buffer), then the next character that\r
+would be read is returned. This character is NOT removed\r
+from the input buffer (hence the term Non Destructive Read).\r
+In essence this call allows the DOS to look ahead one input\r
+character.\r
+\r
+\f\r
+MEDIA CHECK - ES:BX ->\r
+ +------------------------------------+\r
+ | 13-BYTE Static Request Header |\r
+ +------------------------------------+\r
+ | BYTE Media Descriptor from DPB |\r
+ +------------------------------------+\r
+ | BYTE returned |\r
+ +------------------------------------+\r
+\r
+ In addition to setting status word, driver must set the\r
+return byte.\r
+\r
+ Return Byte :\r
+ -1 Media has been changed\r
+ 0 Don't know if media has been changed\r
+ 1 Media has not been changed\r
+\r
+ If the driver can return -1 or 1 (by having a door-lock\r
+or other interlock mechanism) the performance of MSDOS 2.0\r
+is enhanced as the DOS need not reread the FAT for each\r
+directory access.\r
+\r
+\f\r
+BUILD BPB - ES:BX ->\r
+ +------------------------------------+\r
+ | 13-BYTE Static Request Header |\r
+ +------------------------------------+\r
+ | BYTE Media Descriptor from DPB |\r
+ +------------------------------------+\r
+ | DWORD Transfer Address |\r
+ | (points to one sectors worth of |\r
+ | scratch space or first sector |\r
+ | of FAT depending on the value |\r
+ | of the NON IBM FORMAT bit) |\r
+ +------------------------------------+\r
+ | DWORD Pointer to BPB |\r
+ +------------------------------------+\r
+\r
+ If the NON IBM FORMAT bit of the device is set, then\r
+the DWORD Transfer Address points to a one sector buffer\r
+which can be used for any purpose. If the NON IBM FORMAT\r
+bit is 0, then this buffer contains the first sector of the\r
+FAT; in this case the driver must not alter this buffer (this\r
+mode is useful if all that is desired is to read the FAT\r
+ID byte).\r
+\r
+ If IBM compatible format is used (NON IBM FORMAT BIT\r
+= 0), then it must be true that the first sector of the first\r
+FAT is located at the same sector on all possible media.\r
+This is because the FAT sector will be read BEFORE the media\r
+is actually determined.\r
+\r
+ In addition to setting status word, driver must set the\r
+Pointer to the BPB on return.\r
+\f\r
+\r
+ In order to allow for many different OEMs to read each\r
+other's disks, the following standard is suggested: The\r
+information relating to the BPB for a particular piece of\r
+media is kept in the boot sector for the media. In\r
+particular, the format of the boot sector is:\r
+\r
+ +------------------------------------+\r
+ | 3 BYTE near JUMP to boot code |\r
+ +------------------------------------+\r
+ | 8 BYTES OEM name and version |\r
+ ---+------------------------------------+---\r
+ B | WORD bytes per sector |\r
+ P +------------------------------------+\r
+ B | BYTE sectors per allocation unit |\r
+ +------------------------------------+\r
+ | | WORD reserved sectors |\r
+ V +------------------------------------+\r
+ | BYTE number of FATs |\r
+ +------------------------------------+\r
+ | WORD number of root dir entries |\r
+ +------------------------------------+\r
+ | WORD number of sectors in logical |\r
+ ^ | image |\r
+ | +------------------------------------+\r
+ B | BYTE media descriptor |\r
+ P +------------------------------------+\r
+ B | WORD number of FAT sectors |\r
+ ---+------------------------------------+---\r
+ | WORD sectors per track |\r
+ +------------------------------------+\r
+ | WORD number of heads |\r
+ +------------------------------------+\r
+ | WORD number of hidden sectors |\r
+ +------------------------------------+\r
+\r
+ The three words at the end are optional, the DOS doesn't\r
+care about them (since they are not part of the BPB). They\r
+are intended to help the BIOS understand the media. Sectors\r
+per track may be redundant (could be figured out from total\r
+size of the disk). Number of heads is useful for supporting\r
+different multi-head drives which have the same storage\r
+capacity, but a different number of surfaces. Number of\r
+hidden sectors is useful for supporting drive partitioning\r
+schemes.\r
+\f\r
+\r
+ Currently, the media descriptor byte has been defined\r
+for a small range of media:\r
+\r
+ 5 1/4" diskettes:\r
+\r
+ Flag bits:\r
+ 01h - on -> 2 double sided\r
+\r
+ All other bits must be on.\r
+\r
+ 8" disks:\r
+ FEh - IBM 3740 format, singled-sided, single-density,\r
+ 128 bytes per sector, soft sectored, 4 sectors\r
+ per allocation unit, 1 reserved sector, 2 FATs,\r
+ 68 directory entries, 77*26 sectors\r
+\r
+ FDh - 8" IBM 3740 format, singled-sided,\r
+ single-density, 128 bytes per sector, soft\r
+ sectored, 4 sectors per allocation unit, 4\r
+ reserved sectors, 2 FATs, 68 directory entries,\r
+ 77*26 sectors\r
+\r
+ FEh - 8" Double-sided, double-density, 1024 bytes\r
+ per sector, soft sectored, 1 sector per allocation\r
+ unit, 1 reserved sector, 2 FATs, 192 directory\r
+ entries, 77*8*2 sectors\r
+\r
+\f\r
+STATUS Calls - ES:BX ->\r
+ +------------------------------------+\r
+ | 13-BYTE Static Request Header |\r
+ +------------------------------------+\r
+\r
+ All driver must do is set status word accordingly and\r
+set the busy bit as follows:\r
+\r
+ o For output on character devices: If it is 1 on\r
+ return, a write request (if made) would wait for\r
+ completion of a current request. If it is 0, there\r
+ is no current request and a write request (if made)\r
+ would start immediately.\r
+\r
+ o For input on character devices with a buffer a return\r
+ of 1 means, a read request (if made) would go to\r
+ the physical device. If it is 0 on return, then\r
+ there are characters in the devices buffer and a\r
+ read would return quickly, it also indicates that\r
+ the user has typed something. The DOS assumes all\r
+ character devices have an input type ahead buffer.\r
+ Devices which don't have them should always return\r
+ busy = 0 so that the DOS won't hang waiting for\r
+ something to get into a buffer which doesn't exist.\r
+\r
+\f\r
+FLUSH Calls - ES:BX ->\r
+ +------------------------------------+\r
+ | 13-BYTE Static Request Header |\r
+ +------------------------------------+\r
+\r
+ This call tells the driver to flush (terminate) all\r
+pending requests that it has knowledge of. Its primary use\r
+is to flush the input queue on character devices.\r
+\r
+\f\r
+INIT - ES:BX ->\r
+ +------------------------------------+\r
+ | 13-BYTE Static Request Header |\r
+ +------------------------------------+\r
+ | BYTE # of units |\r
+ +------------------------------------+\r
+ | DWORD Break Address |\r
+ ---+------------------------------------+---\r
+ | DWORD Pointer to BPB array |\r
+ | (not set by Character devices) |\r
+ +------------------------------------+\r
+\r
+ The number of units, break address, and BPB pointer are\r
+set by the driver.\r
+\r
+\f\r
+FORMAT OF BPB (Bios Parameter Block) -\r
+\r
+ +------------------------------------+\r
+ | WORD Sector size in Bytes |\r
+ | Must be at least 32 |\r
+ +------------------------------------+\r
+ | BYTE Sectors/Allocation unit |\r
+ | Must be a power of 2 |\r
+ +------------------------------------+\r
+ | WORD Number of reserved sectors |\r
+ | May be zero |\r
+ +------------------------------------+\r
+ | BYTE Number of FATS |\r
+ +------------------------------------+\r
+ | WORD Number of directory entries |\r
+ +------------------------------------+\r
+ | WORD Total number of sectors |\r
+ +------------------------------------+\r
+ | BYTE Media descriptor |\r
+ +------------------------------------+\r
+ | WORD Number of sectors occupied by |\r
+ | FAT |\r
+ +------------------------------------+\r
+\r
+\f\r
+THE CLOCK DEVICE\r
+\r
+ One of the most popular add on boards seems to be "Real\r
+Time CLOCK Boards". To allow these boards to be integrated\r
+into the system for TIME and DATE, there is a special device\r
+(determined by the attribute word) which is the CLOCK device.\r
+In all respects this device defines and performs functions\r
+like any other character device (most functions will be "set\r
+done bit, reset error bit, return). When a read or write\r
+to this device occurs, exactly 6 bytes are transferred. This\r
+I/O can be thought of as transferring 3 words which correspond\r
+exactly to the values of AX, CX and DX which were used in\r
+the old 1.25 DOS date and time routines. Thus the first\r
+two bytes are a word which is the count of days since 1-1-80.\r
+The third byte is minutes, the fourth hours, the fifth\r
+hundredths of seconds, and the sixth seconds. Reading the\r
+CLOCK device gets the date and time, writing to it sets the\r
+date and time.\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+;\r
+; Directory routines for MSDOS\r
+;\r
+\r
+INCLUDE DOSSEG.ASM\r
+\r
+CODE SEGMENT BYTE PUBLIC 'CODE'\r
+ ASSUME SS:DOSGROUP,CS:DOSGROUP\r
+\r
+.xlist\r
+.xcref\r
+INCLUDE DOSSYM.ASM\r
+INCLUDE DEVSYM.ASM\r
+.cref\r
+.list\r
+\r
+TITLE DIR - Directory and path cracking\r
+NAME Dir\r
+\r
+ i_need NoSetDir,BYTE\r
+ i_need EntFree,WORD\r
+ i_need DirStart,WORD\r
+ i_need LastEnt,WORD\r
+ i_need ClusNum,WORD\r
+ i_need CurBuf,DWORD\r
+ i_need ThisFCB,DWORD\r
+ i_need Attrib,BYTE\r
+ i_need DelAll,BYTE\r
+ i_need VolID,BYTE\r
+ i_need Name1,BYTE\r
+ i_need ThisDPB,DWORD\r
+ i_need EntLast,WORD\r
+ i_need Creating,BYTE\r
+ i_need SecClusPos,BYTE\r
+ i_need ClusFac,BYTE\r
+ i_need NxtClusNum,WORD\r
+ i_need DirSec,WORD\r
+ i_need DriveSpec,BYTE\r
+ i_need Device_availability,BYTE\r
+ i_need RootStart,BYTE\r
+ i_need DevString,BYTE\r
+ i_need DevStrLen,BYTE\r
+\r
+SUBTTL BUILDDIR,NEWDIR -- ALLOCATE DIRECTORIES\r
+PAGE\r
+ procedure BUILDDIR,NEAR\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+; Inputs:\r
+; ES:BP Points to DPB\r
+; [THISFCB] Set if using NEWDIR entry point\r
+; [LASTENT] current last valid entry number in directory if no free\r
+; entries\r
+; Function:\r
+; Grow directory if no free entries and not root\r
+; Outputs:\r
+; CARRY SET IF FAILURE\r
+; ELSE\r
+; AX entry number of new entry\r
+; If a new dir [DIRSTART],[CLUSFAC],[CLUSNUM],[DIRSEC] set\r
+; AX = first entry of new dir\r
+; GETENT should be called to set [LASTENT]\r
+\r
+ MOV AX,[ENTFREE]\r
+ CMP AX,-1\r
+ JNZ GOTRET\r
+ CMP [DIRSTART],0\r
+ JNZ NEWDIR\r
+ STC\r
+ return ; Can't grow root\r
+\r
+ entry NEWDIR\r
+ MOV BX,[DIRSTART]\r
+ OR BX,BX\r
+ JZ NULLDIR\r
+ invoke GETEOF\r
+NULLDIR:\r
+ MOV CX,1\r
+ invoke ALLOCATE\r
+ retc\r
+ MOV DX,[DIRSTART]\r
+ OR DX,DX\r
+ JNZ ADDINGDIR\r
+ call SETDIRSRCH\r
+ MOV [LASTENT],-1\r
+ JMP SHORT GOTDIRREC\r
+ADDINGDIR:\r
+ CMP [CLUSNUM],0FF8H\r
+ JB NOTFIRSTGROW\r
+ MOV [CLUSNUM],BX\r
+NOTFIRSTGROW:\r
+ MOV DX,BX\r
+ XOR BL,BL\r
+ invoke FIGREC\r
+GOTDIRREC:\r
+ MOV CL,ES:[BP.dpb_cluster_mask]\r
+ INC CL\r
+ XOR CH,CH\r
+ZERODIR:\r
+ PUSH CX\r
+ MOV AL,0FFH\r
+ invoke GETBUFFR\r
+ MOV CX,ES:[BP.dpb_sector_size]\r
+ PUSH ES\r
+ LES DI,[CURBUF]\r
+ PUSH DI\r
+ ADD DI,BUFINSIZ\r
+ XOR AX,AX\r
+ SHR CX,1\r
+ REP STOSW\r
+ JNC EVENZ\r
+ STOSB\r
+EVENZ:\r
+ POP DI\r
+ INC AL\r
+ MOV ES:[DI.BUFDIRTY],AL\r
+ POP ES\r
+ POP CX\r
+ INC DX\r
+ LOOP ZERODIR\r
+ MOV AX,[LASTENT]\r
+ INC AX\r
+GOTRET:\r
+ CLC\r
+ return\r
+\r
+BUILDDIR ENDP\r
+\r
+;\r
+; set up a . and .. directory entry for a directory\r
+;\r
+ procedure SETDOTENT,NEAR\r
+ASSUME DS:DOSGROUP\r
+ MOV CX,4\r
+ MOV AX,2020H\r
+ REP STOSW\r
+ STOSB\r
+ MOV SI,WORD PTR [THISFCB]\r
+ MOV AL,attr_directory\r
+ STOSB\r
+ ADD DI,10\r
+ MOV AX,[SI.fcb_FTIME]\r
+ STOSW\r
+ MOV AX,[SI.fcb_FDATE]\r
+ STOSW\r
+ MOV AX,DX\r
+ STOSW\r
+ XOR AX,AX\r
+ STOSW\r
+ STOSW\r
+ return\r
+SETDOTENT ENDP\r
+\r
+SUBTTL GETFILE, GETNAME, FINDNAME -- LOOK FOR A FILE\r
+PAGE\r
+ procedure SEARCH,near\r
+\r
+ entry GETFILE\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+; Same as GETNAME except ES:DI points to FCB on successful return\r
+ invoke MOVNAME\r
+ retc\r
+ PUSH DX\r
+ PUSH DS\r
+ CALL FINDNAME\r
+ POP ES\r
+ POP DI\r
+ return\r
+\r
+ entry GETNAME\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DS,DX point to FCB\r
+; Function:\r
+; Find file name in disk directory. First byte is\r
+; drive number (0=current disk). "?" matches any\r
+; character.\r
+; Outputs:\r
+; Carry set if file not found\r
+; ELSE\r
+; Zero set if attributes match (always except when creating)\r
+; AH = Device ID (bit 7 set if not disk)\r
+; [THISDPB] = Base of drive parameters\r
+; DS = DOSGROUP\r
+; ES = DOSGROUP\r
+; [CURBUF+2]:BX = Pointer into directory buffer\r
+; [CURBUF+2]:SI = Pointer to First Cluster field in directory entry\r
+; [CURBUF] has directory record with match\r
+; [NAME1] has file name\r
+; All other registers destroyed.\r
+\r
+ invoke MOVNAME\r
+ASSUME ES:DOSGROUP\r
+ retc ; Bad file name?\r
+\r
+ entry FINDNAME\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ invoke DEVNAME\r
+ JC FindEntry\r
+ invoke BUILDFCB\r
+ return\r
+ASSUME ES:NOTHING\r
+\r
+; NOTE THE FALL THROUGH\r
+\r
+SUBTTL FINDENTRY -- LOOK FOR AN ENTRY\r
+PAGE\r
+ entry FindEntry\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+; Inputs:\r
+; [THISDPB] set\r
+; [SECCLUSPOS] = 0\r
+; [DIRSEC] = Starting directory sector number\r
+; [CLUSNUM] = Next cluster of directory\r
+; [CLUSFAC] = Sectors/Cluster\r
+; [NAME1] = Name to look for\r
+; Function:\r
+; Find file name in disk directory.\r
+; "?" matches any character.\r
+; Outputs:\r
+; Carry set if name not found\r
+; ELSE\r
+; Zero set if attributes match (always except when creating)\r
+; AH = Device ID (bit 7 set if not disk)\r
+; [THISDPB] = Base of drive parameters\r
+; DS = DOSGROUP\r
+; ES = DOSGROUP\r
+; [CURBUF+2]:BX = Pointer into directory buffer\r
+; [CURBUF+2]:SI = Pointer to First Cluster field in directory entry\r
+; [CURBUF] has directory record with match\r
+; [NAME1] has file name\r
+; [LASTENT] is entry number of the entry\r
+; All other registers destroyed.\r
+\r
+ CALL STARTSRCH\r
+ CMP BYTE PTR [ATTRIB],attr_volume_id\r
+ ; Looking for vol ID only ?\r
+ JNZ NOTVOLSRCH ; No\r
+ CALL SETROOTSRCH ; Yes force search of root\r
+NOTVOLSRCH:\r
+ CALL GETENTRY\r
+ entry Srch\r
+ PUSH DS\r
+ MOV DS,WORD PTR [CURBUF+2]\r
+ASSUME DS:NOTHING\r
+ MOV AH,BYTE PTR [BX]\r
+ OR AH,AH ; End of directory?\r
+ JZ FREE\r
+ CMP AH,BYTE PTR [DELALL] ; Free entry?\r
+ JZ FREE\r
+ TEST BYTE PTR [BX+11],attr_volume_id\r
+ ; Volume ID file?\r
+ JZ CHKFNAM ; NO\r
+ INC BYTE PTR [VOLID]\r
+CHKFNAM:\r
+ MOV SI,BX\r
+ PUSH SS\r
+ POP ES\r
+ASSUME ES:DOSGROUP\r
+ MOV DI,OFFSET DOSGROUP:NAME1\r
+ MOV CX,11\r
+WILDCRD:\r
+ REPE CMPSB\r
+ JZ FOUND\r
+ CMP BYTE PTR ES:[DI-1],"?"\r
+ JZ WILDCRD\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ entry NEXTENT\r
+ LES BP,[THISDPB]\r
+ASSUME ES:NOTHING\r
+ CALL NEXTENTRY\r
+ JNC SRCH\r
+ JMP SHORT SETESRET\r
+\r
+FREE:\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ MOV CX,[LASTENT]\r
+ CMP CX,[ENTFREE]\r
+ JAE TSTALL\r
+ MOV [ENTFREE],CX\r
+TSTALL:\r
+ CMP AH,BYTE PTR [DELALL] ; At end of directory?\r
+ JZ NEXTENT ; No - continue search\r
+ MOV [ENTLAST],CX\r
+ STC\r
+ JMP SHORT SETESRET\r
+\r
+FOUND:\r
+;\r
+; We have a file with a matching name. We must now consider\r
+; the attributes:\r
+; ATTRIB Action\r
+; ------ ------\r
+; Volume_ID Is Volume_ID in test?\r
+; Otherwise If no create then Is ATTRIB+extra superset of test?\r
+; If create then Is ATTRIB equal to test?\r
+;\r
+ MOV CH,[SI] ; Attributes of file\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ MOV AH,BYTE PTR [ATTRIB] ; Attributes of search\r
+ TEST CH,attr_volume_id ; Volume ID file?\r
+ JZ check_one_volume_id ; Nope check other attributes\r
+ TEST AH,attr_volume_id ; Can we find Volume ID?\r
+ JZ NEXTENT ; Nope, (not even $FCB_CREATE)\r
+ XOR AH,AH ; Set zero flag for $FCB_CREATE\r
+ JMP SHORT RETF ; Found Volume ID\r
+check_one_volume_id:\r
+ CMP AH,attr_volume_id ; Looking only for Volume ID?\r
+ JZ NEXTENT ; Yes, continue search\r
+ ADD SI,15\r
+ CALL MatchAttributes\r
+ JZ RETF\r
+ TEST BYTE PTR [CREATING],-1 ; Pass back mismatch if creating\r
+ JZ NEXTENT ; Otherwise continue searching\r
+RETF:\r
+ LES BP,[THISDPB]\r
+ MOV AH,ES:[BP.dpb_drive]\r
+SETESRET:\r
+ PUSH SS\r
+ POP ES\r
+ return\r
+\r
+SUBTTL GETENTRY, NEXTENTRY, GETENT -- STEP THROUGH DIRECTORY\r
+PAGE\r
+ entry GETENTRY\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+; Inputs:\r
+; [LASTENT] has directory entry\r
+; ES:BP points to drive parameters\r
+; Function:\r
+; Locates directory entry in preparation for search\r
+; GETENT provides entry for passing desired entry in AX\r
+; A valid search environment MUST exist\r
+; ENDENT,ENTLAST,ENTFREE\r
+; Outputs:\r
+; [CURBUF+2]:BX = Pointer to next directory entry in CURBUF\r
+; [CURBUF+2]:DX = Pointer to first byte after end of CURBUF\r
+; [LASTENT] = New directory entry number\r
+\r
+ MOV AX,[LASTENT]\r
+ entry GETENT\r
+ MOV [LASTENT],AX\r
+ MOV CL,4\r
+ SHL AX,CL\r
+ XOR DX,DX\r
+ SHL AX,1\r
+ RCL DX,1 ; Account for overflow in last shift\r
+ MOV BX,ES:[BP.dpb_sector_size]\r
+ AND BL,255-31 ; Must be multiple of 32\r
+ DIV BX\r
+ MOV BX,DX ; Position within sector\r
+ PUSH BX\r
+ invoke DIRREAD\r
+ POP BX\r
+SETENTRY:\r
+ MOV DX,WORD PTR [CURBUF]\r
+ ADD DX,BUFINSIZ\r
+ ADD BX,DX\r
+ ADD DX,ES:[BP.dpb_sector_size] ; Always clears carry\r
+ return\r
+\r
+ entry NEXTENTRY\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+; Inputs:\r
+; Same as outputs of GETENTRY, above\r
+; Function:\r
+; Update BX, and [LASTENT] for next directory entry.\r
+; Carry set if no more.\r
+\r
+ MOV AX,[LASTENT]\r
+ CMP AX,[ENTLAST]\r
+ JZ NONE\r
+ INC AX\r
+ ADD BX,32\r
+ CMP BX,DX\r
+ JB HAVIT\r
+ MOV BL,BYTE PTR [SECCLUSPOS]\r
+ INC BL\r
+ CMP BL,BYTE PTR [CLUSFAC]\r
+ JB SAMECLUS\r
+ MOV BX,[NXTCLUSNUM]\r
+ CMP BX,0FF8H\r
+ JAE NONE\r
+ CMP BX,2\r
+ JB NONE\r
+ JMP GETENT\r
+\r
+NONE:\r
+ STC\r
+ return\r
+\r
+HAVIT:\r
+ MOV [LASTENT],AX\r
+ CLC\r
+ return\r
+\r
+SAMECLUS:\r
+ MOV BYTE PTR [SECCLUSPOS],BL\r
+ MOV [LASTENT],AX\r
+ PUSH DS\r
+ LDS DI,[CURBUF]\r
+ASSUME DS:NOTHING\r
+ MOV DX,[DI.BUFSECNO]\r
+ INC DX\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ invoke FIRSTCLUSTER\r
+ XOR BX,BX\r
+ JMP SETENTRY\r
+Search ENDP\r
+\r
+SUBTTL GETCURRDIR -- GET CURRENT DIRECTORY\r
+PAGE\r
+ procedure Dir_search,NEAR\r
+ entry GETCURRDIR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; ES:BP Points to DPB\r
+; FATREAD should be called before this routine\r
+; Function:\r
+; Find current directory for drive\r
+; If path is bad set current directory to the root\r
+; Outputs:\r
+; DS = DOSGROUP\r
+; [SECCLUSPOS] = 0\r
+; [DIRSTART] = Cluster # of first cluster of directory ( 0 if root)\r
+; [DIRSEC] Set to phys sec # of first sector first cluster of directory\r
+; [CLUSNUM] Set to next cluster\r
+; [CLUSFAC] Sectors/cluster\r
+; Destroys all registers\r
+\r
+ MOV BX,ES:[BP.dpb_current_dir]\r
+ OR BX,BX\r
+ JZ SETROOTSRCH\r
+ CMP BX,0FF8H\r
+ JB SETDIRSRCH\r
+ PUSH ES\r
+ POP DS\r
+ LEA SI,[BP.dpb_dir_text]\r
+ CALL ROOTPATH\r
+ASSUME DS:DOSGROUP\r
+ JNC SETCURR\r
+ MOV ES:[BP.dpb_current_dir],0\r
+\r
+SETROOTSRCH:\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ XOR AX,AX\r
+ MOV [DIRSTART],AX\r
+ MOV BYTE PTR [SECCLUSPOS],AL\r
+ DEC AX\r
+ MOV [CLUSNUM],AX\r
+ MOV AX,ES:[BP.dpb_first_sector]\r
+ MOV DX,ES:[BP.dpb_dir_sector]\r
+ SUB AX,DX\r
+ MOV BYTE PTR [CLUSFAC],AL\r
+ MOV [DIRSEC],DX\r
+ return\r
+\r
+SETCURR:\r
+ASSUME DS:DOSGROUP\r
+ MOV AX,[DIRSTART]\r
+ MOV ES:[BP.dpb_current_dir],AX\r
+ return\r
+\r
+ entry SETDIRSRCH\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; BX cluster number of start of directory\r
+; ES:BP Points to DPB\r
+; Function:\r
+; Set up a directory search\r
+; Outputs:\r
+; DS = DOSGROUP\r
+; [DIRSTART] = BX\r
+; [CLUSFAC],[CLUSNUM],[SECCLUSPOS],[DIRSEC] set\r
+; destroys AX,DX\r
+\r
+ OR BX,BX\r
+ JZ SETROOTSRCH\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ MOV [DIRSTART],BX\r
+ MOV AL,ES:[BP.dpb_cluster_mask]\r
+ INC AL\r
+ MOV BYTE PTR [CLUSFAC],AL\r
+ invoke UNPACK\r
+ MOV [CLUSNUM],DI\r
+ MOV DX,BX\r
+ XOR BL,BL\r
+ MOV BYTE PTR [SECCLUSPOS],BL\r
+ invoke FIGREC\r
+ MOV [DIRSEC],DX\r
+ return\r
+Dir_search ENDP\r
+\r
+SUBTTL MAKENODE -- CREATE A NEW NODE\r
+PAGE\r
+ procedure MakeNode,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; AL - attribute to create\r
+; DS:SI Points to asciz path\r
+; [THISFCB] Points to an empty FCB\r
+; Function:\r
+; Make a new node\r
+; Outputs:\r
+; DS=DOSGROUP\r
+; ES:BP Points to DPB\r
+; AX = 0 Success\r
+; AX = 1 A node by this name exists and is a directory\r
+; AX = 2 A new node could not be created error\r
+; AX = 3 A node by this name exists and is a file error\r
+; AX = 4 Bad Path error\r
+; AX = 5 Attribute mismatch error\r
+; CARRY SET IF ERROR\r
+; ELSE\r
+; [DIRSTART],[DIRSEC],[CLUSFAC],[CLUSNUM] set to directory\r
+; containing new node.\r
+; [CURBUF+2]:BX Points to entry\r
+; [CURBUF+2]:SI Points to entry.fcb_firclus\r
+; [ThisFCB] is filled in\r
+; If this is a new entry zero is set and\r
+; Attribute byte in entry is directory\r
+; else a file existed by this name and:\r
+; [NAME1] has name\r
+; entry is not changed in any way\r
+; Destroys all registers\r
+\r
+ PUSH AX\r
+ CALL GetPath\r
+ MOV DL,CL ; Save CL info\r
+ POP CX\r
+ MOV BYTE PTR [ATTRIB],CL\r
+ MOV CX,AX\r
+ JNC make_exists ; File existed\r
+ JNZ make_err_4 ; Path bad\r
+ OR DL,DL ; Check "CL" return from GETPATH\r
+ JNZ make_type ; Name simply not found\r
+make_err_4:\r
+ MOV AL,4 ; case 1 bad path\r
+make_err_ret:\r
+ STC\r
+ return\r
+\r
+make_type:\r
+ XOR AL,AL ; nothing exists... assume 0\r
+ STC\r
+ JMP SHORT make_save\r
+make_exists:\r
+ JZ make_exists_dir\r
+ MOV AL,3 ; file exists type 3\r
+ TEST BYTE PTR [ATTRIB],(attr_volume_id+attr_directory)\r
+ JNZ make_err_ret_5 ; but we wanted a volid or dir\r
+ OR CH,CH\r
+ JS make_dev ; No furthur checks if device\r
+ PUSH CX\r
+ MOV DS,WORD PTR [CURBUF+2]\r
+ MOV CH,[BX+dir_attr] ; Get file attributes\r
+ TEST CH,attr_read_only\r
+ JNZ make_err_ret_5P ; Cannot create on read only files\r
+ CALL MatchAttributes\r
+make_err_ret_5P:\r
+ POP CX\r
+ JZ make_dev ; Attributes ok\r
+make_err_ret_5:\r
+ MOV AL,5 ; Attribute mismatch\r
+ JMP SHORT make_err_ret\r
+\r
+make_dev:\r
+ XOR AL,AL ; Make sure zero set(atts match), carry clear(exists)\r
+ MOV AL,3 ; Restore correct value\r
+ JMP SHORT make_save\r
+make_exists_dir:\r
+ MOV AL,1 ; directory exists\r
+ TEST BYTE PTR [ATTRIB],attr_directory\r
+ JZ make_err_ret ; we didn't want a directory\r
+ CLC\r
+ return ; just return\r
+make_save:\r
+ PUSH AX\r
+;\r
+; set up for call to NewEntry - it is in the middle of FCB_CREATE\r
+; so we must also pre-push two registers. They will be popped off\r
+; by FCB_CREATE\r
+;\r
+ PUSH SS\r
+ POP DS\r
+ ASSUME DS:DOSGROUP\r
+ PUSHF ;Save state of flags\r
+ CMP BYTE PTR [NAME1],'.' ;Detect attempt to make '.' or '..'\r
+ JNZ NOTLDOT ; Needed because no '.' or '..' in root\r
+ POPF\r
+ MOV AL,1 ;Force type 2 error\r
+ JMP SHORT SET2ERR\r
+\r
+NOTLDOT:\r
+ POPF\r
+ PUSH ES\r
+ LES DI,[ThisFCB]\r
+ PUSH DS\r
+ PUSH DI\r
+ PUSH ES\r
+ MOV AX,CX\r
+ invoke NewEntry\r
+ POP DS\r
+ POP ES\r
+SET2ERR:\r
+ OR AL,AL\r
+ POP AX\r
+ JZ make_set_fcb\r
+ MOV AL,2 ; create failed case 2\r
+ STC\r
+ return\r
+make_set_fcb:\r
+ASSUME DS:DOSGROUP\r
+ PUSH ES\r
+ LES DI,[THISFCB]\r
+ INC DI\r
+ PUSH DS\r
+ PUSH SI\r
+ MOV DS,WORD PTR [CURBUF+2]\r
+ASSUME DS:NOTHING\r
+ MOV SI,BX\r
+ MOV CX,11\r
+ REP MOVSB\r
+ POP SI\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ POP ES\r
+ CMP AL,1\r
+ JA make_errors\r
+ OR AL,AL\r
+ CLC\r
+ return\r
+make_errors:\r
+ STC\r
+ return\r
+\r
+MakeNode ENDP\r
+\r
+SUBTTL GETPATH -- PARSE AN asciz PATH\r
+PAGE\r
+\r
+ procedure GETPATH,near\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DS:SI Points to asciz path\r
+; Function:\r
+; Crack the path\r
+; Outputs:\r
+; [DRIVESPEC] is non zero if a drive was specified\r
+; [ROOTSTART] is non zero if a / started the path\r
+; [ATTRIB] set to attr_directory+attr_hidden+attr_system\r
+; Same as FINDPATH except if path specifies a device in which case\r
+; bit 7 of AH will be set and SI and BX will point DOSGROUP relative\r
+; Destroys all registers\r
+\r
+ XOR AX,AX\r
+ MOV WORD PTR [DRIVESPEC],AX\r
+ MOV BYTE PTR [ATTRIB],attr_directory+attr_system+attr_hidden\r
+ LODSB\r
+ invoke PATHCHRCMP\r
+ JZ DEFAULTROOT\r
+ MOV AH,AL\r
+ LODSB\r
+ CMP AL,':'\r
+ JZ DRVSPEC\r
+ DEC SI\r
+ DEC SI\r
+ PUSH DS\r
+ PUSH SI\r
+ PUSH SS\r
+ POP ES\r
+ CMP BYTE PTR [device_availability],0\r
+ JZ NOWDEV\r
+ CALL GOTPRESTRING2\r
+ JNC BUILDFCBJ ; If no carry then we have a device\r
+NOWDEV:\r
+ CALL DEFPATH\r
+GOFIND:\r
+ MOV AL,[NoSetDir]\r
+ PUSH AX\r
+ MOV [NoSetDir],0\r
+ CALL GETCURRDIR\r
+ POP AX\r
+ MOV [NoSetDir],AL\r
+ POP SI\r
+ POP DS\r
+ JMP FINDPATH\r
+\r
+DEFPATH:\r
+ XOR AL,AL\r
+DRVPATH:\r
+ invoke GETTHISDRV\r
+ retc ; Bad drive\r
+ PUSH SS\r
+ POP DS\r
+ invoke FATREAD\r
+ CLC\r
+ return\r
+\r
+DEFAULTROOT:\r
+ PUSH DS\r
+ PUSH SI\r
+ CALL DEFPATH\r
+ POP SI\r
+ POP DS\r
+ROOTSRCH:\r
+ INC BYTE PTR [ROOTSTART]\r
+ CMP BYTE PTR [SI],0\r
+ JZ PATHISNULL\r
+ PUSH DS\r
+ PUSH SI\r
+ PUSH ES ; Save pointer to DPB\r
+ CALL CHKDEV\r
+ POP ES\r
+ JNC BUILDFCBJ\r
+ POP SI\r
+ POP DS\r
+ JMP ROOTPATH\r
+\r
+BUILDFCBJ:\r
+ POP AX\r
+ POP AX\r
+ context es\r
+ invoke BUILDFCB ; Clears carry sets zero\r
+ INC AL ; reset zero\r
+ return\r
+\r
+DRVSPEC:\r
+ INC [DRIVESPEC]\r
+ MOV AL,AH\r
+ OR AL,20H ; Convert to lower case\r
+ SUB AL,60H ; Make A=1\r
+ PUSH DS\r
+ PUSH SI\r
+ PUSH AX\r
+ context es\r
+ CALL GotPreString2\r
+ ASSUME ES:NOTHING\r
+ POP AX\r
+ JNC BuildFCBJ\r
+ CALL DRVPATH\r
+ POP SI\r
+ POP DS\r
+ retc ; Bad drive\r
+ LODSB\r
+ invoke PATHCHRCMP\r
+ JZ ROOTSRCH\r
+ DEC SI\r
+ PUSH DS\r
+ PUSH SI\r
+ JMP GOFIND\r
+\r
+PATHISNULL:\r
+ CALL SETROOTSRCH\r
+ASSUME DS:DOSGROUP\r
+ XOR AL,AL ; Set zero (directory) clear carry\r
+ return\r
+\r
+CHKDEV:\r
+ASSUME DS:NOTHING\r
+ PUSH SS\r
+ POP ES\r
+ MOV DI,OFFSET DOSGROUP:DEVSTRING\r
+ XOR CX,CX\r
+ MOV CL,DEVSTRLEN\r
+CHKPRESTRING:\r
+ REPE CMPSB\r
+ JZ GOTPRESTRING\r
+ DEC SI\r
+ invoke GETLET ; Try convert to upper case\r
+ CMP AL,ES:[DI-1]\r
+ JZ CHKPRESTRING\r
+NOPRESTRING:\r
+ STC\r
+ return\r
+\r
+GOTPRESTRING:\r
+ LODSB\r
+ invoke PATHCHRCMP\r
+ JNZ NOPRESTRING\r
+GOTPRESTRING2:\r
+ MOV DI,OFFSET DOSGROUP:NAME1\r
+ MOV CX,9\r
+TESTLOOP:\r
+ invoke GETLET\r
+ CMP AL,'.'\r
+ JZ TESTDEVICE\r
+ invoke PATHCHRCMP\r
+ JZ NOTDEV\r
+ OR AL,AL\r
+ JZ TESTDEVICE\r
+ STOSB\r
+ LOOP TESTLOOP\r
+NOTDEV:\r
+ STC\r
+ return\r
+\r
+TESTDEVICE:\r
+ ADD CX,2\r
+ MOV AL,' '\r
+ REP STOSB\r
+ PUSH SS\r
+ POP DS\r
+ invoke DEVNAME\r
+ return\r
+GETPATH ENDP\r
+\r
+SUBTTL ROOTPATH, FINDPATH -- PARSE A PATH\r
+PAGE\r
+ procedure ROOTPATH,near\r
+\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; ES:BP Points to DPB\r
+; FATREAD should be called before this routine\r
+; DS:SI Points to asciz string of path which is assumed to start at\r
+; the root (no leading '/').\r
+; Function:\r
+; Search from root for path\r
+; Outputs:\r
+; Same as FINDPATH\r
+; Destroys all registers\r
+\r
+ PUSH DS\r
+ CALL SETROOTSRCH\r
+ POP DS\r
+\r
+; NOTE FALL THROUGH\r
+\r
+ entry FINDPATH\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; ES:BP Points to DPB\r
+; DS:SI Points to asciz string of path (no leading '/').\r
+; [SECCLUSPOS] = 0\r
+; [DIRSEC] = Phys sec # of first sector of directory\r
+; [CLUSNUM] = Cluster # of next cluster\r
+; [CLUSFAC] = Sectors per cluster\r
+; Validate_path should be called before this routine is used,\r
+; unless it is KNOWN the path is good.\r
+; Function:\r
+; Parse path name\r
+; Outputs:\r
+; ES:BP Points to DPB\r
+; Carry set if bad path\r
+; DS:SI Points to path element causing failure\r
+; Zero set\r
+; [DIRSTART],[DIRSEC],[CLUSNUM], and [CLUSFAC] are set up to\r
+; start a search on the last directory\r
+; CL is zero if there is a bad name in the path\r
+; CL is non-zero if the name was simply not found\r
+; [ENTFREE] may have free spot in directory\r
+; [NAME1] is the name.\r
+; CL = 81H if '*'s or '?' in name 1, 80H otherwise\r
+; Zero reset\r
+; File in middle of path or bad name in path\r
+; or path too long or malformed path\r
+; ELSE\r
+; DS = DOSGROUP\r
+; AH = device ID\r
+; [CURBUF] contains directory record with match\r
+; [CURBUF+2]:BX Points into [CURBUF] to start of entry\r
+; [CURBUF+2]:SI Points to fcb_FIRCLUS field for entry\r
+; [NAME1] Has entry name\r
+; If last element is a directory zero is set and:\r
+; [DIRSTART],[SECCLUSPOS],[DIRSEC],[CLUSNUM], and [CLUSFAC]\r
+; are set up to start a search on it.\r
+; If last element is a file zero is reset\r
+; Destroys all registers\r
+\r
+ PUSH ES\r
+ PUSH SI\r
+ invoke NAMETRANS\r
+ MOV CL,AL\r
+ OR CL,80H\r
+ POP DI\r
+ POP ES\r
+ CMP SI,DI\r
+ JNZ check_device\r
+ JMP BADPATH\r
+check_device:\r
+ PUSH DS\r
+ PUSH SI\r
+ MOV AL,BYTE PTR [SI]\r
+\r
+;\r
+; can we see all devices\r
+;\r
+ context DS\r
+ CMP BYTE PTR [device_availability],0\r
+ JZ FindFile\r
+\r
+;\r
+; check name1 to see if we have a device...\r
+;\r
+ PUSH ES\r
+ context ES\r
+ invoke DevName ; blast BX\r
+ POP ES\r
+ ASSUME ES:NOTHING\r
+ JC FindFile\r
+ OR AL,AL\r
+ JNZ FileInPath\r
+ POP SI\r
+ POP SI\r
+ context ES\r
+ invoke BuildFCB\r
+ INC AL\r
+ return\r
+\r
+FindFile:\r
+ ASSUME ES:NOTHING\r
+ PUSH DI ; Start of this element\r
+ PUSH ES\r
+ PUSH CX\r
+ CALL FINDENTRY\r
+ POP CX\r
+ POP ES\r
+ POP DI\r
+ JC BADPATHPOP\r
+ LDS DI,[CURBUF]\r
+ASSUME DS:NOTHING\r
+ TEST BYTE PTR [BX+dir_attr],attr_directory\r
+ JZ FileInPath\r
+\r
+;\r
+; if we are not setting the directory, then\r
+; check for end of string\r
+;\r
+ CMP BYTE PTR [NoSetDir],0\r
+ JZ SetDir\r
+ MOV DX,DI\r
+ MOV AX,DS\r
+ POP DI\r
+ POP DS\r
+ CMP BYTE PTR [DI],0\r
+ JZ SetRet\r
+ PUSH DS\r
+ PUSH DI\r
+ MOV DI,DX\r
+ MOV DS,AX\r
+\r
+SetDir:\r
+ MOV DX,[SI]\r
+ SUB BX,DI\r
+ SUB SI,DI\r
+ PUSH BX\r
+ PUSH AX\r
+ PUSH SI\r
+ PUSH CX\r
+ PUSH [DI.BUFSECNO]\r
+ MOV BX,DX\r
+ CALL SETDIRSRCH\r
+ASSUME DS:DOSGROUP\r
+ POP DX\r
+ XOR AL,AL\r
+ invoke GETBUFFR\r
+ POP CX\r
+ POP SI\r
+ POP AX\r
+ POP BX\r
+ MOV DI,WORD PTR [CURBUF]\r
+ ADD SI,DI\r
+ ADD BX,DI\r
+ POP DI\r
+ POP DS\r
+ASSUME DS:NOTHING\r
+ MOV AL,[DI]\r
+ OR AL,AL\r
+ JZ SETRET\r
+ INC DI\r
+ MOV SI,DI\r
+ invoke PATHCHRCMP\r
+ JNZ find_bad_name\r
+ JMP FINDPATH\r
+\r
+find_bad_name:\r
+ DEC SI\r
+BADPATH:\r
+ XOR CL,CL ; Set zero\r
+ STC\r
+ return\r
+\r
+FILEINPATH:\r
+ POP DI\r
+ POP DS\r
+ MOV AL,[DI]\r
+ OR AL,AL\r
+ JZ INCRET\r
+ MOV SI,DI ; Path too long\r
+ STC\r
+ return\r
+\r
+INCRET:\r
+ INC AL ; Reset zero\r
+SETRET:\r
+ PUSH SS\r
+ POP DS\r
+ return\r
+\r
+BADPATHPOP:\r
+ POP SI\r
+ POP DS\r
+ MOV AL,[SI]\r
+ MOV SI,DI ; Start of bad element\r
+ OR AL,AL ; zero if bad element is last, non-zero if path too long\r
+ STC\r
+ return\r
+ROOTPATH ENDP\r
+\r
+SUBTTL STARTSRCH -- INITIATE DIRECTORY SEARCH\r
+PAGE\r
+ procedure StartSrch,NEAR\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+; Inputs:\r
+; [THISDPB] Set\r
+; Function:\r
+; Set up a search for GETENTRY and NEXTENTRY\r
+; Outputs:\r
+; ES:BP = Drive parameters\r
+; Sets up LASTENT, ENDENT, ENTFREE=ENTLAST=-1, VOLID=0\r
+; Destroys all registers (via FATREAD)\r
+\r
+ LES BP,[THISDPB]\r
+ XOR AX,AX\r
+ MOV [LASTENT],AX\r
+ MOV BYTE PTR [VOLID],AL ; No volume ID found\r
+ DEC AX\r
+ MOV [ENTFREE],AX\r
+ MOV [ENTLAST],AX\r
+ return\r
+StartSrch ENDP\r
+\r
+BREAK <MatchAttributes - the final check for attribute matching>\r
+\r
+;\r
+; Input: [Attrib] = attribute to search for\r
+; CH = found attribute\r
+; Output: JZ <match>\r
+; JNZ <nomatch>\r
+;\r
+ procedure MatchAttributes,near\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ PUSH AX\r
+ MOV AL,[Attrib] ; AL <- SearchSet\r
+ NOT AL ; AL <- SearchSet'\r
+ AND AL,CH ; AL <- SearchSet' and FoundSet\r
+ AND AL,attr_all ; AL <- SearchSet' and FoundSet and Important\r
+;\r
+; the result is non-zero if an attribute is not in the search set\r
+; and in the found set and in the important set. This means that we do not\r
+; have a match. Do a JNZ <nomatch> or JZ <match>\r
+;\r
+ POP AX\r
+ return\r
+MatchAttributes ENDP\r
+\r
+do_ext\r
+\r
+CODE ENDS\r
+ END\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+TITLE DIRCALL - Directory manipulation internal calls\r
+NAME DIRCALL\r
+\r
+; $MKDIR\r
+; $CHDIR\r
+; $RMDIR\r
+\r
+.xlist\r
+INCLUDE DOSSEG.ASM\r
+\r
+CODE SEGMENT BYTE PUBLIC 'CODE'\r
+ ASSUME SS:DOSGROUP,CS:DOSGROUP\r
+\r
+.xcref\r
+INCLUDE DOSSYM.ASM\r
+INCLUDE DEVSYM.ASM\r
+.cref\r
+.list\r
+\r
+ifndef Kanji\r
+Kanji equ 0\r
+endif\r
+\r
+ i_need AUXSTACK,BYTE\r
+ i_need NoSetDir,BYTE\r
+ i_need CURBUF, DWORD\r
+ i_need DIRSTART,WORD\r
+ i_need THISDPB,DWORD\r
+ i_need NAME1,BYTE\r
+ i_need LASTENT,WORD\r
+ i_need ATTRIB,BYTE\r
+ i_need THISFCB,DWORD\r
+ i_need AUXSTACK,BYTE\r
+ i_need CREATING,BYTE\r
+ i_need DRIVESPEC,BYTE\r
+ i_need ROOTSTART,BYTE\r
+ i_need SWITCH_CHARACTER,BYTE\r
+\r
+ extrn sys_ret_ok:near,sys_ret_err:near\r
+\r
+\r
+; XENIX CALLS\r
+BREAK <$MkDir - Make a directory entry>\r
+MKNERRJ: JMP MKNERR\r
+NODEEXISTSJ: JMP NODEEXISTS\r
+ procedure $MKDIR,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DS:DX Points to asciz name\r
+; Function:\r
+; Make a new directory\r
+; Returns:\r
+; STD XENIX Return\r
+; AX = mkdir_path_not_found if path bad\r
+; AX = mkdir_access_denied If\r
+; Directory cannot be created\r
+; Node already exists\r
+; Device name given\r
+; Disk or directory(root) full\r
+ invoke validate_path\r
+ JC MKNERRJ\r
+ MOV SI,DX\r
+ MOV WORD PTR [THISFCB+2],SS\r
+ MOV WORD PTR [THISFCB],OFFSET DOSGROUP:AUXSTACK-40 ; Scratch space\r
+ MOV AL,attr_directory\r
+ MOV WORD PTR [CREATING],0E500h\r
+ invoke MAKENODE\r
+ASSUME DS:DOSGROUP\r
+ MOV AL,mkdir_path_not_found\r
+ JC MKNERRJ\r
+ JNZ NODEEXISTSJ\r
+ LDS DI,[CURBUF]\r
+ASSUME DS:NOTHING\r
+ SUB SI,DI\r
+ PUSH SI ; Pointer to fcb_FIRCLUS\r
+ PUSH [DI.BUFSECNO] ; Sector of new node\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ PUSH [DIRSTART] ; Parent for .. entry\r
+ XOR AX,AX\r
+ MOV [DIRSTART],AX ; Null directory\r
+ invoke NEWDIR\r
+ JC NODEEXISTSPOPDEL ; No room\r
+ invoke GETENT ; First entry\r
+ LES DI,[CURBUF]\r
+ MOV ES:[DI.BUFDIRTY],1\r
+ ADD DI,BUFINSIZ ; Point at buffer\r
+ MOV AX,202EH ; ". "\r
+ STOSW\r
+ MOV DX,[DIRSTART] ; Point at itself\r
+ invoke SETDOTENT\r
+ MOV AX,2E2EH ; ".."\r
+ STOSW\r
+ POP DX ; Parent\r
+ invoke SETDOTENT\r
+ LES BP,[THISDPB]\r
+ POP DX ; Entry sector\r
+ XOR AL,AL ; Pre read\r
+ invoke GETBUFFR\r
+ MOV DX,[DIRSTART]\r
+ LDS DI,[CURBUF]\r
+ASSUME DS:NOTHING\r
+ZAPENT:\r
+ POP SI ; fcb_Firclus pointer\r
+ ADD SI,DI\r
+ MOV [SI],DX\r
+ XOR DX,DX\r
+ MOV [SI+2],DX\r
+ MOV [SI+4],DX\r
+DIRUP:\r
+ MOV [DI.BUFDIRTY],1\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ MOV AL,ES:[BP.dpb_drive]\r
+ invoke FLUSHBUF\r
+SYS_RET_OKJ:\r
+ JMP SYS_RET_OK\r
+\r
+NODEEXISTSPOPDEL:\r
+ POP DX ; Parent\r
+ POP DX ; Entry sector\r
+ LES BP,[THISDPB]\r
+ XOR AL,AL ; Pre read\r
+ invoke GETBUFFR\r
+ LDS DI,[CURBUF]\r
+ASSUME DS:NOTHING\r
+ POP SI ; dir_first pointer\r
+ ADD SI,DI\r
+ SUB SI,dir_first ; Point back to start of dir entry\r
+ MOV BYTE PTR [SI],0E5H ; Free the entry\r
+ CALL DIRUP\r
+NODEEXISTS:\r
+ MOV AL,mkdir_access_denied\r
+MKNERR:\r
+ JMP SYS_RET_ERR\r
+$MKDIR ENDP\r
+\r
+BREAK <$ChDir -- Change current directory on a drive>\r
+ procedure $CHDIR,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DS:DX Points to asciz name\r
+; Function:\r
+; Change current directory\r
+; Returns:\r
+; STD XENIX Return\r
+; AX = chdir_path_not_found if error\r
+\r
+ invoke validate_path\r
+ JC PathTooLong\r
+\r
+ PUSH DS\r
+ PUSH DX\r
+ MOV SI,DX\r
+ invoke GETPATH\r
+ JC PATHNOGOOD\r
+ JNZ PATHNOGOOD\r
+ASSUME DS:DOSGROUP\r
+ MOV AX,[DIRSTART]\r
+ MOV BX,AX\r
+ XCHG BX,ES:[BP.dpb_current_dir]\r
+ OR AX,AX\r
+ POP SI\r
+ POP DS\r
+ASSUME DS:NOTHING\r
+ JZ SYS_RET_OKJ\r
+ MOV DI,BP\r
+ ADD DI,dpb_dir_text\r
+ MOV DX,DI\r
+ CMP [DRIVESPEC],0\r
+ JZ NODRIVESPEC\r
+ INC SI\r
+ INC SI\r
+NODRIVESPEC:\r
+ MOV CX,SI\r
+ CMP [ROOTSTART],0\r
+ JZ NOTROOTPATH\r
+ INC SI\r
+ INC CX\r
+ JMP SHORT COPYTHESTRINGBXZ\r
+NOTROOTPATH:\r
+ OR BX,BX ; Previous path root?\r
+ JZ COPYTHESTRING ; Yes\r
+ XOR BX,BX\r
+ENDLOOP:\r
+ CMP BYTE PTR ES:[DI],0\r
+ JZ PATHEND\r
+ INC DI\r
+ INC BX\r
+ JMP SHORT ENDLOOP\r
+PATHEND:\r
+ MOV AL,'/'\r
+ CMP AL,[switch_character]\r
+ JNZ SLASHOK\r
+ MOV AL,'\' ; Use the alternate character\r
+SLASHOK:\r
+ STOSB\r
+ INC BX\r
+ JMP SHORT CHECK_LEN\r
+\r
+PATHNOGOOD:\r
+ POP AX\r
+ POP AX\r
+PATHTOOLONG:\r
+ error error_path_not_found\r
+\r
+ASSUME DS:NOTHING\r
+\r
+INCBXCHK:\r
+ INC BX\r
+BXCHK:\r
+ CMP BX,DIRSTRLEN\r
+ return\r
+\r
+COPYTHESTRINGBXZ:\r
+ XOR BX,BX\r
+COPYTHESTRING:\r
+ LODSB\r
+ OR AL,AL\r
+\r
+ JNZ FOOB\r
+ JMP CPSTDONE\r
+FOOB:\r
+ CMP AL,'.'\r
+ JZ SEEDOT\r
+ CALL COPYELEM\r
+CHECK_LEN:\r
+ CMP BX,DIRSTRLEN\r
+ JB COPYTHESTRING\r
+ MOV AL,ES:[DI-1]\r
+ invoke PATHCHRCMP\r
+ JNZ OK_DI\r
+ DEC DI\r
+OK_DI:\r
+ XOR AL,AL\r
+ STOSB ; Correctly terminate the path\r
+ MOV ES:[BP.dpb_current_dir],-1 ; Force re-validation\r
+ JMP SHORT PATHTOOLONG\r
+\r
+SEEDOT:\r
+ LODSB\r
+ OR AL,AL ; Check for null\r
+ JZ CPSTDONEDEC\r
+ CMP AL,'.'\r
+ JNZ COPYTHESTRING ; eat ./\r
+ CALL DELELMES ; have ..\r
+ LODSB ; eat the /\r
+ OR AL,AL ; Check for null\r
+ JZ CPSTDONEDEC\r
+ JMP SHORT COPYTHESTRING\r
+\r
+; Copy one element from DS:SI to ES:DI include trailing / not trailing null\r
+; LODSB has already been done\r
+COPYELEM:\r
+ PUSH DI ; Save in case too long\r
+ PUSH CX\r
+ MOV CX,800h ; length of filename\r
+ MOV AH,'.' ; char to stop on\r
+ CALL CopyPiece ; go for it!\r
+ CALL BXCHK ; did we go over?\r
+ JAE POPCXDI ; yep, go home\r
+ CMP AH,AL ; did we stop on .?\r
+ JZ CopyExt ; yes, go copy ext\r
+ OR AL,AL ; did we end on nul?\r
+ JZ DECSIRet ; yes, bye\r
+CopyPathEnd:\r
+ STOSB ; save the path char\r
+ CALL INCBXCHK ; was there room for it?\r
+ JAE POPCXDI ; Nope\r
+ INC SI ; guard against following dec\r
+DECSIRET:\r
+ DEC SI ; point back at null\r
+ POP CX\r
+ POP AX ; toss away saved DI\r
+ return\r
+POPCXDI:\r
+ POP CX ; restore\r
+ POP DI ; point back...\r
+ return\r
+CopyExt:\r
+ STOSB ; save the dot\r
+ CALL INCBXCHK ; room?\r
+ JAE POPCXDI ; nope.\r
+ LODSB ; get next char\r
+ XOR AH,AH ; NUL here\r
+ MOV CX,300h ; at most 3 chars\r
+ CALL CopyPiece ; go copy it\r
+ CALL BXCHK ; did we go over\r
+ JAE POPCXDI ; yep\r
+ OR AL,AL ; sucessful end?\r
+ JZ DECSIRET ; yes\r
+ JMP CopyPathEnd ; go stash path char\r
+\r
+DELELMES:\r
+; Delete one path element from ES:DI\r
+ DEC DI ; the '/'\r
+ DEC BX\r
+\r
+ IF KANJI\r
+ PUSH AX\r
+ PUSH CX\r
+ PUSH DI\r
+ PUSH DX\r
+ MOV CX,DI\r
+ MOV DI,DX\r
+DELLOOP:\r
+ CMP DI,CX\r
+ JZ GOTDELE\r
+ MOV AL,ES:[DI]\r
+ INC DI\r
+ invoke TESTKANJ\r
+ JZ NOTKANJ11\r
+ INC DI\r
+ JMP DELLOOP\r
+\r
+NOTKANJ11:\r
+ invoke PATHCHRCMP\r
+ JNZ DELLOOP\r
+ MOV DX,DI ; Point to char after '/'\r
+ JMP DELLOOP\r
+\r
+GOTDELE:\r
+ MOV DI,DX\r
+ POP DX\r
+ POP AX ; Initial DI\r
+ SUB AX,DI ; Distance moved\r
+ SUB BX,AX ; Set correct BX\r
+ POP CX\r
+ POP AX\r
+ return\r
+ ELSE\r
+DELLOOP:\r
+ CMP DI,DX\r
+ retz\r
+ PUSH AX\r
+ MOV AL,ES:[DI-1]\r
+ invoke PATHCHRCMP\r
+ POP AX\r
+ retz\r
+ DEC DI\r
+ DEC BX\r
+ JMP SHORT DELLOOP\r
+ ENDIF\r
+\r
+CPSTDONEDEC:\r
+ DEC DI ; Back up over trailing /\r
+CPSTDONE:\r
+ STOSB ; The NUL\r
+ JMP SYS_RET_OK\r
+\r
+; copy a piece CH chars max until the char in AH (or path or NUL)\r
+CopyPiece:\r
+ STOSB ; store the character\r
+ INC CL ; moved a byte\r
+ CALL INCBXCHK ; room enough?\r
+ JAE CopyPieceRet ; no, pop CX and DI\r
+ OR AL,AL ; end of string?\r
+ JZ CopyPieceRet ; yes, dec si and return\r
+\r
+ IF KANJI\r
+ CALL TestKanj ; was it kanji?\r
+ JZ NotKanj ; nope\r
+ MOVSB ; move the next byte\r
+ CALL INCBXCHK ; room for it?\r
+ JAE CopyPieceRet ; nope\r
+ INC CL ; moved a byte\r
+NotKanj:\r
+ ENDIF\r
+\r
+ CMP CL,CH ; move too many?\r
+ JBE CopyPieceNext ; nope\r
+\r
+ IF KANJI\r
+ CALL TestKanj ; was the last byte kanji\r
+ JZ NotKanj2 ; no only single byte backup\r
+ DEC DI ; back up a char\r
+ DEC BX\r
+NotKanj2:\r
+ ENDIF\r
+\r
+ DEC DI ; back up a char\r
+ DEC BX\r
+CopyPieceNext:\r
+ LODSB ; get next character\r
+ invoke PathChrCmp ; end of road?\r
+ JZ CopyPieceRet ; yep, return and don't dec SI\r
+ CMP AL,AH ; end of filename?\r
+ JNZ CopyPiece ; go do name\r
+CopyPieceRet:\r
+ return ; bye!\r
+\r
+$CHDIR ENDP\r
+\r
+BREAK <$RmDir -- Remove a directory>\r
+NOPATHJ: JMP NOPATH\r
+\r
+ procedure $RMDIR,NEAR ; System call 47\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DS:DX Points to asciz name\r
+; Function:\r
+; Delete directory if empty\r
+; Returns:\r
+; STD XENIX Return\r
+; AX = rmdir_path_not_found If path bad\r
+; AX = rmdir_access_denied If\r
+; Directory not empty\r
+; Path not directory\r
+; Root directory specified\r
+; Directory malformed (. and .. not first two entries)\r
+; AX = rmdir_current_directory\r
+\r
+ invoke Validate_path\r
+ JC NoPathJ\r
+ MOV SI,DX\r
+ invoke GETPATH\r
+ JC NOPATHJ\r
+ASSUME DS:DOSGROUP\r
+ JNZ NOTDIRPATH\r
+ MOV DI,[DIRSTART]\r
+ OR DI,DI\r
+ JZ NOTDIRPATH\r
+ MOV CX,ES:[BP.dpb_current_dir]\r
+ CMP CX,-1\r
+ JNZ rmdir_current_dir_check\r
+ invoke GetCurrDir\r
+ invoke Get_user_stack\r
+ MOV DX,[SI.user_DX]\r
+ MOV DS,[SI.user_DS]\r
+ JMP $RMDIR\r
+\r
+NOTDIRPATHPOP:\r
+ POP AX\r
+ POP AX\r
+NOTDIRPATH:\r
+ error error_access_denied\r
+\r
+rmdir_current_dir_check:\r
+ CMP DI,CX\r
+ JNZ rmdir_get_buf\r
+ error error_current_directory\r
+\r
+rmdir_get_buf:\r
+ LDS DI,[CURBUF]\r
+ASSUME DS:NOTHING\r
+ SUB BX,DI\r
+ PUSH BX ; Save entry pointer\r
+ PUSH [DI.BUFSECNO] ; Save sector number\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ PUSH SS\r
+ POP ES\r
+ MOV DI,OFFSET DOSGROUP:NAME1\r
+ MOV AL,'?'\r
+ MOV CX,11\r
+ REP STOSB\r
+ XOR AL,AL\r
+ STOSB\r
+ invoke STARTSRCH\r
+ invoke GETENTRY\r
+ MOV DS,WORD PTR [CURBUF+2]\r
+ASSUME DS:NOTHING\r
+ MOV SI,BX\r
+ LODSW\r
+ CMP AX,(' ' SHL 8) OR '.'\r
+ JNZ NOTDIRPATHPOP\r
+ ADD SI,32-2\r
+ LODSW\r
+ CMP AX,('.' SHL 8) OR '.'\r
+ JNZ NOTDIRPATHPOP\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ MOV [LASTENT],2 ; Skip . and ..\r
+ invoke GETENTRY\r
+ MOV [ATTRIB],attr_directory+attr_hidden+attr_system\r
+ invoke SRCH\r
+ JNC NOTDIRPATHPOP\r
+ LES BP,[THISDPB]\r
+ MOV BX,[DIRSTART]\r
+ invoke RELEASE\r
+ POP DX\r
+ XOR AL,AL\r
+ invoke GETBUFFR\r
+ LDS DI,[CURBUF]\r
+ASSUME DS:NOTHING\r
+ POP BX\r
+ ADD BX,DI\r
+ MOV BYTE PTR [BX],0E5H ; Free the entry\r
+ JMP DIRUP\r
+\r
+NOPATH:\r
+ error error_path_not_found\r
+\r
+$RMDIR ENDP\r
+\r
+ do_ext\r
+\r
+CODE ENDS\r
+ END\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+;\r
+; Disk routines for MSDOS\r
+;\r
+\r
+INCLUDE DOSSEG.ASM\r
+\r
+CODE SEGMENT BYTE PUBLIC 'CODE'\r
+ ASSUME SS:DOSGROUP,CS:DOSGROUP\r
+\r
+.xlist\r
+.xcref\r
+INCLUDE DOSSYM.ASM\r
+INCLUDE DEVSYM.ASM\r
+.cref\r
+.list\r
+\r
+TITLE DISK - Disk utility routines\r
+NAME Disk\r
+\r
+ i_need COUTDSAV,BYTE\r
+ i_need COUTSAV,DWORD\r
+ i_need CINDSAV,BYTE\r
+ i_need CINSAV,DWORD\r
+ i_need CONSWAP,BYTE\r
+ i_need IDLEINT,BYTE\r
+ i_need THISFCB,DWORD\r
+ i_need DMAADD,DWORD\r
+ i_need DEVCALL,BYTE\r
+ i_need CALLSCNT,WORD\r
+ i_need CALLXAD,DWORD\r
+ i_need CONTPOS,WORD\r
+ i_need NEXTADD,WORD\r
+ i_need CONBUF,BYTE\r
+ i_need User_SS,WORD\r
+ i_need User_SP,WORD\r
+ i_need DSKStack,BYTE\r
+ i_need InDOS,BYTE\r
+ i_need NumIO,BYTE\r
+ i_need CurDrv,BYTE\r
+ i_need ThisDrv,BYTE\r
+ i_need ClusFac,BYTE\r
+ i_need SecClusPos,BYTE\r
+ i_need DirSec,WORD\r
+ i_need ClusNum,WORD\r
+ i_need NxtClusNum,WORD\r
+ i_need ReadOp,BYTE\r
+ i_need DskErr,BYTE\r
+ i_need RecCnt,WORD\r
+ i_need RecPos,4\r
+ i_need Trans,BYTE\r
+ i_need BytPos,4\r
+ i_need SecPos,WORD\r
+ i_need BytSecPos,WORD\r
+ i_need BytCnt1,WORD\r
+ i_need BytCnt2,WORD\r
+ i_need SecCnt,WORD\r
+ i_need ThisDPB,DWORD\r
+ i_need LastPos,WORD\r
+ i_need ValSec,WORD\r
+ i_need GrowCnt,DWORD\r
+\r
+SUBTTL LOAD -- MAIN READ ROUTINE AND DEVICE IN ROUTINES\r
+PAGE\r
+; * * * * Drivers for file input from devices * * * *\r
+\r
+ procedure SWAPBACK,NEAR\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+ PUSH ES\r
+ PUSH DI\r
+ PUSH SI\r
+ PUSH BX\r
+ MOV BX,1\r
+ invoke get_sf_from_jfn\r
+ ADD DI,sf_fcb\r
+ MOV BL,BYTE PTR [COUTDSAV]\r
+ LDS SI,[COUTSAV]\r
+ASSUME DS:NOTHING\r
+ MOV WORD PTR ES:[DI.fcb_FIRCLUS],SI\r
+ MOV WORD PTR ES:[DI.fcb_FIRCLUS+2],DS\r
+ MOV ES:[DI.fcb_DEVID],BL\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ XOR BX,BX\r
+ invoke get_sf_from_jfn\r
+ ADD DI,sf_fcb\r
+ MOV BL,BYTE PTR [CINDSAV]\r
+ LDS SI,[CINSAV]\r
+ASSUME DS:NOTHING\r
+ MOV WORD PTR ES:[DI.fcb_FIRCLUS],SI\r
+ MOV WORD PTR ES:[DI.fcb_FIRCLUS+2],DS\r
+ MOV ES:[DI.fcb_DEVID],BL\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ MOV BYTE PTR [CONSWAP],0\r
+ MOV BYTE PTR [IDLEINT],1\r
+SWAPRET:\r
+ POP BX\r
+ POP SI\r
+ POP DI\r
+ POP ES\r
+ return\r
+SWAPBACK ENDP\r
+\r
+ procedure SWAPCON,NEAR\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+ PUSH ES\r
+ PUSH DI\r
+ PUSH SI\r
+ PUSH BX\r
+ MOV BYTE PTR [CONSWAP],1\r
+ MOV BYTE PTR [IDLEINT],0\r
+ XOR BX,BX\r
+ invoke get_sf_from_jfn\r
+ ADD DI,sf_fcb\r
+ MOV BL,ES:[DI.fcb_DEVID]\r
+ MOV BYTE PTR [CINDSAV],BL\r
+ LDS SI,DWORD PTR ES:[DI.fcb_FIRCLUS]\r
+ASSUME DS:NOTHING\r
+ MOV WORD PTR [CINSAV],SI\r
+ MOV WORD PTR [CINSAV+2],DS\r
+ LDS SI,[THISFCB]\r
+ MOV BL,[SI.fcb_DEVID]\r
+ LDS SI,DWORD PTR [SI.fcb_FIRCLUS]\r
+ MOV ES:[DI.fcb_DEVID],BL\r
+ MOV WORD PTR ES:[DI.fcb_FIRCLUS],SI\r
+ MOV WORD PTR ES:[DI.fcb_FIRCLUS+2],DS\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ MOV BX,1\r
+ invoke get_sf_from_jfn\r
+ ADD DI,sf_fcb\r
+ MOV BL,ES:[DI.fcb_DEVID]\r
+ MOV BYTE PTR [COUTDSAV],BL\r
+ LDS SI,DWORD PTR ES:[DI.fcb_FIRCLUS]\r
+ASSUME DS:NOTHING\r
+ MOV WORD PTR [COUTSAV],SI\r
+ MOV WORD PTR [COUTSAV+2],DS\r
+ LDS SI,[THISFCB]\r
+ MOV BL,[SI.fcb_DEVID]\r
+ LDS SI,DWORD PTR [SI.fcb_FIRCLUS]\r
+ MOV ES:[DI.fcb_DEVID],BL\r
+ MOV WORD PTR ES:[DI.fcb_FIRCLUS],SI\r
+ MOV WORD PTR ES:[DI.fcb_FIRCLUS+2],DS\r
+ PUSH SS\r
+ POP DS\r
+ JMP SWAPRET\r
+SWAPCON ENDP\r
+\r
+ procedure LOAD,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+;\r
+; Inputs:\r
+; DS:DI point to FCB\r
+; DX:AX = Position in file to read\r
+; CX = No. of records to read\r
+; Outputs:\r
+; DX:AX = Position of last record read\r
+; CX = No. of bytes read\r
+; ES:DI point to FCB\r
+; fcb_LSTCLUS, fcb_CLUSPOS fields in FCB set\r
+\r
+ call SETUP\r
+ASSUME DS:DOSGROUP\r
+ OR BL,BL ; Check for named device I/O\r
+ JS READDEV\r
+ call DISKREAD\r
+ return\r
+\r
+READDEV:\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+ LES DI,[DMAADD]\r
+ TEST BL,40H ; End of file?\r
+ JZ ENDRDDEVJ3\r
+ TEST BL,ISNULL ; NUL device?\r
+ JZ TESTRAW ; NO\r
+ XOR AL,AL ; Indicate EOF\r
+ENDRDDEVJ3: JMP ENDRDDEVJ2\r
+\r
+DVRDRAW:\r
+ASSUME DS:DOSGROUP\r
+ PUSH ES\r
+ POP DS\r
+ASSUME DS:NOTHING\r
+DVRDRAWR:\r
+ MOV BX,DI ; DS:BX transfer addr\r
+ XOR DX,DX ; Start at 0\r
+ XOR AX,AX ; Media Byte, unit = 0\r
+ invoke SETREAD\r
+ LDS SI,[THISFCB]\r
+ invoke DEVIOCALL\r
+ MOV DX,DI ; DX is preserved by INT 24\r
+ MOV AH,86H ; Read error\r
+ MOV DI,[DEVCALL.REQSTAT]\r
+ TEST DI,STERR\r
+ JZ CRDROK ; No errors\r
+ invoke CHARHARD\r
+ MOV DI,DX\r
+ CMP AL,1\r
+ JZ DVRDRAWR ; Retry\r
+CRDROK:\r
+ MOV DI,DX\r
+ ADD DI,[CALLSCNT] ; Amount transferred\r
+ JMP SHORT ENDRDDEVJ2\r
+\r
+TESTRAW:\r
+ TEST BL,020H ; Raw mode?\r
+ JNZ DVRDRAW\r
+ TEST BL,ISCIN ; Is it console device?\r
+ JZ NOTRDCON\r
+ JMP READCON\r
+NOTRDCON:\r
+ MOV AX,ES\r
+ MOV DS,AX\r
+ASSUME DS:NOTHING\r
+ MOV BX,DI\r
+ XOR DX,DX\r
+ MOV AX,DX\r
+ PUSH CX\r
+ MOV CX,1\r
+ invoke SETREAD\r
+ POP CX\r
+ LDS SI,[THISFCB]\r
+ LDS SI,DWORD PTR [SI.fcb_FIRCLUS]\r
+DVRDLP:\r
+ invoke DSKSTATCHK\r
+ invoke DEVIOCALL2\r
+ PUSH DI\r
+ MOV AH,86H\r
+ MOV DI,[DEVCALL.REQSTAT]\r
+ TEST DI,STERR\r
+ JZ CRDOK\r
+ invoke CHARHARD\r
+ POP DI\r
+ MOV [CALLSCNT],1\r
+ CMP AL,1\r
+ JZ DVRDLP ;Retry\r
+ XOR AL,AL ;Pick some random character\r
+ JMP SHORT DVRDIGN\r
+CRDOK:\r
+ POP DI\r
+ CMP [CALLSCNT],1\r
+ JNZ ENDRDDEVJ2\r
+ PUSH DS\r
+ MOV DS,WORD PTR [CALLXAD+2]\r
+ MOV AL,BYTE PTR [DI]\r
+ POP DS\r
+DVRDIGN:\r
+ INC WORD PTR [CALLXAD]\r
+ MOV [DEVCALL.REQSTAT],0\r
+ INC DI\r
+ CMP AL,1AH ; ^Z?\r
+ JZ ENDRDDEVJ\r
+ CMP AL,c_CR ; CR?\r
+ LOOPNZ DVRDLP\r
+ENDRDDEVJ:\r
+ DEC DI\r
+ENDRDDEVJ2:\r
+ JMP SHORT ENDRDDEV\r
+\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+TRANBUF:\r
+ LODSB\r
+ STOSB\r
+ CMP AL,c_CR ; Check for carriage return\r
+ JNZ NORMCH\r
+ MOV BYTE PTR [SI],c_LF\r
+NORMCH:\r
+ CMP AL,c_LF\r
+ LOOPNZ TRANBUF\r
+ JNZ ENDRDCON\r
+ XOR SI,SI ; Cause a new buffer to be read\r
+ invoke OUT ; Transmit linefeed\r
+ OR AL,1 ; Clear zero flag--not end of file\r
+ENDRDCON:\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ CALL SWAPBACK\r
+ MOV [CONTPOS],SI\r
+ENDRDDEV:\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ MOV [NEXTADD],DI\r
+ JNZ SETFCBC ; Zero set if Ctrl-Z found in input\r
+ LES DI,[THISFCB]\r
+ AND ES:BYTE PTR [DI.fcb_DEVID],0FFH-40H ; Mark as no more data available\r
+SETFCBC:\r
+ call SETFCB\r
+ return\r
+\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+READCON:\r
+ASSUME DS:DOSGROUP\r
+ CALL SWAPCON\r
+ MOV SI,[CONTPOS]\r
+ OR SI,SI\r
+ JNZ TRANBUF\r
+ CMP BYTE PTR [CONBUF],128\r
+ JZ GETBUF\r
+ MOV WORD PTR [CONBUF],0FF80H ; Set up 128-byte buffer with no template\r
+GETBUF:\r
+ PUSH CX\r
+ PUSH ES\r
+ PUSH DI\r
+ MOV DX,OFFSET DOSGROUP:CONBUF\r
+ invoke $STD_CON_STRING_INPUT ; Get input buffer\r
+ POP DI\r
+ POP ES\r
+ POP CX\r
+ MOV SI,2 + OFFSET DOSGROUP:CONBUF\r
+ CMP BYTE PTR [SI],1AH ; Check for Ctrl-Z in first character\r
+ JNZ TRANBUF\r
+ MOV AL,1AH\r
+ STOSB\r
+ DEC DI\r
+ MOV AL,10\r
+ invoke OUT ; Send linefeed\r
+ XOR SI,SI\r
+ JMP SHORT ENDRDCON\r
+\r
+LOAD ENDP\r
+\r
+SUBTTL STORE -- MAIN WRITE ROUTINE AND DEVICE OUT ROUTINES\r
+PAGE\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+ procedure STORE,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DS:DI point to FCB\r
+; DX:AX = Position in file of disk transfer\r
+; CX = Record count\r
+; Outputs:\r
+; DX:AX = Position of last record written\r
+; CX = No. of records written\r
+; ES:DI point to FCB\r
+; fcb_LSTCLUS, fcb_CLUSPOS fields in FCB set\r
+\r
+ call SETUP\r
+ASSUME DS:DOSGROUP\r
+ OR BL,BL\r
+ JS WRTDEV\r
+ invoke DATE16\r
+ MOV ES:[DI.fcb_FDATE],AX\r
+ MOV ES:[DI.fcb_FTIME],DX\r
+ call DISKWRITE\r
+ return\r
+\r
+WRITECON:\r
+ PUSH DS\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ CALL SWAPCON\r
+ POP DS\r
+ASSUME DS:NOTHING\r
+ MOV SI,BX\r
+ PUSH CX\r
+WRCONLP:\r
+ LODSB\r
+ CMP AL,1AH ; ^Z?\r
+ JZ CONEOF\r
+ invoke OUT\r
+ LOOP WRCONLP\r
+CONEOF:\r
+ POP AX ; Count\r
+ SUB AX,CX ; Amount actually written\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ CALL SWAPBACK\r
+ JMP SHORT ENDWRDEV\r
+\r
+DVWRTRAW:\r
+ASSUME DS:NOTHING\r
+ XOR AX,AX ; Media Byte, unit = 0\r
+ invoke SETWRITE\r
+ LDS SI,[THISFCB]\r
+ invoke DEVIOCALL\r
+ MOV DX,DI\r
+ MOV AH,87H\r
+ MOV DI,[DEVCALL.REQSTAT]\r
+ TEST DI,STERR\r
+ JZ CWRTROK\r
+ invoke CHARHARD\r
+ MOV BX,DX ; Recall transfer addr\r
+ CMP AL,1\r
+ JZ DVWRTRAW ; Try again\r
+CWRTROK:\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ MOV AX,[CALLSCNT] ; Get actual number of bytes transferred\r
+ENDWRDEV:\r
+ LES DI,[THISFCB]\r
+ XOR DX,DX\r
+ DIV ES:[DI.fcb_RECSIZ]\r
+ MOV CX,AX ; Partial record is ignored\r
+ call ADDREC\r
+ return\r
+\r
+ASSUME DS:DOSGROUP\r
+WRTDEV:\r
+ OR BL,40H ; Reset EOF for input\r
+ XOR AX,AX\r
+ JCXZ ENDWRDEV ; problem of creating on a device.\r
+ PUSH DS\r
+ MOV AL,BL\r
+ LDS BX,[DMAADD]\r
+ASSUME DS:NOTHING\r
+ MOV DI,BX\r
+ XOR DX,DX ; Set starting point\r
+ TEST AL,020H ; Raw?\r
+ JNZ DVWRTRAW\r
+ TEST AL,ISCOUT ; Console output device?\r
+ JNZ WRITECON\r
+ TEST AL,ISNULL\r
+ JNZ WRTNUL\r
+ MOV AX,DX\r
+ CMP BYTE PTR [BX],1AH ; ^Z?\r
+ JZ WRTCOOKDONE ; Yes, transfer nothing\r
+ PUSH CX\r
+ MOV CX,1\r
+ invoke SETWRITE\r
+ POP CX\r
+ LDS SI,[THISFCB]\r
+ LDS SI,DWORD PTR [SI.fcb_FIRCLUS]\r
+DVWRTLP:\r
+ invoke DSKSTATCHK\r
+ invoke DEVIOCALL2\r
+ PUSH DI\r
+ MOV AH,87H\r
+ MOV DI,[DEVCALL.REQSTAT]\r
+ TEST DI,STERR\r
+ JZ CWROK\r
+ invoke CHARHARD\r
+ POP DI\r
+ MOV [CALLSCNT],1\r
+ CMP AL,1\r
+ JZ DVWRTLP\r
+ JMP SHORT DVWRTIGN\r
+CWROK:\r
+ POP DI\r
+ CMP [CALLSCNT],0\r
+ JZ WRTCOOKDONE\r
+DVWRTIGN:\r
+ INC DX\r
+ INC WORD PTR [CALLXAD]\r
+ INC DI\r
+ PUSH DS\r
+ MOV DS,WORD PTR [CALLXAD+2]\r
+ CMP BYTE PTR [DI],1AH ; ^Z?\r
+ POP DS\r
+ JZ WRTCOOKDONE\r
+ MOV [DEVCALL.REQSTAT],0\r
+ LOOP DVWRTLP\r
+WRTCOOKDONE:\r
+ MOV AX,DX\r
+ POP DS\r
+ JMP ENDWRDEV\r
+\r
+WRTNUL:\r
+ MOV DX,CX ;Entire transfer done\r
+ JMP WRTCOOKDONE\r
+\r
+STORE ENDP\r
+\r
+ procedure get_io_fcb,near\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+; Convert JFN number in BX to FCB in DS:SI\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ PUSH ES\r
+ PUSH DI\r
+ invoke get_sf_from_jfn\r
+ JC RET44P\r
+ MOV SI,DI\r
+ ADD SI,sf_fcb\r
+ PUSH ES\r
+ POP DS\r
+ASSUME DS:NOTHING\r
+RET44P:\r
+ POP DI\r
+ POP ES\r
+ return\r
+get_io_fcb ENDP\r
+\r
+SUBTTL GETTHISDRV -- FIND CURRENT DRIVE\r
+PAGE\r
+; Input: AL has drive identifier (1=A, 0=default)\r
+; Output: AL has physical drive (0=A)\r
+; Carry set if invalid drive (and AL is garbage anyway)\r
+ procedure GetThisDrv,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+ CMP BYTE PTR [NUMIO],AL\r
+ retc\r
+ DEC AL\r
+ JNS PHYDRV\r
+ MOV AL,[CURDRV]\r
+PHYDRV:\r
+ MOV BYTE PTR [THISDRV],AL\r
+ return\r
+GetThisDrv ENDP\r
+\r
+SUBTTL DIRREAD -- READ A DIRECTORY SECTOR\r
+PAGE\r
+ procedure DirRead,NEAR\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+; Inputs:\r
+; AX = Directory block number (relative to first block of directory)\r
+; ES:BP = Base of drive parameters\r
+; [DIRSEC] = First sector of first cluster of directory\r
+; [CLUSNUM] = Next cluster\r
+; [CLUSFAC] = Sectors/Cluster\r
+; Function:\r
+; Read the directory block into [CURBUF].\r
+; Outputs:\r
+; [NXTCLUSNUM] = Next cluster (after the one skipped to)\r
+; [SECCLUSPOS] Set\r
+; ES:BP unchanged [CURBUF] Points to Buffer with dir sector\r
+; All other registers destroyed.\r
+\r
+ MOV CL,[CLUSFAC]\r
+ DIV CL ; AL # clusters to skip, AH position in cluster\r
+ MOV [SECCLUSPOS],AH\r
+ MOV CL,AL\r
+ XOR CH,CH\r
+ MOV DX,[DIRSEC]\r
+ ADD DL,AH\r
+ ADC DH,0\r
+ MOV BX,[CLUSNUM]\r
+ MOV [NXTCLUSNUM],BX\r
+ JCXZ FIRSTCLUSTER\r
+SKPCLLP:\r
+ invoke UNPACK\r
+ XCHG BX,DI\r
+ CMP BX,0FF8H\r
+ JAE HAVESKIPPED\r
+ LOOP SKPCLLP\r
+HAVESKIPPED:\r
+ MOV [NXTCLUSNUM],BX\r
+ MOV DX,DI\r
+ MOV BL,AH\r
+ invoke FIGREC\r
+ entry FIRSTCLUSTER\r
+ XOR AL,AL ; Indicate pre-read\r
+ MOV AH,DIRPRI\r
+ invoke GETBUFFR\r
+ ret\r
+DirRead ENDP\r
+\r
+SUBTTL FATSECRD -- READ A FAT SECTOR\r
+PAGE\r
+ procedure FATSecRd,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; Same as DREAD\r
+; DS:BX = Transfer address\r
+; CX = Number of sectors\r
+; DX = Absolute record number\r
+; ES:BP = Base of drive parameters\r
+; Function:\r
+; Calls BIOS to perform FAT read.\r
+; Outputs:\r
+; Same as DREAD\r
+\r
+ MOV DI,CX\r
+ MOV CL,ES:[BP.dpb_FAT_count]\r
+ MOV AL,ES:[BP.dpb_FAT_size]\r
+ XOR AH,AH\r
+ MOV CH,AH\r
+ PUSH DX\r
+NXTFAT:\r
+ PUSH CX\r
+ PUSH AX\r
+ MOV CX,DI\r
+ CALL DSKREAD\r
+ POP AX\r
+ POP CX\r
+ JZ RET41P\r
+ ADD DX,AX\r
+ LOOP NXTFAT\r
+ POP DX\r
+ MOV CX,DI\r
+\r
+; NOTE FALL THROUGH\r
+\r
+SUBTTL DREAD -- DO A DISK READ\r
+PAGE\r
+ entry DREAD\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DS:BX = Transfer address\r
+; CX = Number of sectors\r
+; DX = Absolute record number\r
+; ES:BP = Base of drive parameters\r
+; Function:\r
+; Calls BIOS to perform disk read. If BIOS reports\r
+; errors, will call HARDERR for further action.\r
+; DS,ES:BP preserved. All other registers destroyed.\r
+\r
+ CALL DSKREAD\r
+ retz\r
+ MOV BYTE PTR [READOP],0\r
+ invoke HARDERR\r
+ CMP AL,1 ; Check for retry\r
+ JZ DREAD\r
+ return ; Ignore otherwise\r
+RET41P: POP DX\r
+ return\r
+FATSecRd ENDP\r
+\r
+SUBTTL DSKREAD -- PHYSICAL DISK READ\r
+PAGE\r
+ procedure DskRead,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DS:BX = Transfer addr\r
+; CX = Number of sectors\r
+; DX = Absolute record number\r
+; ES:BP = Base of drive parameters\r
+; Function:\r
+; Call BIOS to perform disk read\r
+; Outputs:\r
+; DI = CX on entry\r
+; CX = Number of sectors unsuccessfully transfered\r
+; AX = Status word as returned by BIOS (error code in AL if error)\r
+; Zero set if OK (from BIOS)\r
+; Zero clear if error\r
+; SI Destroyed, others preserved\r
+\r
+ PUSH CX\r
+ MOV AH,ES:[BP.dpb_media]\r
+ MOV AL,ES:[BP.dpb_UNIT]\r
+ PUSH BX\r
+ PUSH ES\r
+ invoke SETREAD\r
+ JMP DODSKOP\r
+\r
+SUBTTL DWRITE -- SEE ABOUT WRITING\r
+PAGE\r
+ entry DWRITE\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DS:BX = Transfer address\r
+; CX = Number of sectors\r
+; DX = Absolute record number\r
+; ES:BP = Base of drive parameters\r
+; Function:\r
+; Calls BIOS to perform disk write. If BIOS reports\r
+; errors, will call HARDERR for further action.\r
+; BP preserved. All other registers destroyed.\r
+\r
+ CALL DSKWRITE\r
+ retz\r
+ MOV BYTE PTR [READOP],1\r
+ invoke HARDERR\r
+ CMP AL,1 ; Check for retry\r
+ JZ DWRITE\r
+ return\r
+\r
+SUBTTL DSKWRITE -- PHYSICAL DISK WRITE\r
+PAGE\r
+ entry DSKWRITE\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DS:BX = Transfer addr\r
+; CX = Number of sectors\r
+; DX = Absolute record number\r
+; ES:BP = Base of drive parameters\r
+; Function:\r
+; Call BIOS to perform disk read\r
+; Outputs:\r
+; DI = CX on entry\r
+; CX = Number of sectors unsuccessfully transfered\r
+; AX = Status word as returned by BIOS (error code in AL if error)\r
+; Zero set if OK (from BIOS)\r
+; Zero clear if error\r
+; SI Destroyed, others preserved\r
+\r
+ PUSH CX\r
+ MOV AH,ES:[BP.dpb_media]\r
+ MOV AL,ES:[BP.dpb_UNIT]\r
+ PUSH BX\r
+ PUSH ES\r
+ invoke SETWRITE\r
+DODSKOP:\r
+ MOV CX,DS ; Save DS\r
+ POP DS ; DS:BP points to DPB\r
+ PUSH DS\r
+ LDS SI,DS:[BP.dpb_driver_addr]\r
+ invoke DEVIOCALL2\r
+ MOV DS,CX ; Restore DS\r
+ POP ES ; Restore ES\r
+ POP BX\r
+ MOV CX,[CALLSCNT] ; Number of sectors transferred\r
+ POP DI\r
+ SUB CX,DI\r
+ NEG CX ; Number of sectors not transferred\r
+ MOV AX,[DEVCALL.REQSTAT]\r
+ TEST AX,STERR\r
+ return\r
+DskRead ENDP\r
+\r
+SUBTTL SETUP -- SETUP A DISK READ OR WRITE FROM USER\r
+PAGE\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+ procedure SETUP,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DS:DI point to FCB\r
+; DX:AX = Record position in file of disk transfer\r
+; CX = Record count\r
+; Outputs:\r
+; DS = DOSGROUP\r
+; BL = fcb_DEVID from FCB\r
+; CX = No. of bytes to transfer (0 = 64K)\r
+; [THISDPB] = Base of drive parameters\r
+; [RECCNT] = Record count\r
+; [RECPOS] = Record position in file\r
+; ES:DI Points to FCB\r
+; [THISFCB] = ES:DI\r
+; [NEXTADD] = Displacement of disk transfer within segment\r
+; [SECPOS] = Position of first sector\r
+; [BYTPOS] = Byte position in file\r
+; [BYTSECPOS] = Byte position in first sector\r
+; [CLUSNUM] = First cluster\r
+; [SECCLUSPOS] = Sector within first cluster\r
+; [DSKERR] = 0 (no errors yet)\r
+; [TRANS] = 0 (No transfers yet)\r
+; [THISDRV] = Physical drive unit number\r
+\r
+ PUSH AX\r
+ MOV AL,[DI]\r
+ DEC AL\r
+ MOV BYTE PTR [THISDRV],AL\r
+ MOV AL,[DI.fcb_DEVID]\r
+ MOV SI,[DI.fcb_RECSIZ]\r
+ OR SI,SI\r
+ JNZ HAVRECSIZ\r
+ MOV SI,128\r
+ MOV [DI.fcb_RECSIZ],SI\r
+HAVRECSIZ:\r
+ MOV WORD PTR [THISFCB+2],DS\r
+ PUSH SS\r
+ POP DS ; Set DS to DOSGROUP\r
+ASSUME DS:DOSGROUP\r
+ MOV WORD PTR [THISFCB],DI\r
+ OR AL,AL ; Is it a device?\r
+ JNS NOTDEVICE\r
+ XOR AL,AL ; Fake in drive 0 so we can get BP\r
+NOTDEVICE:\r
+ invoke GETBP\r
+ POP AX\r
+ JNC CheckRecLen\r
+ XOR CX,CX\r
+ MOV BYTE PTR [DSKERR],4\r
+ POP BX\r
+ return\r
+\r
+CheckRecLen:\r
+ CMP SI,64 ; Check if highest byte of RECPOS is significant\r
+ JB SMALREC\r
+ XOR DH,DH ; Ignore MSB if record >= 64 bytes\r
+SMALREC:\r
+ MOV [RECCNT],CX\r
+ MOV WORD PTR [RECPOS],AX\r
+ MOV WORD PTR [RECPOS+2],DX\r
+ MOV BX,WORD PTR [DMAADD]\r
+ MOV [NEXTADD],BX\r
+ MOV BYTE PTR [DSKERR],0\r
+ MOV BYTE PTR [TRANS],0\r
+ MOV BX,DX\r
+ MUL SI\r
+ MOV WORD PTR [BYTPOS],AX\r
+ PUSH DX\r
+ MOV AX,BX\r
+ MUL SI\r
+ POP BX\r
+ ADD AX,BX\r
+ ADC DX,0 ; Ripple carry\r
+ JNZ EOFERR\r
+ MOV WORD PTR [BYTPOS+2],AX\r
+ MOV DX,AX\r
+ MOV AX,WORD PTR [BYTPOS]\r
+ MOV BX,ES:[BP.dpb_sector_size]\r
+ CMP DX,BX ; See if divide will overflow\r
+ JNC EOFERR\r
+ DIV BX\r
+ MOV [SECPOS],AX\r
+ MOV [BYTSECPOS],DX\r
+ MOV DX,AX\r
+ AND AL,ES:[BP.dpb_cluster_mask]\r
+ MOV [SECCLUSPOS],AL\r
+ MOV AX,CX ; Record count\r
+ MOV CL,ES:[BP.dpb_cluster_shift]\r
+ SHR DX,CL\r
+ MOV [CLUSNUM],DX\r
+ MUL SI ; Multiply by bytes per record\r
+ MOV CX,AX\r
+ ADD AX,WORD PTR [DMAADD] ; See if it will fit in one segment\r
+ ADC DX,0\r
+ JZ OK ; Must be less than 64K\r
+ MOV AX,WORD PTR [DMAADD]\r
+ NEG AX ; Amount of room left in segment\r
+ JNZ PARTSEG\r
+ DEC AX\r
+PARTSEG:\r
+ XOR DX,DX\r
+ DIV SI ; How many records will fit?\r
+ MOV [RECCNT],AX\r
+ MUL SI ; Translate that back into bytes\r
+ MOV BYTE PTR [DSKERR],2 ; Flag that trimming took place\r
+ MOV CX,AX\r
+ JCXZ NOROOM\r
+OK:\r
+ LES DI,[THISFCB]\r
+ MOV BL,ES:[DI.fcb_DEVID]\r
+ return\r
+\r
+EOFERR:\r
+ MOV BYTE PTR [DSKERR],1\r
+ XOR CX,CX\r
+NOROOM:\r
+ LES DI,[THISFCB]\r
+ POP BX ; Kill return address\r
+ return\r
+SETUP ENDP\r
+\r
+SUBTTL BREAKDOWN -- CUT A USER READ OR WRITE INTO PIECES\r
+PAGE\r
+ procedure BREAKDOWN,near\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+; Inputs:\r
+; CX = Length of disk transfer in bytes\r
+; ES:BP = Base of drive parameters\r
+; [BYTSECPOS] = Byte position witin first sector\r
+; Outputs:\r
+; [BYTCNT1] = Bytes to transfer in first sector\r
+; [SECCNT] = No. of whole sectors to transfer\r
+; [BYTCNT2] = Bytes to transfer in last sector\r
+; AX, BX, DX destroyed. No other registers affected.\r
+\r
+ MOV AX,[BYTSECPOS]\r
+ MOV BX,CX\r
+ OR AX,AX\r
+ JZ SAVFIR ; Partial first sector?\r
+ SUB AX,ES:[BP.dpb_sector_size]\r
+ NEG AX ; Max number of bytes left in first sector\r
+ SUB BX,AX ; Subtract from total length\r
+ JAE SAVFIR\r
+ ADD AX,BX ; Don't use all of the rest of the sector\r
+ XOR BX,BX ; And no bytes are left\r
+SAVFIR:\r
+ MOV [BYTCNT1],AX\r
+ MOV AX,BX\r
+ XOR DX,DX\r
+ DIV ES:[BP.dpb_sector_size] ; How many whole sectors?\r
+ MOV [SECCNT],AX\r
+ MOV [BYTCNT2],DX ; Bytes remaining for last sector\r
+ OR DX,[BYTCNT1]\r
+ retnz ; NOT (BYTCNT1 = BYTCNT2 = 0)\r
+ CMP AX,1\r
+ retnz\r
+ MOV AX,ES:[BP.dpb_sector_size] ; Buffer EXACT one sector I/O\r
+ MOV [BYTCNT2],AX\r
+ MOV [SECCNT],DX ; DX = 0\r
+ return\r
+BreakDown ENDP\r
+\r
+SUBTTL DISKREAD -- PERFORM USER DISK READ\r
+PAGE\r
+ procedure DISKREAD,NEAR\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+; Inputs:\r
+; Outputs of SETUP\r
+; Function:\r
+; Perform disk read\r
+; Outputs:\r
+; DX:AX = Position of last record read\r
+; CX = No. of records read\r
+; ES:DI point to FCB\r
+; fcb_LSTCLUS, fcb_CLUSPOS fields in FCB set\r
+\r
+ MOV AX,ES:WORD PTR [DI.fcb_FILSIZ]\r
+ MOV BX,ES:WORD PTR [DI.fcb_FILSIZ+2]\r
+ SUB AX,WORD PTR [BYTPOS]\r
+ SBB BX,WORD PTR [BYTPOS+2]\r
+ JB RDERR\r
+ JNZ ENUF\r
+ OR AX,AX\r
+ JZ RDERR\r
+ CMP AX,CX\r
+ JAE ENUF\r
+ MOV CX,AX\r
+ENUF:\r
+ LES BP,[THISDPB]\r
+ CALL BREAKDOWN\r
+ MOV CX,[CLUSNUM]\r
+ invoke FNDCLUS\r
+ OR CX,CX\r
+ JZ SHORT SKIPERR\r
+RDERR:\r
+ JMP WRTERR\r
+RDLASTJ:JMP RDLAST\r
+SETFCBJ2: JMP SETFCB\r
+\r
+SKIPERR:\r
+\r
+ MOV [LASTPOS],DX\r
+ MOV [CLUSNUM],BX\r
+ CMP [BYTCNT1],0\r
+ JZ RDMID\r
+ invoke BUFRD\r
+RDMID:\r
+ CMP [SECCNT],0\r
+ JZ RDLASTJ\r
+ invoke NEXTSEC\r
+ JC SETFCBJ2\r
+ MOV BYTE PTR [TRANS],1 ; A transfer is taking place\r
+ONSEC:\r
+ MOV DL,[SECCLUSPOS]\r
+ MOV CX,[SECCNT]\r
+ MOV BX,[CLUSNUM]\r
+RDLP:\r
+ invoke OPTIMIZE\r
+ PUSH DI\r
+ PUSH AX\r
+ PUSH BX\r
+ MOV DS,WORD PTR [DMAADD+2]\r
+ASSUME DS:NOTHING\r
+ PUSH DX\r
+ PUSH CX\r
+ CALL DREAD\r
+ POP BX\r
+ POP DX\r
+ ADD BX,DX ; Upper bound of read\r
+ MOV AL,ES:[BP.dpb_drive]\r
+ invoke SETVISIT\r
+NXTBUF: ; Must see if one of these sectors is buffered\r
+ MOV [DI.VISIT],1 ; Mark as visited\r
+ CMP AL,[DI.BUFDRV]\r
+ JNZ DONXTBUF ; Not for this drive\r
+ CMP [DI.BUFSECNO],DX\r
+ JC DONXTBUF ; Below first sector\r
+ CMP [DI.BUFSECNO],BX\r
+ JNC DONXTBUF ; Above last sector\r
+ CMP BYTE PTR [DI.BUFDIRTY],0\r
+ JZ CLBUFF ; Buffer is clean, so OK\r
+; A sector has been read in when a dirty copy of it is in a buffer\r
+; The buffered sector must now be read into the right place\r
+ POP AX ; Recall transfer address\r
+ PUSH AX\r
+ PUSH DI ; Save search environment\r
+ PUSH DX\r
+ SUB DX,[DI.BUFSECNO] ; How far into transfer?\r
+ NEG DX\r
+ MOV SI,DI\r
+ MOV DI,AX\r
+ MOV AX,DX\r
+ MOV CX,ES:[BP.dpb_sector_size]\r
+ MUL CX\r
+ ADD DI,AX ; Put the buffer here\r
+ ADD SI,BUFINSIZ\r
+ SHR CX,1\r
+ PUSH ES\r
+ MOV ES,WORD PTR [DMAADD+2]\r
+ REP MOVSW\r
+ JNC EVENMOV\r
+ MOVSB\r
+EVENMOV:\r
+ POP ES\r
+ POP DX\r
+ POP DI\r
+ MOV AL,ES:[BP.dpb_drive]\r
+CLBUFF:\r
+ invoke SCANPLACE\r
+DONXTBUF:\r
+ invoke SKIPVISIT\r
+ JNZ NXTBUF\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ POP CX\r
+ POP CX\r
+ POP BX\r
+ JCXZ RDLAST\r
+ CMP BX,0FF8H\r
+ JAE SETFCB\r
+ MOV DL,0\r
+ INC [LASTPOS] ; We'll be using next cluster\r
+ JMP RDLP\r
+\r
+RDLAST:\r
+ MOV AX,[BYTCNT2]\r
+ OR AX,AX\r
+ JZ SETFCB\r
+ MOV [BYTCNT1],AX\r
+ invoke NEXTSEC\r
+ JC SETFCB\r
+ MOV [BYTSECPOS],0\r
+ invoke BUFRD\r
+\r
+ entry SETFCB\r
+ LES SI,[THISFCB]\r
+ MOV AX,[NEXTADD]\r
+ MOV DI,AX\r
+ SUB AX,WORD PTR [DMAADD] ; Number of bytes transfered\r
+ XOR DX,DX\r
+ MOV CX,ES:[SI.fcb_RECSIZ]\r
+ DIV CX ; Number of records\r
+ CMP AX,[RECCNT] ; Check if all records transferred\r
+ JZ FULLREC\r
+ MOV BYTE PTR [DSKERR],1\r
+ OR DX,DX\r
+ JZ FULLREC ; If remainder 0, then full record transfered\r
+ MOV BYTE PTR [DSKERR],3 ; Flag partial last record\r
+ SUB CX,DX ; Bytes left in last record\r
+ PUSH ES\r
+ MOV ES,WORD PTR [DMAADD+2]\r
+ XCHG AX,BX ; Save the record count temporarily\r
+ XOR AX,AX ; Fill with zeros\r
+ SHR CX,1\r
+ JNC EVENFIL\r
+ STOSB\r
+EVENFIL:\r
+ REP STOSW\r
+ XCHG AX,BX ; Restore record count to AX\r
+ POP ES\r
+ INC AX ; Add last (partial) record to total\r
+FULLREC:\r
+ MOV CX,AX\r
+ MOV DI,SI ; ES:DI point to FCB\r
+SETCLUS:\r
+ TEST ES:[DI].fcb_DEVID,-1\r
+ JS ADDREC ; don't set clisters if device\r
+ MOV AX,[CLUSNUM]\r
+ AND ES:[DI.fcb_LSTCLUS],0F000h ; fcb_lstclus is packed with dir clus\r
+ OR ES:[DI.fcb_LSTCLUS],AX ; drop in the correct part of fcb_lstclus\r
+ MOV AX,[LASTPOS]\r
+ MOV ES:[DI.fcb_CLUSPOS],AX\r
+ entry AddRec\r
+ MOV AX,WORD PTR [RECPOS]\r
+ MOV DX,WORD PTR [RECPOS+2]\r
+ JCXZ RET28 ; If no records read, don't change position\r
+ DEC CX\r
+ ADD AX,CX ; Update current record position\r
+ ADC DX,0\r
+ INC CX\r
+RET28: return\r
+DISKREAD ENDP\r
+\r
+SUBTTL DISKWRITE -- PERFORM USER DISK WRITE\r
+PAGE\r
+ procedure DISKWRITE,NEAR\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+; Inputs:\r
+; Outputs of SETUP\r
+; Function:\r
+; Perform disk write\r
+; Outputs:\r
+; DX:AX = Position of last record written\r
+; CX = No. of records written\r
+; ES:DI point to FCB\r
+; fcb_LSTCLUS, fcb_CLUSPOS fields in FCB set\r
+\r
+ AND BL,3FH ; Mark file as dirty\r
+ MOV ES:[DI.fcb_DEVID],BL\r
+ LES BP,[THISDPB]\r
+ CALL BREAKDOWN\r
+ MOV AX,WORD PTR [BYTPOS]\r
+ MOV DX,WORD PTR [BYTPOS+2]\r
+ JCXZ WRTEOFJ\r
+ ADD AX,CX\r
+ ADC DX,0 ; AX:DX=last byte accessed\r
+ DIV ES:[BP.dpb_sector_size] ; AX=last sector accessed\r
+ MOV BX,AX ; Save last full sector\r
+ OR DX,DX\r
+ JNZ CALCLUS\r
+ DEC AX ; AX must be zero base indexed\r
+CALCLUS:\r
+ MOV CL,ES:[BP.dpb_cluster_shift]\r
+ SHR AX,CL ; Last cluster to be accessed\r
+ PUSH AX\r
+ PUSH DX ; Save the size of the "tail"\r
+ PUSH ES\r
+ LES DI,[THISFCB]\r
+ MOV AX,ES:WORD PTR [DI.fcb_FILSIZ]\r
+ MOV DX,ES:WORD PTR [DI.fcb_FILSIZ+2]\r
+ POP ES\r
+ DIV ES:[BP.dpb_sector_size]\r
+ MOV CX,AX ; Save last full sector of current file\r
+ OR DX,DX\r
+ JZ NORNDUP\r
+ INC AX ; Round up if any remainder\r
+NORNDUP:\r
+ MOV [VALSEC],AX ; Number of sectors that have been written\r
+ XOR AX,AX\r
+ MOV WORD PTR [GROWCNT],AX\r
+ MOV WORD PTR [GROWCNT+2],AX\r
+ POP AX\r
+ SUB BX,CX ; Number of full sectors\r
+ JB NOGROW\r
+ JZ TESTTAIL\r
+ MOV CX,DX\r
+ XCHG AX,BX\r
+ MUL ES:[BP.dpb_sector_size] ; Bytes of full sector growth\r
+ SUB AX,CX ; Take off current "tail"\r
+ SBB DX,0 ; 32-bit extension\r
+ ADD AX,BX ; Add on new "tail"\r
+ ADC DX,0 ; ripple tim's head off\r
+ JMP SHORT SETGRW\r
+\r
+HAVSTART:\r
+ MOV CX,AX\r
+ invoke SKPCLP\r
+ JCXZ DOWRTJ\r
+ invoke ALLOCATE\r
+ JNC DOWRTJ\r
+WRTERR:\r
+ XOR CX,CX\r
+ MOV BYTE PTR [DSKERR],1\r
+ MOV AX,WORD PTR [RECPOS]\r
+ MOV DX,WORD PTR [RECPOS+2]\r
+ LES DI,[THISFCB]\r
+ return\r
+\r
+DOWRTJ: JMP DOWRT\r
+\r
+WRTEOFJ:\r
+ JMP WRTEOF\r
+\r
+TESTTAIL:\r
+ SUB AX,DX\r
+ JBE NOGROW\r
+ XOR DX,DX\r
+SETGRW:\r
+ MOV WORD PTR [GROWCNT],AX\r
+ MOV WORD PTR [GROWCNT+2],DX\r
+NOGROW:\r
+ POP AX\r
+ MOV CX,[CLUSNUM] ; First cluster accessed\r
+ invoke FNDCLUS\r
+ MOV [CLUSNUM],BX\r
+ MOV [LASTPOS],DX\r
+ SUB AX,DX ; Last cluster minus current cluster\r
+ JZ DOWRT ; If we have last clus, we must have first\r
+ JCXZ HAVSTART ; See if no more data\r
+ PUSH CX ; No. of clusters short of first\r
+ MOV CX,AX\r
+ invoke ALLOCATE\r
+ POP AX\r
+ JC WRTERR\r
+ MOV CX,AX\r
+ MOV DX,[LASTPOS]\r
+ INC DX\r
+ DEC CX\r
+ JZ NOSKIP\r
+ invoke SKPCLP\r
+NOSKIP:\r
+ MOV [CLUSNUM],BX\r
+ MOV [LASTPOS],DX\r
+DOWRT:\r
+ CMP [BYTCNT1],0\r
+ JZ WRTMID\r
+ MOV BX,[CLUSNUM]\r
+ invoke BUFWRT\r
+WRTMID:\r
+ MOV AX,[SECCNT]\r
+ OR AX,AX\r
+ JZ WRTLAST\r
+ ADD [SECPOS],AX\r
+ invoke NEXTSEC\r
+ MOV BYTE PTR [TRANS],1 ; A transfer is taking place\r
+ MOV DL,[SECCLUSPOS]\r
+ MOV BX,[CLUSNUM]\r
+ MOV CX,[SECCNT]\r
+WRTLP:\r
+ invoke OPTIMIZE\r
+ PUSH DI\r
+ PUSH AX\r
+ PUSH DX\r
+ PUSH BX\r
+ MOV AL,ES:[BP.dpb_drive]\r
+ MOV BX,CX\r
+ ADD BX,DX ; Upper bound of write\r
+ invoke SETVISIT\r
+ASSUME DS:NOTHING\r
+NEXTBUFF: ; Search for buffers\r
+ MOV [DI.VISIT],1 ; Mark as visited\r
+ CMP AL,[DI.BUFDRV]\r
+ JNZ DONEXTBUFF ; Not for this drive\r
+ CMP [DI.BUFSECNO],DX\r
+ JC DONEXTBUFF ; Buffer is not in range of write\r
+ CMP [DI.BUFSECNO],BX\r
+ JNC DONEXTBUFF ; Buffer is not in range of write\r
+ MOV WORD PTR [DI.BUFDRV],00FFH ; Free the buffer, it is being over written\r
+ invoke SCANPLACE\r
+DONEXTBUFF:\r
+ invoke SKIPVISIT\r
+ JNZ NEXTBUFF\r
+ POP BX\r
+ POP DX\r
+ MOV DS,WORD PTR [DMAADD+2]\r
+ CALL DWRITE\r
+ POP CX\r
+ POP BX\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ JCXZ WRTLAST\r
+ MOV DL,0\r
+ INC [LASTPOS] ; We'll be using next cluster\r
+ JMP SHORT WRTLP\r
+\r
+WRTERRJ: JMP WRTERR\r
+\r
+WRTLAST:\r
+ MOV AX,[BYTCNT2]\r
+ OR AX,AX\r
+ JZ FINWRT\r
+ MOV [BYTCNT1],AX\r
+ invoke NEXTSEC\r
+ MOV [BYTSECPOS],0\r
+ invoke BUFWRT\r
+FINWRT:\r
+ LES DI,[THISFCB]\r
+ MOV AX,WORD PTR [GROWCNT]\r
+ MOV CX,WORD PTR [GROWCNT+2]\r
+ OR AX,AX\r
+ JNZ UPDATE_size\r
+ OR CX,CX\r
+ JZ SAMSIZ\r
+Update_size:\r
+ ADD WORD PTR ES:[DI.fcb_FILSIZ],AX\r
+ ADC WORD PTR ES:[DI.fcb_FILSIZ+2],CX\r
+SAMSIZ:\r
+ MOV CX,[RECCNT]\r
+ JMP SETCLUS\r
+\r
+WRTEOF:\r
+ MOV CX,AX\r
+ OR CX,DX\r
+ JZ KILLFIL\r
+ SUB AX,1\r
+ SBB DX,0\r
+ DIV ES:[BP.dpb_sector_size]\r
+ MOV CL,ES:[BP.dpb_cluster_shift]\r
+ SHR AX,CL\r
+ MOV CX,AX\r
+ invoke FNDCLUS\r
+ JCXZ RELFILE\r
+ invoke ALLOCATE\r
+ JC WRTERRJ\r
+UPDATE:\r
+ LES DI,[THISFCB]\r
+ MOV AX,WORD PTR [BYTPOS]\r
+ MOV ES:WORD PTR [DI.fcb_FILSIZ],AX\r
+ MOV AX,WORD PTR [BYTPOS+2]\r
+ MOV ES:WORD PTR [DI.fcb_FILSIZ+2],AX\r
+ XOR CX,CX\r
+ JMP ADDREC\r
+\r
+RELFILE:\r
+ MOV DX,0FFFH\r
+ invoke RELBLKS\r
+ JMP SHORT UPDATE\r
+\r
+KILLFIL:\r
+ XOR BX,BX\r
+ PUSH ES\r
+ LES DI,[THISFCB]\r
+ MOV ES:[DI.fcb_CLUSPOS],BX\r
+ XCHG BX,ES:[DI.fcb_FIRCLUS]\r
+ AND ES:[DI.fcb_LSTCLUS],0F000H\r
+ POP ES\r
+ OR BX,BX\r
+ JZ UPDATE\r
+ invoke RELEASE\r
+ JMP SHORT UPDATE\r
+DISKWRITE ENDP\r
+do_ext\r
+\r
+CODE ENDS\r
+ END\r
+\0\0\0\0\0\0\0\0\0\0\0\0\r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+msdos mscode dosmes misc getset dircall alloc dev dir +
+disk fat rom stdbuf stdcall stdctrlc stdfcb stdproc +
+stdio time xenix xenix2;
+
+\1a
\ No newline at end of file
--- /dev/null
+;
+; 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
--- /dev/null
+ INCLUDE STDSW.ASM\r
+\r
+KANJI EQU FALSE\r
+\r
+Rainbow EQU FALSE\r
+\r
+ INCLUDE DOSSYM.ASM\r
+;\r
+; segment ordering for MSDOS\r
+;\r
+\r
+CONSTANTS SEGMENT BYTE PUBLIC 'CONST'\r
+CONSTANTS ENDS\r
+\r
+DATA SEGMENT BYTE PUBLIC 'DATA'\r
+DATA ENDS\r
+\r
+CODE SEGMENT BYTE PUBLIC 'CODE'\r
+CODE ENDS\r
+\r
+LAST SEGMENT BYTE PUBLIC 'LAST'\r
+LAST ENDS\r
+\r
+DOSGROUP GROUP CODE,CONSTANTS,DATA,LAST\r
+\r
+CONSTANTS SEGMENT BYTE PUBLIC 'CONST'\r
+\r
+ PUBLIC DIVMES\r
+DIVMES DB 13,10,"Divide overflow",13,10\r
+\r
+ PUBLIC DivMesLen\r
+DivMesLen DB $-DivMes ; Length of the above message in bytes\r
+\r
+\r
+;\r
+; The next variable points to the country table for the current country\r
+; ( the table returned by the AL=0 INTERNATIONAL call).\r
+;\r
+ PUBLIC Current_Country\r
+\r
+ IF KANJI\r
+Current_Country DW OFFSET DOSGROUP:JAPTABLE\r
+ ELSE\r
+Current_Country DW OFFSET DOSGROUP:USTABLE\r
+ ENDIF\r
+\r
+;\r
+; The international tabel(s).\r
+; This is simply a sequence of tables of the following form:\r
+;\r
+; BYTE Size of this table excluding this byte and the next\r
+; BYTE Country code represented by this table\r
+; A sequence of n bytes, where n is the number specified\r
+; by the first byte above and is not > internat_block_max,\r
+; in the correct order for being returned by the\r
+; INTERNATIONAL call as follows:\r
+; WORD Date format 0=mdy, 1=dmy, 2=ymd\r
+; 5 BYTE Currency symbol null terminated\r
+; 2 BYTE thousands separator null terminated\r
+; 2 BYTE Decimal point null terminated\r
+; 2 BYTE Date separator null terminated\r
+; 2 BYTE Time separator null terminated\r
+; 1 BYTE Bit field. Currency format.\r
+; Bit 0. =0 $ before # =1 $ after #\r
+; Bit 1. no. of spaces between # and $ (0 or 1)\r
+; 1 BYTE No. of significant decimal digits in currency\r
+; 1 BYTE Bit field. Time format.\r
+; Bit 0. =0 12 hour clock =1 24 hour\r
+; WORD Segment offset for address of case conversion routine\r
+; WORD RESERVED. Filled in by DOS. Segment value for above routine\r
+; 2 BYTE Data list separator null terminated.\r
+; NOTE: The segment part of the DWORD Map_call is set\r
+; by the INTERNATIONAL call. Do not try to initialize\r
+; it to anything meaningful.\r
+;\r
+; The list of tables is terminated by putting a byte of -1 after the last\r
+; table (a table with length -1).\r
+\r
+ PUBLIC international_table\r
+\r
+international_table LABEL BYTE\r
+\r
+ IF KANJI\r
+ DB SIZE internat_block ; Size in bytes of this table\r
+ DB 81 ; Country code\r
+JAPTABLE internat_block <2,'\',0,0,0,0,',',0,'.',0,'-',0,':',0,0,0,1,OFFSET DOSGROUP:MAP_DCASE , 0,',',0>\r
+ ENDIF\r
+\r
+ DB SIZE internat_block ; Size in bytes of this table\r
+ DB 1 ; Country code\r
+USTABLE internat_block <0,'$',0,0,0,0,',',0,'.',0,'-',0,':',0,0,2,0,OFFSET DOSGROUP:MAP_DCASE,0,',',0>\r
+; Tables for the IBM PC character set follow. The values\r
+; associated with some of the currency symbols may change with\r
+; other character sets. You may wish to add or delete country\r
+; entries. NOTE: It is not a mistake that the JAPANESE entry\r
+; has different currency symbols for the KANJI and\r
+; non-KANJI versions.\r
+\r
+IF NOT KANJI\r
+IF IBM\r
+ DB SIZE internat_block ; Size in bytes of this table\r
+ DB 44 ; Country code\r
+UKTABLE internat_block <1,9Ch,0,0,0,0,',',0,'.',0,'-',0,':',0,0,2,0,OFFSET DOSGROUP:MAP_DCASE,0,',',0>\r
+ DB SIZE internat_block ; Size in bytes of this table\r
+ DB 49 ; Country code\r
+GRMTABLE internat_block <1,'D','M',0,0,0,'.',0,',',0,'.',0,'.',0,3,2,1,OFFSET DOSGROUP:MAP_DCASE,0,';',0>\r
+ DB SIZE internat_block ; Size in bytes of this table\r
+ DB 33 ; Country code\r
+FRNTABLE internat_block <1,'F',0,0,0,0,' ',0,',',0,'/',0,':',0,3,2,1,OFFSET DOSGROUP:MAP_DCASE,0,';',0>\r
+ DB SIZE internat_block ; Size in bytes of this table\r
+ DB 81 ; Country code\r
+JAPTABLE internat_block <2,9DH,0,0,0,0,',',0,'.',0,'-',0,':',0,0,0,1,OFFSET DOSGROUP:MAP_DCASE , 0,',',0>\r
+ENDIF\r
+ENDIF\r
+ DB -1 ; End of tables\r
+\r
+CONSTANTS ENDS\r
+\r
+\r
+CODE SEGMENT BYTE PUBLIC 'CODE'\r
+ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING\r
+\r
+;CASE MAPPER ROUTINE FOR 80H-FFH character range\r
+; ENTRY: AL = Character to map\r
+; EXIT: AL = The converted character\r
+; Alters no registers except AL and flags.\r
+; The routine should do nothing to chars below 80H.\r
+;\r
+; Example:\r
+ MAP_DCASE PROC FAR\r
+IF NOT KANJI\r
+IF IBM\r
+ CMP AL,80H\r
+ JB L_RET ;Map no chars below 80H ever\r
+ CMP AL,0A7H\r
+ JA L_RET ;This routine maps chars between 80H and A7H\r
+ SUB AL,80H ;Turn into index value\r
+ PUSH DS\r
+ PUSH BX\r
+ PUSH CS ;Move to DS\r
+ POP DS\r
+ MOV BX,OFFSET DOSGROUP:TABLE\r
+ XLAT ;Get upper case character\r
+ POP BX\r
+ POP DS\r
+ENDIF\r
+ENDIF\r
+ L_RET: RET\r
+ MAP_DCASE ENDP\r
+IF NOT KANJI\r
+IF IBM\r
+TABLE: DB 80H,9AH,"E","A",8EH,"A",8FH,80H\r
+ DB "E","E","E","I","I","I",8EH,8FH\r
+ DB 90H,92H,92H,"O",99H,"O","U","U"\r
+ DB "Y",99H,9AH,9BH,9CH,9DH,9EH,9FH\r
+ DB "A","I","O","U",0A5H,0A5H,0A6H,0A7H\r
+ENDIF\r
+ENDIF\r
+\r
+SUBTTL EDIT FUNCTION ASSIGNMENTS AND HEADERS\r
+PAGE\r
+; The following two tables implement the current buffered input editing\r
+; routines. The tables are pairwise associated in reverse order for ease\r
+; in indexing. That is; The first entry in ESCTAB corresponds to the last\r
+; entry in ESCFUNC, and the last entry in ESCTAB to the first entry in ESCFUNC.\r
+\r
+\r
+ PUBLIC ESCCHAR\r
+ESCCHAR DB ESCCH ;Lead-in character for escape sequences\r
+ IF NOT Rainbow\r
+ESCTAB:\r
+ IF NOT IBM\r
+ IF WANG\r
+ DB 0C0h ; ^Z inserter\r
+ DB 0C1H ; Copy one char\r
+ DB 0C7H ; Skip one char\r
+ DB 08AH ; Copy to char\r
+ DB 088H ; Skip to char\r
+ DB 09AH ; Copy line\r
+ DB 0CBH ; Kill line (no change in template)\r
+ DB 08BH ; Reedit line (new template)\r
+ DB 0C3H ; Backspace\r
+ DB 0C6H ; Enter insert mode\r
+ IF NOT TOGLINS\r
+ DB 0D6H ; Exit insert mode\r
+ ENDIF\r
+ DB 0C6H ; Escape character\r
+ DB 0C6H ; End of table\r
+ ELSE\r
+ ; VT52 equivalences\r
+ DB "Z" ; ^Z inserter\r
+ DB "S" ; F1 Copy one char\r
+ DB "V" ; F4 Skip one char\r
+ DB "T" ; F2 Copy to char\r
+ DB "W" ; F5 Skip to char\r
+ DB "U" ; F3 Copy line\r
+ DB "E" ; SHIFT ERASE Kill line (no change in template)\r
+ DB "J" ; ERASE Reedit line (new template)\r
+ DB "D" ; LEFT Backspace\r
+ DB "P" ; BLUE Enter insert mode\r
+ DB "Q" ; RED Exit insert mode\r
+ DB "R" ; GRAY Escape character\r
+ DB "R" ; End of table\r
+ ENDIF\r
+ ENDIF\r
+ IF IBM\r
+ DB 64 ; Ctrl-Z - F6\r
+ DB 77 ; Copy one char - -->\r
+ DB 59 ; Copy one char - F1\r
+ DB 83 ; Skip one char - DEL\r
+ DB 60 ; Copy to char - F2\r
+ DB 62 ; Skip to char - F4\r
+ DB 61 ; Copy line - F3\r
+ DB 61 ; Kill line (no change to template ) - Not used\r
+ DB 63 ; Reedit line (new template) - F5\r
+ DB 75 ; Backspace - <--\r
+ DB 82 ; Enter insert mode - INS (toggle)\r
+ DB 65 ; Escape character - F7\r
+ DB 65 ; End of table\r
+ ENDIF\r
+ESCEND:\r
+ESCTABLEN EQU ESCEND-ESCTAB\r
+\r
+ESCFUNC LABEL WORD\r
+ short_addr GETCH ; Ignore the escape sequence\r
+ short_addr TWOESC\r
+ IF NOT TOGLINS\r
+ short_addr EXITINS\r
+ ENDIF\r
+ short_addr ENTERINS\r
+ short_addr BACKSP\r
+ short_addr REEDIT\r
+ short_addr KILNEW\r
+ short_addr COPYLIN\r
+ short_addr SKIPSTR\r
+ short_addr COPYSTR\r
+ short_addr SKIPONE\r
+ short_addr COPYONE\r
+\r
+ IF IBM\r
+ short_addr COPYONE\r
+ ENDIF\r
+ short_addr CTRLZ\r
+ ENDIF\r
+\r
+;\r
+; OEMFunction key is expected to process a single function\r
+; key input from a device and dispatch to the proper\r
+; routines leaving all registers UNTOUCHED.\r
+;\r
+; Inputs: CS, SS are DOSGROUP\r
+; Outputs: None. This function is expected to JMP to onw of\r
+; the following labels:\r
+;\r
+; GetCh - ignore the sequence\r
+; TwoEsc - insert an ESCChar in the buffer\r
+; ExitIns - toggle insert mode\r
+; EnterIns - toggle insert mode\r
+; BackSp - move backwards one space\r
+; ReEdit - reedit the line with a new template\r
+; KilNew - discard the current line and start from scratch\r
+; CopyLin - copy the rest of the template into the line\r
+; SkipStr - read the next character and skip to it in the template\r
+; CopyStr - read next char and copy from template to line until char\r
+; SkipOne - advance position in template one character\r
+; CopyOne - copy next character in template into line\r
+; CtrlZ - place a ^Z into the template\r
+; Registers that are allowed to be modified by this function are:\r
+; AX, CX, BP\r
+\r
+ PUBLIC OEMFunctionKey\r
+OEMFunctionKey PROC NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGROUP\r
+ invoke $STD_CON_INPUT_NO_ECHO ; Get the second byte of the sequence\r
+\r
+ IF NOT Rainbow\r
+ MOV CL,ESCTABLEN ; length of table for scan\r
+ PUSH DI ; save DI (cannot change it!)\r
+ MOV DI,OFFSET DOSGROUP:ESCTAB ; offset of second byte table\r
+ REPNE SCASB ; Look it up in the table\r
+ POP DI ; restore DI\r
+ SHL CX,1 ; convert byte offset to word\r
+ MOV BP,CX ; move to indexable register\r
+ JMP [BP+OFFSET DOSGROUP:ESCFUNC] ; Go to the right routine\r
+ ENDIF\r
+ IF Rainbow\r
+\r
+TransferIf MACRO value,address\r
+ local a\r
+ CMP AL,value\r
+ JNZ a\r
+ transfer address\r
+a:\r
+ENDM\r
+\r
+ CMP AL,'[' ; is it second lead char\r
+ JZ EatParm ; yes, go walk tree\r
+GoGetCh:\r
+ transfer GetCh ; no, ignore sequence\r
+EatParm:\r
+ invoke $STD_CON_INPUT_NO_ECHO ; get argument\r
+ CMP AL,'A' ; is it alphabetic arg?\r
+ JAE EatAlpha ; yes, go snarf one up\r
+ XOR BP,BP ; init digit counter\r
+ JMP InDigit ; jump into internal eat digit routine\r
+EatNum:\r
+ invoke $STD_CON_INPUT_NO_ECHO ; get next digit\r
+InDigit:\r
+ CMP AL,'9' ; still a digit?\r
+ JA CheckNumEnd ; no, go check for end char\r
+ SUB AL,'0' ; turn into potential digit\r
+ JB GoGetCh ; oops, not a digit, ignore\r
+ MOV CX,BP ; save BP for 10 multiply\r
+ CBW ; make AL into AX\r
+ SHL BP,1 ; 2*BP\r
+ SHL BP,1 ; 4*BP\r
+ ADD BP,CX ; 5*BP\r
+ SHL BP,1 ; 10*BP\r
+ ADD BP,AX ; 10*BP + digit\r
+ JMP EatNum ; continue with number\r
+CheckNumEnd:\r
+ CMP AL,7Eh ; is it end char ~\r
+ JNZ GoGetCh ; nope, ignore key sequence\r
+ MOV AX,BP\r
+ transferIf 1,SkipStr ; FIND key\r
+ transferIf 2,EnterIns ; INSERT HERE key\r
+ transferIf 3,SkipOne ; REMOVE\r
+ transferIf 4,CopyStr ; SELECT\r
+ transferIf 17,TwoEsc ; INTERRUPT\r
+ transferIf 18,ReEdit ; RESUME\r
+ transferIf 19,KilNew ; CANCEL\r
+ transferIf 21,CtrlZ ; EXIT\r
+ transferIf 29,CopyLin ; DO\r
+ JMP GoGetCh\r
+EatAlpha:\r
+ CMP AL,'O' ; is it O?\r
+ JA GoGetCh ; no, after assume bogus\r
+ JZ EatPQRS ; eat the rest of the bogus key\r
+ transferIf 'C',CopyOne ; RIGHT\r
+ transferIf 'D',BackSp ; LEFT\r
+ JMP GoGetCh\r
+EatPQRS:\r
+ invoke $STD_CON_INPUT_NO_ECHO ; eat char after O\r
+ JMP GoGetCh\r
+ ENDIF\r
+\r
+OEMFunctionKey ENDP\r
+\r
+CODE ENDS\r
+\r
+ do_ext\r
+ END\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\r
+\r
+\1a
\ No newline at end of file
--- /dev/null
+;
+; 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
--- /dev/null
+include DOSMAC.ASM\r
+IF2\r
+ %OUT DOSSYM in Pass 2\r
+ENDIF\r
+\r
+IFNDEF ALTVECT\r
+ALTVECT EQU 0 ;FALSE\r
+ENDIF\r
+\r
+BREAK <Control character definitions>\r
+\r
+c_DEL EQU 7Fh ; ASCII rubout or delete previous char\r
+c_BS EQU 08h ; ^H ASCII backspace\r
+c_CR EQU 0Dh ; ^M ASCII carriage return\r
+c_LF EQU 0Ah ; ^J ASCII linefeed\r
+c_ETB EQU 17h ; ^W ASCII end of transmission\r
+c_NAK EQU 15h ; ^U ASCII negative acknowledge\r
+c_ETX EQU 03h ; ^C ASCII end of text\r
+c_HT EQU 09h ; ^I ASCII tab\r
+\r
+BREAK <BPB Definition>\r
+\r
+\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+; ;\r
+; C A V E A T P R O G R A M M E R ;\r
+; ;\r
+; Certain structures, constants and system calls below are private to ;\r
+; the DOS and are extremely version-dependent. They may change at any ;\r
+; time at the implementors' whim. As a result, they must not be ;\r
+; documented to the general public. If an extreme case arises, they ;\r
+; must be documented with this warning. ;\r
+; ;\r
+; Those structures and constants that are subject to the above will be ;\r
+; marked and bracketed with the flag: ;\r
+; ;\r
+; C A V E A T P R O G R A M M E R ;\r
+; ;\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+\r
+BREAK <Bios Parameter Block>\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+; C A V E A T P R O G R A M M E R ;\r
+; ;\r
+\r
+; Bios Parameter Block definition\r
+; This structure is used to build a full DPB\r
+\r
+BPBLOCK STRUC\r
+BPSECSZ DW ? ; Size in bytes of physical sector\r
+BPCLUS DB ? ; Sectors/Alloc unit\r
+BPRES DW ? ; Number of reserved sectors\r
+BPFTCNT DB ? ; Number of FATs\r
+BPDRCNT DW ? ; Number of directory entries\r
+BPSCCNT DW ? ; Total number of sectors\r
+BPMEDIA DB ? ; Media descriptor byte\r
+BPFTSEC DW ? ; Number of sectors taken up by one FAT\r
+BPBLOCK ENDS\r
+; ;\r
+; C A V E A T P R O G R A M M E R ;\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+\r
+BREAK <Disk I/O Buffer Header>\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+; C A V E A T P R O G R A M M E R ;\r
+; ;\r
+\r
+; Field definition for I/O buffer information\r
+\r
+BUFFINFO STRUC\r
+NEXTBUF DD ? ; Pointer to next buffer in list\r
+; The next two items are often refed as a word\r
+BUFDRV DB ? ; Logical drive # assoc with buffer FF = free\r
+BUFDIRTY DB ? ; Dirty flag\r
+BUFPRI DB ? ; Buffer selection priority (see EQUs below)\r
+VISIT DB ? ; Visit flag for buffer pool scans\r
+BUFSECNO DW ? ; Sector number of buffer\r
+; The next two items are often refed as a word\r
+BUFWRTCNT DB ? ; For FAT sectors, # times sector written out\r
+BUFWRTINC DB ? ; " " " , # sectors between each write\r
+BUFDRVDP DD ? ; Pointer to drive parameters\r
+BUFFINFO ENDS\r
+\r
+BUFINSIZ EQU SIZE BUFFINFO\r
+ ; Size of structure in bytes\r
+\r
+FREEPRI EQU 0\r
+LBRPRI EQU 2 ; Last byte of buffer read\r
+LBWPRI EQU 4 ; Last byte written\r
+RPRI EQU 6 ; Read but not last byte\r
+WPRI EQU 8 ; Written but not last byte\r
+DIRPRI EQU 15 ; Directory Sector\r
+FATPRI EQU 30 ; FAT sector\r
+; ;\r
+; C A V E A T P R O G R A M M E R ;\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+\r
+BREAK <User stack inside of system call>\r
+; Location of user registers relative user stack pointer\r
+\r
+user_environ STRUC\r
+user_AX DW ?\r
+user_BX DW ?\r
+user_CX DW ?\r
+user_DX DW ?\r
+user_SI DW ?\r
+user_DI DW ?\r
+user_BP DW ?\r
+user_DS DW ?\r
+user_ES DW ?\r
+user_IP DW ?\r
+user_CS DW ?\r
+user_F DW ?\r
+user_environ ENDS\r
+\r
+BREAK <interrupt definitions>\r
+\r
+INTTAB EQU 20H\r
+INTBASE EQU 4 * inttab\r
+ENTRYPOINT EQU INTBASE+40H\r
+\r
+ IF ALTVECT\r
+ALTTAB EQU 0F0H\r
+ALTBASE EQU 4 * ALTTAB\r
+ ENDIF\r
+\r
+;\r
+; interrupt assignments\r
+;\r
+ IF NOT ALTVECT\r
+int_abort EQU INTTAB ; abort process\r
+int_command EQU int_abort+1 ; call MSDOS\r
+int_terminate EQU int_abort+2 ; int to terminate address\r
+int_ctrl_c EQU int_abort+3 ; ^c trapper\r
+int_fatal_abort EQU int_abort+4 ; hard disk error\r
+int_disk_read EQU int_abort+5 ; logical sector disk read\r
+int_disk_write EQU int_abort+6 ; logical sector disk write\r
+int_keep_process EQU int_abort+7 ; terminate program and stay resident\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+; C A V E A T P R O G R A M M E R ;\r
+; ;\r
+int_spooler EQU int_abort+8 ; spooler call\r
+int_fastcon EQU int_abort+9 ; fast CON interrupt\r
+; ;\r
+; C A V E A T P R O G R A M M E R ;\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+ ELSE\r
+int_abort EQU INTTAB ; abort process\r
+int_command EQU int_abort+1 ; call MSDOS\r
+int_terminate EQU ALTTAB ; int to terminate address\r
+int_ctrl_c EQU int_terminate+1 ; ^c trapper\r
+int_fatal_abort EQU int_terminate+2 ; hard disk error\r
+int_disk_read EQU int_abort+5 ; logical sector disk read\r
+int_disk_write EQU int_abort+6 ; logical sector disk write\r
+int_keep_process EQU int_abort+7 ; terminate program and stay resident\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+; C A V E A T P R O G R A M M E R ;\r
+; ;\r
+int_spooler EQU int_terminate+3 ; spooler call\r
+int_fastcon EQU int_abort+9 ; fast CON interrupt\r
+; ;\r
+; C A V E A T P R O G R A M M E R ;\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+ ENDIF\r
+\r
+addr_int_abort EQU 4 * int_abort\r
+addr_int_command EQU 4 * int_command\r
+addr_int_terminate EQU 4 * int_terminate\r
+addr_int_ctrl_c EQU 4 * int_ctrl_c\r
+addr_int_fatal_abort EQU 4 * int_fatal_abort\r
+addr_int_disk_read EQU 4 * int_disk_read\r
+addr_int_disk_write EQU 4 * int_disk_write\r
+addr_int_keep_process EQU 4 * int_keep_process\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+; C A V E A T P R O G R A M M E R ;\r
+; ;\r
+addr_int_spooler EQU 4 * int_spooler\r
+addr_int_fastcon EQU 4 * int_fastcon\r
+; ;\r
+; C A V E A T P R O G R A M M E R ;\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+\r
+BREAK <Disk map>\r
+; MSDOS partitions the disk into 4 sections:\r
+;\r
+; phys sector 0: +-------------------+\r
+; | | boot/reserved |\r
+; | +-------------------+\r
+; | | File allocation |\r
+; v | table(s) |\r
+; | (multiple copies |\r
+; | are kept) |\r
+; +-------------------+\r
+; | Directory |\r
+; +-------------------+\r
+; | File space |\r
+; +-------------------+\r
+; | Unaddressable |\r
+; | (to end of disk) |\r
+; +-------------------+\r
+;\r
+; All partition boundaries are sector boundaries. The size of the FAT is\r
+; adjusted to maximize the file space addressable.\r
+\r
+BREAK <Directory entry>\r
+\r
+;\r
+; +---------------------------+\r
+; | (12 BYTE) filename/ext | 0 0\r
+; +---------------------------+\r
+; | (BYTE) attributes | 11 B\r
+; +---------------------------+\r
+; | (10 BYTE) reserved | 12 C\r
+; +---------------------------+\r
+; | (WORD) time of last write | 22 16\r
+; +---------------------------+\r
+; | (WORD) date of last write | 24 18\r
+; +---------------------------+\r
+; | (WORD) First cluster | 26 1A\r
+; +---------------------------+\r
+; | (DWORD) file size | 28 1C\r
+; +---------------------------+\r
+;\r
+; First byte of filename = E5 -> free directory entry\r
+; = 00 -> end of allocated directory\r
+; Time: Bits 0-4=seconds/2, bits 5-10=minute, 11-15=hour\r
+; Date: Bits 0-4=day, bits 5-8=month, bits 9-15=year-1980\r
+;\r
+dir_entry STRUC\r
+dir_name DB 11 DUP (?) ; file name\r
+dir_attr DB ? ; attribute bits\r
+dir_pad DB 10 DUP (?) ; reserved for expansion\r
+dir_time DW ? ; time of last write\r
+dir_date DW ? ; date of last write\r
+dir_first DW ? ; first allocation unit of file\r
+dir_size_l DW ? ; low 16 bits of file size\r
+dir_size_h DW ? ; high 16 bits of file size\r
+dir_entry ENDS\r
+\r
+attr_read_only EQU 1h\r
+attr_hidden EQU 2h\r
+attr_system EQU 4h\r
+attr_volume_id EQU 8h\r
+attr_directory EQU 10h\r
+attr_archive EQU 20h\r
+\r
+attr_all EQU attr_hidden+attr_system+attr_directory\r
+ ; OR of hard attributes for FINDENTRY\r
+\r
+attr_ignore EQU attr_read_only+attr_archive\r
+ ; ignore this(ese) attribute(s)\r
+ ; during search first/next\r
+\r
+attr_changeable EQU attr_read_only+attr_hidden+attr_system+attr_archive\r
+ ; changeable via CHMOD\r
+\r
+BREAK <File allocation Table information>\r
+;\r
+; The File Allocation Table uses a 12-bit entry for each allocation unit on the\r
+; disk. These entries are packed, two for every three bytes. The contents of\r
+; entry number N is found by 1) multiplying N by 1.5; 2) adding the result to\r
+; the base address of the Allocation Table; 3) fetching the 16-bit word at this\r
+; address; 4) If N was odd (so that N*1.5 was not an integer), shift the word\r
+; right four bits; 5) mask to 12 bits (AND with 0FFF hex). Entry number zero\r
+; is used as an end-of-file trap in the OS and is passed to the BIOS to help\r
+; determine disk format. Entry 1 is reserved for future use. The first\r
+; available allocation unit is assigned entry number two, and even though it is\r
+; the first, is called cluster 2. Entries greater than 0FF8H are end of file\r
+; marks; entries of zero are unallocated. Otherwise, the contents of a FAT\r
+; entry is the number of the next cluster in the file.\r
+;\r
+; Clusters with bad sectors are tagged with FF7H. Any non-zero number would do\r
+; because these clusters show as allocated, but are not part of any allocation\r
+; chain and thus will never be allocated to a file. A particular number is\r
+; selected so that disk checking programs know what to do (ie. a cluster with\r
+; entry FF7H which is not in a chain is not an error).\r
+\r
+BREAK <DPB structure>\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+; C A V E A T P R O G R A M M E R ;\r
+; ;\r
+\r
+DIRSTRLEN EQU 64 ; Max length in bytes of directory strings\r
+\r
+dpb STRUC\r
+dpb_drive DB ? ; Logical drive # assoc with DPB (A=0,B=1,...)\r
+dpb_UNIT DB ? ; Driver unit number of DPB\r
+dpb_sector_size DW ? ; Size of physical sector in bytes\r
+dpb_cluster_mask DB ? ; Sectors/cluster - 1\r
+dpb_cluster_shift DB ? ; Log2 of sectors/cluster\r
+dpb_first_FAT DW ? ; Starting record of FATs\r
+dpb_FAT_count DB ? ; Number of FATs for this drive\r
+dpb_root_entries DW ? ; Number of directory entries\r
+dpb_first_sector DW ? ; First sector of first cluster\r
+dpb_max_cluster DW ? ; Number of clusters on drive + 1\r
+dpb_FAT_size DB ? ; Number of records occupied by FAT\r
+dpb_dir_sector DW ? ; Starting record of directory\r
+dpb_driver_addr DD ? ; Pointer to driver\r
+dpb_media DB ? ; Media byte\r
+dpb_first_access DB ? ; This is initialized to -1 to force a media\r
+ ; check the first time this DPB is used\r
+dpb_next_dpb DD ? ; Pointer to next Drive parameter block\r
+dpb_current_dir DW ? ; Cluster number of start of current directory\r
+ ; 0 indicates root, -1 indicates invalid\r
+ ; (disk ? changed)\r
+dpb_dir_text DB DIRSTRLEN DUP(?)\r
+ ; ASCIZ string of current directory\r
+dpb ENDS\r
+\r
+DPBSIZ EQU SIZE dpb ; Size of the structure in bytes\r
+\r
+DSKSIZ = dpb_max_cluster ; Size of disk (temp used during init only)\r
+; ;\r
+; C A V E A T P R O G R A M M E R ;\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+\r
+BREAK <File Control Block definition>\r
+;\r
+; Field definition for FCBs\r
+; The FCB has the following structure:\r
+;\r
+; +---------------------------+\r
+; | Drive indicator(byte) |\r
+; +---------------------------+\r
+; | Filename (8 chars) |\r
+; +---------------------------+\r
+; | Extension (3 chars) |\r
+; +---------------------------+\r
+; | Current Extent(word) |\r
+; +---------------------------+\r
+; | Record size (word) |\r
+; +---------------------------+\r
+; | File Size (2 words) |\r
+; +---------------------------+\r
+; | Date of write |\r
+; +---------------------------+\r
+; | Time of write |\r
+; +---------------------------+\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+; C A V E A T P R O G R A M M E R ;\r
+; ;\r
+; | Flags: |\r
+; | bit 7=0 file/1 device |\r
+; | bit 6=0 if dirty |\r
+; | bits 0-5 deviceid |\r
+; +---------------------------+\r
+; | first cluster in file |\r
+; +---------------------------+\r
+; | position of last cluster |\r
+; +---------------------------+\r
+; | last cluster accessed | 12 bit-+--- packed in 3 bytes\r
+; +---------------------------+ |\r
+; | parent directory | <------+\r
+; +---------------------------+\r
+; ;\r
+; C A V E A T P R O G R A M M E R ;\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+; | next record number |\r
+; +---------------------------+\r
+; | random record number |\r
+; +---------------------------+\r
+;\r
+\r
+sys_fcb STRUC\r
+fcb_drive DB ?\r
+fcb_name DB 8 DUP (?)\r
+fcb_ext DB 3 DUP (?)\r
+fcb_EXTENT DW ?\r
+fcb_RECSIZ DW ? ; Size of record (user settable)\r
+fcb_FILSIZ DW ? ; Size of file in bytes; used with the following\r
+ ; word\r
+fcb_DRVBP DW ? ; BP for SEARCH FIRST and SEARCH NEXT\r
+fcb_FDATE DW ? ; Date of last writing\r
+fcb_FTIME DW ? ; Time of last writing\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+; C A V E A T P R O G R A M M E R ;\r
+; ;\r
+fcb_DEVID DB ? ; Device ID number, bits 0-5 if file.\r
+ ; bit 7=0 for file, bit 7=1 for I/O device\r
+ ; If file, bit 6=0 if dirty\r
+ ; If I/O device, bit 6=0 if EOF (input)\r
+ ; Bit 5=1 if Raw mode\r
+ ; Bit 0=1 if console input device\r
+ ; Bit 1=1 if console output device\r
+ ; Bit 2=1 if null device\r
+ ; Bit 3=1 if clock device\r
+fcb_FIRCLUS DW ? ; First cluster of file\r
+fcb_CLUSPOS DW ? ; Position of last cluster accessed\r
+fcb_LSTCLUS DW ? ; Last cluster accessed and directory\r
+ DB ? ; pack 2 12 bit numbers into 24 bits...\r
+; ;\r
+; C A V E A T P R O G R A M M E R ;\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+fcb_NR DB ? ; Next record\r
+fcb_RR DB 4 DUP (?) ; Random record\r
+sys_fcb ENDS\r
+\r
+FILDIRENT = fcb_FILSIZ ; Used only by SEARCH FIRST and\r
+ ; SEARCH NEXT\r
+\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+; C A V E A T P R O G R A M M E R ;\r
+; ;\r
+devid_file_clean EQU 40h ; true if file and not written\r
+devid_file_mask_drive EQU 3Fh ; mask for drive number\r
+\r
+devid_device EQU 80h ; true if a device\r
+devid_device_EOF EQU 40h ; true if end of file reached\r
+devid_device_raw EQU 20h ; true if in raw mode\r
+devid_device_special EQU 10h ; true if special device\r
+devid_device_clock EQU 08h ; true if clock device\r
+devid_device_null EQU 04h ; true if null device\r
+devid_device_con_out EQU 02h ; true if console output\r
+devid_device_con_in EQU 01h ; true if consle input\r
+\r
+;\r
+; structure of devid field as returned by IOCTL is:\r
+;\r
+; BIT 7 6 5 4 3 2 1 0\r
+; |---|---|---|---|---|---|---|---|\r
+; | I | E | R | S | I | I | I | I |\r
+; | S | O | A | P | S | S | S | S |\r
+; | D | F | W | E | C | N | C | C |\r
+; | E | | | C | L | U | O | I |\r
+; | V | | | L | K | L | T | N |\r
+; |---|---|---|---|---|---|---|---|\r
+; ISDEV = 1 if this channel is a device\r
+; = 0 if this channel is a disk file\r
+;\r
+; If ISDEV = 1\r
+;\r
+; EOF = 0 if End Of File on input\r
+; RAW = 1 if this device is in Raw mode\r
+; = 0 if this device is cooked\r
+; ISCLK = 1 if this device is the clock device\r
+; ISNUL = 1 if this device is the null device\r
+; ISCOT = 1 if this device is the console output\r
+; ISCIN = 1 if this device is the console input\r
+;\r
+; If ISDEV = 0\r
+; EOF = 0 if channel has been written\r
+; Bits 0-5 are the block device number for\r
+; the channel (0 = A, 1 = B, ...)\r
+;\r
+devid_ISDEV EQU 80h\r
+devid_EOF EQU 40h\r
+devid_RAW EQU 20h\r
+devid_SPECIAL EQU 10H\r
+devid_ISCLK EQU 08h\r
+devid_ISNUL EQU 04h\r
+devid_ISCOT EQU 02h\r
+devid_ISCIN EQU 01h\r
+\r
+devid_block_dev EQU 1Fh ; mask for block device number\r
+\r
+;\r
+; find first/next buffer\r
+;\r
+find_buf STRUC\r
+find_buf_sattr DB ? ; attribute of search\r
+find_buf_drive DB ? ; drive of search\r
+find_buf_name DB 11 DUP (?) ; formatted name\r
+find_buf_LastEnt DW ? ; LastEnt\r
+find_buf_ThisDPB DD ? ; This DPB\r
+find_buf_DirStart DW ? ; DirStart\r
+; ;\r
+; C A V E A T P R O G R A M M E R ;\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+\r
+find_buf_attr DB ? ; attribute found\r
+find_buf_time DW ? ; time\r
+find_buf_date DW ? ; date\r
+find_buf_size_l DW ? ; low(size)\r
+find_buf_size_h DW ? ; high(size)\r
+find_buf_pname DB 13 DUP (?) ; packed name\r
+find_buf ENDS\r
+\r
+BREAK <Process data block>\r
+;\r
+; Process data block (otherwise known as program header)\r
+;\r
+\r
+FilPerProc EQU 20\r
+\r
+Process_data_block STRUC\r
+PDB_Exit_Call DW ? ; INT int_abort system terminate\r
+PDB_block_len DW ? ; size of execution block\r
+ DB ?\r
+PDB_CPM_Call DB 5 DUP (?) ; ancient call to system\r
+PDB_Exit DD ? ; pointer to exit routine\r
+PDB_Ctrl_C DD ? ; pointer to ^C routine\r
+PDB_Fatal_abort DD ? ; pointer to fatal error\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+; C A V E A T P R O G R A M M E R ;\r
+; ;\r
+PDB_Parent_PID DW ? ; PID of parent (terminate PID)\r
+PDB_JFN_Table DB FilPerProc DUP (?)\r
+ ; indices into system table\r
+; ;\r
+; C A V E A T P R O G R A M M E R ;\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+PDB_environ DW ? ; seg addr of environment\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+; C A V E A T P R O G R A M M E R ;\r
+; ;\r
+PDB_User_stack DD ? ; stack of self during system calls\r
+PDB_PAD1 DB 1Eh DUP (?)\r
+; ;\r
+; C A V E A T P R O G R A M M E R ;\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+PDB_Call_system DB 5 DUP (?) ; portable method of system call\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+; C A V E A T P R O G R A M M E R ;\r
+; ;\r
+PDB_PAD2 DB 6h DUP (?) ;\r
+; ;\r
+; C A V E A T P R O G R A M M E R ;\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+Process_data_block ENDS\r
+\r
+BREAK <EXEC and EXE file structures>\r
+;\r
+; EXEC arg block - load/go program\r
+;\r
+\r
+;\r
+; The following get used as arguments to the EXEC system call. They indicate\r
+; whether or not the program is executed or whether or not a program header\r
+; gets created.\r
+;\r
+exec_func_no_execute EQU 1 ; no execute bit\r
+exec_func_overlay EQU 2 ; overlay bit\r
+\r
+Exec0 STRUC\r
+Exec0_environ DW ? ; seg addr of environment\r
+Exec0_com_line DD ? ; pointer to asciz command line\r
+Exec0_5C_FCB DD ? ; default fcb at 5C\r
+Exec0_6C_FCB DD ? ; default fcb at 6C\r
+Exec0 ENDS\r
+\r
+Exec1 STRUC\r
+Exec1_environ DW ? ; seg addr of environment\r
+Exec1_com_line DD ? ; pointer to asciz command line\r
+Exec1_5C_FCB DD ? ; default fcb at 5C\r
+Exec1_6C_FCB DD ? ; default fcb at 6C\r
+Exec1_SP DW ? ; stack pointer of program\r
+Exec1_SS DW ? ; stack seg register of program\r
+Exec1_IP DW ? ; entry point IP\r
+Exec1_CS DW ? ; entry point CS\r
+Exec1 ENDS\r
+\r
+Exec3 STRUC\r
+Exec3_load_addr DW ? ; seg address of load point\r
+Exec3_reloc_fac DW ? ; relocation factor\r
+Exec3 ENDS\r
+\r
+;\r
+; Exit codes in upper byte\r
+;\r
+Exit_terminate EQU 0\r
+Exit_abort EQU 0\r
+Exit_Ctrl_C EQU 1\r
+Exit_Hard_Error EQU 2\r
+Exit_Keep_process EQU 3\r
+\r
+;\r
+; EXE file header\r
+;\r
+\r
+EXE_file STRUC\r
+exe_signature DW ? ; must contain 4D5A (yay zibo!)\r
+exe_len_mod_512 DW ? ; low 9 bits of length\r
+exe_pages DW ? ; number of 512b pages in file\r
+exe_rle_count DW ? ; count of reloc entries\r
+exe_par_dir DW ? ; number of paragraphs before image\r
+exe_min_BSS DW ? ; minimum number of para of BSS\r
+exe_max_BSS DW ? ; max number of para of BSS\r
+exe_SS DW ? ; stack of image\r
+exe_SP DW ? ; SP of image\r
+exe_chksum DW ? ; checksum of file (ignored)\r
+exe_IP DW ? ; IP of entry\r
+exe_CS DW ? ; CS of entry\r
+exe_rle_table DW ? ; byte offset of reloc table\r
+exe_iov DW ? ; overlay number (0 for root)\r
+exe_sym_tab DD ? ; offset of symbol table in file\r
+EXE_file ENDS\r
+\r
+exe_valid_signature EQU 5A4Dh\r
+exe_valid_old_signature EQU 4D5Ah\r
+\r
+symbol_entry STRUC\r
+sym_value DD ?\r
+sym_type DW ?\r
+sym_len DB ?\r
+sym_name DB 255 dup (?)\r
+symbol_entry ENDS\r
+\r
+BREAK <Internal system file table format>\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+; C A V E A T P R O G R A M M E R ;\r
+; ;\r
+;\r
+; system file table\r
+;\r
+\r
+sft STRUC\r
+sft_link DD ?\r
+sft_count DW ? ; number of entries\r
+sft_table DW ? ; beginning of array of the following\r
+sft ENDS\r
+\r
+;\r
+; system file table entry\r
+;\r
+\r
+sf_entry STRUC\r
+sf_ref_count DB ? ; number of processes sharing fcb\r
+sf_mode DB ? ; mode of access\r
+sf_attr DB ? ; attribute of file\r
+sf_fcb DB (SIZE sys_fcb) DUP (?)\r
+ ; actual FCB\r
+sf_entry ENDS\r
+\r
+sf_default_number EQU 5h\r
+; ;\r
+; C A V E A T P R O G R A M M E R ;\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+\r
+BREAK <Memory arena structure>\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+; C A V E A T P R O G R A M M E R ;\r
+; ;\r
+;\r
+; arena item\r
+;\r
+arena STRUC\r
+arena_signature DB ? ; 4D for valid item, 5A for last item\r
+arena_owner DW ? ; owner of arena item\r
+arena_size DW ? ; size in paragraphs of item\r
+arena ENDS\r
+\r
+arena_owner_system EQU 0 ; free block indication\r
+\r
+arena_signature_normal EQU 4Dh ; valid signature, not end of arena\r
+arena_signature_end EQU 5Ah ; valid signature, last block in arena\r
+; ;\r
+; C A V E A T P R O G R A M M E R ;\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+\r
+BREAK <Machine instruction definitions>\r
+\r
+mi_INT EQU 0CDh\r
+mi_Long_JMP EQU 0EAh\r
+mi_Long_CALL EQU 09Ah\r
+mi_Long_RET EQU 0CBh\r
+\r
+BREAK <Standard I/O assignments>\r
+\r
+stdin EQU 0\r
+stdout EQU 1\r
+stderr EQU 2\r
+stdaux EQU 3\r
+stdprn EQU 4\r
+\r
+BREAK <Xenix subfunction assignments>\r
+\r
+open_for_read EQU 0\r
+open_for_write EQU 1\r
+open_for_both EQU 2\r
+\r
+BREAK <Xenix error codes>\r
+\r
+;\r
+; XENIX calls all return error codes through AX. If an error occurred then the\r
+; carry bit will be set and the error code is in AX. If no error occurred then\r
+; the carry bit is reset and AX contains returned info.\r
+;\r
+\r
+no_error_occurred EQU 0 ?\r
+\r
+error_invalid_function EQU 1\r
+error_file_not_found EQU 2\r
+error_path_not_found EQU 3\r
+error_too_many_open_files EQU 4\r
+error_access_denied EQU 5\r
+error_invalid_handle EQU 6\r
+error_arena_trashed EQU 7\r
+error_not_enough_memory EQU 8\r
+error_invalid_block EQU 9\r
+error_bad_environment EQU 10\r
+error_bad_format EQU 11\r
+error_invalid_access EQU 12\r
+error_invalid_data EQU 13\r
+;**** unused EQU 14\r
+error_invalid_drive EQU 15\r
+error_current_directory EQU 16\r
+error_not_same_device EQU 17\r
+error_no_more_files EQU 18\r
+\r
+alloc_not_enough_memory EQU error_not_enough_memory\r
+alloc_arena_trashed EQU error_arena_trashed\r
+\r
+close_invalid_handle EQU error_invalid_handle\r
+close_invalid_function EQU error_invalid_function\r
+\r
+chdir_path_not_found EQU error_path_not_found\r
+\r
+chmod_path_not_found EQU error_path_not_found\r
+chmod_access_denied EQU error_access_denied\r
+chmod_invalid_function EQU error_invalid_function\r
+\r
+creat_access_denied EQU error_access_denied\r
+creat_path_not_found EQU error_path_not_found\r
+creat_too_many_open_files EQU error_too_many_open_files\r
+\r
+curdir_invalid_drive EQU error_invalid_drive\r
+\r
+dealloc_invalid_block EQU error_invalid_block\r
+dealloc_arena_trashed EQU error_arena_trashed\r
+\r
+dup_invalid_handle EQU error_invalid_handle\r
+dup_too_many_open_files EQU error_too_many_open_files\r
+\r
+dup2_invalid_handle EQU error_invalid_handle\r
+\r
+exec_invalid_function EQU error_invalid_function\r
+exec_bad_environment EQU error_bad_environment\r
+exec_bad_format EQU error_bad_format\r
+exec_not_enough_memory EQU error_not_enough_memory\r
+exec_file_not_found EQU error_file_not_found\r
+\r
+filetimes_invalid_function EQU error_invalid_function\r
+filetimes_invalid_handle EQU error_invalid_handle\r
+\r
+findfirst_file_not_found EQU error_file_not_found\r
+findfirst_no_more_files EQU error_no_more_files\r
+findnext_no_more_files EQU error_no_more_files\r
+\r
+international_invalid_function EQU error_invalid_function\r
+\r
+ioctl_invalid_handle EQU error_invalid_handle\r
+ioctl_invalid_function EQU error_invalid_function\r
+ioctl_invalid_data EQU error_invalid_data\r
+\r
+lseek_invalid_handle EQU error_invalid_handle\r
+lseek_invalid_function EQU error_invalid_function\r
+\r
+mkdir_path_not_found EQU error_path_not_found\r
+mkdir_access_denied EQU error_access_denied\r
+\r
+open_invalid_access EQU error_invalid_access\r
+open_file_not_found EQU error_file_not_found\r
+open_access_denied EQU error_access_denied\r
+open_too_many_open_files EQU error_too_many_open_files\r
+\r
+read_invalid_handle EQU error_invalid_handle\r
+read_access_denied EQU error_access_denied\r
+\r
+rename_file_not_found EQU error_file_not_found\r
+rename_not_same_device EQU error_not_same_device\r
+rename_access_denied EQU error_access_denied\r
+\r
+rmdir_path_not_found EQU error_path_not_found\r
+rmdir_access_denied EQU error_access_denied\r
+rmdir_current_directory EQU error_current_directory\r
+\r
+setblock_invalid_block EQU error_invalid_block\r
+setblock_arena_trashed EQU error_arena_trashed\r
+setblock_not_enough_memory EQU error_not_enough_memory\r
+setblock_invalid_function EQU error_invalid_function\r
+\r
+unlink_file_not_found EQU error_file_not_found\r
+unlink_access_denied EQU error_access_denied\r
+\r
+write_invalid_handle EQU error_invalid_handle\r
+write_access_denied EQU error_access_denied\r
+\r
+BREAK <system call definitions>\r
+\r
+ABORT EQU 0 ; 0 0\r
+STD_CON_INPUT EQU 1 ; 1 1\r
+STD_CON_OUTPUT EQU 2 ; 2 2\r
+STD_AUX_INPUT EQU 3 ; 3 3\r
+STD_AUX_OUTPUT EQU 4 ; 4 4\r
+STD_PRINTER_OUTPUT EQU 5 ; 5 5\r
+RAW_CON_IO EQU 6 ; 6 6\r
+RAW_CON_INPUT EQU 7 ; 7 7\r
+STD_CON_INPUT_NO_ECHO EQU 8 ; 8 8\r
+STD_CON_STRING_OUTPUT EQU 9 ; 9 9\r
+STD_CON_STRING_INPUT EQU 10 ; 10 A\r
+STD_CON_INPUT_STATUS EQU 11 ; 11 B\r
+STD_CON_INPUT_FLUSH EQU 12 ; 12 C\r
+DISK_RESET EQU 13 ; 13 D\r
+SET_DEFAULT_DRIVE EQU 14 ; 14 E\r
+FCB_OPEN EQU 15 ; 15 F\r
+FCB_CLOSE EQU 16 ; 16 10\r
+DIR_SEARCH_FIRST EQU 17 ; 17 11\r
+DIR_SEARCH_NEXT EQU 18 ; 18 12\r
+FCB_DELETE EQU 19 ; 19 13\r
+FCB_SEQ_READ EQU 20 ; 20 14\r
+FCB_SEQ_WRITE EQU 21 ; 21 15\r
+FCB_CREATE EQU 22 ; 22 16\r
+FCB_RENAME EQU 23 ; 23 17\r
+GET_DEFAULT_DRIVE EQU 25 ; 25 19\r
+SET_DMA EQU 26 ; 26 1A\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+; C A V E A T P R O G R A M M E R ;\r
+; ;\r
+GET_DEFAULT_DPB EQU 31 ; 31 1F\r
+; ;\r
+; C A V E A T P R O G R A M M E R ;\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+FCB_RANDOM_READ EQU 33 ; 33 21\r
+FCB_RANDOM_WRITE EQU 34 ; 34 22\r
+GET_FCB_FILE_LENGTH EQU 35 ; 35 23\r
+GET_FCB_POSITION EQU 36 ; 36 24\r
+SET_INTERRUPT_VECTOR EQU 37 ; 37 25\r
+CREATE_PROCESS_DATA_BLOCK EQU 38 ; 38 26\r
+FCB_RANDOM_READ_BLOCK EQU 39 ; 39 27\r
+FCB_RANDOM_WRITE_BLOCK EQU 40 ; 40 28\r
+PARSE_FILE_DESCRIPTOR EQU 41 ; 41 29\r
+GET_DATE EQU 42 ; 42 2A\r
+SET_DATE EQU 43 ; 43 2B\r
+GET_TIME EQU 44 ; 44 2C\r
+SET_TIME EQU 45 ; 45 2D\r
+SET_VERIFY_ON_WRITE EQU 46 ; 46 2E\r
+; Extended functionality group\r
+GET_DMA EQU 47 ; 47 2F\r
+GET_VERSION EQU 48 ; 48 30\r
+KEEP_PROCESS EQU 49 ; 49 31\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+; C A V E A T P R O G R A M M E R ;\r
+; ;\r
+GET_DPB EQU 50 ; 50 32\r
+; ;\r
+; C A V E A T P R O G R A M M E R ;\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+SET_CTRL_C_TRAPPING EQU 51 ; 51 33\r
+GET_INDOS_FLAG EQU 52 ; 52 34\r
+GET_INTERRUPT_VECTOR EQU 53 ; 53 35\r
+GET_DRIVE_FREESPACE EQU 54 ; 54 36\r
+CHAR_OPER EQU 55 ; 55 37\r
+INTERNATIONAL EQU 56 ; 56 38\r
+; XENIX CALLS\r
+; Directory Group\r
+MKDIR EQU 57 ; 57 39\r
+RMDIR EQU 58 ; 58 3A\r
+CHDIR EQU 59 ; 59 3B\r
+; File Group\r
+CREAT EQU 60 ; 60 3C\r
+OPEN EQU 61 ; 61 3D\r
+CLOSE EQU 62 ; 62 3E\r
+READ EQU 63 ; 63 3F\r
+WRITE EQU 64 ; 64 40\r
+UNLINK EQU 65 ; 65 41\r
+LSEEK EQU 66 ; 66 42\r
+CHMOD EQU 67 ; 67 43\r
+IOCTL EQU 68 ; 68 44\r
+XDUP EQU 69 ; 69 45\r
+XDUP2 EQU 70 ; 70 46\r
+CURRENT_DIR EQU 71 ; 71 47\r
+; Memory Group\r
+ALLOC EQU 72 ; 72 48\r
+DEALLOC EQU 73 ; 73 49\r
+SETBLOCK EQU 74 ; 74 4A\r
+; Process Group\r
+EXEC EQU 75 ; 75 4B\r
+EXIT EQU 76 ; 76 4C\r
+WAIT EQU 77 ; 77 4D\r
+FIND_FIRST EQU 78 ; 78 4E\r
+; Special Group\r
+FIND_NEXT EQU 79 ; 79 4F\r
+; SPECIAL SYSTEM GROUP\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+; C A V E A T P R O G R A M M E R ;\r
+; ;\r
+SET_CURRENT_PDB EQU 80 ; 80 50\r
+GET_CURRENT_PDB EQU 81 ; 81 51\r
+GET_IN_VARS EQU 82 ; 82 52\r
+SETDPB EQU 83 ; 83 53\r
+; ;\r
+; C A V E A T P R O G R A M M E R ;\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+GET_VERIFY_ON_WRITE EQU 84 ; 84 54\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+; C A V E A T P R O G R A M M E R ;\r
+; ;\r
+DUP_PDB EQU 85 ; 85 55\r
+; ;\r
+; C A V E A T P R O G R A M M E R ;\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+RENAME EQU 86 ; 86 56\r
+FILE_TIMES EQU 87 ; 87 57\r
+\r
+SET_OEM_HANDLER EQU 248 ; 248 F8\r
+OEM_C1 EQU 249 ; 249 F9\r
+OEM_C2 EQU 250 ; 250 FA\r
+OEM_C3 EQU 251 ; 251 FB\r
+OEM_C4 EQU 252 ; 252 FC\r
+OEM_C5 EQU 253 ; 253 FD\r
+OEM_C6 EQU 254 ; 254 FE\r
+OEM_C7 EQU 255 ; 255 FF\r
+SUBTTL\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+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
--- /dev/null
+ title EDLIN for MSDOS 2.0
+
+;-----------------------------------------------------------------------;
+; REVISION HISTORY: ;
+; ;
+; V1.02 ;
+; ;
+; V2.00 9/13/82 M.A. Ulloa ;
+; Modified to use Pathnames in command line file ;
+; specification, modified REPLACE to use an empty ;
+; string intead of the old replace string when this ;
+; is missing, and search and replace now start from ;
+; first line of buffer (like old version of EDLIN) ;
+; instead than current+1 line. Also added the U and ;
+; V commands that search (replace) starting from the ;
+; current+1 line. ;
+; ;
+; 9/15/82 M.A. Ulloa ;
+; Added the quote character (^V). ;
+; ;
+; 9/16/82 M.A. Ulloa ;
+; Corrected bug about use of quote char when going ;
+; into default insert mode. Also corrected the problem ;
+; with ^Z being the end of file marker. End of file is ;
+; reached when an attempt to read returns less chars ;
+; than requested. ;
+; ;
+; 9/17/82 M.A. Ulloa ;
+; Corrected bug about boundaries for Copy ;
+; ;
+; 10/4/82 Rev. 1 M.A. Ulloa ;
+; The IBM version now does NOT have the U and V ;
+; commands. The MSDOS version HAS the U and V commands. ;
+; Added the B switch, and modified the effect of ;
+; the quote char. ;
+; ;
+; 10/7/82 Rev. 2 M.A. Ulloa ;
+; Changed the S and R commands to start from the ;
+; current line+1 (as U and V did). Took away U and V in ;
+; all versions. ;
+; ;
+; 10/13/82 Rev. 3 M.A. Ulloa ;
+; Now if parameter1 < 1 then parameter1 = 1 ;
+; ;
+; 10/15/82 Rev. 4 M.A. Ulloa ;
+; Param4 if specified must be an absolute number that ;
+; reprecents the count. ;
+; ;
+; 10/18/82 Rev. 5 M.A. Ulloa ;
+; Fixed problem with trying to edit files with the ;
+; same name as directories. Also, if the end of file is ;
+; reached it checks that a LF is the last character, ;
+; otherwise it inserts a CRLF pair at the end. ;
+; ;
+; 10/20/82 Rev. 6 M.A.Ulloa ;
+; Changed the text of some error messages for IBM and ;
+; rewrite PAGE. ;
+; ;
+; 10/25/82 Rev. 7 M.A.Ulloa ;
+; Made all messages as in the IBM vers. ;
+; ;
+; 10/28/82 Rev. 8 M.A.Ulloa ;
+; Corrected problem with parsing for options. ;
+; ;
+; Rev. 9 Aaron Reynolds ;
+; Made error messages external. ;
+; ;
+; 12/08/82 Rev. 10 M.A. Ulloa ;
+; Corrected problem arising with having to restore ;
+; the old directory in case of a file name error. ;
+; ;
+; 12/17/82 Rev. 11 M.A. Ulloa ;
+; Added the ROPROT equate for R/O file protection. ;
+; It causes only certain operations (L,P,S,W,A, and Q) ;
+; to be allowed on read only files. ;
+; ;
+; 12/29/82 Rev. 12 M.A. Ulloa :
+; Added the creation error message. ;
+; ;
+; 4/14/83 Rev. 13 N.Panners ;
+; Fixed bug in Merge which lost char if not ^Z. ;
+; Fixed bug in Copy to correctly check ;
+; for full buffers. ;
+; ;
+; ;
+; 7/23/83 Rev. 14 N.Panners ;
+; Split EDLIN into two seperate modules to ;
+; allow assembly of sources on an IBM PC ;
+; EDLIN and EDLPROC ;
+; ;
+;-----------------------------------------------------------------------;
+
+
+FALSE EQU 0
+TRUE EQU NOT FALSE
+
+KANJI EQU FALSE
+
+roprot equ true ;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
+CONST ENDS
+
+DATA SEGMENT PUBLIC WORD
+DATA ENDS
+
+DG GROUP CODE,CONST,DATA
+
+CONST SEGMENT PUBLIC WORD
+
+ EXTRN BADDRV:BYTE,NDNAME:BYTE,bad_vers_err:BYTE,opt_err:BYTE
+ EXTRN NOBAK:BYTE,BADCOM:BYTE,NEWFIL:BYTE,DEST:BYTE,MRGERR:BYTE
+ EXTRN NODIR:BYTE,DSKFUL:BYTE,MEMFUL:BYTE,FILENM:BYTE
+ EXTRN NOSUCH:BYTE,TOOLNG:BYTE,EOF:BYTE,ro_err:byte,bcreat:byte
+
+ PUBLIC TXT1,TXT2,FUDGE,USERDIR,HARDCH
+
+BAK DB "BAK"
+
+make db "***MAUlloa/Microsoft/V20***"
+rev db "14"
+
+ if roprot ;***** R/O *****
+roflag db 0 ; =1 if file is r/o
+ endif
+
+fourth db 0 ;fourth parameter flag
+
+loadmod db 0 ;Load mode flag, 0 = ^Z marks the
+ ; end of a file, 1 = viceversa.
+hardch dd ?
+
+the_root db 0 ;root directory flag
+
+fudge db 0 ;directory changed flag
+user_drive db 0
+
+
+optchar db "-"
+
+dirchar db "/",0
+
+userdir db "/",0
+ db (dirstrlen) dup(0)
+
+fname_buffer db Comand_Line_Length dup(0)
+;-----------------------------------------------------------------------;
+
+TXT1 DB 0,80H DUP (?)
+TXT2 DB 0,80H DUP (?)
+DELFLG DB 0
+
+CONST ENDS
+
+DATA SEGMENT PUBLIC WORD
+
+ PUBLIC QFLG,FCB2,OLDLEN,PARAM1,PARAM2,OLDDAT,SRCHFLG
+ PUBLIC COMLINE,NEWLEN,SRCHMOD,CURRENT,LSTFND,NUMPOS
+ PUBLIC LSTNUM,SRCHCNT,POINTER,START,ENDTXT,USER_DRIVE
+
+;-----------------------------------------------------------------------;
+; Be carefull when adding parameters, they have to follow the
+; order in which they apperar here. (this is a table, ergo it
+; is indexed thru a pointer, and random additions will cause the
+; wrong item to be accessed). Also param4 is known to be the
+; count parameter, and known to be the fourth entry in the table
+; so it receives special treatment. (See GETNUM)
+
+PARAM1 DW 1 DUP (?)
+PARAM2 DW 1 DUP (?)
+PARAM3 DW 1 DUP (?)
+PARAM4 DW 1 DUP (?)
+
+;-----------------------------------------------------------------------;
+
+PTR_1 DW 1 DUP (?)
+PTR_2 DW 1 DUP (?)
+PTR_3 DW 1 DUP (?)
+COPYSIZ DW 1 DUP (?)
+OLDLEN DW 1 DUP (?)
+NEWLEN DW 1 DUP (?)
+LSTFND DW 1 DUP (?)
+LSTNUM DW 1 DUP (?)
+NUMPOS DW 1 DUP (?)
+SRCHCNT DW 1 DUP (?)
+CURRENT DW 1 DUP (?)
+POINTER DW 1 DUP (?)
+ONE4TH DW 1 DUP (?)
+THREE4TH DW 1 DUP (?)
+LAST DW 1 DUP (?)
+ENDTXT DW 1 DUP (?)
+COMLINE DW 1 DUP (?)
+LASTLIN DW 1 DUP (?)
+COMBUF DB 82H DUP (?)
+EDITBUF DB 258 DUP (?)
+EOL DB 1 DUP (?)
+FCB2 DB 37 DUP (?)
+FCB3 DB 37 DUP (?)
+fake_fcb db 37 dup (?) ;fake for size figuring
+QFLG DB 1 DUP (?)
+HAVEOF DB 1 DUP (?)
+ENDING DB 1 DUP (?)
+SRCHFLG DB 1 DUP (?)
+amnt_req dw 1 dup (?) ;ammount of bytes requested to read
+olddat db 1 dup (?) ;Used in replace and search,
+ ; replace by old data flag (1=yes)
+srchmod db 1 dup (?) ;Search mode: 1=from current+1 to
+ ; end of buffer, 0=from beg. of
+ ; buffer to the end (old way).
+MOVFLG DB 1 DUP (?)
+ DB STKSIZ DUP (?)
+
+STACK LABEL BYTE
+START LABEL WORD
+
+DATA ENDS
+
+SUBTTL Main Body
+PAGE
+
+CODE SEGMENT PUBLIC
+
+ASSUME CS:DG,DS:DG,SS:DG,ES:DG
+
+ EXTRN QUIT:NEAR,QUERY:NEAR,FNDFIRST:NEAR,FNDNEXT:NEAR
+ EXTRN UNQUOTE:NEAR,LF:NEAR,CRLF:NEAR,OUT:NEAR
+ EXTRN REST_DIR:NEAR,KILL_BL:NEAR,INT_24:NEAR
+ EXTRN FINDLIN:NEAR,SHOWNUM:NEAR,SCANLN:NEAR
+
+ if Kanji
+ EXTRN TESTKANJ:NEAR
+ endif
+
+ PUBLIC CHKRANGE
+
+ ORG 100H
+
+EDLIN:
+ JMP SIMPED
+
+edl_pad db 0e00h dup (?)
+
+HEADER DB "Vers 2.14"
+
+NONAME:
+ MOV DX,OFFSET DG:NDNAME
+ERRJ: JMP xERROR
+
+SIMPED:
+ MOV BYTE PTR [ENDING],0
+ MOV SP,OFFSET DG:STACK
+
+;Code to print header
+; PUSH AX
+; MOV DX,OFFSET DG:HEADER
+; MOV AH,STD_CON_STRING_OUTPUT
+; INT 21H
+; POP AX
+
+;----- Check Version Number --------------------------------------------;
+ push ax
+ mov ah,Get_Version
+ int 21h
+ cmp al,2
+ jae vers_ok ; version >= 2, enter editor
+ mov dx,offset dg:bad_vers_err
+ jmp short errj
+;-----------------------------------------------------------------------;
+
+vers_ok:
+
+;----- Process Pathnames -----------------------------------------------;
+
+ mov ax,(char_oper shl 8) ;get switch character
+ int 21h
+ cmp dl,"/"
+ jnz slashok ;if not / , then not PC
+ mov [dirchar],"\" ;in PC, dir separator = \
+ mov [userdir],"\"
+ mov [optchar],"/" ;in PC, option char = /
+
+slashok:
+ mov si,81h ;point to cammand line
+
+ call kill_bl
+ cmp al,13 ;A carriage return?
+ je noname ;yes, file name missing
+
+ mov di,offset dg:fname_buffer
+ xor cx,cx ;zero pathname length
+
+next_char:
+ stosb ;put patname in buffer
+ inc cx
+ lodsb
+ cmp al,' '
+ je xx1
+ cmp al,13 ; a CR ?
+ je name_copied
+ cmp al,[optchar] ; an option character?
+ je an_option
+ jmp short next_char
+
+xx1:
+ dec si
+ call kill_bl
+ cmp al,[optchar]
+ jne name_copied
+
+an_option:
+ lodsb ;get the option
+ cmp al,'B'
+ je b_opt
+ cmp al,'b'
+ je b_opt
+ mov dx,offset dg:opt_err ;bad option specified
+ jmp xerror
+
+b_opt:
+ mov [loadmod],1
+
+name_copied:
+ mov byte ptr dg:[di],0 ;nul terminate the pathname
+
+ if roprot ;***** R/O *****
+;----- Check that file is not R/O --------------------------------------;
+ push cx ;save character count
+ mov dx,offset dg:fname_buffer
+ mov al,0 ;get attributes
+ mov ah,chmod
+ int 21h
+ jc attr_are_ok
+ and cl,00000001b ;mask all but: r/o
+ jz attr_are_ok ;if all = 0 then file ok to edit,
+ mov dg:[roflag],01h ;otherwise: Error (GONG!!!)
+attr_are_ok:
+ pop cx ;restore character count
+ endif
+
+;----- Scan for directory ----------------------------------------------;
+ dec di ;adjust to the end of the pathname
+
+ IF KANJI
+ mov dx,offset dg: fname_buffer
+ PUSH DX
+ PUSH DI
+ MOV BX,DI
+ MOV DI,DX
+DELLOOP:
+ CMP DI,BX
+ Jae GOTDELE
+ MOV AL,[DI]
+ INC DI
+ CALL TESTKANJ
+ JZ NOTKANJ11
+ INC DI
+ JMP DELLOOP
+
+NOTKANJ11:
+ cmp al,dg:[dirchar]
+ JNZ DELLOOP
+ MOV DX,DI ;Point to char after '/'
+ DEC DX
+ DEC DX ;Point to char before '/'
+ JMP DELLOOP
+
+GOTDELE:
+ MOV DI,DX
+ POP AX ;Initial DI
+ POP DX
+ SUB AX,DI ;Distance moved
+ SUB CX,AX ;Set correct CX
+ CMP DX,DI
+ JB sj1 ;Found a pathsep
+ JA sj2 ;Started with a pathsep, root
+ MOV AX,[DI]
+ CALL TESTKANJ
+ JNZ same_dirj
+ XCHG AH,AL
+ cmp al,dg:[dirchar]
+ jz sj1 ;One character directory
+same_dirj:
+ ELSE
+ mov al,dg:[dirchar] ;get directory separator character
+ std ;scan backwards
+ repnz scasb ;(cx has the pathname length)
+ cld ;reset direction, just in case
+ jz sj1
+ ENDIF
+
+ jmp same_dir ;no dir separator char. found, the
+ ; file is in the current directory
+ ; of the corresponding drive. Ergo,
+ ; the FCB contains the data already.
+
+sj1:
+ jcxz sj2 ;no more chars left, it refers to root
+ cmp byte ptr [di],':' ;is the prvious character a disk def?
+ jne not_root
+sj2:
+ mov dg:[the_root],01h ;file is in the root
+not_root:
+ inc di ;point to dir separator char.
+ mov al,0
+ stosb ;nul terminate directory name
+ pop ax
+ push di ;save pointer to file name
+ mov dg:[fudge],01h ;remember that the current directory
+ ; has been changed.
+
+;----- Save current directory for exit ---------------------------------;
+ mov ah,get_default_drive ;save current drive
+ int 21h
+ mov dg:[user_drive],al
+
+ mov dl,byte ptr ds:[fcb] ;get specified drive if any
+ or dl,dl ;default disk?
+ jz same_drive
+ dec dl ;adjust to real drive (a=0,b=1,...)
+ mov ah,set_default_drive ;change disks
+ int 21h
+ cmp al,-1 ;error?
+ jne same_drive
+ mov dx,offset dg:baddrv
+ jmp xerror
+
+same_drive:
+ mov ah,get_default_dpb
+ int 21h
+
+assume ds:nothing
+
+ cmp al,-1 ;bad drive? (should always be ok)
+ jne drvisok
+ mov dx,offset dg:baddrv
+ jmp xerror
+
+drvisok:
+ cmp [bx.dpb_current_dir],0
+ je curr_is_root
+ mov si,bx
+ add si,dpb_dir_text
+ mov di,offset dg:userdir + 1
+
+dir_save_loop:
+ lodsb
+ stosb
+ or al,al
+ jnz dir_save_loop
+
+curr_is_root:
+ push cs
+ pop ds
+
+assume ds:dg
+
+
+;----- Change directories ----------------------------------------------;
+ cmp [the_root],01h
+ mov dx,offset dg:[dirchar] ;assume the root
+ je sj3
+ mov dx,offset dg:[fname_buffer]
+sj3:
+ mov ah,chdir ;change directory
+ int 21h
+ mov dx,offset dg:baddrv
+ jnc no_errors
+ jmp xerror
+no_errors:
+
+;----- Set Up int 24 intercept -----------------------------------------;
+
+ 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
+
+;----- Parse filename to FCB -------------------------------------------;
+ pop si
+ mov di,fcb
+ mov ax,(parse_file_descriptor shl 8) or 1
+ int 21h
+ push ax
+
+;-----------------------------------------------------------------------;
+
+same_dir:
+ pop ax
+ OR AL,AL
+ MOV DX,OFFSET DG:BADDRV
+ jz sj4
+ jmp xerror
+sj4:
+ CMP BYTE PTR DS:[FCB+1]," "
+ jnz sj5
+ jmp noname
+sj5:
+ MOV SI,OFFSET DG:BAK
+ MOV DI,FCB+9
+ MOV CX,3
+ ;File must not have .BAK extension
+ REPE CMPSB
+ JZ NOTBAK
+ ;Open input file
+ MOV AH,FCB_OPEN
+ MOV DX,FCB
+ INT 21H
+ MOV [HAVEOF],AL
+ OR AL,AL
+ JZ HAVFIL
+
+;----- Check that file is not a directory ------------
+ mov ah,fcb_create
+ mov dx,fcb
+ int 21h
+ or al,al
+ jz sj50 ;no error found
+ mov dx,offset dg:bcreat ;creation error
+ jmp xerror
+sj50:
+ mov ah,fcb_close ;no error, close the file
+ mov dx,fcb
+ int 21h
+ mov ah,fcb_delete ;delete the file
+ mov dx,fcb
+ int 21h
+
+;-----------------------------------------------------
+
+ MOV DX,OFFSET DG:NEWFIL
+ MOV AH,STD_CON_STRING_OUTPUT
+ INT 21H
+HAVFIL:
+ MOV SI,FCB
+ MOV DI,OFFSET DG:FCB2
+ MOV CX,9
+ REP MOVSB
+ MOV AL,"$"
+ STOSB
+ STOSB
+ STOSB
+MAKFIL:
+ ;Create .$$$ file to make sure directory has room
+ MOV DX,OFFSET DG:FCB2
+ MOV AH,FCB_CREATE
+ INT 21H
+ OR AL,AL
+ JZ SETUP
+ CMP BYTE PTR [DELFLG],0
+ JNZ NOROOM
+ CALL DELBAK
+ JMP MAKFIL
+NOROOM:
+ MOV DX,OFFSET DG:NODIR
+ JMP xERROR
+NOTBAK:
+ MOV DX,OFFSET DG:NOBAK
+ JMP xERROR
+SETUP:
+ XOR AX,AX
+ MOV WORD PTR DS:[FCB+fcb_RR],AX ;Set RR field to zero
+ MOV WORD PTR DS:[FCB+fcb_RR+2],AX
+ MOV WORD PTR [FCB2+fcb_RR],AX
+ MOV WORD PTR [FCB2+fcb_RR+2],AX
+ INC AX
+ MOV WORD PTR DS:[FCB+fcb_RECSIZ],AX ;Set record length to 1
+ MOV WORD PTR [FCB2+fcb_RECSIZ],AX
+ MOV DX,OFFSET DG:START
+ MOV DI,DX
+ MOV AH,SET_DMA
+ INT 21H
+ MOV CX,DS:[6]
+ DEC CX
+ MOV [LAST],CX
+ TEST BYTE PTR [HAVEOF],-1
+ JNZ SAVEND
+ SUB CX,OFFSET DG:START ;Available memory
+ SHR CX,1 ;1/2 of available memory
+ MOV AX,CX
+ SHR CX,1 ;1/4 of available memory
+ MOV [ONE4TH],CX ;Save amount of 1/4 full
+ ADD CX,AX ;3/4 of available memory
+ MOV DX,CX
+ ADD DX,OFFSET DG:START
+ MOV [THREE4TH],DX ;Save pointer to 3/4 full
+ ;Read in input file
+ MOV DX,FCB
+ MOV AH,FCB_RANDOM_READ_BLOCK
+ mov [amnt_req],cx ;save ammount of chars requested
+ INT 21H
+ CALL SCANEOF
+ ADD DI,CX ;Point to last byte
+SAVEND:
+ CLD
+ MOV BYTE PTR [DI],1AH
+ MOV [ENDTXT],DI
+ MOV BYTE PTR [COMBUF],128
+ MOV BYTE PTR [EDITBUF],255
+ MOV BYTE PTR [EOL],10
+ MOV [POINTER],OFFSET DG:START
+ MOV [CURRENT],1
+ MOV [PARAM1],1
+ TEST BYTE PTR [HAVEOF],-1
+ JNZ COMMAND
+ CALL APPEND
+
+COMMAND:
+ MOV SP, OFFSET DG:STACK
+ MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H
+ MOV DX,OFFSET DG:ABORTCOM
+ INT 21H
+ MOV AL,PROMPT
+ CALL OUT
+ MOV DX,OFFSET DG:COMBUF
+ MOV AH,STD_CON_STRING_INPUT
+ INT 21H
+ MOV [COMLINE],OFFSET DG:COMBUF + 2
+ MOV AL,10
+ CALL OUT
+PARSE:
+ MOV [PARAM2],0
+ MOV [PARAM3],0
+ MOV [PARAM4],0
+ mov [fourth],0 ;reset the fourth parameter flag
+ MOV BYTE PTR [QFLG],0
+ MOV SI,[COMLINE]
+ MOV BP,OFFSET DG:PARAM1
+ XOR DI,DI
+CHKLP:
+ CALL GETNUM
+ MOV [BP+DI],DX
+ INC DI
+ INC DI
+ CALL SKIP1
+ CMP AL,","
+ JNZ CHKNXT
+ INC SI
+CHKNXT:
+ DEC SI
+ CMP DI,8
+ JB CHKLP
+ CALL SKIP
+ CMP AL,"?"
+ JNZ DISPATCH
+ MOV [QFLG],AL
+ CALL SKIP
+DISPATCH:
+ CMP AL,5FH
+ JBE UPCASE
+ AND AL,5FH
+UPCASE:
+ MOV DI,OFFSET DG:COMTAB
+ MOV CX,NUMCOM
+ REPNE SCASB
+ JNZ COMERR
+ MOV BX,CX
+ MOV AX,[PARAM2]
+ OR AX,AX
+ JZ PARMOK
+ CMP AX,[PARAM1]
+ JB COMERR ;Param. 2 must be >= param 1
+PARMOK:
+ MOV [COMLINE],SI
+
+ if roprot ;***** R/O *****
+ cmp [roflag],01 ;file r/o?
+ jne paramok2
+ cmp byte ptr [bx+rotable],01 ;operation allowed?
+ je paramok2
+ mov dx,offset dg:ro_err ;error
+ jmp short comerr1
+paramok2:
+ endif
+
+ SHL BX,1
+ CALL [BX+TABLE]
+COMOVER:
+ MOV SI,[COMLINE]
+ CALL SKIP
+ CMP AL,0DH
+ JZ COMMANDJ
+ CMP AL,1AH
+ JZ DELIM
+ CMP AL,";"
+ JNZ NODELIM
+DELIM:
+ INC SI
+NODELIM:
+ DEC SI
+ MOV [COMLINE],SI
+ JMP PARSE
+
+COMMANDJ:
+ JMP COMMAND
+
+SKIP:
+ LODSB
+SKIP1:
+ CMP AL," "
+ JZ SKIP
+RET1: RET
+
+CHKRANGE:
+ CMP [PARAM2],0
+ JZ RET1
+ CMP BX,[PARAM2]
+ JBE RET1
+COMERR:
+ MOV DX,OFFSET DG:BADCOM
+COMERR1:
+ MOV AH,STD_CON_STRING_OUTPUT
+ INT 21H
+ JMP COMMAND
+
+
+GETNUM:
+ CALL SKIP
+ cmp di,6 ;Is this the fourth parameter?
+ jne sk1
+ mov [fourth],1 ;yes, set the flag
+sk1:
+ CMP AL,"."
+ JZ CURLIN
+ CMP AL,"#"
+ JZ MAXLIN
+ CMP AL,"+"
+ JZ FORLIN
+ CMP AL,"-"
+ JZ BACKLIN
+ MOV DX,0
+ MOV CL,0 ;Flag no parameter seen yet
+NUMLP:
+ CMP AL,"0"
+ JB NUMCHK
+ CMP AL,"9"
+ JA NUMCHK
+ CMP DX,6553 ;Max line/10
+ JAE COMERR ;Ten times this is too big
+ MOV CL,1 ;Parameter digit has been found
+ SUB AL,"0"
+ MOV BX,DX
+ SHL DX,1
+ SHL DX,1
+ ADD DX,BX
+ SHL DX,1
+ CBW
+ ADD DX,AX
+ LODSB
+ JMP SHORT NUMLP
+NUMCHK:
+ CMP CL,0
+ JZ RET1
+ OR DX,DX
+ JZ COMERR ;Don't allow zero as a parameter
+ RET
+
+CURLIN:
+ cmp [fourth],1 ;the fourth parameter?
+ je comerra ;yes, an error
+ MOV DX,[CURRENT]
+ LODSB
+ RET
+MAXLIN:
+ cmp [fourth],1 ;the fourth parameter?
+ je comerra ;yes, an error
+ MOV DX,-2
+ LODSB
+ RET
+FORLIN:
+ cmp [fourth],1 ;the fourth parameter?
+ je comerra ;yes, an error
+ CALL GETNUM
+ ADD DX,[CURRENT]
+ RET
+BACKLIN:
+ cmp [fourth],1 ;the fourth parameter?
+ je comerra ;yes, an error
+ CALL GETNUM
+ MOV BX,[CURRENT]
+ SUB BX,DX
+ jns sk2 ;if below beg of buffer then default to the
+ mov bx,1 ; beg of buffer (line1)
+sk2:
+ MOV DX,BX
+ RET
+
+comerra:
+ jmp comerr
+
+
+COMTAB DB "QTCMWASRDLPIE;",13
+
+NUMCOM EQU $-COMTAB
+
+;-----------------------------------------------------------------------;
+; Carefull changing the order of the next two tables. They are
+; linked and chnges should be be to both.
+
+TABLE DW NOCOM ;No command--edit line
+ DW NOCOM
+ DW ENDED
+ DW INSERT
+ DW PAGE
+ DW LIST
+ DW DELETE
+ dw replac_from_curr ;replace from current+1 line
+ dw search_from_curr ;search from current+1 line
+ DW APPEND
+ DW EWRITE
+ DW MOVE
+ DW COPY
+ DW MERGE
+
+ if roprot ;***** R/O *****
+ DW QUIT1
+ else
+ DW QUIT
+ endif
+
+ if roprot ;***** R/O *****
+;-----------------------------------------------------------------------;
+; If = 1 then the command can be executed with a file that
+; is r/o. If = 0 the command can not be executed, and error.
+
+ROTABLE db 0 ;NOCOM
+ db 0 ;NOCOM
+ db 0 ;ENDED
+ db 0 ;INSERT
+ db 1 ;PAGE
+ db 1 ;LIST
+ db 0 ;DELETE
+ db 0 ;replac_from_curr
+ db 1 ;search_from_curr
+ db 1 ;APPEND
+ db 1 ;EWRITE
+ db 0 ;MOVE
+ db 0 ;COPY
+ db 0 ;MERGE
+ db 1 ;QUIT
+
+;-----------------------------------------------------------------------;
+ endif
+
+ if roprot ;***** R/O *****
+quit1:
+ cmp [roflag],01 ;are we in r/o mode?
+ jne q3 ;no query....
+ MOV DX,OFFSET DG:FCB2 ;yes, quit without query.
+ MOV AH,FCB_CLOSE
+ INT 21H
+ MOV AH,FCB_DELETE
+ INT 21H
+ call rest_dir ;restore directory if needed
+ INT 20H
+q3:
+ call quit
+ endif
+
+SCANEOF:
+ cmp [loadmod],0
+ je sj52
+
+;----- Load till physical end of file
+ cmp cx,word ptr[amnt_req]
+ jb sj51
+ xor al,al
+ inc al ;reset zero flag
+ ret
+sj51:
+ jcxz sj51b
+ push di ;get rid of any ^Z at the end of the file
+ add di,cx
+ dec di ;points to last char
+ cmp byte ptr [di],1ah
+ pop di
+ jne sj51b
+ dec cx
+sj51b:
+ xor al,al ;set zero flag
+ call check_end ;check that we have a CRLF pair at the end
+ ret
+
+;----- Load till first ^Z is found
+sj52:
+ PUSH DI
+ PUSH CX
+ MOV AL,1AH
+ or cx,cx
+ jz not_found ;skip with zero flag set
+ REPNE SCASB ;Scan for end of file mark
+ jnz not_found
+ LAHF ;Save flags momentarily
+ inc cx ;include the ^Z
+ SAHF ;Restore flags
+not_found:
+ mov di,cx ;not found at the end
+ POP CX
+ LAHF ;Save flags momentarily
+ SUB CX,DI ;Reduce byte count if EOF found
+ SAHF ;Restore flags
+ POP DI
+ call check_end ;check that we have a CRLF pair at the end
+
+RET2: RET
+
+
+;-----------------------------------------------------------------------
+; If the end of file was found, then check that the last character
+; in the file is a LF. If not put a CRLF pair in.
+
+check_end:
+ jnz not_end ;end was not reached
+ pushf ;save return flag
+ push di ;save pointer to buffer
+ add di,cx ;points to one past end on text
+ dec di ;points to last character
+ cmp di,offset dg:start
+ je check_no
+ cmp byte ptr[di],0ah ;is a LF the last character?
+ je check_done ;yes, exit
+check_no:
+ mov byte ptr[di+1],0dh ;no, put a CR
+ inc cx ;one more char in text
+ mov byte ptr[di+2],0ah ;put a LF
+ inc cx ;another character at the end
+check_done:
+ pop di
+ popf
+not_end:
+ ret
+
+
+
+NOMOREJ:JMP NOMORE
+
+APPEND:
+ TEST BYTE PTR [HAVEOF],-1
+ JNZ NOMOREJ
+ MOV DX,[ENDTXT]
+ CMP [PARAM1],0 ;See if parameter is missing
+ JNZ PARMAPP
+ CMP DX,[THREE4TH] ;See if already 3/4ths full
+ JAE RET2 ;If so, then done already
+PARMAPP:
+ MOV DI,DX
+ MOV AH,SET_DMA
+ INT 21H
+ MOV CX,[LAST]
+ SUB CX,DX ;Amount of memory available
+ jnz sj53
+ jmp memerr
+sj53:
+ MOV DX,FCB
+ mov [amnt_req],cx ;save ammount of chars requested
+ MOV AH,FCB_RANDOM_READ_BLOCK
+ INT 21H ;Fill memory with file data
+ MOV [HAVEOF],AL
+ PUSH CX ;Save actual byte count
+ CALL SCANEOF
+ JNZ NOTEND
+ MOV BYTE PTR [HAVEOF],1 ;Set flag if 1AH found in file
+NOTEND:
+ XOR DX,DX
+ MOV BX,[PARAM1]
+ OR BX,BX
+ JNZ COUNTLN
+ MOV AX,DI
+ ADD AX,CX ;First byte after loaded text
+ CMP AX,[THREE4TH] ;See if we made 3/4 full
+ JBE COUNTLN
+ MOV DI,[THREE4TH]
+ MOV CX,AX
+ SUB CX,DI ;Length remaining over 3/4
+ MOV BX,1 ;Look for one more line
+COUNTLN:
+ CALL SCANLN ;Look for BX lines
+ CMP [DI-1],AL ;Check for full line
+ JZ FULLN
+ STD
+ DEC DI
+ MOV CX,[LAST]
+ REPNE SCASB ;Scan backwards for last line
+ INC DI
+ INC DI
+ DEC DX
+ CLD
+FULLN:
+ POP CX ;Actual amount read
+ MOV WORD PTR [DI],1AH ;Place EOF after last line
+ SUB CX,DI
+ XCHG DI,[ENDTXT]
+ ADD DI,CX ;Amount of file read but not used
+ SUB WORD PTR DS:[FCB+fcb_RR],DI ;Adjust RR field in case end of file
+ SBB WORD PTR DS:[FCB+fcb_RR+2],0 ; was not reached
+ CMP BX,DX
+ JNZ EOFCHK
+ MOV BYTE PTR [HAVEOF],0
+ RET
+NOMORE:
+ MOV DX,OFFSET DG:EOF
+ MOV AH,STD_CON_STRING_OUTPUT
+ INT 21H
+RET3: RET
+EOFCHK:
+ TEST BYTE PTR [HAVEOF],-1
+ JNZ NOMORE
+ TEST BYTE PTR [ENDING],-1
+ JNZ RET3 ;Suppress memory error during End
+ JMP MEMERR
+
+EWRITE:
+ MOV BX,[PARAM1]
+ OR BX,BX
+ JNZ WRT
+ MOV CX,[ONE4TH]
+ MOV DI,[ENDTXT]
+ SUB DI,CX ;Write everything in front of here
+ JBE RET3
+ CMP DI,OFFSET DG:START ;See if there's anything to write
+ JBE RET3
+ XOR DX,DX
+ MOV BX,1 ;Look for one more line
+ CALL SCANLN
+ JMP SHORT WRTADD
+WRT:
+ INC BX
+ CALL FINDLIN
+WRTADD:
+ CMP BYTE PTR [DELFLG],0
+ JNZ WRTADD1
+ PUSH DI
+ CALL DELBAK ;Want to delete the .BAK file
+ ;as soon as the first write occurs
+ POP DI
+WRTADD1:
+ MOV CX,DI
+ MOV DX,OFFSET DG:START
+ SUB CX,DX ;Amount to write
+ JZ RET3
+ MOV AH,SET_DMA
+ INT 21H
+ MOV DX,OFFSET DG:FCB2
+ MOV AH,FCB_RANDOM_WRITE_BLOCK
+ INT 21H
+ OR AL,AL
+ JNZ WRTERR
+ MOV SI,DI
+ MOV DI,OFFSET DG:START
+ MOV [POINTER],DI
+ MOV CX,[ENDTXT]
+ SUB CX,SI
+ INC CX ;Amount of text remaining
+ REP MOVSB
+ DEC DI ;Point to EOF
+ MOV [ENDTXT],DI
+ MOV [CURRENT],1
+ RET
+
+WRTERR:
+ MOV AH,FCB_CLOSE
+ INT 21H
+ MOV DX,OFFSET DG:DSKFUL
+xERROR:
+ MOV AH,STD_CON_STRING_OUTPUT
+ INT 21H
+;-----------------------------------------------------------------------
+ call rest_dir ;restore to the proper directory
+;-----------------------------------------------------------------------
+ INT 32
+
+RET$5: RET
+
+PAGE:
+ xor bx,bx ;get last line in the buffer
+ call findlin
+ mov [lastlin],dx
+
+ mov bx,[param1]
+ or bx,bx ;was it specified?
+ jnz frstok ;yes, use it
+ mov bx,[current]
+ cmp bx,1 ;if current line =1 start from there
+ je frstok
+ inc bx ;start from current+1 line
+frstok:
+ cmp bx,[lastlin] ;check that we are in the buffer
+ ja ret$5 ;if not just quit
+infile:
+ mov dx,[param2]
+ or dx,dx ;was param2 specified?
+ jnz scndok ;yes,....
+ mov dx,bx ;no, take the end line to be the
+ add dx,22 ; start line + 23
+scndok:
+ inc dx
+ cmp dx,[lastlin] ;check that we are in the buffer
+ jbe infile2
+ mov dx,[lastlin] ;we are not, take the last line as end
+infile2:
+ cmp dx,bx ;is param1 < param2 ?
+ jbe ret$5 ;yes, no backwards listing, quit
+ push dx ;save the end line
+ push bx ;save start line
+ mov bx,dx ;set the current line
+ dec bx
+ call findlin
+ mov [pointer],di
+ mov [current],dx
+ pop bx ;restore start line
+ call findlin ;get pointer to start line
+ mov si,di ;save pointer
+ pop di ;get end line
+ sub di,bx ;number of lines
+ jmp short display
+
+
+LIST:
+ MOV BX,[PARAM1]
+ OR BX,BX
+ JNZ CHKP2
+ MOV BX,[CURRENT]
+ SUB BX,11
+ JA CHKP2
+ MOV BX,1
+CHKP2:
+ CALL FINDLIN
+ JNZ RET7
+ MOV SI,DI
+ MOV DI,[PARAM2]
+ INC DI
+ SUB DI,BX
+ JA DISPLAY
+ MOV DI,23
+ JMP SHORT DISPLAY
+
+
+DISPONE:
+ MOV DI,1
+
+DISPLAY:
+
+; Inputs:
+; BX = Line number
+; SI = Pointer to text buffer
+; DI = No. of lines
+; Function:
+; Ouputs specified no. of line to terminal, each
+; with leading line number.
+; Outputs:
+; BX = Last line output.
+; All registers destroyed.
+
+ MOV CX,[ENDTXT]
+ SUB CX,SI
+ JZ RET7
+ MOV BP,[CURRENT]
+DISPLN:
+ PUSH CX
+ CALL SHOWNUM
+ POP CX
+OUTLN:
+ LODSB
+ CMP AL," "
+ JAE SEND
+ CMP AL,10
+ JZ SEND
+ CMP AL,13
+ JZ SEND
+ CMP AL,9
+ JZ SEND
+ PUSH AX
+ MOV AL,"^"
+ CALL OUT
+ POP AX
+ OR AL,40H
+SEND:
+ CALL OUT
+ CMP AL,10
+ LOOPNZ OUTLN
+ JCXZ RET7
+ INC BX
+ DEC DI
+ JNZ DISPLN
+ DEC BX
+RET7: RET
+
+LOADBUF:
+ MOV DI,2 + OFFSET DG:EDITBUF
+ MOV CX,255
+ MOV DX,-1
+LOADLP:
+ LODSB
+ STOSB
+ INC DX
+ CMP AL,13
+ LOOPNZ LOADLP
+ MOV [EDITBUF+1],DL
+ JZ RET7
+TRUNCLP:
+ LODSB
+ INC DX
+ CMP AL,13
+ JNZ TRUNCLP
+ DEC DI
+ STOSB
+ RET
+
+NOTFNDJ:JMP NOTFND
+
+replac_from_curr:
+ mov byte ptr [srchmod],1 ;search from curr+1 line
+ jmp short sj6
+
+REPLAC:
+ mov byte ptr [srchmod],0 ;search from beg of buffer
+sj6:
+ MOV BYTE PTR [SRCHFLG],0
+ CALL FNDFIRST
+ JNZ NOTFNDJ
+REPLP:
+ MOV SI,[NUMPOS]
+ CALL LOADBUF ;Count length of line
+ SUB DX,[OLDLEN]
+ MOV CX,[NEWLEN]
+ ADD DX,CX ;Length of new line
+ CMP DX,254
+ JA TOOLONG
+ MOV BX,[LSTNUM]
+ PUSH DX
+ CALL SHOWNUM
+ POP DX
+ MOV CX,[LSTFND]
+ MOV SI,[NUMPOS]
+ SUB CX,SI ;Get no. of char on line before change
+ DEC CX
+ CALL OUTCNT ;Output first part of line
+ PUSH SI
+ MOV SI,1+ OFFSET DG:TXT2
+ MOV CX,[NEWLEN]
+ CALL OUTCNT ;Output change
+ POP SI
+ ADD SI,[OLDLEN] ;Skip over old stuff in line
+ MOV CX,DX ;DX=no. of char left in line
+ ADD CX,2 ;Include CR/LF
+ CALL OUTCNT ;Output last part of line
+ CALL QUERY ;Check if change OK
+ JNZ REPNXT
+ CALL PUTCURS
+ MOV DI,[LSTFND]
+ DEC DI
+ MOV SI,1+ OFFSET DG:TXT2
+ MOV DX,[OLDLEN]
+ MOV CX,[NEWLEN]
+ DEC CX
+ ADD [LSTFND],CX ;Bump pointer beyond new text
+ INC CX
+ DEC DX
+ SUB [SRCHCNT],DX ;Old text will not be searched
+ JAE SOMELEFT
+ MOV [SRCHCNT],0
+SOMELEFT:
+ INC DX
+ CALL REPLACE
+REPNXT:
+ CALL FNDNEXT
+ JNZ RET8
+ JMP REPLP
+
+OUTCNT:
+ JCXZ RET8
+OUTLP:
+ LODSB
+ CALL OUT
+ DEC DX
+ LOOP OUTLP
+RET8: RET
+
+TOOLONG:
+ MOV DX,OFFSET DG:TOOLNG
+ JMP SHORT PERR
+
+search_from_curr:
+ mov byte ptr [srchmod],1 ;search from curr+1 line
+ jmp short sj7
+
+SEARCH:
+ mov byte ptr [srchmod],0 ;search from beg of buffer
+sj7:
+ MOV BYTE PTR [SRCHFLG],1
+ CALL FNDFIRST
+ JNZ NOTFND
+SRCH:
+ MOV BX,[LSTNUM]
+ MOV SI,[NUMPOS]
+ CALL DISPONE
+ MOV DI,[LSTFND]
+ MOV CX,[SRCHCNT]
+ MOV AL,10
+ REPNE SCASB
+ JNZ NOTFND
+ MOV [LSTFND],DI
+ MOV [NUMPOS],DI
+ MOV [SRCHCNT],CX
+ INC [LSTNUM]
+ CALL QUERY
+ JZ PUTCURS
+ CALL FNDNEXT
+ JZ SRCH
+NOTFND:
+ MOV DX,OFFSET DG:NOSUCH
+PERR:
+ MOV AH,STD_CON_STRING_OUTPUT
+ INT 21H
+ RET
+
+PUTCURS:
+ MOV BX,[LSTNUM]
+ DEC BX ;Current <= Last matched line
+ CALL FINDLIN
+ MOV [CURRENT],DX
+ MOV [POINTER],DI
+RET9: RET
+
+DELETE:
+ MOV BX,[PARAM1]
+ OR BX,BX
+ JNZ DELFIN1
+ MOV BX,[CURRENT]
+ CALL CHKRANGE
+DELFIN1:
+ CALL FINDLIN
+ JNZ RET9
+ PUSH BX
+ PUSH DI
+ MOV BX,[PARAM2]
+ OR BX,BX
+ JNZ DELFIN2
+ MOV BX,DX
+DELFIN2:
+ INC BX
+ CALL FINDLIN
+ MOV DX,DI
+ POP DI
+ SUB DX,DI
+ JBE COMERRJ
+ POP [CURRENT]
+ MOV [POINTER],DI
+ XOR CX,CX
+ JMP SHORT REPLACE
+
+COMERRJ:JMP COMERR
+
+
+NOCOM:
+ DEC [COMLINE]
+ MOV BX,[PARAM1]
+ OR BX,BX
+ JNZ HAVLIN
+ MOV BX,[CURRENT]
+ INC BX ;Default is current line plus one
+ CALL CHKRANGE
+HAVLIN:
+ CALL FINDLIN
+ MOV SI,DI
+ MOV [CURRENT],DX
+ MOV [POINTER],SI
+ jz sj12
+ ret
+sj12:
+ CMP SI,[ENDTXT]
+ JZ RET12
+ CALL LOADBUF
+ MOV [OLDLEN],DX
+ MOV SI,[POINTER]
+ CALL DISPONE
+ CALL SHOWNUM
+ MOV AH,STD_CON_STRING_INPUT ;Get input buffer
+ MOV DX,OFFSET DG:EDITBUF
+ INT 21H
+ MOV AL,10
+ CALL OUT
+ MOV CL,[EDITBUF+1]
+ MOV CH,0
+ JCXZ RET12
+ MOV DX,[OLDLEN]
+ MOV SI,2 + OFFSET DG:EDITBUF
+;-----------------------------------------------------------------------
+ call unquote ;scan for quote chars if any
+;-----------------------------------------------------------------------
+ MOV DI,[POINTER]
+
+REPLACE:
+
+; Inputs:
+; CX = Length of new text
+; DX = Length of original text
+; SI = Pointer to new text
+; DI = Pointer to old text in buffer
+; Function:
+; New text replaces old text in buffer and buffer
+; size is adjusted. CX or DX may be zero.
+; CX, SI, DI all destroyed. No other registers affected.
+
+ CMP CX,DX
+ JZ COPYIN
+ PUSH SI
+ PUSH DI
+ PUSH CX
+ MOV SI,DI
+ ADD SI,DX
+ ADD DI,CX
+ MOV AX,[ENDTXT]
+ SUB AX,DX
+ ADD AX,CX
+ CMP AX,[LAST]
+ JAE MEMERR
+ XCHG AX,[ENDTXT]
+ MOV CX,AX
+ SUB CX,SI
+ CMP SI,DI
+ JA DOMOV
+ ADD SI,CX
+ ADD DI,CX
+ STD
+DOMOV:
+ INC CX
+
+ REP MOVSB
+ CLD
+ POP CX
+ POP DI
+ POP SI
+COPYIN:
+ REP MOVSB
+RET12: RET
+
+MEMERR:
+ MOV DX,OFFSET DG:MEMFUL
+ MOV AH,STD_CON_STRING_OUTPUT
+ INT 21H
+ JMP COMMAND
+
+MOVERR:
+ MOV DX,OFFSET DG:BADCOM
+ERRORJ:
+ JMP COMERR
+
+MOVE:
+ MOV BYTE PTR [MOVFLG],1
+ JMP SHORT BLKMOVE
+COPY:
+ MOV BYTE PTR [MOVFLG],0
+
+BLKMOVE:
+ MOV BX,[PARAM3] ;Third parameter must be specified
+ OR BX,BX
+ MOV DX,OFFSET DG:DEST
+ JZ ERRORJ
+ MOV BX,[PARAM1] ;Get the first parameter
+ OR BX,BX ;Not specified?
+ JNZ NXTARG
+ MOV BX,[CURRENT] ;Defaults to the current line
+ CALL CHKRANGE
+ MOV [PARAM1],BX ;Save it since current line may change
+ NXTARG:
+ CALL FINDLIN ;Get a pointer to the line
+ MOV [PTR_1],DI ;Save it
+ MOV BX,[PARAM2] ;Get the second parameter
+ OR BX,BX ;Not specified?
+ JNZ HAVARGS
+ MOV BX,[CURRENT] ;Defaults to the current line
+ MOV [PARAM2],BX ;Save it since current line may change
+HAVARGS:
+ ;Parameters must not overlap
+ MOV DX,[PARAM3]
+ CMP DX,[PARAM1]
+ JBE NOERROR
+ CMP DX,[PARAM2]
+ JBE MOVERR
+NOERROR:
+ INC BX ;Get pointer to line Param2+1
+ CALL FINDLIN
+ MOV SI,DI
+ MOV [PTR_2],SI ;Save it
+ MOV CX,DI
+ MOV DI,[PTR_1] ;Restore pointer to line Param1
+ SUB CX,DI ;Calculate number of bytes to copy
+ MOV [COPYSIZ],CX ;Save in COPYSIZ
+ PUSH CX ;And on the stack
+ MOV AX,[PARAM4] ;Is count specified?
+ OR AX,AX
+ JZ MEM_CHECK
+ MUL [COPYSIZ]
+ OR DX,DX
+ JZ COPYSIZ_OK
+ JMP MEMERR
+COPYSIZ_OK:
+ MOV CX,AX
+ MOV [COPYSIZ],CX
+MEM_CHECK:
+ MOV AX,[ENDTXT]
+ MOV DI,[LAST]
+ SUB DI,AX
+ CMP DI,CX
+ JAE HAV_ROOM
+ JMP MEMERR
+HAV_ROOM:
+ MOV BX,[PARAM3]
+ PUSH BX
+ CALL FINDLIN
+ MOV [PTR_3],DI
+ MOV CX,[ENDTXT]
+ SUB CX,DI
+ INC CX
+ MOV SI,[ENDTXT]
+ MOV DI,SI
+ ADD DI,[COPYSIZ]
+ MOV [ENDTXT],DI
+ STD
+ REP MOVSB
+ CLD
+ POP BX
+ CMP BX,[PARAM1]
+ JB GET_PTR_2
+ MOV SI,[PTR_1]
+ JMP SHORT COPY_TEXT
+GET_PTR_2:
+ MOV SI,[PTR_2]
+COPY_TEXT:
+ MOV BX,[PARAM4]
+ MOV DI,[PTR_3]
+ POP CX
+ MOV [COPYSIZ],CX
+COPY_TEXT_1:
+ REP MOVSB
+ DEC BX
+ CMP BX,0
+ JLE MOV_CHK
+ MOV [PARAM4],BX
+ SUB SI,[COPYSIZ]
+ MOV CX,[COPYSIZ]
+ JMP SHORT COPY_TEXT_1
+MOV_CHK:
+ CMP BYTE PTR[MOVFLG],0
+ JZ COPY_DONE
+ MOV DI,[PTR_1]
+ MOV SI,[PTR_2]
+ MOV BX,[PARAM3]
+ CMP BX,[PARAM1]
+ JAE DEL_TEXT
+ ADD DI,[COPYSIZ]
+ ADD SI,[COPYSIZ]
+DEL_TEXT:
+ MOV CX,[ENDTXT]
+ SUB CX,SI
+ REP MOVSB
+ MOV [ENDTXT],DI
+ MOV CX,[PARAM2]
+ SUB CX,[PARAM1]
+ MOV BX,[PARAM3]
+ SUB BX,CX
+ JNC MOVE_DONE
+COPY_DONE:
+ MOV BX,[PARAM3]
+MOVE_DONE:
+ CALL FINDLIN
+ MOV [POINTER],DI
+ MOV [CURRENT],BX
+ RET
+
+
+MOVEFILE:
+ MOV CX,[ENDTXT] ;Get End-of-text marker
+ MOV SI,CX
+ SUB CX,DI ;Calculate number of bytes to copy
+ INC CX
+ MOV DI,DX
+ STD
+ REP MOVSB ;Copy CX bytes
+ XCHG SI,DI
+ CLD
+ INC DI
+ MOV BP,SI
+SETPTS:
+ MOV [POINTER],DI ;Current line is first free loc
+ MOV [CURRENT],BX ; in the file
+ MOV [ENDTXT],BP ;End-of-text is last free loc before
+ RET
+
+NAMERR:
+ JMP COMERR1
+
+
+MERGE:
+ MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 1
+ MOV DI,OFFSET DG:FCB3
+ INT 21H
+ OR AL,AL
+ MOV DX,OFFSET DG:BADDRV
+ JNZ NAMERR
+ MOV [COMLINE],SI
+ MOV DX,OFFSET DG:FCB3
+ MOV AH,FCB_OPEN
+ INT 21H
+ OR AL,AL
+ MOV DX,OFFSET DG:FILENM
+ JNZ NAMERR
+ MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H
+ MOV DX,OFFSET DG:ABORTMERGE
+ INT 21H
+ MOV BX,[PARAM1]
+ OR BX,BX
+ JNZ MRG
+ MOV BX,[CURRENT]
+ CALL CHKRANGE
+MRG:
+ CALL FINDLIN
+ MOV BX,DX
+ MOV DX,[LAST]
+ CALL MOVEFILE
+ ;Set DMA address for reading in new file
+ MOV DX,[POINTER]
+ MOV AH,SET_DMA
+ INT 21H
+ XOR AX,AX
+ MOV WORD PTR DS:[FCB3+fcb_RR],AX
+ MOV WORD PTR DS:[FCB3+fcb_RR+2],AX
+ INC AX
+ MOV WORD PTR DS:[FCB3+fcb_RECSIZ],AX
+ MOV DX,OFFSET DG:FCB3
+ MOV CX,[ENDTXT]
+ SUB CX,[POINTER]
+ MOV AH,FCB_RANDOM_READ_BLOCK
+ INT 21H
+ CMP AL,1
+ JZ FILEMRG
+ MOV DX,OFFSET DG:MRGERR
+ MOV AH,STD_CON_STRING_OUTPUT
+ INT 21H
+ MOV CX,[POINTER]
+ JMP SHORT RESTORE
+FILEMRG:
+ ADD CX,[POINTER]
+ MOV SI,CX
+ DEC SI
+ LODSB
+ CMP AL,1AH
+ JNZ RESTORE
+ DEC CX
+RESTORE:
+ MOV DI,CX
+ MOV SI,[ENDTXT]
+ INC SI
+ MOV CX,[LAST]
+ SUB CX,SI
+ REP MOVSB
+ MOV [ENDTXT],DI
+ MOV BYTE PTR [DI],1AH
+ MOV DX,OFFSET DG:FCB3
+ MOV AH,FCB_CLOSE
+ INT 21H
+ MOV DX,OFFSET DG:START
+ MOV AH,SET_DMA
+ INT 21H
+ RET
+
+
+INSERT:
+ MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H ;Set vector 23H
+ MOV DX,OFFSET DG:ABORTINS
+ INT 21H
+ MOV BX,[PARAM1]
+ OR BX,BX
+ JNZ INS
+ MOV BX,[CURRENT]
+ CALL CHKRANGE
+INS:
+ CALL FINDLIN
+ MOV BX,DX
+ MOV DX,[LAST]
+ CALL MOVEFILE
+INLP:
+ CALL SETPTS ;Update the pointers into file
+ CALL SHOWNUM
+ MOV DX,OFFSET DG:EDITBUF
+ MOV AH,STD_CON_STRING_INPUT
+ INT 21H
+ CALL LF
+ MOV SI,2 + OFFSET DG:EDITBUF
+ CMP BYTE PTR [SI],1AH
+ JZ ENDINS
+;-----------------------------------------------------------------------
+ call unquote ;scan for quote chars if any
+;-----------------------------------------------------------------------
+ MOV CL,[SI-1]
+ MOV CH,0
+ MOV DX,DI
+ INC CX
+ ADD DX,CX
+ JC MEMERRJ1
+ JZ MEMERRJ1
+ CMP DX,BP
+ JB MEMOK
+MEMERRJ1:
+ CALL END_INS
+ JMP MEMERR
+MEMOK:
+ REP MOVSB
+ MOV AL,10
+ STOSB
+ INC BX
+ JMP SHORT INLP
+
+ABORTMERGE:
+ MOV DX,OFFSET DG:START
+ MOV AH,SET_DMA
+ INT 21H
+
+ABORTINS:
+ MOV AX,CS ;Restore segment registers
+ MOV DS,AX
+ MOV ES,AX
+ MOV SS,AX
+ MOV SP,OFFSET DG:STACK
+ STI
+ CALL CRLF
+ CALL ENDINS
+ JMP COMOVER
+
+ENDINS:
+ CALL END_INS
+ RET
+
+END_INS:
+ MOV BP,[ENDTXT]
+ MOV DI,[POINTER]
+ MOV SI,BP
+ INC SI
+ MOV CX,[LAST]
+ SUB CX,BP
+ REP MOVSB
+ DEC DI
+ MOV [ENDTXT],DI
+ MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H
+ MOV DX,OFFSET DG:ABORTCOM
+ INT 21H
+ RET
+
+FILLBUF:
+ MOV [PARAM1],-1 ;Read in max. no of lines
+ CALL APPEND
+ENDED:
+;Write text out to .$$$ file
+ MOV BYTE PTR [ENDING],1 ;Suppress memory errors
+ MOV BX,-1 ;Write max. no of lines
+ CALL WRT
+ TEST BYTE PTR [HAVEOF],-1
+ JZ FILLBUF
+ MOV DX,[ENDTXT]
+ MOV AH,SET_DMA
+ INT 21H
+ MOV CX,1
+ MOV DX,OFFSET DG:FCB2
+ MOV AH,FCB_RANDOM_WRITE_BLOCK
+ INT 21H ;Write end-of-file byte
+;Close .$$$ file
+ MOV AH,FCB_CLOSE
+ INT 21H
+ MOV SI,FCB
+ LEA DI,[SI+fcb_FILSIZ]
+ MOV DX,SI
+ MOV CX,9
+ REP MOVSB
+ MOV SI,OFFSET DG:BAK
+ MOVSW
+ MOVSB
+;Rename original file .BAK
+ MOV AH,FCB_RENAME
+ INT 21H
+ MOV SI,FCB
+ MOV DI,OFFSET DG:FCB2 + fcb_FILSIZ
+ MOV CX,6
+ REP MOVSW
+;Rename .$$$ file to original name
+ MOV DX,OFFSET DG:FCB2
+ INT 21H
+ call rest_dir ;restore directory if needed
+ INT 20H
+
+ABORTCOM:
+ MOV AX,CS
+ MOV DS,AX
+ MOV ES,AX
+ MOV SS,AX
+ MOV SP,OFFSET DG:STACK
+ STI
+ CALL CRLF
+ JMP COMMAND
+
+DELBAK:
+ MOV BYTE PTR [DELFLG],1
+ MOV DI,9+OFFSET DG:FCB2
+ MOV SI,OFFSET DG:BAK
+ MOVSW
+ MOVSB
+ ;Delete old backup file (.BAK)
+ MOV AH,FCB_DELETE
+ MOV DX,OFFSET DG:FCB2
+ INT 21H
+ MOV DI,9+OFFSET DG:FCB2
+ MOV AL,"$"
+ STOSB
+ STOSB
+ STOSB
+ RET
+
+CODE ENDS
+ END EDLIN
+\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a
\ No newline at end of file
--- /dev/null
+\r
+\r
+FALSE EQU 0\r
+TRUE EQU NOT FALSE\r
+\r
+KANJI EQU FALSE\r
+\r
+roprot equ FALSE ;set to TRUE if protection to r/o files\r
+ ; desired.\r
+FCB EQU 5CH\r
+\r
+Comand_Line_Length equ 128\r
+quote_char equ 16h ;quote character = ^V\r
+\r
+\r
+PAGE\r
+\r
+ .xlist\r
+ INCLUDE DOSSYM.ASM\r
+ .list\r
+\r
+\r
+SUBTTL Contants and Data areas\r
+PAGE\r
+\r
+PROMPT EQU "*"\r
+STKSIZ EQU 80H\r
+\r
+CODE SEGMENT PUBLIC\r
+CODE ENDS\r
+\r
+CONST SEGMENT PUBLIC WORD\r
+\r
+ EXTRN TXT1:BYTE,TXT2:BYTE,FUDGE:BYTE,HARDCH:DWORD,USERDIR:BYTE\r
+\r
+CONST ENDS\r
+\r
+DATA SEGMENT PUBLIC WORD\r
+\r
+ EXTRN OLDLEN:WORD,OLDDAT:BYTE,SRCHFLG:BYTE,COMLINE:WORD\r
+ EXTRN PARAM1:WORD,PARAM2:WORD,NEWLEN:WORD,SRCHMOD:BYTE\r
+ EXTRN CURRENT:WORD,POINTER:WORD,START:BYTE,ENDTXT:WORD\r
+ EXTRN USER_DRIVE:BYTE,LSTNUM:WORD,NUMPOS:WORD,LSTFND:WORD\r
+ EXTRN SRCHCNT:WORD\r
+\r
+DATA ENDS\r
+\r
+DG GROUP CODE,CONST,DATA\r
+\r
+CODE SEGMENT PUBLIC\r
+\r
+ASSUME CS:DG,DS:DG,SS:DG,ES:DG\r
+\r
+ PUBLIC REST_DIR,KILL_BL,INT_24,SCANLN,FINDLIN,SHOWNUM\r
+ PUBLIC FNDFIRST,FNDNEXT,CRLF,LF,OUT,UNQUOTE\r
+\r
+ if kanji\r
+ PUBLIC TESTKANJ\r
+ endif\r
+\r
+ EXTRN CHKRANGE:NEAR\r
+\r
+EDLPROC:\r
+\r
+RET1: RET\r
+\r
+FNDFIRST:\r
+ MOV DI,1+OFFSET DG:TXT1\r
+ mov byte ptr[olddat],1 ;replace with old value if none new\r
+ CALL GETTEXT\r
+ OR AL,AL ;Reset zero flag in case CX is zero\r
+ JCXZ RET1\r
+ cmp al,1ah ;terminated with a ^Z ?\r
+ jne sj8\r
+ mov byte ptr[olddat],0 ;do not replace with old value\r
+sj8:\r
+ MOV [OLDLEN],CX\r
+ XOR CX,CX\r
+ CMP AL,0DH\r
+ JZ SETBUF\r
+ CMP BYTE PTR [SRCHFLG],0\r
+ JZ NXTBUF\r
+SETBUF:\r
+ DEC SI\r
+NXTBUF:\r
+ MOV [COMLINE],SI\r
+ MOV DI,1+OFFSET DG:TXT2\r
+ CALL GETTEXT\r
+ CMP BYTE PTR [SRCHFLG],0\r
+ JNZ NOTREPL\r
+ CMP AL,0DH\r
+ JNZ HAVCHR\r
+ DEC SI\r
+HAVCHR:\r
+ MOV [COMLINE],SI\r
+NOTREPL:\r
+ MOV [NEWLEN],CX\r
+ MOV BX,[PARAM1]\r
+ OR BX,BX\r
+ JNZ CALLER\r
+ cmp byte ptr[srchmod],0\r
+ jne sj9\r
+ mov bx,1 ;start from line number 1\r
+ jmp short sj9a\r
+sj9:\r
+ MOV BX,[CURRENT]\r
+ INC BX ;Default search and replace to current+1\r
+sj9a:\r
+ CALL CHKRANGE\r
+CALLER:\r
+ CALL FINDLIN\r
+ MOV [LSTFND],DI\r
+ MOV [NUMPOS],DI\r
+ MOV [LSTNUM],DX\r
+ MOV BX,[PARAM2]\r
+ CMP BX,1\r
+ SBB BX,-1 ;Decrement everything except zero\r
+ CALL FINDLIN\r
+ MOV CX,DI\r
+ SUB CX,[LSTFND]\r
+ OR AL,-1\r
+ JCXZ aret\r
+ CMP CX,[OLDLEN]\r
+ jae sj10\r
+aret: ret\r
+sj10:\r
+ MOV [SRCHCNT],CX\r
+\r
+FNDNEXT:\r
+\r
+; Inputs:\r
+; [TXT1+1] has string to search for\r
+; [OLDLEN] has length of the string\r
+; [LSTFND] has starting position of search in text buffer\r
+; [LSTNUM] has line number which has [LSTFND]\r
+; [SRCHCNT] has length to be searched\r
+; [NUMPOS] has beginning of line which has [LSTFND]\r
+; Outputs:\r
+; Zero flag set if match found\r
+; [LSTFND],[LSTNUM],[SRCHCNT] updated for continuing the search\r
+; [NUMPOS] has beginning of line in which match was made\r
+\r
+ MOV AL,[TXT1+1]\r
+ MOV CX,[SRCHCNT]\r
+ MOV DI,[LSTFND]\r
+SCAN:\r
+ OR DI,DI ;Clear zero flag in case CX=0\r
+ REPNE SCASB\r
+ JNZ RET11\r
+ MOV DX,CX\r
+ MOV BX,DI ;Save search position\r
+ MOV CX,[OLDLEN]\r
+ DEC CX\r
+ MOV SI,2 + OFFSET DG:TXT1\r
+ CMP AL,AL ;Set zero flag in case CX=0\r
+if kanji\r
+ dec si ;Want to look at the first character again\r
+ dec di\r
+kanjchar:\r
+ lodsb\r
+ call testkanj\r
+ jz nxt_kj_char\r
+ xchg ah,al\r
+ lodsb\r
+ mov bx,[di]\r
+ add di,2\r
+ cmp ax,bx\r
+ jnz not_kj_match\r
+ dec cx\r
+ loop kanjchar\r
+nxt_kj_char:\r
+ cmp al,byte ptr[di]\r
+ jnz not_kj_match\r
+ inc di\r
+ loop kanjchar\r
+\r
+not_kj_match:\r
+else\r
+ REPE CMPSB\r
+endif\r
+ MOV CX,DX\r
+ MOV DI,BX\r
+ JNZ SCAN\r
+ MOV [SRCHCNT],CX\r
+ MOV CX,DI\r
+ MOV [LSTFND],DI\r
+ MOV DI,[NUMPOS]\r
+ SUB CX,DI\r
+ MOV AL,10\r
+ MOV DX,[LSTNUM]\r
+;Determine line number of match\r
+GETLIN:\r
+ INC DX\r
+ MOV BX,DI\r
+ REPNE SCASB\r
+ JZ GETLIN\r
+ DEC DX\r
+ MOV [LSTNUM],DX\r
+ MOV [NUMPOS],BX\r
+ XOR AL,AL\r
+RET11: RET\r
+\r
+\r
+GETTEXT:\r
+\r
+; Inputs:\r
+; SI points into command line buffer\r
+; DI points to result buffer\r
+; Function:\r
+; Moves [SI] to [DI] until ctrl-Z (1AH) or\r
+; RETURN (0DH) is found. Termination char not moved.\r
+; Outputs:\r
+; AL = Termination character\r
+; CX = No of characters moved.\r
+; SI points one past termination character\r
+; DI points to next free location\r
+\r
+ XOR CX,CX\r
+\r
+GETIT:\r
+ LODSB\r
+;-----------------------------------------------------------------------\r
+ cmp al,quote_char ;a quote character?\r
+ jne sj101 ;no, skip....\r
+ lodsb ;yes, get quoted character\r
+ call make_cntrl\r
+ jmp short sj102\r
+;-----------------------------------------------------------------------\r
+sj101:\r
+ CMP AL,1AH\r
+ JZ DEFCHK\r
+sj102:\r
+ CMP AL,0DH\r
+ JZ DEFCHK\r
+ STOSB\r
+ INC CX\r
+ JMP SHORT GETIT\r
+\r
+DEFCHK:\r
+ OR CX,CX\r
+ JZ OLDTXT\r
+ PUSH DI\r
+ SUB DI,CX\r
+ MOV BYTE PTR [DI-1],cl\r
+ POP DI\r
+ RET\r
+\r
+OLDTXT:\r
+ cmp byte ptr[olddat],1 ;replace with old text?\r
+ je sj11 ;yes...\r
+ mov byte ptr[di-1],cl ;zero text buffer char count\r
+ ret\r
+\r
+sj11:\r
+ MOV CL,BYTE PTR [DI-1]\r
+ ADD DI,CX\r
+ RET\r
+\r
+\r
+FINDLIN:\r
+\r
+; Inputs\r
+; BX = Line number to be located in buffer (0 means last line)\r
+; Outputs:\r
+; DX = Actual line found\r
+; DI = Pointer to start of line DX\r
+; Zero set if BX = DX\r
+; AL,CX destroyed. No other registers affected.\r
+\r
+ MOV DX,[CURRENT]\r
+ MOV DI,[POINTER]\r
+ CMP BX,DX\r
+ JZ RET4\r
+ JA FINDIT\r
+ OR BX,BX\r
+ JZ FINDIT\r
+ MOV DX,1\r
+ MOV DI,OFFSET DG:START\r
+ CMP BX,DX\r
+ JZ RET4\r
+FINDIT:\r
+ MOV CX,[ENDTXT]\r
+ SUB CX,DI\r
+SCANLN:\r
+ MOV AL,10\r
+ OR AL,AL ;Clear zero flag\r
+FINLIN:\r
+ JCXZ RET4\r
+ REPNE SCASB\r
+ INC DX\r
+ CMP BX,DX\r
+ JNZ FINLIN\r
+RET4: RET\r
+\r
+\r
+SHOWNUM:\r
+\r
+; Inputs:\r
+; BX = Line number to be displayed\r
+; Function:\r
+; Displays line number on terminal in 8-character\r
+; format, suppressing leading zeros.\r
+; AX, CX, DX destroyed. No other registers affected.\r
+\r
+ PUSH BX\r
+ MOV AL," "\r
+ CALL OUT\r
+ CALL CONV10\r
+ MOV AL,":"\r
+ CALL OUT\r
+ MOV AL,"*"\r
+ POP BX\r
+ CMP BX,[CURRENT]\r
+ JZ STARLIN\r
+ MOV AL," "\r
+STARLIN:\r
+ JMP OUT\r
+\r
+\r
+CONV10:\r
+\r
+;Inputs:\r
+; BX = Binary number to be displayed\r
+; Function:\r
+; Ouputs binary number. Five digits with leading\r
+; zero suppression. Zero prints 5 blanks.\r
+\r
+ XOR AX,AX\r
+ MOV DL,AL\r
+ MOV CX,16\r
+CONV:\r
+ SHL BX,1\r
+ ADC AL,AL\r
+ DAA\r
+ XCHG AL,AH\r
+ ADC AL,AL\r
+ DAA\r
+ XCHG AL,AH\r
+ ADC DL,DL\r
+ LOOP CONV\r
+ MOV BL,"0"-" "\r
+ XCHG AX,DX\r
+ CALL LDIG\r
+ MOV AL,DH\r
+ CALL DIGITS\r
+ MOV AL,DL\r
+DIGITS:\r
+ MOV DH,AL\r
+ SHR AL,1\r
+ SHR AL,1\r
+ SHR AL,1\r
+ SHR AL,1\r
+ CALL LDIG\r
+ MOV AL,DH\r
+LDIG:\r
+ AND AL,0FH\r
+ JZ ZERDIG\r
+ MOV BL,0\r
+ZERDIG:\r
+ ADD AL,"0"\r
+ SUB AL,BL\r
+ JMP OUT\r
+\r
+RET5: RET\r
+\r
+\r
+CRLF:\r
+ MOV AL,13\r
+ CALL OUT\r
+LF:\r
+ MOV AL,10\r
+OUT:\r
+ PUSH DX\r
+ XCHG AX,DX\r
+ MOV AH,STD_CON_OUTPUT\r
+ INT 21H\r
+ XCHG AX,DX\r
+ POP DX\r
+ RET\r
+\r
+\r
+;-----------------------------------------------------------------------;\r
+; Will scan buffer given pointed to by SI and get rid of quote\r
+;characters, compressing the line and adjusting the length at the\r
+;begining of the line.\r
+; Preserves al registers except flags and AX .\r
+\r
+unquote:\r
+ push cx\r
+ push di\r
+ push si\r
+ mov di,si\r
+ mov cl,[si-1] ;length of buffer\r
+ xor ch,ch\r
+ mov al,quote_char\r
+ cld\r
+unq_loop:\r
+ jcxz unq_done ;no more chars in the buffer, exit\r
+ repnz scasb ;search for quote character\r
+ jnz unq_done ;none found, exit\r
+ push cx ;save chars left in buffer\r
+ push di ;save pointer to quoted character\r
+ push ax ;save quote character\r
+ mov al,byte ptr[di] ;get quoted character\r
+ call make_cntrl\r
+ mov byte ptr[di],al\r
+ pop ax ;restore quote character\r
+ mov si,di\r
+ dec di ;points to the quote character\r
+ inc cx ;include the carriage return also\r
+ rep movsb ;compact line\r
+ pop di ;now points to after quoted character\r
+ pop cx\r
+ jcxz sj13 ;if quote char was last of line do not adjust\r
+ dec cx ;one less char left in the buffer\r
+sj13: pop si\r
+ dec byte ptr[si-1] ;one less character in total buffer count also\r
+ push si\r
+ jmp short unq_loop\r
+\r
+unq_done:\r
+ pop si\r
+ pop di\r
+ pop cx\r
+ ret\r
+\r
+\r
+;-----------------------------------------------------------------------;\r
+; Convert the character in AL to the corresponding control\r
+; character. AL has to be between @ and _ to be converted. That is,\r
+; it has to be a capital letter. All other letters are left unchanged.\r
+\r
+make_cntrl:\r
+ push ax\r
+ and ax,11100000b\r
+ cmp ax,01000000b\r
+ pop ax\r
+ jne sj14\r
+ and ax,00011111b\r
+sj14:\r
+ ret\r
+\r
+\r
+;---- Kill spaces in buffer --------------------------------------------;\r
+kill_bl:\r
+ lodsb ;get rid of blanks\r
+ cmp al,' '\r
+ je kill_bl\r
+ ret\r
+\r
+\r
+;----- Restore INT 24 vector and old current directory -----------------;\r
+rest_dir:\r
+ cmp [fudge],0\r
+ je no_fudge\r
+\r
+ mov ax,(set_interrupt_vector shl 8) or 24h\r
+ lds dx,[hardch]\r
+ int 21h\r
+ push cs\r
+ pop ds\r
+\r
+ mov dx,offset dg:userdir ;restore directory\r
+ mov ah,chdir\r
+ int 21h\r
+ mov dl,[user_drive] ;restore old current drive\r
+ mov ah,set_default_drive\r
+ int 21h\r
+\r
+no_fudge:\r
+ ret\r
+\r
+;----- INT 24 Processing -----------------------------------------------;\r
+\r
+int_24_retaddr dw offset dg:int_24_back\r
+\r
+int_24 proc far\r
+assume ds:nothing,es:nothing,ss:nothing\r
+\r
+ pushf\r
+ push cs\r
+ push [int_24_retaddr]\r
+ push word ptr [hardch+2]\r
+ push word ptr [hardch]\r
+ ret\r
+int_24 endp\r
+\r
+int_24_back:\r
+ cmp al,2 ;abort?\r
+ jnz ireti\r
+ push cs\r
+ pop ds\r
+\r
+assume ds:dg\r
+\r
+ call rest_dir\r
+ int 20h\r
+ireti:\r
+ iret\r
+\r
+ IF KANJI\r
+TESTKANJ:\r
+ CMP AL,81H\r
+ JB NOTLEAD\r
+ CMP AL,9FH\r
+ JBE ISLEAD\r
+ CMP AL,0E0H\r
+ JB NOTLEAD\r
+ CMP AL,0FCH\r
+ JBE ISLEAD\r
+NOTLEAD:\r
+ PUSH AX\r
+ XOR AX,AX ;Set zero\r
+ POP AX\r
+ RET\r
+\r
+ISLEAD:\r
+ PUSH AX\r
+ XOR AX,AX ;Set zero\r
+ INC AX ;Reset zero\r
+ POP AX\r
+ RET\r
+ ENDIF\r
+\r
+;-----------------------------------------------------------------------;\r
+\r
+CODE ENDS\r
+ END EDLPROC\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\r
+\r
+\1a
\ No newline at end of file
--- /dev/null
+ title LOCATE (EXE2BIN)\r
+\r
+;Loader for EXE files under 86-DOS\r
+\r
+;The following switch allows use with the "old linker", which put a version\r
+;number where the new linker puts the number of bytes used in the last page.\r
+;If enabled, this will cause a test for 0004 at this location (the old linker\r
+;version number), and if equal, change it to 200H so all of the last page\r
+;will be used.\r
+\r
+;VER. 1.5\r
+; 05/21/82 Added rev number\r
+;\r
+;VER. 1.6\r
+; 07/01/82 A little less choosy about size matches\r
+;\r
+;VER. 2.0 Rev. 1 M.A.Ulloa\r
+; 10/08/82 Modified to use new 2.0 system calls for file i/o\r
+;\r
+; Rev. 2 M.A.Ulloa\r
+; 10/27/82 Added the DOS version check\r
+\r
+FALSE EQU 0\r
+TRUE EQU NOT FALSE\r
+\r
+OLDLINK EQU 0 ;1 to enable, 0 to disable\r
+\r
+ .xlist\r
+ INCLUDE DOSSYM.ASM\r
+ .list\r
+\r
+\r
+ subttl Main Code Area\r
+ page\r
+\r
+\r
+code segment byte\r
+code ends\r
+\r
+DATA SEGMENT PUBLIC BYTE\r
+\r
+\r
+ EXTRN bad_vers_err:BYTE,NOTFND:BYTE,NOROOM:BYTE,DIRFULL:BYTE\r
+ EXTRN CANTFIX:BYTE,RDBAD:BYTE,FULL:BYTE,PROMPT:BYTE,CRLF:BYTE\r
+\r
+make db "MAUlloa/Microsoft/V20"\r
+rev db "2"\r
+\r
+file1_ext db ".EXE",00h\r
+file2_ext db ".BIN",00h\r
+\r
+per1 db 0\r
+per2 db 0\r
+\r
+file1 db 64 dup(?)\r
+handle1 dw 1 dup(?)\r
+\r
+file2 db 64 dup(?)\r
+handle2 dw 1 dup(?)\r
+\r
+\r
+INBUF DB 5,0\r
+ DB 5 DUP(?)\r
+\r
+;The following locations must be defined for storing the header:\r
+\r
+RUNVAR LABEL BYTE ;Start of RUN variables\r
+RELPT DW ?\r
+LASTP LABEL WORD\r
+RELSEG DW ?\r
+SIZ LABEL WORD ;Share these locations\r
+PAGES DW ?\r
+RELCNT DW ?\r
+HEADSIZ DW ?\r
+ DW ?\r
+LOADLOW DW ?\r
+INITSS DW ?\r
+INITSP DW ?\r
+ DW ?\r
+INITIP DW ?\r
+INITCS DW ?\r
+RELTAB DW ?\r
+RUNVARSIZ EQU $-RUNVAR\r
+\r
+DATA ENDS\r
+\r
+STACK SEGMENT WORD STACK\r
+ DB 80H DUP (?)\r
+STACK ENDS\r
+\r
+ZLOAD SEGMENT\r
+ZLOAD ENDS\r
+LOAD EQU ZLOAD\r
+\r
+CODE SEGMENT BYTE\r
+\r
+ ASSUME CS:CODE\r
+\r
+LOCATE PROC FAR\r
+ JMP SHORT LOCSTRT\r
+\r
+HEADER DB "Vers 2.00"\r
+\r
+LOCSTRT:\r
+ MOV SI,81H\r
+ PUSH DS\r
+ XOR AX,AX\r
+ PUSH AX ;Push return address to DS:0\r
+\r
+;Code to print header\r
+; PUSH DS\r
+; MOV DX,DATA\r
+; MOV DS,DX\r
+; MOV DX,OFFSET HEADER\r
+; MOV AH,STD_CON_STRING_OUTPUT\r
+; INT 21H\r
+; POP DS\r
+\r
+;----- Check Version Number --------------------------------------------;\r
+ mov ah,Get_Version\r
+ int 21h\r
+ cmp al,2\r
+ jge vers_ok ; version >= 2, enter locate\r
+ push ds\r
+ mov dx,data\r
+ mov ds,dx\r
+ mov dx,offset bad_vers_err\r
+ MOV AH,STD_CON_STRING_OUTPUT\r
+ INT 21H\r
+ pop ds\r
+ ret ;long return to DOS\r
+\r
+;-----------------------------------------------------------------------;\r
+vers_ok:\r
+\r
+\r
+ MOV BX,WORD PTR DS:2 ;Get size of memory\r
+ MOV DX,DATA\r
+ MOV ES,DX\r
+\r
+ assume es:data\r
+\r
+;-----------------------------------------------------------------------;\r
+\r
+;----- Get the first file name\r
+ call kill_bl\r
+ jnc sj01\r
+ mov ds,dx\r
+ jmp bad_file\r
+sj01:\r
+ mov di,offset file1\r
+sj0:\r
+ lodsb ;get character of file name\r
+ cmp al,' '\r
+ je sj2\r
+ cmp al,0dh\r
+ je sj2\r
+ cmp al,'.' ;an extension separator found?\r
+ jne sj1\r
+ mov es:[per1],-1\r
+sj1:\r
+ stosb\r
+ jmp short sj0\r
+sj2:\r
+ dec si\r
+ mov byte ptr es:[di],00h ;nul terminate the filename\r
+ call kill_bl\r
+ jc no_second\r
+\r
+;----- Get the second file name\r
+ mov di,offset file2\r
+sj3:\r
+ lodsb ;get character of file name\r
+ cmp al,' '\r
+ je sj5\r
+ cmp al,0dh\r
+ je sj5\r
+ cmp al,'.' ;an extension separator found?\r
+ jne sj4\r
+ mov es:[per2],-1\r
+sj4:\r
+ stosb\r
+ jmp short sj3\r
+sj5:\r
+ mov byte ptr es:[di],00h ;nul terminate\r
+ jmp short check_ext\r
+\r
+;----- Copy file1 to file2\r
+no_second:\r
+ mov ds,dx\r
+\r
+ assume ds:data\r
+\r
+ mov si,offset file1\r
+ mov di,offset file2\r
+sj6:\r
+ lodsb\r
+ cmp al,'.'\r
+ je sj7\r
+ cmp al,00h\r
+ je sj7\r
+ stosb\r
+ jmp short sj6\r
+sj7:\r
+ mov byte ptr [di],00h\r
+\r
+;----- Check that files have an extension, otherwise set default\r
+check_ext:\r
+ mov ds,dx\r
+\r
+ assume ds:data\r
+\r
+ cmp [per1],-1\r
+ je file1_ok\r
+ mov si,offset file1\r
+sj8:\r
+ lodsb\r
+ cmp al,00h\r
+ jne sj8\r
+ mov di,si\r
+ mov si,offset file1_ext\r
+ call put_ext\r
+\r
+file1_ok:\r
+ cmp [per2],-1\r
+ je file2_ok\r
+ mov si,offset file2\r
+sj9:\r
+ lodsb\r
+ cmp al,00h\r
+ jne sj9\r
+ mov di,si\r
+ mov si,offset file2_ext\r
+ call put_ext\r
+ jmp short file2_ok\r
+\r
+;----- Fill in the default extent\r
+put_ext proc near\r
+ dec di\r
+ mov cx,5 ;move extent: period,extent,null\r
+ rep movsb\r
+ ret\r
+put_ext endp\r
+\r
+;----- Find the first non-blank\r
+kill_bl proc near\r
+ cld\r
+sj10:\r
+ lodsb\r
+ cmp al,' '\r
+ je sj10\r
+ dec si\r
+ cmp al,0dh\r
+ clc\r
+ jne sj11\r
+ stc\r
+sj11:\r
+ ret\r
+kill_bl endp\r
+\r
+file2_ok:\r
+\r
+;-----------------------------------------------------------------------;\r
+\r
+ mov dx,offset file1\r
+ mov ah,open\r
+ mov al,0 ;ror reading only\r
+ INT 21H ;Open input file\r
+ jc bad_file\r
+ mov [handle1],ax\r
+ jmp exeload\r
+\r
+bad_file:\r
+ MOV DX,OFFSET NOTFND\r
+xERROR:\r
+ MOV AH,STD_CON_STRING_OUTPUT\r
+ INT 21H\r
+ RET ;FAR return to MS-DOS\r
+TOOBIG:\r
+ MOV DX,OFFSET NOROOM\r
+ JMP xERROR\r
+BADEXE:\r
+ MOV DX,OFFSET CANTFIX\r
+ERRORJ: JMP xERROR\r
+\r
+EXELOAD:\r
+ MOV DX,OFFSET RUNVAR ;Read header in here\r
+ MOV CX,RUNVARSIZ ;Amount of header info we need\r
+ push bx\r
+ mov bx,[handle1]\r
+ MOV AH,read\r
+ INT 21H ;Read in header\r
+ pop bx\r
+ CMP [RELPT],5A4DH ;Check signature word\r
+ JNZ BADEXE\r
+ MOV AX,[HEADSIZ] ;size of header in paragraphs\r
+ ADD AX,31 ;Round up first\r
+ CMP AX,1000H ;Must not be >=64K\r
+ JAE TOOBIG\r
+ AND AX,NOT 31\r
+ MOV CL,4\r
+ SHL AX,CL ;Header size in bytes\r
+\r
+ push dx\r
+ push cx\r
+ push ax\r
+ push bx\r
+ mov dx,ax\r
+ xor cx,cx\r
+ mov al,0\r
+ mov bx,[handle1]\r
+ mov ah,lseek\r
+ int 21h\r
+ pop bx\r
+ pop ax\r
+ pop cx\r
+ pop dx\r
+\r
+ XCHG AL,AH\r
+ SHR AX,1 ;Convert to pages\r
+ MOV DX,[PAGES] ;Total size of file in 512-byte pages\r
+ SUB DX,AX ;Size of program in pages\r
+ CMP DX,80H ;Fit in 64K?\r
+ JAE TOOBIG\r
+ XCHG DH,DL\r
+ SHL DX,1 ;Convert pages to bytes\r
+ MOV AX,[LASTP] ;Get count of bytes in last page\r
+ OR AX,AX ;If zero, use all of last page\r
+ JZ WHOLEP\r
+\r
+ IF OLDLINK\r
+ CMP AX,4 ;Produced by old linker?\r
+ JZ WHOLEP ;If so, use all of last page too\r
+ ENDIF\r
+\r
+ SUB DX,200H ;Subtract last page\r
+ ADD DX,AX ;Add in byte count for last page\r
+WHOLEP:\r
+ MOV [SIZ],DX\r
+ ADD DX,15\r
+ SHR DX,CL ;Convert bytes to paragraphs\r
+ MOV BP,LOAD\r
+ ADD DX,BP ;Size + start = minimum memory (paragr.)\r
+ CMP DX,BX ;Enough memory?\r
+ JA TOOBIG\r
+ MOV DX,OFFSET CANTFIX\r
+ MOV AX,[INITSS]\r
+ OR AX,[INITSP]\r
+ OR AX,[INITCS]\r
+ERRORNZ:\r
+ jz xj\r
+ JMP ERRORJ ;Must not have SS, SP, or CS to init.\r
+xj: MOV AX,[INITIP]\r
+ OR AX,AX ;If IP=0, do binary fix\r
+ JZ BINFIX\r
+ CMP AX,100H ;COM file must be set up for CS:100\r
+ JNZ ERRORNZ\r
+\r
+ push dx\r
+ push cx\r
+ push ax\r
+ push bx\r
+ mov dx,100h ;chop off first 100h\r
+ xor cx,cx\r
+ mov al,1 ;seek from current position\r
+ mov bx,[handle1]\r
+ mov ah,lseek\r
+ int 21h\r
+ pop bx\r
+ pop ax\r
+ pop cx\r
+ pop dx\r
+\r
+ SUB [SIZ],AX ;And count decreased size\r
+ CMP [RELCNT],0 ;Must have no fixups\r
+ JNZ ERRORNZ\r
+BINFIX:\r
+ XOR BX,BX ;Initialize fixup segment\r
+;See if segment fixups needed\r
+ CMP [RELCNT],0\r
+ JZ LOADEXE\r
+GETSEG:\r
+ MOV DX,OFFSET PROMPT\r
+ MOV AH,STD_CON_STRING_OUTPUT\r
+ INT 21H\r
+ MOV AH,STD_CON_STRING_INPUT\r
+ MOV DX,OFFSET INBUF\r
+ INT 21H ;Get user response\r
+ MOV DX,OFFSET CRLF\r
+ MOV AH,STD_CON_STRING_OUTPUT\r
+ INT 21H\r
+ MOV SI,OFFSET INBUF+2\r
+ MOV BYTE PTR [SI-1],0 ;Any digits?\r
+ JZ GETSEG\r
+DIGLP:\r
+ LODSB\r
+ SUB AL,"0"\r
+ JC DIGERR\r
+ CMP AL,10\r
+ JB HAVDIG\r
+ AND AL,5FH ;Convert to upper case\r
+ SUB AL,7\r
+ CMP AL,10\r
+ JB DIGERR\r
+ CMP AL,10H\r
+ JAE DIGERR\r
+HAVDIG:\r
+ SHL BX,1\r
+ SHL BX,1\r
+ SHL BX,1\r
+ SHL BX,1\r
+ OR BL,AL\r
+ JMP DIGLP\r
+\r
+DIGERR:\r
+ CMP BYTE PTR [SI-1],0DH ;Is last char. a CR?\r
+ JNZ GETSEG\r
+LOADEXE:\r
+ XCHG BX,BP ;BX has LOAD, BP has fixup\r
+\r
+ MOV CX,[SIZ]\r
+ MOV AH,read\r
+ push di\r
+ mov di,[handle1]\r
+ PUSH DS\r
+ MOV DS,BX\r
+ XOR DX,DX\r
+ push bx\r
+ mov bx,di\r
+ INT 21H ;Read in up to 64K\r
+ pop bx\r
+ POP DS\r
+ pop di\r
+ Jnc HAVEXE ;Did we get it all?\r
+ MOV DX,OFFSET RDBAD\r
+ jmp xERROR ;Non fatal, print warning\r
+HAVEXE:\r
+ CMP [RELCNT],0 ;Any fixups to do?\r
+ JZ STORE\r
+ MOV AX,[RELTAB] ;Get position of table\r
+\r
+ push dx\r
+ push cx\r
+ push ax\r
+ push bx\r
+ mov dx,ax\r
+ xor cx,cx\r
+ mov al,0\r
+ mov bx,[handle1]\r
+ mov ah,lseek\r
+ int 21h\r
+ pop bx\r
+ pop ax\r
+ pop cx\r
+ pop dx\r
+\r
+ MOV DX,OFFSET RELPT ;4-byte buffer for relocation address\r
+RELOC:\r
+ MOV DX,OFFSET RELPT ;4-byte buffer for relocation address\r
+ MOV CX,4\r
+ MOV AH,read\r
+ push bx\r
+ mov bx,[handle1]\r
+ INT 21H ;Read in one relocation pointer\r
+ pop bx\r
+ Jnc RDCMP\r
+ JMP BADEXE\r
+RDCMP:\r
+ MOV DI,[RELPT] ;Get offset of relocation pointer\r
+ MOV AX,[RELSEG] ;Get segment\r
+ ADD AX,BX ;Bias segment with actual load segment\r
+ MOV ES,AX\r
+ ADD ES:[DI],BP ;Relocate\r
+ DEC [RELCNT] ;Count off\r
+ JNZ RELOC\r
+STORE:\r
+ MOV AH,CREAT\r
+ MOV DX,OFFSET file2\r
+ xor cx,cx\r
+ INT 21H\r
+ Jc MKERR\r
+ mov [handle2],ax\r
+ MOV CX,[SIZ]\r
+ MOV AH,write\r
+ push di\r
+ mov di,[handle2]\r
+ PUSH DS\r
+ MOV DS,BX\r
+ XOR DX,DX ;Address 0 in segment\r
+ push bx\r
+ mov bx,di\r
+ INT 21H\r
+ pop bx\r
+ POP DS\r
+ pop di\r
+ Jc WRTERR ;Must be zero if more to come\r
+ MOV AH,CLOSE\r
+ push bx\r
+ mov bx,[handle2]\r
+ INT 21H\r
+ pop bx\r
+ RET\r
+\r
+WRTERR:\r
+ MOV DX,OFFSET FULL\r
+ JMP xERROR\r
+MKERR:\r
+ MOV DX,OFFSET DIRFULL\r
+ JMP xERROR\r
+\r
+LOCATE ENDP\r
+CODE ENDS\r
+ END LOCATE\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+SUBTTL $exec - load/go a program
+PAGE
+;
+; Assembler usage:
+; LDS DX, name
+; LES BX, blk
+; MOV AH, Exec
+; MOV AL, func
+; INT int_command
+;
+; AL Function
+; -- --------
+; 0 Load and execute the program.
+; 1 Load, create the program header but do not
+; begin execution.
+; 3 Load overlay. No header created.
+;
+; AL = 0 -> load/execute program
+;
+; +---------------------------+
+; | WORD segment address of |
+; | environment. |
+; +---------------------------+
+; | DWORD pointer to ASCIZ |
+; | command line at 80h |
+; +---------------------------+
+; | DWORD pointer to default |
+; | FCB to be passed at 5Ch |
+; +---------------------------+
+; | DWORD pointer to default |
+; | FCB to be passed at 6Ch |
+; +---------------------------+
+;
+; AL = 1 -> load program
+;
+; +---------------------------+
+; | WORD segment address of |
+; | environment. |
+; +---------------------------+
+; | DWORD pointer to ASCIZ |
+; | command line at 80h |
+; +---------------------------+
+; | DWORD pointer to default |
+; | FCB to be passed at 5Ch |
+; +---------------------------+
+; | DWORD pointer to default |
+; | FCB to be passed at 6Ch |
+; +---------------------------+
+; | DWORD returned value of |
+; | CS:IP |
+; +---------------------------+
+; | DWORD returned value of |
+; | SS:IP |
+; +---------------------------+
+;
+; AL = 3 -> load overlay
+;
+; +---------------------------+
+; | WORD segment address where|
+; | file will be loaded. |
+; +---------------------------+
+; | WORD relocation factor to |
+; | be applied to the image. |
+; +---------------------------+
+;
+; Returns:
+; AX = exec_invalid_function
+; = exec_bad_format
+; = exec_bad_environment
+; = exec_not_enough_memory
+; = exec_file_not_found
+;
+
+IF IBM
+ZEXEC_DATA SEGMENT PUBLIC BYTE
+ZERO = $
+ENDIF
+
+exec_blk DD ?
+exec_func DB ?
+exec_fh DW ?
+exec_rel_fac DW ?
+exec_res_len_para DW ?
+exec_init_IP DW ?
+exec_init_CS DW ?
+exec_init_SP DW ?
+exec_init_SS DW ?
+exec_environ DW ?
+exec_size DW ?
+exec_load_block DW ?
+
+exec_load_high DB ?
+
+exec_internal_buffer EQU $
+exec_signature DW ? ; must contain 4D5A (yay zibo!)
+exec_len_mod_512 DW ? ; low 9 bits of length
+exec_pages DW ? ; number of 512b pages in file
+exec_rle_count DW ? ; count of reloc entries
+exec_par_dir DW ? ; number of paragraphs before image
+exec_min_BSS DW ? ; minimum number of para of BSS
+exec_max_BSS DW ? ; max number of para of BSS
+exec_SS DW ? ; stack of image
+exec_SP DW ? ; SP of image
+exec_chksum DW ? ; checksum of file (ignored)
+exec_IP DW ? ; IP of entry
+exec_CS DW ? ; CS of entry
+exec_rle_table DW ? ; byte offset of reloc table
+exec_iov DW ? ; overlay number (0 for root)
+exec_dma DW ?
+exec_internal_buffer_size EQU $-exec_internal_buffer
+
+IF IBM
+exec_ctrlc DB ? ; state of users ctrlc flag
+Exec_low_seg DW ?
+CurrentPDB DW ?
+NUMIO DB ?
+ZEXECDATASIZ = $-ZERO
+ZEXECDATAEND LABEL BYTE
+ PUBLIC ZEXECDATAEND
+ZEXEC_DATA ENDS
+ZEXEC_CODE SEGMENT PUBLIC PARA
+ PUBLIC $EXEC
+ZERO = $
+ procedure $EXEC,FAR
+ ASSUME CS:EGROUP,SS:RESGROUP,ES:NOTHING,DS:NOTHING
+ENDIF
+IF NOT IBM
+ procedure $Exec,NEAR
+ ASSUME DS:NOTHING, ES:NOTHING
+ENDIF
+;
+; validate function
+;
+
+IF IBM
+ PUSH CS
+ POP DS
+ ASSUME DS:EGROUP
+
+ MOV AX,(Set_Ctrl_C_Trapping SHL 8) + 0 ; Save current ctrl-c
+ INT int_command
+ MOV exec_ctrlc,DL
+ XOR DX,DX
+ MOV AX,(Set_Ctrl_C_Trapping SHL 8) + 1 ; Turn it off!
+ INT int_command
+
+ MOV AH,Get_current_PDB
+ INT int_command
+ MOV [CurrentPDB],BX
+;
+; set up user return stack info
+;
+ MOV ES,BX
+ LES BX,DWORD PTR [user_sp]
+ MOV WORD PTR ES:[PDB_user_stack+2],ES
+ MOV WORD PTR ES:[PDB_user_stack],BX
+
+ MOV AH,Get_Default_Drive
+ INT int_command
+ MOV DL,AL
+ MOV AH,Set_default_drive
+ INT int_command
+ MOV [NUMIO],AL
+;
+; determine lowest seg address for overwrite problem (round DOWN)
+;
+ MOV CL,4
+ MOV AX,OFFSET ZEXEC_CODE:exec_check
+ SHR AX,CL
+ PUSH CS
+ POP BX
+ ADD AX,BX
+ MOV [exec_low_seg],AX
+
+ CALL get_user_stack
+ ASSUME DS:NOTHING
+ MOV AX,[SI.user_AX]
+ MOV BX,[SI.user_BX]
+ MOV DX,[SI.user_DX]
+ MOV ES,[SI.user_ES]
+ MOV DS,[SI.user_DS]
+ENDIF
+
+ CMP AL,3 ; only 0, 1 or 3 are allowed
+ JNA exec_check_2
+
+exec_bad_fun:
+ error error_invalid_function
+
+exec_ret_err:
+ transfer SYS_RET_ERR
+
+exec_check_2:
+ CMP AL,2
+ JZ exec_bad_fun
+
+ MOV WORD PTR [exec_blk],BX ; stash args
+ MOV WORD PTR [exec_blk+2],ES
+ MOV BYTE PTR [exec_func],AL
+ MOV BYTE PTR [exec_load_high],0
+IF IBM
+ MOV AX,(OPEN SHL 8) + 0
+ INT int_command
+ENDIF
+IF NOT IBM
+ XOR AL,AL ; open for reading
+ invoke $OPEN ; is the file there?
+ENDIF
+ JC exec_ret_err
+ MOV [exec_fh],AX
+ MOV BX,AX
+IF IBM
+ MOV AX,(ioctl SHL 8) ; get device information
+ INT int_command
+ENDIF
+IF NOT IBM
+ XOR AL,AL
+ invoke $IOCTL
+ENDIF
+ TEST DL,devid_ISDEV
+ JZ exec_check_environ
+ MOV AL,exec_file_not_found
+ transfer SYS_RET_ERR
+
+exec_check_environ:
+ MOV [exec_load_block],0
+
+ TEST BYTE PTR [exec_func],exec_func_overlay ; overlays... no environment
+ JNZ exec_read_header
+ LDS SI,DWORD PTR [exec_blk] ; get block
+ MOV AX,[SI].Exec1_environ ; address of environ
+ OR AX,AX
+ JNZ exec_scan_env
+ MOV DS,[CurrentPDB]
+ MOV AX,DS:[PDB_environ]
+ MOV [exec_environ],AX
+ OR AX,AX
+ JZ exec_read_header
+
+exec_scan_env:
+ CLD
+ MOV ES,AX
+ XOR DI,DI
+ MOV CX,07FFFh ; at most 32k of environment
+ XOR AL,AL
+
+exec_get_environ_len:
+ REPNZ SCASB ; find that nul byte
+ JZ exec_check ; CX is out... bad environment
+ MOV AL,exec_bad_environment
+ JMP exec_bomb
+
+exec_check:
+ SCASB ; is there another nul byte?
+ JNZ exec_get_environ_len ; no, scan some more
+ PUSH DI
+ MOV BX,DI ; AX <- length of environment
+ ADD BX,0Fh
+ MOV CL,4
+ SHR BX,CL ; number of paragraphs needed
+ PUSH ES
+IF IBM
+ MOV AH,ALLOC
+ INT int_command
+ENDIF
+IF NOT IBM
+ invoke $ALLOC ; can we get the space?
+ENDIF
+ POP DS
+ POP CX
+ JNC exec_save_environ
+ JMP exec_no_mem ; nope... cry and sob
+
+exec_save_environ:
+ MOV ES,AX
+ MOV [exec_environ],AX ; save him for a rainy day
+IF IBM
+ PUSH CX
+ MOV CX,ES
+ ADD CX,BX
+ CMP BX,[exec_low_seg]
+ POP CX
+ JA exec_no_mem
+ENDIF
+ XOR SI,SI
+ XOR DI,DI
+ REP MOVSB ; copy the environment
+
+exec_read_header:
+;
+; We read in the program header into the above data area and determine
+; where in this memory the image will be located.
+;
+IF IBM
+ PUSH CS
+ POP DS ; and put it in DS:DX
+ ASSUME DS:EGROUP
+ENDIF
+IF NOT IBM
+ PUSH SS
+ POP DS ; and put it in DS:DX
+ ASSUME DS:DOSGROUP
+ENDIF
+ MOV CX,exec_internal_buffer_size; header size
+ MOV BX,[exec_fh] ; from the handle
+IF IBM
+ MOV DX,OFFSET EGROUP:exec_signature
+ENDIF
+IF NOT IBM
+ MOV DX,OFFSET DOSGROUP:exec_signature
+ENDIF
+ PUSH ES
+ PUSH DS
+ CALL exec_dealloc
+IF IBM
+ MOV AH,READ
+ INT int_command
+ENDIF
+IF NOT IBM
+ invoke $READ
+ENDIF
+ CALL exec_alloc
+ POP DS
+ POP ES
+ JC exec_bad_file
+ CMP AX,exec_internal_buffer_size; did we read the right number?
+ JNZ exec_com_filej ; yep... continue
+ CMP [exec_max_BSS],0
+ JNZ exec_check_sig
+ MOV [exec_load_high],-1
+exec_check_sig:
+ MOV AX,[exec_signature]
+ CMP AX,exe_valid_signature ; zibo arises!
+ JZ exec_save_start ; assume com file if no signature
+ CMP AX,exe_valid_old_signature ; zibo arises!
+ JZ exec_save_start ; assume com file if no signature
+
+exec_com_filej:
+ JMP exec_com_file
+
+;
+; We have the program header... determine memory requirements
+;
+exec_save_start:
+ MOV AX,[exec_pages] ; get 512-byte pages
+ MOV CL,5 ; convert to paragraphs
+ SHL AX,CL
+ SUB AX,[exec_par_dir] ; AX = size in paragraphs
+ MOV [exec_res_len_para],AX
+
+;
+; Do we need to allocate memory? Yes if function is not load-overlay
+;
+ TEST BYTE PTR [exec_func],exec_func_overlay
+ JZ exec_allocate ; allocation of space
+;
+; get load address from block
+;
+ LES DI,DWORD PTR [exec_blk]
+ MOV AX,ES:[DI].exec3_load_addr
+ MOV [exec_dma],AX
+ MOV AX,ES:[DI].exec3_reloc_fac
+ MOV [exec_rel_fac],AX
+IF IBM
+ JMP exec_find_res
+ENDIF
+IF NOT IBM
+ JMP SHORT exec_find_res
+ENDIF
+
+exec_no_mem:
+ MOV AL,exec_not_enough_memory
+ JMP SHORT exec_bomb ; AX should be set by $ALLOC
+
+exec_bad_file:
+ MOV AL,exec_bad_format
+
+exec_bomb:
+ ASSUME DS:NOTHING,ES:NOTHING
+ PUSH AX
+ MOV BX,[exec_fh]
+ CALL exec_dealloc
+IF IBM
+ MOV AH,CLOSE
+ INT int_command
+ENDIF
+IF NOT IBM
+ invoke $CLOSE
+ENDIF
+ POP AX
+ transfer SYS_RET_ERR
+
+exec_allocate:
+IF IBM
+ ASSUME DS:EGROUP
+ENDIF
+IF NOT IBM
+ ASSUME DS:DOSGROUP
+ENDIF
+ PUSH AX
+ MOV BX,0FFFFh ; see how much room in arena
+ PUSH DS
+IF IBM
+ MOV AH,ALLOC
+ INT int_command
+ENDIF
+IF NOT IBM
+ invoke $ALLOC ; should have carry set and BX has max
+ENDIF
+ POP DS
+ POP AX
+ ADD AX,10h ; room for header
+ CMP BX,11h ; enough room for a header
+ JB exec_no_mem
+ CMP AX,BX ; is there enough for bare image?
+ JA exec_no_mem
+ CMP [exec_load_high],0 ; if load high, use max
+ JNZ exec_BX_max ; use max
+ ADD AX,[exec_min_BSS] ; go for min allocation
+ JC exec_no_mem ; oops! carry
+ CMP AX,BX ; enough space?
+ JA exec_no_mem ; nope...
+ SUB AX,[exec_min_BSS]
+ ADD AX,[exec_max_BSS] ; go for the MAX
+ JC exec_BX_max
+ CMP AX,BX
+ JBE exec_got_block
+
+exec_BX_max:
+ MOV AX,BX
+
+exec_got_block:
+ PUSH DS
+ MOV BX,AX
+ MOV [exec_size],BX
+IF IBM
+ MOV AH,ALLOC
+ INT int_command
+ENDIF
+IF NOT IBM
+ invoke $ALLOC ; get the space
+ENDIF
+ POP DS
+ JC exec_no_mem
+ MOV [exec_load_block],AX
+ ADD AX,10h
+ CMP [exec_load_high],0
+ JZ exec_use_ax ; use ax for load info
+ ADD AX,[exec_size] ; go to end
+ SUB AX,[exec_res_len_para] ; drop off header
+ SUB AX,10h ; drop off pdb
+exec_use_ax:
+ MOV [exec_rel_fac],AX ; new segment
+ MOV [exec_dma],AX ; beginning of dma
+IF IBM
+ CMP AX,[exec_low_seg] ; below loader
+ JA exec_no_mem_try
+ ADD AX,[exec_res_len_para] ; go to end
+ CMP Ax,[exec_low_seg] ; above loader
+ JBE exec_find_res
+exec_try_high:
+ CMP [exec_load_high],0
+ JZ exec_no_memj1
+exec_try_just_below:
+ MOV DX,AX
+ SUB DX,[exec_size] ; get beginning
+ ADD DX,[exec_res_len_para] ; no space
+ CMP DX,[exec_low_seg] ; room there?
+ JA exec_no_memj1
+ MOV AX,[exec_low_seg]
+ SUB AX,[exec_res_len_para]
+ JMP exec_use_ax
+exec_no_mem_try:
+ MOV DX,CS
+ ADD DX,(zexecdatasiz+zexeccodesize+15)/16
+ CMP AX,DX
+ JAE exec_try_high
+ JMP exec_try_just_below
+exec_no_memj1:
+ JMP exec_no_mem
+ENDIF
+
+;
+; Determine the location in the file of the beginning of the resident
+;
+exec_find_res:
+ MOV DX,[exec_par_dir]
+ PUSH DX
+ MOV CL,4
+ SHL DX,CL ; low word of location
+ POP AX
+ MOV CL,12
+ SHR AX,CL ; high word of location
+ MOV CX,AX ; CX <- high
+
+;
+; Read in the resident image (first, seek to it)
+;
+ MOV BX,[exec_fh]
+ PUSH DS
+IF IBM
+ MOV AX,(LSEEK SHL 8) + 0
+ INT int_command
+ENDIF
+IF NOT IBM
+ XOR AL,AL
+ invoke $LSEEK ; seek to resident
+ENDIF
+ POP DS
+
+exec_big_read: ; Read resident into memory
+ MOV BX,[exec_res_len_para]
+ CMP BX,1000h ; too many bytes to read?
+ JB exec_read_ok
+ MOV BX,0FE0h ; max in one chunk FE00 bytes
+
+exec_read_ok:
+ SUB [exec_res_len_para],BX ; we read (soon) this many
+ PUSH BX
+ MOV CL,4
+ SHL BX,CL ; get count in bytes from paras
+ MOV CX,BX ; count in correct register
+ MOV BX,[exec_fh] ; handle in correct register
+ PUSH DS
+ MOV DS,[exec_dma] ; Set up read buffer
+ ASSUME DS:NOTHING
+ XOR DX,DX
+ PUSH CX ; save our count
+ CALL exec_dealloc
+IF IBM
+ MOV AH,READ
+ INT int_command
+ENDIF
+IF NOT IBM
+ invoke $READ ; WOMP!
+ENDIF
+ CALL exec_alloc
+ POP CX ; get old count to verify
+ POP DS
+IF IBM
+ ASSUME DS:EGROUP
+ENDIF
+IF NOT IBM
+ ASSUME DS:DOSGROUP
+ENDIF
+ CMP CX,AX ; did we read enough?
+ POP BX ; get paragraph count back
+ JNZ exec_do_reloc ; and do reloc if no more to read
+;
+; We've read in CX bytes... bump DTA location
+;
+
+ ADD [exec_dma],BX ; bump dma address
+ CMP [exec_res_len_para],0
+ JNZ exec_big_read
+
+;
+; The image has now been read in. We must perform relocation to
+; the current location.
+;
+
+exec_do_reloc:
+ MOV CX,[exec_rel_fac]
+ MOV AX,[exec_SS] ; get initial SS
+ ADD AX,CX ; and relocate him
+ MOV [exec_init_SS],AX
+
+ MOV AX,[exec_SP] ; initial SP
+ MOV [exec_init_SP],AX
+
+ LES AX,DWORD PTR [exec_IP]
+ MOV [exec_init_IP],AX
+ MOV AX,ES
+ ADD AX,CX ; relocated...
+ MOV [exec_init_CS],AX
+
+ XOR CX,CX
+ MOV DX,[exec_rle_table]
+ MOV BX,[exec_fh]
+ PUSH DS
+IF IBM
+ MOV AX,(LSEEK SHL 8) + 0
+ INT int_command
+ENDIF
+IF NOT IBM
+ XOR AX,AX
+ invoke $LSEEK
+ENDIF
+ POP DS
+
+ JNC exec_get_entries
+exec_bad_filej:
+ JMP exec_bad_file
+
+exec_get_entries:
+ MOV DX,[exec_rle_count] ; Number of entries left
+
+exec_read_reloc:
+ ASSUME DS:NOTHING
+ PUSH DX
+IF IBM
+ MOV DX,OFFSET EGROUP:exec_signature
+ENDIF
+IF NOT IBM
+ MOV DX,OFFSET DOSGROUP:exec_signature
+ENDIF
+ MOV CX,((exec_internal_buffer_size)/4)*4
+ MOV BX,[exec_fh]
+ PUSH DS
+ CALL exec_dealloc
+IF IBM
+ MOV AH,READ
+ INT int_command
+ENDIF
+IF NOT IBM
+ invoke $READ
+ENDIF
+ CALL exec_alloc
+ POP ES
+ POP DX
+ JC exec_bad_filej
+ MOV CX,(exec_internal_buffer_size)/4
+IF IBM
+ MOV DI,OFFSET EGROUP:exec_signature ; Pointer to byte location in header
+ENDIF
+IF NOT IBM
+ MOV DI,OFFSET DOSGROUP:exec_signature ; Pointer to byte location in header
+ENDIF
+;
+; Relocate a single address
+;
+ MOV SI,[exec_rel_fac]
+
+exec_reloc_one:
+ CMP DX,0 ; Any more entries?
+ JNE exec_get_addr
+ JMP Exec_set_PDB
+
+exec_get_addr:
+ LDS BX,DWORD PTR ES:[DI] ; Get ra/sa of entry
+ MOV AX,DS ; Relocate address of item
+ ADD AX,SI
+ MOV DS,AX
+ MOV AX,WORD PTR DS:[BX] ; Relocate item
+ ADD AX,SI
+ MOV WORD PTR DS:[BX],AX
+ ADD DI,4
+ DEC DX
+ LOOP exec_reloc_one ; End of internal buffer?
+
+;
+; We've exhausted a single buffer's worth. Read in the next piece
+; of the relocation table.
+;
+
+ PUSH ES
+ POP DS
+ JMP exec_read_reloc
+
+exec_no_memj:
+ JMP exec_no_mem
+
+;
+; we have a .COM file. First, determine if we are merely loading an overlay.
+;
+exec_com_file:
+ TEST BYTE PTR [exec_func],exec_func_overlay
+ JZ exec_alloc_com_file
+ LDS SI,DWORD PTR [exec_blk] ; get arg block
+ LODSW ; get load address
+ MOV [exec_dma],AX
+ JMP SHORT exec_64k ; read it all!
+
+; We must allocate the max possible size block (ick!) and set up
+; CS=DS=ES=SS=PDB pointer, IP=100, SP=max size of block.
+;
+exec_alloc_com_file:
+ MOV BX,0FFFFh
+IF IBM
+ MOV AH,ALLOC
+ INT int_command
+ENDIF
+IF NOT IBM
+ invoke $ALLOC ; largest piece available as error
+ENDIF
+ OR BX,BX
+ JZ exec_no_memj
+ MOV [exec_size],BX ; save size of allocation block
+IF IBM
+ MOV AH,ALLOC
+ INT int_command
+ENDIF
+IF NOT IBM
+ PUSH BX
+ invoke $ALLOC ; largest piece available as error
+ POP BX ; get size of block...
+ENDIF
+ MOV [exec_load_block],AX
+ ADD AX,10h ; increment for header
+ MOV [exec_dma],AX
+ SUB BX,10h ; remember header
+IF IBM
+;
+; need to read up to exec_low_seg (at most)
+;
+ MOV CX,[exec_low_seg]
+ CMP AX,CX ; is base of allocation above spot
+ JA exec_check_64k
+ SUB CX,AX
+ CMP CX,BX
+ JA exec_check_64k
+ MOV BX,CX
+
+exec_check_64k:
+ENDIF
+ CMP BX,1000h ; 64k or more?
+ JAE exec_64k ; yes, read only 64k
+ MOV AX,BX ; convert size to bytes
+ MOV CL,4
+ SHL AX,CL
+ JMP SHORT exec_read_com
+
+exec_64k:
+ MOV AX,0FFFFh ; 64k-1 bytes
+
+exec_read_com:
+ PUSH AX ; save number to read
+ MOV BX,[exec_fh] ; of com file
+ XOR CX,CX ; but seek to 0:0
+ MOV DX,CX
+IF IBM
+ MOV AX,(LSEEK SHL 8) + 0
+ INT int_command
+ENDIF
+IF NOT IBM
+ XOR AX,AX ; seek relative to beginning
+ invoke $LSEEK ; back to beginning of file
+ENDIF
+ MOV BX,[exec_fh]
+ POP CX ; number to read
+ MOV DS,[exec_dma]
+ XOR DX,DX
+ PUSH CX
+ CALL exec_dealloc
+IF IBM
+ MOV AH,READ
+ INT int_command
+ENDIF
+IF NOT IBM
+ invoke $READ ; read in com file
+ENDIF
+ CALL exec_alloc
+ POP SI ; get number of bytes to read
+ CMP AX,SI ; did we read them all?
+IF IBM
+ JNZ exec_skip ; exactly the wrong number... no memory
+ JMP exec_no_mem
+exec_skip:
+ENDIF
+IF NOT IBM
+ JZ exec_no_memj ; exactly the wrong number... no memory
+ENDIF
+ TEST BYTE PTR [exec_func],exec_func_overlay
+ JNZ exec_set_PDB ; no starto, chumo!
+ MOV AX,[exec_DMA]
+ SUB AX,10h
+ MOV [exec_init_CS],AX
+ MOV [exec_init_IP],100h ; initial IP is 100
+ ; SI is at most FFFFh
+ DEC SI ; make room for stack
+ ; SI is at most FFFEh, room for a 0!
+ MOV [exec_init_SP],SI ; max value for read is also SP!
+ MOV [exec_init_SS],AX
+ MOV DS,AX
+ MOV WORD PTR DS:[SI],0 ; 0 for return
+
+exec_set_PDB:
+ MOV BX,[exec_fh] ; we are finished with the file.
+ CALL exec_dealloc
+IF IBM
+ MOV AH,CLOSE
+ INT int_command
+ENDIF
+IF NOT IBM
+ invoke $CLOSE ; release the jfn
+ENDIF
+ CALL exec_alloc
+ TEST BYTE PTR [exec_func],exec_func_overlay
+ JZ exec_build_header
+ transfer SYS_RET_OK ; overlay load -> done
+
+exec_build_header:
+ MOV DX,[exec_load_block]
+;
+; assign the space to the process
+;
+
+ MOV SI,arena_owner ; pointer to owner field
+
+ MOV AX,[exec_environ] ; get environ pointer
+ OR AX,AX
+ JZ NO_OWNER ; no environment
+ DEC AX ; point to header
+ MOV DS,AX
+ MOV DS:[SI],DX ; assign ownership
+NO_OWNER:
+ MOV AX,[exec_load_block] ; get load block pointer
+ DEC AX
+ MOV DS,AX ; point to header
+ MOV DS:[SI],DX ; assign ownership
+
+ PUSH DX
+IF IBM
+ MOV AH,DUP_PDB
+ INT int_command
+ MOV ES,DX
+ MOV [CurrentPDB],DX
+ENDIF
+IF NOT IBM
+ MOV BYTE PTR [CreatePDB], 0FFH ; indicate a new process
+ invoke $Dup_PDB ; ES is now PDB
+ENDIF
+ POP DX
+ PUSH [exec_environ]
+ POP ES:[PDB_environ]
+ MOV SI,[exec_size]
+ ADD SI,DX
+ MOV ES:[PDB_block_len],SI
+;
+; set up proper command line stuff
+;
+ LDS SI,DWORD PTR [exec_blk] ; get the block
+ PUSH DS ; save its location
+ PUSH SI
+ LDS SI,DS:[SI.exec0_5C_FCB] ; get the 5c fcb
+ MOV CX,12 ; copy drive, name and ext
+ PUSH CX
+ MOV DI,5Ch
+ MOV BL,DS:[SI]
+ REP MOVSB
+ XOR AX,AX ; zero extent, etc for CPM
+ STOSW
+ STOSW
+ POP CX
+ POP SI ; get block
+ POP DS
+ PUSH DS ; save (again)
+ PUSH SI
+ LDS SI,DS:[SI.exec0_6C_FCB] ; get 6C FCB
+ MOV DI,6Ch ; do same as above
+ MOV BH,DS:[SI]
+ REP MOVSB
+ STOSW
+ STOSW
+ POP SI ; get block (last time)
+ POP DS
+ LDS SI,DS:[SI.exec0_com_line] ; command line
+ MOV CX,80h
+ MOV DI,CX
+ REP MOVSB ; Wham!
+
+;
+; Process BX into default AX (validity of drive specs on args)
+;
+ DEC CL ; get 0FFh in CX
+ CMP BH,[NUMIO]
+ JBE exec_BH_good
+ MOV BH,CL
+ JMP SHORT exec_BL
+exec_BH_good:
+ XOR BH,BH
+exec_BL:
+ CMP BL,[NUMIO]
+ JBE exec_BL_good
+ MOV BL,CL
+ JMP SHORT exec_set_return
+exec_BL_good:
+ XOR BL,BL
+exec_set_return:
+ invoke get_user_stack ; get his return address
+ PUSH [SI.user_CS] ; suck out the CS and IP
+ PUSH [SI.user_IP]
+ PUSH [SI.user_CS] ; suck out the CS and IP
+ PUSH [SI.user_IP]
+ POP WORD PTR ES:[PDB_Exit]
+ POP WORD PTR ES:[PDB_Exit+2]
+ XOR AX,AX
+ MOV DS,AX
+ POP DS:[addr_int_terminate] ; save them where we can get them later
+ POP DS:[addr_int_terminate+2] ; when the child exits.
+IF NOT IBM
+ MOV WORD PTR [DMAADD],80h
+ MOV DS,[CurrentPDB]
+ MOV WORD PTR [DMAADD+2],DS
+ENDIF
+IF IBM
+ PUSH DX
+ PUSH DS
+ MOV DS,[CurrentPDB]
+ MOV DX,80h
+ MOV AH,SET_DMA
+ INT int_command
+ POP DS
+ POP DX
+ENDIF
+ TEST BYTE PTR [exec_func],exec_func_no_execute
+ JZ exec_go
+
+ LDS SI,DWORD PTR [exec_init_SP] ; get stack
+ LES DI,DWORD PTR [exec_blk] ; and block for return
+ MOV ES:[DI].exec1_SS,DS ; return SS
+
+ DEC SI ; 'push' default AX
+ DEC SI
+ MOV DS:[SI],BX ; save default AX reg
+ MOV ES:[DI].exec1_SP,SI ; return 'SP'
+
+ LDS AX,DWORD PTR [exec_init_IP]
+ MOV ES:[DI].exec1_CS,DS ; initial entry stuff
+
+ MOV ES:[DI].exec1_IP,AX
+ transfer SYS_RET_OK
+
+exec_go:
+IF IBM
+ CALL restore_ctrlc ; restore value of ctrl-c checker
+ENDIF
+ LDS SI,DWORD PTR [exec_init_IP] ; get entry point
+ CLI
+IF NOT IBM
+ MOV BYTE PTR INDOS,0
+ENDIF
+ MOV SS,[exec_init_SS] ; set up user's stack
+ ASSUME SS:NOTHING
+ MOV SP,[exec_init_SP] ; and SP
+ STI
+ PUSH DS ; fake long call to entry
+ PUSH SI
+ MOV ES,DX ; set up proper seg registers
+ MOV DS,DX
+ MOV AX,BX ; set up proper AX
+ procedure exec_long_ret,FAR
+ RET
+exec_long_ret ENDP
+
+$Exec ENDP
+
+ procedure exec_dealloc,near
+ ASSUME DS:NOTHING,ES:NOTHING
+ PUSH BX
+ MOV BX,arena_owner_system
+ CALL exec_do_change_owner
+ POP BX
+ return
+exec_dealloc ENDP
+
+ procedure exec_alloc,near
+ PUSH BX
+ MOV BX,[CurrentPDB]
+ CALL exec_do_change_owner
+ POP BX
+ return
+exec_alloc ENDP
+
+ procedure exec_do_change_owner,NEAR
+ PUSH DS
+ PUSH AX
+ MOV AX,[exec_environ]
+ OR AX,AX
+ JZ exec_alloc_try_load
+ DEC AX
+ MOV DS,AX
+ MOV DS:[arena_owner],BX
+exec_alloc_try_load:
+ MOV AX,[exec_load_block]
+ OR AX,AX
+ JZ exec_alloc_done
+ DEC AX
+ MOV DS,AX
+ MOV DS:[arena_owner],BX
+exec_alloc_done:
+ POP AX
+ POP DS
+ RET
+exec_do_change_owner ENDP
+
+IF IBM
+SYS_RET_ERR:
+ CALL get_user_stack
+ PUSH [SI.user_f]
+ XOR AH,AH
+ MOV [SI.user_AX],AX
+ POPF
+ STC
+ JMP SYS_RET
+SYS_RET_OK:
+ CALL get_user_stack
+ PUSH [SI.user_f]
+ POPF
+ CLC
+SYS_RET:
+ PUSHF
+ CALL restore_ctrlc
+ POP [SI.user_f]
+ JMP exec_long_ret
+
+;
+; get_user_stack returns the user's stack (and hence registers) in DS:SI
+;
+ procedure get_user_stack,NEAR
+ PUSH SS
+ POP DS
+ ASSUME DS:RESGROUP
+ LDS SI,DWORD PTR [user_SP]
+ RET
+get_user_stack ENDP
+;
+; restore value of the ctrl-c checker
+;
+ procedure restore_ctrlc
+ PUSH AX
+ PUSH DX
+ MOV DL,CS:[exec_ctrlc]
+ MOV AX,(Set_Ctrl_C_Trapping SHL 8) + 1 ; Put it back
+ INT int_command
+ POP DX
+ POP AX
+ RET
+restore_ctrlc ENDP
+
+ZEXECCODESIZE EQU $-ZERO
+ZEXECCODEEND LABEL BYTE
+ PUBLIC ZEXECCODEEND
+ZEXEC_CODE ENDS
+ENDIF
--- /dev/null
+;\r
+; FAT operations for MSDOS\r
+;\r
+\r
+INCLUDE DOSSEG.ASM\r
+\r
+CODE SEGMENT BYTE PUBLIC 'CODE'\r
+ ASSUME SS:DOSGROUP,CS:DOSGROUP\r
+\r
+.xlist\r
+.xcref\r
+INCLUDE DOSSYM.ASM\r
+INCLUDE DEVSYM.ASM\r
+.cref\r
+.list\r
+\r
+TITLE FAT - FAT maintenance routines\r
+NAME FAT\r
+\r
+ i_need CURBUF,DWORD\r
+ i_need CLUSSPLIT,BYTE\r
+ i_need CLUSSAVE,WORD\r
+ i_need CLUSSEC,WORD\r
+ i_need THISDRV,BYTE\r
+ i_need DEVCALL,BYTE\r
+ i_need CALLMED,BYTE\r
+ i_need CALLRBYT,BYTE\r
+ i_need BUFFHEAD,DWORD\r
+ i_need CALLXAD,DWORD\r
+ i_need CALLBPB,DWORD\r
+\r
+SUBTTL UNPACK -- UNPACK FAT ENTRIES\r
+PAGE\r
+\r
+ASSUME SS:DOSGROUP\r
+ procedure UNPACK,NEAR\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+; Inputs:\r
+; BX = Cluster number\r
+; ES:BP = Base of drive parameters\r
+; Outputs:\r
+; DI = Contents of FAT for given cluster\r
+; Zero set means DI=0 (free cluster)\r
+; SI Destroyed, No other registers affected. Fatal error if cluster too big.\r
+\r
+ CMP BX,ES:[BP.dpb_max_cluster]\r
+ JA HURTFAT\r
+ CALL MAPCLUSTER\r
+ASSUME DS:NOTHING\r
+ MOV DI,[DI]\r
+ JNC HAVCLUS\r
+ PUSH CX\r
+ MOV CL,4\r
+ SHR DI,CL\r
+ POP CX\r
+ STC\r
+HAVCLUS:\r
+ AND DI,0FFFH\r
+ PUSH SS\r
+ POP DS\r
+ return\r
+\r
+HURTFAT:\r
+ PUSH AX\r
+ MOV AH,80H ; Signal Bad FAT to INT int_fatal_abort handler\r
+ MOV DI,0FFFH ; In case INT int_fatal_abort returns (it shouldn't)\r
+ invoke FATAL\r
+ POP AX ; Try to ignore bad FAT\r
+ return\r
+UNPACK ENDP\r
+\r
+SUBTTL PACK -- PACK FAT ENTRIES\r
+PAGE\r
+ procedure PACK,NEAR\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+; Inputs:\r
+; BX = Cluster number\r
+; DX = Data\r
+; ES:BP = Pointer to drive DPB\r
+; Outputs:\r
+; The data is stored in the FAT at the given cluster.\r
+; SI,DX,DI all destroyed\r
+; No other registers affected\r
+\r
+ CALL MAPCLUSTER\r
+ASSUME DS:NOTHING\r
+ MOV SI,[DI]\r
+ JNC ALIGNED\r
+ PUSH CX\r
+ MOV CL,4\r
+ SHL DX,CL\r
+ POP CX\r
+ AND SI,0FH\r
+ JMP SHORT PACKIN\r
+ALIGNED:\r
+ AND SI,0F000H\r
+PACKIN:\r
+ OR SI,DX\r
+ MOV [DI],SI\r
+ LDS SI,[CURBUF]\r
+ MOV [SI.BUFDIRTY],1\r
+ CMP BYTE PTR [CLUSSPLIT],0\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ retz\r
+ PUSH AX\r
+ PUSH BX\r
+ PUSH CX\r
+ MOV AX,[CLUSSAVE]\r
+ MOV DS,WORD PTR [CURBUF+2]\r
+ASSUME DS:NOTHING\r
+ ADD SI,BUFINSIZ\r
+ MOV [SI],AH\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ PUSH AX\r
+ MOV DX,[CLUSSEC]\r
+ MOV SI,1\r
+ XOR AL,AL\r
+ invoke GETBUFFRB\r
+ LDS DI,[CURBUF]\r
+ASSUME DS:NOTHING\r
+ MOV [DI.BUFDIRTY],1\r
+ ADD DI,BUFINSIZ\r
+ DEC DI\r
+ ADD DI,ES:[BP.dpb_sector_size]\r
+ POP AX\r
+ MOV [DI],AL\r
+ PUSH SS\r
+ POP DS\r
+ POP CX\r
+ POP BX\r
+ POP AX\r
+ return\r
+PACK ENDP\r
+\r
+SUBTTL MAPCLUSTER - BUFFER A FAT SECTOR\r
+PAGE\r
+ procedure MAPCLUSTER,NEAR\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+; Inputs:\r
+; ES:BP Points to DPB\r
+; BX Is cluster number\r
+; Function:\r
+; Get a pointer to the cluster\r
+; Outputs:\r
+; DS:DI Points to contents of FAT for given cluster\r
+; DS:SI Points to start of buffer\r
+; Carry set if cluster data is in high 12 bits of word\r
+; No other registers effected\r
+\r
+ MOV BYTE PTR [CLUSSPLIT],0\r
+ PUSH AX\r
+ PUSH BX\r
+ PUSH CX\r
+ PUSH DX\r
+ MOV AX,BX\r
+ SHR AX,1\r
+ ADD AX,BX\r
+ XOR DX,DX\r
+ MOV CX,ES:[BP.dpb_sector_size]\r
+ DIV CX ; AX is FAT sector # DX is sector index\r
+ ADD AX,ES:[BP.dpb_first_FAT]\r
+ DEC CX\r
+ PUSH AX\r
+ PUSH DX\r
+ PUSH CX\r
+ MOV DX,AX\r
+ XOR AL,AL\r
+ MOV SI,1\r
+ invoke GETBUFFRB\r
+ LDS SI,[CURBUF]\r
+ASSUME DS:NOTHING\r
+ LEA DI,[SI.BufInSiz]\r
+ POP CX\r
+ POP AX\r
+ POP DX\r
+ ADD DI,AX\r
+ CMP AX,CX\r
+ JNZ MAPRET\r
+ MOV AL,[DI]\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ INC BYTE PTR [CLUSSPLIT]\r
+ MOV BYTE PTR [CLUSSAVE],AL\r
+ MOV [CLUSSEC],DX\r
+ INC DX\r
+ XOR AL,AL\r
+ MOV SI,1\r
+ invoke GETBUFFRB\r
+ LDS SI,[CURBUF]\r
+ASSUME DS:NOTHING\r
+ LEA DI,[SI.BufInSiz]\r
+ MOV AL,[DI]\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ MOV BYTE PTR [CLUSSAVE+1],AL\r
+ MOV DI,OFFSET DOSGROUP:CLUSSAVE\r
+MAPRET:\r
+ POP DX\r
+ POP CX\r
+ POP BX\r
+ MOV AX,BX\r
+ SHR AX,1\r
+ POP AX\r
+ return\r
+MAPCLUSTER ENDP\r
+\r
+SUBTTL FATREAD -- CHECK DRIVE GET FAT\r
+PAGE\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+ procedure FAT_operation,NEAR\r
+FATERR:\r
+ AND DI,STECODE ; Put error code in DI\r
+ MOV AH,2 ; While trying to read FAT\r
+ MOV AL,BYTE PTR [THISDRV] ; Tell which drive\r
+ invoke FATAL1\r
+\r
+ entry FATREAD\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+; Function:\r
+; If disk may have been changed, FAT is read in and buffers are\r
+; flagged invalid. If not, no action is taken.\r
+; Outputs:\r
+; ES:BP = Base of drive parameters\r
+; All other registers destroyed\r
+\r
+ MOV AL,BYTE PTR [THISDRV]\r
+ invoke GETBP\r
+ MOV AL,DMEDHL\r
+ MOV AH,ES:[BP.dpb_UNIT]\r
+ MOV WORD PTR [DEVCALL],AX\r
+ MOV BYTE PTR [DEVCALL.REQFUNC],DEVMDCH\r
+ MOV [DEVCALL.REQSTAT],0\r
+ MOV AL,ES:[BP.dpb_media]\r
+ MOV BYTE PTR [CALLMED],AL\r
+ PUSH ES\r
+ PUSH DS\r
+ MOV BX,OFFSET DOSGROUP:DEVCALL\r
+ LDS SI,ES:[BP.dpb_driver_addr] ; DS:SI Points to device header\r
+ASSUME DS:NOTHING\r
+ POP ES ; ES:BX Points to call header\r
+ invoke DEVIOCALL2\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ POP ES ; Restore ES:BP\r
+ MOV DI,[DEVCALL.REQSTAT]\r
+ TEST DI,STERR\r
+ JNZ FATERR\r
+ XOR AH,AH\r
+ XCHG AH,ES:[BP.dpb_first_access] ; Reset dpb_first_access\r
+ MOV AL,BYTE PTR [THISDRV] ; Use physical unit number\r
+ OR AH,BYTE PTR [CALLRBYT]\r
+ JS NEWDSK ; new disk or first access?\r
+ JZ CHKBUFFDIRT\r
+ return ; If Media not changed\r
+CHKBUFFDIRT:\r
+ INC AH ; Here if ?Media..Check buffers\r
+ LDS DI,[BUFFHEAD]\r
+ASSUME DS:NOTHING\r
+NBUFFER: ; Look for dirty buffers\r
+ CMP AX,WORD PTR [DI.BUFDRV]\r
+ retz ; There is a dirty buffer, assume Media OK\r
+ LDS DI,[DI.NEXTBUF]\r
+ CMP DI,-1\r
+ JNZ NBUFFER\r
+; If no dirty buffers, assume Media changed\r
+NEWDSK:\r
+ invoke SETVISIT\r
+NXBUFFER:\r
+ MOV [DI.VISIT],1\r
+ CMP AL,[DI.BUFDRV] ; For this drive?\r
+ JNZ SKPBUFF\r
+ MOV WORD PTR [DI.BUFDRV],00FFH ; Free up buffer\r
+ invoke SCANPLACE\r
+SKPBUFF:\r
+ invoke SKIPVISIT\r
+ JNZ NXBUFFER\r
+ LDS DI,ES:[BP.dpb_driver_addr]\r
+ TEST [DI.SDEVATT],ISFATBYDEV\r
+ JNZ GETFREEBUF\r
+ context DS\r
+ MOV BX,2\r
+ CALL UNPACK ; Read the first FAT sector into CURBUF\r
+ LDS DI,[CURBUF]\r
+ JMP SHORT GOTGETBUF\r
+GETFREEBUF:\r
+ASSUME DS:NOTHING\r
+ PUSH ES ; Get a free buffer for BIOS to use\r
+ PUSH BP\r
+ LDS DI,[BUFFHEAD]\r
+ invoke BUFWRITE\r
+ POP BP\r
+ POP ES\r
+GOTGETBUF:\r
+ ADD DI,BUFINSIZ\r
+ MOV WORD PTR [CALLXAD+2],DS\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ MOV WORD PTR [CALLXAD],DI\r
+ MOV AL,DBPBHL\r
+ MOV AH,BYTE PTR ES:[BP.dpb_UNIT]\r
+ MOV WORD PTR [DEVCALL],AX\r
+ MOV BYTE PTR [DEVCALL.REQFUNC],DEVBPB\r
+ MOV [DEVCALL.REQSTAT],0\r
+ MOV AL,BYTE PTR ES:[BP.dpb_media]\r
+ MOV [CALLMED],AL\r
+ PUSH ES\r
+ PUSH DS\r
+ PUSH WORD PTR ES:[BP.dpb_driver_addr+2]\r
+ PUSH WORD PTR ES:[BP.dpb_driver_addr]\r
+ MOV BX,OFFSET DOSGROUP:DEVCALL\r
+ POP SI\r
+ POP DS ; DS:SI Points to device header\r
+ASSUME DS:NOTHING\r
+ POP ES ; ES:BX Points to call header\r
+ invoke DEVIOCALL2\r
+ POP ES ; Restore ES:BP\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ MOV DI,[DEVCALL.REQSTAT]\r
+ TEST DI,STERR\r
+ JNZ FATERRJ\r
+ MOV AL,BYTE PTR ES:[BP.dpb_media]\r
+ LDS SI,[CALLBPB]\r
+ASSUME DS:NOTHING\r
+ CMP AL,BYTE PTR [SI.BPMEDIA]\r
+ JZ DPBOK\r
+ invoke $SETDPB\r
+ LDS DI,[CALLXAD] ; Get back buffer pointer\r
+ MOV AL,BYTE PTR ES:[BP.dpb_FAT_count]\r
+ MOV AH,BYTE PTR ES:[BP.dpb_FAT_size]\r
+ MOV WORD PTR [DI.BUFWRTCNT-BUFINSIZ],AX ;Correct buffer info\r
+DPBOK:\r
+ context ds\r
+ MOV AX,-1\r
+ TEST ES:[BP.dpb_current_dir],AX\r
+ retz ; If root, leave as root\r
+ MOV ES:[BP.dpb_current_dir],AX ; Path may be bad, mark invalid\r
+ return\r
+\r
+FATERRJ: JMP FATERR\r
+\r
+FAT_operation ENDP\r
+\r
+do_ext\r
+\r
+CODE ENDS\r
+ END\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+ title File Compare Routine for MSDOS 2.0\r
+\r
+;-----------------------------------------------------------------------;\r
+; Revision History: ;\r
+; ;\r
+; V1.0 Rev. 0 10/27/82 M.A.Ulloa ;\r
+; ;\r
+; Rev. 1 10/28/82 M.A.Ulloa ;\r
+; Changed switch names and added binary compare using the ;\r
+; -b switch. ;\r
+; ;\r
+; Rev. 1 11/4/82 A.R. Reynolds ;\r
+; Messages in separate module ;\r
+; Also added header for MSVER ;\r
+; ;\r
+; Rev. 2 11/29/82 M.A. Ulloa ;\r
+; Corrected sysntex problem with references to [base...] ;\r
+; ;\r
+; Rev. 3 01/03/83 M.A. Ulloa ;\r
+; Stack is right size now. ;\r
+; ;\r
+;-----------------------------------------------------------------------;\r
+\r
+FALSE equ 0\r
+TRUE equ 0ffh\r
+\r
+\r
+buf_size equ 4096 ;buffer size\r
+\r
+\r
+;-----------------------------------------------------------------------;\r
+; Description ;\r
+; ;\r
+; FC [-# -b -w -c] <file1> <file2> ;\r
+; ;\r
+; Options: ;\r
+; ;\r
+; -# were # is a number from 1 to 9, how many lines have to ;\r
+; before the end of an area of difference ends. ;\r
+; ;\r
+; -b will force a binary comparation of both files. ;\r
+; ;\r
+; -w will cause all spaces and tabs to be compressed to a single ;\r
+; space before comparing. All leading and trailing spaces and/or tabs ;\r
+; in a line are ignored. ;\r
+; ;\r
+; -c will cause FC to ignore the case of the letters. ;\r
+; ;\r
+; Algorithm for text compare: (The one for binary comp. is trivial) ;\r
+; ;\r
+; The files are read into two separate buffers and the ;\r
+; comparation starts. If two lines are found to be different in the ;\r
+; two buffers, say line i of buffer A and line j of buffer B differ. ;\r
+; The program will try to match line i with line j+1, then with line ;\r
+; j+2 and so on, if the end of buffer is reached the program will ;\r
+; recompact the buffer and try to read more lines into the buffer, if ;\r
+; no more lines can be read because either the buffer is full, or the ;\r
+; end of file was reached, then it will revert and try to match line ;\r
+; j of buffer B to line i+1, i+2 and so on of buffer A. If an end of ;\r
+; buffer is found, it tries to refill it as before. If no matches are ;\r
+; found, then it will try to match line i+1 of buffer A to line j+1, ;\r
+; j+2, j+3, .... of buffer B, if still no matches are found, it reverts ;\r
+; again and tries to match line j+1 of buffer B with lines i+2, i+3,... ;\r
+; of buffer A. And so on till a match is found. ;\r
+; ;\r
+; Once a match is found it continues chcking pairs of lines till ;\r
+; the specified number are matched (option #, 3 by default), and then ;\r
+; it prints the differing area in both files, each followed by the ;\r
+; first line matched. ;\r
+; ;\r
+; If no match is found (the difference is bigger than the buffer) ;\r
+; a "files different" message is printed. ;\r
+; ;\r
+; If one of the files finishes before another the remaining ;\r
+; portion of the file (plus any ongoing difference) is printed out. ;\r
+; ;\r
+;-----------------------------------------------------------------------;\r
+\r
+\r
+ subttl Debug Macros\r
+ page\r
+\r
+m_debug macro str\r
+ local a,b\r
+ jmp short b\r
+a db str,0dh,0ah,"$"\r
+b: pushf\r
+ push dx\r
+ mov dx,offset code:a\r
+ push ds\r
+ push cs\r
+ pop ds\r
+ push ax\r
+ mov ah,9h\r
+ int 21h\r
+ pop ax\r
+ pop ds\r
+ pop dx\r
+ popf\r
+ endm\r
+\r
+\r
+m_bname macro\r
+ local a0,a1,a2,b1,b2\r
+ jmp short a0\r
+b1 db "------ buffer 1",0dh,0ah,"$"\r
+b2 db "------ buffer 2",0dh,0ah,"$"\r
+a0: pushf\r
+ push dx\r
+ cmp bx,offset dg:buf1\r
+ je a1\r
+ mov dx,offset code:b2\r
+ jmp short a2\r
+a1: mov dx,offset code:b1\r
+a2: push ds\r
+ push cs\r
+ pop ds\r
+ push ax\r
+ mov ah,9h\r
+ int 21h\r
+ pop ax\r
+ pop ds\r
+ pop dx\r
+ popf\r
+ endm\r
+\r
+\r
+ page\r
+\r
+ .SALL\r
+ .XLIST\r
+ include dossym.asm\r
+ .LIST\r
+\r
+ subttl General Definitions\r
+ page\r
+\r
+CR equ 0dh\r
+LF equ 0ah\r
+\r
+\r
+;-----------------------------------------------------------------------;\r
+; Offsets to buffer structure\r
+; For text comparations:\r
+\r
+fname equ 0 ;file name ptr\r
+fname_len equ 2 ;file name length\r
+handle equ 4 ;handle\r
+curr equ 6 ;current line ptr\r
+lst_curr equ 8 ;last current line ptr\r
+fst_sinc equ 10 ;first line towards a sinc ptr\r
+fst_nosinc equ 12 ;first line out of sinc ptr\r
+dat_end equ 14 ;ptr to last char of the buffer\r
+buf_end equ 16 ;pointer to the end of the buffer\r
+buf equ 18 ;pointer to the buffer\r
+\r
+; For binary comparations:\r
+\r
+by_read equ 6 ;bytes read into buffer\r
+\r
+;-----------------------------------------------------------------------;\r
+\r
+\r
+code segment word\r
+code ends\r
+\r
+const segment public word\r
+const ends\r
+\r
+data segment word\r
+data ends\r
+\r
+dg group code,const,data\r
+\r
+\r
+ subttl Constants Area\r
+ page\r
+\r
+const segment public word\r
+\r
+make db "MAUlloa/Microsoft/V10"\r
+rev db "2"\r
+\r
+;----- CAREFULL WITH PRESERVING THE ORDER OF THE TABLE -----\r
+opt_tbl equ $ ;option table\r
+\r
+flg_b db FALSE\r
+flg_c db FALSE\r
+flg_s db FALSE\r
+flg_w db FALSE\r
+;-----------------------------------------------------------\r
+\r
+ib_first1 db FALSE ;flags used when comparing lines\r
+ib_first2 db FALSE ; while in ignore white mode.\r
+\r
+m_num dw 3 ;lines that have to match before\r
+ ; reporting a match\r
+\r
+mtch_cntr dw 0 ;matches towards a sinc\r
+\r
+mode db FALSE ;If false then trying to match a line\r
+ ; from buf1 to lines in buf2. If true\r
+ ; then viceversa.\r
+\r
+sinc db TRUE ;Sinc flag, start IN SINC\r
+\r
+bend db 0 ;binary end of file flag, 0= none yet,\r
+ ; 1= file 1 ended, 2= file 2 ended\r
+\r
+base dd 0 ;base address of files for binary\r
+ ; comparations\r
+\r
+bhead_flg db false ;true if heading for binary comp.\r
+ ; has been printed already.\r
+\r
+;-----------------------------------------------------------\r
+bp_buf equ $ ;binary compare difference template\r
+\r
+bp_buf1 db 8 dup(' ') ;file address\r
+ db 3 dup(' ')\r
+bp_buf2 db 2 dup(' ') ;byte of file 1\r
+ db 3 dup(' ')\r
+bp_buf3 db 2 dup(' ') ;byte of file 1\r
+ db CR,LF\r
+\r
+bp_buf_len equ $ - bp_buf ;length of template\r
+;-----------------------------------------------------------\r
+\r
+ EXTRN vers_err:byte,opt_err:byte,opt_e:byte,crlf:byte,opt_err_len:byte\r
+ EXTRN bhead_len:byte\r
+ EXTRN found_err_pre:byte,found_err_pre_len:byte\r
+ EXTRN found_err_post:byte,found_err_post_len:byte\r
+ EXTRN read_err_pre:byte,read_err_pre_len:byte\r
+ EXTRN read_err_post:byte,read_err_post_len:byte\r
+ EXTRN file_err:byte,file_err_len:byte\r
+ EXTRN bf1ne:byte,bf1ne_len:byte,bf2ne:byte,bf2ne_len:byte,bhead:byte\r
+ EXTRN int_err:byte,int_err_len:byte,dif_err:byte,dif_err_len:byte\r
+ EXTRN args_err:byte,args_err_len:byte,fname_sep:byte,fname_sep_len:byte\r
+ EXTRN diff_sep:byte,diff_sep_len:byte\r
+\r
+const ends\r
+\r
+\r
+\r
+ subttl Data Area\r
+ page\r
+\r
+data segment word\r
+\r
+com_buf db 128 dup(?) ;command line buffer\r
+\r
+;----- Buffer structures\r
+buf1 dw 11 dup(?)\r
+buf2 dw 11 dup(?)\r
+\r
+; two extra for guard in case of need to insert a CR,LF pair\r
+b1 db buf_size dup(?)\r
+end_b1 db 2 dup(?)\r
+b2 db buf_size dup(?)\r
+end_b2 db 2 dup(?)\r
+\r
+data ends\r
+\r
+\r
+\r
+ subttl MAIN Routine\r
+ page\r
+\r
+code segment\r
+assume cs:dg,ds:nothing,es:nothing,ss:stack\r
+\r
+start:\r
+ jmp short FCSTRT\r
+;-----------------------------------------------------------------------;\r
+; Check version number\r
+\r
+HEADER DB "Vers 1.00"\r
+\r
+FCSTRT:\r
+;Code to print header\r
+; PUSH DS\r
+; push cs\r
+; pop ds\r
+; MOV DX,OFFSET DG:HEADER\r
+; mov ah,std_con_string_output\r
+; int 21h\r
+; POP DS\r
+\r
+ mov ah,get_version\r
+ int 21h\r
+ cmp al,2\r
+ jge vers_ok\r
+ mov dx,offset dg:vers_err\r
+ mov ah,std_con_string_output\r
+ int 21h\r
+ push es ;bad vers, exit a la 1.x\r
+ xor ax,ax\r
+ push ax\r
+\r
+badvex proc far\r
+ ret\r
+badvex endp\r
+\r
+\r
+vers_ok:\r
+ push cs\r
+ pop es\r
+\r
+assume es:dg\r
+\r
+;-----------------------------------------------------------------------;\r
+; Copy command line\r
+\r
+ mov si,80h ;command line address\r
+ cld\r
+ lodsb ;get char count\r
+ mov cl,al\r
+ xor ch,ch\r
+ inc cx ;include the CR\r
+ mov di,offset dg:com_buf\r
+ cld\r
+ rep movsb\r
+\r
+ push cs\r
+ pop ds\r
+\r
+assume ds:dg\r
+\r
+\r
+\r
+;-----------------------------------------------------------------------;\r
+; Initialize buffer structures\r
+\r
+ mov bx,offset dg:buf1\r
+ mov word ptr [bx].buf,offset dg:b1\r
+ mov word ptr [bx].buf_end,offset dg:end_b1\r
+ mov bx,offset dg:buf2\r
+ mov word ptr [bx].buf,offset dg:b2\r
+ mov word ptr [bx].buf_end,offset dg:end_b2\r
+\r
+\r
+;-----------------------------------------------------------------------;\r
+; Process options\r
+\r
+ mov ah,char_oper\r
+ mov al,0\r
+ int 21h ;get switch character\r
+ mov si,offset dg:com_buf\r
+\r
+cont_opt:\r
+ call kill_bl\r
+ jc bad_args ;arguments missing\r
+ cmp al,dl ;switch character?\r
+ jne get_file ;no, process file names\r
+ cld\r
+ lodsb ;get option\r
+ call make_caps ;capitalize option\r
+ mov bx,offset dg:opt_tbl\r
+\r
+ cmp al,'B'\r
+ je b_opt\r
+ cmp al,'C'\r
+ je c_opt\r
+ cmp al,'S'\r
+ je s_opt\r
+ cmp al,'W'\r
+ je w_opt\r
+ cmp al,'1' ;a number option?\r
+ jb bad_opt\r
+ cmp al,'9'\r
+ ja bad_opt\r
+ and al,0fh ;a number option, convert to binary\r
+ xor ah,ah ;zero high nibble\r
+ mov [m_num],ax\r
+ jmp short cont_opt\r
+\r
+bad_opt: ;a bad option:\r
+ push dx ; save switch character\r
+ mov [opt_e],al ; option in error\r
+ mov dx,offset dg:opt_err\r
+ mov cl,opt_err_len\r
+ call prt_err ; print error message\r
+ pop dx\r
+ jmp short cont_opt ; process rest of options\r
+\r
+b_opt:\r
+ mov di,0\r
+ jmp short opt_dispatch\r
+\r
+c_opt:\r
+ mov di,1\r
+ jmp short opt_dispatch\r
+\r
+s_opt:\r
+ mov di,2\r
+ jmp short opt_dispatch\r
+\r
+w_opt:\r
+ mov di,3\r
+\r
+opt_dispatch:\r
+ mov byte ptr dg:[bx+di],TRUE ;set the corresponding flag\r
+ jmp short cont_opt\r
+\r
+\r
+bad_args:\r
+ mov dx,offset dg:args_err\r
+ mov cl,args_err_len\r
+ jmp an_err\r
+\r
+\r
+\r
+;-----------------------------------------------------------------------;\r
+; Get the file names\r
+\r
+get_file:\r
+ dec si ;adjust pointer\r
+ call find_nonb ;find first non blank in com. buffer\r
+ jc bad_args ;file (or files) missing\r
+ mov byte ptr [di],0 ;nul terminate\r
+ mov dx,si ;pointer to file name\r
+ mov bx,offset dg:buf1\r
+ mov word ptr [bx].fname,dx ;save pointer to file name\r
+ mov word ptr [bx].fname_len,cx ;file name length\r
+ mov ah,open\r
+ mov al,0 ;open for reading\r
+ int 21h\r
+ jc bad_file\r
+ mov word ptr [bx].handle,ax ;save the handle\r
+\r
+ mov si,di\r
+ inc si ;point past the nul\r
+ call kill_bl ;find other file name\r
+ jc bad_args ;a CR found: file name missing\r
+ dec si ;adjust pointer\r
+ call find_nonb\r
+ mov byte ptr [di],0 ;nul terminate the file name\r
+ mov dx,si\r
+ mov bx,offset dg:buf2\r
+ mov word ptr [bx].fname,dx ;save pointer to file name\r
+ mov word ptr [bx].fname_len,cx ;file name length\r
+ mov ah,open\r
+ mov al,0 ;open for reading\r
+ int 21h\r
+ jc bad_file\r
+ mov word ptr [bx].handle,ax ;save the handle\r
+ jmp short go_compare\r
+\r
+bad_file:\r
+ cmp ax,error_file_not_found\r
+ je sj01\r
+ mov dx,offset dg:int_err\r
+ mov cl,int_err_len\r
+ jmp short an_err\r
+sj01:\r
+ push cx ;save file name length\r
+ mov dx,offset dg:found_err_pre\r
+ mov cl,found_err_pre_len\r
+ call prt_err\r
+ pop cx\r
+ mov dx,si ;pointer to file name length\r
+ call prt_err\r
+ mov dx,offset dg:found_err_post\r
+ mov cl,found_err_post_len\r
+an_err:\r
+ call prt_err\r
+ mov al,-1 ;return an error code\r
+ mov ah,exit\r
+ int 21h\r
+\r
+\r
+\r
+;-----------------------------------------------------------------------;\r
+; CHECK COMPARE MODE\r
+\r
+go_compare:\r
+ cmp [flg_b],true ;do we do a binary comparation?\r
+ je bin_compare\r
+ jmp txt_compare\r
+\r
+\r
+ subttl Binary Compare Routine\r
+ page\r
+\r
+;-----------------------------------------------------------------------;\r
+; COMPARE BUFFERS IN BINARY MODE\r
+\r
+bin_compare:\r
+\r
+;----- Fill in the buffers\r
+\r
+ mov bx,offset dg:buf1 ;pointer to buffer structure\r
+ mov dx,word ptr[bx].buf ;pointer to buffer\r
+ mov si,dx ;save for latter comparation\r
+ call read_dat ;read into buffer\r
+ jc bad_datj ;an error\r
+ mov word ptr[bx].by_read,AX ;save ammount read\r
+ push ax ;save for now\r
+\r
+ mov bx,offset dg:buf2 ;pointer to buffer structure\r
+ mov dx,word ptr[bx].buf ;pointer to buffer\r
+ mov di,dx ;save for comparation\r
+ call read_dat ;read into buffer\r
+bad_datj: jc bad_dat ;an error\r
+ mov word ptr[bx].by_read,AX ;save ammount read\r
+\r
+ pop cx ;restore byte count of buffer1\r
+ cmp ax,cx ;compare byte counts\r
+ ja morein_b2\r
+ jb morein_b1\r
+ or ax,ax ;the same ammount, is it 0?\r
+ jne go_bcomp ;no,compare\r
+ jmp go_quit ;yes, all done....\r
+\r
+morein_b2:\r
+ mov [bend],1 ;file 1 ended\r
+ jmp short go_bcomp\r
+\r
+morein_b1:\r
+ mov [bend],2 ;file 2 ended\r
+ mov cx,ax\r
+\r
+;----- Compare data in buffers\r
+\r
+go_bcomp:\r
+ mov ax,word ptr [base] ;load base addrs. to AX,BX pair\r
+ mov bx,word ptr [base+2]\r
+ add bx,cx ;add to base num. of bytes to\r
+ adc ax,0 ; compare.\r
+ mov word ptr [base],ax ;save total\r
+ mov word ptr [base+2],bx\r
+\r
+next_bcomp:\r
+ cld\r
+ jcxz end_check\r
+ repz cmpsb ;compare both buffers\r
+ jz end_check ;all bytes match\r
+ push cx ;save count so far\r
+ push ax\r
+ push bx\r
+ inc cx\r
+ sub bx,cx ;get file address of bytes that\r
+ sbb ax,0 ; are different.\r
+ call prt_bdif ;print difference\r
+ pop bx\r
+ pop ax\r
+ pop cx ;restore on-going comparation count\r
+ jmp short next_bcomp\r
+\r
+bnot_yet:\r
+ jmp bin_compare\r
+\r
+end_check:\r
+ cmp [bend],0 ;have any file ended yet?\r
+ je bnot_yet ;no, read in more data\r
+ cmp [bend],1 ;yes, was it file 1?\r
+ je bf1_ended ;yes, data left in file 2\r
+ mov dx,offset dg:bf1ne\r
+ mov cl,bf1ne_len\r
+ jmp short bend_mes\r
+\r
+bf1_ended:\r
+ mov dx,offset dg:bf2ne\r
+ mov cl,bf2ne_len\r
+\r
+bend_mes:\r
+ xor ch,ch\r
+ call prout\r
+ jmp go_quit\r
+\r
+\r
+\r
+ subttl Text Compare Routine\r
+ page\r
+\r
+;-----------------------------------------------------------------------;\r
+; Fill in the buffers\r
+\r
+bad_dat:\r
+ mov dx,offset dg:file_err\r
+ mov cl,file_err_len\r
+ jmp an_err\r
+\r
+\r
+txt_compare:\r
+\r
+ mov bx,offset dg:buf1\r
+ mov dx,word ptr [bx].buf\r
+ mov word ptr [bx].fst_nosinc,dx\r
+ mov word ptr [bx].curr,dx\r
+\r
+ call fill_buffer\r
+ jc bad_dat\r
+\r
+ mov bx,offset dg:buf2\r
+ mov dx,word ptr [bx].buf\r
+ mov word ptr [bx].fst_nosinc,dx\r
+ mov word ptr [bx].curr,dx\r
+\r
+ call fill_buffer\r
+ jc bad_dat\r
+\r
+\r
+;-----------------------------------------------------------------------;\r
+; COMPARE BUFFERS IN TEXT MODE\r
+\r
+another_line:\r
+ call go_match ;try to match both current lines\r
+ jc sj02 ;a match\r
+ jmp no_match ;no match, continue....\r
+sj02:\r
+ cmp byte ptr[sinc],true ;are we in SINC?\r
+ je sj04\r
+ mov ax,[mtch_cntr]\r
+ or ax,ax ;first line of a possible SINC?\r
+ jnz sj03\r
+ mov bx,offset dg:buf1\r
+ mov word ptr [bx].fst_sinc,si ;yes, save curr line buffer 1\r
+ mov bx,offset dg:buf2\r
+ mov word ptr [bx].fst_sinc,di ;save curr line buffer 2\r
+sj03:\r
+ inc ax ;increment match counter\r
+ mov [mtch_cntr],ax ;save number of matches\r
+ cmp m_num,ax ;enough lines matched for a SINC?\r
+ jne sj04 ;not yet, match some more\r
+ mov [sinc],true ;yes, flag we are now in sinc\r
+ call print_diff ;print mismatched lines\r
+\r
+\r
+\r
+;-----------------------------------------------------------------------;\r
+; Advance current line pointer in both buffers\r
+\r
+sj04:\r
+ mov bx,offset dg:buf1\r
+ call adv_b\r
+ jnc sj05\r
+ jmp no_more1\r
+sj05:\r
+ mov word ptr[bx].curr,si\r
+ mov bx,offset dg:buf2\r
+ call adv_b\r
+ jnc sj051\r
+ jmp no_more2\r
+sj051:\r
+ mov word ptr[bx].curr,si\r
+ jmp another_line ;continue matching\r
+\r
+\r
+\r
+;-----------------------------------------------------------------------;\r
+; Process a mismatch\r
+\r
+no_match:\r
+ cmp [sinc],true ;are we in SINC?\r
+ jne sj06\r
+ mov [sinc],false ;not any more....\r
+ mov bx,offset dg:buf1\r
+ mov word ptr [bx].fst_nosinc,si ;save current lines\r
+ mov word ptr [bx].lst_curr,si\r
+ mov bx,offset dg:buf2\r
+ mov word ptr [bx].fst_nosinc,di\r
+ mov word ptr [bx].lst_curr,di\r
+sj06:\r
+ mov [mtch_cntr],0 ;reset match counter\r
+ cmp [mode],true\r
+ je sj09\r
+\r
+;----- MODE A -----\r
+ mov bx,offset dg:buf2\r
+ call adv_b ;get next line in buffer (or file)\r
+ jc sj08 ;no more lines in buffer\r
+sj07:\r
+ mov word ptr [bx].curr,si\r
+ jmp another_line\r
+sj08:\r
+ mov [mode],true ;change mode\r
+ mov si,word ptr [bx].lst_curr\r
+ mov word ptr [bx].curr,si\r
+ mov bx,offset dg:buf1\r
+ mov si,word ptr [bx].lst_curr\r
+ mov word ptr [bx].curr,si\r
+ call adv_b ;get next line\r
+ jc no_more1 ;no more lines fit in buffer 1\r
+ mov word ptr [bx].lst_curr,si\r
+ jmp short sj10\r
+\r
+;----- MODE B -----\r
+sj09:\r
+ mov bx,offset dg:buf1\r
+ call adv_b ;get next line in buffer (or file)\r
+ jc sj11 ;no more lines in buffer\r
+sj10:\r
+ mov word ptr [bx].curr,si\r
+ jmp another_line\r
+\r
+sj11:\r
+ mov [mode],false\r
+ mov si,word ptr [bx].lst_curr\r
+ mov word ptr [bx].curr,si\r
+ mov bx,offset dg:buf2\r
+ mov si,word ptr [bx].lst_curr\r
+ mov word ptr [bx].curr,si\r
+ call adv_b ;get next line\r
+ jc no_more2 ;no more lines fit in buffer 2\r
+ mov word ptr [bx].lst_curr,si\r
+ jmp sj07\r
+\r
+\r
+\r
+;-----------------------------------------------------------------------;\r
+; Process end of files\r
+\r
+no_more1:\r
+ cmp ax,0 ;end of file reached?\r
+ jz xj1\r
+ jmp dif_files ;no, difference was too big\r
+xj1:\r
+ cmp [sinc],true ;file1 ended, are we in SINC?\r
+ je xj3\r
+ jmp no_sinc\r
+xj3:\r
+ mov bx,offset dg:buf2\r
+ call adv_b ;advance current line in buf2\r
+ jnc xj5\r
+ jmp go_quit ;file2 ended too, terminate prog.\r
+xj5:\r
+\r
+;----- File 1 ended but NOT file 2\r
+ mov bx,offset dg:buf1\r
+ call print_head\r
+ mov bx,offset dg:buf2\r
+ call print_head\r
+ call print_all ;print the rest of file2\r
+ jmp go_quit\r
+\r
+\r
+no_more2:\r
+ cmp ax,0 ;end of file reached?\r
+ jz xj2\r
+ jmp dif_files ;no, difference was too big\r
+xj2:\r
+ cmp [sinc],true ;file1 ended, are we in SINC?\r
+ je xj4\r
+ jmp no_sinc\r
+xj4:\r
+ mov bx,offset dg:buf1\r
+ call adv_b ;advance current line in buf2\r
+ jnc xj6\r
+ jmp go_quit ;file2 ended too, terminate prog.\r
+xj6:\r
+\r
+;----- File 2 ended but NOT file 1\r
+ mov bx,offset dg:buf1\r
+ call print_head\r
+ call print_all ;print the rest of file1\r
+ mov bx,offset dg:buf2\r
+ call print_head\r
+ jmp go_quit\r
+\r
+\r
+\r
+no_sinc:\r
+ mov bx,offset dg:buf1\r
+ call print_head\r
+ call print_all\r
+ mov bx,offset dg:buf2\r
+ call print_head\r
+ call print_all\r
+ jmp go_quit\r
+\r
+\r
+\r
+dif_files:\r
+ mov dx,offset dg:dif_err\r
+ mov cl,dif_err_len\r
+ jmp an_err\r
+\r
+go_quit:\r
+ mov al,0\r
+ mov ah,exit\r
+ int 21h\r
+\r
+\r
+ subttl Subroutines: make caps\r
+ page\r
+\r
+;-----------------------------------------------------------------------;\r
+; CAPIALIZES THE CHARACTER IN AL ;\r
+; ;\r
+; entry: ;\r
+; AL has the character to Capitalize ;\r
+; ;\r
+; exit: ;\r
+; AL has the capitalized character ;\r
+; ;\r
+; Called from MAIN and go_match ;\r
+;-----------------------------------------------------------------------;\r
+make_caps:\r
+ cmp al,'a'\r
+ jb sa1\r
+ cmp al,'z'\r
+ jg sa1\r
+ and al,0dfh\r
+sa1: ret\r
+\r
+\r
+ subttl Subroutines: kill_bl\r
+ page\r
+\r
+;-----------------------------------------------------------------------;\r
+; Get rid of blanks in command line. ;\r
+; ;\r
+; entry: ;\r
+; SI points to the first character on the line to scan. ;\r
+; ;\r
+; exit: ;\r
+; SI points to the next char after the first non-blank ;\r
+; char found. ;\r
+; Carry Set if a CR found ;\r
+; ;\r
+; modifies: ;\r
+; SI and AX ;\r
+; ;\r
+; Called from MAIN ;\r
+;-----------------------------------------------------------------------;\r
+kill_bl:\r
+ cld ;increment\r
+sb1: lodsb ;get rid of blanks\r
+ cmp al,' '\r
+ je sb1\r
+ cmp al,9\r
+ je sb1\r
+ cmp al,CR\r
+ clc ;assume not a CR\r
+ jne sb2\r
+ stc ;a CR found, set carry\r
+sb2: ret\r
+\r
+\r
+ subttl Subroutines: find_nonb\r
+ page\r
+\r
+;-----------------------------------------------------------------------;\r
+; Find the first non-blank in a line ;\r
+; ;\r
+; entry: ;\r
+; SI points to the line buffer ;\r
+; ;\r
+; exit: ;\r
+; DI pointer to the first blank found (incl. CR) ;\r
+; CX character count of non-blanks ;\r
+; Carry Set if a CR was found ;\r
+; ;\r
+; modifies: ;\r
+; AX ;\r
+; ;\r
+; Called from MAIN ;\r
+;-----------------------------------------------------------------------;\r
+find_nonb:\r
+ push si ;save pointer\r
+ xor cx,cx ;zero character count\r
+ cld\r
+sc1:\r
+ lodsb\r
+ cmp al,' '\r
+ je sc2\r
+ cmp al,9\r
+ je sc2\r
+ cmp al,CR\r
+ je sc2\r
+ inc cx ;inc character count\r
+ jmp short sc1\r
+sc2:\r
+ dec si\r
+ mov di,si\r
+ pop si\r
+ cmp al,CR\r
+ jne sc3\r
+ stc\r
+ ret\r
+sc3:\r
+ clc\r
+ ret\r
+\r
+\r
+ subttl Subroutines: prt_bdif\r
+ page\r
+\r
+;-----------------------------------------------------------------------;\r
+; Print a binary difference ;\r
+; ;\r
+; entry: ;\r
+; AX,BX file address of diference ;\r
+; SI pointer to one past byte in buffer1 ;\r
+; DI pointer to one past byte in buffer2 ;\r
+; ;\r
+; modifies: ;\r
+; AX, DX and CX ;\r
+; ;\r
+; called from bin_compare ;\r
+;-----------------------------------------------------------------------;\r
+prt_bdif:\r
+ cmp [bhead_flg],true ;have we peinted head yet?\r
+ je bhead_ok\r
+ mov [bhead_flg],true ;no, set flag\r
+ push ax ;print heading\r
+ mov dx,offset dg:bhead\r
+ mov cl,bhead_len\r
+ xor ch,ch\r
+ call prout\r
+ pop ax\r
+\r
+bhead_ok:\r
+ mov dx,di ;conver file address\r
+ mov di,offset dg:bp_buf1\r
+ push ax\r
+ mov al,ah\r
+ call bin2hex\r
+ pop ax\r
+ call bin2hex\r
+ mov al,bh\r
+ call bin2hex\r
+ mov al,bl\r
+ call bin2hex\r
+\r
+ mov di,offset dg:bp_buf2 ;convert byte from file 1\r
+ mov al, byte ptr[si-1]\r
+ call bin2hex\r
+\r
+ mov di,offset dg:bp_buf3 ;convert byte from file 2\r
+ push si\r
+ mov si,dx\r
+ mov al, byte ptr[si-1]\r
+ pop si\r
+ call bin2hex\r
+\r
+ mov di,dx ;print result\r
+ mov dx,offset dg:bp_buf\r
+ mov cx,bp_buf_len\r
+ call prout\r
+ ret\r
+\r
+\r
+ subttl Subroutines: bin2hex\r
+ page\r
+\r
+;-----------------------------------------------------------------------;\r
+; Binary to ASCII hex conversion ;\r
+; ;\r
+; entry: ;\r
+; AL byte to convert ;\r
+; DI pointer to were the two result ASCII bytes should go ;\r
+; ;\r
+; exit: ;\r
+; DI points to one past were the last result byte whent ;\r
+; ;\r
+; modifies: ;\r
+; AH and CL ;\r
+; ;\r
+; Called from prt_bdif ;\r
+;-----------------------------------------------------------------------;\r
+bin2hex:\r
+ mov cl,4\r
+ ror ax,cl ;get the high nibble\r
+ and al,0fh ;mask of high nible\r
+ call pt_hex\r
+ rol ax,cl ;get the low nibble\r
+ and al,0fh ;mask....\r
+\r
+pt_hex:\r
+ cmp al,0ah ;is it past an A ?\r
+ jae pasta\r
+ add al,30h\r
+ jmp short put_hex\r
+pasta:\r
+ add al,37h\r
+put_hex:\r
+ stosb ;place in buffer\r
+ ret\r
+\r
+\r
+ subttl Subroutines: go_match\r
+ page\r
+\r
+;-----------------------------------------------------------------------;\r
+; Match current lines ;\r
+; ;\r
+; exit: ;\r
+; Carry set if the match reset otherwise ;\r
+; SI Current line of buff1 ;\r
+; DI Current line of buff2 ;\r
+; ;\r
+; ;\r
+; modifies: ;\r
+; AX,BX,CX,DX and BP ;\r
+; ;\r
+; Called from txt_compare ;\r
+;-----------------------------------------------------------------------;\r
+go_match:\r
+ mov bx,offset dg:buf1\r
+ mov si,word ptr[bx].curr\r
+ push si\r
+ mov bp,si ;save line pointer\r
+ call find_eol\r
+ mov dx,cx ;save length of line\r
+ mov bx,offset dg:buf2\r
+ mov si,word ptr[bx].curr\r
+ push si\r
+ mov di,si\r
+ call find_eol\r
+ cmp cx,dx ;compare lengths\r
+ jne sd1 ;they do not match\r
+ mov si,bp ;restore line pointer\r
+ jcxz sd4 ;both length = 0, they match\r
+ push cx ;save the length\r
+ cld\r
+ repz cmpsb ;compare strings\r
+ pop cx ;restore the length\r
+ jz sd4 ;they match\r
+sd1:\r
+ cmp [flg_w],true ;do we ignore multiple whites?\r
+ je ib_compare ;yes, go compare\r
+ cmp [flg_c],true ;do we ignore case differences?\r
+ je ic_compare ;yes, go compare\r
+sd3:\r
+ clc ;they don't match\r
+ jmp short sd5\r
+sd4:\r
+ stc\r
+sd5:\r
+ pop di ;curr2\r
+ pop si ;curr1\r
+ ret\r
+\r
+\r
+ page\r
+\r
+;-----------------------------------------------------------------------;\r
+; Compare ignoring case differences.\r
+\r
+ic_compare:\r
+ pop di ;get pointer to lines\r
+ pop si\r
+ push si ;re-save pointers\r
+ push di\r
+sd8:\r
+ mov al,byte ptr [si] ;get next char. of first line\r
+ call make_caps\r
+ mov bl,al ;save capitalized char\r
+ mov al,byte ptr [di] ;get next chra. of second line\r
+ call make_caps\r
+ cmp al,bl\r
+ jne sd3 ;they do not match....\r
+ inc si ;advance pointers\r
+ inc di\r
+ loop sd8 ;loop for the line lengths\r
+ jmp short sd4 ;they match\r
+\r
+\r
+ page\r
+\r
+;-----------------------------------------------------------------------;\r
+; Compare compressing whites and ignoring case differences if\r
+; desired too.\r
+\r
+ib_compare:\r
+ mov [ib_first1],true ;we start by the first char in the\r
+ mov [ib_first2],true ; in the lines.\r
+ pop di ;get pointer to lines\r
+ pop si\r
+ push si ;re-save pointers\r
+ push di\r
+sd9:\r
+ mov al,byte ptr [si] ;get next char. of first line\r
+ call isa_white ;is it a white?\r
+ jnc sd12 ;no, compare....\r
+sd10:\r
+ mov al,byte ptr [si+1] ;peek to next,\r
+ call isa_white ; it is a white too?\r
+ jnc sd11\r
+ inc si ; yes,\r
+ jmp short sd10 ; compress all whites to a blank\r
+sd11:\r
+ cmp [ib_first1],true ;is this the first char. of the line?\r
+ jne sd111 ;no, it stays a white\r
+ inc si ;ignore the white\r
+ jmp short sd12\r
+sd111:\r
+ cmp al,CR ;is this the last char. of the line\r
+ jne sd112 ;no, it stays a white\r
+ inc si ;yes, ignore the whites\r
+ jmp short sd12\r
+sd112:\r
+ mov al,' ' ;no more whites found\r
+\r
+sd12:\r
+ cmp [ib_first1],true ;is this the first char. of the line?\r
+ jne sd121 ;no, continue\r
+ mov [ib_first1],false ;yes, reset the flag\r
+sd121:\r
+ cmp [flg_c],true ;do we ignore case?\r
+ jne sd122 ;no,....\r
+ call make_caps\r
+sd122:\r
+ mov bl,al ;save char\r
+ mov al,byte ptr [di] ;get next chra. of second line\r
+ call isa_white\r
+ jnc sd15\r
+sd13:\r
+ mov al,byte ptr [di+1] ;peek to next as before\r
+ call isa_white\r
+ jnc sd14\r
+ inc di\r
+ jmp short sd13\r
+sd14:\r
+ cmp [ib_first2],true ;is this the first char. of the line?\r
+ jne sd141 ;no, it stays a white\r
+ inc di ;ignore the white\r
+ jmp short sd15\r
+sd141:\r
+ cmp al,CR ;is this the last char. of the line\r
+ jne sd142 ;no, it stays a white\r
+ inc si ;yes, ignore the whites\r
+ jmp short sd15\r
+sd142:\r
+ mov al,' '\r
+\r
+sd15:\r
+ cmp [ib_first2],true ;is this the first char. of the line?\r
+ jne sd151 ;no, continue\r
+ mov [ib_first2],false ;yes, reset the flag\r
+sd151:\r
+ cmp [flg_c],true ;do we ignore case?\r
+ jne sd152 ;no,....\r
+ call make_caps\r
+sd152:\r
+ cmp al,bl\r
+ je sd153\r
+ jmp sd3 ;they do not match....\r
+sd153:\r
+ cmp al,CR ;have we reached the end?\r
+ jne sd154 ;no, continue....\r
+ jmp sd4 ;yes, they match\r
+sd154:\r
+ inc si ;no, advance pointers\r
+ inc di\r
+ jmp sd9 ;loop for the line lengths\r
+\r
+\r
+isa_white:\r
+ cmp al,' ' ;is it a space?\r
+ je sdx1\r
+ cmp al,09h ;is it a tab?\r
+ je sdx1\r
+ clc ;if not a white return with carry clear\r
+ ret\r
+sdx1:\r
+ stc ;is a white return with carry set\r
+ ret\r
+\r
+\r
+ page\r
+\r
+;-----------------------------------------------------------------------;\r
+find_eol:\r
+ xor cx,cx ;zero count\r
+ cld\r
+sd6:\r
+ lodsb\r
+ cmp al,CR\r
+ je sd7\r
+ inc cx\r
+ jmp short sd6\r
+sd7:\r
+ ret\r
+\r
+\r
+ subttl Subroutines: adv_b\r
+ page\r
+\r
+;-----------------------------------------------------------------------;\r
+; Get the next line in the buffer ;\r
+; ;\r
+; It will attempt to get the next current line from the buffer ;\r
+; if it fails, it will force a refill, and if some data is read in ;\r
+; then it will return the next current line. ;\r
+; ;\r
+; entry: ;\r
+; BX pointer to buffer structure ;\r
+; ;\r
+; exit: ;\r
+; SI pointer to next line (if any) ;\r
+; Carry set if no more lines available. If carry set then: ;\r
+; AX End Code: 0 = end of file reached ;\r
+; 1 = no room in buffer for a line ;\r
+; ;\r
+; modifies: ;\r
+; CX,DX and DI ;\r
+; ;\r
+; Called from txt_compare ;\r
+;-----------------------------------------------------------------------;\r
+adv_b:\r
+ call get_nextl\r
+ jc se1\r
+ ret\r
+se1:\r
+ call refill\r
+ jnc se0\r
+ ret\r
+se0:\r
+ call get_nextl\r
+ ret\r
+\r
+\r
+ subttl Subroutines: get_nextl\r
+ page\r
+\r
+;-----------------------------------------------------------------------;\r
+; Returns the next line in a buffer ;\r
+; (next from current or next from pointer) ;\r
+; ;\r
+; entry: ;\r
+; BX pointer to buffer structure ;\r
+; (SI pointer to line, if calling get_next) ;\r
+; ;\r
+; exit: ;\r
+; SI pointer to next line ;\r
+; Carry set if no more lines available ;\r
+; ;\r
+; modifies: ;\r
+; DI and CX ;\r
+; ;\r
+; Called from adv_b and print_diff (in the case of get_next) ;\r
+;-----------------------------------------------------------------------;\r
+get_nextl:\r
+ mov si,word ptr [bx].curr\r
+get_next:\r
+ mov cx,word ptr [bx].dat_end\r
+ sub cx,si\r
+ mov di,si\r
+ mov al,LF\r
+ cld\r
+ repnz scasb\r
+ mov si,di ;pointer to next line\r
+ jnz se2 ;not found\r
+ clc\r
+ ret\r
+se2:\r
+ inc si ;point past the LF\r
+ stc\r
+ ret\r
+\r
+\r
+ subttl Subroutines: refill\r
+ page\r
+\r
+;-----------------------------------------------------------------------;\r
+; Refill a buffer ;\r
+; ;\r
+; It will refill a buffer with data from the corresponding ;\r
+; file. It will first recompact the buffer to make room for the new ;\r
+; data. If in SINC then it will move the current line to the top of ;\r
+; the buffer, and read the data from the end of this line till the ;\r
+; end of the buffer. ;\r
+; If NOT in SINC then it will recompact the buffer by moving ;\r
+; all lines between the first to go out of SINC till the current line ;\r
+; to the top of the buffer, and then reading data after the current ;\r
+; line. ;\r
+; When recompacting the buffer it relocates all pointers to ;\r
+; point to the new locations of the respective lines. ;\r
+; Some of the pointers may be pointing to meaningless locations ;\r
+; before the relocation, and consecuently they will be pointing to ;\r
+; even less meaningfull locations after relocation. ;\r
+; After reading the data it normalizes the buffer to make sure ;\r
+; that no partially full lines are present at the end of the buffer. If ;\r
+; after recompacting and reading some character it is found that the ;\r
+; characters read do not constitute a full line, then it will return ;\r
+; with an error code. It will also return with an error code if it ;\r
+; attempts to read past the end of file. ;\r
+; ;\r
+; entry: ;\r
+; BX pointer to buffer structure ;\r
+; ;\r
+; exit: ;\r
+; Carry set if no chars read into the buffer. If carry set then: ;\r
+; AX End Code: 0 = end of file reached ;\r
+; 1 = no room in the buffer for a line ;\r
+; ;\r
+; modifies: ;\r
+; CX,DX,SI and DI ;\r
+; ;\r
+; Called from adv_b ;\r
+;-----------------------------------------------------------------------;\r
+refill:\r
+\r
+;----- Calculate ammount to move & pointer relocation factor.\r
+\r
+ cmp [sinc],true\r
+ jne sf1\r
+ mov si,word ptr [bx].curr\r
+ jmp short sf2\r
+sf1:\r
+ mov si,word ptr [bx].fst_nosinc\r
+sf2:\r
+ mov di,word ptr [bx].buf\r
+ mov cx,word ptr [bx].dat_end\r
+\r
+ mov dx,si ;calculate pointer relocation factor\r
+ sub dx,di ;DX = factor\r
+ jz sf3 ;no room in buffer\r
+ sub cx,si ;calculate ammount of data to move\r
+ inc cx ;CX = ammount\r
+\r
+;----- Move data\r
+\r
+ cld ;auto decrement\r
+ rep movsb\r
+\r
+;----- Relocate pointers\r
+\r
+ sub word ptr [bx].curr,dx\r
+ sub word ptr [bx].lst_curr,dx\r
+ sub word ptr [bx].fst_sinc,dx\r
+ sub word ptr [bx].fst_nosinc,dx\r
+ sub word ptr [bx].dat_end,dx\r
+\r
+sf3:\r
+ mov dx,word ptr [bx].dat_end\r
+ inc dx ;empty part starts here\r
+\r
+;----- fill the buffer\r
+\r
+ call fill_buffer\r
+ ret\r
+\r
+\r
+ subttl Subroutines: fill_buffer\r
+ page\r
+\r
+;-----------------------------------------------------------------------;\r
+; Fill the data buffers ;\r
+; ;\r
+; It will fill the buffer from the pointer to the end of buffer ;\r
+; and normalize the buffer. ;\r
+; ;\r
+; entry: ;\r
+; BX pointer to buffer structure ;\r
+; DX pointer to buffer (or part of buffer) ;\r
+; ;\r
+; exit: ;\r
+; Carry set if no chars read into the buffer. If carry set then: ;\r
+; AX End Code: 0 = end of file reached ;\r
+; 1 = no room in the buffer for a line ;\r
+; ;\r
+; modifies: ;\r
+; AX,CX,DX and DI ;\r
+; ;\r
+; Called from txt_compare and refill ;\r
+;-----------------------------------------------------------------------;\r
+fill_buffer:\r
+ push bx\r
+ call read_dat ;get data\r
+ jc bad_read\r
+ or ax,ax ;zero chars read?\r
+ jz rd_past_eof\r
+ call nor_buf\r
+ mov di,cx ;save normalized char. count\r
+ mov bp,dx ;save data end for now\r
+\r
+;----- seek for old partial line\r
+\r
+ or ax,ax ;is the seek value = 0 ?\r
+ jz sg1 ;yes, do not seek\r
+ mov dx,ax\r
+ neg dx\r
+ mov cx,-1\r
+ mov al,1 ;seek from current position\r
+ mov ah,lseek\r
+ int 21h\r
+ jc bad_read ;error mesage (BX already in stack)\r
+\r
+sg1:\r
+ mov cx,di ;restore normalized char count.\r
+ or cx,cx ;char count = 0 due to normalization?\r
+ jz no_room\r
+\r
+ pop bx\r
+ mov word ptr [bx].dat_end,bp\r
+ clc\r
+ ret\r
+\r
+bad_read:\r
+ mov dx,offset dg:read_err_pre\r
+ mov cl,read_err_pre_len\r
+ call prt_err ;print error message\r
+ pop bx\r
+ mov dx,word ptr[bx].fname\r
+ mov cx,word ptr[bx].fname_len\r
+ call prt_err ;print file name\r
+ mov dx,offset dg:read_err_post\r
+ mov cl,read_err_post_len\r
+ jmp an_err\r
+\r
+no_room:\r
+ mov ax,1\r
+ jmp short sg2\r
+\r
+rd_past_eof:\r
+ xor ax,ax\r
+sg2:\r
+ pop bx\r
+ stc\r
+ ret\r
+\r
+\r
+ subttl Subroutines: read_dat\r
+ page\r
+\r
+;-----------------------------------------------------------------------;\r
+; ;\r
+; entry: ;\r
+; DX pointer to data area (buffer or part of buffer) ;\r
+; ;\r
+; exit: ;\r
+; AX character count or error code (from DOS read) ;\r
+; Carry set if error condition ;\r
+; ;\r
+; modifies: ;\r
+; BX and CX ;\r
+; ;\r
+; Called from fill_buffer, print_all and bin_compare ;\r
+;-----------------------------------------------------------------------;\r
+read_dat:\r
+ mov cx,word ptr [bx].buf_end\r
+ mov bx,word ptr [bx].handle\r
+ sub cx,dx ;ammount to read to buff1\r
+ mov ah,read\r
+ int 21h\r
+ ret\r
+\r
+\r
+ subttl Subroutines: nor_buf\r
+ page\r
+\r
+;-----------------------------------------------------------------------;\r
+; Normalize buffers so they do not have partially full ;\r
+; lines at the end. If character count is less than the buffer size ;\r
+; then it checks that the last line is terminated by a CR,LF pair. ;\r
+; If it is not it inserts a CR,LF at the end. It returns a seek value ;\r
+; for the buffer corresponding to the number of characters in the ;\r
+; incomplete line at the end of the buffer (if any). This can be used ;\r
+; to start reading from the beggining of the incomplete line on next ;\r
+; time the buffer is loaded. ;\r
+; ;\r
+; ENTRY: ;\r
+; DX buffer pointer ;\r
+; AX character count read ;\r
+; CX character count requested ;\r
+; ;\r
+; EXIT: ;\r
+; DX pointer to last char in buffer (normalized) ;\r
+; CX character count (normalized) ;\r
+; AX seek value ;\r
+; ;\r
+; MODIFIES: ;\r
+; DI ;\r
+; ;\r
+; Called from fill_buffer ;\r
+;-----------------------------------------------------------------------;\r
+nor_buf:\r
+ mov di,dx\r
+ add di,ax\r
+ dec di ;points to last char in buffer\r
+ cmp ax,cx ;were all chars. requested read?\r
+ je sm7 ;yes, buffer full\r
+ cmp byte ptr[di],1ah ;terminated with a ^Z ?\r
+ jne sm1\r
+ dec di ;point to previous character\r
+ dec ax ;decrement character count\r
+sm1: cmp byte ptr[di],lf ;is last char a LF?\r
+ je sm6\r
+ cmp byte ptr[di],cr ;is it a CR then?\r
+ je sm5\r
+ add ax,2 ;two more chars in buffer\r
+ inc di\r
+sm2: mov byte ptr[di],cr\r
+sm3: inc di\r
+ mov byte ptr[di],lf\r
+sm4: mov cx,ax ;new character count\r
+ mov dx,di ;pointer to last char\r
+ xor ax,ax ;seek = 0\r
+ ret\r
+\r
+sm5:\r
+ inc ax ;one more char in buffer\r
+ jmp short sm3\r
+\r
+sm6:\r
+ cmp byte ptr[di-1],cr ;is previous char a CR?\r
+ je sm4\r
+ inc ax ;no, one more char in buffer\r
+ jmp short sm2\r
+\r
+sm7:\r
+ push ax ;save char count\r
+ mov cx,ax\r
+ mov al,LF\r
+ std\r
+ repnz scasb ;search for last LF\r
+ pop ax ;restore char count\r
+ jnz bad_line ;none found, line too big\r
+ inc di ;point to last LF\r
+ mov dx,di\r
+ inc cx ;ammount of chars in buffer\r
+ sub ax,cx ;seek value\r
+ ret\r
+\r
+bad_line: ;full line not possible, return\r
+ mov dx,di ; with AX=count, CX=0 and DX=\r
+ ret ; old last char in buffer pointer.\r
+\r
+\r
+\r
+ subttl Subroutines: print_diff\r
+ page\r
+\r
+;-----------------------------------------------------------------------;\r
+; print the difference between buffers ;\r
+; ;\r
+; It will print the mismatched lines. First it prints a heading ;\r
+; with the first file name, then the lines that differ from file 1, ;\r
+; then a heading with the second file name, and then the lines that ;\r
+; differ in file 2 . ;\r
+; The lines that differ are considered to start from fst_nosinc ;\r
+; till fst_sinc. ;\r
+; ;\r
+; Called from txt_compare ;\r
+;-----------------------------------------------------------------------;\r
+print_diff:\r
+ mov bx,offset dg:buf1\r
+ call print_head ;print heading for file 1\r
+ mov dx,word ptr [bx].fst_nosinc\r
+ mov si,word ptr [bx].fst_sinc\r
+ call get_next ;get pointer to next line\r
+ mov cx,si\r
+ sub cx,dx ;get character count\r
+ call prout\r
+ mov bx,offset dg:buf2\r
+ call print_head ;print heading for file 1\r
+ mov dx,word ptr [bx].fst_nosinc\r
+ mov si,word ptr [bx].fst_sinc\r
+ call get_next ;get pointer to next line\r
+ mov cx,si\r
+ sub cx,dx ;get character count\r
+ call prout\r
+ mov dx,offset dg:diff_sep\r
+ mov cl,diff_sep_len\r
+ xor ch,ch\r
+ call prout ;print difference separator\r
+ ret\r
+\r
+\r
+ subttl Subroutines: print_head\r
+ page\r
+\r
+;-----------------------------------------------------------------------;\r
+; Print heading for difference ;\r
+; ;\r
+; entry: ;\r
+; BX pointer to buffer structure ;\r
+; ;\r
+; modifies: ;\r
+; AX,CX and DX ;\r
+; ;\r
+; Called from txt_compare and print_diff ;\r
+;-----------------------------------------------------------------------;\r
+print_head:\r
+ mov dx,offset dg:fname_sep\r
+ mov cl,fname_sep_len\r
+ xor ch,ch\r
+ call prout\r
+ mov dx,word ptr [bx].fname\r
+ mov cx,word ptr [bx].fname_len\r
+ call prout\r
+ mov dx,offset dg:CRLF\r
+ mov cx,2\r
+ call prout\r
+ ret\r
+\r
+\r
+ subttl Subroutines: print_all\r
+ page\r
+\r
+;-----------------------------------------------------------------------;\r
+; Print the rest of a file ;\r
+; ;\r
+; If in SINC it will print the file from the fst_nosinc line ;\r
+; till the end of the file. If NOT in SINC then it will print from ;\r
+; the current line of the buffer to the end of the file. ;\r
+; ;\r
+; entry: ;\r
+; BX pointer to buffer structure ;\r
+; ;\r
+; modifies: ;\r
+; AX,CX and DX ;\r
+; ;\r
+; Called from txt_compare ;\r
+;-----------------------------------------------------------------------;\r
+print_all:\r
+ cmp [sinc],true ;are we in SINC?\r
+ jne so1\r
+ mov dx,word ptr [bx].curr\r
+ jmp short so2\r
+so1:\r
+ mov dx,word ptr [bx].fst_nosinc\r
+so2:\r
+ mov cx,word ptr [bx].dat_end\r
+ inc cx\r
+\r
+prt_again:\r
+ sub cx,dx ;ammount of data to write\r
+ call prout ;write it out\r
+\r
+;----- Read more data to the buffer\r
+ push bx ;save pointer to buffer struct\r
+ mov dx,word ptr [bx].buf\r
+ call read_dat\r
+ jnc so3\r
+ jmp bad_read ;print error (BX in stack)\r
+so3:\r
+ or ax,ax ;zero chars read?\r
+ jne so4\r
+ pop bx ;all done writting\r
+ ret\r
+so4:\r
+ pop bx\r
+ mov cx,word ptr [bx].buf_end\r
+ jmp short prt_again ;print next buffer full\r
+\r
+\r
+ subttl Subroutines: prout and prt_err\r
+ page\r
+\r
+;-----------------------------------------------------------------------;\r
+; ;\r
+;-----------------------------------------------------------------------;\r
+prout:\r
+ push bx\r
+ mov bx,stdout\r
+ mov ah,write\r
+ int 21h\r
+ pop bx\r
+ ret\r
+\r
+\r
+;-----------------------------------------------------------------------;\r
+; ;\r
+;-----------------------------------------------------------------------;\r
+prt_err:\r
+ push bx\r
+ xor ch,ch\r
+ jcxz retpbx\r
+ mov bx,stderr\r
+ mov ah,write\r
+ int 21h\r
+retpbx:\r
+ pop bx\r
+ ret\r
+\r
+code ends\r
+\r
+ page\r
+\r
+\r
+stack segment stack\r
+\r
+ dw 128 dup(?)\r
+\r
+stack ends\r
+\r
+\r
+ end start\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+;
+; 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
--- /dev/null
+ title MSDOS V2.0 FIND\r
+\r
+;--------------------------------------------------------------------;\r
+; Revision History: ;\r
+; ;\r
+; V1.1 8/23/82 M.A.Ulloa ;\r
+; ;\r
+; V1.2 9/22/82 M.A.Ulloa ;\r
+; Added the -c and -n options ;\r
+; ;\r
+; 9/23/82 M.A.Ulloa ;\r
+; Added DOS version number control ;\r
+; ;\r
+; 10/07/82 Rev.2 M.A.Ulloa ;\r
+; Changed quote for double quotes, and added ;\r
+; file name printing ;\r
+; ;\r
+; 10/20/82 Rev.3 M.A.Ulloa ;\r
+; Modified IBM name to FIND, and changed the text ;\r
+; of some messages. ;\r
+; ;\r
+; 10/25/82 Rev.4 M.A.Ulloa ;\r
+; Changed name to FIND and all messages to the ;\r
+; IBM form. ;\r
+; ;\r
+; 10/27/82 Rev.5 M.A.Ulloa ;\r
+; Made the correct exit on version check in case ;\r
+; of a 1.x DOS. ;\r
+; ;\r
+; 11/4/82 Rev. 5 A.R. Reynolds ;\r
+; Messages moved to external module ;\r
+; ;\r
+; 11/10/82 Rev. 6 M.A. Ulloa ;\r
+; Corrected problem with line numbers, and a problem ;\r
+; with seeking for 0 chars. ;\r
+; ;\r
+; 03/30/83 Rev. 7 M.A. Ulloa ;\r
+; Added patch area for bug fixing. ;\r
+; ;\r
+; 04/14/83 Rev. 8 M.A. Ulloa ;\r
+; Made changes for Kanji characters. (uhg!) ;\r
+; ;\r
+;--------------------------------------------------------------------;\r
+\r
+FALSE equ 0\r
+TRUE equ NOT FALSE\r
+\r
+KANJI equ FALSE ;set to true is kanji vers.\r
+\r
+;--------------------------------------------------------------------;\r
+; FIND program following the standart UNIX operation. ;\r
+; ;\r
+; FORMAT: ;\r
+; find {option} string {filename {filename} {...}} ;\r
+; ;\r
+; NOTES: ;\r
+; 1) String arguments HAVE to be enclosed ;\r
+; in double quotes. (Two double quotes if a ;\r
+; doble quote is to be included). Only ONE ;\r
+; string argument is presently allowed. ;\r
+; ;\r
+; 2) Options are available: ;\r
+; v All lines but those matching are considered ;\r
+; c Only print a count of matching lines ;\r
+; n Each line is preceded by its relative ;\r
+; line number in the file. ;\r
+; ;\r
+; - Options can be Upper or lower case. ;\r
+; - Format: The switch character followed by an options ;\r
+; character. I.e.: In the IBM PC: /v ;\r
+; ;\r
+; 3) The program returns: ;\r
+; 0 - OK, and some matches ;\r
+; 2 - Some Error ;\r
+; ;\r
+; 4) The maximum line size is determined by ;\r
+; buffer size. Bigger lines will bomb the program. ;\r
+; ;\r
+; 5) If no file name is given then it will asssume ;\r
+; the input is comming from the Standart Input. NO ;\r
+; errors are reported when reading from Standart Input. ;\r
+;--------------------------------------------------------------------;\r
+\r
+code segment public\r
+assume cs:code,ss:code,ds:nothing,es:nothing\r
+\r
+\r
+CR equ 0dh ;A Carriage Return\r
+LF equ 0ah ;A Line Feed\r
+quote_char equ 22h ;A double quote character\r
+\r
+\r
+buffer_size equ 4096 ;file buffer size\r
+st_buf_size equ 128 ;string arg. buffer size\r
+fname_buf_size equ 64 ;file name buffer size\r
+\r
+\r
+;----- DOS EQUATES --------------------------------------------------;\r
+std_in equ 0 ;STD input handle\r
+std_out equ 1 ;STD output handle\r
+std_err equ 2 ;STD error handle\r
+dos_ent equ 21h ;DOS entry point\r
+\r
+std_con_string_output equ 9\r
+get_version equ 48\r
+char_oper equ 55 ;get configuration parameters\r
+open equ 61 ;DOS std open code\r
+close equ 62 ;DOS std close code\r
+read equ 63 ;DOS std read code\r
+write equ 64 ;DOS std write code\r
+lseek equ 66 ;DOS file seek\r
+exit equ 76 ;DOS process exit code\r
+\r
+\r
+;----- Misc Data -----------------------------------------------;\r
+make db "***MAUlloa/Microsoft/V12***"\r
+rev db "8"\r
+\r
+\r
+colon db ": "\r
+n1_buf db "["\r
+n2_buf db 8 dup(0) ;buffer for number conversion\r
+\r
+\r
+\r
+;----- OPTION FLAGS -------------------------------------------------;\r
+; If a flag is set (0ffh) then the option has been selected, if\r
+;reset (0) then it has been not. All options are reset initially.\r
+; NOTE: the order of this table has to remain consistent with the\r
+;options dispatch code. If any changes are made they have to\r
+;correspond with the code.\r
+\r
+opt_tbl:\r
+\r
+v_flg db 0\r
+c_flg db 0\r
+n_flg db 0\r
+x_flg db 0 ;not used\r
+l_flg db 0 ;not used\r
+\r
+\r
+;----- LINE COUNTERS ------------------------------------------------;\r
+mtch_cntr dw 0 ;matched lines counter\r
+line_cntr dw 0 ;line counter\r
+\r
+\r
+;----- MAIN ROUTINE -------------------------------------------------;\r
+start:\r
+\r
+;----- CHECK VERSION NUMBER -----------------------------------------;\r
+\r
+ mov ah,get_version\r
+ int 21h\r
+ cmp al,2\r
+ jge vers_ok\r
+ push cs\r
+ pop ds\r
+ mov dx,offset bad_vers\r
+ mov ah,std_con_string_output\r
+ int 21h\r
+ push es ;bad vers, exit a la 1.x\r
+ xor ax,ax\r
+ push ax\r
+\r
+badfart proc far ;(what a hack!!)\r
+ ret\r
+badfart endp\r
+\r
+vers_ok:\r
+\r
+ push cs ;load ES to the right area,\r
+ pop es ; for use with DI register\r
+\r
+assume es:code\r
+\r
+;--------------------------------------------------------------------;\r
+\r
+ mov si,81h ;Start addrss. of commad line buf.\r
+\r
+ call kill_bl ;Get rid of blanks\r
+ or bx,bx ;A CR found?\r
+ jz find_opt ;no, first find the options\r
+args_missing:\r
+ mov dx,offset errmsg1 ;empty command line, no args: error.\r
+ mov cl,cs:errlen1\r
+ call prt_err\r
+ mov al,2 ;error code for exit\r
+ jmp done\r
+\r
+\r
+;----- FIND THE OPTION IF ANY ---------------------------------------;\r
+find_opt:\r
+ mov ah,char_oper ;get the dos switch char.\r
+ mov al,0\r
+ int dos_ent ;switch char in DL\r
+ push dx\r
+another_opt:\r
+ lodsb ;get the first char of command line\r
+ cmp al,' ' ;a blank?\r
+ je cont_scan\r
+ cmp al,CR ;a Carriage Return\r
+ je args_missing\r
+ pop dx ;get switch character\r
+ cmp al,dl ;is it the switch char?\r
+ jne find_str ;no, no options: get the string\r
+ push dx ;save for another round\r
+\r
+ lodsb ;get the option character\r
+ cmp al,' ' ;a blank?\r
+ je cont_scan ;yes, ignore and continue\r
+ cmp al,CR ;a CR?\r
+ je args_missing ;yes, error...\r
+ call make_caps ;Capitalize the character\r
+ mov bx,offset opt_tbl ;pointer to option flag table\r
+\r
+ cmp al,'V' ;the v option?\r
+ je opt_v\r
+ cmp al,'C' ;the c option?\r
+ je opt_c\r
+ cmp al,'N' ;the n option?\r
+ je opt_n\r
+\r
+ mov cs:errmsg5_opt,al ;save the option\r
+ mov dx,offset errmsg5 ;unknown option: error\r
+ mov cl,cs:errlen5\r
+ call prt_err\r
+ mov dx,offset crlf ;print a CRLF\r
+ mov cx,2\r
+ call prt_err\r
+ jmp another_opt ;process next option\r
+\r
+opt_v:\r
+ mov di,0\r
+ jmp short opt_dispatch\r
+\r
+opt_c:\r
+ mov di,1\r
+ jmp short opt_dispatch\r
+\r
+opt_n:\r
+ mov di,2\r
+\r
+opt_dispatch:\r
+ mov es:byte ptr[bx+di],0ffh ;set the corresponding flag\r
+ jmp another_opt ;process the rest of the options\r
+\r
+cont_scan:\r
+ dec si ;adjust SI\r
+ call kill_bl ;get rid of blanks\r
+ or bx,bx ;A CR found?\r
+ jz another_opt ;no, test for other options\r
+ jmp args_missing ;yes, error...\r
+\r
+\r
+;----- FIND STRING ARGUMENT -----------------------------------------;\r
+find_str:\r
+ cmp al,quote_char ;string should start with a\r
+ jnz bad_str_err ; quote character, if not: error.\r
+ mov di,offset st_buffer ;String argument buffer addrss.\r
+ xor cx,cx ;Clear to keep string length.\r
+\r
+move_str:\r
+ lodsb\r
+ cmp al,CR ;if a CR is found in the string\r
+ jnz str_ok ; then it's a bad string\r
+bad_str_err:\r
+ mov dx,offset errmsg2 ;bad string error message\r
+ mov cl,cs:errlen2\r
+ call prt_err ;print the error.\r
+ mov al,2\r
+ jmp done\r
+\r
+str_ok:\r
+ cmp al,quote_char ;look for a quote character\r
+ jnz move_char ;not an apost., move to buffer\r
+ lodsb ;an apost., check next char.\r
+ cmp al,quote_char ;another quote character?\r
+ je move_char ;yes, move it to the buffer\r
+ dec si ;no, adjust the pointer\r
+ mov es:st_length,cx ;store the string length\r
+ or cx,cx ;Is the string empty?\r
+ jnz other_args ;no: get the rest of the args.\r
+ mov al,1 ;empty: no matches(!?)\r
+ jmp done\r
+move_char:\r
+ stosb ;put in buffer\r
+ inc cx ;increment string length\r
+ jmp move_str\r
+\r
+\r
+;----- FIND THE FILE ARGUMENTS --------------------------------------;\r
+other_args: ;Process the rest of the command\r
+ ; line arguments.\r
+ call kill_bl ;get rid of leading blanks\r
+ or bx,bx ;At least one argument necessary,\r
+ jz further_args ; if a CR not found: ok.\r
+\r
+;----- USE STD IN FOR INPUT -----------------------------------------;\r
+ push cs\r
+ pop ds\r
+ mov ax,std_in ;handle\r
+ jmp fill\r
+\r
+further_args:\r
+ call clr_cntrs ;set all counters to zero\r
+ mov di,offset file_name_buf ;Set pointer to the name buffer\r
+ xor cx,cx ;zero file name length\r
+move_fname:\r
+ lodsb\r
+ cmp al,' ' ;A blank: end of file name,\r
+ je done_move\r
+ cmp al,CR ;A CR: idem.\r
+ je done_move\r
+ stosb ;store in name buffer\r
+ inc cx ;increment file name length\r
+ jmp move_fname\r
+done_move:\r
+ dec si ;Adjust pointer for next round.\r
+ mov es:byte ptr[di],00h ;File names are null terminated\r
+ push si ;Save SI to continue com. line scan.\r
+ push ds ;Save DS register contents for\r
+ ; later because it points to the\r
+ ; rest of the arguments.\r
+ mov es:file_name_len,cx ;save the name length\r
+\r
+;----- OPEN FILE FOR READING ----------------------------------------;\r
+ push cs ;Load new DS with CS\r
+ pop ds\r
+ mov dx,offset file_name_buf ;addrss. of the file name\r
+ mov ah,open\r
+ mov al,0 ;file open for reading\r
+ int dos_ent ;call the DOS\r
+ jnc say_name ;if no carry then no errors\r
+ jmp open_error\r
+\r
+;----- PRINT FILE NAME ----------------------------------------------;\r
+say_name:\r
+ push ax ;save file handle\r
+ mov dx,offset heading\r
+ mov cl,cs:heading_len\r
+ xor ch,ch\r
+ call prout\r
+\r
+ mov dx,offset file_name_buf\r
+ mov cx,ds:file_name_len\r
+ call prout\r
+\r
+ cmp ds:c_flg,0ffh ;count only flag set?\r
+ je xx1\r
+\r
+ mov dx,offset crlf\r
+ mov cx,2\r
+ call prout\r
+\r
+xx1:\r
+ pop ax\r
+\r
+;----- Fill Buffer for Matching -------------------------------------;\r
+fill:\r
+ mov bx,ax ;retrieve handle\r
+refill:\r
+ mov dx,offset buffer ;data buffer addrss.\r
+ mov cx,buffer_size\r
+ mov ah,read\r
+ int dos_ent\r
+ jnc no_read_error ;if carry then read error\r
+ jmp read_error\r
+no_read_error:\r
+ or ax,ax ;if ax=0 then all done\r
+ jnz go_match\r
+ cmp ds:c_flg,0ffh ;count only flag set?\r
+ jne sj2\r
+ call print_count\r
+sj2:\r
+ cmp bx,std_in ;Using STD IN?\r
+ jnz regular\r
+ jmp foo ;if so: all done, exit\r
+regular:\r
+ mov ah,close ;otherwise close the file\r
+ int dos_ent\r
+ jmp scan_rest ;get another file\r
+\r
+;----- MATCH ROUTINE ------------------------------------------------;\r
+;Note: If input is being taken from a file the stack contains\r
+; (from top to bottom):\r
+; - Pointer to the next command in the command line\r
+; - Pointer to the program segment prefix (to be loaded into\r
+; DS to access the command line.\r
+; if the imput is from the standart input then NONE of it will be\r
+; in the stack.\r
+\r
+go_match:\r
+ push bx ;save the file handle\r
+ mov bp,offset buffer ;ptr to first line of file\r
+ mov di,ax ;dispalcement from beg of buffer\r
+\r
+ cmp ax,buffer_size-1 ;last line of the file?\r
+ jg no_last_line ;if yes, add a CRLF just in case\r
+ mov bx,bp\r
+ cmp byte ptr[bx+di-1],LF ;finished with a LF?\r
+ je no_last_line ;yes, it's an OK line.\r
+ mov byte ptr[bx+di],CR ;put a CR at the end of the data\r
+ inc di\r
+ mov byte ptr[bx+di],LF ;put a LF ...\r
+ inc di\r
+\r
+no_last_line:\r
+ push di ;save the # of chars. in the buffer\r
+ push bp\r
+ mov dx,ds:st_length ;length of the string arg.\r
+ dec dx ;adjust for later use\r
+ jmp short try_again\r
+\r
+\r
+more_stuff_o:\r
+ jmp more_stuff\r
+\r
+\r
+\r
+;----- SCAN LINES IN THE BUFFER FOR A MATCH -------------------------;\r
+;Note: at this point the stack contains (from top to bottom):\r
+; - Stuff mentioned before\r
+; - File Handle\r
+; - Number of chars. left in the buffer from the next line.\r
+; - Addrs. of the next line in the buffer.\r
+;\r
+; plus, DX has the adjusted length of the string argument.\r
+\r
+try_again:\r
+ inc ds:line_cntr ;increment line counter\r
+ pop bp ;addrs. of next line in the buffer\r
+ mov di,bp ;points to beg. of a line\r
+ pop cx ;get # of chars left in the buffer\r
+ mov bx,cx ;save in case a non-complete line\r
+ mov al,LF ;search for a Line Feed\r
+ jcxz more_stuff_o ;no chars left in buffer\r
+ repnz scasb\r
+ jnz more_stuff_o ;no full line left in buffer\r
+\r
+ push cx ;save chars left in buffer\r
+ push di ;points to beg. of next line\r
+ mov cx,di\r
+ sub cx,bp ;length of the current line\r
+ mov bx,cx ;save in case it has a match\r
+ dec cx\r
+ dec cx ;CRLF characters discounted\r
+ jcxz try_again_opt ;if line empty go to next line\r
+ mov di,bp ;pointer to the beg. of current line\r
+another_char:\r
+;\r
+; On entry:\r
+; BX line length\r
+; CX adjusted line length\r
+; DX adjusted string argument length\r
+; DI points to beg. of line\r
+;\r
+\r
+IF KANJI\r
+\r
+ push dx ;save for next line\r
+lop:\r
+ pop dx\r
+ push dx\r
+ inc dx ;different algorithm!\r
+ mov si,offset st_buffer ;pointer to beg. of string argument\r
+\r
+comp_next_char:\r
+ push di\r
+ mov di,si\r
+ call is_prefix ;check for a prefix char\r
+ pop di\r
+ jnc nopre\r
+ lodsw\r
+ cmp cx,1 ; Can not compare a two byte char\r
+ jz try_again_opt1 ; if there is only one available\r
+ cmp ax,word ptr [di]\r
+ jz kmatch1\r
+ call next_kchar ;no match, advance di to next kanji\r
+ jc try_again_opt1 ;not enough chars left in line\r
+ jmp short lop ;try another char in line\r
+\r
+nopre:\r
+ lodsb\r
+ cmp al,byte ptr [di]\r
+ jz kmatch\r
+ call next_kchar ;no match, advance di to next kanji\r
+ jc try_again_opt1 ;not enough chars left in line\r
+ jmp short lop ;try another char in line\r
+\r
+try_again_opt1:\r
+ pop dx\r
+ jmp try_again_opt\r
+\r
+\r
+kmatch1:\r
+ dec dx ;last char had prefix so it was\r
+ ; long.\r
+kmatch:\r
+ dec dx\r
+ jz a_matchk ; no chars left: a match!\r
+ call next_kchar\r
+ jc try_again_opt1\r
+ jmp comp_next_char ; loop if chars left in arg.\r
+\r
+a_matchk:\r
+ pop dx\r
+\r
+ELSE\r
+\r
+ mov si,offset st_buffer ;pointer to beg. of string argument\r
+ lodsb ;get first character of the str. arg.\r
+ repnz scasb ;search for a match in current line\r
+ jnz try_again_opt ;no match, try the next line\r
+ cmp cx,dx ;compare lengths, a full match is not\r
+ jb try_again_opt ; possible if CX < DX.\r
+ push di ;save addrs. of next char. in the line\r
+ push cx ;save the # of chars. left in the line\r
+ mov cx,dx ;get the adjusted string arg. length\r
+ jcxz a_match ;if a single char string, then match!\r
+ repz cmpsb ;compare string with line\r
+ jz a_match ;a match found, hurrah!\r
+ pop cx ;no match, get # of chars remaining\r
+ ; in the line.\r
+ pop di ;position of the next char. in the line\r
+ jmp another_char\r
+\r
+\r
+;----- A MATCH: CHECK FOR THE v OPTION ------------------------------;\r
+a_match:\r
+ pop ax ;adjust stack\r
+ pop ax\r
+ENDIF\r
+\r
+ cmp ds:v_flg,0ffh ;is flag set?\r
+ jne prt_line ;no, print the line\r
+ jmp try_again\r
+\r
+;----- NO MATCH: CHECK FOR THE v OPTION -----------------------------;\r
+try_again_opt:\r
+ cmp ds:v_flg,0ffh ;is flag set?\r
+ jne try_again ;no goto next line\r
+\r
+;----- PRINT THE LINE WITH THE MATCH --------------------------------;\r
+;Note: at this point the stack contains (top to bottom)\r
+; - Stuff mentioned before\r
+;\r
+; plus, BP points to begginig of the current line, BX has the length\r
+;of the current line including the CRLF, and DX the adjusted length of\r
+;the string argument.\r
+\r
+prt_line:\r
+ cmp ds:c_flg,0ffh ;is count only flag set?\r
+ jne no_c_flg\r
+ inc ds:mtch_cntr ;yes, increment counter\r
+ jmp try_again\r
+\r
+no_c_flg:\r
+ push dx ;save the adjusted string arg. length\r
+ cmp ds:n_flg,0ffh ;is line number flag set?\r
+ jne no_n_flg\r
+ call prt_lcntr\r
+no_n_flg:\r
+ mov dx,bp\r
+ mov cx,bx\r
+ call prout\r
+ pop dx ;restore\r
+ jmp try_again\r
+\r
+;----- READ MORE TEXT LINES INTO THE BUFFER -------------------------;\r
+; The scanning routines have detected that the buffer does not\r
+;contain a full line any more. More lines have to be read into the\r
+;buffer. But first perform a seek on the file in order to re-read\r
+;the non-complete line into the begining of the buffer.\r
+; Uppon entry BP contains points to the begining of the non-complete\r
+;line, and BX has the number of characters left in the buffer.\r
+; The Stack contains (top to bottom):\r
+; - Pointer to the next command in the command line\r
+; - Pointer to the program segment prefix (to be loaded into\r
+; DS to access the command line).\r
+; - File handle.\r
+\r
+more_stuff:\r
+ mov dx,bx ;get chars left in buffer\r
+ pop bx ;get the handle\r
+ or dx,dx ;are there 0 left?\r
+ jz no_seek ;yes, do not seek\r
+ neg dx ;form two's complement\r
+ mov cx,-1\r
+ mov al,1 ;seek from the current position\r
+ mov ah,lseek ;seek on file\r
+ int dos_ent\r
+ jc read_error\r
+no_seek:\r
+ jmp refill ;no errors: refill the buffer\r
+read_error:\r
+ cmp bx,std_in ;Using STD IN?\r
+ je foo ;if so: all done, exit\r
+ mov ah,close ;close the file\r
+ int dos_ent\r
+ mov dx,offset errmsg4_pre ;read error\r
+ mov cl,cs:errlen4_pre\r
+ call prt_file_name ;print the file name in error\r
+ mov dx,offset errmsg4_post ;read error\r
+ mov cl,cs:errlen4_post\r
+ jmp r_error\r
+\r
+;----- PRINT ERRORS -------------------------------------------------;\r
+open_error:\r
+ mov dx,offset errmsg3_pre ;error in open operation\r
+ mov cl,cs:errlen3_pre\r
+ call prt_err_2 ;print error message\r
+ call prt_file_name ;print the file name in error\r
+ mov dx,offset errmsg3_post ;error in open operation\r
+ mov cl,cs:errlen3_post\r
+r_error:\r
+ call prt_err_2 ;print error message\r
+\r
+;----- SCAN THE REST OF THE COMMAND LINE ----------------------------;\r
+scan_rest:\r
+ pop ds ;restore pointer to comm. line\r
+ pop si ;restore pointer to next comm.\r
+ call kill_bl ;look for further args.\r
+ or bx,bx ;test for a CR\r
+ jnz foo\r
+ jmp further_args\r
+foo:\r
+ mov al,0 ;Proper code\r
+done:\r
+ mov ah,exit ;All done, exit with proper code.\r
+ int dos_ent\r
+\r
+\r
+;--------------------------------------------------------------------;\r
+; Get rid of blanks in command line. ;\r
+; Advances the SI reg till the next non-blank character, if the ;\r
+; character is a CR (0dh) then returns with BX non-zero, otherwise ;\r
+; BX is zero. ;\r
+; ;\r
+; entry: ;\r
+; SI points to the first character on the line to scan. ;\r
+; ;\r
+; exit: ;\r
+; SI points to the first non-blank character found. ;\r
+; BX contains 0D hex if the first non-blank found is ;\r
+; a Carriage Return, otherwise it is 0. ;\r
+; ;\r
+; modifies: ;\r
+; BX, SI, and AX ;\r
+; ;\r
+;--------------------------------------------------------------------;\r
+kill_bl:\r
+ cld ;increment\r
+ xor bx,bx ;zero bx to start: no CR found\r
+no_bl:\r
+ lodsb ;get rid of blanks\r
+ cmp al,' '\r
+ je no_bl\r
+ cmp al,CR\r
+ jnz no_cr\r
+ mov bx,ax ;make bx non-zero (actually 0dh)\r
+no_cr:\r
+ dec si ;adjust pointer\r
+ ret\r
+\r
+\r
+;--------------------------------------------------------------------;\r
+; Clear Counters ;\r
+;--------------------------------------------------------------------;\r
+clr_cntrs:\r
+ mov byte ptr es:mtch_cntr,0\r
+ mov byte ptr es:line_cntr,0\r
+ ret\r
+\r
+;--------------------------------------------------------------------;\r
+; Print Count of Matched lines ;\r
+; ;\r
+; Modifies: AX,CX,DX and DI ;\r
+;--------------------------------------------------------------------;\r
+print_count:\r
+ push bx ;save handle\r
+ cmp bx,std_in ;using std_in?\r
+ jz sj3 ;if so do not print file name\r
+\r
+ mov dx,offset colon\r
+ mov cx,2\r
+ call prout ;print colon\r
+sj3:\r
+ mov ax,ds:mtch_cntr\r
+ mov di,offset n2_buf ;buffer for characters\r
+ call bin2asc ;convert to ascii\r
+ mov dx,offset n2_buf\r
+ call prout ;print the number\r
+ mov dx,offset crlf\r
+ mov cx,2\r
+ call prout ;print an end of line\r
+ pop bx\r
+ ret\r
+\r
+\r
+;--------------------------------------------------------------------;\r
+; Print relative line number ;\r
+; ;\r
+; Modifies: AX,CX and DI ;\r
+;--------------------------------------------------------------------;\r
+prt_lcntr:\r
+ push bx\r
+ push dx\r
+ mov ax,ds:line_cntr\r
+ mov di,offset n2_buf\r
+ call bin2asc\r
+ mov byte ptr[di],"]"\r
+ inc cx\r
+ inc cx\r
+ mov dx,offset n1_buf\r
+ call prout\r
+ pop dx\r
+ pop bx\r
+ ret\r
+\r
+;--------------------------------------------------------------------;\r
+; Print string to STD_OUT ;\r
+;--------------------------------------------------------------------;\r
+prout:\r
+ mov bx,std_out\r
+ mov ah,write\r
+ int dos_ent\r
+ ret\r
+\r
+\r
+;--------------------------------------------------------------------;\r
+; Binary to Ascii conversion routine ;\r
+; ;\r
+; Entry: ;\r
+; AX Binary number ;\r
+; DI Points to one past the last char in the ;\r
+; result buffer. ;\r
+; ;\r
+; Exit: ;\r
+; Result in the buffer MSD first ;\r
+; CX Digit count ;\r
+; ;\r
+; Modifies: ;\r
+; AX,BX,CX,DX and DI ;\r
+; ;\r
+;--------------------------------------------------------------------;\r
+bin2asc:\r
+ mov bx,0ah\r
+ xor cx,cx\r
+go_div:\r
+ inc cx\r
+ cmp ax,bx\r
+ jb div_done\r
+ xor dx,dx\r
+ div bx\r
+ add dl,'0' ;convert to ASCII\r
+ push dx\r
+ jmp short go_div\r
+\r
+div_done:\r
+ add al,'0'\r
+ push ax\r
+ mov bx,cx\r
+deposit:\r
+ pop ax\r
+ stosb\r
+ loop deposit\r
+ mov cx,bx\r
+ ret\r
+\r
+\r
+;--------------------------------------------------------------------;\r
+; Print the current file name ;\r
+; ;\r
+; modifies: ;\r
+; DX, CX, BX and AX ;\r
+;--------------------------------------------------------------------;\r
+prt_file_name:\r
+ mov dx,offset file_name_buf ;print the file name\r
+ mov cx,ds:file_name_len ;retrive file name length\r
+ jmp short prt_err_2\r
+\r
+\r
+;--------------------------------------------------------------------;\r
+; Print an error message to the Standart error ;\r
+; ;\r
+; entry: ;\r
+; DX has the pointer to the message ;\r
+; CX has the length of the message ;\r
+; ;\r
+; modifies: ;\r
+; BX and AX ;\r
+;--------------------------------------------------------------------;\r
+prt_err:\r
+ push ds ;Save the current DS\r
+ push cs ;Make DS point to the right\r
+ pop ds ; place, for DOS use.\r
+ call prt_err_2\r
+ pop ds\r
+ ret\r
+\r
+prt_err_2:\r
+ xor ch,ch\r
+ mov bx,std_err\r
+ mov ah,write\r
+ int dos_ent ;write error message\r
+ ret\r
+\r
+\r
+;--------------------------------------------------------------------;\r
+; CAPIALIZES THE CHARACTER IN AL ;\r
+; ;\r
+; entry: ;\r
+; AL has the character to Capitalize ;\r
+; ;\r
+; exit: ;\r
+; AL has the capitalized character ;\r
+; ;\r
+; modifies: ;\r
+; AL ;\r
+;--------------------------------------------------------------------;\r
+make_caps:\r
+ cmp al,'a'\r
+ jb no_cap\r
+ cmp al,'z'\r
+ jg no_cap\r
+ and al,0dfh\r
+no_cap:\r
+ ret\r
+\r
+\r
+\r
+IF KANJI\r
+\r
+;--------------------------------------------------------------------;\r
+; ADVANCE POINTER TO NEXT KANJI CHARACTER ;\r
+; ;\r
+; entry: DI points to a Kanji string ;\r
+; CX length in bytes of the string ;\r
+; ;\r
+; exit: DI points to next Kanji char ;\r
+; CX has number of bytes left ;\r
+; ;\r
+; modifies: AX ;\r
+; ;\r
+;--------------------------------------------------------------------;\r
+next_kchar:\r
+ jcxz no_kleft\r
+ call is_prefix\r
+ jnc no_p\r
+ inc di\r
+ dec cx\r
+ jcxz no_kleft ; for insurance\r
+no_p:\r
+ inc di\r
+ dec cx\r
+ clc\r
+ ret\r
+\r
+no_kleft:\r
+ stc\r
+ ret\r
+\r
+\r
+;--------------------------------------------------------------------;\r
+; FIND OUT IS THE BYTE IS A KANJI PREFIX ;\r
+; ;\r
+; entry: DI points to a kanji string ;\r
+; ;\r
+; exit: Carry set if it is a kanji prefix ;\r
+; ;\r
+; modifies: AX ;\r
+; ;\r
+;--------------------------------------------------------------------;\r
+is_prefix:\r
+ mov al,byte ptr [di]\r
+ cmp al,81h\r
+ jb nok\r
+ cmp al,0a0h\r
+ jb isk\r
+ cmp al,0e0h\r
+ jb nok\r
+ cmp al,0fdh\r
+ jb isk\r
+nok:\r
+ clc\r
+ ret\r
+isk:\r
+ stc\r
+ ret\r
+\r
+ENDIF\r
+\r
+\r
+;----- PATCH AREA ---------------------------------------------------;\r
+\r
+patch_area dw 100h dup(?)\r
+\r
+\r
+\r
+;----- BUFFER AREA --------------------------------------------------;\r
+st_length dw 0 ;String argumnet length\r
+st_buffer db st_buf_size dup(?) ;String argument buffer\r
+\r
+file_name_len dw 0 ;File name length\r
+file_name_buf db fname_buf_size+1 dup(?) ;File name buffer,(allow for\r
+ ; null at the end).\r
+\r
+buffer db buffer_size+1 dup(?) ;file buffer, the last byte is\r
+ ;a guard in case of forced insertion\r
+ ;of a CRLF pair.\r
+\r
+;----- ERROR MESSAGES -----------------------------------------------;\r
+ EXTRN bad_vers:byte,crlf:byte,errmsg1:byte,errlen1:byte,errmsg2:byte\r
+ EXTRN errmsg3_pre:byte,errlen3_pre:byte\r
+ EXTRN errmsg3_post:byte,errlen3_post:byte\r
+ EXTRN errmsg4_pre:byte,errlen4_pre:byte\r
+ EXTRN errmsg4_post:byte,errlen4_post:byte\r
+ EXTRN heading:byte,heading_len:byte,errlen2:byte\r
+ EXTRN errmsg5:byte,errmsg5_opt:byte,errlen5:byte\r
+code ends\r
+\r
+\r
+;----- STACK AREA ---------------------------------------------------;\r
+stack segment stack\r
+\r
+ dw 64 dup(?,?)\r
+stack_top equ $\r
+\r
+stack ends\r
+\r
+ end start\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+;***************************************************************
+;
+; 86-DOS FORMAT DISK UTILITY
+;
+; This routine formats a new disk,clears the FAT and DIRECTORY
+; then optionally copies the SYSTEM and COMMAND.COM to this
+; new disk
+;
+; SYNTAX: FORMAT [drive][/switch1][/switch2]...[/switch16]
+;
+; Regardless of the drive designator , the user will be
+; prompted to insert the diskette to be formatted.
+;
+;***************************************************************
+
+;Mod to ask for volume ID ARR 5/12/82
+; 05/19/82 Fixed rounding bug in CLUSCAL: ARR
+;REV 1.5
+; Added rev number message
+; Added dir attribute to DELALL FCB
+;REV 2.00
+; Redone for 2.0
+;REV 2.10
+; 5/1/83 ARR Re-do to transfer system on small memory systems
+
+FALSE EQU 0
+TRUE EQU NOT FALSE
+
+IBMJAPVER EQU FALSE ; SET ONLY ONE SWITCH TO TRUE!
+IBMVER EQU FALSE
+MSVER EQU TRUE
+
+KANJI EQU FALSE
+
+ .xlist
+ INCLUDE DOSSYM.ASM
+ .list
+
+
+;FORMAT Pre-defined switches
+SYSSW EQU 1 ; System transfer
+VOLSW EQU 2 ; Volume ID prompt
+OLDSW EQU 4 ; E5 dir terminator
+
+
+DRNUM EQU 5CH
+
+RECLEN EQU fcb_RECSIZ+7
+RR EQU fcb_RR+7
+
+;Per system file data structure
+
+FILESTRUC STRUC
+FILE_HANDLE DW ? ; Source handle
+FILE_SIZEP DW ? ; File size in para
+FILE_SIZEB DD ? ; File size in bytes
+FILE_OFFSET DD ? ; Offset in file (partial)
+FILE_START DW ? ; Para number of start in buffer
+FILE_DATE DW ? ; Date of file
+FILE_TIME DW ? ; Time of file
+FILE_NAME DB ? ; Start of name
+FILESTRUC ENDS
+
+CODE SEGMENT PUBLIC 'CODE'
+
+ ASSUME CS:CODE,DS:CODE,ES:CODE
+
+ ORG 100H
+
+;For OEM module
+ PUBLIC SWITCHMAP,DRIVE
+ EXTRN HARDFLAG:BYTE ;0 = REMOVABLE MEDIA
+ EXTRN SWITCHLIST:BYTE,FATID:BYTE,FATSPACE:WORD
+ EXTRN STARTSECTOR:WORD,FREESPACE:WORD,INIT:NEAR
+ EXTRN DISKFORMAT:NEAR,BADSECTOR:NEAR,DONE:NEAR
+ EXTRN WRTFAT:NEAR
+
+;For FORMES module
+ EXTRN WAITYN:NEAR,REPORT:NEAR
+ PUBLIC PRINT,CRLF,DISP32BITS,UNSCALE,FDSKSIZ,SECSIZ,CLUSSIZ
+ PUBLIC SYSSIZ,BADSIZ
+
+START:
+ JMP SHORT FSTRT
+
+HEADER DB "Vers 2.10"
+
+FSTRT:
+ MOV SP,OFFSET STACK ;Use internal stack
+
+;Code to print header
+; PUSH AX
+; MOV DX,OFFSET HEADER
+; CALL PRINT
+; POP AX
+
+DOSVER_HIGH EQU 020BH ;2.11 in hex
+ PUSH AX ;Save DRIVE validity info
+ 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 BADVER
+ MOV AH,STD_CON_STRING_OUTPUT
+ INT 21H
+ INT 20H
+
+OKDOS:
+
+ IF IBMVER ; IBM WANTS TO CHECK FOR ASSIGN.COM
+ XOR AX,AX
+ MOV ES,AX
+ MOV BX,ES:[4*21H]
+ MOV ES,ES:[4*21H+2]
+ CMP BX,122H
+ JNZ NO_ASSIGN
+ CMP ES:[109H],0807H
+ JNZ NO_ASSIGN
+ CMP ES:[103H],0201H
+ JNZ RE_ASSIGN
+ CMP ES:[105H],0403H
+ JNZ RE_ASSIGN
+ CMP ES:[107H],0605H
+ JZ NO_ASSIGN
+RE_ASSIGN:
+ MOV DX,OFFSET ASGERR
+ CALL PRINT
+ JMP FEXIT2
+NO_ASSIGN:
+ PUSH CS
+ POP ES
+ ENDIF
+
+ POP AX
+
+ CMP AL,0FFH ;See if invalid drive specified
+ JNZ DRVGD ;If not proceed
+ MOV DX,OFFSET INVDRV ;Invalid drive message
+ CALL PRINT ;Print the message
+ JMP FEXIT2 ;Exit
+DRVGD:
+ MOV AH,GET_DEFAULT_DRIVE ;Must get the default drive
+ INT 21H ;Default now in AL
+ MOV DEFALT,AL ;Save for later
+ ADD AL,"A"
+ MOV [BIODRV],AL
+ MOV [DOSDRV],AL
+ MOV [SYSDRV],AL
+ MOV [COMDRV],AL
+ MOV SI,DRNUM ;So we can get our parameters
+ LODSB ;Fetch drive designation
+ OR AL,AL ;See if specified
+ JNZ DRVSPEC ;If specfied proceed
+ MOV AL,DEFALT
+ INC AL
+DRVSPEC:
+ DEC AL ;Drive designator now correct
+ MOV BYTE PTR DS:[DRNUM],AL ;And updated
+ MOV DRIVE,AL ;Save copy
+ MOV DX,OFFSET INT_23
+ MOV AH,SET_INTERRUPT_VECTOR
+ MOV AL,23H
+ INT 21H ;Set ^C vector
+ ;Get all the swith information from the command line
+ XOR AX,AX
+ MOV AH,CHAR_OPER ;GET SWITCH CHARACTER
+ INT 21H ;CALL THE DOS
+ MOV [SWTCH],DL
+
+ XOR BX,BX ;Store switch information in BX
+ MOV SI,81H ;Point to the command line buffer
+NXTSWT:
+ CALL SCANOFF
+ LODSB
+ CMP AL,[SWTCH]
+ JZ GETPARM
+ CMP AL,13
+ JZ SAVSWT
+ LODSB ;Get next character
+ CMP AL,":" ;Is it a drive specifier?
+ JNZ INVALID ;No -- invalid parameter
+ CMP BYTE PTR DBLFLG,0 ;Is is the only drive specifier we've seen
+ JNZ INVALID ;No -- invalid parameter
+ INC BYTE PTR DBLFLG ;Yes -- set the flag
+ JMP SHORT NXTSWT
+GETPARM:
+ LODSB
+ ;Convert any lower case input into upper case
+ CMP AL,41H
+ JL GETCHR ;Switch is a digit don't try to convert it
+ AND AL,0DFH
+GETCHR:
+ MOV CL,SWITCHLIST ;Number of legal switches
+ OR CL,CL ;If it's none we shouldn't be here
+ JZ INVALID ;Report the error
+ MOV CH,0
+ MOV DI,1+OFFSET SWITCHLIST ;Point to the legal switch characters
+ REPNE SCASB
+ JNZ INVALID
+ MOV AX,1
+ SHL AX,CL
+ OR BX,AX ;Set the appropriate bit in SWITCHMAP
+ JMP SHORT NXTSWT ;See if there are anymore
+
+INVALID:
+ MOV DX,OFFSET INVPAR
+ CALL PRINT
+ JMP FEXIT
+
+SCANOFF:
+ LODSB
+ CMP AL,20H
+ JZ SCANOFF
+ CMP AL,9
+ JZ SCANOFF
+ DEC SI
+ RET
+
+MEMERR:
+ MOV DX,OFFSET MEMEX
+ CALL PRINT
+ JMP FEXIT
+
+
+SAVSWT:
+
+ IF IBMVER ;/B SWITCH TURNS /8 ON AND /S OFF
+ TEST BX,00100000B
+ JZ NOT_SW_B
+ AND BX,NOT SYSSW ;TURN OFF /S
+ OR BX,00010000B ;TURN ON /8
+NOT_SW_B:
+ ENDIF
+
+ MOV SWITCHMAP,BX
+ TEST SWITCHMAP,SYSSW
+ JZ INITCALL
+ CALL SAVUDIRS
+ MOV BX,[FREESPACE]
+ ADD BX,15
+ MOV CL,4
+ SHR BX,CL
+ PUSH CS
+ POP ES
+ MOV AH,SETBLOCK
+ INT 21H
+ MOV BX,0FFFFH
+ MOV AH,ALLOC
+ INT 21H
+ OR BX,BX
+ JZ MEMERR ;No memory
+ MOV [MSIZE],BX
+ MOV AH,ALLOC
+ INT 21H
+ JC MEMERR ;No memory
+ MOV [MSTART],AX
+ MOV DX,OFFSET SWTCH
+ MOV AH,CHDIR
+ INT 21H ;Go to root on default drive (source)
+
+RDFRST:
+ CALL READDOS ;Read BIOS and DOS
+ JNC INITCALL ;OK -- read next file
+NEEDSYS:
+ CALL SYSPRM ;Prompt for system disk
+ JMP RDFRST ;Try again
+
+INITCALL:
+ CALL INIT ;Let OEM read any files before disk is changed
+ JNC SWITCHCHK
+ MOV DX,OFFSET FRMTERR
+ CALL PRINT
+ JMP FEXIT
+
+SWITCHCHK:
+ MOV DX,SWITCHMAP
+ MOV SWITCHCOPY,DX
+
+SYSLOOP:
+ MOV WORD PTR BADSIZ,0 ;Must intialize for each iteration
+ MOV WORD PTR BADSIZ+2,0
+ MOV WORD PTR SYSSIZ,0
+ MOV WORD PTR SYSSIZ+2,0
+ MOV BYTE PTR DBLFLG,0
+ MOV BYTE PTR CLEARFLG,0
+ MOV DX,SWITCHCOPY
+ MOV SWITCHMAP,DX ;Restore original Switches
+ MOV AL,DRIVE ;Fetch drive
+ ADD AL,"A" ;(AL)= ASCII designation
+ MOV BYTE PTR SNGDRV,AL ;Fill out the message
+ MOV BYTE PTR TARGDRV,AL
+ MOV BYTE PTR HRDDRV,AL
+ CALL DSKPRM ;Prompt for new disk
+ CALL DISKFORMAT ;Format the disk
+ JNC GETTRK
+FRMTPROB:
+ MOV DX,OFFSET FRMTERR
+ CALL PRINT
+ JMP SHORT SYSLOOP
+
+ ;Mark any bad sectors in the FATs
+ ;And keep track of how many bytes there are in bad sectors
+
+GETTRK:
+ CALL BADSECTOR ;Do bad track fix-up
+ JC FRMTPROB ;Had an error in Formatting - can't recover
+ CMP AX,0 ;Are we finished?
+ JNZ TRKFND ;No - check error conditions
+ JMP DRTFAT ;Yes
+TRKFND:
+ CMP BX,STARTSECTOR ;Are any sectors in the system area bad?
+ JGE CLRTEST
+ MOV DX,OFFSET NOUSE ;Can't build FATs of Directory
+ CALL PRINT
+ JMP FRMTPROB ;Bad disk -- try again
+CLRTEST:
+ MOV SECTORS,AX ;Save the number of sectors on the track
+ CMP BYTE PTR CLEARFLG,0 ;Have we already cleared the FAT and DIR?
+ JNZ SYSTEST ;Yes - all set
+ INC CLEARFLG ;Set the flag
+ PUSH BX
+ CALL CLEAR ;Fix-up fat and directory
+ POP BX
+SYSTEST:
+ TEST SWITCHMAP,SYSSW ;If system requested calculate size
+ JZ BAD100
+ CMP BYTE PTR DBLFLG,0 ;Have we already calculated System space?
+ JNZ CMPTRKS ;Yes -- all ready for the compare
+ INC BYTE PTR DBLFLG ;No -- set the flag
+ CALL GETSIZE ;Calculate the system size
+ MOV DX,WORD PTR SYSSIZ+2
+ MOV AX,WORD PTR SYSSIZ
+ DIV SECSIZ
+ ADD AX,STARTSECTOR
+ MOV SYSTRKS,AX ;Space FAT,Dir,and system files require
+CMPTRKS:
+ CMP BX,SYSTRKS
+ JG BAD100
+ MOV DX,OFFSET NOTSYS ;Can't transfer a system
+ CALL PRINT
+ AND SWITCHMAP,NOT SYSSW ;Turn off system transfer switch
+ MOV WORD PTR SYSSIZ+2,0 ;No system to transfer
+ MOV WORD PTR SYSSIZ,0 ;No system to transfer
+BAD100:
+; BX is the first bad sector #, SECTORS is the number of bad sectors starting
+; at BX. This needs to be converted to clusters. The start sector number may
+; need to be rounded down to a cluster boundry, the end sector may need to be
+; rounded up to a cluster boundry. Know BX >= STARTSECTOR
+ SUB BX,STARTSECTOR ; BX is now DATA area relative
+ MOV CX,BX
+ ADD CX,SECTORS
+ DEC CX ; CX is now the last bad sector #
+ MOV AX,BX
+ XOR DX,DX
+ DIV CLUSSIZ
+ MOV BX,AX ; BX is rounded down and converted
+ ; to a cluster #. Where cluster 0 =
+ ; first cluster of data. First bad
+ ; Sector is in cluster BX.
+ MOV AX,CX
+ XOR DX,DX
+ DIV CLUSSIZ
+ MOV CX,AX ; CX is rounded up and converted to a
+ ; to a cluster #. Where cluster 0 =
+ ; first cluster of data. Last bad
+ ; Sector is in cluster CX.
+ SUB CX,BX
+ INC CX ; CX is number of clusters to mark bad
+ ADD BX,2 ; Bias start by correct amount since
+ ; first cluster of data is really
+ ; cluster 2.
+ MOV AX,CLUSSIZ ; Sectors/Cluster
+ MUL SECSIZ ; Times Bytes/Sector
+ MOV BP,AX ; = Bytes/Cluster
+
+; Mark CX clusters bad starting at cluster BX
+PACKIT:
+ MOV DX,0FF7H ;0FF7H indicates a bad sector
+ CALL PACK ;Put it in the allocation map
+ CMP DX,DI ;Have we already marked it bad?
+ JZ BAD150 ;if so, don't add it in
+ ADD WORD PTR BADSIZ,BP ;Add in number of bad bytes
+ JNB BAD150
+ INC WORD PTR BADSIZ+2
+BAD150:
+ INC BX ;Next cluster
+ LOOP PACKIT ;Continue for # of clusters
+ JMP GETTRK
+
+; Inputs:
+ ;BX = Cluster number
+ ;DX = Data
+; Outputs:
+ ;The data is stored in the FAT at the given cluster.
+ ;SI is destroyed
+ ;DI contains the former contents
+ ;No other registers affected
+PACK:
+ PUSH BX
+ PUSH CX
+ PUSH DX
+ MOV SI,BX
+ SHR BX,1
+ ADD BX,FATSPACE
+ ADD BX,SI
+ SHR SI,1
+ MOV SI,WORD PTR [BX]
+ MOV DI,SI
+ JNB ALIGNED
+ MOV CL,4
+ SHL DX,CL
+ SHR DI,CL
+ AND SI,15
+ JMP SHORT PACKIN
+
+ALIGNED:
+ AND SI,0F000H
+PACKIN:
+ AND DI,00FFFH ;DI CONTAINS FORMER CONTENTS
+ OR SI,DX
+ MOV WORD PTR[BX],SI
+ POP DX
+ POP CX
+ POP BX
+ RET
+
+DRTFAT:
+ CMP BYTE PTR CLEARFLG,0
+ JNZ CLEARED
+ CALL CLEAR ;Clear the FAT and Dir
+ TEST SWITCHMAP,SYSSW ;If system requested, calculate size
+ JZ CLEARED
+ CMP BYTE PTR DBLFLG,0 ;Have we already calculated System space?
+ JNZ CLEARED ;Yes
+ INC BYTE PTR DBLFLG ;No -- set the flag
+ CALL GETSIZE ;Calculate the system size
+CLEARED:
+ CALL WRTFAT
+ JNC FATWRT
+ MOV DX,OFFSET NOUSE
+ CALL PRINT
+ JMP FRMTPROB
+
+FATWRT:
+
+ TEST SWITCHMAP,SYSSW ;System desired
+ JZ STATUS
+ CALL WRITEDOS ;Write the BIOS & DOS
+ JNC SYSOK
+ MOV DX,OFFSET NOTSYS ;Can't transfer a system
+ CALL PRINT
+ MOV WORD PTR SYSSIZ+2,0 ;No system transfered
+ MOV WORD PTR SYSSIZ,0 ;No system transfered
+ JMP SHORT STATUS
+
+SYSOK:
+ MOV DX,OFFSET SYSTRAN
+ CALL PRINT
+STATUS:
+ CALL CRLF
+ CALL VOLID
+ MOV AH,DISK_RESET
+ INT 21H
+ CALL DONE ;Final call to OEM module
+ JNC REPORTC
+ JMP FRMTPROB ;Report an error
+
+REPORTC:
+ CALL REPORT
+
+ CALL MORE ;See if more disks to format
+ JMP SYSLOOP ;If we returned from MORE then continue
+
+DISP32BITS:
+ 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. Print 8-digit number with 2 leading blanks.
+ MOV CX,1810H
+ XCHG DX,AX
+ CALL DIGIT
+ XCHG AX,BX
+ CALL OUTWORD
+ XCHG AX,BP
+ CALL OUTWORD
+ POP DX
+ CMP DX,0
+ JZ RET3
+ CALL PRINT
+RET3: 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
+ MOV AH,STD_CON_OUTPUT
+ INT 21H
+ RET
+
+CONVWRD:
+ ADC AL,AL
+ DAA
+ XCHG AL,AH
+ ADC AL,AL
+ DAA
+ XCHG AL,AH
+RET2: RET
+
+UNSCALE:
+ SHR CX,1
+ JC RET2
+ SHL AX,1
+ RCL DX,1
+ JMP SHORT UNSCALE
+
+
+;******************************************
+; Calculate the size in bytes of the system rounded up to sector and
+; cluster boundries, Answer in SYSSIZ
+
+GETSIZE:
+ MOV AX,WORD PTR BIOSSIZB ;And calculate the system size
+ MOV DX,WORD PTR BIOSSIZB+2
+ CALL FNDSIZ
+ MOV AX,WORD PTR DOSSIZB
+ MOV DX,WORD PTR DOSSIZB+2
+ CALL FNDSIZ
+ MOV AX,WORD PTR COMSIZB
+ MOV DX,WORD PTR COMSIZB+2
+
+;Calculate the number of sectors used for the system
+FNDSIZ:
+ DIV SECSIZ
+ OR DX,DX
+ JZ FNDSIZ0
+ INC AX ; Round up to next sector
+FNDSIZ0:
+ PUSH AX
+ XOR DX,DX
+ DIV CLUSSIZ
+ POP AX
+ OR DX,DX
+ JZ ONCLUS
+ SUB DX,CLUSSIZ
+ NEG DX
+ ADD AX,DX ; Round up sector count to cluster
+ ; boundry
+ONCLUS:
+ MUL SECSIZ ; Turn it back into bytes
+ ADD WORD PTR SYSSIZ,AX
+ ADC WORD PTR SYSSIZ+2,DX
+ RET
+
+PRINT: MOV AH,STD_CON_STRING_OUTPUT ;Print msg pointed to by DX
+ INT 21H
+ RET
+
+MORE: CMP BYTE PTR [HARDFLAG],0 ;Check if removable media
+ JNZ FEXIT
+ CALL WAITYN ;Get yes or no response
+ JB FEXIT ;Exit if CF=1
+ CALL CRLF
+CRLF:
+ MOV DX,OFFSET CRLFMSG
+ CALL PRINT
+ RET
+
+PERROR: CALL PRINT ;Print message and exit
+FEXIT:
+ CALL RESTUDIR ;Restore users dirs
+FEXIT2:
+ INT 20H
+
+ ;Prompt the user for a system diskette in the default drive
+SYSPRM:
+ MOV AH,GET_DEFAULT_DRIVE ;Will find out the default drive
+ INT 21H ;Default now in AL
+ IF IBMVER OR IBMJAPVER
+ MOV BX,AX
+ ENDIF
+ ADD AL,41H ;Now in Ascii
+ MOV SYSDRV,AL ;Text now ok
+
+ IF IBMVER OR IBMJAPVER
+ INT 11H ;Make sure drive has insertable media
+ AND AL,11000000B
+ ROL AL,1
+ ROL AL,1
+ OR AL,AL
+ JNZ NOTONEDRV
+ INC AL
+NOTONEDRV:
+ CMP BL,AL
+ JBE ISFLOPPY
+ MOV AL,"A"
+ MOV BYTE PTR [SYSDRV],AL
+ MOV [BIODRV],AL
+ MOV [DOSDRV],AL
+ MOV [COMDRV],AL
+ISFLOPPY:
+ ENDIF
+
+ MOV DX,OFFSET SYSMSG
+ CALL PRINT ;Print first line
+ CALL WAITKY ;Wait for a key
+ CALL CRLF
+ RET
+
+TARGPRM:
+ MOV DX,OFFSET TARGMSG
+ CALL PRINT ;Print first line
+ CALL WAITKY ;Wait for a key
+ CALL CRLF
+ RET
+
+DSKPRM:
+ MOV DX,OFFSET SNGMSG ;Point to the message
+ CMP BYTE PTR [HARDFLAG],0 ;Check if removable media
+ JZ GOPRNIT
+ MOV DX,OFFSET HRDMSG
+GOPRNIT:
+ CALL PRINT ;Print the message
+ CALL WAITKY ;Wait for space bar
+ CALL CRLF
+ CALL CRLF
+ RET
+
+ ;Will wait for any key to be depressed.
+WAITKY:
+ MOV AX,(STD_CON_INPUT_FLUSH SHL 8) OR STD_CON_INPUT_NO_ECHO
+ INT 21H
+ MOV AX,(STD_CON_INPUT_FLUSH SHL 8) + 0
+ INT 21H
+
+ return
+
+FDPB: MOV DL,DRIVE
+ INC DL
+ MOV AH,GET_DPB
+ PUSH DS
+ INT 21H
+ INC AL
+ JZ DRVERR
+ MOV DX,WORD PTR [BX+13]
+ DEC DX
+ MOV AL,BYTE PTR [BX+4]
+ INC AL
+ MOV CX,WORD PTR [BX+2]
+ POP DS
+ RET
+DRVERR:
+ POP DS
+ MOV DX,OFFSET INVDRV
+ JMP PERROR
+
+ ;Clear the FAT and directory and set Dirty byte in the FAT
+CLEAR:
+ MOV AL,FATID
+ OR AL,0F8H ;Make sure it's a legal value
+ MOV AH,0FFH
+ MOV DI,FATSPACE
+ MOV WORD PTR[DI],AX
+ MOV BYTE PTR[DI+2],AH
+ MOV AH,DISK_RESET
+ INT 21H
+ CALL WRTFAT
+
+ IF IBMJAPVER
+ PUSH DS
+ MOV DL,[DRIVE] ;GET THE DRIVE PARAMETER
+ INC DL
+ MOV AH,32H
+ INT 21H
+
+ MOV DPB_FIRST_ACCESS[BX],-1 ;FORCE MEDIA CHANGE
+ POP DS
+ ENDIF
+
+ CALL FDPB
+ MOV WORD PTR FDSKSIZ,DX
+ MOV SECSIZ,CX
+ MOV AH,0
+ MOV CLUSSIZ,AX
+ SHR DX,1
+ JNC ROUNDED
+ INC DX
+ROUNDED:
+ ADD DX,WORD PTR FDSKSIZ
+ XOR AX,AX
+ MOV CX,DX
+ MOV DI,FATSPACE
+ ADD DI,3
+ REP STOSB
+ MOV AH,DISK_RESET
+ INT 21H
+ CALL WRTFAT
+ MOV DL,[DRIVE]
+ ADD DL,'A'
+ MOV [ROOTSTR],DL
+ MOV DX,OFFSET ROOTSTR
+ MOV AH,CHDIR
+ INT 21H ;Go to root on target drive
+ MOV AL,DRIVE
+ INC AL
+ MOV ALLDRV,AL
+ MOV AH,FCB_DELETE
+ MOV DX,OFFSET ALLFILE
+ INT 21H
+
+ TEST SWITCHMAP,OLDSW ;See if E5 terminated DIR requested
+ JZ RET25
+ MOV AL,DRIVE
+ INC AL
+ MOV BYTE PTR CLEANFILE,AL ;Get the drive
+ MOV DX,OFFSET CLEANFILE
+ MOV AH,FCB_CREATE
+MAKE_NEXT:
+ INT 21H
+ OR AL,AL
+ JNZ DELETE_THEM
+ INC BYTE PTR CLNNAM
+ CMP BYTE PTR CLNNAM,"Z" + 1
+ JNZ MAKE_NEXT
+ MOV BYTE PTR CLNNAM,"A"
+ INC BYTE PTR CLNNAM + 1
+ CMP BYTE PTR CLNNAM + 1,"Z" + 1
+ JNZ MAKE_NEXT
+ MOV BYTE PTR CLNNAM + 1,"A"
+ INC BYTE PTR CLNNAM + 2
+ JMP MAKE_NEXT
+
+DELETE_THEM:
+ MOV WORD PTR CLNNAM,"??"
+ MOV BYTE PTR CLNNAM + 2,"?"
+ MOV AH,FCB_DELETE
+ INT 21H
+RET25:
+ RET ;And return
+
+
+;*****************************************
+; Process V switch if set
+
+VOLID:
+ TEST [SWITCHMAP],VOLSW
+ JNZ DOVOL
+VRET: CLC
+ RET
+
+DOVOL:
+ PUSH CX
+ PUSH SI
+ PUSH DI
+ PUSH ES
+ PUSH DS
+ POP ES
+VOL_LOOP:
+ MOV AL,DRIVE
+ INC AL
+ MOV DS:BYTE PTR[VOLFCB+7],AL
+ MOV DX,OFFSET LABPRMT
+ CALL PRINT
+ MOV DX,OFFSET INBUFF
+ MOV AH,STD_CON_STRING_INPUT
+ INT 21H
+ MOV DX,OFFSET CRLFMSG
+ CALL PRINT
+ MOV DX,OFFSET CRLFMSG
+ CALL PRINT
+ MOV CL,[INBUFF+1]
+ OR CL,CL
+ JZ VOLRET
+ XOR CH,CH
+ MOV SI,OFFSET INBUFF+2
+ MOV DI,SI
+ ADD DI,CX
+ MOV CX,11
+ MOV AL,' '
+ REP STOSB
+ MOV CX,5
+ MOV DI,OFFSET VOLNAM
+ REP MOVSW
+ MOVSB
+ MOV DX,OFFSET VOLFCB
+ MOV AH,FCB_CREATE
+ INT 21H
+ OR AL,AL
+ JZ GOOD_CREATE
+ MOV DX,OFFSET INVCHR ;PRINT INVALID CHARS MESSAGE
+ CALL PRINT
+ JMP VOL_LOOP
+GOOD_CREATE:
+ MOV DX,OFFSET VOLFCB
+ MOV AH,FCB_CLOSE
+ INT 21H
+ CALL CRLF
+VOLRET:
+ POP ES
+ POP DI
+ POP SI
+ POP CX
+ RET
+
+;****************************************
+;Copy IO.SYS, MSDOS.SYS and COMMAND.COM into data area.
+; Carry set if problems
+
+READDOS:
+ CALL TESTSYSDISK
+ JNC RDFILS
+ RET
+
+RDFILS:
+ MOV BYTE PTR [FILSTAT],0
+ MOV BX,[BIOSHandle]
+ MOV AX,[MSTART]
+ MOV DX,AX
+ ADD DX,[MSIZE] ; CX first bad para
+ MOV [BIOSSTRT],AX
+ MOV CX,[BIOSSIZP]
+ ADD AX,CX
+ CMP AX,DX
+ JBE GOTBIOS
+ MOV BYTE PTR [FILSTAT],00000001B ; Got part of BIOS
+ MOV SI,[MSIZE]
+ XOR DI,DI
+ CALL DISIX4
+ MOV DS,[BIOSSTRT]
+ASSUME DS:NOTHING
+ CALL READFILE
+ASSUME DS:CODE
+ JC CLSALL
+ XOR DX,DX
+ MOV CX,DX
+ MOV AX,(LSEEK SHL 8) OR 1
+ INT 21H
+ MOV WORD PTR [BIOSOFFS],AX
+ MOV WORD PTR [BIOSOFFS+2],DX
+FILESDONE:
+ CLC
+CLSALL:
+ PUSHF
+ CALL COMCLS
+ POPF
+ RET
+
+GOTBIOS:
+ MOV BYTE PTR [FILSTAT],00000010B ; Got all of BIOS
+ LES SI,[BIOSSIZB]
+ MOV DI,ES
+ MOV DS,[BIOSSTRT]
+ASSUME DS:NOTHING
+ CALL READFILE
+ASSUME DS:CODE
+ JC CLSALL
+ MOV BX,[DOSHandle]
+ MOV [DOSSTRT],AX
+ CMP AX,DX ; No room left?
+ JZ CLSALL ; Yes
+ MOV CX,[DOSSIZP]
+ ADD AX,CX
+ CMP AX,DX
+ JBE GOTDOS
+ OR BYTE PTR [FILSTAT],00000100B ; Got part of DOS
+ SUB DX,[DOSSTRT]
+ MOV SI,DX
+ XOR DI,DI
+ CALL DISIX4
+ MOV DS,[DOSSTRT]
+ASSUME DS:NOTHING
+ CALL READFILE
+ASSUME DS:CODE
+ JC CLSALL
+ XOR DX,DX
+ MOV CX,DX
+ MOV AX,(LSEEK SHL 8) OR 1
+ INT 21H
+ MOV WORD PTR [DOSOFFS],AX
+ MOV WORD PTR [DOSOFFS+2],DX
+ JMP FILESDONE
+
+GOTDOS:
+ OR BYTE PTR [FILSTAT],00001000B ; Got all of DOS
+ LES SI,[DOSSIZB]
+ MOV DI,ES
+ MOV DS,[DOSSTRT]
+ASSUME DS:NOTHING
+ CALL READFILE
+ASSUME DS:CODE
+CLSALLJ: JC CLSALL
+ MOV BX,[COMHandle]
+ MOV [COMSTRT],AX
+ CMP AX,DX ; No room left?
+ JZ CLSALL ; Yes
+ MOV CX,[COMSIZP]
+ ADD AX,CX
+ CMP AX,DX
+ JBE GOTCOM
+ OR BYTE PTR [FILSTAT],00010000B ; Got part of COMMAND
+ SUB DX,[COMSTRT]
+ MOV SI,DX
+ XOR DI,DI
+ CALL DISIX4
+ MOV DS,[COMSTRT]
+ASSUME DS:NOTHING
+ CALL READFILE
+ASSUME DS:CODE
+ JC CLSALLJ
+ XOR DX,DX
+ MOV CX,DX
+ MOV AX,(LSEEK SHL 8) OR 1
+ INT 21H
+ MOV WORD PTR [COMOFFS],AX
+ MOV WORD PTR [COMOFFS+2],DX
+ JMP FILESDONE
+
+GOTCOM:
+ OR BYTE PTR [FILSTAT],00100000B ; Got all of COMMAND
+ LES SI,[COMSIZB]
+ MOV DI,ES
+ MOV DS,[COMSTRT]
+ASSUME DS:NOTHING
+ CALL READFILE
+ASSUME DS:CODE
+ JMP CLSALL
+
+;**************************************************
+;Write BIOS DOS COMMAND to the newly formatted disk.
+
+WRITEDOS:
+ MOV CX,BIOSATT
+ MOV DX,OFFSET BIOSFIL
+ LES SI,[BIOSSIZB]
+ MOV DI,ES
+ CALL MAKEFIL
+ JNC GOTNBIO
+RET34: RET
+
+GOTNBIO:
+ MOV [TempHandle],BX
+ TEST BYTE PTR FILSTAT,00000010B
+ JNZ GOTALLBIO
+ LES SI,[BIOSOFFS]
+ MOV DI,ES
+ MOV WORD PTR [IOCNT],SI
+ MOV WORD PTR [IOCNT+2],DI
+ MOV BP,OFFSET BIOSData
+ CALL GOTTARG
+ JC RET34
+ JMP SHORT BIOSDONE
+
+GOTALLBIO:
+ LES SI,[BIOSSIZB]
+ MOV DI,ES
+ MOV DS,[BIOSSTRT]
+ASSUME DS:NOTHING
+ CALL WRITEFILE
+ASSUME DS:CODE
+BIOSDONE:
+ MOV BX,[TempHandle]
+ MOV CX,BTIME
+ MOV DX,BDATE
+ CALL CLOSETARG
+ MOV CX,DOSATT
+ MOV DX,OFFSET DOSFIL
+ LES SI,[DOSSIZB]
+ MOV DI,ES
+ CALL MAKEFIL
+ JC RET34
+
+GOTNDOS:
+ MOV [TempHandle],BX
+ TEST BYTE PTR FILSTAT,00001000B
+ JNZ GOTALLDOS
+ MOV BP,OFFSET DOSData
+ TEST BYTE PTR FILSTAT,00000100B
+ JNZ PARTDOS
+ MOV WORD PTR [DOSOFFS],0
+ MOV WORD PTR [DOSOFFS+2],0
+ CALL GETSYS3
+RET34J: JC RET34
+ JMP SHORT DOSDONE
+
+PARTDOS:
+ LES SI,[DOSOFFS]
+ MOV DI,ES
+ MOV WORD PTR [IOCNT],SI
+ MOV WORD PTR [IOCNT+2],DI
+ CALL GOTTARG
+ JC RET34J
+ JMP SHORT DOSDONE
+
+GOTALLDOS:
+ LES SI,[DOSSIZB]
+ MOV DI,ES
+ MOV DS,[DOSSTRT]
+ASSUME DS:NOTHING
+ CALL WRITEFILE
+ASSUME DS:CODE
+DOSDONE:
+ MOV BX,[TempHandle]
+ MOV CX,DTIME
+ MOV DX,DDATE
+ CALL CLOSETARG
+ MOV CX,COMATT
+ MOV DX,OFFSET COMFIL
+ LES SI,[COMSIZB]
+ MOV DI,ES
+ CALL MAKEFIL
+ JNC GOTNCOM
+RET35: RET
+
+GOTNCOM:
+ MOV [TempHandle],BX
+ TEST BYTE PTR FILSTAT,00100000B
+ JNZ GOTALLCOM
+ MOV BP,OFFSET COMData
+ TEST BYTE PTR FILSTAT,00010000B
+ JNZ PARTCOM
+ MOV WORD PTR [COMOFFS],0
+ MOV WORD PTR [COMOFFS+2],0
+ CALL GETSYS3
+ JC RET35
+ JMP SHORT COMDONE
+
+PARTCOM:
+ LES SI,[COMOFFS]
+ MOV DI,ES
+ MOV WORD PTR [IOCNT],SI
+ MOV WORD PTR [IOCNT+2],DI
+ CALL GOTTARG
+ JC RET35
+ JMP SHORT COMDONE
+
+GOTALLCOM:
+ LES SI,[COMSIZB]
+ MOV DI,ES
+ MOV DS,[COMSTRT]
+ASSUME DS:NOTHING
+ CALL WRITEFILE
+ASSUME DS:CODE
+COMDONE:
+ MOV BX,[TempHandle]
+ MOV CX,CTIME
+ MOV DX,CDATE
+ CALL CLOSETARG
+ CMP BYTE PTR [FILSTAT],00101010B
+ JZ NOREDOS
+RDFRST2:
+ CALL READDOS ; Start back with BIOS
+ JNC NOREDOS
+ CALL SYSPRM ;Prompt for system disk
+ JMP RDFRST2 ;Try again
+NOREDOS:
+ CLC
+ RET
+
+;*********************************************
+; Create a file on target disk
+; CX = attributes, DX points to name
+; DI:SI is size file is to have
+;
+; There is a bug in DOS 2.00 and 2.01 having to do with writes
+; from the end of memory. In order to circumvent it this routine
+; must create files with the length in DI:SI
+;
+; On return BX is handle, carry set if problem
+
+MAKEFIL:
+ MOV BX,DX
+ PUSH WORD PTR [BX]
+ MOV AL,TARGDRV
+ MOV [BX],AL
+ MOV AH,CREAT
+ INT 21H
+ POP WORD PTR [BX]
+ MOV BX,AX
+ JC RET50
+ MOV CX,DI
+ MOV DX,SI
+ MOV AX,LSEEK SHL 8
+ INT 21H ; Seek to eventual EOF
+ XOR CX,CX
+ MOV AH,WRITE
+ INT 21H ; Set size of file to position
+ XOR CX,CX
+ MOV DX,CX
+ MOV AX,LSEEK SHL 8
+ INT 21H ; Seek back to start
+RET50:
+ RET
+
+;*********************************************
+; Close a file on the target disk
+; CX/DX is time/date, BX is handle
+
+CLOSETARG:
+ MOV AX,(FILE_TIMES SHL 8) OR 1
+ INT 21H
+ MOV AH,CLOSE
+ INT 21H
+ RET
+
+SAVUDIRS:
+ XOR DL,DL
+ MOV SI,OFFSET USERDIRS
+ MOV BYTE PTR [SI],'\'
+ INC SI
+ MOV AH,CURRENT_DIR
+ INT 21H
+RET43: RET
+
+
+RESTUDIR:
+ TEST SWITCHMAP,SYSSW
+ JZ RET43
+ MOV DX,OFFSET USERDIRS
+ MOV AH,CHDIR
+ INT 21H ; Restore users DIR
+ RET
+
+INT_23:
+ PUSH CS
+ POP DS
+ JMP FEXIT
+
+;****************************************
+; Transfer system files
+; BP points to data structure for file involved
+; offset is set to current amount read in
+; Start set to start of file in buffer
+; TempHandle is handle to write to on target
+
+IOLOOP:
+ MOV AL,[SYSDRV]
+ CMP AL,[TARGDRV]
+ JNZ GOTTARG
+ MOV AH,DISK_RESET
+ INT 21H
+ CALL TARGPRM ;Get target disk
+
+GOTTARG:
+;Enter here if some of file is already in buffer, IOCNT must be set
+; to size already in buffer.
+ MOV BX,[TempHandle]
+ MOV SI,WORD PTR [IOCNT]
+ MOV DI,WORD PTR [IOCNT+2]
+ MOV DS,[BP.FILE_START]
+ASSUME DS:NOTHING
+ CALL WRITEFILE ; Write next part
+ASSUME DS:CODE
+ JNC TESTDONE
+ RET
+
+TESTDONE:
+ LES AX,[BP.FILE_OFFSET]
+ CMP AX,WORD PTR [BP.FILE_SIZEB]
+ JNZ GETSYS3
+ MOV AX,ES
+ CMP AX,WORD PTR [BP.FILE_SIZEB+2]
+ JNZ GETSYS3
+ RET ; Carry clear from CMP
+
+GETSYS3:
+;Enter here if none of file is in buffer
+ MOV AX,[MSTART] ; Furthur IO done starting here
+ MOV [BP.FILE_START],AX
+ MOV AL,[SYSDRV]
+ CMP AL,[TARGDRV]
+ JNZ TESTSYS
+ MOV AH,DISK_RESET
+ INT 21H
+GSYS:
+ CALL SYSPRM ;Prompt for system disk
+TESTSYS:
+ CALL TESTSYSDISK
+ JC GSYS
+ MOV BX,[BP.FILE_HANDLE]
+ LES DX,[BP.FILE_OFFSET]
+ PUSH DX
+ MOV CX,ES
+ MOV AX,LSEEK SHL 8
+ INT 21H
+ POP DX
+ LES SI,[BP.FILE_SIZEB]
+ MOV DI,ES
+ SUB SI,DX
+ SBB DI,CX ; DI:SI is #bytes to go
+ PUSH DI
+ PUSH SI
+ ADD SI,15
+ ADC DI,0
+ CALL DISID4
+ MOV AX,SI
+ POP SI
+ POP DI
+ CMP AX,[MSIZE]
+ JBE GOTSIZ2
+ MOV SI,[MSIZE]
+ XOR DI,DI
+ CALL DISIX4
+GOTSIZ2:
+ MOV WORD PTR [IOCNT],SI
+ MOV WORD PTR [IOCNT+2],DI
+ MOV DS,[MSTART]
+ASSUME DS:NOTHING
+ CALL READFILE
+ASSUME DS:CODE
+ JNC GETOFFS
+ CALL CLSALL
+ JMP GSYS
+GETOFFS:
+ XOR DX,DX
+ MOV CX,DX
+ MOV AX,(LSEEK SHL 8) OR 1
+ INT 21H
+ MOV WORD PTR [BP.FILE_OFFSET],AX
+ MOV WORD PTR [BP.FILE_OFFSET+2],DX
+ CALL CLSALL
+ JMP IOLOOP
+
+;*************************************************
+; Test to see if correct system disk. Open handles
+
+TESTSYSDISK:
+ MOV AX,OPEN SHL 8
+ MOV DX,OFFSET BIOSFIL
+ INT 21H
+ JNC SETBIOS
+CRET12: STC
+RET12: RET
+
+SETBIOS:
+ MOV [BIOSHandle],AX
+ MOV BX,AX
+ CALL GETFSIZ
+ CMP [BIOSSIZP],0
+ JZ SETBIOSSIZ
+ CMP [BIOSSIZP],AX
+ JZ SETBIOSSIZ
+BIOSCLS:
+ MOV AH,CLOSE
+ MOV BX,[BIOSHandle]
+ INT 21H
+ JMP CRET12
+
+SETBIOSSIZ:
+ MOV [BIOSSIZP],AX
+ MOV WORD PTR [BIOSSIZB],SI
+ MOV WORD PTR [BIOSSIZB+2],DI
+ MOV [BDATE],DX
+ MOV [BTIME],CX
+ MOV AX,OPEN SHL 8
+ MOV DX,OFFSET DOSFIL
+ INT 21H
+ JNC DOSOPNOK
+ JMP BIOSCLS
+
+DOSOPNOK:
+ MOV [DOSHandle],AX
+ MOV BX,AX
+ CALL GETFSIZ
+ CMP [DOSSIZP],0
+ JZ SETDOSSIZ
+ CMP [DOSSIZP],AX
+ JZ SETDOSSIZ
+DOSCLS:
+ MOV AH,CLOSE
+ MOV BX,[DOSHandle]
+ INT 21H
+ JMP BIOSCLS
+
+SETDOSSIZ:
+ MOV [DOSSIZP],AX
+ MOV WORD PTR [DOSSIZB],SI
+ MOV WORD PTR [DOSSIZB+2],DI
+ MOV [DDATE],DX
+ MOV [DTIME],CX
+ MOV AX,OPEN SHL 8
+ MOV DX,OFFSET COMFIL
+ INT 21H
+ JC DOSCLS
+ MOV [COMHandle],AX
+ MOV BX,AX
+ CALL GETFSIZ
+ CMP [COMSIZP],0
+ JZ SETCOMSIZ
+ CMP [COMSIZP],AX
+ JZ SETCOMSIZ
+COMCLS:
+ MOV AH,CLOSE
+ MOV BX,[COMHandle]
+ INT 21H
+ JMP DOSCLS
+
+SETCOMSIZ:
+ MOV [COMSIZP],AX
+ MOV WORD PTR [COMSIZB],SI
+ MOV WORD PTR [COMSIZB+2],DI
+ MOV [CDATE],DX
+ MOV [CTIME],CX
+ CLC
+ RET
+
+;*******************************************
+; Handle in BX, return file size in para in AX
+; File size in bytes DI:SI, file date in DX, file
+; time in CX.
+
+GETFSIZ:
+ MOV AX,(LSEEK SHL 8) OR 2
+ XOR CX,CX
+ MOV DX,CX
+ INT 21H
+ MOV SI,AX
+ MOV DI,DX
+ ADD AX,15 ; Para round up
+ ADC DX,0
+ AND DX,0FH ; If the file is larger than this
+ ; it is bigger than the 8086 address space!
+ MOV CL,12
+ SHL DX,CL
+ MOV CL,4
+ SHR AX,CL
+ OR AX,DX
+ PUSH AX
+ MOV AX,LSEEK SHL 8
+ XOR CX,CX
+ MOV DX,CX
+ INT 21H
+ MOV AX,FILE_TIMES SHL 8
+ INT 21H
+ POP AX
+ RET
+
+;********************************************
+; Read/Write file
+; DS:0 is Xaddr
+; DI:SI is byte count to I/O
+; BX is handle
+; Carry set if screw up
+;
+; I/O SI bytes
+; I/O 64K - 1 bytes DI times
+; I/O DI bytes
+; DS=CS on output
+
+
+READFILE:
+; Must preserve AX,DX
+ PUSH AX
+ PUSH DX
+ PUSH BP
+ MOV BP,READ SHL 8
+ CALL FILIO
+ POP BP
+ POP DX
+ POP AX
+ PUSH CS
+ POP DS
+ RET
+
+WRITEFILE:
+ PUSH BP
+ MOV BP,WRITE SHL 8
+ CALL FILIO
+ POP BP
+ PUSH CS
+ POP DS
+ RET
+
+FILIO:
+ XOR DX,DX
+ MOV CX,SI
+ JCXZ K64IO
+ MOV AX,BP
+ INT 21H
+ JC IORET
+ ADD DX,AX
+ CMP AX,CX ; If not =, AX<CX, carry set.
+ JNZ IORET
+ CALL NORMALIZE
+K64IO:
+ CLC
+ MOV CX,DI
+ JCXZ IORET
+ MOV AX,BP
+ INT 21H
+ JC IORET
+ ADD DX,AX
+ CMP AX,CX ; If not =, AX<CX, carry set.
+ JNZ IORET
+ CALL NORMALIZE
+ MOV CX,DI
+K64M1:
+ PUSH CX
+ XOR AX,AX
+ OR DX,DX
+ JZ NORMIO
+ MOV CX,10H
+ SUB CX,DX
+ MOV AX,BP
+ INT 21H
+ JC IORETP
+ ADD DX,AX
+ CMP AX,CX ; If not =, AX<CX, carry set.
+ JNZ IORETP
+ CALL NORMALIZE
+NORMIO:
+ MOV CX,0FFFFH
+ SUB CX,AX
+ MOV AX,BP
+ INT 21H
+ JC IORETP
+ ADD DX,AX
+ CMP AX,CX ; If not =, AX<CX, carry set.
+ JNZ IORETP
+ CALL NORMALIZE ; Clears carry
+ POP CX
+ LOOP K64M1
+ PUSH CX
+IORETP:
+ POP CX
+IORET:
+ RET
+
+
+;*********************************
+; Shift DI:SI left 4 bits
+DISIX4:
+ MOV CX,4
+SH32:
+ SHL SI,1
+ RCL DI,1
+ LOOP SH32
+ RET
+
+;*********************************
+; Shift DI:SI right 4 bits
+DISID4:
+ MOV CX,4
+SH32B:
+ SHR DI,1
+ RCR SI,1
+ LOOP SH32B
+ RET
+
+;********************************
+; Normalize DS:DX
+
+NORMALIZE:
+ PUSH DX
+ PUSH AX
+ SHR DX,1
+ SHR DX,1
+ SHR DX,1
+ SHR DX,1
+ MOV AX,DS
+ ADD AX,DX
+ MOV DS,AX
+ POP AX
+ POP DX
+ AND DX,0FH ; Clears carry
+ RET
+
+
+ROOTSTR DB ?
+ DB ":"
+SWTCH DB "/",0
+DBLFLG DB 0 ;Initialize flags to zero
+CLEARFLG DB 0
+DRIVE DB 0
+DEFALT DB 0 ;Default drive
+IOCNT DD ?
+MSTART DW ? ; Start of sys file buffer (para#)
+MSIZE DW ? ; Size of above in paragraphs
+TempHandle DW ?
+FILSTAT DB ? ; In memory status of files
+ ; XXXXXX00B BIOS not in
+ ; XXXXXX01B BIOS partly in
+ ; XXXXXX10B BIOS all in
+ ; XXXX00XXB DOS not in
+ ; XXXX01XXB DOS partly in
+ ; XXXX10XXB DOS all in
+ ; XX00XXXXB COMMAND not in
+ ; XX01XXXXB COMMAND partly in
+ ; XX10XXXXB COMMAND all in
+
+USERDIRS DB DIRSTRLEN+3 DUP(?) ; Storage for users current directory
+
+BIOSData LABEL BYTE
+BIOSHandle DW 0
+BIOSSIZP DW 0
+BIOSSIZB DD ?
+BIOSOFFS DD ?
+BIOSSTRT DW ?
+BDATE DW 0 ;IO system date stored here
+BTIME DW 0 ;IO system time stored here
+
+BIOSATT EQU attr_hidden + attr_system + attr_read_only
+BIOSFIL LABEL BYTE
+BIODRV LABEL BYTE
+ DB "X:\"
+ IF IBMVER OR IBMJAPVER
+ DB "IBMBIO.COM"
+ ENDIF
+ IF MSVER
+ DB "IO.SYS"
+ ENDIF
+ DB 0
+
+DOSData LABEL BYTE
+DOSHandle DW 0
+DOSSIZP DW 0
+DOSSIZB DD ?
+DOSOFFS DD ?
+DOSSTRT DW ?
+DDATE DW 0 ;DOS date stored here
+DTIME DW 0 ;DOS time
+
+DOSATT EQU attr_hidden + attr_system + attr_read_only
+DOSFIL LABEL BYTE
+DOSDRV LABEL BYTE
+ DB "X:\"
+ IF IBMVER OR IBMJAPVER
+ DB "IBMDOS.COM"
+ ENDIF
+ IF MSVER
+ DB "MSDOS.SYS"
+ ENDIF
+ DB 0
+
+COMData LABEL BYTE
+COMHandle DW 0
+COMSIZP DW 0
+COMSIZB DD ?
+COMOFFS DD ?
+COMSTRT DW ?
+CDATE DW 0 ;Date of COMMAND
+CTIME DW 0 ;Time of COMMAND
+
+COMATT EQU 0
+COMFIL LABEL BYTE
+COMDRV LABEL BYTE
+ DB "X:\COMMAND.COM",0
+
+VOLFCB DB -1,0,0,0,0,0,8
+ DB 0
+VOLNAM DB " "
+ DB 8
+ DB 26 DUP(?)
+
+ALLFILE DB -1,0,0,0,0,0,0FFH
+ALLDRV DB 0,"???????????"
+ DB 26 DUP(?)
+
+CLEANFILE DB 0
+CLNNAM DB "AAAFFFFFFOR"
+ DB 26 DUP(?)
+
+SWITCHMAP DW ?
+SWITCHCOPY DW ?
+FAT DW ?
+ DW ?
+CLUSSIZ DW ?
+SECSIZ DW ?
+SYSSIZ DD ?
+FDSKSIZ DD ?
+BADSIZ DD ?
+SYSTRKS DW ?
+SECTORS DW ?
+INBUFF DB 80,0
+ DB 80 DUP(?)
+
+ DB 100H DUP(?)
+
+STACK LABEL BYTE
+
+;For FORMES module
+
+ EXTRN BADVER:BYTE,SNGMSG:BYTE,SNGDRV:BYTE,HRDMSG:BYTE,HRDDRV:BYTE
+ EXTRN LABPRMT:BYTE,TARGMSG:BYTE,TARGDRV:BYTE
+ EXTRN SYSTRAN:BYTE,CRLFMSG:BYTE,INVCHR:BYTE,INVDRV:BYTE
+ EXTRN SYSMSG:BYTE,SYSDRV:BYTE,FRMTERR:BYTE,NOTSYS:BYTE
+ EXTRN NOUSE:BYTE,MEMEX:BYTE,INVPAR:BYTE
+
+ IF IBMVER
+ EXTRN ASGERR:BYTE
+ ENDIF
+
+CODE ENDS
+
+ END START
+\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a
\ No newline at end of file
--- /dev/null
+FORMAT - formats a new disk, clears the FAT and DIRECTORY\r
+and optionally copies the SYSTEM and COMMAND.COM to this\r
+new disk.\r
+\r
+Command syntax:\r
+\r
+ FORMAT [drive:][/switch1][/switch2]...[/switch16]\r
+\r
+ Where "drive:" is a legal drive specification and if\r
+ omitted indicates that the default drive will be used.\r
+ There may be up to 16 legal switches included in the\r
+ command line.\r
+\r
+\r
+ The OEM must supply five (NEAR) routines to the program\r
+along with 6 data items. The names of the routines are INIT,\r
+DISKFORMAT, BADSECTOR, WRTFAT and DONE, and their flow of\r
+control (by the Microsoft module) is like this:\r
+\r
+ |\r
+ +---------+\r
+ | INIT |\r
+ +---------+\r
+ |\r
+ |<------------------------------+\r
++------------+ |\r
+| DISKFORMAT | |\r
++------------+ |\r
+ |<-------+ |\r
++-----------+ |-This loop is done |- This loop done\r
+| BADSECTOR | | for each group of | once for each disk\r
++-----------+ | bad sectors | to be formatted.\r
+ |----->--+ | If variable HARDFLAG\r
+ | | is set then the loop\r
++----------+ | is only performed\r
+| | | once.\r
+| WRTFAT | |\r
++----------+ |\r
+ | |\r
+ +------+ |\r
+ | DONE | |\r
+ +------+ |\r
+ +---->--------------------------+\r
+\r
+ The INIT, DISKFORMAT, and BADSECTOR routines are free\r
+to use any MS-DOS system calls, except for calls that cause\r
+disk accesses on the disk being formatted. DONE may use\r
+ANY calls, since by the time it is called the new disk has\r
+been formatted.\r
+\r
+The following data must be declared PUBLIC in a module\r
+provided by the OEM:\r
+\r
+ SWITCHLIST - A string of bytes. The first byte is count\r
+ N, followed by N characters which are the switches to\r
+ be accepted by the command line scanner. Alphabetic\r
+ characters must be in upper case (the numeric\r
+ characters 0-9 are allowed). The last three switches,\r
+ normally "O", "V" and "S", have pre-defined meanings.\r
+\r
+ The "S" switch is the switch which causes the\r
+ system files IO.SYS, MSDOS.SYS, and COMMAND.COM to be\r
+ transfered to the disk after it is formatted thus\r
+ making a "S"ystem disk. The switch can be some letter\r
+ other than "S", but the last switch in the list is\r
+ assumed to have the meaning "transfer system",\r
+ regardles of what the particular letter is.\r
+\r
+ The second to the last switch, "V", causes FORMAT\r
+ to prompt the user for a volume label after the disk\r
+ is formatted. Again, as with "S", the particular\r
+ letter is not important but rather the position in the\r
+ list.\r
+\r
+ The third to the last switch, "O", causes FORMAT to\r
+ produce an IBM Personal Computer DOS version 1.X\r
+ compatible disk. Normally FORMAT causes a 0 byte to\r
+ be placed in the first byte of each directory entry\r
+ instead of the 0E5 Hex free entry designator. This\r
+ results in a very marked directory search performance\r
+ increase due to an optimization in the DOS. Disks\r
+ made this way cause trouble on IBM PC DOS 1.X\r
+ versions, however, which did not have this\r
+ optimization. The 0 byte fools IBM 1.X versions into\r
+ thinking these entries are allocated instead of free,\r
+ NOTE that IBM Personnal Computer DOS version 2.00 and\r
+ MS-DOS version 1.25 will have no trouble with these\r
+ disks, since they have the same optimization. The "O"\r
+ switch causes FORMAT to re-do the directory with a 0E5\r
+ Hex byte at the start of each entry so that the disk\r
+ may be used with 1.X versions of IBM PC DOS, as well\r
+ as MS-DOS 1.25/2.00 and IBM PC DOS 2.00. This switch\r
+ should only be given when needed because it takes a\r
+ fair amount of time for FORMAT to perform the\r
+ conversion, and it noticably decreases 1.25 and 2.00\r
+ performance on disks with few directory entries.\r
+\r
+ Up to 16 switches are permitted. Normally a "C"\r
+ switch is specified for "Clear". This switch should\r
+ cause the formatting operation to be bypassed (within\r
+ DISKFORMAT or BADSECTOR). This is provided as a\r
+ time-saving convenience to the user, who may wish\r
+ to "start fresh" on a previosly formatted and used\r
+ disk.\r
+\r
+ HARDFLAG - BYTE location which specifies whether the\r
+ OEM routine is formatting a fixed disk or a a drive\r
+ with removable media. A zero indicates removable\r
+ media, any other value indicates a fixed disk. The\r
+ status of this byte only effect the messages printed\r
+ by the main format module. This value should be\r
+ set or reset by the OEM supplied INIT routine.\r
+\r
+ FATID - BYTE location containing the value to be used\r
+ in the first byte of the FAT. Must be in the range\r
+ F8 hex to FF hex.\r
+\r
+ STARTSECTOR - WORD location containing the sector number\r
+ of the first sector of the data area.\r
+\r
+ FATSPACE - WORD location containing the address of the\r
+ start of the FAT area. A FAT built in this area\r
+ will be written to disk using the OEM supplied WRTFAT\r
+ subroutine. 6k is sufficient to store any FAT. This\r
+ area must not overlap the FREESPACE area.\r
+\r
+ FREESPACE - WORD location which contains the address\r
+ of the start of free memory space. This is where\r
+ the system will be loaded, by the Microsoft module,\r
+ for transferring to the newly formatted disk. Memory\r
+ should be available from this address to the end\r
+ of memory, so it is typically the address of the\r
+ end of the OEM module.\r
+\r
+The following routines must be declared PUBLIC in the\r
+OEM-supplied module:\r
+\r
+ INIT - An initialization routine. This routine is called\r
+ once at the start of the FORMAT run after the switches\r
+ have been processed. This routine should perform\r
+ any functions that only need to be done once per\r
+ FORMAT run. An example of what this routine might\r
+ do is read the boot sector into a buffer so that\r
+ it can be transferred to the new disks by DISKFORMAT.\r
+ If this routine returns with the CARRY flag set it\r
+ indicates an error, and FORMAT will print "Format\r
+ failure" and quit. This feature can be used to detect\r
+ conflicting switches (like specifying both single\r
+ and double density) and cause FORMAT to quit without\r
+ doing anything.\r
+\r
+ DISKFORMAT - Formats the disk according to the options\r
+ indicated by the switches and the value of FATID\r
+ must be defined when it returns (although INIT may\r
+ have already done it). This routine is called once\r
+ for EACH disk to be formatted. If neccessary it\r
+ must transfer the Bootstrap loader. If any error\r
+ conditions are detected, set the CARRY flag and return\r
+ to FORMAT. FORMAT will report a 'Format failure'\r
+ and prompt for another disk. (If you only require\r
+ a clear directory and FAT then simply setting the\r
+ appropriate FATID, if not done by INIT, will be all\r
+ that DISKFORMAT must do.)\r
+\r
+ BADSECTOR - Reports the sector number of any bad sectors\r
+ that may have been found during the formatting of\r
+ the disk. This routine is called at least once for\r
+ EACH disk to be formatted, and is called repeatedly\r
+ until AX is zero or the carry flag is set. The carry\r
+ flag is used just as in DISKFORMAT to indicate an\r
+ error, and FORMAT handles it in the same way. The\r
+ first sector in the data area must be in STARTSECTOR\r
+ for the returns from this routine to be interpreted\r
+ correctly. If there are bad sectors, BADSECTOR must\r
+ return a sector number in in register BX, the number\r
+ of consecutive bad sectors in register AX, and carry\r
+ clear. FORMAT will then process the bad sectors\r
+ and call BADSECTOR again. When BADSECTOR returns\r
+ with AX = 0 this means there are no more bad sectors;\r
+ FORMAT clears the directory and goes on to DONE,\r
+ so for this last return BX need not contain anything\r
+ meaningful.\r
+\r
+ FORMAT processes bad sectors by determining their\r
+ corresponding allocation unit and marking that unit\r
+ with an FF7 hex in the File Allocation Table. CHKDSK\r
+ understands the FF7 mark as a flag for bad sectors\r
+ and accordingly reports the number of bytes marked\r
+ in this way.\r
+\r
+ NOTE: Actual formatting of the disk can be done in\r
+ BADSECTOR instead of DISKFORMAT on a "report as you\r
+ go" basis. Formatting goes until a group of bad\r
+ sectors is encountered, BADSECTOR then reports them\r
+ by returning with AX and BX set. FORMAT will then\r
+ call BADSECTOR again and formatting can continue.\r
+\r
+ WRTFAT - This routine is called after the disk is\r
+ formatted and bad sectors have been reported. Its\r
+ purpose is to write all copies of the FAT from the\r
+ area of memory referenced by FATSPACE to the drive\r
+ just formatted. It may be possible to use INT 26H\r
+ to perform the write, or a direct BIOS call. Whether\r
+ this is possible depends on whether the FAT ID byte\r
+ is used by the BIOS to determine the media in the\r
+ drive. If it is, these methods will probably fail\r
+ because there is no FAT ID byte on the disk yet (in\r
+ this case WRTFATs primary job is to get the FAT ID\r
+ byte out on the disk and thus solve the chicken and\r
+ egg problem).\r
+\r
+ DONE - This routine is called after the formatting is\r
+ complete, the disk directory has been initialized,\r
+ and the system has been transferred. It is called\r
+ once for EACH disk to be formatted. This gives the\r
+ chance for any finishing-up operations, if needed.\r
+ If the OEM desires certain extra files to be put\r
+ on the diskette by default, or according to a switch,\r
+ this could be done in DONE. Again, as in BADSECTOR\r
+ and DISKFORMAT, carry flag set on return means an\r
+ error has occurred: 'Format failure' will be printed\r
+ and FORMAT will prompt for another disk.\r
+\r
+\r
+The following data is declared PUBLIC in Microsoft's FORMAT\r
+module:\r
+\r
+ SWITCHMAP - A word with a bit vector indicating what\r
+ switches have been included in the command line. The\r
+ correspondence of the bits to the switches is\r
+ determined by SWITCHLIST. The right-most\r
+ (highest-addressed) switch in SWITCHLIST (which must\r
+ be the system transfer switch, normally "S")\r
+ corresponds to bit 0, the second from the right,\r
+ normally "V" to bit 1, etc. For example, if\r
+ SWITCHLIST is the string "7,'AGI2OVS'", and the user\r
+ specifies "/G/S" on the command line, then bit 6 will\r
+ be 0 (A not specified), bit 5 will be 1 (G specified),\r
+ bits 4,3,2 and 1 will be 0 (neither I,2,O or V\r
+ specified), and bit 0 will be 1 (S specified).\r
+\r
+ Bits 0,1 and 2 are the only switches used in\r
+ Microsoft's FORMAT module. These switches are used 1)\r
+ after INIT has been called, to determine if it is\r
+ necessary to load the system; 2) after the last\r
+ BADSECTOR call, to determine if the system is to be\r
+ written, E5 directory conversion is to be done, and/or\r
+ a volume label is to be asked for. INIT may force\r
+ these bits set or reset if desired (for example, some\r
+ drives may never be used as system disk, such as hard\r
+ disks). After INIT, the "S" bit may be turned off\r
+ (but not on, since the system was never read) if\r
+ something happens that means the system should not be\r
+ transferred.\r
+\r
+ After INIT, a second copy of SWITCHMAP is made\r
+ internally which is used to restore SWITCHMAP for\r
+ each disk to be formatted. FORMAT itself will turn\r
+ off the system bit if bad sectors are reported in\r
+ the system area; DISKFORMAT and BADSECTOR are also\r
+ allowed to change the map. However, these changes\r
+ affect only the current disk being formatted, since\r
+ SWITCHMAP is restored after each disk. (Changes\r
+ made to SWITCHMAP by INIT do affect ALL disks.)\r
+\r
+ DRIVE - A byte containing the drive specified in the\r
+ command line. 0=A, 1=B, etc.\r
+\r
+Once the OEM-supplied module has been prepared, it must linked\r
+with Microsoft's FORMAT.OBJ module and the FORMES.OBJ module.\r
+If the OEM-supplied module is called OEMFOR.OBJ, then the\r
+following linker command will do:\r
+\r
+ LINK FORMAT FORMES OEMFOR;\r
+\r
+This command will produce a file called FORMAT.EXE. FORMAT\r
+has been designed to run under MS-DOS as a simple binary\r
+.COM file. This conversion is performed by LOCATE (EXE2BIN)\r
+with the command\r
+\r
+ LOCATE FORMAT.EXE FORMAT.COM\r
+\r
+which will produce the file FORMAT.COM.\r
+\r
+;*****************************************\r
+;\r
+; A Sample OEM module\r
+;\r
+;*****************************************\r
+\r
+CODE SEGMENT BYTE PUBLIC 'CODE'\r
+; This segment must be\r
+; named CODE, it must be\r
+; PUBLIC, and it's\r
+; classname must be 'CODE'\r
+ \r
+\r
+ ASSUME CS:CODE,DS:CODE,ES:CODE\r
+\r
+; Must declare data and routines PUBLIC\r
+ \r
+PUBLIC FATID,STARTSECTOR,SWITCHLIST,FREESPACE\r
+PUBLIC INIT,DISKFORMAT,BADSECTOR,DONE,WRTFAT\r
+PUBLIC FATSPACE,HARDFLAG\r
+\r
+; This data defined in Microsoft-supplied module\r
+\r
+ EXTRN SWITCHMAP:WORD,DRIVE:BYTE\r
+\r
+INIT:\r
+\r
+; Read the boot sector into memory\r
+ CALL READBOOT\r
+ ...\r
+; Set FATID to double sided if "D" switch specified\r
+ TEST SWITCHMAP,10H\r
+ JNZ SETDBLSIDE\r
+ ...\r
+ RET\r
+\r
+DISKFORMAT:\r
+ ...\r
+ \r
+; Use the bit map in SWITCHMAP to determine\r
+; what switches are set\r
+\r
+ TEST SWITCHMAP,8 ;Is there a "/C"?\r
+ JNZ CLEAR ; Yes -- clear operation\r
+ ; requested jump around the\r
+ ; format code\r
+ < format the disk >\r
+CLEAR:\r
+ ...\r
+; Transfer the boot from memory to the new disk\r
+ CALL TRANSBOOT\r
+ ...\r
+ RET\r
+\r
+; Error return - set carry\r
+\r
+ERRET:\r
+ STC\r
+ RET\r
+\r
+BADSECTOR:\r
+ ...\r
+ RET\r
+\r
+\r
+WRTFAT:\r
+ ...\r
+\r
+WRTFATLOOP:\r
+ < Set up call to write out a fat to disk>\r
+ ...\r
+ MOV BX,[FATSPACE]\r
+\r
+ < Write out one fat to disk>\r
+ JC ERRET\r
+ ...\r
+ < Decrement fat counter >\r
+ JNZ WRTFATLOOP\r
+ CLC ;Good return\r
+ RET\r
+\r
+\r
+DONE:\r
+ ...\r
+ RET\r
+\r
+; Default Single sided\r
+FATID DB 0FEH\r
+\r
+HARDFLAG DB 0\r
+\r
+STARTSECTOR DW 9\r
+\r
+SWITCHLIST DB 5,"DCOVS" ; "OVS" must be the last\r
+ ; switches in the list\r
+\r
+FATSPACE DW FATBUF\r
+\r
+FREESPACE DW ENDBOOT\r
+\r
+BOOT DB BOOTSIZE DUP(?) ; Buffer for the\r
+ ; boot sector\r
+\r
+FATBUF DB 6 * 1024 DUP(?) ; Fat buffer\r
+ENDBOOT LABEL BYTE\r
+\r
+CODE ENDS\r
+ END \r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+TITLE GETSET - GETting and SETting MS-DOS system calls\r
+NAME GETSET\r
+;\r
+; System Calls which get and set various things\r
+;\r
+; $GET_VERSION\r
+; $GET_VERIFY_ON_WRITE\r
+; $SET_VERIFY_ON_WRITE\r
+; $SET_CTRL_C_TRAPPING\r
+; $INTERNATIONAL\r
+; $GET_DRIVE_FREESPACE\r
+; $GET_DMA\r
+; $SET_DMA\r
+; $GET_DEFAULT_DRIVE\r
+; $SET_DEFAULT_DRIVE\r
+; $GET_INTERRUPT_VECTOR\r
+; $SET_INTERRUPT_VECTOR\r
+; RECSET\r
+; $CHAR_OPER\r
+;\r
+.xlist\r
+;\r
+; get the appropriate segment definitions\r
+;\r
+INCLUDE DOSSEG.ASM\r
+\r
+IFNDEF ALTVECT\r
+ALTVECT EQU 0 ; FALSE\r
+ENDIF\r
+\r
+IFNDEF IBM\r
+IBM EQU 0\r
+ENDIF\r
+\r
+CODE SEGMENT BYTE PUBLIC 'CODE'\r
+ ASSUME SS:DOSGROUP,CS:DOSGROUP\r
+\r
+.xcref\r
+INCLUDE DOSSYM.ASM\r
+INCLUDE DEVSYM.ASM\r
+.cref\r
+.list\r
+\r
+\r
+ i_need VERFLG,BYTE\r
+ i_need CNTCFLAG,BYTE\r
+ i_need DMAADD,DWORD\r
+ i_need CURDRV,BYTE\r
+ i_need Current_Country,WORD\r
+ i_need international_table,BYTE\r
+ i_need INDOS,BYTE\r
+ i_need SYSINITVAR,WORD\r
+ i_need NUMIO,BYTE\r
+ i_need SWITCH_CHARACTER,BYTE\r
+ i_need DEVICE_AVAILABILITY,BYTE\r
+\r
+USERNUM DW ? ; 24 bit user number\r
+ DB ?\r
+ IF IBM\r
+OEMNUM DB 0 ; 8 bit OEM number\r
+ ELSE\r
+OEMNUM DB 0FFH ; 8 bit OEM number\r
+ ENDIF\r
+\r
+MSVERS EQU THIS WORD ; MS-DOS version in hex for $GET_VERSION\r
+MSMAJOR DB DOS_MAJOR_VERSION\r
+MSMINOR DB DOS_MINOR_VERSION\r
+\r
+\r
+BREAK <$Get_Version -- Return MSDOS version number>\r
+ procedure $GET_VERSION,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; None\r
+; Function:\r
+; Return MS-DOS version number\r
+; Outputs:\r
+; OEM number in BH\r
+; User number in BL:CX (24 bits)\r
+; Version number as AL.AH in binary\r
+; NOTE: On pre 1.28 DOSs AL will be zero\r
+\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ MOV BX,[USERNUM + 2]\r
+ MOV CX,[USERNUM]\r
+ MOV AX,[MSVERS]\r
+ invoke get_user_stack\r
+ASSUME DS:NOTHING\r
+ MOV [SI.user_BX],BX\r
+ MOV [SI.user_CX],CX\r
+ MOV [SI.user_AX],AX ; Really only sets AH\r
+ return\r
+$GET_VERSION ENDP\r
+\r
+BREAK <$International - return country-dependent information>\r
+;\r
+; Inputs:\r
+; DS:DX point to a block\r
+; Function:\r
+; give users an idea of what country the application is running\r
+; Outputs:\r
+; AX = number of bytes transferred\r
+; DS:DX ->+---------------------------------+\r
+; | WORD Date/time format |\r
+; +---------------------------------+\r
+; | BYTE ASCIZ currency symbol |\r
+; +---------------------------------+\r
+; | BYTE ASCIZ thousands separator |\r
+; +---------------------------------+\r
+; | BYTE ASCIZ decimal separator |\r
+; +---------------------------------+\r
+\r
+ procedure $INTERNATIONAL,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+ MOV BL,AL\r
+ PUSH DS\r
+ POP ES\r
+ PUSH DX\r
+ POP DI\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ CMP DI,-1\r
+ JZ international_set\r
+ OR BL,BL\r
+ JNZ international_find\r
+ MOV SI,[Current_Country]\r
+ MOV AX,WORD PTR [SI-2] ; Get size in AL, country code in AH\r
+ MOV BL,AH ; Set country code\r
+ JMP SHORT international_copy\r
+\r
+international_find:\r
+ CALL international_get\r
+ JNC international_copy\r
+ error country_not_found\r
+\r
+international_get:\r
+ MOV SI,OFFSET DOSGROUP:international_table\r
+international_next:\r
+ LODSW ; Get size in AL, country code in AH\r
+ CMP AL,-1\r
+ JNZ check_code\r
+ STC\r
+RET35:\r
+ RET\r
+\r
+check_code:\r
+ CMP BL,AH\r
+ JZ RET35 ; Carry clear\r
+ XOR AH,AH\r
+ ADD SI,AX\r
+ JMP international_next\r
+\r
+international_copy:\r
+ MOV CL,AL\r
+ XOR CH,CH\r
+ PUSH DI\r
+ REP MOVSB\r
+ POP DI\r
+ MOV WORD PTR ES:[DI.MAP_CALL + 2],CS ; Set segment for case map call\r
+international_ok:\r
+ XOR AX,AX\r
+ MOV AL,BL ; Return country code in AX\r
+ transfer SYS_RET_OK\r
+\r
+international_set:\r
+ CALL international_get\r
+ JNC international_store\r
+ error country_not_found\r
+\r
+international_store:\r
+ MOV [Current_Country],SI\r
+ JMP international_ok\r
+\r
+$INTERNATIONAL ENDP\r
+\r
+BREAK <$Get_Verify_on_Write - return verify-after-write flag>\r
+ procedure $GET_VERIFY_ON_WRITE,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; none.\r
+; Function:\r
+; returns flag\r
+; Returns:\r
+; AL = value of VERIFY flag\r
+\r
+ MOV AL,[VERFLG]\r
+ return\r
+$GET_VERIFY_ON_WRITE ENDP\r
+\r
+BREAK <$Set_Verify_on_Write - Toggle verify-after-write flag>\r
+ procedure $SET_VERIFY_ON_WRITE,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; AL = desired value of VERIFY flag\r
+; Function:\r
+; Sets flag\r
+; Returns:\r
+; None\r
+\r
+ AND AL,1\r
+ MOV [VERFLG],AL\r
+ return\r
+$SET_VERIFY_ON_WRITE ENDP\r
+\r
+BREAK <$Set_CTRL_C_Trapping -- En/Disable ^C check in dispatcher>\r
+ procedure $SET_CTRL_C_TRAPPING,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; AL = 0 read ^C status\r
+; AL = 1 Set ^C status, DL = 0/1 for ^C off/on\r
+; Function:\r
+; Enable disable ^C checking in dispatcher\r
+; Outputs:\r
+; If AL = 0 then DL = 0/1 for ^C off/on\r
+\r
+ OR AL,AL\r
+ JNZ CTRL_C_set\r
+ invoke get_user_stack\r
+ MOV AL,[CNTCFLAG]\r
+ MOV BYTE PTR [SI.user_DX],AL\r
+ return\r
+CTRL_C_set:\r
+ DEC AL\r
+ JNZ bad_val\r
+ AND DL,01h\r
+ MOV [CNTCFLAG],DL\r
+ return\r
+bad_val:\r
+ MOV AL,0FFH\r
+ return\r
+$SET_CTRL_C_TRAPPING ENDP\r
+\r
+BREAK <$Get_INDOS_Flag -- Return location of DOS critical-section flag>\r
+ procedure $GET_INDOS_FLAG,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; None\r
+; Function:\r
+; Returns location of DOS status for interrupt routines\r
+; Returns:\r
+; Flag location in ES:BX\r
+\r
+ invoke get_user_stack\r
+ MOV [SI.user_BX],OFFSET DOSGROUP:INDOS\r
+ MOV [SI.user_ES],SS\r
+ return\r
+$GET_INDOS_FLAG ENDP\r
+\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+; C A V E A T P R O G R A M M E R ;\r
+; ;\r
+ procedure $GET_IN_VARS,NEAR\r
+; Return a pointer to interesting DOS variables This call is version\r
+; dependent and is subject to change without notice in future versions.\r
+; Use at risk.\r
+ invoke get_user_stack\r
+ MOV [SI.user_BX],OFFSET DOSGROUP:SYSINITVAR\r
+ MOV [SI.user_ES],SS\r
+ return\r
+$GET_IN_VARS ENDP\r
+; ;\r
+; C A V E A T P R O G R A M M E R ;\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+\r
+BREAK <$Get_Drive_Freespace -- Return bytes of free disk space on a drive>\r
+ procedure $GET_DRIVE_FREESPACE,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DL = Drive number\r
+; Function:\r
+; Return number of free allocation units on drive\r
+; Outputs:\r
+; BX = Number of free allocation units\r
+; DX = Total Number of allocation units on disk\r
+; CX = Sector size\r
+; AX = Sectors per allocation unit\r
+; = -1 if bad drive specified\r
+; This call returns the same info in the same registers (except for FAT pointer)\r
+; as the old FAT pointer calls\r
+\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ MOV AL,DL\r
+ invoke GETTHISDRV\r
+ MOV AX,-1\r
+ JC BADFRDRIVE\r
+ invoke FATREAD\r
+ XOR DX,DX\r
+ MOV BX,2\r
+ MOV CX,ES:[BP.dpb_max_cluster]\r
+ DEC CX\r
+ PUSH CX ; Save Total\r
+SCANFREE:\r
+ invoke UNPACK\r
+ JNZ NOTFREECLUS\r
+ INC DX\r
+NOTFREECLUS:\r
+ INC BX\r
+ LOOP SCANFREE\r
+ POP BX ; Remember Total\r
+ MOV AL,ES:[BP.dpb_cluster_mask]\r
+ INC AL\r
+ XOR AH,AH\r
+ MOV CX,ES:[BP.dpb_sector_size]\r
+BADFRDRIVE:\r
+ invoke get_user_stack\r
+ASSUME DS:NOTHING\r
+ MOV [SI. user_CX],CX\r
+ MOV [SI.user_DX],BX\r
+ MOV [SI.user_BX],DX\r
+ MOV [SI.user_AX],AX\r
+ return\r
+\r
+$GET_DRIVE_FREESPACE ENDP\r
+\r
+BREAK <$Get_DMA, $Set_DMA -- Get/Set current DMA address>\r
+ procedure $GET_DMA,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; None\r
+; Function:\r
+; Get DISK TRANSFER ADDRESS\r
+; Returns:\r
+; ES:BX is current transfer address\r
+\r
+ MOV BX,WORD PTR [DMAADD]\r
+ MOV CX,WORD PTR [DMAADD+2]\r
+ invoke get_user_stack\r
+ MOV [SI.user_BX],BX\r
+ MOV [SI.user_ES],CX\r
+ return\r
+$GET_DMA ENDP\r
+\r
+ procedure $SET_DMA,NEAR ; System call 26\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DS:DX is desired new disk transfer address\r
+; Function:\r
+; Set DISK TRANSFER ADDRESS\r
+; Returns:\r
+; None\r
+\r
+ MOV WORD PTR [DMAADD],DX\r
+ MOV WORD PTR [DMAADD+2],DS\r
+ return\r
+$SET_DMA ENDP\r
+\r
+BREAK <$Get_Default_DPB,$Get_DPB -- Return pointer to DPB>\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+; C A V E A T P R O G R A M M E R ;\r
+; ;\r
+ procedure $GET_DEFAULT_DPB,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DL = Drive number (always default drive for call 31)\r
+; Function:\r
+; Return pointer to drive parameter table for default drive\r
+; Returns:\r
+; DS:BX points to the DPB\r
+; AL = 0 If OK, = -1 if bad drive (call 50 only)\r
+\r
+ MOV DL,0\r
+ entry $GET_DPB\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ MOV AL,DL\r
+ invoke GETTHISDRV\r
+ JC ISNODRV\r
+ invoke FATREAD\r
+ invoke get_user_stack\r
+ASSUME DS:NOTHING\r
+ MOV [SI.user_BX],BP\r
+ MOV [SI.user_DS],ES\r
+ XOR AL,AL\r
+ return\r
+\r
+ISNODRV:\r
+ MOV AL,-1\r
+ return\r
+$GET_Default_dpb ENDP\r
+; ;\r
+; C A V E A T P R O G R A M M E R ;\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+\r
+\r
+BREAK <$Get_Default_Drive, $Set_Default_Drive -- Set/Get default drive>\r
+ procedure $GET_DEFAULT_DRIVE,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; None\r
+; Function:\r
+; Return current drive number\r
+; Returns:\r
+; AL = drive number\r
+\r
+ MOV AL,[CURDRV]\r
+ return\r
+$GET_DEFAULT_DRIVE ENDP\r
+\r
+ procedure $SET_DEFAULT_DRIVE,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DL = Drive number for new default drive\r
+; Function:\r
+; Set the default drive\r
+; Returns:\r
+; AL = Number of drives, NO ERROR RETURN IF DRIVE NUMBER BAD\r
+\r
+ MOV AL,[NUMIO]\r
+ CMP DL,AL\r
+ JNB RET17\r
+ MOV [CURDRV],DL\r
+RET17: return\r
+$SET_DEFAULT_DRIVE ENDP\r
+\r
+\r
+BREAK <$Get_Interrupt_Vector - Get/Set interrupt vectors>\r
+ procedure $GET_INTERRUPT_VECTOR,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; AL = interrupt number\r
+; Function:\r
+; Get the interrupt vector\r
+; Returns:\r
+; ES:BX is current interrupt vector\r
+\r
+ CALL RECSET\r
+ LES BX,DWORD PTR ES:[BX]\r
+ invoke get_user_stack\r
+ MOV [SI.user_BX],BX\r
+ MOV [SI.user_ES],ES\r
+ return\r
+$GET_INTERRUPT_VECTOR ENDP\r
+\r
+ procedure $SET_INTERRUPT_VECTOR,NEAR ; System call 37\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; AL = interrupt number\r
+; DS:DX is desired new interrupt vector\r
+; Function:\r
+; Set the interrupt vector\r
+; Returns:\r
+; None\r
+\r
+ CALL RECSET\r
+ MOV ES:[BX],DX\r
+ MOV ES:[BX+2],DS\r
+ return\r
+$SET_INTERRUPT_VECTOR ENDP\r
+\r
+ IF ALTVECT\r
+VECIN: ; INPUT VECTORS\r
+ DB 22H ; Terminate\r
+ DB 23H ; ^C\r
+ DB 24H ; Hard error\r
+ DB 28H ; Spooler\r
+LSTVEC DB ? ; ALL OTHER\r
+\r
+VECOUT: ; GET MAPPED VECTOR\r
+ DB int_terminate\r
+ DB int_ctrl_c\r
+ DB int_fatal_abort\r
+ DB int_spooler\r
+LSTVEC2 DB ? ; Map to itself\r
+\r
+NUMVEC = VECOUT-VECIN\r
+ ENDIF\r
+\r
+procedure RECSET,NEAR\r
+\r
+ IF ALTVECT\r
+ PUSH SS\r
+ POP ES\r
+ MOV [LSTVEC],AL ; Terminate list with real vector\r
+ MOV [LSTVEC2],AL ; Terminate list with real vector\r
+ MOV CX,NUMVEC ; Number of possible translations\r
+ MOV DI,OFFSET DOSGROUP:VECIN ; Point to vectors\r
+ REPNE SCASB\r
+ MOV AL,ES:[DI+NUMVEC-1] ; Get translation\r
+ ENDIF\r
+\r
+ XOR BX,BX\r
+ MOV ES,BX\r
+ MOV BL,AL\r
+ SHL BX,1\r
+ SHL BX,1\r
+ return\r
+recset ENDP\r
+\r
+BREAK <$Char_Oper - hack on paths, switches so that xenix can look like PCDOS>\r
+;\r
+; input: AL = function:\r
+; 0 - read switch char\r
+; 1 - set switch char (char in DL)\r
+; 2 - read device availability\r
+; 3 - set device availability (0/FF in DL)\r
+; DL = 0 means /DEV/ must preceed device names\r
+; DL = Non0 means /DEV/ need not preeceed\r
+; output: (get) DL - character/flag\r
+;\r
+ procedure $CHAR_OPER,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ OR AL,AL\r
+ JNZ char_oper_set_switch\r
+ MOV DL,[switch_character]\r
+ JMP SHORT char_oper_ret\r
+char_oper_set_switch:\r
+ DEC AL\r
+ JNZ char_oper_read_avail\r
+ MOV [switch_character],DL\r
+ return\r
+char_oper_read_avail:\r
+ DEC AL\r
+ JNZ char_oper_set_avail\r
+ MOV DL,[device_availability]\r
+ JMP SHORT char_oper_ret\r
+char_oper_set_avail:\r
+ DEC AL\r
+ JNZ char_oper_bad_ret\r
+ MOV [device_availability],DL\r
+ return\r
+char_oper_bad_ret:\r
+ MOV AL,0FFh\r
+ return\r
+char_oper_ret:\r
+ invoke get_user_stack\r
+ MOV [SI.user_DX],DX\r
+ return\r
+$CHAR_OPER ENDP\r
+\r
+BREAK <$SetDPB - Create a valid DPB from a user-specified BPB>\r
+ procedure $SETDPB,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; ES:BP Points to DPB\r
+; DS:SI Points to BPB\r
+; Function:\r
+; Build a correct DPB from the BPB\r
+; Outputs:\r
+; ES:BP and DS preserved all others destroyed\r
+\r
+ MOV DI,BP\r
+ ADD DI,2 ; Skip over dpb_drive and dpb_UNIT\r
+ LODSW\r
+ STOSW ; dpb_sector_size\r
+ MOV DX,AX\r
+ LODSB\r
+ DEC AL\r
+ STOSB ; dpb_cluster_mask\r
+ INC AL\r
+ XOR AH,AH\r
+LOG2LOOP:\r
+ TEST AL,1\r
+ JNZ SAVLOG\r
+ INC AH\r
+ SHR AL,1\r
+ JMP SHORT LOG2LOOP\r
+SAVLOG:\r
+ MOV AL,AH\r
+ STOSB ; dpb_cluster_shift\r
+ MOV BL,AL\r
+ MOVSW ; dpb_first_FAT Start of FAT (# of reserved sectors)\r
+ LODSB\r
+ STOSB ; dpb_FAT_count Number of FATs\r
+ MOV BH,AL\r
+ LODSW\r
+ STOSW ; dpb_root_entries Number of directory entries\r
+ MOV CL,5\r
+ SHR DX,CL ; Directory entries per sector\r
+ DEC AX\r
+ ADD AX,DX ; Cause Round Up\r
+ MOV CX,DX\r
+ XOR DX,DX\r
+ DIV CX\r
+ MOV CX,AX ; Number of directory sectors\r
+ INC DI\r
+ INC DI ; Skip dpb_first_sector\r
+ MOVSW ; Total number of sectors in DSKSIZ (temp as dpb_max_cluster)\r
+ LODSB\r
+ MOV ES:[BP.dpb_media],AL ; Media byte\r
+ LODSW ; Number of sectors in a FAT\r
+ STOSB ; dpb_FAT_size\r
+ MUL BH ; Space occupied by all FATs\r
+ ADD AX,ES:[BP.dpb_first_FAT]\r
+ STOSW ; dpb_dir_sector\r
+ ADD AX,CX ; Add number of directory sectors\r
+ MOV ES:[BP.dpb_first_sector],AX\r
+ SUB AX,ES:[BP.DSKSIZ]\r
+ NEG AX ; Sectors in data area\r
+ MOV CL,BL ; dpb_cluster_shift\r
+ SHR AX,CL ; Div by sectors/cluster\r
+ INC AX\r
+ MOV ES:[BP.dpb_max_cluster],AX\r
+ MOV ES:[BP.dpb_current_dir],0 ; Current directory is root\r
+ return\r
+$SETDPB ENDP\r
+; ;\r
+; C A V E A T P R O G R A M M E R ;\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+\r
+ do_ext\r
+\r
+CODE ENDS\r
+ END\r
+\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+ TITLE HRDDRV.SYS for the ALTOS ACS-86C.\r
+\r
+; Hard Disk Drive for Version 2.x of MSDOS.\r
+\r
+; Constants for commands in Altos ROM.\r
+\r
+ROM_CONSTA EQU 01 ;Return status AL of console selected in CX.\r
+ROM_CONIN EQU 02 ;Get char. from console in CX to AL\r
+ROM_CONOUT EQU 03 ;Write char. in DL to console in CX.\r
+ROM_PMSG EQU 07 ;Write string ES:DX to console in CX.\r
+ROM_DISKIO EQU 08 ;Perform disk I/O from IOPB in ES:CX.\r
+ROM_INIT EQU 10 ;Returns boot console and top memory ES:DX.\r
+\r
+\r
+CODE SEGMENT\r
+ASSUME CS:CODE,DS:CODE,ES:CODE,SS:CODE\r
+\r
+ ORG 0 ;Starts at an offset of zero.\r
+\r
+ PAGE\r
+ SUBTTL Device driver tables.\r
+\r
+;-----------------------------------------------+\r
+; DWORD pointer to next device | 1 word offset.\r
+; (-1,-1 if last device) | 1 word segement.\r
+;-----------------------------------------------+\r
+; Device attribute WORD ; 1 word.\r
+; Bit 15 = 1 for chacter devices. ;\r
+; 0 for Block devices. ;\r
+; ;\r
+; Charcter devices. (Bit 15=1) ;\r
+; Bit 0 = 1 current sti device. ;\r
+; Bit 1 = 1 current sto device. ;\r
+; Bit 2 = 1 current NUL device. ;\r
+; Bit 3 = 1 current Clock device. ;\r
+; ;\r
+; Bit 13 = 1 for non IBM machines. ;\r
+; 0 for IBM machines only. ;\r
+; Bit 14 = 1 IOCTL control bit. ;\r
+;-----------------------------------------------+\r
+; Device strategy pointer. ; 1 word offset.\r
+;-----------------------------------------------+\r
+; Device interrupt pointer. ; 1 word offset.\r
+;-----------------------------------------------+\r
+; Device name field. ; 8 bytes.\r
+; Character devices are any valid name ;\r
+; left justified, in a space filled ;\r
+; field. ;\r
+; Block devices contain # of units in ;\r
+; the first byte. ;\r
+;-----------------------------------------------+\r
+\r
+DSKDEV: ;Header for hard disk driver.\r
+ DW -1,-1 ;Last device\r
+ DW 2000H ;Is a block device\r
+ DW STRATEGY\r
+ DW DSK_INT\r
+MEMMAX DB 1 ;Number of Units\r
+\r
+ PAGE\r
+ SUBTTL Dispatch tables for each device.\r
+\r
+DSK_TBL:DW DSK_INI ;0 - Initialize Driver.\r
+ DW MEDIAC ;1 - Return current media code.\r
+ DW GET_BPB ;2 - Get Bios Parameter Block.\r
+ DW CMDERR ;3 - Reserved. (currently returns error)\r
+ DW DSK_RED ;4 - Block read.\r
+ DW BUS_EXIT ;5 - (Not used, return busy flag)\r
+ DW EXIT ;6 - Return status. (Not used)\r
+ DW EXIT ;7 - Flush input buffer. (Not used.)\r
+ DW DSK_WRT ;8 - Block write.\r
+ DW DSK_WRV ;9 - Block write with verify.\r
+ DW EXIT ;10 - Return output status.\r
+ DW EXIT ;11 - Flush output buffer. (Not used.)\r
+ DW EXIT ;12 - IO Control.\r
+\r
+ PAGE\r
+ SUBTTL Strategy and Software Interrupt routines.\r
+\r
+;Define offsets for io data packet\r
+\r
+IODAT STRUC\r
+CMDLEN DB ? ;LENGTH OF THIS COMMAND\r
+UNIT DB ? ;SUB UNIT SPECIFIER\r
+CMD DB ? ;COMMAND CODE\r
+STATUS DW ? ;STATUS\r
+ DB 8 DUP (?)\r
+MEDIA DB ? ;MEDIA DESCRIPTOR\r
+TRANS DD ? ;TRANSFER ADDRESS\r
+COUNT DW ? ;COUNT OF BLOCKS OR CHARACTERS\r
+START DW ? ;FIRST BLOCK TO TRANSFER\r
+IODAT ENDS\r
+\r
+PTRSAV DD 0 ;Strategy pointer save.\r
+\r
+;\r
+; Simplistic Strategy routine for non-multi-Tasking system.\r
+;\r
+; Currently just saves I/O packet pointers in PTRSAV for\r
+; later processing by the individual interrupt routines.\r
+;\r
+\r
+STRATP PROC FAR\r
+\r
+STRATEGY:\r
+ MOV WORD PTR CS:[PTRSAV],BX\r
+ MOV WORD PTR CS:[PTRSAV+2],ES\r
+ RET\r
+\r
+STRATP ENDP\r
+\r
+\r
+;\r
+; Ram memory driver interrupt routine for processing I/O packets.\r
+;\r
+\r
+DSK_INT:\r
+ PUSH SI ;Save SI from caller.\r
+ MOV SI,OFFSET DSK_TBL\r
+\r
+;\r
+; Common program for handling the simplistic I/O packet\r
+; processing scheme in MSDOS 2.0\r
+;\r
+\r
+ENTRY: PUSH AX ;Save all nessacary registers.\r
+ PUSH CX\r
+ PUSH DX\r
+ PUSH DI\r
+ PUSH BP\r
+ PUSH DS\r
+ PUSH ES\r
+ PUSH BX\r
+\r
+ LDS BX,CS:[PTRSAV] ;Retrieve pointer to I/O Packet.\r
+\r
+ MOV AL,[BX.UNIT] ;AL = Unit code.\r
+ MOV AH,[BX.MEDIA] ;AH = Media descriptor.\r
+ MOV CX,[BX.COUNT] ;CX = Contains byte/sector count.\r
+ MOV DX,[BX.START] ;DX = Starting Logical sector.\r
+ XCHG DI,AX ;Save Unit and Media Temporarily.\r
+ MOV AL,[BX.CMD] ;Retrieve Command type. (1 => 11)\r
+ XOR AH,AH ;Clear upper half of AX for calculation.\r
+ ADD SI,AX ;Compute entry pointer in dispatch table.\r
+ ADD SI,AX\r
+ CMP AL,11 ;Verify that not more than 11 commands.\r
+ JA CMDERR ;Ah, well, error out.\r
+ XCHG AX,DI\r
+ LES DI,[BX.TRANS] ;DI contains addess of Transfer address.\r
+ ;ES contains segment.\r
+ PUSH CS\r
+ POP DS ;Data segment same as Code segment.\r
+ JMP [SI] ;Perform I/O packet command.\r
+\r
+ PAGE\r
+ SUBTTL Common error and exit points.\r
+\r
+BUS_EXIT: ;Device busy exit.\r
+ MOV AH,00000011B ;Set busy and done bits.\r
+ JMP SHORT EXIT1\r
+\r
+CMDERR: MOV AL,3 ;Set unknown command error #.\r
+\r
+;\r
+; Common error processing routine.\r
+; AL contains actual error code.\r
+;\r
+; Error # 0 = Write Protect violation.\r
+; 1 = Unkown unit.\r
+; 2 = Drive not ready.\r
+; 3 = Unknown command in I/O packet.\r
+; 4 = CRC error.\r
+; 5 = Bad drive request structure length.\r
+; 6 = Seek error.\r
+; 7 = Unknown media discovered.\r
+; 8 = Sector not found.\r
+; 9 = Printer out of paper.\r
+; 10 = Write fault.\r
+; 11 = Read fault.\r
+; 12 = General failure.\r
+;\r
+\r
+ERR_EXIT:\r
+ MOV AH,10000001B ;Set error and done bits.\r
+ STC ;Set carry bit also.\r
+ JMP SHORT EXIT1 ;Quick way out.\r
+\r
+EXITP PROC FAR ;Normal exit for device drivers.\r
+\r
+EXIT: MOV AH,00000001B ;Set done bit for MSDOS.\r
+EXIT1: LDS BX,CS:[PTRSAV]\r
+ MOV [BX.STATUS],AX ;Save operation compete and status.\r
+\r
+ POP BX ;Restore registers.\r
+ POP ES\r
+ POP DS\r
+ POP BP\r
+ POP DI\r
+ POP DX\r
+ POP CX\r
+ POP AX\r
+ POP SI\r
+ RET ;RESTORE REGS AND RETURN\r
+EXITP ENDP\r
+\r
+ PAGE\r
+\r
+ subttl Hard Disk drive control.\r
+\r
+;\r
+; Read command = 09 hex.\r
+; Write command = 02 hex.\r
+; Seek command = 10 hex.\r
+; Recal command = 20 hex.\r
+; Rezero command = 40 hex.\r
+; Reset command = 80 hex.\r
+;\r
+; Busy = 01 hex.\r
+; Operation Complete = 02 hex.\r
+; Bad Sector = 04 hex.\r
+; Record Not found = 08 hex.\r
+; CRC error = 10 hex.\r
+; (not used) = 20 hex.\r
+; Write fault = 40 hex.\r
+; Drive Ready = 80 hex.\r
+;\r
+\r
+hd_read equ 09h\r
+hd_writ equ 02h\r
+hd_wmsk equ 5dh\r
+hd_rmsk equ 9ch\r
+ page\r
+\r
+ SUBTTL Altos monitor ram and 8089 IOPB structures.\r
+\r
+;\r
+; Structure to reference 8089 and ROM command table.\r
+;\r
+\r
+SIOPB STRUC\r
+ DB 4 DUP (?) ;Monitor Use Only\r
+OPCODE DB ? ;I/O operation code.\r
+DRIVE DB ? ;Logical drive spec.\r
+TRACK DW ? ;Logical track number.\r
+HEAD DB ? ;Logical head number.\r
+SECTOR DB ? ;Logical sector to start with.\r
+SCOUNT DB ? ;Number of logical sectors in buffer.\r
+RETCODE DB ? ;Error code after masking.\r
+RETMASK DB ? ;Error mask.\r
+RETRIES DB ? ;Number of retries before error exit.\r
+DMAOFF DW ? ;Buffer offset address.\r
+DMASEG DW ? ;Buffer segment.\r
+SECLENG DW ? ;Sector Length.\r
+ DB 6 DUP (?) ;8089 use only.\r
+SIOPB ENDS\r
+\r
+IOPB SIOPB <,0,0,0,0,0,0,0,0,0,0,0,0,>\r
+\r
+ PAGE\r
+ SUBTTL Common Drive parameter block definitions on Altos.\r
+\r
+DBP STRUC\r
+\r
+JMPNEAR DB 3 DUP (?) ;Jmp Near xxxx for boot.\r
+NAMEVER DB 8 DUP (?) ;Name / Version of OS.\r
+\r
+;------- Start of Drive Parameter Block.\r
+\r
+SECSIZE DW ? ;Sector size in bytes. (dpb)\r
+ALLOC DB ? ;Number of sectors per alloc. block. (dpb)\r
+RESSEC DW ? ;Reserved sectors. (dpb)\r
+FATS DB ? ;Number of FAT's. (dpb)\r
+MAXDIR DW ? ;Number of root directory entries. (dpb)\r
+SECTORS DW ? ;Number of sectors per diskette. (dpb)\r
+MEDIAID DB ? ;Media byte ID. (dpb)\r
+FATSEC DW ? ;Number of FAT Sectors. (dpb)\r
+\r
+;------- End of Drive Parameter Block.\r
+\r
+SECTRK DW ? ;Number of Sectors per track.\r
+HEADS DW ? ;Number of heads per cylinder.\r
+HIDDEN DW ? ;Number of hidden sectors.\r
+\r
+DBP ENDS\r
+\r
+HDDRIVE DBP <,,512,4,0,2,256,4000,0F5H,3,12,4,0>\r
+\r
+\r
+INI_TAB DW OFFSET HDDRIVE.SECSIZE\r
+\r
+ PAGE\r
+ SUBTTL Media check routine\r
+\r
+;\r
+; Media check routine.\r
+; On entry:\r
+; AL = memory driver unit number.\r
+; AH = media byte\r
+; On exit:\r
+;\r
+; [MEDIA FLAG] = -1 (FF hex) if disk is changed.\r
+; [MEDIA FLAG] = 0 if don't know.\r
+; [MEDIA FLAG] = 1 if not changed.\r
+;\r
+\r
+MEDIAC: LDS BX,CS:[PTRSAV]\r
+ MOV BYTE PTR [BX.TRANS],1\r
+ JMP EXIT\r
+\r
+ PAGE\r
+ SUBTTL Build and return Bios Parameter Block for a diskette.\r
+\r
+;\r
+; Build Bios Parameter Blocks.\r
+;\r
+; On entry: ES:BX contains the address of a scratch sector buffer.\r
+; AL = Unit number.\r
+; AH = Current media byte.\r
+;\r
+; On exit: Return a DWORD pointer to the associated BPB\r
+; in the Request packet.\r
+;\r
+\r
+GET_BPB:\r
+ MOV SI,OFFSET HDDRIVE+11\r
+ LDS BX,CS:[PTRSAV]\r
+ MOV WORD PTR [BX.COUNT],SI\r
+ MOV WORD PTR [BX.COUNT+2],CS\r
+ JMP EXIT\r
+\r
+ PAGE\r
+ SUBTTL MSDOS 2.x Disk I/O drivers.\r
+\r
+;\r
+; Disk READ/WRITE functions.\r
+;\r
+; On entry:\r
+; AL = Disk I/O driver number\r
+; AH = Media byte.\r
+; ES = Disk transfer segment.\r
+; DI = Disk transfer offset in ES.\r
+; CX = Number of sectors to transfer\r
+; DX = Logical starting sector.\r
+;\r
+; On exit:\r
+; Normal exit through common exit routine.\r
+;\r
+; Abnormal exit through common error routine.\r
+;\r
+\r
+DSK_RED:\r
+ MOV AH,HD_READ\r
+ JMP SHORT DSK_COM\r
+DSK_WRV:\r
+DSK_WRT:\r
+ MOV AH,HD_WRIT\r
+DSK_COM:\r
+ MOV SI,OFFSET HDDRIVE ;Keeps code size down.\r
+ MOV [IOPB.DMASEG],ES\r
+ MOV [IOPB.DMAOFF],DI\r
+ MOV DI,[SI.SECSIZE]\r
+ MOV [IOPB.SECLENG],DI\r
+ MOV [IOPB.RETRIES],1\r
+ MOV [IOPB.RETMASK],05DH ;Error return mask.\r
+ MOV [IOPB.OPCODE],AH\r
+ MOV [IOPB.DRIVE],4 ;Drive 4 is only available.\r
+ ADD DX,[SI.HIDDEN] ;Account for invisible sectors.\r
+ MOV BP,CX ;Save number of sectors to R/W\r
+DSK_IO1:\r
+ PUSH DX ;Save starting sector.\r
+ MOV AX,DX\r
+ MOV DX,0 ;32 bit divide coming up.\r
+ MOV CX,[SI.SECTRK]\r
+ DIV CX ;Get track+head and start sector.\r
+ MOV [IOPB.SECTOR],DL ;Starting sector.\r
+ MOV BL,DL ;Save starting sector for later.\r
+ MOV DX,0\r
+ MOV CX,[SI.HEADS]\r
+ DIV CX ;Compute head we are on.\r
+ MOV [IOPB.HEAD],DL\r
+ MOV [IOPB.TRACK],AX ;Track to read/write.\r
+ MOV AX,[SI.SECTRK] ;Now see how many sectors\r
+ INC AL ; we can burst read.\r
+ SUB AL,BL ;BL is the starting sector.\r
+ MOV AH,0\r
+ POP DX ;Retrieve logical sector start.\r
+ CMP AX,BP ;See if on last partial track+head.\r
+ JG DSK_IO2 ;Yes, on last track+head.\r
+ SUB BP,AX ;No, update number of sectors left.\r
+ ADD DX,AX ;Update next starting sector.\r
+ JMP SHORT DSK_IO3\r
+DSK_IO2:MOV AX,BP ;Only read enough of sector\r
+ MOV BP,0 ;to finish buffer and clear # left.\r
+DSK_IO3:MOV [IOPB.SCOUNT],AL\r
+ MOV DI,AX ;Save number sectors for later.\r
+ MOV BX,ROM_DISKIO\r
+ MOV CX,OFFSET IOPB\r
+ PUSH CS\r
+ POP ES\r
+ CALL ROM_CALL ;Do disk operation.\r
+ MOV AL,[IOPB.RETCODE] ;Get error code.\r
+ OR AL,AL\r
+ JNZ DERROR\r
+ MOV AX,DI ;Retrieve number of sectors read.\r
+ MOV CX,[SI.SECSIZE] ;Number of bytes per sector.\r
+ PUSH DX\r
+ MUL CX\r
+ POP DX\r
+ TEST AL,0FH ;Make sure no strange sizes.\r
+ JNZ SERR1\r
+ MOV CL,4\r
+ SHR AX,CL ;Convert number of bytes to para.\r
+ ADD AX,[IOPB.DMASEG]\r
+ MOV [IOPB.DMASEG],AX\r
+ OR BP,BP\r
+ JNZ DSK_IO1 ;Still more to do.\r
+ MOV AL,0\r
+ JMP EXIT ;All done.\r
+SERR1: MOV AL,12\r
+ JMP ERR_EXIT\r
+\r
+ PAGE\r
+ SUBTTL Disk Error processing.\r
+\r
+;\r
+; Disk error routine.\r
+;\r
+\r
+DERROR:\r
+ LDS BX,CS:[PTRSAV]\r
+ MOV [BX.COUNT],0\r
+ PUSH CS\r
+ POP DS\r
+\r
+ MOV BL,-1\r
+ MOV AH,AL\r
+ MOV BH,14 ;Lenght of table.\r
+ MOV SI,OFFSET DERRTAB\r
+DERROR2:INC BL ;Increment to next error code.\r
+ LODS BYTE PTR CS:[SI]\r
+ CMP AH,AL ;See if error code matches disk status.\r
+ JZ DERROR3 ;Got the right error, exit.\r
+ DEC BH\r
+ JNZ DERROR2 ;Keep checking table.\r
+ MOV BL,12 ;Set general type of error.\r
+DERROR3:MOV AL,BL ;Now we've got the code.\r
+ JMP ERR_EXIT\r
+\r
+DERRTAB DB 00H ; 0. Write protect error\r
+ DB 00H ; 1. Unknown unit.\r
+ DB 00H ; 2. Not ready error.\r
+ DB 00H ; 3. Unknown command.\r
+ DB 10H ; 4. CRC error\r
+ DB 00H ; 5. Bad drive request.\r
+ DB 00H ; 6. Seek error\r
+ DB 00H ; 7. Unknown media.\r
+ DB 08H ; 8. Sector not found\r
+ DB 00H ; 9. (Not used.)\r
+ DB 40H ;10. Write fault.\r
+ DB 04H ;11. Read fault.\r
+ DB 01H ;12. General type of failure.\r
+\r
+ PAGE\r
+ SUBTTL Common ROM call routine.\r
+\r
+;\r
+; Save all registers except CX, BX and AX.\r
+\r
+ROMRTN DD 0FE000000H ;Main ROM entry point.\r
+\r
+ROM_CALL:\r
+ PUSH DI\r
+ PUSH SI\r
+ PUSH BP\r
+ PUSH DX\r
+ PUSH ES\r
+ CALL CS:DWORD PTR [ROMRTN]\r
+ POP ES\r
+ POP DX\r
+ POP BP\r
+ POP SI\r
+ POP DI\r
+ RET\r
+\r
+\r
+ PAGE\r
+ SUBTTL Hard Disk Drive initalization routine.\r
+\r
+DSK_INI:\r
+ LDS BX,CS:[PTRSAV]\r
+ MOV BYTE PTR [BX.MEDIA],1\r
+ MOV WORD PTR [BX.TRANS],OFFSET DSK_INI\r
+ MOV WORD PTR [BX.TRANS+2],CS\r
+ MOV WORD PTR [BX.COUNT],OFFSET INI_TAB\r
+ MOV WORD PTR [BX.COUNT+2],CS\r
+ JMP EXIT\r
+\r
+CODE ENDS\r
+\r
+ END\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+;*************************************
+; 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
--- /dev/null
+TITLE COMMAND Initialization\r
+\r
+ INCLUDE COMSW.ASM\r
+\r
+.xlist\r
+.xcref\r
+ INCLUDE DOSSYM.ASM\r
+ INCLUDE DEVSYM.ASM\r
+ INCLUDE COMSEG.ASM\r
+.list\r
+.cref\r
+\r
+ INCLUDE COMEQU.ASM\r
+\r
+ENVIRONSIZ EQU 0A0H ;Must agree with values in EVIRONMENT segment\r
+ENVIRONSIZ2 EQU 092H\r
+\r
+CODERES SEGMENT PUBLIC\r
+ EXTRN RSTACK:WORD,SETVECT:NEAR,LODCOM:NEAR,CONTC:NEAR,INT_2E:NEAR\r
+ EXTRN LOADCOM:NEAR,CHKSUM:NEAR\r
+\r
+ IF IBMVER\r
+ EXTRN EXECHK:NEAR,SYSCALL:NEAR\r
+ ENDIF\r
+\r
+CODERES ENDS\r
+\r
+DATARES SEGMENT PUBLIC\r
+ EXTRN DATARESEND:BYTE,LTPA:WORD,MYSEG:WORD,MYSEG1:WORD,MYSEG2:WORD\r
+ EXTRN MEMSIZ:WORD,TRNSEG:WORD,ENVIRSEG:WORD,RSWITCHAR:BYTE\r
+ EXTRN COMDRV:BYTE,COMLET:BYTE,PERMCOM:BYTE,SINGLECOM:WORD\r
+ EXTRN PARENT:WORD,IO_SAVE:WORD,COM_PTR:DWORD,COM_FCB1:DWORD\r
+ EXTRN COM_FCB2:DWORD,SUM:WORD,BATCH:WORD,COMSPEC:BYTE\r
+\r
+ IF IBMVER\r
+ EXTRN SYS_CALL:DWORD,EXESEG:WORD,EXESUM:WORD\r
+ ENDIF\r
+\r
+DATARES ENDS\r
+\r
+ENVIRONMENT SEGMENT PUBLIC\r
+ EXTRN ENVIREND:BYTE,PATHSTRING:BYTE,ECOMSPEC:BYTE\r
+ENVIRONMENT ENDS\r
+\r
+TRANCODE SEGMENT PUBLIC\r
+ EXTRN DATINIT:FAR\r
+TRANCODE ENDS\r
+\r
+TRANSPACE SEGMENT PUBLIC\r
+ EXTRN TRANSPACEEND:BYTE\r
+TRANSPACE ENDS\r
+\r
+ZEXEC_DATA SEGMENT PUBLIC\r
+ IF IBM\r
+ EXTRN ZEXECDATAEND:BYTE\r
+ ENDIF\r
+ZEXEC_DATA ENDS\r
+\r
+; *******************************************************************\r
+; START OF INIT PORTION\r
+; This code is overlayed the first time the TPA is used.\r
+\r
+INIT SEGMENT PUBLIC PARA\r
+\r
+ EXTRN HEADER:BYTE\r
+ EXTRN BADCOMLKMES:BYTE\r
+\r
+ PUBLIC CONPROC\r
+\r
+ASSUME CS:RESGROUP,DS:RESGROUP,ES:RESGROUP,SS:RESGROUP\r
+\r
+ ORG 0\r
+ZERO = $\r
+\r
+CONPROC:\r
+ MOV SP,OFFSET RESGROUP:RSTACK\r
+\r
+ IF HIGHMEM\r
+ MOV BX,WORD PTR DS:[PDB_block_len]\r
+ MOV AX,OFFSET RESGROUP:ENVIREND + 15\r
+ MOV CL,4\r
+ SHR AX,CL\r
+ PUSH AX ; Save size to alloc\r
+ INC AX ; Plus one for arena\r
+ SUB BX,AX ; Subtract size of resident\r
+ MOV WORD PTR DS:[PDB_block_len],BX\r
+ MOV AX,CS\r
+ SUB BX,AX\r
+ MOV AH,SETBLOCK\r
+ INT 21H\r
+ POP BX ; Get back size to alloc\r
+ MOV AH,ALLOC\r
+ INT 21H\r
+ MOV [REALRES],AX\r
+ MOV ES,AX\r
+ XOR SI,SI\r
+ MOV DI,SI\r
+ MOV CX,OFFSET RESGROUP:ENVIREND\r
+ SHR CX,1 ; Length of resident and environment in words\r
+ ; Last byte doesn't matter\r
+ REP MOVSW ; Move to end of memory\r
+ MOV DS,AX\r
+ MOV BX,AX\r
+ MOV AH,SET_CURRENT_PDB\r
+ INT 21H\r
+ MOV AX,BX\r
+ MOV BX,OFFSET RESGROUP:DATARESEND + 15\r
+ MOV CL,4\r
+ SHR BX,CL ; BX is size for SETBLOCK\r
+ MOV WORD PTR DS:[PDB_block_len],BX\r
+ ADD WORD PTR DS:[PDB_block_len],AX\r
+ MOV [LTPA],CS\r
+ MOV AH,SETBLOCK\r
+ INT 21H ;Shrink to not include environment\r
+ MOV BX,(ENVIRONSIZ + 15) / 16\r
+ MOV AH,ALLOC\r
+ INT 21H ;Allocate the environment\r
+ MOV [ENVIRSEG],AX\r
+ MOV CS:[ENVIRSEGSAV],AX\r
+ MOV ES,AX\r
+ASSUME ES:ENVIRONMENT\r
+ XOR DI,DI\r
+ MOV SI,OFFSET RESGROUP:PATHSTRING\r
+ MOV CX,ENVIRONSIZ\r
+ REP MOVSB\r
+ MOV AX,WORD PTR CS:[PDB_block_len]\r
+ ENDIF\r
+\r
+ IF NOT HIGHMEM\r
+ MOV AX,OFFSET RESGROUP:ENVIREND + 15\r
+ MOV CL,4\r
+ SHR AX,CL\r
+ MOV CX,CS\r
+ ADD AX,CX ; Compute segment of TPA\r
+ MOV [LTPA],AX ; Good enough for the moment\r
+ MOV AX,WORD PTR DS:[PDB_block_len]\r
+ ENDIF\r
+\r
+ MOV [MYSEG1],DS\r
+ MOV [MYSEG2],DS\r
+ MOV [MYSEG],DS\r
+ MOV [MEMSIZ],AX\r
+\r
+ MOV DX,OFFSET TRANGROUP:TRANSPACEEND + 15\r
+ MOV CL,4\r
+ SHR DX,CL\r
+\r
+ IF IBM\r
+ PUSH DX\r
+ MOV DX,OFFSET EGROUP:ZEXECDATAEND + 15\r
+ MOV CL,4\r
+ SHR DX,CL\r
+ POP CX\r
+ ADD DX,CX\r
+ ENDIF\r
+\r
+ SUB AX,DX\r
+ MOV [TRNSEG],AX ; Read it in here\r
+ MOV AX,DS:[PDB_environ]\r
+ OR AX,AX\r
+ JZ BUILDENV ; Need to make an environment\r
+\r
+ IF HIGHMEM\r
+ INC BYTE PTR CS:[CHUCKENV] ; Flag no ENVIRONSEG\r
+ ELSE\r
+ INC BYTE PTR [CHUCKENV] ; Flag no ENVIRONSEG\r
+ ENDIF\r
+\r
+ JMP SHORT ENVIRONPASSED\r
+\r
+BUILDENV:\r
+\r
+ IF NOT HIGHMEM\r
+ MOV AX,OFFSET RESGROUP:PATHSTRING ; Figure environment pointer\r
+ MOV CL,4\r
+ SHR AX,CL\r
+ MOV DX,DS\r
+ ADD AX,DX\r
+ ELSE\r
+ JMP SHORT GOTTHEENVIR\r
+ ENDIF\r
+\r
+ENVIRONPASSED:\r
+ MOV [ENVIRSEG],AX\r
+\r
+ IF HIGHMEM\r
+ DEC AX\r
+ MOV ES,AX\r
+ INC AX\r
+ MOV ES:[arena_owner],DS ; Adjust owner of passed envir\r
+ ENDIF\r
+\r
+ MOV ES,AX\r
+ASSUME ES:ENVIRONMENT\r
+\r
+GOTTHEENVIR:\r
+ MOV AX,CHAR_OPER SHL 8\r
+ INT int_command\r
+ MOV [RSWITCHAR],DL\r
+\r
+ CMP DL,'/'\r
+ JNZ IUSESLASH\r
+\r
+ IF HIGHMEM\r
+ MOV CS:[COMSPECT],'\'\r
+ ELSE\r
+ MOV [COMSPECT],'\'\r
+ ENDIF\r
+\r
+ IF HIGHMEM\r
+ CMP BYTE PTR CS:[CHUCKENV],0\r
+ ELSE\r
+ CMP BYTE PTR [CHUCKENV],0\r
+ ENDIF\r
+\r
+ JNZ IUSESLASH\r
+\r
+ MOV ES:[ECOMSPEC-10H],'\'\r
+IUSESLASH:\r
+\r
+IF IBMVER\r
+ PUSH ES\r
+ MOV AX,(Get_interrupt_vector SHL 8) + int_command\r
+ INT int_command\r
+ MOV WORD PTR [SYS_CALL],BX\r
+ MOV WORD PTR [SYS_CALL+2],ES\r
+ MOV DX,OFFSET RESGROUP:SYSCALL\r
+ MOV AX,(Set_interrupt_vector SHL 8) + int_command\r
+ INT int_command\r
+ POP ES\r
+ENDIF\r
+\r
+ MOV AL,BYTE PTR DS:[FCB] ; get drive spec for default\r
+ MOV AH,DRVCHAR\r
+ MOV [COMDRV],AL\r
+ ADD AL,40H ; Convert to letter\r
+ CMP AL,40H\r
+ JZ NOCOMDRV\r
+ STD\r
+ IF HIGHMEM\r
+ CMP BYTE PTR CS:[CHUCKENV],0\r
+ ELSE\r
+ CMP BYTE PTR [CHUCKENV],0\r
+ ENDIF\r
+\r
+ JNZ NOTWIDENV\r
+\r
+ PUSH DS\r
+ PUSH ES\r
+ POP DS\r
+ MOV DI,OFFSET ENVIRONMENT:ECOMSPEC + ENVIRONSIZ2 - 1 - 10H\r
+ MOV SI,OFFSET ENVIRONMENT:ECOMSPEC + ENVIRONSIZ2 - 3 - 10H\r
+ MOV CX,ENVIRONSIZ2 - 2\r
+ REP MOVSB\r
+\r
+ POP DS\r
+ MOV WORD PTR ES:[ECOMSPEC-10H],AX\r
+\r
+NOTWIDENV:\r
+ CLD\r
+ IF HIGHMEM\r
+ MOV WORD PTR CS:[AUTOBAT],AX\r
+ ELSE\r
+ MOV WORD PTR [AUTOBAT],AX\r
+ ENDIF\r
+\r
+ MOV [COMLET],AL\r
+NOCOMDRV:\r
+ CALL SETVECT ; Set the vectors\r
+\r
+ MOV SI,80H\r
+ LODSB\r
+ MOV CL,AL\r
+ XOR CH,CH\r
+ JCXZ COMRETURNSJ ; No parameters\r
+ MOV SI,81H ; Start of parms\r
+CHKARG:\r
+ LODSB\r
+ CMP AL,' '\r
+ JZ NEXTCH\r
+ CMP AL,9 ; Tab only other delimiter\r
+ JZ NEXTCH\r
+ CMP AL,[RSWITCHAR] ; Switch?\r
+ JNZ CHKOTHERARGS ; No\r
+ DEC CX\r
+ JCXZ ARGSDONEJ ; oops\r
+ LODSB\r
+ OR AL,20H ; Lower case\r
+ CMP AL,'p' ; PERMCOM switch\r
+ JNZ NEXTCH\r
+ JMP SETPERM\r
+\r
+NEXTCH:\r
+ CMP AL,'d'\r
+ JNZ NEXTCH3\r
+\r
+ IF HIGHMEM\r
+ MOV BYTE PTR CS:[PRDATTM],1 ; User explicitly says no date time\r
+ ELSE\r
+ MOV BYTE PTR [PRDATTM],1 ; User explicitly says no date time\r
+ ENDIF\r
+\r
+ LOOP CHKARG\r
+ JMP SHORT ARGSDONEJ\r
+NEXTCH3:\r
+ CMP AL,'c'\r
+ JNZ NEXTCH2 ; SINGLECOM switch 2\r
+ MOV [SINGLECOM],SI ; Point to the rest of the command line\r
+ MOV [PERMCOM],0 ; A SINGLECOM must not be a PERMCOM\r
+\r
+ IF HIGHMEM\r
+ MOV BYTE PTR CS:[PRDATTM],1 ; No date or time either, explicit\r
+ ELSE\r
+ MOV BYTE PTR [PRDATTM],1 ; No date or time either, explicit\r
+ ENDIF\r
+\r
+ARGSDONEJ:\r
+ JMP ARGSDONE\r
+\r
+NEXTCH2:\r
+ LOOP CHKARG\r
+\r
+COMRETURNSJ:\r
+ JMP COMRETURNS\r
+\r
+CHKOTHERARGS:\r
+ DEC SI\r
+ MOV DX,SI\r
+ PUSH CX\r
+ PUSH SI\r
+CONTRLOOP:\r
+ LODSB\r
+ DEC CX\r
+ CMP AL,' '\r
+ JZ SETCDEV\r
+ CMP AL,9\r
+ JZ SETCDEV\r
+ JCXZ SETCDEVA\r
+ JMP SHORT CONTRLOOP\r
+\r
+SETCDEVA:\r
+ INC SI\r
+SETCDEV:\r
+ MOV BYTE PTR [SI-1],0\r
+ MOV AX,(OPEN SHL 8) OR 2 ; Read and write\r
+ INT int_command\r
+ JC CHKSRCHSPEC ; Wasn't a file\r
+ MOV BX,AX\r
+ MOV AX,IOCTL SHL 8\r
+ INT int_command\r
+ TEST DL,80H\r
+ JNZ ISADEVICE\r
+ MOV AH,CLOSE ; Close initial handle, wasn't a device\r
+ INT int_command\r
+ JMP CHKSRCHSPEC\r
+\r
+ISADEVICE:\r
+ XOR DH,DH\r
+ OR DL,3 ; Make sure has CON attributes\r
+ MOV AX,(IOCTL SHL 8) OR 1\r
+ INT int_command\r
+ MOV DX,BX ; Save new handle\r
+ POP BX ; Throw away saved SI\r
+ POP BX ; Throw away saved CX\r
+ PUSH CX\r
+ MOV CX,3\r
+ XOR BX,BX\r
+RCCLLOOP: ; Close 0,1 and 2\r
+ MOV AH,CLOSE\r
+ INT int_command\r
+ INC BX\r
+ LOOP RCCLLOOP\r
+ MOV BX,DX ; New device handle\r
+ MOV AH,XDUP\r
+ INT int_command ; Dup to 0\r
+ MOV AH,XDUP\r
+ INT int_command ; Dup to 1\r
+ MOV AH,XDUP\r
+ INT int_command ; Dup to 2\r
+ MOV AH,CLOSE\r
+ INT int_command ; Close initial handle\r
+ POP CX\r
+ JCXZ ARGSDONEJ2\r
+ JMP CHKARG\r
+\r
+CHKSRCHSPEC: ; Not a device, so must be directory spec\r
+\r
+ IF HIGHMEM\r
+ MOV BYTE PTR CS:[CHUCKENV],0 ; If search specified -- no inheritance\r
+ MOV AX,CS:[ENVIRSEGSAV]\r
+ MOV [ENVIRSEG],AX\r
+ ELSE\r
+ MOV BYTE PTR [CHUCKENV],0 ; If search specified -- no inheritance\r
+ MOV AX,OFFSET RESGROUP:PATHSTRING ; Figure environment pointer\r
+ MOV CL,4\r
+ SHR AX,CL\r
+ MOV DX,DS\r
+ ADD AX,DX\r
+ MOV [ENVIRSEG],AX\r
+ ENDIF\r
+\r
+ MOV ES,AX\r
+ MOV BYTE PTR [SI-1],' '\r
+ POP SI ; Remember location\r
+ POP CX ; and count\r
+\r
+ IF HIGHMEM\r
+ MOV DI,CS:[ECOMLOC]\r
+ ELSE\r
+ MOV DI,[ECOMLOC]\r
+ ENDIF\r
+\r
+COMTRLOOP:\r
+ LODSB\r
+ DEC CX\r
+ CMP AL,' '\r
+ JZ SETCOMSR\r
+ CMP AL,9\r
+ JZ SETCOMSR\r
+ STOSB\r
+\r
+ IF KANJI\r
+ XOR AH,AH\r
+ ENDIF\r
+\r
+ JCXZ SETCOMSR\r
+\r
+ IF KANJI\r
+ CALL ITESTKANJ\r
+ JZ COMTRLOOP\r
+ DEC CX\r
+ MOVSB\r
+ INC AH\r
+ JCXZ SETCOMSR\r
+ ENDIF\r
+\r
+ JMP SHORT COMTRLOOP\r
+\r
+SETCOMSR:\r
+ PUSH SI\r
+ PUSH CX\r
+\r
+ PUSH DS\r
+\r
+ IF HIGHMEM\r
+ PUSH CS\r
+ POP DS\r
+ ENDIF\r
+\r
+ MOV SI,OFFSET RESGROUP:COMSPECT\r
+ MOV CX,14\r
+\r
+ MOV AL,ES:[DI-1]\r
+\r
+ IF KANJI\r
+ OR AH,AH\r
+ JNZ INOTROOT ; Last char was KANJI second byte, might be '\'\r
+ ENDIF\r
+\r
+ CALL PATHCHRCMPR\r
+ JNZ INOTROOT\r
+ INC SI ; Don't make a double /\r
+ DEC CX\r
+INOTROOT:\r
+ REP MOVSB\r
+\r
+ MOV DX,[ECOMLOC] ; Now lets make sure its good!\r
+ PUSH ES\r
+ POP DS\r
+\r
+ MOV AX,OPEN SHL 8\r
+ INT int_command ; Open COMMAND.COM\r
+ POP DS\r
+ JC SETCOMSRBAD ; No COMMAND.COM here\r
+ MOV BX,AX ; Handle\r
+ MOV AH,CLOSE\r
+ INT int_command ; Close COMMAND.COM\r
+SETCOMSRRET:\r
+ POP CX\r
+ POP SI\r
+ARGSDONEJ2:\r
+ JCXZ ARGSDONE\r
+ JMP CHKARG\r
+\r
+SETCOMSRBAD:\r
+\r
+ IF HIGHMEM\r
+ PUSH DS\r
+ PUSH CS\r
+ POP DS\r
+ ENDIF\r
+\r
+ MOV DX,OFFSET RESGROUP:BADCOMLKMES\r
+ MOV AH,STD_CON_STRING_OUTPUT\r
+ INT int_command\r
+ MOV SI,OFFSET RESGROUP:COMSPECT\r
+ MOV DI,[ECOMLOC]\r
+ MOV CX,14\r
+ REP MOVSB ; Get my default back\r
+\r
+ IF HIGHMEM\r
+ POP DS\r
+ ENDIF\r
+\r
+ JMP SHORT SETCOMSRRET\r
+\r
+CHKARGJ:\r
+ JMP CHKARG\r
+\r
+SETPERM:\r
+ INC [PERMCOM]\r
+\r
+ IF HIGHMEM\r
+ CMP BYTE PTR CS:[PRDATTM],-1\r
+ ELSE\r
+ CMP BYTE PTR [PRDATTM],-1\r
+ ENDIF\r
+\r
+ JNZ LOOPIT\r
+\r
+ IF HIGHMEM\r
+ MOV BYTE PTR CS:[PRDATTM],0 ; If not set explicit, set to prompt\r
+ ELSE\r
+ MOV BYTE PTR [PRDATTM],0 ; If not set explicit, set to prompt\r
+ ENDIF\r
+\r
+LOOPIT:\r
+ LOOP CHKARGJ\r
+ARGSDONE:\r
+ CMP [PERMCOM],0\r
+ JZ COMRETURNS\r
+ PUSH ES ; Save environment pointer\r
+ MOV AH,SET_CURRENT_PDB\r
+ MOV BX,DS\r
+ MOV ES,BX\r
+ INT int_command ; Current process is me\r
+ MOV DI,PDB_Exit ; Diddle the addresses in my header\r
+ MOV AX,OFFSET RESGROUP:LODCOM\r
+ STOSW\r
+ MOV AX,DS\r
+ STOSW\r
+ MOV AX,OFFSET RESGROUP:CONTC\r
+ STOSW\r
+ MOV AX,DS\r
+ STOSW\r
+ MOV WORD PTR DS:[PDB_Parent_PID],DS ; Parent is me forever\r
+ MOV DX,OFFSET RESGROUP:INT_2E\r
+ MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 02EH\r
+ INT int_command ;Set magic interrupt\r
+ POP ES ;Remember environment\r
+COMRETURNS:\r
+ MOV AX,WORD PTR DS:[PDB_Parent_PID]\r
+ MOV [PARENT],AX ; Save parent\r
+ MOV WORD PTR DS:[PDB_Parent_PID],DS ; Parent is me\r
+ MOV AX,WORD PTR DS:[PDB_JFN_Table]\r
+ MOV [IO_SAVE],AX ; Get the default stdin and out\r
+ MOV WORD PTR [COM_PTR+2],DS ; Set all these to resident\r
+ MOV WORD PTR [COM_FCB1+2],DS\r
+ MOV WORD PTR [COM_FCB2+2],DS\r
+ MOV DI,OFFSET RESGROUP:COMSPEC\r
+\r
+ IF HIGHMEM\r
+ MOV SI,CS:[ECOMLOC]\r
+ CMP BYTE PTR CS:[CHUCKENV],0\r
+ ELSE\r
+ MOV SI,[ECOMLOC]\r
+ CMP BYTE PTR [CHUCKENV],0\r
+ ENDIF\r
+\r
+ MOV AX,DS ; XCHG ES,DS\r
+ PUSH ES\r
+ POP DS\r
+ MOV ES,AX\r
+\r
+ JZ COPYCOMSP ; All set up for copy\r
+\r
+ PUSH CS\r
+ POP DS\r
+\r
+ MOV SI,OFFSET RESGROUP:COMSPSTRING\r
+ PUSH ES\r
+ PUSH DI\r
+ CALL IFINDE\r
+ MOV SI,DI\r
+ PUSH ES\r
+ POP DS\r
+ POP DI\r
+ POP ES\r
+ JNC COPYCOMSP\r
+COMSPECNOFND:\r
+\r
+ IF HIGHMEM\r
+ MOV DS,CS:[ENVIRSEG]\r
+ MOV SI,CS:[ECOMLOC]\r
+ ELSE\r
+ MOV SI,[ECOMLOC]\r
+ ADD SI,OFFSET RESGROUP:PATHSTRING\r
+ PUSH CS\r
+ POP DS\r
+ ENDIF\r
+\r
+COPYCOMSP:\r
+ LODSB\r
+ STOSB\r
+ OR AL,AL\r
+ JNZ COPYCOMSP\r
+\r
+ IF HIGHMEM\r
+ MOV DS,CS:[REALRES]\r
+ PUSH CS\r
+ POP ES\r
+ MOV AH,DEALLOC\r
+ INT 21H\r
+ CMP BYTE PTR CS:[CHUCKENV],0\r
+ JZ GOTENVIR ; Environment is ok\r
+ MOV ES,CS:[ENVIRSEGSAV]\r
+ MOV AH,DEALLOC\r
+ INT 21H\r
+ ELSE\r
+ PUSH CS\r
+ POP DS\r
+ MOV BX,OFFSET RESGROUP:DATARESEND + 15\r
+ MOV CL,4\r
+ SHR BX,CL\r
+ MOV AH,SETBLOCK\r
+ INT int_command ; Shrink me to the resident only\r
+ CMP BYTE PTR [CHUCKENV],0\r
+ JNZ GOTENVIR ; Environment was passed\r
+ MOV BX,(ENVIRONSIZ + 15) /16\r
+ MOV AH,ALLOC\r
+ INT int_command ; "ALLOCATE" the environment\r
+ MOV DS,[ENVIRSEG]\r
+ MOV [ENVIRSEG],AX\r
+ MOV ES,AX\r
+ XOR SI,SI\r
+ MOV DI,SI\r
+ MOV CX,ENVIRONSIZ\r
+ REP MOVSB\r
+ PUSH CS\r
+ POP DS\r
+ ENDIF\r
+\r
+GOTENVIR:\r
+ CALL LOADCOM ; Load the transient in the right place\r
+ CALL CHKSUM ; Compute the checksum\r
+ MOV [SUM],DX ; Save it\r
+IF IBM\r
+ MOV AX,[MEMSIZ]\r
+ MOV DX,OFFSET EGROUP:ZEXECDATAEND + 15\r
+ MOV CL,4\r
+ SHR DX,CL\r
+ SUB AX,DX\r
+ MOV [EXESEG],AX\r
+ CALL EXECHK\r
+ MOV [EXESUM],DX\r
+ENDIF\r
+ IF MSVER\r
+ CMP [SINGLECOM],0\r
+ JNZ NOPHEAD ; Don't print header if SINGLECOM\r
+ IF HIGHMEM\r
+ PUSH DS\r
+ PUSH CS\r
+ POP DS\r
+ ENDIF\r
+ MOV DX,OFFSET RESGROUP:HEADER\r
+ MOV AH,STD_CON_STRING_OUTPUT\r
+ INT int_command\r
+ IF HIGHMEM\r
+ POP DS\r
+ ENDIF\r
+NOPHEAD:\r
+ ENDIF\r
+\r
+ IF HIGHMEM\r
+ CMP BYTE PTR CS:[PRDATTM],0\r
+ ELSE\r
+ CMP BYTE PTR [PRDATTM],0\r
+ ENDIF\r
+\r
+ JNZ NODTTM ; Don't do AUTOEXEC or date time\r
+ MOV BX,3 ; 48 BYTES ENOUGH\r
+ MOV AH,ALLOC\r
+ INT int_command\r
+ JC DODTTM ; PRETEND NO BATCH\r
+ MOV [BATCH],AX\r
+ MOV ES,AX\r
+ XOR DI,DI\r
+\r
+ IF HIGHMEM\r
+ CMP BYTE PTR CS:[AUTOBAT],0\r
+ ELSE\r
+ CMP BYTE PTR [AUTOBAT],0\r
+ ENDIF\r
+\r
+ JNZ NOAUTSET\r
+ MOV AH,GET_DEFAULT_DRIVE\r
+ INT int_command\r
+ ADD AL,'A'\r
+\r
+ IF HIGHMEM\r
+ MOV CS:[AUTOBAT],AL\r
+ ELSE\r
+ MOV [AUTOBAT],AL\r
+ ENDIF\r
+\r
+NOAUTSET:\r
+\r
+ IF HIGHMEM\r
+ PUSH DS\r
+ PUSH CS\r
+ POP DS\r
+ ENDIF\r
+\r
+ MOV SI,OFFSET RESGROUP:AUTOBAT\r
+ MOV CX,8\r
+ REP MOVSW ; NAME\r
+ MOV AX,-1\r
+ MOV CL,10\r
+ REP STOSW ; PARMS\r
+ MOV DX,OFFSET RESGROUP:AUTOBAT\r
+ MOV AX,OPEN SHL 8\r
+ INT int_command ; See if AUTOEXEC.BAT exists\r
+ JC NOABAT\r
+ MOV BX,AX\r
+ MOV AH,CLOSE\r
+ INT int_command\r
+\r
+ IF HIGHMEM\r
+ POP DS\r
+ ENDIF\r
+\r
+ JMP SHORT DRV0\r
+\r
+NOABAT:\r
+\r
+ IF HIGHMEM\r
+ POP DS\r
+ ENDIF\r
+\r
+ MOV ES,[BATCH] ; Not found--turn off batch job\r
+ MOV AH,DEALLOC\r
+ INT int_command\r
+ MOV [BATCH],0 ; AFTER DEALLOC in case of ^C\r
+DODTTM:\r
+\r
+ IF HIGHMEM\r
+ MOV AX,OFFSET TRANGROUP:DATINIT\r
+ MOV WORD PTR CS:[INITADD],AX\r
+ MOV AX,[TRNSEG]\r
+ MOV WORD PTR CS:[INITADD+2],AX\r
+ CALL DWORD PTR CS:[INITADD]\r
+ ELSE\r
+ MOV AX,OFFSET TRANGROUP:DATINIT\r
+ MOV WORD PTR[INITADD],AX\r
+ MOV AX,[TRNSEG]\r
+ MOV WORD PTR[INITADD+2],AX\r
+ CALL DWORD PTR [INITADD]\r
+ ENDIF\r
+\r
+NODTTM:\r
+\r
+ IF IBMVER\r
+ CMP [SINGLECOM],0\r
+ JNZ DRV0 ; Don't print header if SINGLECOM\r
+ MOV DX,OFFSET RESGROUP:HEADER\r
+ MOV AH,STD_CON_STRING_OUTPUT\r
+ INT int_command\r
+ ENDIF\r
+\r
+DRV0:\r
+ IF HIGHMEM\r
+ PUSH DS\r
+ MOV AX,OFFSET RESGROUP:LODCOM\r
+ PUSH AX\r
+MQQ PROC FAR\r
+ RET\r
+MQQ ENDP\r
+ ELSE\r
+ JMP LODCOM ; Allocate the transient\r
+ ENDIF\r
+\r
+PATHCHRCMPR:\r
+ CMP [RSWITCHAR],'/'\r
+ JZ RNOSLASHT\r
+ CMP AL,'/'\r
+ JZ RET41\r
+RNOSLASHT:\r
+ CMP AL,'\'\r
+RET41:\r
+ RET\r
+\r
+\r
+IFINDE:\r
+ CALL IFIND ; FIND THE NAME\r
+ JC IFIND2 ; CARRY MEANS NOT FOUND\r
+ JMP ISCASB1 ; SCAN FOR = SIGN\r
+;\r
+; On return of FIND1, ES:DI points to beginning of name\r
+;\r
+IFIND:\r
+ CLD\r
+\r
+ CALL ICOUNT0 ; CX = LENGTH OF NAME\r
+\r
+ IF HIGHMEM\r
+ MOV ES,CS:[REALRES]\r
+ASSUME ES:RESGROUP\r
+ MOV ES,ES:[ENVIRSEG]\r
+ASSUME ES:NOTHING\r
+ ELSE\r
+ MOV ES,[ENVIRSEG]\r
+ ENDIF\r
+\r
+ XOR DI,DI\r
+IFIND1:\r
+ PUSH CX\r
+ PUSH SI\r
+ PUSH DI\r
+IFIND11:\r
+ LODSB\r
+\r
+ IF KANJI\r
+ CALL ITESTKANJ\r
+ JZ NOTKANJ4\r
+ DEC SI\r
+ LODSW\r
+ INC DI\r
+ INC DI\r
+ CMP AX,ES:[DI-2]\r
+ JNZ IFIND12\r
+ DEC CX\r
+ LOOP IFIND11\r
+ JMP SHORT IFIND12\r
+\r
+NOTKANJ4:\r
+ ENDIF\r
+\r
+ CALL IUPCONV\r
+ INC DI\r
+ CMP AL,ES:[DI-1]\r
+ JNZ IFIND12\r
+ LOOP IFIND11\r
+IFIND12:\r
+ POP DI\r
+ POP SI\r
+ POP CX\r
+ JZ IFIND2\r
+ PUSH CX\r
+ CALL ISCASB2 ; SCAN FOR A NUL\r
+ POP CX\r
+ CMP BYTE PTR ES:[DI],0\r
+ JNZ IFIND1\r
+ STC ; INDICATE NOT FOUND\r
+IFIND2:\r
+ RET\r
+\r
+ICOUNT0:\r
+ PUSH DS\r
+ POP ES\r
+ MOV DI,SI\r
+\r
+ PUSH DI ; COUNT NUMBER OF CHARS UNTIL "="\r
+ CALL ISCASB1\r
+ JMP SHORT ICOUNTX\r
+ PUSH DI ; COUNT NUMBER OF CHARS UNTIL NUL\r
+ CALL ISCASB2\r
+ICOUNTX:\r
+ POP CX\r
+ SUB DI,CX\r
+ XCHG DI,CX\r
+ RET\r
+\r
+ISCASB1:\r
+ MOV AL,"=" ; SCAN FOR AN =\r
+ JMP SHORT ISCASBX\r
+ISCASB2:\r
+ XOR AL,AL ; SCAN FOR A NUL\r
+ISCASBX:\r
+ MOV CX,100H\r
+ REPNZ SCASB\r
+ RET\r
+\r
+ IF KANJI\r
+ITESTKANJ:\r
+ CMP AL,81H\r
+ JB NOTLEAD\r
+ CMP AL,9FH\r
+ JBE ISLEAD\r
+ CMP AL,0E0H\r
+ JB NOTLEAD\r
+ CMP AL,0FCH\r
+ JBE ISLEAD\r
+NOTLEAD:\r
+ PUSH AX\r
+ XOR AX,AX ;Set zero\r
+ POP AX\r
+ RET\r
+\r
+ISLEAD:\r
+ PUSH AX\r
+ XOR AX,AX ;Set zero\r
+ INC AX ;Reset zero\r
+ POP AX\r
+ RET\r
+ ENDIF\r
+\r
+IUPCONV:\r
+ CMP AL,"a"\r
+ JB IRET22\r
+ CMP AL,"z"\r
+ JA IRET22\r
+ SUB AL,20H ; Lower-case changed to upper-case\r
+IRET22:\r
+ RET\r
+\r
+ICONDEV LABEL BYTE\r
+ DB "/DEV/"\r
+ DB "CON",0,0,0,0,0,0 ; Room for 8 char device\r
+BADCSPFL DB 0\r
+COMSPECT DB "/COMMAND.COM",0,0\r
+AUTOBAT DB 0,":\AUTOEXEC.BAT",0\r
+\r
+PRDATTM DB -1 ;Init not to prompt for date time\r
+INITADD DD ?\r
+CHUCKENV DB 0\r
+ECOMLOC DW OFFSET ENVIRONMENT:ECOMSPEC-10H\r
+\r
+ IF HIGHMEM\r
+REALRES DW ?\r
+ENVIRSEGSAV DW ?\r
+ ENDIF\r
+\r
+COMSPSTRING DB "COMSPEC="\r
+\r
+\r
+INIT ENDS\r
+\r
+ END\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+TITLE MISC - Miscellanious routines for MS-DOS\r
+NAME MISC\r
+;\r
+; Miscellaneous system calls most of which are CAVEAT\r
+;\r
+; $SLEAZEFUNC\r
+; $SLEAZEFUNCDL\r
+; $GET_INDOS_FLAG\r
+; $GET_IN_VARS\r
+; $GET_DEFAULT_DPB\r
+; $GET_DPB\r
+; $DISK_RESET\r
+; $SETDPB\r
+; $Dup_PDB\r
+; $CREATE_PROCESS_DATA_BLOCK\r
+; SETMEM\r
+;\r
+.xlist\r
+;\r
+; get the appropriate segment definitions\r
+;\r
+INCLUDE DOSSEG.ASM\r
+\r
+CODE SEGMENT BYTE PUBLIC 'CODE'\r
+ ASSUME SS:DOSGROUP,CS:DOSGROUP\r
+\r
+.xcref\r
+INCLUDE DOSSYM.ASM\r
+INCLUDE DEVSYM.ASM\r
+.cref\r
+.list\r
+\r
+\r
+ifndef Kanji\r
+Kanji equ 0\r
+endif\r
+\r
+ENTRYPOINTSEG EQU 0CH\r
+MAXDIF EQU 0FFFH\r
+SAVEXIT EQU 10\r
+\r
+ i_need LASTBUFFER,DWORD\r
+ i_need INDOS,BYTE\r
+ i_need SYSINITVAR,BYTE\r
+ i_need CurrentPDB,WORD\r
+ i_need CreatePDB,BYTE\r
+ i_need EXIT_TYPE,BYTE\r
+ i_need EXIT_CODE,WORD\r
+ i_need LASTENT,WORD\r
+ i_need THISDPB,DWORD\r
+ i_need ATTRIB,BYTE\r
+ i_need EXTFCB,BYTE\r
+ i_need DMAADD,DWORD\r
+ i_need DIRSTART,WORD\r
+ i_need CURBUF,DWORD\r
+ i_need USER_SP,WORD\r
+ i_need ENTLAST,WORD\r
+ i_need THISDRV,BYTE\r
+\r
+ASSUME SS:DOSGROUP\r
+\r
+BREAK <SleazeFunc -- get a pointer to media byte>\r
+\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+; C A V E A T P R O G R A M M E R ;\r
+; ;\r
+ procedure $SLEAZEFUNC,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; None\r
+; Function:\r
+; Return Stuff sort of like old get fat call\r
+; Outputs:\r
+; DS:BX = Points to FAT ID byte (IBM only)\r
+; GOD help anyone who tries to do ANYTHING except\r
+; READ this ONE byte.\r
+; DX = Total Number of allocation units on disk\r
+; CX = Sector size\r
+; AL = Sectors per allocation unit\r
+; = -1 if bad drive specified\r
+\r
+ MOV DL,0\r
+ entry $SLEAZEFUNCDL\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ MOV AL,DL\r
+ invoke GETTHISDRV\r
+ MOV AL,-1\r
+ JC BADSLDRIVE\r
+ invoke FATREAD\r
+ MOV DX,ES:[BP.dpb_max_cluster]\r
+ DEC DX\r
+ MOV AL,ES:[BP.dpb_cluster_mask]\r
+ INC AL\r
+ MOV CX,ES:[BP.dpb_sector_size]\r
+ ADD BP,dpb_media\r
+BADSLDRIVE:\r
+ invoke get_user_stack\r
+ASSUME DS:NOTHING\r
+ MOV [SI.user_CX],CX\r
+ MOV [SI.user_DX],DX\r
+ MOV [SI.user_BX],BP\r
+ MOV [SI.user_DS],ES\r
+ return\r
+$SLEAZEFUNC ENDP\r
+; ;\r
+; C A V E A T P R O G R A M M E R ;\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+\r
+\r
+\r
+BREAK <$ABORT -- Terminate a process>\r
+ procedure $ABORT,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; CS:00 must point to valid program header block\r
+; Function:\r
+; Restore terminate and Cntrl-C addresses, flush buffers\r
+; and transfer to the terminate address\r
+; Returns:\r
+; TO THE TERMINATE ADDRESS\r
+\r
+ XOR AL,AL\r
+ MOV [exit_type],exit_abort\r
+\r
+;\r
+; abort_inner must have AL set as the exit code!\r
+;\r
+ entry abort_inner\r
+ MOV AH,[exit_type]\r
+ MOV [exit_code],AX\r
+ invoke Get_user_stack\r
+ MOV DS,[SI.user_CS] ; set up old interrupts\r
+ XOR AX,AX\r
+ MOV ES,AX\r
+ MOV SI,SAVEXIT\r
+ MOV DI,addr_int_terminate\r
+ MOVSW\r
+ MOVSW\r
+ MOVSW\r
+ MOVSW\r
+ MOVSW\r
+ MOVSW\r
+ transfer reset_environment\r
+$ABORT ENDP\r
+\r
+BREAK <$Dir_Search_First -- Start a directory search>\r
+ procedure $DIR_SEARCH_FIRST,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DS:DX Points to unopenned FCB\r
+; Function:\r
+; Directory is searched for first matching entry and the directory\r
+; entry is loaded at the disk transfer address\r
+; Returns:\r
+; AL = -1 if no entries matched, otherwise 0\r
+\r
+ invoke GETFILE\r
+ASSUME DS:DOSGROUP\r
+SAVPLCE:\r
+; Search-for-next enters here to save place and report\r
+; findings.\r
+ MOV DL,0 ; Do not XOR!!!\r
+ JC KILLSRCH\r
+ OR AH,AH ; Is it I/O device?\r
+ JS KILLIT ; If so, sign bit will end search\r
+ MOV AX,[LASTENT]\r
+ INC DL\r
+KILLIT:\r
+ MOV ES:[DI.FILDIRENT],AX\r
+ MOV AX,WORD PTR [THISDPB]\r
+ MOV ES:[DI.fcb_DRVBP],AX\r
+ MOV AX,WORD PTR [THISDPB+2]\r
+ MOV ES:[DI.fcb_DRVBP+2],AX\r
+ MOV AX,[DIRSTART]\r
+ MOV ES:[DI.fcb_DRVBP+4],AX\r
+; Information in directory entry must be copied into the first\r
+; 33 bytes starting at the disk transfer address.\r
+ MOV SI,BX\r
+ LES DI,[DMAADD]\r
+ MOV AX,00FFH\r
+ CMP AL,[EXTFCB]\r
+ JNZ NORMFCB\r
+ STOSW\r
+ INC AL\r
+ STOSW\r
+ STOSW\r
+ MOV AL,[ATTRIB]\r
+ STOSB\r
+NORMFCB:\r
+ MOV AL,[THISDRV]\r
+ INC AL\r
+ STOSB ; Set drive number\r
+ OR DL,DL\r
+ JZ DOSRELATIVE\r
+ MOV DS,WORD PTR [CURBUF+2]\r
+ASSUME DS:NOTHING\r
+DOSRELATIVE:\r
+\r
+ IF KANJI\r
+ MOVSW\r
+ CMP BYTE PTR ES:[DI-2],5\r
+ JNZ NOTKTRAN\r
+ MOV BYTE PTR ES:[DI-2],0E5H\r
+NOTKTRAN:\r
+ MOV CX,15\r
+ ELSE\r
+ MOV CX,16\r
+ ENDIF\r
+\r
+ REP MOVSW ; Copy 32 bytes of directory entry\r
+ XOR AL,AL\r
+ return\r
+\r
+ASSUME DS:NOTHING\r
+KILLSRCH1:\r
+ PUSH DS\r
+ POP ES ; Make ES:DI point to the FCB\r
+KILLSRCH:\r
+ MOV AX,-1\r
+ MOV WORD PTR ES:[DI.FILDIRENT],AX\r
+ return\r
+$DIR_SEARCH_FIRST ENDP\r
+\r
+BREAK <$Dir_Search_Next -- Find next matching directory entry>\r
+ procedure $DIR_SEARCH_NEXT,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DS:DX points to unopenned FCB returned by $DIR_SEARCH_FIRST\r
+; Function:\r
+; Directory is searched for the next matching entry and the directory\r
+; entry is loaded at the disk transfer address\r
+; Returns:\r
+; AL = -1 if no entries matched, otherwise 0\r
+\r
+ invoke MOVNAMENOSET\r
+ASSUME ES:DOSGROUP\r
+ MOV DI,DX\r
+ JC NEAR PTR KILLSRCH1\r
+ MOV AX,[DI.FILDIRENT]\r
+ LES BP,DWORD PTR [DI.fcb_DRVBP]\r
+ OR AX,AX\r
+ JS NEAR PTR KILLSRCH1\r
+ MOV BX,[DI.fcb_DRVBP+4]\r
+ PUSH DX\r
+ PUSH DS\r
+ PUSH AX\r
+ MOV WORD PTR [THISDPB],BP\r
+ MOV WORD PTR [THISDPB+2],ES\r
+ invoke SetDirSrch\r
+ ASSUME DS:DOSGROUP\r
+ POP AX\r
+ MOV [ENTLAST],-1\r
+ invoke GetEnt\r
+ invoke NextEnt\r
+ POP ES\r
+ ASSUME ES:NOTHING\r
+ POP DI\r
+ JMP SAVPLCE\r
+$DIR_SEARCH_NEXT ENDP\r
+\r
+BREAK <$Get_FCB_File_Length -- Return size of file in current records>\r
+ procedure $GET_FCB_FILE_LENGTH,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DS:DX points to unopenned FCB\r
+; Function:\r
+; Set random record field to size of file\r
+; Returns:\r
+; AL = -1 if no entries matched, otherwise 0\r
+\r
+ invoke GETFILE\r
+ASSUME DS:DOSGROUP\r
+ MOV AL,-1\r
+ retc\r
+ ADD DI,fcb_RR ; Write size in RR field\r
+ MOV CX,WORD PTR ES:[DI.fcb_RECSIZ-fcb_RR]\r
+ OR CX,CX\r
+ JNZ RECOK\r
+ MOV CX,128\r
+RECOK:\r
+ XOR DX,DX ; Intialize size to zero\r
+ INC SI\r
+ INC SI ; Point to length field\r
+ MOV DS,WORD PTR [CURBUF+2]\r
+ASSUME DS:NOTHING\r
+ MOV AX,[SI+2] ; Get high word of size\r
+ DIV CX\r
+ PUSH AX ; Save high part of result\r
+ LODSW ; Get low word of size\r
+ DIV CX\r
+ OR DX,DX ; Check for zero remainder\r
+ POP DX\r
+ JZ DEVSIZ\r
+ INC AX ; Round up for partial record\r
+ JNZ DEVSIZ ; Propagate carry?\r
+ INC DX\r
+DEVSIZ:\r
+ STOSW\r
+ MOV AX,DX\r
+ STOSB\r
+ MOV AL,0\r
+ CMP CX,64\r
+ JAE RET14 ; Only 3-byte field if fcb_RECSIZ >= 64\r
+ MOV ES:[DI],AH\r
+RET14: return\r
+$GET_FCB_FILE_LENGTH ENDP\r
+\r
+BREAK <$Get_Fcb_Position -- Set random record field to current position>\r
+ procedure $GET_FCB_POSITION,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DS:DX points to openned FCB\r
+; Function:\r
+; Sets random record field to be same as current record fields\r
+; Returns:\r
+; None\r
+\r
+ invoke GETREC\r
+ MOV WORD PTR [DI+fcb_RR],AX\r
+ MOV [DI+fcb_RR+2],DL\r
+ CMP [DI.fcb_RECSIZ],64\r
+ JAE RET16\r
+ MOV [DI+fcb_RR+2+1],DH ; Set 4th byte only if record size < 64\r
+RET16: return\r
+$GET_FCB_POSITION ENDP\r
+\r
+BREAK <$Disk_Reset -- Flush out all dirty buffers>\r
+ procedure $DISK_RESET,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; None\r
+; Function:\r
+; Flush and invalidate all buffers\r
+; Returns:\r
+; Nothing\r
+\r
+ PUSH SS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ MOV AL,-1\r
+ invoke FLUSHBUF\r
+ MOV WORD PTR [LASTBUFFER+2],-1\r
+ MOV WORD PTR [LASTBUFFER],-1\r
+ invoke SETVISIT\r
+ASSUME DS:NOTHING\r
+NBFFR: ; Free ALL buffers\r
+ MOV [DI.VISIT],1 ; Mark as visited\r
+ CMP BYTE PTR [DI.BUFDRV],-1\r
+ JZ SKPBF ; Save a call to PLACEBUF\r
+ MOV WORD PTR [DI.BUFDRV],00FFH\r
+ invoke SCANPLACE\r
+SKPBF:\r
+ invoke SKIPVISIT\r
+ JNZ NBFFR\r
+ return\r
+$DISK_RESET ENDP\r
+\r
+ procedure $RAW_CON_IO,NEAR ; System call 6\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DL = -1 if input\r
+; else DL is output character\r
+; Function:\r
+; Input or output raw character from console, no echo\r
+; Returns:\r
+; AL = character\r
+\r
+ MOV AL,DL\r
+ CMP AL,-1\r
+ JNZ RAWOUT\r
+ LES DI,DWORD PTR [user_SP] ; Get pointer to register save area\r
+ XOR BX,BX\r
+ invoke GET_IO_FCB\r
+ retc\r
+ MOV AH,1\r
+ invoke IOFUNC\r
+ JNZ RESFLG\r
+ invoke SPOOLINT\r
+ OR BYTE PTR ES:[DI.user_F],40H ; Set user's zero flag\r
+ XOR AL,AL\r
+ return\r
+\r
+RESFLG:\r
+ AND BYTE PTR ES:[DI.user_F],0FFH-40H ; Reset user's zero flag\r
+\r
+RILP:\r
+ invoke SPOOLINT\r
+ entry $RAW_CON_INPUT ; System call 7\r
+\r
+; Inputs:\r
+; None\r
+; Function:\r
+; Input raw character from console, no echo\r
+; Returns:\r
+; AL = character\r
+\r
+ XOR BX,BX\r
+ invoke GET_IO_FCB\r
+ retc\r
+ MOV AH,1\r
+ invoke IOFUNC\r
+ JZ RILP\r
+ XOR AH,AH\r
+ invoke IOFUNC\r
+ return\r
+;\r
+; Output the character in AL to stdout\r
+;\r
+entry RAWOUT\r
+\r
+ PUSH BX\r
+ MOV BX,1\r
+\r
+ invoke GET_IO_FCB\r
+ JC RAWRET1\r
+\r
+ TEST [SI.fcb_DEVID],080H ; output to file?\r
+ JZ RAWNORM ; if so, do normally\r
+ PUSH DS\r
+ PUSH SI\r
+ LDS SI,DWORD PTR [SI.fcb_FIRCLUS] ; output to special?\r
+ TEST BYTE PTR [SI+SDEVATT],ISSPEC\r
+ POP SI\r
+ POP DS\r
+ JZ RAWNORM ; if not, do normally\r
+ INT int_fastcon ; quickly output the char\r
+ JMP SHORT RAWRET\r
+RAWNORM:\r
+\r
+ CALL RAWOUT3\r
+RAWRET: CLC\r
+RAWRET1:\r
+ POP BX\r
+ return\r
+\r
+;\r
+; Output the character in AL to handle in BX\r
+;\r
+entry RAWOUT2\r
+\r
+ invoke GET_IO_FCB\r
+ retc\r
+RAWOUT3:\r
+ PUSH AX\r
+ JMP SHORT RAWOSTRT\r
+ROLP:\r
+ invoke SPOOLINT\r
+RAWOSTRT:\r
+ MOV AH,3\r
+ CALL IOFUNC\r
+ JZ ROLP\r
+ POP AX\r
+ MOV AH,2\r
+ CALL IOFUNC\r
+ CLC ; Clear carry indicating successful\r
+ return\r
+$RAW_CON_IO ENDP\r
+\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+; This routine is called at DOS init\r
+\r
+ procedure OUTMES,NEAR ; String output for internal messages\r
+ LODS CS:BYTE PTR [SI]\r
+ CMP AL,"$"\r
+ retz\r
+ invoke OUT\r
+ JMP SHORT OUTMES\r
+ return\r
+OutMes ENDP\r
+ ASSUME SS:DOSGROUP\r
+\r
+BREAK <$Parse_File_Descriptor -- Parse an arbitrary string into an FCB>\r
+ procedure $PARSE_FILE_DESCRIPTOR,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DS:SI Points to a command line\r
+; ES:DI Points to an empty FCB\r
+; Bit 0 of AL = 1 At most one leading separator scanned off\r
+; = 0 Parse stops if separator encountered\r
+; Bit 1 of AL = 1 If drive field blank in command line - leave FCB\r
+; = 0 " " " " " " - put 0 in FCB\r
+; Bit 2 of AL = 1 If filename field blank - leave FCB\r
+; = 0 " " " - put blanks in FCB\r
+; Bit 3 of AL = 1 If extension field blank - leave FCB\r
+; = 0 " " " - put blanks in FCB\r
+; Function:\r
+; Parse command line into FCB\r
+; Returns:\r
+; AL = 1 if '*' or '?' in filename or extension, 0 otherwise\r
+; DS:SI points to first character after filename\r
+\r
+ invoke MAKEFCB\r
+ PUSH SI\r
+ invoke get_user_stack\r
+ POP [SI.user_SI]\r
+ return\r
+$PARSE_FILE_DESCRIPTOR ENDP\r
+\r
+BREAK <$Create_Process_Data_Block,SetMem -- Set up process data block>\r
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;\r
+; C A V E A T P R O G R A M M E R ;\r
+; ;\r
+ procedure $Dup_PDB,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+ MOV BYTE PTR [CreatePDB], 0FFH ; indicate a new process\r
+$Dup_PDB ENDP\r
+\r
+\r
+ procedure $CREATE_PROCESS_DATA_BLOCK,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING\r
+\r
+; Inputs:\r
+; DX = Segment number of new base\r
+; Function:\r
+; Set up program base and copy term and ^C from int area\r
+; Returns:\r
+; None\r
+; Called at DOS init\r
+\r
+ MOV ES,DX\r
+ TEST BYTE PTR [CreatePDB],0FFh\r
+ JZ create_PDB_old\r
+ MOV DS,[CurrentPDB]\r
+ JMP SHORT Create_copy\r
+\r
+Create_PDB_old:\r
+ invoke get_user_stack\r
+ MOV DS,[SI.user_CS]\r
+\r
+Create_copy:\r
+ XOR SI,SI ; copy all 80h bytes\r
+ MOV DI,SI\r
+ MOV CX,80H\r
+ REP MOVSW\r
+\r
+ TEST BYTE PTR [CreatePDB],0FFh ; Shall we create a process?\r
+ JZ Create_PDB_cont ; nope, old style call\r
+;\r
+; Here we set up for a new process...\r
+;\r
+\r
+ PUSH CS\r
+ POP DS\r
+ ASSUME DS:DOSGROUP\r
+ XOR BX,BX ; dup all jfns\r
+ MOV CX,FilPerProc\r
+\r
+Create_dup_jfn:\r
+ PUSH ES ; save new PDB\r
+ invoke get_jfn_pointer ; ES:DI is jfn\r
+ JC create_skip ; not a valid jfn\r
+ PUSH ES ; save him\r
+ PUSH DI\r
+ invoke get_sf_from_jfn ; get sf pointer\r
+ JC create_no_inc\r
+ INC ES:[DI].sf_ref_count ; new fh\r
+\r
+create_no_inc:\r
+ POP DI\r
+ POP ES ; get old jfn\r
+ MOV AL,ES:[DI] ; get sfn\r
+ POP ES\r
+ PUSH ES\r
+ MOV AL,ES:[BX] ; copy into new place!\r
+\r
+create_skip:\r
+ POP ES\r
+ INC BX ; next jfn...\r
+ LOOP create_dup_jfn\r
+\r
+ PUSH [CurrentPDB] ; get current process\r
+ POP BX\r
+ PUSH BX\r
+ POP ES:[PDB_Parent_PID] ; stash in child\r
+ MOV [CurrentPDB],ES\r
+ ASSUME DS:NOTHING\r
+ MOV DS,BX\r
+;\r
+; end of new process create\r
+;\r
+Create_PDB_cont:\r
+ MOV BYTE PTR [CreatePDB],0h ; reset flag\r
+ MOV AX,DS:[2] ; set up size for fall through\r
+\r
+entry SETMEM\r
+ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING\r
+\r
+; Inputs:\r
+; AX = Size of memory in paragraphs\r
+; DX = Segment\r
+; Function:\r
+; Completely prepares a program base at the\r
+; specified segment.\r
+; Called at DOS init\r
+; Outputs:\r
+; DS = DX\r
+; ES = DX\r
+; [0] has INT int_abort\r
+; [2] = First unavailable segment ([ENDMEM])\r
+; [5] to [9] form a long call to the entry point\r
+; [10] to [13] have exit address (from int_terminate)\r
+; [14] to [17] have ctrl-C exit address (from int_ctrl_c)\r
+; [18] to [21] have fatal error address (from int_fatal_abort)\r
+; DX,BP unchanged. All other registers destroyed.\r
+\r
+ XOR CX,CX\r
+ MOV DS,CX\r
+ MOV ES,DX\r
+ MOV SI,addr_int_terminate\r
+ MOV DI,SAVEXIT\r
+ MOV CX,6\r
+ REP MOVSW\r
+ MOV ES:[2],AX\r
+ SUB AX,DX\r
+ CMP AX,MAXDIF\r
+ JBE HAVDIF\r
+ MOV AX,MAXDIF\r
+HAVDIF:\r
+ MOV BX,ENTRYPOINTSEG\r
+ SUB BX,AX\r
+ MOV CL,4\r
+ SHL AX,CL\r
+ MOV DS,DX\r
+ MOV WORD PTR DS:[PDB_CPM_Call+1],AX\r
+ MOV WORD PTR DS:[PDB_CPM_Call+3],BX\r
+ MOV DS:[PDB_Exit_Call],(int_abort SHL 8) + mi_INT\r
+ MOV BYTE PTR DS:[PDB_CPM_Call],mi_Long_CALL\r
+ MOV WORD PTR DS:[PDB_Call_System],(int_command SHL 8) + mi_INT\r
+ MOV BYTE PTR DS:[PDB_Call_System+2],mi_Long_RET\r
+ return\r
+\r
+$CREATE_PROCESS_DATA_BLOCK ENDP\r
+ do_ext\r
+\r
+ CODE ENDS\r
+ END\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+TITLE MORE Messages
+
+CODE SEGMENT PUBLIC
+ PUBLIC MORETXT,BADVER,CRLFTXT,BUFFER
+
+MORETXT DB 13,"-- More --$"
+BADVER DB "MORE: Incorrect DOS version"
+CRLFTXT DB 13,10,"$"
+;
+; THIS VARIABLE MUST BE DEFINED LAST!
+;
+BUFFER DB 4098 DUP (?)
+
+CODE ENDS
+ END
+
+\1a
\ No newline at end of file
--- /dev/null
+;
+; MSCODE.ASM -- MSDOS code
+;
+
+INCLUDE DOSSEG.ASM
+INCLUDE STDSW.ASM
+
+CODE SEGMENT BYTE PUBLIC 'CODE'
+ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
+
+.xcref
+INCLUDE DOSSYM.ASM
+INCLUDE DEVSYM.ASM
+.cref
+.list
+
+IFNDEF KANJI
+KANJI EQU 0 ; FALSE
+ENDIF
+
+IFNDEF IBM
+IBM EQU 0
+ENDIF
+
+IFNDEF HIGHMEM
+HIGHMEM EQU 0
+ENDIF
+
+
+ i_need USER_SP,WORD
+ i_need USER_SS,WORD
+ i_need SAVEDS,WORD
+ i_need SAVEBX,WORD
+ i_need INDOS,BYTE
+ i_need NSP,WORD
+ i_need NSS,WORD
+ i_need CURRENTPDB,WORD
+ i_need AUXSTACK,BYTE
+ i_need CONSWAP,BYTE
+ i_need IDLEINT,BYTE
+ i_need NOSETDIR,BYTE
+ i_need ERRORMODE,BYTE
+ i_need IOSTACK,BYTE
+ i_need WPERR,BYTE
+ i_need DSKSTACK,BYTE
+ i_need CNTCFLAG,BYTE
+ i_need LEAVEADDR,WORD
+ i_need NULLDEVPT,DWORD
+
+ IF NOT IBM
+ i_need OEM_HANDLER,DWORD
+ ENDIF
+
+ EXTRN DSKSTATCHK:NEAR,GETBP:NEAR,DSKREAD:NEAR,DSKWRITE:NEAR
+
+
+BREAK <Copyright notice and version>
+
+CODSTRT EQU $
+
+ IF NOT IBM
+ IF NOT KANJI
+ PUBLIC HEADER
+HEADER DB 13,10,"Microsoft MS-DOS version "
+ DB DOS_MAJOR_VERSION + "0"
+ DB "."
+ DB (DOS_MINOR_VERSION / 10) + "0"
+ DB (DOS_MINOR_VERSION MOD 10) + "0"
+ IF HIGHMEM
+ DB "H"
+ ENDIF
+ ENDIF
+ IF KANJI
+ PUBLIC HEADER
+HEADER DB 13,10,82h,"M"+1fh,82h,"i"+20h,82h,"c"+20h,82h,"r"+20h,82h,"o"+20h
+ DB 82h,"s"+20h,82h,"o"+20h,82h,"f"+20h,82h,"t"+20h
+ DB 81h,40h,82h,"M"+1fh,82h,"S"+1fh,81h,5dh+1fh
+ DB 82h,"D"+1fh,82h,"O"+1fh,82h,"S"+1fh,81h,40h
+ DB 82h,DOS_MAJOR_VERSION+"0"+1fh
+ DB 81h,25h+1fh
+ DB 82h,(DOS_MINOR_VERSION / 10)+"0"+1fh
+ DB 82h,(DOS_MINOR_VERSION MOD 10)+"0"+1fh
+ DB 94h,0c5h
+ ENDIF
+ DB 13,10
+ DB "Copyright 1981,82,83 Microsoft Corp.",13,10,"$"
+ ENDIF
+BREAK <System call entry points and dispatcher>
+ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
+
+ procedure SYSTEM_CALL,NEAR
+entry QUIT ; INT 20H entry point
+ MOV AH,0
+ JMP SHORT SAVREGS
+
+entry COMMAND ; Interrupt call entry point (INT 21H)
+
+ IF NOT IBM
+ CMP AH,SET_OEM_HANDLER
+ JB NOTOEM
+ JMP $SET_OEM_HANDLER
+NOTOEM:
+ ENDIF
+
+ CMP AH,MAXCOM
+ JBE SAVREGS
+BADCALL:
+ MOV AL,0
+entry IRET
+ IRET
+
+entry CALL_ENTRY ; System call entry point and dispatcher
+ POP AX ; IP from the long call at 5
+ POP AX ; Segment from the long call at 5
+ POP [User_SP] ; IP from the CALL 5
+ PUSHF ; Start re-ordering the stack
+ CLI
+ PUSH AX ; Save segment
+ PUSH [User_SP] ; Stack now ordered as if INT had been used
+ CMP CL,MAXCALL ; This entry point doesn't get as many calls
+ JA BADCALL
+ MOV AH,CL
+SAVREGS:
+ CALL save_world
+ MOV [SaveDS],DS
+ MOV [SaveBX],BX
+ MOV BX,CS
+ MOV DS,BX
+ASSUME DS:DOSGROUP
+ INC [INDOS] ; Flag that we're in the DOS
+ MOV AX,[user_SP]
+ MOV [NSP],AX
+ MOV AX,[user_SS]
+ MOV [NSS],AX
+ POP AX
+ PUSH AX
+ MOV [user_SP],SP
+ MOV [user_SS],SS
+;
+; save user stack in his area for later returns (possibly from EXEC)
+; Here comes multitasking!!!
+;
+ MOV DS,[CurrentPDB]
+ MOV WORD PTR DS:[PDB_User_stack],SP
+ MOV WORD PTR DS:[PDB_User_stack+2],SS
+
+ MOV BX,CS ; no holes here.
+ MOV SS,BX
+ASSUME SS:DOSGROUP
+
+ entry REDISP
+ MOV SP,OFFSET DOSGROUP:AUXSTACK ; Enough stack for interrupts
+ STI ; Stack OK now
+ PUSH CS
+ POP DS
+ XOR BH,BH
+ MOV [CONSWAP],BH
+ MOV [IDLEINT],1
+ MOV BYTE PTR [NoSetDir],0 ; set directories on search
+ MOV BL,AH
+ SHL BX,1
+ CLD
+ OR AH,AH
+ JZ DSKROUT ; ABORT
+ CMP AH,12
+ JBE IOROUT ; Character I/O
+ CMP AH,GET_CURRENT_PDB ; INT 24 needs GET,SET PDB
+ JZ IOROUT
+ CMP AH,SET_CURRENT_PDB
+ JNZ DSKROUT
+IOROUT:
+ CMP [ERRORMODE],0
+ JNZ DISPCALL ; Stay on AUXSTACK if INT 24
+ MOV SP,OFFSET DOSGROUP:IOSTACK
+ JMP SHORT DISPCALL
+
+DSKROUT:
+ MOV [ERRORMODE],0 ; Cannot make non 1-12 calls in
+ MOV [WPERR],-1 ; error mode, so good place to
+ ; make sure flags are reset
+ MOV SP,OFFSET DOSGROUP:DSKSTACK
+ TEST [CNTCFLAG],-1
+ JZ DISPCALL
+ PUSH AX
+ invoke DSKSTATCHK
+ POP AX
+DISPCALL:
+ PUSH [LEAVEADDR]
+ PUSH CS:[BX+DISPATCH]
+ MOV BX,[SaveBX]
+ MOV DS,[SaveDS]
+ASSUME DS:NOTHING
+ return
+
+ entry LEAVE
+ASSUME SS:NOTHING ; User routines may misbehave
+ CLI
+ DEC [INDOS]
+ MOV SP,[user_SP]
+ MOV SS,[user_SS]
+ MOV BP,SP
+ MOV BYTE PTR [BP.user_AX],AL
+ MOV AX,[NSP]
+ MOV [user_SP],AX
+ MOV AX,[NSS]
+ MOV [user_SS],AX
+ CALL restore_world
+
+ IRET
+SYSTEM_CALL ENDP
+
+;
+; restore_world restores all registers ('cept SS:SP, CS:IP, flags) from
+; the stack prior to giving the user control
+;
+ ASSUME DS:NOTHING,ES:NOTHING
+restore_tmp DW ?
+ procedure restore_world,NEAR
+ POP restore_tmp ; POP restore_tmp
+ 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
+world_ret:
+ PUSH restore_tmp ; PUSH restore_tmp
+ return
+restore_world ENDP
+
+;
+; save_world saves complete registers on the stack
+;
+ procedure save_world,NEAR
+ POP restore_tmp
+ PUSH ES
+ PUSH DS
+ PUSH BP
+ PUSH DI
+ PUSH SI
+ PUSH DX
+ PUSH CX
+ PUSH BX
+ PUSH AX
+ JMP SHORT world_ret
+save_world ENDP
+
+;
+; get_user_stack returns the user's stack (and hence registers) in DS:SI
+;
+ procedure get_user_stack,NEAR
+ LDS SI,DWORD PTR [user_SP]
+ return
+get_user_stack ENDP
+
+; Standard Functions
+DISPATCH LABEL WORD
+.lall
+ short_addr $ABORT ; 0 0
+.xall
+ short_addr $STD_CON_INPUT ; 1 1
+ short_addr $STD_CON_OUTPUT ; 2 2
+ short_addr $STD_AUX_INPUT ; 3 3
+ short_addr $STD_AUX_OUTPUT ; 4 4
+ short_addr $STD_PRINTER_OUTPUT ; 5 5
+ short_addr $RAW_CON_IO ; 6 6
+ short_addr $RAW_CON_INPUT ; 7 7
+ short_addr $STD_CON_INPUT_NO_ECHO ; 8 8
+ short_addr $STD_CON_STRING_OUTPUT ; 9 9
+ short_addr $STD_CON_STRING_INPUT ; 10 A
+ short_addr $STD_CON_INPUT_STATUS ; 11 B
+ short_addr $STD_CON_INPUT_FLUSH ; 12 C
+ short_addr $DISK_RESET ; 13 D
+ short_addr $SET_DEFAULT_DRIVE ; 14 E
+ short_addr $FCB_OPEN ; 15 F
+ short_addr $FCB_CLOSE ; 16 10
+ short_addr $DIR_SEARCH_FIRST ; 17 11
+ short_addr $DIR_SEARCH_NEXT ; 18 12
+ short_addr $FCB_DELETE ; 19 13
+ short_addr $FCB_SEQ_READ ; 20 14
+ short_addr $FCB_SEQ_WRITE ; 21 15
+ short_addr $FCB_CREATE ; 22 16
+ short_addr $FCB_RENAME ; 23 17
+ short_addr CPMFUNC ; 24 18
+ short_addr $GET_DEFAULT_DRIVE ; 25 19
+ short_addr $SET_DMA ; 26 1A
+
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+; C A V E A T P R O G R A M M E R ;
+; ;
+ short_addr $SLEAZEFUNC ; 27 1B
+ short_addr $SLEAZEFUNCDL ; 28 1C
+; ;
+; C A V E A T P R O G R A M M E R ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+
+ short_addr CPMFUNC ; 29 1D
+ short_addr CPMFUNC ; 30 1E
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+; C A V E A T P R O G R A M M E R ;
+; ;
+ short_addr $GET_DEFAULT_DPB ; 31 1F
+; ;
+; C A V E A T P R O G R A M M E R ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+ short_addr CPMFUNC ; 32 20
+ short_addr $FCB_RANDOM_READ ; 33 21
+ short_addr $FCB_RANDOM_WRITE ; 34 22
+ short_addr $GET_FCB_FILE_LENGTH ; 35 23
+ short_addr $GET_FCB_POSITION ; 36 24
+MAXCALL = ($-DISPATCH)/2 - 1
+
+; Extended Functions
+ short_addr $SET_INTERRUPT_VECTOR ; 37 25
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+; C A V E A T P R O G R A M M E R ;
+; ;
+ short_addr $CREATE_PROCESS_DATA_BLOCK ; 38 26
+; ;
+; C A V E A T P R O G R A M M E R ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+ short_addr $FCB_RANDOM_READ_BLOCK ; 39 27
+ short_addr $FCB_RANDOM_WRITE_BLOCK ; 40 28
+ short_addr $PARSE_FILE_DESCRIPTOR ; 41 29
+ short_addr $GET_DATE ; 42 2A
+ short_addr $SET_DATE ; 43 2B
+ short_addr $GET_TIME ; 44 2C
+ short_addr $SET_TIME ; 45 2D
+ short_addr $SET_VERIFY_ON_WRITE ; 46 2E
+
+; Extended functionality group
+ short_addr $GET_DMA ; 47 2F
+ short_addr $GET_VERSION ; 48 30
+ short_addr $Keep_Process ; 49 31
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+; C A V E A T P R O G R A M M E R ;
+; ;
+ short_addr $GET_DPB ; 50 32
+; ;
+; C A V E A T P R O G R A M M E R ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+ short_addr $SET_CTRL_C_TRAPPING ; 51 33
+ short_addr $GET_INDOS_FLAG ; 52 34
+ short_addr $GET_INTERRUPT_VECTOR ; 53 35
+ short_addr $GET_DRIVE_FREESPACE ; 54 36
+ short_addr $CHAR_OPER ; 55 37
+ short_addr $INTERNATIONAL ; 56 38
+; XENIX CALLS
+; Directory Group
+ short_addr $MKDIR ; 57 39
+ short_addr $RMDIR ; 58 3A
+ short_addr $CHDIR ; 59 3B
+; File Group
+ short_addr $CREAT ; 60 3C
+ short_addr $OPEN ; 61 3D
+ short_addr $CLOSE ; 62 3E
+ short_addr $READ ; 63 3F
+ short_addr $WRITE ; 64 40
+ short_addr $UNLINK ; 65 41
+ short_addr $LSEEK ; 66 42
+ short_addr $CHMOD ; 67 43
+ short_addr $IOCTL ; 68 44
+ short_addr $DUP ; 69 45
+ short_addr $DUP2 ; 70 46
+ short_addr $CURRENT_DIR ; 71 47
+; Memory Group
+ short_addr $ALLOC ; 72 48
+ short_addr $DEALLOC ; 73 49
+ short_addr $SETBLOCK ; 74 4A
+; Process Group
+ short_addr $EXEC ; 75 4B
+ short_addr $EXIT ; 76 4C
+ short_addr $WAIT ; 77 4D
+ short_addr $FIND_FIRST ; 78 4E
+; Special Group
+ short_addr $FIND_NEXT ; 79 4F
+; SPECIAL SYSTEM GROUP
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+; C A V E A T P R O G R A M M E R ;
+; ;
+ short_addr $SET_CURRENT_PDB ; 80 50
+ short_addr $GET_CURRENT_PDB ; 81 51
+ short_addr $GET_IN_VARS ; 82 52
+ short_addr $SETDPB ; 83 53
+; ;
+; C A V E A T P R O G R A M M E R ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+ short_addr $GET_VERIFY_ON_WRITE ; 84 54
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+; C A V E A T P R O G R A M M E R ;
+; ;
+ short_addr $DUP_PDB ; 85 55
+; ;
+; C A V E A T P R O G R A M M E R ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+ short_addr $RENAME ; 86 56
+ short_addr $FILE_TIMES ; 87 57
+ short_addr $AllocOper ; 88 58
+
+MAXCOM = ($-DISPATCH)/2 - 1
+
+CPMFUNC:
+ XOR AL,AL
+ return
+
+ IF NOT IBM
+BREAK <Set_OEM_Handler -- Set OEM sys call address and handle OEM Calls>
+
+$SET_OEM_HANDLER:
+ASSUME DS:NOTHING,ES:NOTHING
+
+; Inputs:
+; User registers, User Stack, INTS disabled
+; If CALL F8, DS:DX is new handler address
+; Function:
+; Process OEM INT 21 extensions
+; Outputs:
+; Jumps to OEM_HANDLER if appropriate
+
+ JNE DO_OEM_FUNC ; If above F8 try to jump to handler
+ MOV WORD PTR [OEM_HANDLER],DX ; Set Handler
+ MOV WORD PTR [OEM_HANDLER+2],DS
+ IRET ; Quick return, Have altered no registers
+
+DO_OEM_FUNC:
+ CMP WORD PTR [OEM_HANDLER],-1
+ JNZ OEM_JMP
+ JMP BADCALL ; Handler not initialized
+
+OEM_JMP:
+ JMP [OEM_HANDLER]
+
+ ENDIF
+
+
+ASSUME SS:DOSGROUP
+
+;
+; $Set_current_PDB takes BX and sets it to be the current process
+; *** THIS FUNCTION CALL IS SUBJECT TO CHANGE!!! ***
+;
+ procedure $SET_CURRENT_PDB,NEAR
+ ASSUME DS:NOTHING,SS:NOTHING
+ MOV [CurrentPDB],BX
+ return
+$SET_CURRENT_PDB ENDP
+
+;
+; $get_current_PDB returns in BX the current process
+; *** THIS FUNCTION CALL IS SUBJECT TO CHANGE!!! ***
+;
+ procedure $GET_CURRENT_PDB,NEAR
+ ASSUME DS:NOTHING,SS:NOTHING
+ invoke get_user_stack
+ PUSH [CurrentPDB]
+ POP [SI.user_BX]
+ return
+$GET_CURRENT_PDB ENDP
+; ;
+; C A V E A T P R O G R A M M E R ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+
+BREAK <NullDev -- Driver for null device>
+ procedure SNULDEV,FAR
+ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
+ MOV WORD PTR [NULLDEVPT],BX
+ MOV WORD PTR [NULLDEVPT+2],ES
+ return
+SNULDEV ENDP
+
+ procedure INULDEV,FAR
+ PUSH ES
+ PUSH BX
+ LES BX,[NULLDEVPT]
+ OR ES:[BX.REQSTAT],STDON ; Set done bit
+ POP BX
+ POP ES
+ return
+
+INULDEV ENDP
+
+
+BREAK <AbsDRD, AbsDWRT -- INT int_disk_read, int_disk_write handlers>>
+
+
+ IF IBM
+ERRIN: ; Codes returned by BIOS
+ DB 2 ; NO RESPONSE
+ DB 6 ; SEEK FAILURE
+ DB 12 ; GENERAL ERROR
+ DB 4 ; BAD CRC
+ DB 8 ; SECTOR NOT FOUND
+ DB 0 ; WRITE ATTEMPT ON WRITE-PROTECT DISK
+ERROUT: ; DISK ERRORS RETURNED FROM INT 25 and 26
+ DB 80H ; NO RESPONSE
+ DB 40H ; Seek failure
+ DB 2 ; Address Mark not found
+ DB 8 ; DMA OVERRUN
+ DB 4 ; SECTOR NOT FOUND
+ DB 3 ; WRITE ATTEMPT TO WRITE-PROTECT DISK
+
+NUMERR EQU $-ERROUT
+ ENDIF
+
+ procedure ABSDRD,FAR
+ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
+
+ CLI
+ MOV [user_SS],SS
+ MOV [user_SP],SP
+ PUSH CS
+ POP SS
+ASSUME SS:DOSGROUP
+ MOV SP,OFFSET DOSGROUP:DSKSTACK
+ INC BYTE PTR [INDOS]
+ STI
+ CLD
+ PUSH ES
+ PUSH DS
+ PUSH SS
+ POP DS
+ASSUME DS:DOSGROUP
+ invoke GETBP
+ POP DS
+ASSUME DS:NOTHING
+ JC ILEAVE
+ invoke DSKREAD
+TLEAVE:
+ JZ ILEAVE
+
+ IF IBM
+; Translate the error code to ancient 1.1 codes
+ PUSH ES
+ PUSH CS
+ POP ES
+ XOR AH,AH ; Nul error code
+ MOV CX,NUMERR ; Number of possible error conditions
+ MOV DI,OFFSET DOSGROUP:ERRIN ; Point to error conditions
+ REPNE SCASB
+ JNZ LEAVECODE ; Not found
+ MOV AH,ES:[DI+NUMERR-1] ; Get translation
+LEAVECODE:
+ POP ES
+ ENDIF
+
+ STC
+ILEAVE:
+ POP ES
+ CLI
+ DEC BYTE PTR [INDOS]
+ MOV SP,[user_SP]
+ MOV SS,[user_SS]
+ASSUME SS:NOTHING
+ STI
+ return
+ABSDRD ENDP
+
+ procedure ABSDWRT,FAR
+ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
+
+ CLI
+ MOV [user_SS],SS
+ MOV [user_SP],SP
+ PUSH CS
+ POP SS
+ASSUME SS:DOSGROUP
+ MOV SP,OFFSET DOSGROUP:DSKSTACK
+ INC BYTE PTR [INDOS]
+ STI
+ CLD
+ PUSH ES
+ PUSH DS
+ PUSH SS
+ POP DS
+ASSUME DS:DOSGROUP
+ invoke GETBP
+ POP DS
+ASSUME DS:NOTHING
+ JC ILEAVE
+ invoke DSKWRITE
+ JMP TLEAVE
+ABSDWRT ENDP
+
+
+
+ procedure SYS_RETURN,NEAR
+ ASSUME DS:NOTHING,ES:NOTHING
+ entry SYS_RET_OK
+ call get_user_stack
+ PUSH [SI.user_F]
+ POPF
+ CLC
+ JMP SHORT DO_RET
+
+ entry SYS_RET_ERR
+ XOR AH,AH ; hack to allow for smaller error rets
+ call get_user_stack
+ PUSH [SI.user_F]
+ POPF
+ STC
+DO_RET:
+ MOV [SI.user_AX],AX ; Really only sets AH
+ PUSHF
+ POP [SI.user_F] ; dump on his flags
+ return
+SYS_RETURN ENDP
+
+do_ext
+
+CODE ENDS
+ END
+\1a
\ No newline at end of file
--- /dev/null
+SUBTTL Initialized data and data used at DOS initialization\r
+PAGE\r
+; DATA AREA for MS-DOS\r
+\r
+IFNDEF KANJI\r
+KANJI EQU 0 ;FALSE\r
+ENDIF\r
+\r
+CONSTANTS SEGMENT BYTE PUBLIC 'CONST'\r
+ EXTRN international_table:BYTE\r
+ EXTRN Current_Country:WORD\r
+\r
+\r
+ ORG 0\r
+CONSTRT EQU $ ; Start of constants segment\r
+\r
+ PUBLIC DevStrLen\r
+DEVSTRLEN DB 3 ; Size of below\r
+ PUBLIC DevString\r
+DEVSTRING DB "DEV" ; Dummy device directory\r
+\r
+;\r
+; Table of routines for assignable devices\r
+;\r
+; MSDOS allows assignment if the following standard devices:\r
+; stdin (usually CON input)\r
+; stdout (usually CON output)\r
+; auxin (usually AUX input)\r
+; auxout (usually AUX output)\r
+; stdlpt (usually PRN output)\r
+;\r
+; SPECIAL NOTE:\r
+; Status of a file is a strange idea. We choose to handle it in this manner:\r
+; If we're not at end-of-file, then we always say that we have a character.\r
+; Otherwise, we return ^Z as the character and set the ZERO flag. In this\r
+; manner we can support program written under the old DOS (they use ^Z as EOF\r
+; on devices) and programs written under the new DOS (they use the ZERO flag\r
+; as EOF).\r
+\r
+; Default FCBs for boot up\r
+\r
+sftabl LABEL DWORD ; file table\r
+ DW -1\r
+ DW -1\r
+ DW sf_default_number ; Number of entries in table\r
+ DB sf_default_number DUP ( (SIZE sf_entry) DUP (0))\r
+\r
+ I_AM NoSetDir,BYTE ; true -> do not set directory\r
+ I_am DidCTRLC,BYTE ; true -> we did a ^C exit\r
+ I_am SpaceFlag,BYTE ; true -> embedded spaces are allowed\r
+ ; in FCB\r
+; the next two variables relate to the position of the logical stdout/stdin\r
+; cursor. They are only meaningful when stdin/stdout are assigned to the\r
+; console.\r
+\r
+ i_am CARPOS,BYTE ; cursor position in stdin\r
+ i_am STARTPOS,BYTE ; position of cursor at beginning\r
+ ; of buffered input call\r
+ I_AM PFLAG,BYTE\r
+ I_AM VERFLG,BYTE ; Initialize with verify off\r
+ I_AM CONTPOS,WORD\r
+ PUBLIC CHARCO\r
+CHARCO DB 00000011B ; Allows statchks every 4 chars...\r
+\r
+ I_AM DMAADD,DWORD ; User's disk transfer address\r
+ ; (disp/seg)\r
+ ORG $-CONSTRT-4\r
+ DW 80H\r
+ DW ?\r
+\r
+ENDMEM DW ?\r
+\r
+ PUBLIC switch_character\r
+switch_character DB '/'\r
+\r
+ PUBLIC device_availability\r
+device_availability DB 0FFH\r
+\r
+ I_AM FirstArena,WORD ; first free block found\r
+ I_AM BestArena,WORD ; best free block found\r
+ I_AM LastArena,WORD ; last free block found\r
+ I_AM AllocMethod,BYTE ; how to alloc first(best)last\r
+ I_AM arena_head,WORD\r
+\r
+; The following block of data is used by SYSINIT. Do not change the order or\r
+; size of this block\r
+\r
+ PUBLIC SYSINITVAR\r
+SYSINITVAR LABEL WORD\r
+ I_AM DPBHEAD,DWORD ; Pointer to head of DPB-FAT list\r
+ I_AM sft_addr,DWORD ; Pointer to first FCB table\r
+ ORG $-CONSTRT-4\r
+ short_addr sftabl\r
+ DW ? ; DOS segment set at INIT\r
+\r
+; The following address points to the CLOCK device\r
+ i_am BCLOCK,DWORD\r
+; The following address is used by DISKSTATCHK it is always points to the\r
+; console input device header\r
+ I_AM BCON,DWORD ; Console device entry points\r
+ i_am NUMIO,BYTE ; Number of disk tables\r
+MAXSEC DW 0 ; Maximum allowed sector size\r
+ I_AM BUFFHEAD,DWORD ; Pointer to head of buffer queue\r
+DEVHEAD LABEL DWORD\r
+ I_AM NULDEV,DWORD ; Set to list start passed by \r
+ ; BIOS at DOS Init\r
+\r
+ DW DEVTYP OR ISNULL\r
+ short_addr SNULDEV\r
+ short_addr INULDEV\r
+ DB "NUL "\r
+\r
+\r
+ i_am DAY,BYTE\r
+ i_am MONTH,BYTE\r
+ i_am YEAR,WORD\r
+ i_am DAYCNT,WORD\r
+ i_am WEEKDAY,BYTE\r
+ ORG $-CONSTRT-7\r
+ DB 0,0\r
+ DW 0,-1\r
+ DB 0\r
+\r
+ I_AM CURDRV,BYTE ; Default to drive A\r
+ I_AM LASTENT,WORD\r
+ i_am INDOS,BYTE ; DOS status for interrupt processing\r
+ ORG $-CONSTRT-1\r
+ DB 0\r
+ I_AM ErrorMode,BYTE ; Flag for INT 24 processing\r
+ PUBLIC WPErr\r
+WPERR DB -1 ; Write protect error flag\r
+ I_AM CONSWAP,BYTE\r
+ PUBLIC IDLEINT\r
+IDLEINT DB 1\r
+ PUBLIC CNTCFLAG\r
+CNTCFLAG DB 0 ; ^C check in dispatch disabled\r
+\r
+ PUBLIC LastBuffer\r
+LASTBUFFER LABEL DWORD ; Buffer queue recency pointer\r
+ DW -1\r
+ DW -1\r
+\r
+; Combination of all device call parameters\r
+\r
+ PUBLIC DEVCALL\r
+DEVCALL SRHEAD <>\r
+CALLUNIT LABEL BYTE\r
+CALLFLSH LABEL WORD\r
+ I_AM CALLMED,BYTE\r
+CALLBR LABEL DWORD\r
+ PUBLIC CALLXAD\r
+CALLXAD LABEL DWORD\r
+ I_AM CALLRBYT,BYTE\r
+ DB 3 DUP(?)\r
+ PUBLIC CallBPB\r
+CALLBPB LABEL DWORD\r
+ I_AM CALLSCNT,WORD\r
+CALLSSEC DW ?\r
+\r
+ I_AM CALLDEVAD,DWORD ; stash for device entry point\r
+\r
+; Same as above for I/O calls\r
+\r
+ PUBLIC IOCall\r
+IOCALL SRHEAD <>\r
+IOFLSH LABEL WORD\r
+ PUBLIC IORCHR\r
+IORCHR LABEL BYTE\r
+ I_AM IOMED,BYTE\r
+ I_AM IOXAD,DWORD\r
+ I_AM IOSCNT,WORD\r
+ I_AM IOSSEC,WORD\r
+\r
+; Call struct for DSKSTATCHK\r
+ PUBLIC DSKSTCALL\r
+DSKSTCALL DB DRDNDHL\r
+ DB 0\r
+ PUBLIC DSKSTCOM\r
+DSKSTCOM DB DEVRDND\r
+ I_AM DSKSTST,WORD\r
+ DB 8 DUP (0)\r
+ I_AM DSKCHRET,BYTE\r
+ short_addr DEVIOBUF\r
+ DW ? ; DOS segment set at Init\r
+ PUBLIC DSKSTCNT\r
+DSKSTCNT DW 1\r
+ DW 0\r
+\r
+; Days in year\r
+ i_am YRTAB,8\r
+ ORG $-CONSTRT-8\r
+ DB 200,166 ; Leap year\r
+ DB 200,165\r
+ DB 200,165\r
+ DB 200,165\r
+\r
+; Days of each month\r
+ i_am MONTAB,12\r
+ ORG $-CONSTRT-12\r
+ DB 31 ; January\r
+ DB 28 ; February--reset each \r
+ ; time year changes\r
+ DB 31 ; March\r
+ DB 30 ; April\r
+ DB 31 ; May\r
+ DB 30 ; June\r
+ DB 31 ; July\r
+ DB 31 ; August\r
+ DB 30 ; September\r
+ DB 31 ; October\r
+ DB 30 ; November\r
+ DB 31 ; December\r
+\r
+ IF NOT IBM\r
+ PUBLIC OEM_HANDLER\r
+OEM_HANDLER DD -1\r
+ ENDIF\r
+\r
+;WARNING For HIGHMEM version, these two vars must be at the end of the\r
+; Constants segment to prevent them getting overwritten.\r
+ I_AM CurrentPDB,WORD\r
+ i_am CreatePDB,BYTE ; flag for creating a process\r
+\r
+ PUBLIC LEAVEADDR\r
+LEAVEADDR LABEL WORD\r
+ short_addr LEAVE\r
+\r
+CONSTANTS ENDS\r
+\r
+SUBTTL Uninitialized data overlayed by initialization code\r
+PAGE\r
+DATA SEGMENT WORD PUBLIC 'DATA'\r
+; Init code overlaps with data area below\r
+\r
+ ORG 0\r
+ i_am INBUF,128\r
+ I_AM CONBUF,131 ; The rest of INBUF and console buffer\r
+ i_am TIMEBUF,6\r
+ I_AM DEVIOBUF,2 ; Buffer for I/O under file assignment\r
+ I_AM EXITHOLD,DWORD\r
+\r
+ PUBLIC DevFCB\r
+DEVFCB LABEL BYTE ; Uses NAME1, NAME2, NAME3 combined\r
+; WARNING.. do not alter size or relative location of the following 4 items\r
+; without first examining FCB_RENAME\r
+ I_AM NAME1,12 ; File name buffer\r
+ I_AM ATTRIB,BYTE\r
+ I_AM NAME2,13\r
+ I_AM NAME3,14\r
+\r
+ I_AM EXTFCB,BYTE\r
+\r
+; WARNING - the following two items are accessed as a word\r
+ I_AM CREATING,BYTE\r
+ I_AM DELALL,BYTE\r
+\r
+ I_AM FoundDel,BYTE\r
+\r
+ I_AM user_SP,WORD\r
+ I_AM user_SS,WORD\r
+ I_AM CONTSTK,WORD\r
+ I_AM SECCLUSPOS,BYTE ; Position of first sector \r
+ ; within cluster\r
+ I_AM DSKERR,BYTE\r
+ I_AM TRANS,BYTE\r
+ I_AM READOP,BYTE\r
+ I_AM THISDRV,BYTE\r
+ I_AM THISDPB,DWORD\r
+ I_AM CLUSFAC,BYTE\r
+\r
+; WARNING - the following two items are accessed as a word\r
+ I_AM DRIVESPEC,BYTE\r
+ I_AM ROOTSTART,BYTE\r
+\r
+ I_AM CLUSSPLIT,BYTE\r
+ i_am INSMODE,BYTE\r
+ I_AM CLUSSAVE,WORD\r
+ I_AM CLUSSEC,WORD\r
+ I_AM PREREAD,WORD ; 0 means preread; 1 means optional\r
+ I_AM FATBYT,WORD\r
+ I_AM DEVPT,DWORD\r
+ I_AM THISFCB,DWORD ; Address of user FCB\r
+\r
+ I_AM NEXTADD,WORD\r
+ I_AM RECPOS,4\r
+ I_AM RECCNT,WORD\r
+ I_AM LASTPOS,WORD\r
+ I_AM CLUSNUM,WORD\r
+ I_AM DIRSEC,WORD\r
+ I_AM DIRSTART,WORD\r
+ I_AM SECPOS,WORD ; Position of first sector accessed\r
+ I_AM VALSEC,WORD ; Number of valid (previously written)\r
+ ; sectors\r
+ I_AM BYTSECPOS,WORD ; Position of first byte within sector\r
+ I_AM BYTPOS,4 ; Byte position in file of access\r
+ I_AM BYTCNT1,WORD ; No. of bytes in first sector\r
+ I_AM BYTCNT2,WORD ; No. of bytes in last sector\r
+ I_AM SECCNT,WORD ; No. of whole sectors\r
+ I_AM ENTFREE,WORD\r
+ I_AM ENTLAST,WORD\r
+ I_AM NXTCLUSNUM,WORD\r
+ I_AM GROWCNT,DWORD\r
+ I_AM CURBUF,DWORD\r
+ I_AM VOLID,BYTE\r
+ I_AM NULLDEVPT,DWORD\r
+ I_AM CINSAV,DWORD\r
+ I_AM CINDSAV,BYTE\r
+ I_AM COUTDSAV,BYTE\r
+ I_AM COUTSAV,DWORD\r
+ PUBLIC SaveBX\r
+SaveBX DW ?\r
+ PUBLIC SaveDS\r
+SaveDS DW ?\r
+ I_AM ConC_spsave,WORD\r
+\r
+ I_AM exit_code,WORD ; exit code of last proc.\r
+ I_am exit_type,BYTE ; type of exit...\r
+\r
+ IF IBM\r
+;For 2.00 this pads the DOS so that on a 2 disk IBM PC with no\r
+;CONFIG.SYS file the space taken up by BIOS, DOS, res COMMAND is\r
+;about 24K\r
+IBMPAD DB 540h DUP(?)\r
+ ENDIF\r
+\r
+; make those pushes fast!!!\r
+EVEN\r
+ DB 0A0H DUP (?)\r
+ I_am AuxStack,0A0h\r
+ I_AM DSKSTACK,0A0h ; Stack space\r
+ PUBLIC IOSTACK\r
+IOSTACK LABEL BYTE\r
+\r
+ PUBLIC NSS\r
+NSS DW ?\r
+ PUBLIC NSP\r
+NSP DW ?\r
+\r
+PAGE\r
+ INCLUDE MSINIT.ASM\r
+\r
+\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a
\ No newline at end of file
--- /dev/null
+TITLE Standard MSDOS
+NAME MSDOS_2
+
+; Number of disk I/O buffers
+
+ INCLUDE STDSW.ASM
+ INCLUDE MSHEAD.ASM
+ INCLUDE MSDATA.ASM
+
+ END
+
+\1a
\ No newline at end of file
--- /dev/null
+; TITLE MSHEAD.ASM -- MS-DOS DEFINITIONS
+PAGE
+; MS-DOS High-performance operating system for the 8086 version 1.28
+; by Microsoft MSDOS development group:
+; Tim Paterson (Ret.)
+; Aaron Reynolds
+; Nancy Panners (Parenting)
+; Mark Zbikowski
+; Chris Peters (BIOS) (ret.)
+
+; ****************** Revision History *************************
+; >> EVERY change must noted below!! <<
+;
+; 0.34 12/29/80 General release, updating all past customers
+; 0.42 02/25/81 32-byte directory entries added
+; 0.56 03/23/81 Variable record and sector sizes
+; 0.60 03/27/81 Ctrl-C exit changes, including register save on user stack
+; 0.74 04/15/81 Recognize I/O devices with file names
+; 0.75 04/17/81 Improve and correct buffer handling
+; 0.76 04/23/81 Correct directory size when not 2^N entries
+; 0.80 04/27/81 Add console input without echo, Functions 7 & 8
+; 1.00 04/28/81 Renumber for general release
+; 1.01 05/12/81 Fix bug in `STORE'
+; 1.10 07/21/81 Fatal error trapping, NUL device, hidden files, date & time,
+; RENAME fix, general cleanup
+; 1.11 09/03/81 Don't set CURRENT BLOCK to 0 on open; fix SET FILE SIZE
+; 1.12 10/09/81 Zero high half of CURRENT BLOCK after all (CP/M programs don't)
+; 1.13 10/29/81 Fix classic "no write-through" error in buffer handling
+; 1.20 12/31/81 Add time to FCB; separate FAT from DPT; Kill SMALLDIR; Add
+; FLUSH and MAPDEV calls; allow disk mapping in DSKCHG; Lots
+; of smaller improvements
+; 1.21 01/06/82 HIGHMEM switch to run DOS in high memory
+; 1.22 01/12/82 Add VERIFY system call to enable/disable verify after write
+; 1.23 02/11/82 Add defaulting to parser; use variable escape character Don't
+; zero extent field in IBM version (back to 1.01!)
+; 1.24 03/01/82 Restore fcn. 27 to 1.0 level; add fcn. 28
+; 1.25 03/03/82 Put marker (00) at end of directory to speed searches
+; 1.26 03/03/82 Directory buffers searched as a circular queue, current buffer
+; is searched first when possible to minimize I/O
+; 03/03/82 STORE routine optimized to tack on partial sector tail as
+; full sector write when file is growing
+; 03/09/82 Multiple I/O buffers
+; 03/29/82 Two bugs: Delete all case resets search to start at beginning
+; of directory (infinite loop possible otherwise), DSKRESET
+; must invalidate all buffers (disk and directory).
+; 1.27 03/31/82 Installable device drivers
+; Function call 47 - Get pointer to device table list
+; Function call 48 - Assign CON AUX LIST
+; 04/01/82 Spooler interrupt (INT 28) added.
+; 1.28 04/15/82 DOS retructured to use ASSUMEs and PROC labels around system
+; call entries. Most CS relative references changed to SS
+; relative with an eye toward putting a portion of the DOS in
+; ROM. DOS source also broken into header, data and code pieces
+; 04/15/82 GETDMA and GETVECT calls added as 24 and 32. These calls
+; return the current values.
+; 04/15/82 INDOS flag implemented for interrupt processing along with
+; call to return flag location (call 29)
+; 04/15/82 Volume ID attribute added
+; 04/17/82 Changed ABORT return to user to a long ret from a long jump to
+; avoid a CS relative reference.
+; 04/17/82 Put call to STATCHK in dispatcher to catch ^C more often
+; 04/20/82 Added INT int_upooler into loop ^S wait
+; 04/22/82 Dynamic disk I/O buffer allocation and call to manage them
+; call 49.
+; 04/23/82 Added GETDSKPTDL as call 50, similar to GETFATPT(DL), returns
+; address of DPB
+; 04/29/82 Mod to WRTDEV to look for ^C or ^S at console input when
+; writting to console device via file I/O. Added a console
+; output attribute to devices.
+; 04/30/82 Call to en/dis able ^C check in dispatcher Call 51
+; 04/30/82 Code to allow assignment of func 1-12 to disk files as well
+; as devices.... pipes, redirection now possible
+; 04/30/82 Expanded GETLIST call to 2.0 standard
+; 05/04/82 Change to INT int_fatal_abort callout int HARDERR. DOS SS
+; (data segment) stashed in ES, INT int_fatal_abort routines must
+; preserve ES. This mod so HARDERR can be ROMed.
+; 1.29 06/01/82 Installable block and character devices as per 2.0 spec
+; 06/04/82 Fixed Bug in CLOSE regarding call to CHKFATWRT. It got left
+; out back about 1.27 or so (oops). ARR
+; 1.30 06/07/82 Directory sector buffering added to main DOS buffer queue
+; 1.40 06/15/82 Tree structured directories. XENIX Path Parser MKDIR CHDIR
+; RMDIR Xenix calls
+; 1.41 06/13/82 Made GETBUFFR call PLACEBUF
+; 1.50 06/17/82 FATs cached in buffer pool, get FAT pointer calls disappear
+; Frees up lots of memory.
+; 1.51 06/24/82 BREAKDOWN modified to do EXACT one sector read/write through
+; system buffers
+; 1.52 06/30/82 OPEN, CLOSE, READ, WRITE, DUP, DUP2, LSEEK implemented
+; 1.53 07/01/82 OPEN CLOSE mod for Xenix calls, saves and gets remote dir
+; 1.54 07/11/82 Function calls 1-12 make use of new 2.0 PDB. Init code
+; changed to set file handle environment.
+; 2.00 08/01/82 Number for IBM release
+; 01/19/83 No environ bug in EXEC
+; 01/19/83 MS-DOS OEM INT 21 extensions (SET_OEM_HANDLER)
+; 01/19/83 Performance bug fix in cooked write to NUL
+; 01/27/83 Growcnt fixed for 32-bits
+; 01/27/83 Find-first problem after create
+; 2.01 02/17/83 International DOS
+; 2.11 08/12/83 Dos split into several more modules for assembly on
+; an IBM PC
+;
+; *************************************************************
+
+
+SUBTTL EQUATES
+PAGE
+; Interrupt Entry Points:
+
+; INTBASE: ABORT
+; INTBASE+4: COMMAND
+; INTBASE+8: BASE EXIT ADDRESS
+; INTBASE+C: CONTROL-C ABORT
+; INTBASE+10H: FATAL ERROR ABORT
+; INTBASE+14H: BIOS DISK READ
+; INTBASE+18H: BIOS DISK WRITE
+; INTBASE+1CH: END BUT STAY RESIDENT (NOT SET BY DOS)
+; INTBASE+20H: SPOOLER INTERRUPT
+; INTBASE+40H: Long jump to CALL entry point
+
+ENTRYPOINTSEG EQU 0CH
+MAXDIF EQU 0FFFH
+SAVEXIT EQU 10
+
+ INCLUDE DOSSYM.ASM
+ INCLUDE DEVSYM.ASM
+
+SUBTTL ^C, terminate/abort/exit and Hard error actions
+PAGE
+;
+; There are three kinds of context resets that can occur during normal DOS
+; functioning: ^C trap, terminate/abort/exit, and Hard-disk error. These must
+; be handles in a clean fashion that allows nested executions along with the
+; ability to trap one's own errors.
+;
+; ^C trap - A process may elect to catch his own ^Cs. This is achieved by
+; using the $GET_INTERRUPT_VECTOR and $SET_INTERRUPT_VECTOR as
+; follows:
+;
+; $GET_INTERRUPT_VECTOR for INT int_ctrl_c
+; Save it in static memory.
+; $SET_INTERRUPT_VECTOR for INT int_ctrl_c
+;
+; The interrupt service routine must preserve all registers and
+; return carry set iff the operation is to be aborted (via abort
+; system call), otherwise, carry is reset and the operation is
+; restarted. ANY DEVIATION FROM THIS WILL LEAD TO UNRELIABLE
+; RESULTS.
+;
+; To restore original ^C processing (done on terminate/abort/exit),
+; restore INT int_ctrl_c from the saved vector.
+;
+; Hard-disk error -- The interrupt service routine for INT int_fatal_abort must
+; also preserve registers and return one of three values in AL: 0 and
+; 1 imply retry and ignore (???) and 2 indicates an abort. The user
+; himself is not to issue the abort, rather, the dos will do it for
+; him by simulating a normal abort/exit system call. ANY DEVIATION
+; FROM THIS WILL LEAD TO UNRELIABLE RESULTS.
+;
+; terminate/abort/exit -- The user may not, under any circumstances trap an
+; abort call. This is reserved for knowledgeable system programs.
+; ANY DEVIATION FROM THIS WILL LEAD TO UNRELIABLE RESULTS.
+
+SUBTTL SEGMENT DECLARATIONS
+PAGE
+
+; The following are all of the segments used. They are declared in the order
+; that they should be placed in the executable
+
+;
+; segment ordering for MSDOS
+;
+
+START SEGMENT BYTE PUBLIC 'START'
+START ENDS
+
+CONSTANTS SEGMENT BYTE PUBLIC 'CONST'
+CONSTANTS ENDS
+
+DATA SEGMENT WORD PUBLIC 'DATA'
+DATA ENDS
+
+CODE SEGMENT BYTE PUBLIC 'CODE'
+CODE ENDS
+
+LAST SEGMENT BYTE PUBLIC 'LAST'
+LAST ENDS
+
+DOSGROUP GROUP CODE,CONSTANTS,DATA,LAST
+
+; The following segment is defined such that the data/const classes appear
+; before the code class for ROMification
+
+START SEGMENT BYTE PUBLIC 'START'
+ ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
+ JMP DOSINIT
+START ENDS
+
+\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a
\ No newline at end of file
--- /dev/null
+; TITLE MSINIT.ASM -- MS-DOS INITIALIZATION CODE\r
+\r
+ ORG 0 ; reset to beginning of data segment\r
+; Init code below overlaps with data area\r
+\r
+INITBLOCK DB 110H DUP(0) ; Allow for segment round up\r
+\r
+INITSP DW ?\r
+INITSS DW ?\r
+BUFFSTRT DW ?\r
+\r
+ASSUME CS:DOSGROUP,DS:DOSGROUP,ES:DOSGROUP,SS:NOTHING\r
+\r
+ EXTRN QUIT:NEAR,IRET:NEAR,ABSDRD:FAR,ABSDWRT:FAR\r
+ EXTRN COMMAND:NEAR,CALL_ENTRY:NEAR\r
+ IF NOT IBM\r
+ EXTRN HEADER:BYTE\r
+ ENDIF\r
+\r
+MOVDPB:\r
+; This section of code is safe from being overwritten by block move\r
+ MOV SP,CS:[INITSP]\r
+ MOV SS,CS:[INITSS]\r
+ REP MOVS BYTE PTR [DI],[SI]\r
+ CLD\r
+ MOV WORD PTR ES:[DMAADD+2],DX\r
+ MOV SI,WORD PTR [DPBHEAD] ; Address of first DPB\r
+ MOV WORD PTR ES:[DPBHEAD+2],ES\r
+ MOV WORD PTR ES:[sft_addr+2],ES\r
+ MOV CL,[NUMIO] ; Number of DPBs\r
+ XOR CH,CH\r
+SETFINDPB:\r
+ MOV WORD PTR ES:[SI.dpb_next_dpb+2],ES\r
+ MOV ES:[SI.dpb_first_access],-1 ; Never accessed before\r
+ ADD SI,DPBSIZ ; Point to next DPB\r
+ LOOP SETFINDPB\r
+ SUB SI,DPBSIZ\r
+ MOV WORD PTR ES:[SI.dpb_next_dpb+2],-1\r
+ MOV DI,[BUFFSTRT] ; Set up one default buffer\r
+ MOV WORD PTR ES:[BUFFHEAD+2],ES\r
+ MOV WORD PTR ES:[BUFFHEAD],DI\r
+ MOV WORD PTR ES:[DI.BUFDRV],00FFH\r
+ MOV ES:[DI.BUFPRI],FREEPRI\r
+ MOV WORD PTR ES:[DI.NEXTBUF],-1\r
+ MOV WORD PTR ES:[DI.NEXTBUF+2],-1\r
+ PUSH ES\r
+ INC DX ; Leave enough room for the ARENA\r
+ MOV BYTE PTR [CreatePDB],0FFh ; create jfns and set CurrentPDB\r
+ invoke $CREATE_PROCESS_DATA_BLOCK ; Set up segment\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+ POP ES\r
+ASSUME ES:DOSGROUP\r
+\r
+;\r
+; set up memory arena\r
+;SPECIAL NOTE FOR HIGHMEM VERSION\r
+; At this point a process header has been built where the start of the \r
+; CONSTANTS segment as refed by CS is. From this point until the return \r
+; below be careful about references off of CS.\r
+;\r
+ PUSH AX\r
+ MOV AX,[CurrentPDB]\r
+ MOV ES:[CurrentPDB],AX ; Put it in the REAL location\r
+ MOV BYTE PTR ES:[CreatePDB],0h ; reset flag in REAL location\r
+ DEC AX\r
+ MOV ES:[arena_head],AX\r
+ PUSH DS\r
+ MOV DS,AX\r
+ MOV DS:[arena_signature],arena_signature_end\r
+ MOV DS:[arena_owner],arena_owner_system\r
+ SUB AX,ES:[ENDMEM]\r
+ NEG AX\r
+ DEC AX\r
+ MOV DS:[arena_size],AX\r
+ POP DS\r
+ POP AX\r
+\r
+ MOV DI,OFFSET DOSGROUP:sftabl + sft_table ; Point to sft 0\r
+ MOV AL,3\r
+ STOSB ; Adjust Refcount\r
+ MOV DI,OFFSET DOSGROUP:SYSINITVAR\r
+\r
+XXX PROC FAR\r
+ RET\r
+XXX ENDP\r
+DATA ENDS\r
+\r
+; the next segment defines a new class that MUST appear last in the link map.\r
+; This defines several important locations for the initialization process that\r
+; must be the first available locations of free memory.\r
+\r
+LAST SEGMENT BYTE PUBLIC 'LAST'\r
+ PUBLIC SYSBUF\r
+ PUBLIC MEMSTRT\r
+\r
+SYSBUF LABEL WORD\r
+ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING\r
+\r
+DOSINIT:\r
+ CLI\r
+ CLD\r
+ MOV [ENDMEM],DX\r
+ MOV [INITSP],SP\r
+ MOV [INITSS],SS\r
+ MOV SP,OFFSET DOSGROUP:INITSTACK\r
+ MOV AX,CS\r
+ MOV SS,AX\r
+ASSUME SS:DOSGROUP\r
+ MOV WORD PTR [DEVHEAD+2],DS\r
+ MOV WORD PTR [DEVHEAD],SI ; DS:SI Points to CONSOLE Device\r
+ CALL CHARINIT\r
+ PUSH SI\r
+ ADD SI,SDEVNAME ; Point to name\r
+ PUSH CS\r
+ POP ES\r
+ASSUME ES:DOSGROUP\r
+ MOV DI,OFFSET DOSGROUP:sftabl + sft_table ; Point to sft 0\r
+ MOV AL,3\r
+ STOSB ; Refcount\r
+ DEC AL\r
+ STOSB ; Access rd/wr\r
+ XOR AL,AL\r
+ STOSB ; Drive byte\r
+ STOSB ; attribute\r
+ MOV CX,4\r
+ REP MOVSW ; Name\r
+ MOV CL,3\r
+ MOV AL," "\r
+ REP STOSB ; Extension\r
+ ADD DI,12 ; Skip\r
+ MOV AL,0C0H OR ISCIN OR ISCOUT\r
+ STOSB\r
+ POP SI\r
+ MOV AX,SI\r
+ STOSW ; Device pointer in FIRCLUS\r
+ MOV AX,DS\r
+ STOSW\r
+ OR BYTE PTR [SI.SDEVATT],ISCIN OR ISCOUT\r
+ MOV WORD PTR [BCON],SI\r
+ MOV WORD PTR [BCON+2],DS\r
+CHAR_INIT_LOOP:\r
+ LDS SI,DWORD PTR [SI] ; AUX device\r
+ CALL CHARINIT\r
+ TEST BYTE PTR [SI.SDEVATT],ISCLOCK\r
+ JZ CHAR_INIT_LOOP\r
+ MOV WORD PTR [BCLOCK],SI\r
+ MOV WORD PTR [BCLOCK+2],DS\r
+ MOV BP,OFFSET DOSGROUP:MEMSTRT ; ES:BP points to DPB\r
+PERDRV:\r
+ LDS SI,DWORD PTR [SI] ; Next device\r
+ CMP SI,-1\r
+ JZ CONTINIT\r
+ CALL CHARINIT\r
+ TEST [SI.SDEVATT],DEVTYP\r
+ JNZ PERDRV ; Skip any other character devs\r
+ MOV CL,[CALLUNIT]\r
+ XOR CH,CH\r
+ MOV [SI.SDEVNAME],CL ; Number of units in name field\r
+ MOV DL,[NUMIO]\r
+ XOR DH,DH\r
+ ADD [NUMIO],CL\r
+ PUSH DS\r
+ PUSH SI\r
+ LDS BX,[CALLBPB]\r
+PERUNIT:\r
+ MOV SI,[BX] ; DS:SI Points to BPB\r
+ INC BX\r
+ INC BX ; On to next BPB\r
+ MOV ES:[BP.dpb_drive],DL\r
+ MOV ES:[BP.dpb_UNIT],DH\r
+ PUSH BX\r
+ PUSH CX\r
+ PUSH DX\r
+ invoke $SETDPB\r
+ MOV AX,ES:[BP.dpb_sector_size]\r
+ CMP AX,[MAXSEC]\r
+ JBE NOTMAX\r
+ MOV [MAXSEC],AX\r
+NOTMAX:\r
+ POP DX\r
+ POP CX\r
+ POP BX\r
+ MOV AX,DS ; Save DS\r
+ POP SI\r
+ POP DS\r
+ MOV WORD PTR ES:[BP.dpb_driver_addr],SI\r
+ MOV WORD PTR ES:[BP.dpb_driver_addr+2],DS\r
+ PUSH DS\r
+ PUSH SI\r
+ INC DH\r
+ INC DL\r
+ MOV DS,AX\r
+ ADD BP,DPBSIZ\r
+ LOOP PERUNIT\r
+ POP SI\r
+ POP DS\r
+ JMP PERDRV\r
+\r
+CONTINIT:\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+; Calculate true address of buffers, FATs, free space\r
+ MOV DI,BP ; First byte after current DPBs\r
+ MOV BP,[MAXSEC]\r
+ MOV AX,OFFSET DOSGROUP:SYSBUF\r
+ MOV [BUFFSTRT],AX\r
+ ADD AX,BP ; One I/O buffer\r
+ ADD AX,BUFINSIZ\r
+ MOV WORD PTR [DPBHEAD],AX ; True start of DPBs\r
+ MOV DX,AX\r
+ SUB DX,OFFSET DOSGROUP:SYSBUF\r
+ MOV BP,DX\r
+ ADD BP,DI ; Allocate buffer space\r
+ SUB BP,ADJFAC ; True address of free memory\r
+ PUSH BP\r
+ MOV DI,OFFSET DOSGROUP:MEMSTRT ; Current start of DPBs\r
+ ADD DI,dpb_next_dpb ; Point at dpb_next_dpb field\r
+ MOV CL,[NUMIO]\r
+ XOR CH,CH\r
+TRUEDPBAD:\r
+ ADD AX,DPBSIZ ; Compute address of next DPB\r
+ STOSW ; Set the link to next DPB\r
+ ADD DI,DPBSIZ-2 ; Point at next address\r
+ LOOP TRUEDPBAD\r
+ SUB DI,DPBSIZ ; Point at last dpb_next_dpb field\r
+ MOV AX,-1\r
+ STOSW ; End of list\r
+ ADD BP,15 ;True start of free space (round up to segment)\r
+ MOV CL,4\r
+ SHR BP,CL ; Number of segments for DOS resources\r
+ MOV DX,CS\r
+ ADD DX,BP ; First free segment\r
+ MOV BX,0FH\r
+ MOV CX,[ENDMEM]\r
+\r
+ IF HIGHMEM\r
+ SUB CX,BP\r
+ MOV BP,CX ; Segment of DOS\r
+ MOV DX,CS ; Program segment\r
+ ENDIF\r
+\r
+ IF NOT HIGHMEM\r
+ MOV BP,CS\r
+ ENDIF\r
+\r
+; BP has segment of DOS (whether to load high or run in place)\r
+; DX has program segment (whether after DOS or overlaying DOS)\r
+; CX has size of memory in paragraphs (reduced by DOS size if HIGHMEM)\r
+ MOV [ENDMEM],CX\r
+ MOV ES,BP\r
+ASSUME ES:DOSGROUP\r
+\r
+ IF HIGHMEM\r
+ XOR SI,SI\r
+ MOV DI,SI\r
+ MOV CX,OFFSET DOSGROUP:SYSBUF ;# bytes to move\r
+ SHR CX,1 ;# words to move (carry set if odd)\r
+ REP MOVSW ; Move DOS to high memory\r
+ JNC NOTODD\r
+ MOVSB\r
+NOTODD:\r
+ ENDIF\r
+\r
+ MOV WORD PTR ES:[DSKCHRET+3],ES\r
+ XOR AX,AX\r
+ MOV DS,AX\r
+ MOV ES,AX\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+ MOV DI,INTBASE+2\r
+ MOV AX,BP\r
+ MOV BYTE PTR DS:[ENTRYPOINT],mi_Long_JMP\r
+ MOV WORD PTR DS:[ENTRYPOINT+1],OFFSET DOSGROUP:CALL_ENTRY\r
+ MOV WORD PTR DS:[ENTRYPOINT+3],AX\r
+ EXTRN DIVOV:near\r
+ MOV WORD PTR DS:[0],OFFSET DOSGROUP:DIVOV ; Set default divide \r
+ ; trap address\r
+ MOV DS:[2],AX\r
+ MOV CX,17\r
+ REP STOSW ; Set 9 segments (skip 2 between each)\r
+\r
+ IF ALTVECT\r
+ MOV DI,ALTBASE+2\r
+ MOV CX,15\r
+ REP STOSW ; Set 8 segments (skip 2 between each)\r
+ ENDIF\r
+\r
+ MOV WORD PTR DS:[addr_int_abort],OFFSET DOSGROUP:QUIT\r
+ MOV WORD PTR DS:[addr_int_command],OFFSET DOSGROUP:COMMAND\r
+ MOV WORD PTR DS:[addr_int_terminate],100H\r
+ MOV WORD PTR DS:[addr_int_terminate+2],DX\r
+ MOV WORD PTR DS:[addr_int_ctrl_c],OFFSET DOSGROUP:IRET \r
+ ; Ctrl-C exit\r
+ MOV WORD PTR DS:[addr_int_fatal_abort],OFFSET DOSGROUP:IRET\r
+ ; Fatal error exit\r
+ MOV WORD PTR DS:[addr_int_disk_read],OFFSET DOSGROUP:ABSDRD\r
+ ; INT 25\r
+ MOV WORD PTR DS:[addr_int_disk_write],OFFSET DOSGROUP:ABSDWRT\r
+ ; INT 26\r
+ EXTRN Stay_resident:NEAR\r
+ MOV WORD PTR DS:[addr_int_keep_process],OFFSET DOSGROUP:Stay_resident\r
+ MOV WORD PTR DS:[addr_int_spooler],OFFSET DOSGROUP:IRET ; Spooler\r
+\r
+ IF NOT ALTVECT\r
+ MOV CX,12\r
+ XOR AX,AX\r
+ MOV DI,2AH*4\r
+ REP STOSW ;Zero interrupt locs for ints 2AH-2FH\r
+ ENDIF\r
+\r
+ PUSH CS\r
+ POP DS\r
+ PUSH CS\r
+ POP ES\r
+ASSUME DS:DOSGROUP,ES:DOSGROUP\r
+ MOV AX,OFFSET DOSGROUP:INITBLOCK\r
+ ADD AX,0Fh ; round to a paragraph\r
+ MOV CL,4\r
+ SHR AX,CL\r
+ MOV DI,DS\r
+ ADD DI,AX\r
+ INC DI\r
+ MOV [CurrentPDB],DI\r
+ PUSH BP\r
+ PUSH DX ; Save COMMAND address\r
+ MOV AX,[ENDMEM]\r
+ MOV DX,DI\r
+\r
+ invoke SETMEM ; Basic Header\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:DOSGROUP\r
+ MOV DI,PDB_JFN_Table\r
+ XOR AX,AX\r
+ STOSW\r
+ STOSB ; 0,1 and 2 are CON device\r
+ MOV AL,0FFH\r
+ MOV CX,FilPerProc - 3\r
+ REP STOSB ; Rest are unused\r
+ PUSH CS\r
+ POP ES\r
+ASSUME ES:DOSGROUP\r
+ MOV WORD PTR [sft_addr+2],DS ; Must be set to print messages\r
+\r
+; After this points the char device functions for CON will work for\r
+; printing messages\r
+\r
+ IF NOT IBM\r
+ IF NOT ALTVECT\r
+ MOV SI,OFFSET DOSGROUP:HEADER\r
+ invoke OUTMES\r
+ PUSH CS ; Outmes stomps on segments\r
+ POP DS\r
+ PUSH CS\r
+ POP ES\r
+ ENDIF\r
+ ENDIF\r
+\r
+; Move the FATs into position\r
+ POP DX ; Restore COMMAND address\r
+ POP BP\r
+ POP CX ; True address of free memory\r
+ MOV SI,OFFSET DOSGROUP:MEMSTRT ; Place to move DPBs from\r
+ MOV DI,WORD PTR [DPBHEAD] ; Place to move DPBs to\r
+ SUB CX,DI ; Total length of DPBs\r
+ CMP DI,SI\r
+ JBE MOVJMP ; Are we moving to higher or \r
+ ; lower memory?\r
+ DEC CX ; Move backwards to higher memory\r
+ ADD DI,CX\r
+ ADD SI,CX\r
+ INC CX\r
+ STD\r
+MOVJMP:\r
+ MOV ES,BP\r
+ASSUME ES:DOSGROUP\r
+ JMP MOVDPB\r
+\r
+CHARINIT:\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+; DS:SI Points to device header\r
+ MOV [DEVCALL.REQLEN],DINITHL\r
+ MOV [DEVCALL.REQUNIT],0\r
+ MOV [DEVCALL.REQFUNC],DEVINIT\r
+ MOV [DEVCALL.REQSTAT],0\r
+ PUSH ES\r
+ PUSH BX\r
+ PUSH AX\r
+ MOV BX,OFFSET DOSGROUP:DEVCALL\r
+ PUSH CS\r
+ POP ES\r
+ invoke DEVIOCALL2\r
+ POP AX\r
+ POP BX\r
+ POP ES\r
+ RET\r
+\r
+ DB 80H DUP(?)\r
+INITSTACK LABEL BYTE\r
+ DW ?\r
+\r
+MEMSTRT LABEL WORD\r
+ADJFAC EQU MEMSTRT-SYSBUF\r
+\r
+ do_ext\r
+LAST ENDS\r
+\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a
\ No newline at end of file
--- /dev/null
+;MS-DOS PRINT program for background printing of text files to the list\r
+; device. INT 28H is a software interrupt generated by the DOS\r
+; in its I/O wait loops. This spooler can be assembled for\r
+; operation using only this interrupt which is portable from\r
+; system to system. It may also be assembled to use a hardware\r
+; timer interrupt in addition to the software INT 28H. The\r
+; purpose of using hardware interrupts is to allow printing to\r
+; continue during programs which do not enter the system and\r
+; therefore causes the INT 28H to go away. A timer interrupt is\r
+; chosen in preference to a "printer buffer empty" interrupt\r
+; because PRINT in the timer form is generic. It can be given\r
+; the name of any currently installed character device as the\r
+; "printer", this makes it portable to devices which are\r
+; installed by the user even in the hardware case. It could be\r
+; modified to use a buffer empty interrupt (no code is given for\r
+; this case), if this is done the PROMPT and BADMES messages and\r
+; their associated code should be removed as PRINT will then be\r
+; device specific.\r
+;\r
+; VERSION 1.00 07/03/82\r
+\r
+\r
+FALSE EQU 0\r
+TRUE EQU NOT FALSE\r
+\r
+IBM EQU FALSE\r
+IBMVER EQU IBM\r
+MSVER EQU TRUE\r
+\r
+ IF MSVER\r
+HARDINT EQU FALSE ;No hardware ints\r
+AINT EQU FALSE ;No need to do interrupt acknowledge\r
+ ENDIF\r
+\r
+ IF IBM\r
+HARDINT EQU TRUE\r
+INTLOC EQU 1CH ;Hardware interrupt location (Timer)\r
+AINT EQU TRUE ;Acknowledge interrupts\r
+EOI EQU 20H ;End Of Interrupt "instruction"\r
+AKPORT EQU 20H ;Interrupt Acknowledge port\r
+ ENDIF\r
+\r
+;The following values have to do with the ERRCNT variable and the\r
+; CNTMES message. The values define levels at wich it is assumed\r
+; an off-line error exists. ERRCNT1 defines the value of ERRCNT above\r
+; which the CNTMES message is printed by the transient. ERRCNT2\r
+; defines the value of ERRCNT above which the resident will give up\r
+; trying to print messages on the printer, it is much greater than\r
+; ERRCNT1 because a much tighter loop is involved. The bounding event\r
+; which determines the correct value is the time required to do a\r
+; form feed.\r
+\r
+ IF IBM\r
+ERRCNT1 EQU 1000\r
+ERRCNT2 EQU 20000\r
+ ELSE\r
+ERRCNT1 EQU 1000\r
+ERRCNT2 EQU 20000\r
+ ENDIF\r
+\r
+ IF HARDINT\r
+TIMESLICE EQU 8 ;The PRINT scheduling time slice. PRINT\r
+ ; lets this many "ticks" go by before\r
+ ; using a time slice to pump out characters.\r
+ ; Setting this to 3 for instance means PRINT\r
+ ; Will skip 3 slices, then take the fourth.\r
+ ; Thus using up 1/4 of the CPU. Setting it\r
+ ; to one gives PRINT 1/2 of the CPU.\r
+ ; The above examples assume MAXTICK is\r
+ ; 1. The actual PRINT CPU percentage is\r
+ ; (MAXTICK/(1+TIMESLICE))*100\r
+\r
+MAXTICK EQU 2 ;The PRINT in timeslice. PRINT will pump\r
+ ; out characters for this many clock ticks\r
+ ; and then exit. The selection of a value\r
+ ; for this is dependent on the timer rate.\r
+\r
+BUSYTICK EQU 1 ;If PRINT sits in a wait loop waiting for\r
+ ; output device to come ready for this\r
+ ; many ticks, it gives up its time slice.\r
+ ; Setting it greater than or equal to\r
+ ; MAXTICK causes it to be ignored.\r
+\r
+;User gets TIMESLICE ticks and then PRINT takes MAXTICK ticks unless BUSYTICK\r
+; ticks go by without getting a character out.\r
+ ENDIF\r
+\r
+\r
+;WARNING DANGER WARNING:\r
+; PRINT is a systems utility. It is clearly understood that it may have\r
+; to be entirely re-written for future versions of MS-DOS. The following\r
+; TWO vectors are version specific, they may not exist at all in future\r
+; versions. If they do exist, they may function differently.\r
+; ANY PROGRAM WHICH IMITATES PRINTS USE OF THESE VECTORS IS ALSO A SYSTEMS\r
+; UTILITY AND IS THEREFORE NOT VERSION PORTABLE IN ANY WAY SHAPE OR FORM.\r
+; YOU HAVE BEEN WARNED, "I DID IT THE SAME WAY PRINT DID" IS NOT AN REASON\r
+; TO EXPECT A PROGRAM TO WORK ON FUTURE VERSIONS OF MS-DOS.\r
+SOFTINT EQU 28H ;Software interrupt generated by DOS\r
+COMINT EQU 2FH ;Communications interrupt used by PRINT\r
+ ; This vector number is DOS reserved. It\r
+ ; is not generally available to programs\r
+ ; other than PRINT.\r
+\r
+BLKSIZ EQU 512 ;Size of the PRINT I/O block in bytes\r
+FCBSIZ EQU 40 ;Size of an FCB\r
+\r
+ INCLUDE DOST:DOSSYM.ASM\r
+\r
+FCB EQU 5CH\r
+PARMS EQU 80H\r
+\r
+DG GROUP CODE,DATA\r
+\r
+CODE SEGMENT\r
+ASSUME CS:DG\r
+\r
+ ORG 100H\r
+START:\r
+ JMP TRANSIENT\r
+\r
+HEADER DB "Vers 1.00"\r
+\r
+ DB 128 DUP (?)\r
+ISTACK LABEL WORD ;Stack starts here and grows down\r
+\r
+;Resident data\r
+\r
+ IF HARDINT\r
+INDOS DD ? ;DOS buisy flag\r
+NEXTINT DD ? ;Chain for int\r
+BUSY DB 0 ;Internal ME flag\r
+SOFINT DB 0 ;Internal ME flag\r
+TICKCNT DB 0 ;Tick counter\r
+TICKSUB DB 0 ;Tick miss counter\r
+SLICECNT DB TIMESLICE ;Time slice counter\r
+ ENDIF\r
+\r
+CBUSY DB 0 ;ME on com interrupt\r
+SPNEXT DD ? ;Chain location for INT 28\r
+PCANMES DB 0 ;Cancel message flag\r
+SSsave DW ? ;Stack save area for INT 24\r
+SPsave DW ?\r
+DMAADDR DD ? ;Place to save DMA address\r
+HERRINT DD ? ;Place to save Hard error interrupt\r
+LISTDEV DD ? ;Pointer to Device\r
+COLPOS DB 0 ;Column position for TAB processing\r
+NXTCHR DW OFFSET DG:BUFFER + BLKSIZ ;Buffer pointer\r
+CURRFIL DW OFFSET DG:SPLFCB ;Current file being printed\r
+\r
+LASTFCB DW ? ;Back pointer\r
+LASTFCB2 DW ? ;Another back pointer\r
+PABORT DB 0 ;Abort flag\r
+\r
+;Resident messages\r
+\r
+ERRMES DB 13,10,13,10,"**********",13,10,"$"\r
+ERRMEST DB " error reading file",13,10\r
+EMFILNAM DB " : . "\r
+BELMES DB 13,0CH,7,"$"\r
+\r
+CANMES DB 13,10,13,10\r
+CANFILNAM DB " : . "\r
+ DB " Canceled by operator$"\r
+\r
+ALLCAN DB 13,10,13,10,"All files canceled by operator$"\r
+\r
+MESBAS DW OFFSET DG:ERR0\r
+ DW OFFSET DG:ERR1\r
+ DW OFFSET DG:ERR2\r
+ DW OFFSET DG:ERR3\r
+ DW OFFSET DG:ERR4\r
+ DW OFFSET DG:ERR5\r
+ DW OFFSET DG:ERR6\r
+ DW OFFSET DG:ERR7\r
+ DW OFFSET DG:ERR8\r
+ DW OFFSET DG:ERR9\r
+ DW OFFSET DG:ERR10\r
+ DW OFFSET DG:ERR11\r
+ DW OFFSET DG:ERR12\r
+\r
+;INT 24 messages A La COMMAND\r
+\r
+ERR0 DB "Write protect$"\r
+ERR1 DB "Bad unit$"\r
+ERR2 DB "Not ready$"\r
+ERR3 DB "Bad command$"\r
+ERR4 DB "Data$"\r
+ERR5 DB "Bad call format$"\r
+ERR6 DB "Seek$"\r
+ERR7 DB "Non-DOS disk$"\r
+ERR8 DB "Sector not found$"\r
+ERR9 DB "No paper$"\r
+ERR10 DB "Write fault$"\r
+ERR11 DB "Read fault$"\r
+ERR12 DB "Disk$"\r
+\r
+FATMES DB "File allocation table bad drive "\r
+BADDRVM DB "A.",13,10,"$"\r
+\r
+;The DATA buffer\r
+BUFFER DB BLKSIZ DUP(0)\r
+ DB ?\r
+CODE ENDS\r
+\r
+;Transient data\r
+\r
+DATA SEGMENT BYTE\r
+ ORG 0\r
+SWITCHAR DB ? ;User switch character\r
+FULLFLAG DB 0 ;Flag for printing queue full message\r
+MAKERES DB 0 ;Flag to indicate presence of resident\r
+ARGSETUP DB 0 ;Flag to indicate a formatted FCB exists at 5C\r
+DEFDRV DB 0 ;Default drive\r
+CANFLG DB 0 ;Flag to indicate cancel\r
+FILCNT DB 0 ;Number of files\r
+SPLIST DD ? ;Pointer to FCBs in resident\r
+CURFILE DD ? ;Pointer to current FCB\r
+SRCHFCB DB 38 DUP (0) ;SEARCH-FIRST/NEXT FCB\r
+ENDRES DW OFFSET DG:DEF_ENDRES ;Term-Res location\r
+\r
+;Messages\r
+\r
+NOFILS DB "PRINT queue is empty",13,10,"$"\r
+CURMES DB 13,10," "\r
+CURFNAM DB " : . is currently being printed",13,10,"$"\r
+FILMES DB " "\r
+FILFNAM DB " : . is in queue"\r
+CRLF DB 13,10,"$"\r
+OPMES DB "Cannot open "\r
+OPFILNAM DB " : . ",13,10,"$"\r
+FULLMES DB "PRINT queue is full",13,10,"$"\r
+SRCHMES LABEL BYTE\r
+SRCHFNAM DB " : . "," File not found",13,10,"$"\r
+BADMES DB "List output is not assigned to a device",13,10,"$"\r
+GOODMES DB "Resident part of PRINT installed",13,10,"$"\r
+PROMPT DB "Name of list device [PRN]: $"\r
+CNTMES DB "Errors on list device indicate that it",13,10\r
+ DB "may be off-line. Please check it.",13,10,13,10,"$"\r
+BADSWT DB "Invalid parameter",13,10,"$"\r
+\r
+\r
+BADVER DB "Incorrect DOS version",13,10,"$"\r
+\r
+ IF IBM\r
+;Reserved names for parallel card\r
+INT_17_HITLIST LABEL BYTE\r
+ DB 8,"PRN ",0\r
+ DB 8,"LPT1 ",0\r
+ DB 8,"LPT2 ",1\r
+ DB 8,"LPT3 ",2\r
+ DB 0\r
+;Reserved names for Async adaptor\r
+INT_14_HITLIST LABEL BYTE\r
+ DB 8,"AUX ",0\r
+ DB 8,"COM1 ",0\r
+ DB 8,"COM2 ",1\r
+ DB 0\r
+ ENDIF\r
+\r
+COMBUF DB 14,0 ;Device name buffer\r
+ DB 14 DUP (?)\r
+LISTFCB DB 0,"PRN " ;Device name FCB\r
+ DB 25 DUP (0)\r
+PARSEBUF DB 80 DUP (?) ;Parsing space\r
+\r
+DATA ENDS\r
+\r
+CODE SEGMENT\r
+ASSUME CS:DG,DS:DG,ES:DG,SS:DG\r
+\r
+\r
+;Interrupt routines\r
+ASSUME CS:DG,DS:NOTHING,ES:NOTHING,SS:NOTHING\r
+ IF HARDINT\r
+HDSPINT: ;Hardware interrupt entry point\r
+ INC [TICKCNT] ;Tick\r
+ INC [TICKSUB] ;Tick\r
+ CMP [SLICECNT],0\r
+ JZ TIMENOW\r
+ DEC [SLICECNT] ;Count down\r
+ JMP SHORT CHAININT ;Not time yet\r
+TIMENOW:\r
+ CMP [BUSY],0 ;See if interrupting ourself\r
+ JNZ CHAININT\r
+ PUSH DS\r
+ PUSH SI\r
+ LDS SI,[INDOS] ;Check for making DOS calls\r
+ CMP BYTE PTR [SI],0\r
+ POP SI\r
+ POP DS\r
+ JNZ CHAININT ;DOS is Buisy\r
+ INC [BUSY] ;Exclude furthur interrupts\r
+ MOV [TICKCNT],0 ;Reset tick counter\r
+ MOV [TICKSUB],0 ;Reset tick counter\r
+ STI ;Keep things rolling\r
+\r
+ IF AINT\r
+ MOV AL,EOI ;Acknowledge interrupt\r
+ OUT AKPORT,AL\r
+ ENDIF\r
+\r
+ CALL DOINT\r
+ CLI\r
+ MOV [SLICECNT],TIMESLICE ;Either soft or hard int resets time slice\r
+ MOV [BUSY],0 ;Done, let others in\r
+CHAININT:\r
+ JMP [NEXTINT] ;Chain to next clock routine\r
+ ENDIF\r
+\r
+\r
+SPINT: ;INT 28H entry point\r
+ IF HARDINT\r
+ CMP [BUSY],0\r
+ JNZ NXTSP\r
+ INC [BUSY] ;Exclude hardware interrupt\r
+ INC [SOFINT] ;Indicate a software int in progress\r
+ ENDIF\r
+\r
+ STI ;Hardware interrupts ok on INT 28H entry\r
+ CALL DOINT\r
+\r
+ IF HARDINT\r
+ CLI\r
+ MOV [SOFINT],0 ;Indicate INT done\r
+ MOV [SLICECNT],TIMESLICE ;Either soft or hard int resets time slice\r
+ MOV [BUSY],0\r
+ ENDIF\r
+\r
+NXTSP: JMP [SPNEXT] ;Chain to next INT 28\r
+\r
+DOINT:\r
+ PUSH SI\r
+ MOV SI,[CURRFIL]\r
+ INC SI\r
+ INC SI\r
+ CMP BYTE PTR CS:[SI],-1\r
+ POP SI\r
+ JNZ GOAHEAD\r
+ JMP SPRET ;Nothing to do\r
+GOAHEAD:\r
+ PUSH AX ;Need a working register\r
+ MOV [SSsave],SS\r
+ MOV [SPsave],SP\r
+ MOV AX,CS\r
+ CLI\r
+;Go to internal stack to prevent INT 24 overflowing system stack\r
+ MOV SS,AX\r
+ MOV SP,OFFSET DG:ISTACK\r
+ STI\r
+ PUSH ES\r
+ PUSH DS\r
+ PUSH BX\r
+ PUSH CX\r
+ PUSH DX\r
+ PUSH SI\r
+ PUSH DI\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:DG\r
+\r
+ MOV BX,[NXTCHR]\r
+ CMP BX,OFFSET DG:BUFFER + BLKSIZ\r
+ JNZ PLOOP\r
+ JMP READBUFF ;Buffer empty\r
+\r
+PLOOP:\r
+ IF HARDINT\r
+ MOV BX,[NXTCHR]\r
+ CMP BX,OFFSET DG:BUFFER + BLKSIZ\r
+ JZ DONEJMP ;Buffer has become empty\r
+ CMP [SOFINT],0\r
+ JNZ STATCHK\r
+ CMP [TICKCNT],MAXTICK ;Check our time slice\r
+ JAE DONEJMP\r
+STATCHK:\r
+ ENDIF\r
+\r
+ CALL PSTAT\r
+\r
+ IF HARDINT\r
+ JZ DOCHAR ;Printer ready\r
+ CMP [SOFINT],0\r
+ ENDIF\r
+\r
+ JNZ DONEJMP ;If soft int give up\r
+\r
+ IF HARDINT\r
+ CMP [TICKSUB],BUSYTICK ;Check our busy timeout\r
+ JAE DONEJMP\r
+ JMP PLOOP\r
+ ENDIF\r
+\r
+DOCHAR:\r
+ MOV AL,BYTE PTR [BX]\r
+ CMP AL,1AH ;^Z?\r
+ JZ FILEOFJ ;CPM EOF\r
+ CMP AL,0DH ;CR?\r
+ JNZ NOTCR\r
+ MOV [COLPOS],0\r
+NOTCR:\r
+ CMP AL,9 ;TAB?\r
+ JNZ NOTABDO\r
+ MOV CL,[COLPOS]\r
+ OR CL,0F8H\r
+ NEG CL\r
+ XOR CH,CH\r
+ JCXZ TABDONE\r
+TABLP:\r
+ MOV AL," "\r
+ INC [COLPOS]\r
+ PUSH CX\r
+ CALL POUT\r
+ POP CX\r
+ LOOP TABLP\r
+ JMP TABDONE\r
+\r
+NOTABDO:\r
+ CMP AL,8 ;Back space?\r
+ JNZ NOTBACK\r
+ DEC [COLPOS]\r
+NOTBACK:\r
+ CMP AL,20H ;Non Printing char?\r
+ JB NOCHAR\r
+ INC [COLPOS] ;Printing char\r
+NOCHAR:\r
+ CALL POUT ;Print it\r
+TABDONE:\r
+ INC [NXTCHR] ;Next char\r
+\r
+ IF HARDINT\r
+ MOV [TICKSUB],0 ;Got a character out, Reset counter\r
+ CMP [SOFINT],0 ;Soft int does one char at a time\r
+ JZ PLOOP\r
+ ENDIF\r
+\r
+DONEJMP:\r
+ POP DI\r
+ POP SI\r
+ POP DX\r
+ POP CX\r
+ POP BX\r
+ POP DS\r
+ POP ES\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+ CLI\r
+ MOV SS,[SSsave] ;Restore Entry Stack\r
+ MOV SP,[SPsave]\r
+ STI\r
+ POP AX\r
+SPRET:\r
+ RET\r
+\r
+FILEOFJ: JMP FILEOF\r
+\r
+READBUFF:\r
+ASSUME DS:DG,ES:NOTHING\r
+\r
+ MOV AL,24H\r
+ MOV AH,GET_INTERRUPT_VECTOR\r
+ INT 21H\r
+ MOV WORD PTR [HERRINT+2],ES ;Save current vector\r
+ MOV WORD PTR [HERRINT],BX\r
+ MOV DX,OFFSET DG:DSKERR\r
+ MOV AL,24H\r
+ MOV AH,SET_INTERRUPT_VECTOR ;Install our own\r
+ INT 21H ;Spooler must catch its errors\r
+ MOV AH,GET_DMA\r
+ INT 21H\r
+ MOV WORD PTR [DMAADDR+2],ES ;Save DMA address\r
+ MOV WORD PTR [DMAADDR],BX\r
+ MOV DX,OFFSET DG:BUFFER\r
+ MOV AH,SET_DMA\r
+ INT 21H ;New DMA address\r
+ MOV [PABORT],0 ;No abort\r
+ MOV DX,[CURRFIL] ;Read\r
+ INC DX\r
+ INC DX ;Skip over pointer\r
+ MOV AH,FCB_SEQ_READ\r
+ INT 21H\r
+ PUSH AX\r
+ LDS DX,[DMAADDR]\r
+ASSUME DS:NOTHING\r
+ MOV AH,SET_DMA\r
+ INT 21H ;Restore DMA\r
+ LDS DX,[HERRINT]\r
+ MOV AL,24H\r
+ MOV AH,SET_INTERRUPT_VECTOR\r
+ INT 21H ;Restore Error INT\r
+ POP AX\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:DG\r
+ CMP [PABORT],0\r
+ JNZ TONEXTFIL ;Barf on this file, got INT 24\r
+ CMP AL,01\r
+ JZ FILEOF ;Read EOF?\r
+ MOV BX,OFFSET DG:BUFFER ;Buffer full\r
+ MOV [NXTCHR],BX\r
+ JMP DONEJMP\r
+\r
+FILEOF:\r
+ MOV AL,0CH ;Form feed\r
+ CALL LOUT\r
+TONEXTFIL:\r
+ CALL NEXTFIL\r
+ JMP DONEJMP\r
+\r
+;INT 24 handler\r
+\r
+DSKERR:\r
+ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING\r
+ STI\r
+ CMP [PABORT],0\r
+ JNZ IGNRET\r
+ PUSH BX\r
+ PUSH CX\r
+ PUSH DX\r
+ PUSH DI\r
+ PUSH SI\r
+ PUSH BP\r
+ PUSH ES\r
+ PUSH DS\r
+ PUSH CS\r
+ POP DS\r
+ PUSH CS\r
+ POP ES\r
+ASSUME DS:DG,ES:DG\r
+ ADD [BADDRVM],AL ;Set correct drive letter\r
+ MOV SI,OFFSET DG:ERRMES\r
+ CALL LISTMES\r
+ TEST AH,080H\r
+ JNZ FATERR\r
+ AND DI,0FFH\r
+ CMP DI,12\r
+ JBE HAVCOD\r
+ MOV DI,12\r
+HAVCOD:\r
+ SHL DI,1\r
+ MOV DI,WORD PTR [DI+MESBAS] ; Get pointer to error message\r
+ MOV SI,DI\r
+ CALL LISTMES ; Print error type\r
+ MOV DI,OFFSET DG:EMFILNAM\r
+ MOV SI,[CURRFIL]\r
+ ADD SI,2 ;Get to file name\r
+ LODSB\r
+ ADD AL,'@'\r
+ STOSB\r
+ INC DI\r
+ MOV CX,4\r
+ REP MOVSW\r
+ INC DI\r
+ MOVSW\r
+ MOVSB\r
+ MOV SI,OFFSET DG:ERRMEST\r
+ CALL LISTMES\r
+SETABORT:\r
+ INC [PABORT] ;Indicate abort\r
+ POP DS\r
+ POP ES\r
+ POP BP\r
+ POP SI\r
+ POP DI\r
+ POP DX\r
+ POP CX\r
+ POP BX\r
+IGNRET:\r
+ XOR AL,AL ;Ignore\r
+ IRET\r
+\r
+FATERR:\r
+ MOV SI,OFFSET DG:FATMES\r
+ CALL LISTMES\r
+ JMP SHORT SETABORT\r
+\r
+ADDFILJ: JMP ADDFIL\r
+\r
+COMBUSY:\r
+ MOV AX,-1\r
+ IRET\r
+\r
+;Communications interrupt\r
+SPCOMINT:\r
+ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING\r
+ CMP [CBUSY],0\r
+ JNZ COMBUSY\r
+ INC [CBUSY] ;Exclude\r
+ STI ;Turn ints back on\r
+ PUSH SI\r
+ PUSH DI\r
+ PUSH CX\r
+ PUSH DS\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:DG\r
+ MOV [PCANMES],0 ;Havn't printed cancel message\r
+ OR AH,AH\r
+ JZ ADDFILJ ;Add file\r
+ CMP AH,1\r
+ JZ CANFIL ;Cancel File(s)\r
+ XOR AL,AL\r
+SETCOUNT:\r
+ PUSH AX ;Save AL return code\r
+ XOR AH,AH\r
+ MOV SI,OFFSET DG:SPLFCB\r
+ MOV CX,[NUMFCBS]\r
+CNTFILS:\r
+ CMP BYTE PTR [SI+2],-1 ;Valid?\r
+ JZ LNEXT\r
+ INC AH\r
+LNEXT:\r
+ ADD SI,FCBSIZ\r
+ LOOP CNTFILS\r
+COMRET:\r
+ MOV BX,OFFSET DG:SPLFCB\r
+ MOV DX,[CURRFIL]\r
+ PUSH DS\r
+ POP ES\r
+ASSUME ES:NOTHING\r
+ MOV CH,AH\r
+ POP AX ;Get AL return\r
+ MOV AH,CH\r
+\r
+ IF HARDINT\r
+BWAIT3:\r
+ CMP [BUSY],0\r
+ JNZ BWAIT3\r
+ INC [BUSY]\r
+ ENDIF\r
+\r
+ CALL PSTAT ; Tweek error counter\r
+\r
+ IF HARDINT\r
+ MOV [BUSY],0\r
+ ENDIF\r
+\r
+ POP DS\r
+ASSUME DS:NOTHING\r
+ POP CX\r
+ POP DI\r
+ POP SI\r
+ MOV [CBUSY],0\r
+ IRET\r
+\r
+DELALLJ: JMP DELALL\r
+\r
+CANFIL:\r
+ASSUME DS:DG,ES:NOTHING\r
+ MOV CX,[NUMFCBS]\r
+\r
+ IF HARDINT\r
+BWAIT:\r
+ CMP [BUSY],0\r
+ JNZ BWAIT\r
+ INC [BUSY]\r
+ ENDIF\r
+\r
+ MOV SI,[CURRFIL]\r
+ CMP DX,-1\r
+ JZ DELALLJ\r
+ MOV BX,[SI]\r
+ PUSH BX\r
+LOOKEND: ;Set initial pointer values\r
+ CMP BX,SI\r
+ JZ GOTLAST\r
+ POP AX\r
+ PUSH BX\r
+ MOV BX,[BX]\r
+ JMP SHORT LOOKEND\r
+\r
+GOTLAST:\r
+ POP BX\r
+ MOV [LASTFCB],BX\r
+ MOV [LASTFCB2],BX\r
+ POP ES\r
+ PUSH ES\r
+ MOV BX,SI\r
+LOOKMATCH:\r
+ MOV DI,DX\r
+ ADD SI,2 ;Skip pointer\r
+ CMP BYTE PTR [SI],-1\r
+ JZ CANTERMJ ;No more\r
+ CMPSB\r
+ JNZ SKIPFIL ;DRIVE\r
+ PUSH CX\r
+ MOV CX,11\r
+NXTCHAR:\r
+ MOV AL,ES:[DI]\r
+ INC DI\r
+ CALL UPCONV\r
+ MOV AH,AL\r
+ LODSB\r
+ CALL UPCONV\r
+ CMP AH,"?" ;Wild card?\r
+ JZ NXTCHRLP ;Yes\r
+ CMP AH,AL\r
+ JNZ SKIPFILC\r
+NXTCHRLP:\r
+ LOOP NXTCHAR\r
+MATCH:\r
+ POP CX\r
+ MOV AH,-1\r
+ XCHG AH,[BX+2] ;Zap it\r
+ CMP BX,[CURRFIL] ;Is current file?\r
+ JNZ REQUEUE ;No\r
+ MOV AL,1\r
+ XCHG AL,[PCANMES]\r
+ OR AL,AL\r
+ JNZ DIDCMES ;Only print cancel message once\r
+ PUSH ES\r
+ PUSH CS\r
+ POP ES\r
+ MOV DI,OFFSET DG:CANFILNAM\r
+ MOV SI,BX\r
+ ADD SI,3 ;Get to file name\r
+ MOV AL,AH\r
+ ADD AL,'@'\r
+ STOSB\r
+ INC DI\r
+ MOV CX,4\r
+ REP MOVSW\r
+ INC DI\r
+ MOVSW\r
+ MOVSB\r
+ POP ES\r
+ MOV SI,OFFSET DG:CANMES\r
+ CALL LISTMES\r
+ MOV SI,OFFSET DG:BELMES\r
+ CALL LISTMES\r
+DIDCMES:\r
+ PUSH CX\r
+ CALL NEXTFIL\r
+SKIPFILC:\r
+ POP CX\r
+SKIPFIL:\r
+ MOV [LASTFCB2],BX\r
+ MOV BX,[BX]\r
+NEXTFC:\r
+ MOV SI,BX\r
+ LOOP LOOKMATCH\r
+CANTERMJ: JMP SHORT CANTERM\r
+\r
+REQUEUE:\r
+ MOV AX,[BX]\r
+ CMP AX,[CURRFIL] ;Is last FCB?\r
+ JZ SKIPFIL ;Yes, is in right place\r
+ MOV SI,[LASTFCB2]\r
+ MOV [SI],AX ;Unlink FCB\r
+ MOV SI,[CURRFIL]\r
+ MOV [BX],SI\r
+ MOV SI,[LASTFCB]\r
+ MOV [SI],BX ;Link FCB at end\r
+ MOV [LASTFCB],BX ;New end\r
+ MOV BX,AX ;Process what it pointed to\r
+ JMP SHORT NEXTFC\r
+\r
+DELALL:\r
+ CMP BYTE PTR CS:[SI+2],-1 ;Examine current file\r
+DELALL2:\r
+ MOV BYTE PTR [SI+2],-1 ;Zap it\r
+ MOV SI,[SI]\r
+ LOOP DELALL2\r
+ JZ CANTERM1 ;No message if nothing was in progress\r
+ MOV SI,OFFSET DG:ALLCAN\r
+ CALL LISTMES\r
+ MOV SI,OFFSET DG:BELMES\r
+ CALL LISTMES\r
+CANTERM1:\r
+ MOV [NXTCHR],OFFSET DG:BUFFER + BLKSIZ ;Buffer empty\r
+CANTERM:\r
+\r
+ IF HARDINT\r
+ MOV [BUSY],0\r
+ ENDIF\r
+\r
+ XOR AX,AX\r
+ JMP SETCOUNT\r
+\r
+UPCONV:\r
+ CMP AL,'a'\r
+ JB NOCONV\r
+ CMP AL,'z'\r
+ JA NOCONV\r
+ SUB AL,20H\r
+NOCONV:\r
+ RET\r
+\r
+ADDFIL:\r
+ASSUME DS:DG,ES:NOTHING\r
+ MOV SI,[CURRFIL]\r
+ MOV CX,[NUMFCBS]\r
+\r
+ IF HARDINT\r
+BWAIT2:\r
+ CMP [BUSY],0\r
+ JNZ BWAIT2\r
+ INC [BUSY]\r
+ ENDIF\r
+\r
+LOOKSPOT:\r
+ CMP BYTE PTR [SI+2],-1\r
+ JZ GOTSPOT\r
+ MOV SI,[SI]\r
+ LOOP LOOKSPOT\r
+\r
+ IF HARDINT\r
+ MOV [BUSY],0\r
+ ENDIF\r
+\r
+ MOV AL,1\r
+ JMP SETCOUNT\r
+\r
+GOTSPOT:\r
+ PUSH DS\r
+ POP ES\r
+ POP DS\r
+ PUSH DS\r
+ASSUME DS:NOTHING\r
+ PUSH SI\r
+ MOV DI,SI\r
+ ADD DI,2\r
+ MOV SI,DX\r
+ MOV CX,19\r
+ REP MOVSW ;Copy in and set FCB\r
+ POP SI\r
+ PUSH ES\r
+ POP DS\r
+ASSUME DS:DG\r
+ MOV WORD PTR [SI+2+fcb_EXTENT],0\r
+ MOV BYTE PTR [SI+2+fcb_NR],0\r
+ MOV WORD PTR [SI+2+fcb_RECSIZ],BLKSIZ\r
+\r
+ IF HARDINT\r
+ MOV [BUSY],0\r
+ ENDIF\r
+\r
+ XOR AL,AL\r
+ JMP SETCOUNT\r
+\r
+NEXTFIL:\r
+ASSUME DS:DG,ES:NOTHING\r
+ MOV SI,[CURRFIL]\r
+ MOV BYTE PTR [SI+2],-1 ;Done with current file\r
+ MOV SI,[SI]\r
+ MOV [CURRFIL],SI\r
+ MOV [NXTCHR],OFFSET DG:BUFFER + BLKSIZ ;Buffer empty\r
+ MOV [COLPOS],0 ;Start of line\r
+ RET\r
+\r
+LISTMES:\r
+ASSUME DS:DG,ES:NOTHING\r
+ LODSB\r
+ CMP AL,"$"\r
+ JZ LMESDONE\r
+ CALL LOUT\r
+ JMP LISTMES\r
+\r
+LMESDONE:\r
+ RET\r
+\r
+LOUT:\r
+ PUSH BX\r
+LWAIT:\r
+ CALL PSTAT\r
+ JZ PREADY\r
+ CMP [ERRCNT],ERRCNT2\r
+ JA POPRET ;Don't get stuck\r
+ JMP SHORT LWAIT\r
+PREADY:\r
+ CALL POUT\r
+POPRET:\r
+ POP BX\r
+ RET\r
+\r
+;Stuff for BIOS interface\r
+IOBUSY EQU 0200H\r
+IOERROR EQU 8000H\r
+\r
+BYTEBUF DB ?\r
+\r
+CALLAD DD ?\r
+\r
+IOCALL DB 22\r
+ DB 0\r
+IOREQ DB ?\r
+IOSTAT DW 0\r
+ DB 8 DUP(?)\r
+ DB 0\r
+ DW OFFSET DG:BYTEBUF\r
+INTSEG DW ?\r
+IOCNT DW 1\r
+ DW 0\r
+\r
+PSTAT:\r
+ASSUME DS:DG\r
+ PUSH BX\r
+ INC [ERRCNT]\r
+ MOV BL,10\r
+ CALL DOCALL\r
+ TEST [IOSTAT],IOERROR\r
+ JZ NOSTATERR\r
+ OR [IOSTAT],IOBUSY ;If error, show buisy\r
+NOSTATERR:\r
+ TEST [IOSTAT],IOBUSY\r
+ JNZ RET13P ;Shows buisy\r
+ MOV [ERRCNT],0\r
+RET13P:\r
+ POP BX\r
+ RET\r
+\r
+POUT:\r
+ASSUME DS:DG\r
+ MOV [BYTEBUF],AL\r
+ MOV BL,8\r
+DOCALL:\r
+ PUSH ES\r
+ MOV [IOREQ],BL\r
+ MOV BX,CS\r
+ MOV ES,BX\r
+ MOV BX,OFFSET DG:IOCALL\r
+ MOV [IOSTAT],0\r
+ MOV [IOCNT],1\r
+ PUSH DS\r
+ PUSH SI\r
+ PUSH AX\r
+ LDS SI,[LISTDEV]\r
+ASSUME DS:NOTHING\r
+ MOV AX,[SI+6]\r
+ MOV WORD PTR [CALLAD],AX\r
+ CALL [CALLAD]\r
+ MOV AX,[SI+8]\r
+ MOV WORD PTR [CALLAD],AX\r
+ CALL [CALLAD]\r
+ POP AX\r
+ POP SI\r
+ POP DS\r
+ASSUME DS:DG\r
+ POP ES\r
+ RET\r
+\r
+ IF IBM\r
+REAL_INT_13 DD ?\r
+INT_13_RETADDR DW OFFSET DG:INT_13_BACK\r
+\r
+INT_13 PROC FAR\r
+ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING\r
+ PUSHF\r
+ INC [BUSY] ;Exclude if dumb program call ROM\r
+ PUSH CS\r
+ PUSH [INT_13_RETADDR]\r
+ PUSH WORD PTR [REAL_INT_13+2]\r
+ PUSH WORD PTR [REAL_INT_13]\r
+ RET\r
+INT_13 ENDP\r
+\r
+INT_13_BACK PROC FAR\r
+ PUSHF\r
+ DEC [BUSY]\r
+ POPF\r
+ RET 2 ;Chuck saved flags\r
+INT_13_BACK ENDP\r
+ ENDIF\r
+\r
+\r
+ IF IBM\r
+\r
+REAL_INT_5 DD ?\r
+REAL_INT_17 DD ?\r
+INT_17_NUM DW 0\r
+\r
+INT_17:\r
+ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING\r
+ PUSH SI\r
+ MOV SI,[CURRFIL]\r
+ INC SI\r
+ INC SI\r
+ CMP BYTE PTR CS:[SI],-1\r
+ POP SI\r
+ JZ DO_INT_17 ;Nothing pending, so OK\r
+ CMP DX,[INT_17_NUM]\r
+ JNZ DO_INT_17 ;Not my unit\r
+ CMP [BUSY],0\r
+ JNZ DO_INT_17 ;You are me\r
+ STI\r
+ MOV AH,0A1H ;You are bad, get out of paper\r
+ IRET\r
+\r
+DO_INT_17:\r
+ JMP [REAL_INT_17] ;Do a 17\r
+\r
+REAL_INT_14 DD ?\r
+INT_14_NUM DW 0\r
+\r
+INT_14:\r
+ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING\r
+ PUSH SI\r
+ MOV SI,[CURRFIL]\r
+ INC SI\r
+ INC SI\r
+ CMP BYTE PTR CS:[SI],-1\r
+ POP SI\r
+ JZ DO_INT_14 ;Nothing pending, so OK\r
+ CMP DX,[INT_14_NUM]\r
+ JNZ DO_INT_14 ;Not my unit\r
+ CMP [BUSY],0\r
+ JNZ DO_INT_14 ;You are me\r
+ STI\r
+ OR AH,AH\r
+ JZ SET14_AX\r
+ CMP AH,2\r
+ JBE SET14_AH\r
+SET14_AX:\r
+ MOV AL,0\r
+SET14_AH:\r
+ MOV AH,80H ;Time out\r
+ IRET\r
+\r
+DO_INT_14:\r
+ JMP [REAL_INT_14] ;Do a 14\r
+\r
+INT_5:\r
+ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING\r
+ PUSH SI\r
+ MOV SI,[CURRFIL]\r
+ INC SI\r
+ INC SI\r
+ CMP BYTE PTR CS:[SI],-1\r
+ POP SI\r
+ JZ DO_INT_5 ;Nothing pending, so OK\r
+ CMP [INT_17_NUM],0\r
+ JNZ DO_INT_5 ;Only care about unit 0\r
+ IRET ;Pretend it worked\r
+\r
+DO_INT_5:\r
+ JMP [REAL_INT_5] ;Do a 5\r
+ ENDIF\r
+\r
+\r
+;The following data is order and position dependant\r
+NUMFCBS DW 10\r
+ERRCNT DW 0\r
+\r
+SPLFCB DW OFFSET DG:FC1\r
+ DB (FCBSIZ - 2) DUP (-1)\r
+FC1 DW OFFSET DG:FC2\r
+ DB (FCBSIZ - 2) DUP (-1)\r
+FC2 DW OFFSET DG:FC3\r
+ DB (FCBSIZ - 2) DUP (-1)\r
+FC3 DW OFFSET DG:FC4\r
+ DB (FCBSIZ - 2) DUP (-1)\r
+FC4 DW OFFSET DG:FC5\r
+ DB (FCBSIZ - 2) DUP (-1)\r
+FC5 DW OFFSET DG:FC6\r
+ DB (FCBSIZ - 2) DUP (-1)\r
+FC6 DW OFFSET DG:FC7\r
+ DB (FCBSIZ - 2) DUP (-1)\r
+FC7 DW OFFSET DG:FC8\r
+ DB (FCBSIZ - 2) DUP (-1)\r
+FC8 DW OFFSET DG:FC9\r
+ DB (FCBSIZ - 2) DUP (-1)\r
+FC9 DW OFFSET DG:SPLFCB\r
+ DB (FCBSIZ - 2) DUP (-1)\r
+\r
+DEF_ENDRES LABEL BYTE\r
+\r
+ASSUME CS:DG,DS:DG,ES:DG,SS:DG\r
+\r
+BADSPOOL:\r
+ MOV DX,OFFSET DG:BADMES\r
+ MOV AH,STD_CON_STRING_OUTPUT\r
+ INT 21H\r
+ INT 20H\r
+\r
+SETUP:\r
+;Called once to install resident\r
+ CLD\r
+ MOV [INTSEG],CS\r
+ MOV DX,OFFSET DG:PROMPT\r
+ MOV AH,STD_CON_STRING_OUTPUT\r
+ INT 21H\r
+ MOV DX,OFFSET DG:COMBUF\r
+ MOV AH,STD_CON_STRING_INPUT\r
+ INT 21H ;Get device name\r
+ MOV DX,OFFSET DG:CRLF\r
+ MOV AH,STD_CON_STRING_OUTPUT\r
+ INT 21H\r
+ MOV CL,[COMBUF+1]\r
+ OR CL,CL\r
+ JZ DEFSPOOL ;User didn't specify one\r
+ XOR CH,CH\r
+ MOV DI,OFFSET DG:LISTFCB + 1\r
+ MOV SI,OFFSET DG:COMBUF + 2\r
+ REP MOVSB\r
+DEFSPOOL:\r
+ MOV DX,OFFSET DG:LISTFCB\r
+ MOV AH,FCB_OPEN\r
+ INT 21H\r
+ OR AL,AL\r
+ JNZ BADSPOOL ;Bad\r
+ TEST BYTE PTR [LISTFCB.fcb_DEVID],080H\r
+ JZ BADSPOOL ;Must be a device\r
+ LDS SI,DWORD PTR [LISTFCB.fcb_FIRCLUS]\r
+ASSUME DS:NOTHING\r
+ MOV WORD PTR [CALLAD+2],DS ;Get I/O routines\r
+ MOV WORD PTR [LISTDEV+2],DS ;Get I/O routines\r
+ MOV WORD PTR [LISTDEV],SI\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:DG\r
+ MOV DX,OFFSET DG:SPINT\r
+ MOV AL,SOFTINT\r
+ MOV AH,GET_INTERRUPT_VECTOR\r
+ INT 21H ;Get soft vector\r
+ MOV WORD PTR [SPNEXT+2],ES\r
+ MOV WORD PTR [SPNEXT],BX\r
+ MOV AL,SOFTINT\r
+ MOV AH,SET_INTERRUPT_VECTOR\r
+ INT 21H ;Set soft vector\r
+ MOV DX,OFFSET DG:SPCOMINT\r
+ MOV AL,COMINT\r
+ MOV AH,SET_INTERRUPT_VECTOR ;Set communication vector\r
+ INT 21H\r
+\r
+ IF IBM\r
+ MOV AL,13H\r
+ MOV AH,GET_INTERRUPT_VECTOR\r
+ INT 21H\r
+ MOV WORD PTR [REAL_INT_13+2],ES\r
+ MOV WORD PTR [REAL_INT_13],BX\r
+ MOV DX,OFFSET DG:INT_13\r
+ MOV AL,13H\r
+ MOV AH,SET_INTERRUPT_VECTOR\r
+ INT 21H ;Set diskI/O interrupt\r
+ MOV AL,17H\r
+ MOV AH,GET_INTERRUPT_VECTOR\r
+ INT 21H\r
+ MOV WORD PTR [REAL_INT_17+2],ES\r
+ MOV WORD PTR [REAL_INT_17],BX\r
+ MOV AL,14H\r
+ MOV AH,GET_INTERRUPT_VECTOR\r
+ INT 21H\r
+ MOV WORD PTR [REAL_INT_14+2],ES\r
+ MOV WORD PTR [REAL_INT_14],BX\r
+ MOV AL,5H\r
+ MOV AH,GET_INTERRUPT_VECTOR\r
+ INT 21H\r
+ MOV WORD PTR [REAL_INT_5+2],ES\r
+ MOV WORD PTR [REAL_INT_5],BX\r
+ PUSH CS\r
+ POP ES\r
+ MOV BP,OFFSET DG:LISTFCB + 1\r
+ MOV SI,BP\r
+ MOV CX,8\r
+CONLP: ;Make sure device name in upper case\r
+ LODSB\r
+ CMP AL,'a'\r
+ JB DOCONLP\r
+ CMP AL,'z'\r
+ JA DOCONLP\r
+ SUB BYTE PTR [SI-1],20H\r
+DOCONLP:\r
+ LOOP CONLP\r
+ MOV DI,OFFSET DG:INT_17_HITLIST\r
+CHKHIT:\r
+ MOV SI,BP\r
+ MOV CL,[DI]\r
+ INC DI\r
+ JCXZ NOTONHITLIST\r
+ REPE CMPSB\r
+ LAHF\r
+ ADD DI,CX ;Bump to next position without affecting flags\r
+ MOV BL,[DI] ;Get device number\r
+ INC DI\r
+ SAHF\r
+ JNZ CHKHIT\r
+ XOR BH,BH\r
+ MOV [INT_17_NUM],BX\r
+ MOV DX,OFFSET DG:INT_17\r
+ MOV AL,17H\r
+ MOV AH,SET_INTERRUPT_VECTOR\r
+ INT 21H ;Set printer interrupt\r
+ MOV DX,OFFSET DG:INT_5\r
+ MOV AL,5H\r
+ MOV AH,SET_INTERRUPT_VECTOR\r
+ INT 21H ;Set print screen interrupt\r
+ JMP SHORT ALLSET\r
+NOTONHITLIST:\r
+ MOV DI,OFFSET DG:INT_14_HITLIST\r
+CHKHIT2:\r
+ MOV SI,BP\r
+ MOV CL,[DI]\r
+ INC DI\r
+ JCXZ ALLSET\r
+ REPE CMPSB\r
+ LAHF\r
+ ADD DI,CX ;Bump to next position without affecting flags\r
+ MOV BL,[DI] ;Get device number\r
+ INC DI\r
+ SAHF\r
+ JNZ CHKHIT2\r
+ XOR BH,BH\r
+ MOV [INT_14_NUM],BX\r
+ MOV DX,OFFSET DG:INT_14\r
+ MOV AL,14H\r
+ MOV AH,SET_INTERRUPT_VECTOR\r
+ INT 21H ;Set RS232 port interrupt\r
+ALLSET:\r
+ ENDIF\r
+\r
+ IF HARDINT\r
+ MOV AH,GET_INDOS_FLAG\r
+ INT 21H\r
+ MOV WORD PTR [INDOS+2],ES ;Get indos flag location\r
+ MOV WORD PTR [INDOS],BX\r
+ MOV AL,INTLOC\r
+ MOV AH,GET_INTERRUPT_VECTOR\r
+ INT 21H\r
+ MOV WORD PTR [NEXTINT+2],ES\r
+ MOV WORD PTR [NEXTINT],BX\r
+ MOV DX,OFFSET DG:HDSPINT\r
+ MOV AL,INTLOC\r
+ MOV AH,SET_INTERRUPT_VECTOR\r
+ INT 21H ;Set hardware interrupt\r
+ ENDIF\r
+\r
+ MOV [MAKERES],1 ;Indicate to do a terminate stay resident\r
+ MOV DX,OFFSET DG:GOODMES\r
+ MOV AH,STD_CON_STRING_OUTPUT\r
+ INT 21H\r
+ RET\r
+\r
+ASSUME CS:DG,DS:DG,ES:DG,SS:DG\r
+\r
+TRANSIENT:\r
+;User interface\r
+ CLD\r
+\r
+;Code to print header\r
+; MOV DX,OFFSET DG:HEADER\r
+; MOV AH,STD_CON_STRING_OUTPUT\r
+; INT 21H\r
+\r
+DOSVER_LOW EQU 0136H ;1.54 in hex\r
+DOSVER_HIGH EQU 0200H ;2.00 in hex\r
+ MOV AH,GET_VERSION\r
+ INT 21H\r
+ XCHG AH,AL ;Turn it around to AH.AL\r
+ CMP AX,DOSVER_LOW\r
+ JB GOTBADDOS\r
+ CMP AX,DOSVER_HIGH\r
+ JBE OKDOS\r
+GOTBADDOS:\r
+ PUSH CS\r
+ POP DS\r
+ MOV DX,OFFSET DG:BADVER\r
+ MOV AH,STD_CON_STRING_OUTPUT\r
+ INT 21H\r
+ INT 20H\r
+OKDOS:\r
+ MOV AX,CHAR_OPER SHL 8\r
+ INT 21H\r
+ MOV [SWITCHAR],DL ;Get user switch character\r
+ MOV AH,GET_INTERRUPT_VECTOR\r
+ MOV AL,COMINT\r
+ INT 21H\r
+ASSUME ES:NOTHING\r
+ MOV DI,BX\r
+ MOV SI,OFFSET DG:SPCOMINT\r
+ MOV CX,13\r
+ REPE CMPSB\r
+ JZ GOTRES ;Signature matched\r
+ PUSH CS\r
+ POP ES\r
+ CALL SETUP\r
+GOTRES:\r
+ PUSH CS\r
+ POP ES\r
+ MOV AH,GET_DEFAULT_DRIVE\r
+ INT 21H\r
+ MOV [DEFDRV],AL\r
+ MOV SI,PARMS\r
+ LODSB\r
+ OR AL,AL\r
+ JNZ GOTPARMS\r
+TRANEXIT:\r
+ CALL GETSPLIST\r
+ CMP [MAKERES],0\r
+ JNZ SETRES\r
+ INT 20H\r
+\r
+SETRES:\r
+ MOV DX,[ENDRES]\r
+ INT 27H\r
+\r
+ARGSDONE:\r
+ CMP [ARGSETUP],0\r
+ JZ TRANEXIT\r
+ CALL PROCESS\r
+ JMP SHORT TRANEXIT\r
+\r
+GOTPARMS:\r
+PARSE:\r
+ MOV DI,OFFSET DG:PARSEBUF\r
+ CALL CPARSE\r
+ JC ARGSDONE\r
+ CMP AX,4 ;Switch?\r
+ JNZ GOTNORMARG\r
+ MOV AL,[DI] ;Get the switch character\r
+ CMP AL,'C'\r
+ JZ SETCAN\r
+ CMP AL,'c'\r
+ JNZ CHKSPL\r
+SETCAN:\r
+ MOV [CANFLG],1\r
+ JMP SHORT PARSE\r
+CHKSPL:\r
+ CMP AL,'P'\r
+ JZ RESETCAN\r
+ CMP AL,'p'\r
+ JNZ CHKTERM\r
+RESETCAN:\r
+ MOV [CANFLG],0\r
+ JMP SHORT PARSE\r
+CHKTERM:\r
+ CMP AL,'T'\r
+ JZ SETTERM\r
+ CMP AL,'t'\r
+ JZ SETTERM\r
+ MOV DX,OFFSET DG:BADSWT\r
+ MOV AH,STD_CON_STRING_OUTPUT\r
+ INT 21H\r
+ JMP SHORT PARSE\r
+\r
+SETTERM:\r
+ CALL TERMPROCESS\r
+ JMP TRANEXIT ; Ignore everything after T switch\r
+\r
+GOTNORMARG:\r
+ XOR AL,AL\r
+ XCHG AL,[ARGSETUP]\r
+ OR AL,AL\r
+ JZ PARSEARG\r
+ CALL NORMPROC ;Don't test ARGSETUP, it just got zeroed\r
+PARSEARG:\r
+ PUSH SI\r
+ MOV SI,DI\r
+ MOV DI,FCB\r
+ MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 1\r
+ INT 21H ;Parse the arg\r
+ CMP BYTE PTR [DI],0\r
+ JNZ DRVOK\r
+ MOV DL,[DEFDRV]\r
+ INC DL\r
+ MOV BYTE PTR [DI],DL ;Set the default drive\r
+DRVOK:\r
+ POP SI\r
+ INC [ARGSETUP]\r
+ JMP SHORT PARSE\r
+\r
+TERMPROCESS:\r
+ MOV DX,-1\r
+PROCRET:\r
+ MOV AH,1\r
+ CALL DOSET\r
+PROCRETNFUNC:\r
+ MOV [ARGSETUP],0\r
+ PUSH CS\r
+ POP ES\r
+RET14: RET\r
+\r
+PROCESS:\r
+ CMP [ARGSETUP],0\r
+ JZ RET14 ;Nothing to process\r
+NORMPROC:\r
+ MOV AL,BYTE PTR DS:[FCB+1]\r
+ CMP AL," "\r
+ JZ SRCHBADJ\r
+ MOV DX,FCB\r
+ MOV AH,[CANFLG]\r
+ CMP AH,0\r
+ JNZ PROCRET\r
+ MOV DX,OFFSET DG:SRCHFCB\r
+ MOV AH,SET_DMA\r
+ INT 21H\r
+ MOV DX,FCB\r
+ MOV AH,DIR_SEARCH_FIRST\r
+ INT 21H\r
+ OR AL,AL\r
+ JNZ SRCHBADJ\r
+SRCHLOOP:\r
+ MOV DX,OFFSET DG:SRCHFCB\r
+ MOV AH,FCB_OPEN\r
+ INT 21H\r
+ OR AL,AL\r
+ JZ OPENOK\r
+ CALL OPENERR\r
+ JMP SHORT NEXTSEARCH\r
+SRCHBADJ: JMP SRCHBAD\r
+OPENOK:\r
+ MOV DX,OFFSET DG:SRCHFCB\r
+ MOV AH,0\r
+ CALL DOSET\r
+ OR AL,AL\r
+ JZ NEXTSEARCH\r
+ XCHG AL,[FULLFLAG] ;Know AL non-zero\r
+ OR AL,AL\r
+ JNZ NEXTSEARCH ;Only print message once\r
+ MOV DX,OFFSET DG:FULLMES ;Queue full\r
+ MOV AH,STD_CON_STRING_OUTPUT\r
+ INT 21H\r
+NEXTSEARCH:\r
+ MOV DX,OFFSET DG:SRCHFCB\r
+ MOV AH,SET_DMA\r
+ INT 21H\r
+ MOV DX,FCB\r
+ MOV AH,DIR_SEARCH_NEXT\r
+ INT 21H\r
+ OR AL,AL\r
+ JNZ PROCRETNFUNC\r
+ JMP SRCHLOOP\r
+\r
+DOSET:\r
+ INT COMINT\r
+ MOV [FILCNT],AH ;Suck up return info\r
+ MOV WORD PTR [SPLIST+2],ES\r
+ MOV WORD PTR [CURFILE+2],ES\r
+ MOV WORD PTR [SPLIST],BX\r
+ MOV WORD PTR [CURFILE],DX\r
+ RET\r
+\r
+OPENERR:\r
+ PUSH SI\r
+ PUSH DI\r
+ MOV SI,OFFSET DG:OPFILNAM\r
+ PUSH DS\r
+ POP ES\r
+ MOV DI,OFFSET DG:SRCHFCB\r
+ CALL MVFNAM\r
+ MOV DX,OFFSET DG:OPMES\r
+ MOV AH,STD_CON_STRING_OUTPUT\r
+ INT 21H\r
+ POP DI\r
+ POP SI\r
+ RET\r
+\r
+SRCHBAD:\r
+ PUSH SI\r
+ PUSH DI\r
+ MOV SI,OFFSET DG:SRCHFNAM\r
+ PUSH DS\r
+ POP ES\r
+ MOV DI,FCB\r
+ CALL MVFNAM\r
+ MOV DX,OFFSET DG:SRCHMES\r
+ MOV AH,STD_CON_STRING_OUTPUT\r
+ INT 21H\r
+ POP DI\r
+ POP SI\r
+ JMP PROCRETNFUNC\r
+\r
+GETSPLIST:\r
+ MOV AH,0FFH\r
+ CALL DOSET\r
+ PUSH DS\r
+ LDS DI,[SPLIST]\r
+ MOV DI,[DI-2] ;Get the error count\r
+ POP DS\r
+ CMP DI,ERRCNT1\r
+ JB CNTOK\r
+ MOV DX,OFFSET DG:CNTMES\r
+ MOV AH,STD_CON_STRING_OUTPUT\r
+ INT 21H\r
+CNTOK:\r
+ MOV CL,[FILCNT]\r
+ OR CL,CL\r
+ JZ NOFILES\r
+ XOR CH,CH\r
+ LES DI,[CURFILE]\r
+ PUSH DI\r
+ INC DI\r
+ INC DI\r
+ MOV SI,OFFSET DG:CURFNAM\r
+ CALL MVFNAM\r
+ POP DI\r
+ MOV DX,OFFSET DG:CURMES\r
+ MOV AH,STD_CON_STRING_OUTPUT\r
+ INT 21H\r
+ DEC CX\r
+ JCXZ RET12\r
+FILOOP:\r
+ MOV DI,ES:[DI]\r
+ PUSH DI\r
+ INC DI\r
+ INC DI\r
+ MOV SI,OFFSET DG:FILFNAM\r
+ CALL MVFNAM\r
+ POP DI\r
+ MOV DX,OFFSET DG:FILMES\r
+ MOV AH,STD_CON_STRING_OUTPUT\r
+ INT 21H\r
+ LOOP FILOOP\r
+RET12: RET\r
+\r
+NOFILES:\r
+ MOV DX,OFFSET DG:NOFILS\r
+ MOV AH,STD_CON_STRING_OUTPUT\r
+ INT 21H\r
+ RET\r
+\r
+;Make a message with the file name\r
+MVFNAM:\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+ PUSH SI\r
+ PUSH DI\r
+ PUSH CX\r
+ MOV AX,ES\r
+ PUSH DS\r
+ POP ES\r
+ MOV DS,AX\r
+ XCHG SI,DI\r
+ LODSB\r
+ ADD AL,"@"\r
+ CMP AL,"@"\r
+ JNZ STCHR\r
+ MOV AL,[DEFDRV]\r
+ ADD AL,"A"\r
+STCHR:\r
+ STOSB\r
+ INC DI\r
+ MOV CX,4\r
+ REP MOVSW\r
+ INC DI\r
+ MOVSW\r
+ MOVSB\r
+ MOV AX,ES\r
+ PUSH DS\r
+ POP ES\r
+ MOV DS,AX\r
+ POP CX\r
+ POP DI\r
+ POP SI\r
+ RET\r
+\r
+;-----------------------------------------------------------------------;\r
+; ENTRY: ;\r
+; DS:SI Points input buffer ;\r
+; ES:DI Points to the token buffer ;\r
+; ;\r
+; EXIT: ;\r
+; DS:SI Points to next char in the input buffer ;\r
+; ES:DI Points to the token buffer ;\r
+; CX Character count ;\r
+; AX Condition Code ;\r
+; =1 same as carry set ;\r
+; =2 normal token ;\r
+; =4 switch character, char in token buffer ;\r
+; Carry Flag Set if a CR was found, Reset otherwise ;\r
+; ;\r
+; MODIFIES: ;\r
+; CX, SI, AX and the Carry Flag ;\r
+; ;\r
+;-----------------------------------------------------------------------;\r
+\r
+TAB equ 09h\r
+CR equ 0dh\r
+\r
+CPARSE:\r
+ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING\r
+ pushf ;save flags\r
+ push di ;save the token buffer addrss\r
+ xor cx,cx ;no chars in token buffer\r
+ call kill_bl\r
+\r
+ cmp al,CR ;a CR?\r
+ jne sj2 ;no, skip\r
+sj1:\r
+ mov ax,1 ;condition code\r
+ dec si ;adjust the pointer\r
+ pop di ;retrive token buffer address\r
+ popf ;restore flags\r
+ stc ;set the carry bit\r
+ ret\r
+\r
+sj2:\r
+ mov dl,[SWITCHAR]\r
+ cmp al,dl ;is the char the switch char?\r
+ jne anum_char ;no, process...\r
+ call kill_bl\r
+ cmp al,CR ;a CR?\r
+ je sj1 ;yes, error exit\r
+ call move_char ;Put the switch char in the token buffer\r
+ mov ax,4 ;Flag switch\r
+ jmp short x_done2\r
+\r
+anum_char:\r
+ call move_char ;just an alphanum string\r
+ lodsb\r
+ cmp al,' '\r
+ je x_done\r
+ cmp al,tab\r
+ je x_done\r
+ cmp al,CR\r
+ je x_done\r
+ cmp al,','\r
+ je x_done\r
+ cmp al,'='\r
+ je x_done\r
+ cmp al,dl ;Switch character\r
+ jne anum_char\r
+x_done:\r
+ dec si ;adjust for next round\r
+ mov ax,2 ;normal token\r
+x_done2:\r
+ push ax ;save condition code\r
+ mov al,0\r
+ stosb ;null at the end\r
+ pop ax\r
+ pop di ;restore token buffer pointer\r
+ popf\r
+ clc ;clear carry flag\r
+ ret\r
+\r
+\r
+kill_bl proc near\r
+ lodsb\r
+ cmp al,' '\r
+ je kill_bl\r
+ cmp al,tab\r
+ je kill_bl\r
+ cmp al,',' ;a comma?\r
+ je kill_bl\r
+ cmp al,'='\r
+ je kill_bl\r
+ ret\r
+kill_bl endp\r
+\r
+\r
+move_char proc near\r
+ stosb ;store char in token buffer\r
+ inc cx ;increment char count\r
+ ret\r
+move_char endp\r
+\r
+CODE ENDS\r
+ END START\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+;MS-DOS PRINT program for background printing of text files to the list
+; device. INT 28H is a software interrupt generated by the DOS
+; in its I/O wait loops. This spooler can be assembled for
+; operation using only this interrupt which is portable from
+; system to system. It may also be assembled to use a hardware
+; timer interrupt in addition to the software INT 28H. The
+; purpose of using hardware interrupts is to allow printing to
+; continue during programs which do not enter the system and
+; therefore causes the INT 28H to go away. A timer interrupt is
+; chosen in preference to a "printer buffer empty" interrupt
+; because PRINT in the timer form is generic. It can be given
+; the name of any currently installed character device as the
+; "printer", this makes it portable to devices which are
+; installed by the user even in the hardware case. It could be
+; modified to use a buffer empty interrupt (no code is given for
+; this case), if this is done the PROMPT and BADMES messages and
+; their associated code should be removed as PRINT will then be
+; device specific.
+;
+; VERSION 1.00 07/03/82
+
+
+FALSE EQU 0
+TRUE EQU NOT FALSE
+
+IBM EQU TRUE
+IBMVER EQU IBM
+MSVER EQU FALSE
+
+ IF MSVER
+HARDINT EQU FALSE ;No hardware ints
+AINT EQU FALSE ;No need to do interrupt acknowledge
+ ENDIF
+
+ IF IBM
+HARDINT EQU TRUE
+INTLOC EQU 1CH ;Hardware interrupt location (Timer)
+AINT EQU TRUE ;Acknowledge interrupts
+EOI EQU 20H ;End Of Interrupt "instruction"
+AKPORT EQU 20H ;Interrupt Acknowledge port
+ ENDIF
+
+;The following values have to do with the ERRCNT variable and the
+; CNTMES message. The values define levels at wich it is assumed
+; an off-line error exists. ERRCNT1 defines the value of ERRCNT above
+; which the CNTMES message is printed by the transient. ERRCNT2
+; defines the value of ERRCNT above which the resident will give up
+; trying to print messages on the printer, it is much greater than
+; ERRCNT1 because a much tighter loop is involved. The bounding event
+; which determines the correct value is the time required to do a
+; form feed.
+
+ IF IBM
+ERRCNT1 EQU 1000
+ERRCNT2 EQU 20000
+ ELSE
+ERRCNT1 EQU 1000
+ERRCNT2 EQU 20000
+ ENDIF
+
+ IF HARDINT
+TIMESLICE EQU 8 ;The PRINT scheduling time slice. PRINT
+ ; lets this many "ticks" go by before
+ ; using a time slice to pump out characters.
+ ; Setting this to 3 for instance means PRINT
+ ; Will skip 3 slices, then take the fourth.
+ ; Thus using up 1/4 of the CPU. Setting it
+ ; to one gives PRINT 1/2 of the CPU.
+ ; The above examples assume MAXTICK is
+ ; 1. The actual PRINT CPU percentage is
+ ; (MAXTICK/(1+TIMESLICE))*100
+
+MAXTICK EQU 2 ;The PRINT in timeslice. PRINT will pump
+ ; out characters for this many clock ticks
+ ; and then exit. The selection of a value
+ ; for this is dependent on the timer rate.
+
+BUSYTICK EQU 1 ;If PRINT sits in a wait loop waiting for
+ ; output device to come ready for this
+ ; many ticks, it gives up its time slice.
+ ; Setting it greater than or equal to
+ ; MAXTICK causes it to be ignored.
+
+;User gets TIMESLICE ticks and then PRINT takes MAXTICK ticks unless BUSYTICK
+; ticks go by without getting a character out.
+ ENDIF
+
+
+;WARNING DANGER WARNING:
+; PRINT is a systems utility. It is clearly understood that it may have
+; to be entirely re-written for future versions of MS-DOS. The following
+; TWO vectors are version specific, they may not exist at all in future
+; versions. If they do exist, they may function differently.
+; ANY PROGRAM WHICH IMITATES PRINTS USE OF THESE VECTORS IS ALSO A SYSTEMS
+; UTILITY AND IS THEREFORE NOT VERSION PORTABLE IN ANY WAY SHAPE OR FORM.
+; YOU HAVE BEEN WARNED, "I DID IT THE SAME WAY PRINT DID" IS NOT AN REASON
+; TO EXPECT A PROGRAM TO WORK ON FUTURE VERSIONS OF MS-DOS.
+SOFTINT EQU 28H ;Software interrupt generated by DOS
+COMINT EQU 2FH ;Communications interrupt used by PRINT
+ ; This vector number is DOS reserved. It
+ ; is not generally available to programs
+ ; other than PRINT.
+
+BLKSIZ EQU 512 ;Size of the PRINT I/O block in bytes
+FCBSIZ EQU 40 ;Size of an FCB
+
+ INCLUDE DOSSYM.ASM
+
+FCB EQU 5CH
+PARMS EQU 80H
+
+DG GROUP CODE,DATA
+
+CODE SEGMENT
+ASSUME CS:DG
+
+ ORG 100H
+START:
+ JMP TRANSIENT
+
+HEADER DB "Vers 1.00"
+
+ DB 128 DUP (?)
+ISTACK LABEL WORD ;Stack starts here and grows down
+
+;Resident data
+
+ IF HARDINT
+INDOS DD ? ;DOS buisy flag
+NEXTINT DD ? ;Chain for int
+BUSY DB 0 ;Internal ME flag
+SOFINT DB 0 ;Internal ME flag
+TICKCNT DB 0 ;Tick counter
+TICKSUB DB 0 ;Tick miss counter
+SLICECNT DB TIMESLICE ;Time slice counter
+ ENDIF
+
+CBUSY DB 0 ;ME on com interrupt
+SPNEXT DD ? ;Chain location for INT 28
+PCANMES DB 0 ;Cancel message flag
+SSsave DW ? ;Stack save area for INT 24
+SPsave DW ?
+DMAADDR DD ? ;Place to save DMA address
+HERRINT DD ? ;Place to save Hard error interrupt
+LISTDEV DD ? ;Pointer to Device
+COLPOS DB 0 ;Column position for TAB processing
+NXTCHR DW OFFSET DG:BUFFER + BLKSIZ ;Buffer pointer
+CURRFIL DW OFFSET DG:SPLFCB ;Current file being printed
+
+LASTFCB DW ? ;Back pointer
+LASTFCB2 DW ? ;Another back pointer
+PABORT DB 0 ;Abort flag
+
+;Resident messages
+
+ERRMES DB 13,10,13,10,"**********",13,10,"$"
+ERRMEST DB " error reading file",13,10
+EMFILNAM DB " : . "
+BELMES DB 13,0CH,7,"$"
+
+CANMES DB 13,10,13,10
+CANFILNAM DB " : . "
+ DB " Canceled by operator$"
+
+ALLCAN DB 13,10,13,10,"All files canceled by operator$"
+
+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
+
+;INT 24 messages A La COMMAND
+
+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$"
+
+FATMES DB "File allocation table bad drive "
+BADDRVM DB "A.",13,10,"$"
+
+;The DATA buffer
+BUFFER DB BLKSIZ DUP(0)
+ DB ?
+CODE ENDS
+
+;Transient data
+
+DATA SEGMENT BYTE
+ ORG 0
+SWITCHAR DB ? ;User switch character
+FULLFLAG DB 0 ;Flag for printing queue full message
+MAKERES DB 0 ;Flag to indicate presence of resident
+ARGSETUP DB 0 ;Flag to indicate a formatted FCB exists at 5C
+DEFDRV DB 0 ;Default drive
+CANFLG DB 0 ;Flag to indicate cancel
+FILCNT DB 0 ;Number of files
+SPLIST DD ? ;Pointer to FCBs in resident
+CURFILE DD ? ;Pointer to current FCB
+SRCHFCB DB 38 DUP (0) ;SEARCH-FIRST/NEXT FCB
+ENDRES DW OFFSET DG:DEF_ENDRES ;Term-Res location
+
+;Messages
+
+NOFILS DB "PRINT queue is empty",13,10,"$"
+CURMES DB 13,10," "
+CURFNAM DB " : . is currently being printed",13,10,"$"
+FILMES DB " "
+FILFNAM DB " : . is in queue"
+CRLF DB 13,10,"$"
+OPMES DB "Cannot open "
+OPFILNAM DB " : . ",13,10,"$"
+FULLMES DB "PRINT queue is full",13,10,"$"
+SRCHMES LABEL BYTE
+SRCHFNAM DB " : . "," File not found",13,10,"$"
+BADMES DB "List output is not assigned to a device",13,10,"$"
+GOODMES DB "Resident part of PRINT installed",13,10,"$"
+PROMPT DB "Name of list device [PRN]: $"
+CNTMES DB "Errors on list device indicate that it",13,10
+ DB "may be off-line. Please check it.",13,10,13,10,"$"
+BADSWT DB "Invalid parameter",13,10,"$"
+
+
+BADVER DB "Incorrect DOS version",13,10,"$"
+
+ IF IBM
+;Reserved names for parallel card
+INT_17_HITLIST LABEL BYTE
+ DB 8,"PRN ",0
+ DB 8,"LPT1 ",0
+ DB 8,"LPT2 ",1
+ DB 8,"LPT3 ",2
+ DB 0
+;Reserved names for Async adaptor
+INT_14_HITLIST LABEL BYTE
+ DB 8,"AUX ",0
+ DB 8,"COM1 ",0
+ DB 8,"COM2 ",1
+ DB 0
+ ENDIF
+
+COMBUF DB 14,0 ;Device name buffer
+ DB 14 DUP (?)
+LISTFCB DB 0,"PRN " ;Device name FCB
+ DB 25 DUP (0)
+PARSEBUF DB 80 DUP (?) ;Parsing space
+
+DATA ENDS
+
+CODE SEGMENT
+ASSUME CS:DG,DS:DG,ES:DG,SS:DG
+
+
+;Interrupt routines
+ASSUME CS:DG,DS:NOTHING,ES:NOTHING,SS:NOTHING
+ IF HARDINT
+HDSPINT: ;Hardware interrupt entry point
+ INC [TICKCNT] ;Tick
+ INC [TICKSUB] ;Tick
+ CMP [SLICECNT],0
+ JZ TIMENOW
+ DEC [SLICECNT] ;Count down
+ JMP SHORT CHAININT ;Not time yet
+TIMENOW:
+ CMP [BUSY],0 ;See if interrupting ourself
+ JNZ CHAININT
+ PUSH DS
+ PUSH SI
+ LDS SI,[INDOS] ;Check for making DOS calls
+ CMP BYTE PTR [SI],0
+ POP SI
+ POP DS
+ JNZ CHAININT ;DOS is Buisy
+ INC [BUSY] ;Exclude furthur interrupts
+ MOV [TICKCNT],0 ;Reset tick counter
+ MOV [TICKSUB],0 ;Reset tick counter
+ STI ;Keep things rolling
+
+ IF AINT
+ MOV AL,EOI ;Acknowledge interrupt
+ OUT AKPORT,AL
+ ENDIF
+
+ CALL DOINT
+ CLI
+ MOV [SLICECNT],TIMESLICE ;Either soft or hard int resets time slice
+ MOV [BUSY],0 ;Done, let others in
+CHAININT:
+ JMP [NEXTINT] ;Chain to next clock routine
+ ENDIF
+
+
+SPINT: ;INT 28H entry point
+ IF HARDINT
+ CMP [BUSY],0
+ JNZ NXTSP
+ INC [BUSY] ;Exclude hardware interrupt
+ INC [SOFINT] ;Indicate a software int in progress
+ ENDIF
+
+ STI ;Hardware interrupts ok on INT 28H entry
+ CALL DOINT
+
+ IF HARDINT
+ CLI
+ MOV [SOFINT],0 ;Indicate INT done
+ MOV [SLICECNT],TIMESLICE ;Either soft or hard int resets time slice
+ MOV [BUSY],0
+ ENDIF
+
+NXTSP: JMP [SPNEXT] ;Chain to next INT 28
+
+DOINT:
+ PUSH SI
+ MOV SI,[CURRFIL]
+ INC SI
+ INC SI
+ CMP BYTE PTR CS:[SI],-1
+ POP SI
+ JNZ GOAHEAD
+ JMP SPRET ;Nothing to do
+GOAHEAD:
+ PUSH AX ;Need a working register
+ MOV [SSsave],SS
+ MOV [SPsave],SP
+ MOV AX,CS
+ CLI
+;Go to internal stack to prevent INT 24 overflowing system stack
+ MOV SS,AX
+ MOV SP,OFFSET DG:ISTACK
+ STI
+ PUSH ES
+ PUSH DS
+ PUSH BX
+ PUSH CX
+ PUSH DX
+ PUSH SI
+ PUSH DI
+ PUSH CS
+ POP DS
+ASSUME DS:DG
+
+ MOV BX,[NXTCHR]
+ CMP BX,OFFSET DG:BUFFER + BLKSIZ
+ JNZ PLOOP
+ JMP READBUFF ;Buffer empty
+
+PLOOP:
+ IF HARDINT
+ MOV BX,[NXTCHR]
+ CMP BX,OFFSET DG:BUFFER + BLKSIZ
+ JZ DONEJMP ;Buffer has become empty
+ CMP [SOFINT],0
+ JNZ STATCHK
+ CMP [TICKCNT],MAXTICK ;Check our time slice
+ JAE DONEJMP
+STATCHK:
+ ENDIF
+
+ CALL PSTAT
+
+ IF HARDINT
+ JZ DOCHAR ;Printer ready
+ CMP [SOFINT],0
+ ENDIF
+
+ JNZ DONEJMP ;If soft int give up
+
+ IF HARDINT
+ CMP [TICKSUB],BUSYTICK ;Check our busy timeout
+ JAE DONEJMP
+ JMP PLOOP
+ ENDIF
+
+DOCHAR:
+ MOV AL,BYTE PTR [BX]
+ CMP AL,1AH ;^Z?
+ JZ FILEOFJ ;CPM EOF
+ CMP AL,0DH ;CR?
+ JNZ NOTCR
+ MOV [COLPOS],0
+NOTCR:
+ CMP AL,9 ;TAB?
+ JNZ NOTABDO
+ MOV CL,[COLPOS]
+ OR CL,0F8H
+ NEG CL
+ XOR CH,CH
+ JCXZ TABDONE
+TABLP:
+ MOV AL," "
+ INC [COLPOS]
+ PUSH CX
+ CALL POUT
+ POP CX
+ LOOP TABLP
+ JMP TABDONE
+
+NOTABDO:
+ CMP AL,8 ;Back space?
+ JNZ NOTBACK
+ DEC [COLPOS]
+NOTBACK:
+ CMP AL,20H ;Non Printing char?
+ JB NOCHAR
+ INC [COLPOS] ;Printing char
+NOCHAR:
+ CALL POUT ;Print it
+TABDONE:
+ INC [NXTCHR] ;Next char
+
+ IF HARDINT
+ MOV [TICKSUB],0 ;Got a character out, Reset counter
+ CMP [SOFINT],0 ;Soft int does one char at a time
+ JZ PLOOP
+ ENDIF
+
+DONEJMP:
+ POP DI
+ POP SI
+ POP DX
+ POP CX
+ POP BX
+ POP DS
+ POP ES
+ASSUME DS:NOTHING,ES:NOTHING
+ CLI
+ MOV SS,[SSsave] ;Restore Entry Stack
+ MOV SP,[SPsave]
+ STI
+ POP AX
+SPRET:
+ RET
+
+FILEOFJ: JMP FILEOF
+
+READBUFF:
+ASSUME DS:DG,ES:NOTHING
+
+ MOV AL,24H
+ MOV AH,GET_INTERRUPT_VECTOR
+ INT 21H
+ MOV WORD PTR [HERRINT+2],ES ;Save current vector
+ MOV WORD PTR [HERRINT],BX
+ MOV DX,OFFSET DG:DSKERR
+ MOV AL,24H
+ MOV AH,SET_INTERRUPT_VECTOR ;Install our own
+ INT 21H ;Spooler must catch its errors
+ MOV AH,GET_DMA
+ INT 21H
+ MOV WORD PTR [DMAADDR+2],ES ;Save DMA address
+ MOV WORD PTR [DMAADDR],BX
+ MOV DX,OFFSET DG:BUFFER
+ MOV AH,SET_DMA
+ INT 21H ;New DMA address
+ MOV [PABORT],0 ;No abort
+ MOV DX,[CURRFIL] ;Read
+ INC DX
+ INC DX ;Skip over pointer
+ MOV AH,FCB_SEQ_READ
+ INT 21H
+ PUSH AX
+ LDS DX,[DMAADDR]
+ASSUME DS:NOTHING
+ MOV AH,SET_DMA
+ INT 21H ;Restore DMA
+ LDS DX,[HERRINT]
+ MOV AL,24H
+ MOV AH,SET_INTERRUPT_VECTOR
+ INT 21H ;Restore Error INT
+ POP AX
+ PUSH CS
+ POP DS
+ASSUME DS:DG
+ CMP [PABORT],0
+ JNZ TONEXTFIL ;Barf on this file, got INT 24
+ CMP AL,01
+ JZ FILEOF ;Read EOF?
+ MOV BX,OFFSET DG:BUFFER ;Buffer full
+ MOV [NXTCHR],BX
+ JMP DONEJMP
+
+FILEOF:
+ MOV AL,0CH ;Form feed
+ CALL LOUT
+TONEXTFIL:
+ CALL NEXTFIL
+ JMP DONEJMP
+
+;INT 24 handler
+
+DSKERR:
+ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
+ STI
+ CMP [PABORT],0
+ JNZ IGNRET
+ PUSH BX
+ PUSH CX
+ PUSH DX
+ PUSH DI
+ PUSH SI
+ PUSH BP
+ PUSH ES
+ PUSH DS
+ PUSH CS
+ POP DS
+ PUSH CS
+ POP ES
+ASSUME DS:DG,ES:DG
+ ADD [BADDRVM],AL ;Set correct drive letter
+ MOV SI,OFFSET DG:ERRMES
+ CALL LISTMES
+ TEST AH,080H
+ JNZ FATERR
+ AND DI,0FFH
+ CMP DI,12
+ JBE HAVCOD
+ MOV DI,12
+HAVCOD:
+ SHL DI,1
+ MOV DI,WORD PTR [DI+MESBAS] ; Get pointer to error message
+ MOV SI,DI
+ CALL LISTMES ; Print error type
+ MOV DI,OFFSET DG:EMFILNAM
+ MOV SI,[CURRFIL]
+ ADD SI,2 ;Get to file name
+ LODSB
+ ADD AL,'@'
+ STOSB
+ INC DI
+ MOV CX,4
+ REP MOVSW
+ INC DI
+ MOVSW
+ MOVSB
+ MOV SI,OFFSET DG:ERRMEST
+ CALL LISTMES
+SETABORT:
+ INC [PABORT] ;Indicate abort
+ POP DS
+ POP ES
+ POP BP
+ POP SI
+ POP DI
+ POP DX
+ POP CX
+ POP BX
+IGNRET:
+ XOR AL,AL ;Ignore
+ IRET
+
+FATERR:
+ MOV SI,OFFSET DG:FATMES
+ CALL LISTMES
+ JMP SHORT SETABORT
+
+ADDFILJ: JMP ADDFIL
+
+COMBUSY:
+ MOV AX,-1
+ IRET
+
+;Communications interrupt
+SPCOMINT:
+ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
+ CMP [CBUSY],0
+ JNZ COMBUSY
+ INC [CBUSY] ;Exclude
+ STI ;Turn ints back on
+ PUSH SI
+ PUSH DI
+ PUSH CX
+ PUSH DS
+ PUSH CS
+ POP DS
+ASSUME DS:DG
+ MOV [PCANMES],0 ;Havn't printed cancel message
+ OR AH,AH
+ JZ ADDFILJ ;Add file
+ CMP AH,1
+ JZ CANFIL ;Cancel File(s)
+ XOR AL,AL
+SETCOUNT:
+ PUSH AX ;Save AL return code
+ XOR AH,AH
+ MOV SI,OFFSET DG:SPLFCB
+ MOV CX,[NUMFCBS]
+CNTFILS:
+ CMP BYTE PTR [SI+2],-1 ;Valid?
+ JZ LNEXT
+ INC AH
+LNEXT:
+ ADD SI,FCBSIZ
+ LOOP CNTFILS
+COMRET:
+ MOV BX,OFFSET DG:SPLFCB
+ MOV DX,[CURRFIL]
+ PUSH DS
+ POP ES
+ASSUME ES:NOTHING
+ MOV CH,AH
+ POP AX ;Get AL return
+ MOV AH,CH
+
+ IF HARDINT
+BWAIT3:
+ CMP [BUSY],0
+ JNZ BWAIT3
+ INC [BUSY]
+ ENDIF
+
+ CALL PSTAT ; Tweek error counter
+
+ IF HARDINT
+ MOV [BUSY],0
+ ENDIF
+
+ POP DS
+ASSUME DS:NOTHING
+ POP CX
+ POP DI
+ POP SI
+ MOV [CBUSY],0
+ IRET
+
+DELALLJ: JMP DELALL
+
+CANFIL:
+ASSUME DS:DG,ES:NOTHING
+ MOV CX,[NUMFCBS]
+
+ IF HARDINT
+BWAIT:
+ CMP [BUSY],0
+ JNZ BWAIT
+ INC [BUSY]
+ ENDIF
+
+ MOV SI,[CURRFIL]
+ CMP DX,-1
+ JZ DELALLJ
+ MOV BX,[SI]
+ PUSH BX
+LOOKEND: ;Set initial pointer values
+ CMP BX,SI
+ JZ GOTLAST
+ POP AX
+ PUSH BX
+ MOV BX,[BX]
+ JMP SHORT LOOKEND
+
+GOTLAST:
+ POP BX
+ MOV [LASTFCB],BX
+ MOV [LASTFCB2],BX
+ POP ES
+ PUSH ES
+ MOV BX,SI
+LOOKMATCH:
+ MOV DI,DX
+ ADD SI,2 ;Skip pointer
+ CMP BYTE PTR [SI],-1
+ JZ CANTERMJ ;No more
+ CMPSB
+ JNZ SKIPFIL ;DRIVE
+ PUSH CX
+ MOV CX,11
+NXTCHAR:
+ MOV AL,ES:[DI]
+ INC DI
+ CALL UPCONV
+ MOV AH,AL
+ LODSB
+ CALL UPCONV
+ CMP AH,"?" ;Wild card?
+ JZ NXTCHRLP ;Yes
+ CMP AH,AL
+ JNZ SKIPFILC
+NXTCHRLP:
+ LOOP NXTCHAR
+MATCH:
+ POP CX
+ MOV AH,-1
+ XCHG AH,[BX+2] ;Zap it
+ CMP BX,[CURRFIL] ;Is current file?
+ JNZ REQUEUE ;No
+ MOV AL,1
+ XCHG AL,[PCANMES]
+ OR AL,AL
+ JNZ DIDCMES ;Only print cancel message once
+ PUSH ES
+ PUSH CS
+ POP ES
+ MOV DI,OFFSET DG:CANFILNAM
+ MOV SI,BX
+ ADD SI,3 ;Get to file name
+ MOV AL,AH
+ ADD AL,'@'
+ STOSB
+ INC DI
+ MOV CX,4
+ REP MOVSW
+ INC DI
+ MOVSW
+ MOVSB
+ POP ES
+ MOV SI,OFFSET DG:CANMES
+ CALL LISTMES
+ MOV SI,OFFSET DG:BELMES
+ CALL LISTMES
+DIDCMES:
+ PUSH CX
+ CALL NEXTFIL
+SKIPFILC:
+ POP CX
+SKIPFIL:
+ MOV [LASTFCB2],BX
+ MOV BX,[BX]
+NEXTFC:
+ MOV SI,BX
+ LOOP LOOKMATCH
+CANTERMJ: JMP SHORT CANTERM
+
+REQUEUE:
+ MOV AX,[BX]
+ CMP AX,[CURRFIL] ;Is last FCB?
+ JZ SKIPFIL ;Yes, is in right place
+ MOV SI,[LASTFCB2]
+ MOV [SI],AX ;Unlink FCB
+ MOV SI,[CURRFIL]
+ MOV [BX],SI
+ MOV SI,[LASTFCB]
+ MOV [SI],BX ;Link FCB at end
+ MOV [LASTFCB],BX ;New end
+ MOV BX,AX ;Process what it pointed to
+ JMP SHORT NEXTFC
+
+DELALL:
+ CMP BYTE PTR CS:[SI+2],-1 ;Examine current file
+DELALL2:
+ MOV BYTE PTR [SI+2],-1 ;Zap it
+ MOV SI,[SI]
+ LOOP DELALL2
+ JZ CANTERM1 ;No message if nothing was in progress
+ MOV SI,OFFSET DG:ALLCAN
+ CALL LISTMES
+ MOV SI,OFFSET DG:BELMES
+ CALL LISTMES
+CANTERM1:
+ MOV [NXTCHR],OFFSET DG:BUFFER + BLKSIZ ;Buffer empty
+CANTERM:
+
+ IF HARDINT
+ MOV [BUSY],0
+ ENDIF
+
+ XOR AX,AX
+ JMP SETCOUNT
+
+UPCONV:
+ CMP AL,'a'
+ JB NOCONV
+ CMP AL,'z'
+ JA NOCONV
+ SUB AL,20H
+NOCONV:
+ RET
+
+ADDFIL:
+ASSUME DS:DG,ES:NOTHING
+ MOV SI,[CURRFIL]
+ MOV CX,[NUMFCBS]
+
+ IF HARDINT
+BWAIT2:
+ CMP [BUSY],0
+ JNZ BWAIT2
+ INC [BUSY]
+ ENDIF
+
+LOOKSPOT:
+ CMP BYTE PTR [SI+2],-1
+ JZ GOTSPOT
+ MOV SI,[SI]
+ LOOP LOOKSPOT
+
+ IF HARDINT
+ MOV [BUSY],0
+ ENDIF
+
+ MOV AL,1
+ JMP SETCOUNT
+
+GOTSPOT:
+ PUSH DS
+ POP ES
+ POP DS
+ PUSH DS
+ASSUME DS:NOTHING
+ PUSH SI
+ MOV DI,SI
+ ADD DI,2
+ MOV SI,DX
+ MOV CX,19
+ REP MOVSW ;Copy in and set FCB
+ POP SI
+ PUSH ES
+ POP DS
+ASSUME DS:DG
+ MOV WORD PTR [SI+2+fcb_EXTENT],0
+ MOV BYTE PTR [SI+2+fcb_NR],0
+ MOV WORD PTR [SI+2+fcb_RECSIZ],BLKSIZ
+
+ IF HARDINT
+ MOV [BUSY],0
+ ENDIF
+
+ XOR AL,AL
+ JMP SETCOUNT
+
+NEXTFIL:
+ASSUME DS:DG,ES:NOTHING
+ MOV SI,[CURRFIL]
+ MOV BYTE PTR [SI+2],-1 ;Done with current file
+ MOV SI,[SI]
+ MOV [CURRFIL],SI
+ MOV [NXTCHR],OFFSET DG:BUFFER + BLKSIZ ;Buffer empty
+ MOV [COLPOS],0 ;Start of line
+ RET
+
+LISTMES:
+ASSUME DS:DG,ES:NOTHING
+ LODSB
+ CMP AL,"$"
+ JZ LMESDONE
+ CALL LOUT
+ JMP LISTMES
+
+LMESDONE:
+ RET
+
+LOUT:
+ PUSH BX
+LWAIT:
+ CALL PSTAT
+ JZ PREADY
+ CMP [ERRCNT],ERRCNT2
+ JA POPRET ;Don't get stuck
+ JMP SHORT LWAIT
+PREADY:
+ CALL POUT
+POPRET:
+ POP BX
+ RET
+
+;Stuff for BIOS interface
+IOBUSY EQU 0200H
+IOERROR EQU 8000H
+
+BYTEBUF DB ?
+
+CALLAD DD ?
+
+IOCALL DB 22
+ DB 0
+IOREQ DB ?
+IOSTAT DW 0
+ DB 8 DUP(?)
+ DB 0
+ DW OFFSET DG:BYTEBUF
+INTSEG DW ?
+IOCNT DW 1
+ DW 0
+
+PSTAT:
+ASSUME DS:DG
+ PUSH BX
+ INC [ERRCNT]
+ MOV BL,10
+ CALL DOCALL
+ TEST [IOSTAT],IOERROR
+ JZ NOSTATERR
+ OR [IOSTAT],IOBUSY ;If error, show buisy
+NOSTATERR:
+ TEST [IOSTAT],IOBUSY
+ JNZ RET13P ;Shows buisy
+ MOV [ERRCNT],0
+RET13P:
+ POP BX
+ RET
+
+POUT:
+ASSUME DS:DG
+ MOV [BYTEBUF],AL
+ MOV BL,8
+DOCALL:
+ PUSH ES
+ MOV [IOREQ],BL
+ MOV BX,CS
+ MOV ES,BX
+ MOV BX,OFFSET DG:IOCALL
+ MOV [IOSTAT],0
+ MOV [IOCNT],1
+ PUSH DS
+ PUSH SI
+ PUSH AX
+ LDS SI,[LISTDEV]
+ASSUME DS:NOTHING
+ MOV AX,[SI+6]
+ MOV WORD PTR [CALLAD],AX
+ CALL [CALLAD]
+ MOV AX,[SI+8]
+ MOV WORD PTR [CALLAD],AX
+ CALL [CALLAD]
+ POP AX
+ POP SI
+ POP DS
+ASSUME DS:DG
+ POP ES
+ RET
+
+ IF IBM
+REAL_INT_13 DD ?
+INT_13_RETADDR DW OFFSET DG:INT_13_BACK
+
+INT_13 PROC FAR
+ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
+ PUSHF
+ INC [BUSY] ;Exclude if dumb program call ROM
+ PUSH CS
+ PUSH [INT_13_RETADDR]
+ PUSH WORD PTR [REAL_INT_13+2]
+ PUSH WORD PTR [REAL_INT_13]
+ RET
+INT_13 ENDP
+
+INT_13_BACK PROC FAR
+ PUSHF
+ DEC [BUSY]
+ POPF
+ RET 2 ;Chuck saved flags
+INT_13_BACK ENDP
+ ENDIF
+
+
+ IF IBM
+
+REAL_INT_5 DD ?
+REAL_INT_17 DD ?
+INT_17_NUM DW 0
+
+INT_17:
+ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
+ PUSH SI
+ MOV SI,[CURRFIL]
+ INC SI
+ INC SI
+ CMP BYTE PTR CS:[SI],-1
+ POP SI
+ JZ DO_INT_17 ;Nothing pending, so OK
+ CMP DX,[INT_17_NUM]
+ JNZ DO_INT_17 ;Not my unit
+ CMP [BUSY],0
+ JNZ DO_INT_17 ;You are me
+ STI
+ MOV AH,0A1H ;You are bad, get out of paper
+ IRET
+
+DO_INT_17:
+ JMP [REAL_INT_17] ;Do a 17
+
+REAL_INT_14 DD ?
+INT_14_NUM DW 0
+
+INT_14:
+ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
+ PUSH SI
+ MOV SI,[CURRFIL]
+ INC SI
+ INC SI
+ CMP BYTE PTR CS:[SI],-1
+ POP SI
+ JZ DO_INT_14 ;Nothing pending, so OK
+ CMP DX,[INT_14_NUM]
+ JNZ DO_INT_14 ;Not my unit
+ CMP [BUSY],0
+ JNZ DO_INT_14 ;You are me
+ STI
+ OR AH,AH
+ JZ SET14_AX
+ CMP AH,2
+ JBE SET14_AH
+SET14_AX:
+ MOV AL,0
+SET14_AH:
+ MOV AH,80H ;Time out
+ IRET
+
+DO_INT_14:
+ JMP [REAL_INT_14] ;Do a 14
+
+INT_5:
+ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
+ PUSH SI
+ MOV SI,[CURRFIL]
+ INC SI
+ INC SI
+ CMP BYTE PTR CS:[SI],-1
+ POP SI
+ JZ DO_INT_5 ;Nothing pending, so OK
+ CMP [INT_17_NUM],0
+ JNZ DO_INT_5 ;Only care about unit 0
+ IRET ;Pretend it worked
+
+DO_INT_5:
+ JMP [REAL_INT_5] ;Do a 5
+ ENDIF
+
+
+;The following data is order and position dependant
+NUMFCBS DW 10
+ERRCNT DW 0
+
+SPLFCB DW OFFSET DG:FC1
+ DB (FCBSIZ - 2) DUP (-1)
+FC1 DW OFFSET DG:FC2
+ DB (FCBSIZ - 2) DUP (-1)
+FC2 DW OFFSET DG:FC3
+ DB (FCBSIZ - 2) DUP (-1)
+FC3 DW OFFSET DG:FC4
+ DB (FCBSIZ - 2) DUP (-1)
+FC4 DW OFFSET DG:FC5
+ DB (FCBSIZ - 2) DUP (-1)
+FC5 DW OFFSET DG:FC6
+ DB (FCBSIZ - 2) DUP (-1)
+FC6 DW OFFSET DG:FC7
+ DB (FCBSIZ - 2) DUP (-1)
+FC7 DW OFFSET DG:FC8
+ DB (FCBSIZ - 2) DUP (-1)
+FC8 DW OFFSET DG:FC9
+ DB (FCBSIZ - 2) DUP (-1)
+FC9 DW OFFSET DG:SPLFCB
+ DB (FCBSIZ - 2) DUP (-1)
+
+DEF_ENDRES LABEL BYTE
+
+ASSUME CS:DG,DS:DG,ES:DG,SS:DG
+
+BADSPOOL:
+ MOV DX,OFFSET DG:BADMES
+ MOV AH,STD_CON_STRING_OUTPUT
+ INT 21H
+ INT 20H
+
+SETUP:
+;Called once to install resident
+ CLD
+ MOV [INTSEG],CS
+ MOV DX,OFFSET DG:PROMPT
+ MOV AH,STD_CON_STRING_OUTPUT
+ INT 21H
+ MOV DX,OFFSET DG:COMBUF
+ MOV AH,STD_CON_STRING_INPUT
+ INT 21H ;Get device name
+ MOV DX,OFFSET DG:CRLF
+ MOV AH,STD_CON_STRING_OUTPUT
+ INT 21H
+ MOV CL,[COMBUF+1]
+ OR CL,CL
+ JZ DEFSPOOL ;User didn't specify one
+ XOR CH,CH
+ MOV DI,OFFSET DG:LISTFCB + 1
+ MOV SI,OFFSET DG:COMBUF + 2
+ REP MOVSB
+DEFSPOOL:
+ MOV DX,OFFSET DG:LISTFCB
+ MOV AH,FCB_OPEN
+ INT 21H
+ OR AL,AL
+ JNZ BADSPOOL ;Bad
+ TEST BYTE PTR [LISTFCB.fcb_DEVID],080H
+ JZ BADSPOOL ;Must be a device
+ LDS SI,DWORD PTR [LISTFCB.fcb_FIRCLUS]
+ASSUME DS:NOTHING
+ MOV WORD PTR [CALLAD+2],DS ;Get I/O routines
+ MOV WORD PTR [LISTDEV+2],DS ;Get I/O routines
+ MOV WORD PTR [LISTDEV],SI
+ PUSH CS
+ POP DS
+ASSUME DS:DG
+ MOV DX,OFFSET DG:SPINT
+ MOV AL,SOFTINT
+ MOV AH,GET_INTERRUPT_VECTOR
+ INT 21H ;Get soft vector
+ MOV WORD PTR [SPNEXT+2],ES
+ MOV WORD PTR [SPNEXT],BX
+ MOV AL,SOFTINT
+ MOV AH,SET_INTERRUPT_VECTOR
+ INT 21H ;Set soft vector
+ MOV DX,OFFSET DG:SPCOMINT
+ MOV AL,COMINT
+ MOV AH,SET_INTERRUPT_VECTOR ;Set communication vector
+ INT 21H
+
+ IF IBM
+ MOV AL,13H
+ MOV AH,GET_INTERRUPT_VECTOR
+ INT 21H
+ MOV WORD PTR [REAL_INT_13+2],ES
+ MOV WORD PTR [REAL_INT_13],BX
+ MOV DX,OFFSET DG:INT_13
+ MOV AL,13H
+ MOV AH,SET_INTERRUPT_VECTOR
+ INT 21H ;Set diskI/O interrupt
+ MOV AL,17H
+ MOV AH,GET_INTERRUPT_VECTOR
+ INT 21H
+ MOV WORD PTR [REAL_INT_17+2],ES
+ MOV WORD PTR [REAL_INT_17],BX
+ MOV AL,14H
+ MOV AH,GET_INTERRUPT_VECTOR
+ INT 21H
+ MOV WORD PTR [REAL_INT_14+2],ES
+ MOV WORD PTR [REAL_INT_14],BX
+ MOV AL,5H
+ MOV AH,GET_INTERRUPT_VECTOR
+ INT 21H
+ MOV WORD PTR [REAL_INT_5+2],ES
+ MOV WORD PTR [REAL_INT_5],BX
+ PUSH CS
+ POP ES
+ MOV BP,OFFSET DG:LISTFCB + 1
+ MOV SI,BP
+ MOV CX,8
+CONLP: ;Make sure device name in upper case
+ LODSB
+ CMP AL,'a'
+ JB DOCONLP
+ CMP AL,'z'
+ JA DOCONLP
+ SUB BYTE PTR [SI-1],20H
+DOCONLP:
+ LOOP CONLP
+ MOV DI,OFFSET DG:INT_17_HITLIST
+CHKHIT:
+ MOV SI,BP
+ MOV CL,[DI]
+ INC DI
+ JCXZ NOTONHITLIST
+ REPE CMPSB
+ LAHF
+ ADD DI,CX ;Bump to next position without affecting flags
+ MOV BL,[DI] ;Get device number
+ INC DI
+ SAHF
+ JNZ CHKHIT
+ XOR BH,BH
+ MOV [INT_17_NUM],BX
+ MOV DX,OFFSET DG:INT_17
+ MOV AL,17H
+ MOV AH,SET_INTERRUPT_VECTOR
+ INT 21H ;Set printer interrupt
+ MOV DX,OFFSET DG:INT_5
+ MOV AL,5H
+ MOV AH,SET_INTERRUPT_VECTOR
+ INT 21H ;Set print screen interrupt
+ JMP SHORT ALLSET
+NOTONHITLIST:
+ MOV DI,OFFSET DG:INT_14_HITLIST
+CHKHIT2:
+ MOV SI,BP
+ MOV CL,[DI]
+ INC DI
+ JCXZ ALLSET
+ REPE CMPSB
+ LAHF
+ ADD DI,CX ;Bump to next position without affecting flags
+ MOV BL,[DI] ;Get device number
+ INC DI
+ SAHF
+ JNZ CHKHIT2
+ XOR BH,BH
+ MOV [INT_14_NUM],BX
+ MOV DX,OFFSET DG:INT_14
+ MOV AL,14H
+ MOV AH,SET_INTERRUPT_VECTOR
+ INT 21H ;Set RS232 port interrupt
+ALLSET:
+ ENDIF
+
+ IF HARDINT
+ MOV AH,GET_INDOS_FLAG
+ INT 21H
+ MOV WORD PTR [INDOS+2],ES ;Get indos flag location
+ MOV WORD PTR [INDOS],BX
+ MOV AL,INTLOC
+ MOV AH,GET_INTERRUPT_VECTOR
+ INT 21H
+ MOV WORD PTR [NEXTINT+2],ES
+ MOV WORD PTR [NEXTINT],BX
+ MOV DX,OFFSET DG:HDSPINT
+ MOV AL,INTLOC
+ MOV AH,SET_INTERRUPT_VECTOR
+ INT 21H ;Set hardware interrupt
+ ENDIF
+
+ MOV [MAKERES],1 ;Indicate to do a terminate stay resident
+ MOV DX,OFFSET DG:GOODMES
+ MOV AH,STD_CON_STRING_OUTPUT
+ INT 21H
+ RET
+
+ASSUME CS:DG,DS:DG,ES:DG,SS:DG
+
+TRANSIENT:
+;User interface
+ CLD
+
+;Code to print header
+; MOV DX,OFFSET DG:HEADER
+; MOV AH,STD_CON_STRING_OUTPUT
+; INT 21H
+
+DOSVER_LOW EQU 0136H ;1.54 in hex
+DOSVER_HIGH EQU 020BH ;2.11 in hex
+ 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:
+ PUSH CS
+ POP DS
+ MOV DX,OFFSET DG:BADVER
+ MOV AH,STD_CON_STRING_OUTPUT
+ INT 21H
+ INT 20H
+OKDOS:
+ MOV AX,CHAR_OPER SHL 8
+ INT 21H
+ MOV [SWITCHAR],DL ;Get user switch character
+ MOV AH,GET_INTERRUPT_VECTOR
+ MOV AL,COMINT
+ INT 21H
+ASSUME ES:NOTHING
+ MOV DI,BX
+ MOV SI,OFFSET DG:SPCOMINT
+ MOV CX,13
+ REPE CMPSB
+ JZ GOTRES ;Signature matched
+ PUSH CS
+ POP ES
+ CALL SETUP
+GOTRES:
+ PUSH CS
+ POP ES
+ MOV AH,GET_DEFAULT_DRIVE
+ INT 21H
+ MOV [DEFDRV],AL
+ MOV SI,PARMS
+ LODSB
+ OR AL,AL
+ JNZ GOTPARMS
+TRANEXIT:
+ CALL GETSPLIST
+ CMP [MAKERES],0
+ JNZ SETRES
+ INT 20H
+
+SETRES:
+ MOV DX,[ENDRES]
+ INT 27H
+
+ARGSDONE:
+ CMP [ARGSETUP],0
+ JZ TRANEXIT
+ CALL PROCESS
+ JMP SHORT TRANEXIT
+
+GOTPARMS:
+PARSE:
+ MOV DI,OFFSET DG:PARSEBUF
+ CALL CPARSE
+ JC ARGSDONE
+ CMP AX,4 ;Switch?
+ JNZ GOTNORMARG
+ MOV AL,[DI] ;Get the switch character
+ CMP AL,'C'
+ JZ SETCAN
+ CMP AL,'c'
+ JNZ CHKSPL
+SETCAN:
+ MOV [CANFLG],1
+ JMP SHORT PARSE
+CHKSPL:
+ CMP AL,'P'
+ JZ RESETCAN
+ CMP AL,'p'
+ JNZ CHKTERM
+RESETCAN:
+ MOV [CANFLG],0
+ JMP SHORT PARSE
+CHKTERM:
+ CMP AL,'T'
+ JZ SETTERM
+ CMP AL,'t'
+ JZ SETTERM
+ MOV DX,OFFSET DG:BADSWT
+ MOV AH,STD_CON_STRING_OUTPUT
+ INT 21H
+ JMP SHORT PARSE
+
+SETTERM:
+ CALL TERMPROCESS
+ JMP TRANEXIT ; Ignore everything after T switch
+
+GOTNORMARG:
+ XOR AL,AL
+ XCHG AL,[ARGSETUP]
+ OR AL,AL
+ JZ PARSEARG
+ CALL NORMPROC ;Don't test ARGSETUP, it just got zeroed
+PARSEARG:
+ PUSH SI
+ MOV SI,DI
+ MOV DI,FCB
+ MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 1
+ INT 21H ;Parse the arg
+ CMP BYTE PTR [DI],0
+ JNZ DRVOK
+ MOV DL,[DEFDRV]
+ INC DL
+ MOV BYTE PTR [DI],DL ;Set the default drive
+DRVOK:
+ POP SI
+ INC [ARGSETUP]
+ JMP SHORT PARSE
+
+TERMPROCESS:
+ MOV DX,-1
+PROCRET:
+ MOV AH,1
+ CALL DOSET
+PROCRETNFUNC:
+ MOV [ARGSETUP],0
+ PUSH CS
+ POP ES
+RET14: RET
+
+PROCESS:
+ CMP [ARGSETUP],0
+ JZ RET14 ;Nothing to process
+NORMPROC:
+ MOV AL,BYTE PTR DS:[FCB+1]
+ CMP AL," "
+ JZ SRCHBADJ
+ MOV DX,FCB
+ MOV AH,[CANFLG]
+ CMP AH,0
+ JNZ PROCRET
+ MOV DX,OFFSET DG:SRCHFCB
+ MOV AH,SET_DMA
+ INT 21H
+ MOV DX,FCB
+ MOV AH,DIR_SEARCH_FIRST
+ INT 21H
+ OR AL,AL
+ JNZ SRCHBADJ
+SRCHLOOP:
+ MOV DX,OFFSET DG:SRCHFCB
+ MOV AH,FCB_OPEN
+ INT 21H
+ OR AL,AL
+ JZ OPENOK
+ CALL OPENERR
+ JMP SHORT NEXTSEARCH
+SRCHBADJ: JMP SRCHBAD
+OPENOK:
+ MOV DX,OFFSET DG:SRCHFCB
+ MOV AH,0
+ CALL DOSET
+ OR AL,AL
+ JZ NEXTSEARCH
+ XCHG AL,[FULLFLAG] ;Know AL non-zero
+ OR AL,AL
+ JNZ NEXTSEARCH ;Only print message once
+ MOV DX,OFFSET DG:FULLMES ;Queue full
+ MOV AH,STD_CON_STRING_OUTPUT
+ INT 21H
+NEXTSEARCH:
+ MOV DX,OFFSET DG:SRCHFCB
+ MOV AH,SET_DMA
+ INT 21H
+ MOV DX,FCB
+ MOV AH,DIR_SEARCH_NEXT
+ INT 21H
+ OR AL,AL
+ JNZ PROCRETNFUNC
+ JMP SRCHLOOP
+
+DOSET:
+ INT COMINT
+ MOV [FILCNT],AH ;Suck up return info
+ MOV WORD PTR [SPLIST+2],ES
+ MOV WORD PTR [CURFILE+2],ES
+ MOV WORD PTR [SPLIST],BX
+ MOV WORD PTR [CURFILE],DX
+ RET
+
+OPENERR:
+ PUSH SI
+ PUSH DI
+ MOV SI,OFFSET DG:OPFILNAM
+ PUSH DS
+ POP ES
+ MOV DI,OFFSET DG:SRCHFCB
+ CALL MVFNAM
+ MOV DX,OFFSET DG:OPMES
+ MOV AH,STD_CON_STRING_OUTPUT
+ INT 21H
+ POP DI
+ POP SI
+ RET
+
+SRCHBAD:
+ PUSH SI
+ PUSH DI
+ MOV SI,OFFSET DG:SRCHFNAM
+ PUSH DS
+ POP ES
+ MOV DI,FCB
+ CALL MVFNAM
+ MOV DX,OFFSET DG:SRCHMES
+ MOV AH,STD_CON_STRING_OUTPUT
+ INT 21H
+ POP DI
+ POP SI
+ JMP PROCRETNFUNC
+
+GETSPLIST:
+ MOV AH,0FFH
+ CALL DOSET
+ PUSH DS
+ LDS DI,[SPLIST]
+ MOV DI,[DI-2] ;Get the error count
+ POP DS
+ CMP DI,ERRCNT1
+ JB CNTOK
+ MOV DX,OFFSET DG:CNTMES
+ MOV AH,STD_CON_STRING_OUTPUT
+ INT 21H
+CNTOK:
+ MOV CL,[FILCNT]
+ OR CL,CL
+ JZ NOFILES
+ XOR CH,CH
+ LES DI,[CURFILE]
+ PUSH DI
+ INC DI
+ INC DI
+ MOV SI,OFFSET DG:CURFNAM
+ CALL MVFNAM
+ POP DI
+ MOV DX,OFFSET DG:CURMES
+ MOV AH,STD_CON_STRING_OUTPUT
+ INT 21H
+ DEC CX
+ JCXZ RET12
+FILOOP:
+ MOV DI,ES:[DI]
+ PUSH DI
+ INC DI
+ INC DI
+ MOV SI,OFFSET DG:FILFNAM
+ CALL MVFNAM
+ POP DI
+ MOV DX,OFFSET DG:FILMES
+ MOV AH,STD_CON_STRING_OUTPUT
+ INT 21H
+ LOOP FILOOP
+RET12: RET
+
+NOFILES:
+ MOV DX,OFFSET DG:NOFILS
+ MOV AH,STD_CON_STRING_OUTPUT
+ INT 21H
+ RET
+
+;Make a message with the file name
+MVFNAM:
+ASSUME DS:NOTHING,ES:NOTHING
+ PUSH SI
+ PUSH DI
+ PUSH CX
+ MOV AX,ES
+ PUSH DS
+ POP ES
+ MOV DS,AX
+ XCHG SI,DI
+ LODSB
+ ADD AL,"@"
+ CMP AL,"@"
+ JNZ STCHR
+ MOV AL,[DEFDRV]
+ ADD AL,"A"
+STCHR:
+ STOSB
+ INC DI
+ MOV CX,4
+ REP MOVSW
+ INC DI
+ MOVSW
+ MOVSB
+ MOV AX,ES
+ PUSH DS
+ POP ES
+ MOV DS,AX
+ POP CX
+ POP DI
+ POP SI
+ RET
+
+;-----------------------------------------------------------------------;
+; ENTRY: ;
+; DS:SI Points input buffer ;
+; ES:DI Points to the token buffer ;
+; ;
+; EXIT: ;
+; DS:SI Points to next char in the input buffer ;
+; ES:DI Points to the token buffer ;
+; CX Character count ;
+; AX Condition Code ;
+; =1 same as carry set ;
+; =2 normal token ;
+; =4 switch character, char in token buffer ;
+; Carry Flag Set if a CR was found, Reset otherwise ;
+; ;
+; MODIFIES: ;
+; CX, SI, AX and the Carry Flag ;
+; ;
+;-----------------------------------------------------------------------;
+
+TAB equ 09h
+CR equ 0dh
+
+CPARSE:
+ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
+ pushf ;save flags
+ push di ;save the token buffer addrss
+ xor cx,cx ;no chars in token buffer
+ call kill_bl
+
+ cmp al,CR ;a CR?
+ jne sj2 ;no, skip
+sj1:
+ mov ax,1 ;condition code
+ dec si ;adjust the pointer
+ pop di ;retrive token buffer address
+ popf ;restore flags
+ stc ;set the carry bit
+ ret
+
+sj2:
+ mov dl,[SWITCHAR]
+ cmp al,dl ;is the char the switch char?
+ jne anum_char ;no, process...
+ call kill_bl
+ cmp al,CR ;a CR?
+ je sj1 ;yes, error exit
+ call move_char ;Put the switch char in the token buffer
+ mov ax,4 ;Flag switch
+ jmp short x_done2
+
+anum_char:
+ call move_char ;just an alphanum string
+ lodsb
+ cmp al,' '
+ je x_done
+ cmp al,tab
+ je x_done
+ cmp al,CR
+ je x_done
+ cmp al,','
+ je x_done
+ cmp al,'='
+ je x_done
+ cmp al,dl ;Switch character
+ jne anum_char
+x_done:
+ dec si ;adjust for next round
+ mov ax,2 ;normal token
+x_done2:
+ push ax ;save condition code
+ mov al,0
+ stosb ;null at the end
+ pop ax
+ pop di ;restore token buffer pointer
+ popf
+ clc ;clear carry flag
+ ret
+
+
+kill_bl proc near
+ lodsb
+ cmp al,' '
+ je kill_bl
+ cmp al,tab
+ je kill_bl
+ cmp al,',' ;a comma?
+ je kill_bl
+ cmp al,'='
+ je kill_bl
+ ret
+kill_bl endp
+
+
+move_char proc near
+ stosb ;store char in token buffer
+ inc cx ;increment char count
+ ret
+move_char endp
+
+CODE ENDS
+ END START
+\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a
\ No newline at end of file
--- /dev/null
+;
+; process control system calls 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 CurrentPDB,WORD
+ i_need CreatePDB,BYTE
+ i_need NUMIO,BYTE
+ i_need Exit_type,BYTE
+ i_need INDOS,BYTE
+ i_need DMAADD,DWORD
+ i_need DidCTRLC,BYTE
+
+SUBTTL $WAIT - return previous process error code
+PAGE
+;
+; process control data
+;
+ i_need exit_code,WORD ; code of exit
+
+;
+; Assembler usage:
+; MOV AH, Wait
+; INT int_command
+; AX has the exit code
+ procedure $WAIT,NEAR
+ ASSUME DS:NOTHING,ES:NOTHING
+ MOV AX,[exit_code]
+ XOR DX,DX
+ MOV [exit_code],DX
+ transfer SYS_RET_OK
+$WAIT ENDP
+
+IF IBM
+ procedure $EXEC,NEAR
+ error error_invalid_function
+$EXEC ENDP
+ENDIF
+IF NOT IBM
+INCLUDE EXEC.ASM
+ENDIF
+
+SUBTTL Terminate and stay resident handler
+PAGE
+;
+; Input: DX is an offset from CurrentPDB at which to
+; truncate the current block.
+;
+; output: The current block is truncated (expanded) to be [DX+15]/16
+; paragraphs long. An exit is simulated via resetting CurrentPDB
+; and restoring the vectors.
+;
+ procedure $Keep_process,NEAR
+ ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGROUP
+
+ PUSH AX ; keep exit code around
+ MOV BYTE PTR [Exit_type],Exit_keep_process
+ MOV ES,[CurrentPDB]
+ CMP DX,6h ; keep enough space around for system
+ JAE Keep_shrink ; info
+ MOV DX,6h
+keep_shrink:
+ MOV BX,DX
+ PUSH BX
+ PUSH ES
+ invoke $SETBLOCK ; ignore return codes.
+ POP DS
+ POP BX
+ JC keep_done ; failed on modification
+ MOV AX,DS
+ ADD AX,BX
+ MOV DS:[PDB_block_len],AX
+
+keep_done:
+ POP AX
+ JMP SHORT exit_inner ; and let abort take care of the rest
+
+$Keep_process ENDP
+
+ procedure Stay_resident,NEAR
+ ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
+ MOV AX,(Keep_process SHL 8) + 0 ; Lower part is return code
+ ADD DX,15
+ MOV CL,4
+ SHR DX,CL
+
+ transfer COMMAND
+Stay_resident ENDP
+
+SUBTTL $EXIT - return to parent process
+PAGE
+;
+; Assembler usage:
+; MOV AL, code
+; MOV AH, Exit
+; INT int_command
+; Error return:
+; None.
+;
+ procedure $EXIT,NEAR
+ ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGROUP
+ XOR AH,AH
+ XCHG AH,BYTE PTR [DidCTRLC]
+ OR AH,AH
+ MOV BYTE PTR [Exit_type],exit_terminate
+ JZ exit_inner
+ MOV BYTE PTR [Exit_type],exit_ctrl_c
+
+Exit_inner:
+ invoke get_user_stack
+ PUSH [CurrentPDB]
+ POP [SI.user_CS]
+ transfer abort_inner
+$EXIT ENDP
+
+do_ext
+
+CODE ENDS
+ END
--- /dev/null
+ TITLE PROFIL - MS-DOS Profile program\r
+\r
+;Profiler for MS-DOS 1.25 2.00\r
+;\r
+; Lots of stuff stolen from debug.\r
+; User provides # of paragraphs per bucket, program is cut up accordingly.\r
+; User also specifies clock interval\r
+\r
+\r
+;System calls\r
+PRINTBUF EQU 9\r
+SETDMA EQU 26\r
+CREATE EQU 22\r
+OPEN EQU 15\r
+CLOSE EQU 16\r
+GETBUF EQU 10\r
+BLKWRT EQU 40\r
+BLKRD EQU 39\r
+OUTCH EQU 2\r
+SETBASE EQU 38\r
+\r
+FCB EQU 5CH\r
+BUFLEN EQU 80\r
+\r
+; FCB offsets\r
+RR EQU 33\r
+RECLEN EQU 14\r
+FILELEN EQU 16\r
+\r
+\r
+;Segments in load order\r
+\r
+CODE SEGMENT PUBLIC\r
+CODE ENDS\r
+\r
+DATA SEGMENT BYTE\r
+DATA ENDS\r
+\r
+INIT SEGMENT BYTE\r
+INIT ENDS\r
+\r
+DG GROUP CODE,DATA,INIT\r
+\r
+;The data segment\r
+\r
+DATA SEGMENT BYTE\r
+ ORG 0\r
+ENDMES DB 13,10,"Program terminated normally",13,10,"$"\r
+ABORTMES DB 13,10,"Program aborted",13,10,"$"\r
+TOOBIG DB "Program too big",13,10,"$"\r
+EXEBAD DB "EXE file bad",13,10,"$"\r
+\r
+OUT_FCB LABEL WORD\r
+ DB 0\r
+OUTNAME DB " PRF"\r
+ DB 30 DUP(0)\r
+\r
+ DB 80H DUP(?)\r
+STACK LABEL WORD\r
+\r
+BYTEBUF DB BUFLEN DUP(?) ;Processed input queue\r
+AXSAVE DW ? ;See interrupt routine\r
+BXSAVE DW ? ; " " "\r
+PROG_AREA DW ? ;Segment of program start\r
+\r
+;EXE file header\r
+RUNVAR LABEL WORD\r
+RELPT DW ?\r
+LASTP LABEL WORD\r
+RELSEG DW ?\r
+PSIZE LABEL WORD\r
+PAGES DW ?\r
+RELCNT DW ?\r
+HEADSIZ DW ?\r
+ DW ?\r
+LOADLOW DW ?\r
+PROG_SS LABEL WORD ;Program stack seg\r
+INITSS DW ?\r
+PROG_SP LABEL WORD ;Program SP\r
+INITSP DW ?\r
+ DW ?\r
+PROG_ENTRY EQU THIS DWORD\r
+PROG_RA LABEL WORD ;Program start offset\r
+INITIP DW ?\r
+PROG_SA LABEL WORD ;Program start segment (may be different from PROG_AREA)\r
+INITCS DW ?\r
+RELTAB DW ?\r
+RUNVARSIZ EQU $-RUNVAR\r
+\r
+EXEFILE DB 0 ;Flag to indicate EXE file\r
+DRV_VALID DW ? ;Init for AX register\r
+OUTPUT_DATA LABEL WORD ;Start of the profile data\r
+CLOCK_GRAIN DW ? ;Clock interval micro-seconds\r
+BUCKET_NUM DW ? ;Number of buckets\r
+BUCKET_SIZE DW ? ;Paragraphs per bucket\r
+PROG_LOW_PA DW ? ;Start of program (PARA #)\r
+PROG_HIGH_PA DW ? ;End of program (PARA #)\r
+DOS_PA DW ? ;IO-DOS PARA boundry\r
+HIT_IO DW 0 ;IO bucket\r
+HIT_DOS DW 0 ;DOS bucket\r
+HIT_HIGH DW 0 ;Above Program bucket\r
+NUM_DATA_WORDS EQU ($-OUTPUT_DATA)/2 ;Number of word items\r
+BUCKET LABEL WORD ;Bucket count area\r
+\r
+;The following data will be overwritten when the buckets are initialized\r
+LINEBUF DB BUFLEN,1,0DH ;Raw input buffer\r
+ DB BUFLEN DUP(?)\r
+\r
+NOFILE DB "File not found",13,10,"$"\r
+OUTERR DB "Cannot open output file",13,10,"$"\r
+GRAIN_PROMPT DB "Sample time (micro-sec) >= 60 ? ","$"\r
+SIZE_PROMPT DB "Number of paragraphs (16 bytes) per bucket? ","$"\r
+PARAM_PROMPT DB "Parameters to program? ","$"\r
+DATA ENDS\r
+\r
+;The resident code portion\r
+CODE SEGMENT PUBLIC\r
+ASSUME CS:DG,DS:DG,ES:DG,SS:DG\r
+\r
+;The clock interrupt routine\r
+ PUBLIC CLK_INTER\r
+\r
+;Stuff provided by external clock handler routine\r
+ EXTRN CLOCKON:NEAR,CLOCKOFF:NEAR,LEAVE_INT:NEAR\r
+\r
+ ORG 100H\r
+START:\r
+ CLD\r
+ MOV SP,OFFSET DG:STACK ;Use internal stack\r
+ CALL SETUP\r
+;The following setup stuff cannot be done in SETUP because we're probably\r
+; overwritting the INIT area\r
+ MOV DX,[PROG_AREA]\r
+ MOV AH,SETBASE\r
+ INT 21H ;Set base for program\r
+ MOV ES,[PROG_AREA]\r
+ PUSH SI ;Points to BYTEBUF\r
+ MOV DI,81H ;Set unformatted params\r
+COMTAIL:\r
+ LODSB\r
+ STOSB\r
+ CMP AL,13\r
+ JNZ COMTAIL\r
+ SUB DI,82H ;Figure length\r
+ XCHG AX,DI\r
+ MOV BYTE PTR ES:[80H],AL\r
+ POP SI\r
+ MOV DI,FCB ;First param\r
+ MOV AX,2901H\r
+ INT 21H\r
+ MOV BYTE PTR [DRV_VALID],AL\r
+ MOV AX,2901H \r
+ MOV DI,6CH ;Second param\r
+ INT 21H\r
+ MOV BYTE PTR [DRV_VALID+1],AL\r
+\r
+ MOV AX,ES ;Prog segment to AX\r
+ MOV DX,[PROG_RA] ;Offset\r
+ CMP [EXEFILE],1\r
+ JZ EXELOAD ;EXE file\r
+ JMP BINFIL ;Regular file (.COM)\r
+\r
+EXELOAD:\r
+ MOV AX,[HEADSIZ] ;Size of header in paragraphs\r
+ ADD AX,31\r
+ MOV CL,4\r
+ ROL AX,CL ;Size in bytes\r
+ MOV BX,AX\r
+ AND AX,0FE00H\r
+ AND BX,0FH\r
+ MOV WORD PTR DS:[FCB+RR],AX ;Position in file of program\r
+ MOV WORD PTR DS:[FCB+RR+2],BX ;Record size\r
+ MOV DX,[PAGES] ;Size in 512 byte blocks\r
+ DEC DX\r
+ XCHG DH,DL\r
+ ROL DX,1\r
+ MOV DI,DX\r
+ MOV SI,DX\r
+ AND DI,0FE00H\r
+ AND SI,1FFH\r
+ SUB DI,AX\r
+ SBB SI,BX\r
+ MOV AX,[LASTP]\r
+ OR AX,AX\r
+ JNZ PARTP\r
+ MOV AX,200H\r
+PARTP:\r
+ ADD DI,AX\r
+ ADC SI,0\r
+ MOV AX,DI\r
+ ADD AX,15\r
+ AND AL,0F0H\r
+ OR AX,SI\r
+ MOV CL,4\r
+ ROR AX,CL\r
+ XCHG AX,CX\r
+ MOV BX,[PROG_AREA]\r
+ ADD BX,10H\r
+ MOV AX,WORD PTR DS:[2]\r
+ SUB AX,CX\r
+ MOV DX,OFFSET DG:TOOBIG\r
+ JB ERROR\r
+ CMP BX,AX\r
+ JA ERROR\r
+ CMP [LOADLOW],-1\r
+ JNZ LOADEXE\r
+ XCHG AX,BX\r
+LOADEXE:\r
+ MOV BP,AX\r
+ XOR DX,DX\r
+ CALL READ\r
+ JC HAVEXE\r
+BADEXE:\r
+ MOV DX,OFFSET DG:EXEBAD\r
+\r
+ERROR:\r
+ MOV AH,PRINTBUF ;Print the message in DX\r
+ INT 21H\r
+ INT 20H ;Exit\r
+\r
+HAVEXE:\r
+ MOV AX,[RELTAB] ;Get position of relocation table\r
+ MOV WORD PTR DS:[FCB+RR],AX\r
+ MOV WORD PTR DS:[FCB+RR+2],0\r
+ MOV DX,OFFSET DG:RELPT ;Four byte buffer\r
+ MOV AH,SETDMA\r
+ INT 21H\r
+ CMP [RELCNT],0\r
+ JZ NOREL\r
+RELOC:\r
+ MOV AH,BLKRD\r
+ MOV DX,FCB\r
+ MOV CX,4\r
+ INT 21H ;Read in one relocation pointer\r
+ OR AL,AL\r
+ JNZ BADEXE\r
+ MOV DI,[RELPT] ;Pointer offset\r
+ MOV AX,[RELSEG] ;pointer segment\r
+ ADD AX,BP ;Bias with actual load segment\r
+ MOV ES,AX\r
+ ADD ES:[DI],BP ;Relocate\r
+ DEC [RELCNT]\r
+ JNZ RELOC\r
+\r
+NOREL:\r
+ ADD [INITSS],BP\r
+ ADD [INITCS],BP\r
+ JMP SHORT PROGGO\r
+\r
+BINFIL:\r
+ MOV WORD PTR DS:[FCB+RECLEN],1\r
+ MOV SI,-1\r
+ MOV DI,SI\r
+ CALL READ\r
+ MOV ES,[PROG_SA] ;Prog segment to ES\r
+ MOV AX,WORD PTR ES:[6]\r
+ MOV [PROG_SP],AX ;Default SP for non EXE files\r
+ DEC AH\r
+ MOV WORD PTR ES:[6],AX ;Fix size\r
+ \r
+PROGGO:\r
+ PUSH DS\r
+ MOV AX,[PROG_AREA]\r
+ MOV DS,AX\r
+ MOV DX,80H\r
+ MOV AH,SETDMA\r
+ INT 21H ;Set default disk transfer address\r
+ POP DS\r
+ MOV BX,[BUCKET_NUM]\r
+ SHL BX,1 ;Mult by 2 to get #bytes in bucket area\r
+CLEAR:\r
+ MOV BUCKET[BX],0 ;Zero counts\r
+ SUB BX,2\r
+ JGE CLEAR\r
+ MOV DX,[CLOCK_GRAIN]\r
+ PUSH DS\r
+ POP ES\r
+ CLI ;Don't collect data yet\r
+ CALL CLOCKON ;Set the interrupt\r
+ MOV SI,[PROG_RA]\r
+ MOV DI,[PROG_AREA]\r
+ MOV BX,[PROG_SS]\r
+ MOV CX,[PROG_SP]\r
+ MOV AX,[DRV_VALID]\r
+ MOV DX,[PROG_SA]\r
+ MOV SS,BX\r
+ MOV SP,CX\r
+ XOR CX,CX\r
+ PUSH CX ;0 on prog stack\r
+ PUSH DX\r
+ PUSH SI\r
+ MOV DS,DI ;Set up segments\r
+ MOV ES,DI\r
+ STI ;Start collecting data\r
+XXX PROC FAR\r
+ RET ;Hop to program\r
+XXX ENDP\r
+ \r
+READ:\r
+; AX:DX is disk transfer address (segment:offset)\r
+; SI:DI is 32 bit length\r
+\r
+RDLOOP:\r
+ MOV BX,DX\r
+ AND DX,000FH\r
+ MOV CL,4\r
+ SHR BX,CL\r
+ ADD AX,BX\r
+ PUSH AX\r
+ PUSH DX\r
+ PUSH DS\r
+ MOV DS,AX\r
+ MOV AH,SETDMA\r
+ INT 21H\r
+ POP DS\r
+ MOV DX,FCB\r
+ MOV CX,0FFF0H ;Keep request in segment\r
+ OR SI,SI ;Need > 64K?\r
+ JNZ BIGRD\r
+ MOV CX,DI ;Limit to amount requested\r
+BIGRD:\r
+ MOV AH,BLKRD\r
+ INT 21H\r
+ SUB DI,CX ;Subtract off amount done\r
+ SBB SI,0 ;Ripple carry\r
+ CMP AL,1 ;EOF?\r
+ POP DX\r
+ POP AX ;Restore transfer address\r
+ JZ RET10\r
+ ADD DX,CX ;Bump transfer address by last read\r
+ MOV BX,SI\r
+ OR BX,DI ;Finished with request\r
+ JNZ RDLOOP\r
+RET10: STC\r
+ RET\r
+\r
+\r
+;Return here on termination or abort\r
+\r
+TERMINATE:\r
+ CLI ;Stop collecting data\r
+ MOV DX,OFFSET DG:ENDMES\r
+ JMP SHORT WRITEOUT\r
+ABORT:\r
+ CLI ;Stop collecting data\r
+ MOV DX,OFFSET DG:ABORTMES\r
+WRITEOUT:\r
+ MOV AX,CS\r
+ MOV DS,AX\r
+ MOV SS,AX\r
+ MOV SP,OFFSET DG:STACK ;Use internal stack\r
+ PUSH DX\r
+ CALL CLOCKOFF ;Restore original clock routine\r
+ STI ;Back to normal clock\r
+ POP DX\r
+ MOV AH,PRINTBUF\r
+ INT 21H ;Apropriate termination message\r
+ MOV [OUT_FCB+14],2 ;Word size records\r
+ MOV DX,OFFSET DG:OUTPUT_DATA\r
+ MOV AH,SETDMA\r
+ INT 21H ;Set the transfer address\r
+ MOV CX,NUM_DATA_WORDS\r
+ ADD CX,[BUCKET_NUM]\r
+ MOV DX,OFFSET DG:OUT_FCB\r
+ MOV AH,BLKWRT\r
+ INT 21H ;Write out data\r
+ MOV DX,OFFSET DG:OUT_FCB\r
+ MOV AH,CLOSE\r
+ INT 21H\r
+ INT 20H ;Exit\r
+\r
+\r
+;The clock interrupt routine\r
+CLK_INTER PROC NEAR\r
+ CLI\r
+ PUSH DS\r
+ PUSH CS\r
+ POP DS ;Get profile segment\r
+ MOV [AXSAVE],AX\r
+ MOV [BXSAVE],BX\r
+ POP AX ;old DS\r
+ MOV BX,OFFSET DG:LEAVE_INT\r
+ PUSH BX\r
+ PUSH AX\r
+ PUSH ES\r
+ PUSH [AXSAVE]\r
+ PUSH [BXSAVE]\r
+ PUSH CX\r
+ PUSH DX\r
+\r
+\r
+;Stack looks like this\r
+;\r
+; +18 OLDFLAGS\r
+; +16 OLDCS\r
+; +14 OLDIP\r
+; +12 RETURN TO LEAVE_INT\r
+; +10 OLDDS\r
+; +8 OLDES\r
+; +6 OLDAX\r
+; +4 OLDBX\r
+; +2 OLDCX\r
+;SP-> OLDDX\r
+\r
+ MOV BX,SP\r
+ LES BX,DWORD PTR SS:[BX+14] ;Get CS:IP\r
+ MOV AX,BX\r
+ MOV CL,4\r
+ SHR AX,CL\r
+ MOV CX,ES\r
+ ADD AX,CX ;Paragraph of CS:IP\r
+ CMP AX,[DOS_PA] ;Below DOS?\r
+ JB IOHIT\r
+ CMP AX,[PROG_LOW_PA] ;Below program?\r
+ JB DOSHIT\r
+ CMP AX,[PROG_HIGH_PA] ;Above program?\r
+ JAE MISSH\r
+\r
+ SUB AX,[PROG_LOW_PA] ;Paragraph offset\r
+ XOR DX,DX\r
+ \r
+ DIV [BUCKET_SIZE]\r
+ MOV BX,AX\r
+ SHL BX,1 ;Mult by 2 to get byte offset\r
+ INC BUCKET[BX]\r
+ JMP SHORT DONE\r
+\r
+IOHIT:\r
+ INC [HIT_IO]\r
+ JMP SHORT DONE\r
+\r
+DOSHIT:\r
+ INC [HIT_DOS]\r
+ JMP SHORT DONE\r
+\r
+MISSH:\r
+ INC [HIT_HIGH]\r
+\r
+DONE:\r
+ POP DX\r
+ POP CX\r
+ POP BX\r
+ POP AX\r
+ POP ES\r
+ POP DS\r
+ STI\r
+ RET ;To LEAVE_INT\r
+\r
+CLK_INTER ENDP\r
+\r
+CODE ENDS\r
+\r
+;The init segment contains code to process input parameters\r
+; It will be blasted as soon as the program to be run is read in\r
+; And/or the bucket area is initialized\r
+ \r
+INIT SEGMENT BYTE\r
+ ORG 0\r
+\r
+SETUP:\r
+ MOV DX,FCB\r
+ MOV AH,OPEN\r
+ INT 21H ;Open program file\r
+ AND AL,AL\r
+ JZ OPENOK\r
+ MOV DX,OFFSET DG:NOFILE\r
+ JMP ERROR\r
+\r
+OPENOK:\r
+ XOR BX,BX\r
+ MOV WORD PTR DS:[FCB+RR],BX\r
+ MOV WORD PTR DS:[FCB+RR+2],BX ;RR to 0\r
+ MOV SI,FCB\r
+ MOV DI,OFFSET DG:OUT_FCB\r
+ MOV CX,4\r
+ REP MOVSW\r
+ MOVSB ;Transfer drive spec and file to output\r
+ MOV DX,OFFSET DG:OUT_FCB\r
+ MOV AH,CREATE\r
+ INT 21H ;Try to create the output file\r
+ AND AL,AL\r
+ JZ GETSIZE\r
+ MOV DX,OFFSET DG:OUTERR\r
+ JMP ERROR\r
+\r
+GETSIZE: ;Get bucket size\r
+ MOV DX,OFFSET DG:SIZE_PROMPT\r
+ MOV AH,PRINTBUF\r
+ INT 21H\r
+ CALL INBUF\r
+ CALL SCANB\r
+ JZ GETSIZE ;SCANB went to CR\r
+ XOR BX,BX\r
+ INC BX ;Size >=1\r
+ CALL GETNUM\r
+ JC GETSIZE ;Bad number\r
+ MOV [BUCKET_SIZE],DX\r
+\r
+ CMP WORD PTR DS:[FCB+9],5800H+"E" ;"EX"\r
+ JNZ NOTEXE\r
+ CMP BYTE PTR DS:[FCB+11],"E"\r
+ JNZ NOTEXE\r
+\r
+LOADEXEHEAD: ;Load the EXE header\r
+ MOV [EXEFILE],1\r
+ MOV DX,OFFSET DG:RUNVAR ;Read header in here\r
+ MOV AH,SETDMA\r
+ INT 21H\r
+ MOV CX,RUNVARSIZ\r
+ MOV DX,FCB\r
+ MOV WORD PTR DS:[FCB+RECLEN],1\r
+ OR AL,AL\r
+ MOV AH,BLKRD\r
+ INT 21H\r
+ CMP [RELPT],5A4DH ;Magic number\r
+ JZ EXEOK\r
+ JMP BADEXE\r
+EXEOK:\r
+ MOV AX,[PAGES] ;Size of file in 512 byte blocks\r
+ MOV CL,5\r
+ SHL AX,CL ;Size in paragraphs \r
+ JMP SHORT SETBUCKET\r
+\r
+NOTEXE:\r
+ MOV AX,WORD PTR DS:[FCB+FILELEN]\r
+ MOV DX,WORD PTR DS:[FCB+FILELEN+2] ;Size of file in bytes DX:AX\r
+ ADD AX,15\r
+ ADC DX,0 ;Round to PARA\r
+ MOV CL,4\r
+ SHR AX,CL\r
+ AND AX,0FFFH\r
+ MOV CL,12\r
+ SHL DX,CL\r
+ AND DX,0F000H\r
+ OR AX,DX ;Size in paragraphs to AX\r
+ MOV [PROG_RA],100H ;Default offset\r
+\r
+SETBUCKET:\r
+ PUSH AX ;Save size\r
+ XOR DX,DX\r
+ DIV [BUCKET_SIZE]\r
+ INC AX ;Round up\r
+ MOV [BUCKET_NUM],AX\r
+ MOV BX,OFFSET DG:BUCKET\r
+ SHL AX,1 ;Number of bytes in bucket area\r
+ ADD AX,BX ;Size of profil in bytes\r
+ ADD AX,15 ;Round up to PARA boundry\r
+ MOV CL,4\r
+ SHR AX,CL ;Number of paragraphs in profil\r
+ INC AX ;Insurance\r
+ MOV BX,CS\r
+ ADD AX,BX\r
+ MOV [PROG_AREA],AX\r
+\r
+ CMP [EXEFILE],1\r
+ JZ SETBOUNDS\r
+ MOV AX,[PROG_AREA] ;Set up .COM segments\r
+ MOV [PROG_SS],AX\r
+ MOV [PROG_SA],AX\r
+\r
+SETBOUNDS: ;Set the sample window\r
+ MOV BX,10H ;Get start offset\r
+ ADD BX,[PROG_AREA] ;PARA # of start\r
+ MOV [PROG_LOW_PA],BX\r
+ POP AX ;Recall size of PROG in paragraphs\r
+ ADD BX,AX\r
+ MOV [PROG_HIGH_PA],BX\r
+\r
+SETDOS:\r
+ XOR DX,DX\r
+ MOV ES,DX ;look in interrupt area\r
+ MOV DX,WORD PTR ES:[82H] ;From int #20\r
+ MOV [DOS_PA],DX\r
+ PUSH DS\r
+ POP ES\r
+\r
+GETGRAIN: ;Get sample interval\r
+ MOV DX,OFFSET DG:GRAIN_PROMPT\r
+ MOV AH,PRINTBUF\r
+ INT 21H\r
+ CALL INBUF\r
+ CALL SCANB\r
+ JZ GETGRAIN ;SCANB went to CR\r
+ MOV BX,60 ;Grain >=60\r
+ CALL GETNUM\r
+ JC GETGRAIN ;Bad number\r
+ MOV [CLOCK_GRAIN],DX\r
+\r
+ MOV DX,OFFSET DG:PARAM_PROMPT\r
+ MOV AH,PRINTBUF\r
+ INT 21H\r
+ CALL INBUF ;Get program parameters\r
+\r
+ MOV AX,2522H ;Set vector 22H\r
+ MOV DX,OFFSET DG:TERMINATE\r
+ INT 21H\r
+ MOV AL,23H ;Set vector 23H\r
+ MOV DX,OFFSET DG:ABORT\r
+ INT 21H\r
+ RET ;Back to resident code\r
+\r
+GETNUM: ;Get a number, DS:SI points to buffer, carry set if bad\r
+ XOR DX,DX\r
+ MOV CL,0\r
+ LODSB\r
+NUMLP:\r
+ SUB AL,"0"\r
+ JB NUMCHK\r
+ CMP AL,9\r
+ JA NUMCHK\r
+ CMP DX,6553\r
+ JAE BADNUM\r
+ MOV CL,1\r
+ PUSH BX\r
+ MOV BX,DX\r
+ SHL DX,1\r
+ SHL DX,1\r
+ ADD DX,BX\r
+ SHL DX,1\r
+ CBW\r
+ POP BX\r
+ ADD DX,AX\r
+ LODSB\r
+ JMP NUMLP\r
+NUMCHK:\r
+ CMP CL,0\r
+ JZ BADNUM\r
+ CMP BX,DX\r
+ JA BADNUM\r
+ CLC\r
+ RET\r
+BADNUM:\r
+ STC\r
+ RET \r
+\r
+INBUF: ;Read in from console, SI points to start on exit\r
+ MOV AH,GETBUF\r
+ MOV DX,OFFSET DG:LINEBUF\r
+ INT 21H\r
+ MOV SI,2 + OFFSET DG:LINEBUF\r
+ MOV DI,OFFSET DG:BYTEBUF\r
+CASECHK:\r
+ LODSB\r
+ CMP AL,'a'\r
+ JB NOCONV\r
+ CMP AL,'z'\r
+ JA NOCONV\r
+ ADD AL,"A"-"a" ;Convert to upper case\r
+NOCONV:\r
+ STOSB\r
+ CMP AL,13\r
+ JZ INDONE\r
+ CMP AL,'"'\r
+ JNZ QUOTSCAN\r
+ CMP AL,"'"\r
+ JNZ CASECHK\r
+QUOTSCAN:\r
+ MOV AH,AL\r
+KILLSTR:\r
+ LODSB\r
+ STOSB\r
+ CMP AL,13\r
+ JZ INDONE\r
+ CMP AL,AH\r
+ JNZ KILLSTR\r
+ JMP SHORT CASECHK\r
+\r
+INDONE:\r
+ MOV SI,OFFSET DG:BYTEBUF\r
+\r
+;Output CR/LF\r
+\r
+CRLF:\r
+ MOV AL,13\r
+ CALL OUT\r
+ MOV AL,10\r
+\r
+OUT:\r
+ PUSH AX\r
+ PUSH DX\r
+ AND AL,7FH\r
+ XCHG AX,DX\r
+ MOV AH,OUTCH\r
+ INT 21H\r
+ POP DX\r
+ POP AX\r
+ RET\r
+\r
+SCANB: ;Scan to first non-blank\r
+ PUSH AX\r
+SCANNEXT:\r
+ LODSB\r
+ CMP AL," "\r
+ JZ SCANNEXT\r
+ CMP AL,9\r
+ JZ SCANNEXT\r
+ DEC SI\r
+ POP AX\r
+EOLCHK:\r
+ CMP BYTE PTR[SI],13\r
+ RET\r
+\r
+INIT ENDS\r
+ END START\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+PROHST is a preliminary version of a utility to process the profile\r
+file produced by the PROFIL utility of MSDOS.\r
+Those of you familiar with MS-Pascal or MS-Fortran will have little\r
+difficulty in understanding how the parameters work. There are three,\r
+the .PRF filename, an optional histogram file (default extension .HST,\r
+default name same as the .PRF file) and an optional link map. If the\r
+link map was produced with the line number options PROHST will try\r
+and relate buckets to line numbers. Otherwise, it will relate it to\r
+module offsets. If you specify no map file (the default), addresses\r
+relative to the start of the program will be used. The default extension\r
+for the map file is .MAP.\r
+\r
+a:prohst f;\r
+\r
+this will produce a histogram for the file f.prf in f.hst and no map file\r
+will be assumed.\r
+\r
+a:prohst f,,;\r
+\r
+this will produce a histogram for f.prf in f.hst and expects a f.map file.\r
+\r
+a:prohst f,g,k\r
+\r
+this produces a histogram for f.prf in g.hst and expects a map file k.map.\r
+\r
+Note that if you select the map option with line numbers, the program will\r
+appear to be looping. Never fear, go and have lunch or some other time\r
+consuming pastime, and you will be suprised how long it took to produce\r
+such a small file. Also, some of the line number/bucket correspondances are\r
+not what they might be. Future version shoudl fix this. If you make a better\r
+version, be sure to let me have a copy.\r
+\r
+David Jones.\r
+\r
+\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a
\ No newline at end of file
--- /dev/null
+ MSDOS 2.0 RELEASE\r
+\r
+\r
+The 2.0 Release of MSDOS includes five 5 1/4 double density single sided\r
+diskettes or three 8 iinch CP/M 80 format diskettes.\r
+\r
+The software/documentation on the five inch diskettes is arranged\r
+as follows:\r
+\r
+1. DOS distribution diskette. This diskette contains files which\r
+ should be distriibuted to all users. This allows the DOS distri-\r
+ bution diskette to meet the requirements of users of high level\r
+ language compilers as well as users running only applications.\r
+ Many compilers marketed independently through the retail channel\r
+ (including those of Microsoft) assume LINK comes with the DOS, as\r
+ in the case of IBM. How you choose to distrubute BASIC (contracted\r
+ for separately) is up to you.\r
+\r
+2. Assembly Language Development System diskette. This diskette\r
+ contains files of interest to assembly language programmers.\r
+ High level language programmers do not need these programs unless\r
+ they are writing assembly language subroutines. IBM chose to\r
+ unbundle this package from the DOS distribution diskette (except\r
+ for DEBUG), but you do not have to do so.\r
+\r
+3. PRINT and FORMAT diskette. This diskette contains .ASM source\r
+ files which are necessary to assemble the print spooler, which you\r
+ may wish to customize for greater performance. .OBJ files are also\r
+ included for the FORMAT utility.\r
+\r
+4. Skeltal BIOS and documentation diskette. This diskette contains\r
+ the skeltal BIOS source code and the SYSINIT and SYSIMES object\r
+ modules which must be linked with your BIOS module. The proper\r
+ sequence for linking is BIOS - SYSINIT - SYSIMES.\r
+ A profiler utiliity is also included on the diskette, but this\r
+ is not intended for end-users. This is distributed for use by\r
+ your development staff only and is not supported by Microsoft\r
+ If you do decide to distribute it, it is at your own risk!\r
+\r
+\r
+5. Documentation. Features of 2.0 are documented on this disk.\r
+\r
+The user manual contains some significant errors. Most of these are\r
+due to last minute changes to achieve a greater degree of compatibility\r
+with IBM's implementation of MS-DOS (PC DOS). This includes the use\r
+of "\" instead of "/" as the path separator, and "/" instead of "-"\r
+as the switch character. For transporting of batch files across\r
+machines, Microsoft encourages the use of "\" and "/" respectively\r
+in the U.S. market. (See DOSPATCH.TXT for how you can overide this.\r
+The user guide explains how the end-user can override this in CONFIG.SYS).\r
+Both the printer echo keys and insert mode keys have now been made to\r
+toggle. The default prompt (this may also be changed by the user\r
+with the PROMPT command) has been changed from "A:" to "A>".\r
+We apologize for any inconveniences these changes may have caused\r
+your technical publications staff.\r
+\r
+\r
+Here is what you need to do to MSDOS 2.0 to create a shipable product:\r
+(see "Making a Bootable Diskette" below)\r
+\r
+1. BIOS. If you have developed a BIOS for the Beta Test 2.0 version\r
+ You should link your BIOS module to SYSINIT.OBJ and SYSIMES.OBJ.\r
+ You must modify your BIOS to accomodate the call back to the BIOS\r
+ at the end of SYSINIT. If you have no need for this call, simply\r
+ find a far RET and label it RE_INIT and declare it public.\r
+ An example of this can be found in the skeletal BIOS. In addition\r
+ please add support for the new fast console output routine as\r
+ described in the device drivers document. We strongly recommend\r
+ that you adapt the standard boot sector format also described in\r
+ device drivers. Once again, please refer to the skeletal BIOS.\r
+ If you have not yet implemented version 2.0 please read the device\r
+ drivers document. Microsoft strongly recommends that machines\r
+ incorporating integrated display devices with memory mapped video\r
+ RAM implement some sort of terminal emulations through the use of\r
+ escape sequences. The skeletal BIOS includes a sample ANSI\r
+ terminal driver.\r
+\r
+2. Please refer to DOSPATCH.TXT for possible changes you might wish\r
+ to make. We strongly recommend that you not patch the switch\r
+ characters for the U.S. market. Your one byte serial number\r
+ will be issued upon signing the license agreement. Please patch\r
+ the DOS accordingly. If you wish to serialize the DOS, this is\r
+ described in DOSPATCH.TXT. Please patch the editing template\r
+ definitions. Please note the addition of the Control-Z entry\r
+ at the beginning of the table. Also note that the insert switches\r
+ have now both been made to toggle.\r
+\r
+3. Utilities. FORMAT must be configured for each specific system.\r
+ GENFOR is a generic example of a system independent format module,\r
+ but it is not recommended that this be distributed to your customers.\r
+ Link in the following order: FORMAT, FORMES, (your format module).\r
+ The print spooler is distributed as an executable file, which only\r
+ prints during wait for keyboard input. If you wish with your\r
+ implementation to steal some compute time when printing as well,\r
+ you will need to customize it and reassemble. Please note that\r
+ you can use a printer-ready or timer interrupt. The former is more\r
+ efficient, but ties the user to a specific device. Sample code\r
+ is conditionaled out for the IBM PC timer interrupt.\r
+\r
+The following problems are known to exist:\r
+\r
+1. Macro assembler does not support the initialization of 10-byte\r
+ floating point constants in 8087 emulation mode - the last two bytes\r
+ are zero filled.\r
+\r
+2. LIB has not been provided. The version which incorporates support\r
+ for 2.0 path names will be completed in a couple of weeks. The\r
+ 1.x version should work fine if you cannot wait. Because the library\r
+ manager acts as a counterpart to the linker, we recommend that it\r
+ be distributed with the DOS distribution diskette as opposed to the\r
+ assembly language development system.\r
+\r
+3. International (French, German, Japanese, and U.K.) versions will be\r
+ available in several months.\r
+\r
+4. COMMAND.ASM is currently too large to assemble on a micro. It is\r
+ being broken down into separate modules so it can be asembled on\r
+ a machine. Source licensees should realize that the resultant\r
+ binaries from the new version will not correspond exactly to the\r
+ old version.\r
+\r
+5. If you have any further questions regarding the MSDOS 2.0 distribution\r
+ please contact Don Immerwahr (OEM technical support (206) 828-8086).\r
+\r
+\r
+ Sincerely yours,\r
+\r
+\r
+ Chris Larson\r
+ MS-DOS Product Marketing Manager\r
+ (206) 828-8080\r
+\r
+\r
+\r
+ BUILDING A BOOTABLE (MSDOS FORMAT) DISKETTE\r
+\r
+\r
+1. In implementing MSDOS on a new machine, it is highly recommended\r
+ that an MSDOS machine be available for the development.\r
+ Please note that utilities shipped with MSDOS 2.0 use MSDOS 2.0\r
+ system calls and WILL NOT not run under MSDOS 1.25.\r
+\r
+2. Use your MSDOS development machine and EDLIN or a word processor\r
+ package to write BOOT.ASM, your bootstrap loader BIOS.ASM and\r
+ your Format module.\r
+\r
+3. Use MASM, the Microsoft Macro-86 Assembler, to assemble these\r
+ modules. LINK is then used to link together the .OBJ modules in\r
+ the order specified.\r
+\r
+4. Link creates .EXE format files which are not memory image files\r
+ and contain relocation information in their headers. Since your\r
+ BIOS and BOOT routines will not be loaded by the EXE loader in\r
+ MSDOS, they must first be turned into memory image files by\r
+ using the EXE2BIN utility.\r
+\r
+5. The easiest thing to do is to (using your development machine)\r
+ FORMAT a single sided diskette without the system. Use DEBUG\r
+ to load and write your BOOT.COM bootstrap loader to the BOOT\r
+ sector of that diskette. You may decide to have your bootstrap\r
+ load BIOS and let the BIOS load MSDOS or it may load both. Note that\r
+ the Bootstrap loader will have to know physically where to go on\r
+ the disk to get the BIOS and the DOS. COMMAND.COM is loaded\r
+ by the SYSINIT module.\r
+\r
+6. Use the COPY command to copy your IO.SYS file (what the\r
+ BIOS-SYSINIT-SYSIMES module is usually called) onto the disk\r
+ followed by MSDOS.SYS and COMMAND.COM. You may use DEBUG\r
+ to change the directory attribute bytes to make these files hidden.\r
+\r
+CAUTION:\r
+\r
+At all times, the BIOS writer should be careful to preserve the state\r
+of the DOS - including the flags. You should be also be cautioned that\r
+the MSDOS stack is not deep. You should not count on more than one or\r
+two pushes of the registers.\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+TITLE RECOVER MS-DOS File/Disk Recovery Utility\r
+;----------------------------------------------------------\r
+;\r
+; Recover - Program to rebuild an ms.dos directory\r
+;\r
+; Copyright 1982 by Microsoft Corporation\r
+; Written by Chris Peters, April 1982\r
+;\r
+;-----------------------------------------------------------\r
+;\r
+;REV 1.5 added header message ARR\r
+;\r
+\r
+FALSE EQU 0\r
+TRUE EQU NOT FALSE\r
+\r
+\r
+IBMVER EQU true\r
+KANJI EQU FALSE\r
+\r
+bdos equ 21h\r
+boot equ 20h\r
+aread equ 25h\r
+awrite equ 26h\r
+\r
+ INCLUDE DOSSYM.ASM\r
+\r
+;\r
+cr equ 0dh\r
+lf equ 0ah\r
+;\r
+fcb equ 5ch\r
+\r
+code segment public\r
+code ends\r
+\r
+const segment public byte\r
+const ends\r
+\r
+data segment public byte\r
+data ends\r
+\r
+\r
+dg group code,const,data\r
+\r
+code segment public\r
+ assume cs:dg,ds:dg,es:dg,ss:dg\r
+\r
+ PUBLIC PCRLF,PRINT,INT_23,convert\r
+ EXTRN dskwrt:NEAR,dskrd:NEAR,DSKERR:NEAR,report:NEAR\r
+\r
+ org 100h\r
+\r
+recover:jmp rec_start\r
+\r
+HEADER DB "Vers 1.50"\r
+\r
+;-----------------------------------------------------------------------;\r
+hardch dd ?\r
+\r
+the_root db 0 ;root directory flag\r
+\r
+fudge db 0 ;directory changed flag\r
+user_drive db 0\r
+drive db 0\r
+\r
+\r
+dirchar db "/",0\r
+\r
+\r
+userdir db "/",0\r
+ db (dirstrlen) dup(0)\r
+\r
+fname_buffer db 128 dup(0)\r
+;-----------------------------------------------------------------------;\r
+\r
+pcrlf: mov dx,offset dg: crlf\r
+print: mov ah,STD_CON_STRING_OUTPUT\r
+ int bdos\r
+pret: ret\r
+;\r
+convert:push bx\r
+ xor ax,ax\r
+ mov bx,ax\r
+ mov bp,ax\r
+ mov cx,32\r
+convlp: shl si,1\r
+ rcl di,1\r
+ xchg ax,bp\r
+ call convwrd\r
+ xchg ax,bp\r
+ xchg ax,bx\r
+ call convwrd\r
+ xchg ax,bx\r
+ adc al,0\r
+ loop convlp\r
+\r
+ mov cx,1810h\r
+ xchg dx,ax\r
+ call digit\r
+ xchg ax,bx\r
+ call outword\r
+ mov ax,bp\r
+ call outword\r
+ pop dx\r
+ call print\r
+ret2: ret\r
+;\r
+outword:push ax\r
+ mov dl,ah\r
+ call outbyte\r
+ pop dx\r
+outbyte:mov dh,dl\r
+ shr dl,1\r
+ shr dl,1\r
+ shr dl,1\r
+ shr dl,1\r
+ call digit\r
+ mov dl,dh\r
+digit: and dl,0fh\r
+ jz blankzer\r
+ xor cl,cl\r
+blankzer:\r
+ dec ch\r
+ and cl,ch\r
+ or dl,30h\r
+ sub dl,cl\r
+ cmp dl,30h\r
+ jl ret2\r
+ mov ah,STD_CON_OUTPUT\r
+ int bdos\r
+ ret\r
+;\r
+convwrd:adc al,al\r
+ daa\r
+ xchg al,ah\r
+ adc al,al\r
+ daa\r
+ xchg al,ah\r
+ ret\r
+;\r
+; bx = fat[ax]\r
+;\r
+getfat: mov bx,offset dg: fattbl\r
+ push ax\r
+ mov si,ax\r
+ sar ax,1\r
+ pushf\r
+ add si,ax\r
+ mov bx,word ptr [bx][si]\r
+ popf\r
+ jnc getfat1\r
+ mov cl,4\r
+ shr bx,cl\r
+getfat1:and bh,00001111b\r
+ pop ax\r
+ mov cx,secsiz\r
+ ret\r
+;\r
+; fat[ax] = dx\r
+;\r
+setfat: mov bx,offset dg: fattbl\r
+ push ax\r
+ push dx\r
+ mov si,ax\r
+ sar ax,1\r
+ pushf\r
+ add si,ax\r
+ mov ax,word ptr [bx][si]\r
+ popf\r
+ jnc setfat2\r
+ and ax,000fh\r
+ mov cl,4\r
+ shl dx,cl\r
+setfat1:or ax,dx\r
+ mov word ptr [bx][si],ax\r
+ pop dx\r
+ pop ax\r
+ ret\r
+\r
+setfat2:and ax,0f000h\r
+ jmp setfat1\r
+\r
+load: mov dx,firfat\r
+ mov al,byte ptr fatnum\r
+ mov byte ptr fatcnt,al\r
+ mov al,byte ptr drive\r
+ mov cx,fatsiz\r
+ mov bx,offset dg: fattbl\r
+ret66: ret\r
+\r
+readft: call load\r
+readit: call dskrd\r
+ cmp [fndfat],0 ;save location of readable fat sector\r
+ jnz fdfat\r
+ mov [fndfat],dx\r
+fdfat: cmp word ptr [bx+1],-1\r
+ jz ret66\r
+\r
+ add dx,cx ;try to read the other fats\r
+ dec byte ptr fatcnt\r
+ jnz readit\r
+\r
+ mov dx,[fndfat] ;see if any readable at all\r
+ or dx,dx\r
+ jz readft ;if not disk is blown, keep trying\r
+ call dskrd\r
+ ret\r
+\r
+wrtfat: call load\r
+wrtit: push ax\r
+ push bx\r
+ push cx\r
+ push dx\r
+ call dskwrt\r
+ pop dx\r
+ pop cx\r
+ pop bx\r
+ pop ax\r
+\r
+wrtok: add dx,cx\r
+ dec byte ptr fatcnt\r
+ jnz wrtit\r
+ ret\r
+\r
+printerr:\r
+ call print\r
+ jmp rabort\r
+\r
+\r
+rec_start:\r
+\r
+;Code to print header\r
+; PUSH AX\r
+; MOV DX,OFFSET DG:HEADER\r
+; CALL print\r
+; POP AX\r
+\r
+DOSVER_HIGH EQU 0200H ;2.00 in hex\r
+ PUSH AX ;Save DRIVE validity info\r
+ MOV AH,GET_VERSION\r
+ INT 21H\r
+ XCHG AH,AL ;Turn it around to AH.AL\r
+ CMP AX,DOSVER_HIGH\r
+ JAE OKDOS\r
+GOTBADDOS:\r
+ MOV DX,OFFSET DG:BADVER\r
+ CALL PRINT\r
+ INT 20H\r
+\r
+OKDOS: POP AX\r
+\r
+ cmp al,0ffH\r
+ JZ BADDRVSPECJ\r
+ mov si,80h\r
+ lodsb\r
+ or al,al\r
+ jz noparm\r
+look: lodsb\r
+ cmp al," "\r
+ jz look\r
+ cmp al,9\r
+ jz look\r
+ cmp al,13\r
+ jnz gotparm\r
+noparm:\r
+ jmp noname\r
+\r
+BADDRVSPECJ: JMP BADDRVSPEC\r
+\r
+gotparm:\r
+ mov ah,DISK_RESET\r
+ int bdos ;empty buffer queue\r
+\r
+ mov ah,get_default_drive ;save current drive\r
+ int 21h\r
+ mov [user_drive],al\r
+\r
+ mov bx,fcb ;determine input command\r
+ mov al,[bx]\r
+ dec al\r
+ cmp al,-1\r
+ jnz drvok1\r
+ mov al,[user_drive]\r
+drvok1:\r
+ mov [drive],al\r
+ add [drvlet],al\r
+ add [drvlet1],al\r
+ mov dx,offset dg: askmsg\r
+ call print\r
+ mov ah,STD_CON_INPUT_FLUSH\r
+ mov al,1 ;wait for a key\r
+ int bdos\r
+\r
+ cmp al,17h\r
+ jnz drvok2\r
+ mov dx,offset dg: egomes\r
+ jmp printerr\r
+egomes: db "Chris Peters helped with the new dos!",cr,lf\r
+ db "Microsoft rules ok$"\r
+\r
+drvok2:\r
+ IF IBMVER\r
+ MOV AL,DRIVE ;This is for ibm's single drive sys\r
+ PUSH DS\r
+ MOV BX,50H\r
+ MOV DS,BX\r
+ MOV DS:(BYTE PTR 4),AL ;Indicate drive changed\r
+ POP DS\r
+ ENDIF\r
+\r
+;----- Process Pathnames -----------------------------------------------;\r
+ mov ax,(char_oper shl 8) ;get switch character\r
+ int 21h\r
+ cmp dl,"/"\r
+ jnz slashok ;if not / , then not PC\r
+ mov [dirchar],"\" ;in PC, dir separator = \\r
+ mov [userdir],"\"\r
+\r
+slashok:\r
+ mov si,81h ;point to cammand line\r
+ mov di,offset dg: fname_buffer\r
+ xor cx,cx ;zero pathname length\r
+\r
+kill_bl:\r
+ lodsb ;get rid of blanks\r
+ cmp al,9\r
+ je kill_bl\r
+ cmp al,' '\r
+ je kill_bl\r
+ cmp al,13 ;A carriage return?\r
+ jne next_char\r
+ jmp noname ;yes, file name missing\r
+\r
+next_char:\r
+ stosb ;put patname in buffer\r
+ inc cx\r
+ lodsb\r
+ cmp al,' '\r
+ je name_copied\r
+ cmp al,9\r
+ je name_copied\r
+ cmp al,13 ; a CR ?\r
+ jne next_char\r
+\r
+name_copied:\r
+ mov byte ptr [di],0 ;nul terminate the pathname\r
+ dec di ;adjust to the end of the pathname\r
+\r
+;----- Scan for directory ----------------------------------------------;\r
+\r
+ IF KANJI\r
+ mov dx,offset dg: [fname_buffer]\r
+ PUSH DX\r
+ PUSH DI\r
+ MOV BX,DI\r
+ MOV DI,DX\r
+DELLOOP:\r
+ CMP DI,BX\r
+ JZ GOTDELE\r
+ MOV AL,[DI]\r
+ INC DI\r
+ CALL TESTKANJ\r
+ JZ NOTKANJ11\r
+ INC DI\r
+ JMP DELLOOP\r
+\r
+NOTKANJ11:\r
+ cmp al,[dirchar]\r
+ JNZ DELLOOP\r
+ MOV DX,DI ;Point to char after '/'\r
+ DEC DX\r
+ DEC DX ;Point to char before '/'\r
+ JMP DELLOOP\r
+\r
+GOTDELE:\r
+ MOV DI,DX\r
+ POP AX ;Initial DI\r
+ POP DX\r
+ SUB AX,DI ;Distance moved\r
+ SUB CX,AX ;Set correct CX\r
+ CMP DX,DI\r
+ JB sja ;Found a pathsep\r
+ JA sjb ;Started with a pathsep, root\r
+ MOV AX,[DI]\r
+ CALL TESTKANJ\r
+ JNZ same_dirj\r
+ XCHG AH,AL\r
+ cmp al,[dirchar]\r
+ jz sja ;One character directory\r
+same_dirj:\r
+ ELSE\r
+ mov al,[dirchar] ;get directory separator character\r
+ std ;scan backwards\r
+ repnz scasb ;(cx has the pathname length)\r
+ cld ;reset direction, just in case\r
+ jz sja\r
+ ENDIF\r
+\r
+ jmp same_dir ;no dir separator char. found, the\r
+ ; file is in the current directory\r
+ ; of the corresponding drive. Ergo,\r
+ ; the FCB contains the data already.\r
+\r
+sja:\r
+ jcxz sjb ;no more chars left, it refers to root\r
+ cmp byte ptr [di],':' ;is the prvious character a disk def?\r
+ jne not_root\r
+sjb:\r
+ mov [the_root],01h ;file is in the root\r
+not_root:\r
+ inc di ;point to dir separator char.\r
+ mov al,0\r
+ stosb ;nul terminate directory name\r
+ pop ax\r
+ push di ;save pointer to file name\r
+ mov [fudge],01h ;remember that the current directory\r
+ ; has been changed.\r
+\r
+;----- Save current directory for exit ---------------------------------;\r
+ mov dl,byte ptr ds:[fcb] ;get specified drive if any\r
+ or dl,dl ;default disk?\r
+ jz same_drive\r
+ dec dl ;adjust to real drive (a=0,b=1,...)\r
+ mov ah,set_default_drive ;change disks\r
+ int 21h\r
+ cmp al,-1 ;error?\r
+ jne same_drive\r
+BADDRVSPEC:\r
+ mov dx,offset dg: baddrv\r
+ jmp printerr\r
+\r
+same_drive:\r
+ mov ah,get_default_dpb\r
+ int 21h\r
+\r
+assume ds:nothing\r
+\r
+ cmp al,-1 ;bad drive? (should always be ok)\r
+ jne drvisok\r
+ mov dx,offset dg: baddrv\r
+ jmp printerr\r
+\r
+drvisok:\r
+ cmp [bx.dpb_current_dir],0\r
+ je curr_is_root\r
+ mov si,bx\r
+ add si,dpb_dir_text\r
+ mov di,offset dg: userdir + 1\r
+\r
+dir_save_loop:\r
+ lodsb\r
+ stosb\r
+ or al,al\r
+ jnz dir_save_loop\r
+\r
+curr_is_root:\r
+ push cs\r
+ pop ds\r
+\r
+assume ds:dg\r
+\r
+\r
+;----- Change directories ----------------------------------------------;\r
+ cmp [the_root],01h\r
+ mov dx,offset dg: [dirchar] ;assume the root\r
+ je sj1\r
+ mov dx,offset dg: [fname_buffer]\r
+sj1:\r
+ mov ah,chdir ;change directory\r
+ int 21h\r
+ mov dx,offset dg: baddrv\r
+ jnc no_errors\r
+ jmp printerr\r
+no_errors:\r
+\r
+;----- Set Up int 24 intercept -----------------------------------------;\r
+\r
+ mov ax,(get_interrupt_vector shl 8) or 24h\r
+ int 21h\r
+ mov word ptr [hardch],bx\r
+ mov word ptr [hardch+2],es\r
+ mov ax,(set_interrupt_vector shl 8) or 23h\r
+ mov dx,offset dg: int_23\r
+ int 21h\r
+ mov ax,(set_interrupt_vector shl 8) or 24h\r
+ mov dx,offset dg: int_24\r
+ int 21h\r
+ push cs\r
+ pop es\r
+\r
+;----- Parse filename to FCB -------------------------------------------;\r
+ pop si\r
+ mov di,fcb\r
+ mov ax,(parse_file_descriptor shl 8) or 1\r
+ int 21h\r
+ push ax\r
+;-----------------------------------------------------------------------;\r
+same_dir:\r
+ pop ax\r
+\r
+ mov bx,fcb\r
+ cmp byte ptr [bx+1],' ' ;must specify file name\r
+ jnz drvok\r
+ cmp byte ptr [bx],0 ;or drive specifier\r
+ jnz drvok\r
+noname: mov dx,offset dg: drverr\r
+ call print\r
+ jmp int_23\r
+\r
+drvok: push ds\r
+ mov dl,drive\r
+ inc dl\r
+ mov ah,GET_DPB\r
+ int bdos\r
+ mov ax,word ptr [bx+2] ;get physical sector size\r
+ mov cl,byte ptr [bx+4] ;get sectors/cluster - 1\r
+ xor ch,ch\r
+ inc cx\r
+ mov cs:secall,cx ;save sectors per cluster\r
+ mul cx ;ax = bytes per cluster\r
+ mov bp,word ptr [bx+11] ;get record of first sector\r
+ mov dx,word ptr [bx+16] ;get record of first directory entry\r
+ mov si,word ptr [bx+6] ;get record of first fat\r
+ mov cl,byte ptr [bx+15] ;get size of fat\r
+ mov di,word ptr [bx+13] ;get number of clusters\r
+ mov ch,byte ptr [bx+8] ;get number of fats on drive\r
+ mov bx,word ptr [bx+9] ;get max number of dir entries\r
+ pop ds\r
+\r
+ mov maxent,bx\r
+ mov firfat,si\r
+ mov firrec,bp\r
+ mov firdir,dx\r
+ mov byte ptr fatsiz,cl\r
+ mov lastfat,di ;number of fat entries\r
+ mov byte ptr fatnum,ch ;save number of fats on disk\r
+\r
+ mov secsiz,ax\r
+\r
+ mov di,table ;di points into constructed directory\r
+ mov ax,0e5e5h ;deleted file magic number\r
+ shl bx,1 ;16 words in a dir entry\r
+ shl bx,1\r
+ shl bx,1\r
+ shl bx,1\r
+ mov cx,bx\r
+ rep stosw\r
+\r
+ call readft\r
+ mov bx,fcb\r
+ cmp byte ptr [bx+1],' '\r
+ jz recdsk\r
+ jmp recfil\r
+\r
+recdsk: mov di,table\r
+ mov fatptr,2\r
+ mov ax,fatptr\r
+step1: call getfat\r
+ cmp bx,0fffh\r
+ jz step1a\r
+ jmp step6\r
+step1a: mov filsiz,0\r
+ mov word ptr filsiz+2,0\r
+ mov dx,lastfat\r
+ mov target,ax\r
+step2: mov ax,2\r
+ add filsiz,cx\r
+ adc word ptr filsiz+2,0\r
+step3: call getfat\r
+ cmp bx,target\r
+ jne step4\r
+ mov target,ax\r
+ jmp step2\r
+step4: inc ax\r
+ cmp ax,dx\r
+ jle step3\r
+;\r
+; at this point target = head of list, filsiz = file size\r
+;\r
+ inc filcnt ;increment file count\r
+ mov ax,maxent\r
+ cmp filcnt,ax ;compare with max number of entries\r
+ ja direrr\r
+\r
+ mov si,(offset dg: dirent)+7\r
+nam0: inc byte ptr [si] ;increment file name\r
+ cmp byte ptr [si],'9'\r
+ jle nam1\r
+ mov byte ptr [si],'0'\r
+ dec si\r
+ jmp nam0\r
+\r
+nam1: mov ah,GET_DATE\r
+ int bdos ;set the date\r
+ sub cx,1980\r
+ add dh,dh\r
+ add dh,dh\r
+ add dh,dh\r
+ add dh,dh\r
+ add dh,dh\r
+ rcl cl,1\r
+ or dh,dl\r
+ mov byte ptr dirent+24,dh\r
+ mov byte ptr dirent+25,cl\r
+ mov ah,GET_TIME\r
+ int bdos ;set the time\r
+ shr dh,1\r
+ add cl,cl\r
+ add cl,cl\r
+ add cl,cl\r
+ rcl ch,1\r
+ add cl,cl\r
+ rcl ch,1\r
+ add cl,cl\r
+ rcl ch,1\r
+ or dh,cl\r
+ mov byte ptr dirent+22,dh\r
+ mov byte ptr dirent+23,ch\r
+\r
+ mov ax,filsiz ;set file size\r
+ mov word ptr dirent+28,ax\r
+ mov ax,word ptr filsiz+2\r
+ mov word ptr dirent+30,ax\r
+ mov ax,target ;set first cluster location\r
+ mov word ptr dirent+26,ax\r
+\r
+ mov si,offset dg: dirent ;copy in new dir entry\r
+ mov cx,32\r
+ rep movsb\r
+\r
+step6: inc fatptr ;keep looking for eof's\r
+ mov ax,fatptr\r
+ cmp ax,lastfat\r
+ jg step7\r
+ jmp step1\r
+\r
+direrr: dec filcnt\r
+ mov dx,offset dg: dirmsg\r
+ call print\r
+\r
+step7:\r
+ mov al,drive\r
+ mov dx,firdir ;write out constructed directory\r
+ mov cx,firrec\r
+ sub cx,dx\r
+ mov bx,table\r
+ call dskwrt\r
+ call pcrlf\r
+ mov dx,offset dg: recmsg_pre\r
+ call print\r
+ mov bx,offset dg: recmsg_post\r
+ mov si,filcnt\r
+ xor di,di ;output number of files created\r
+ call convert\r
+ jmp rexit\r
+recfil: mov dx,fcb\r
+ mov ah,FCB_OPEN\r
+ int bdos\r
+ inc al\r
+ jnz recfil0\r
+ mov dx,offset dg: opnerr\r
+ call print\r
+ jmp rexit\r
+\r
+recfil0:mov lastfat,1 ;indicate location of list head\r
+ mov di,fcb\r
+ mov ax,[di+16] ;get file size\r
+ mov filsiz,ax\r
+ mov siztmp,ax\r
+ mov ax,[di+18]\r
+ mov filsiz+2,ax\r
+ mov siztmp+2,ax\r
+ mov ax,[di+25] ;get list head\r
+ or ax,ax\r
+ mov fatptr,ax\r
+ jnz recfil1\r
+recvec: jmp recfil6\r
+\r
+recfil1:cmp fatptr,0fffh\r
+ jz recvec ;terminate loop at e-o-f\r
+\r
+ mov cx,secall\r
+ mov ax,fatptr\r
+ dec ax\r
+ dec ax\r
+ mul cx\r
+ add ax,firrec\r
+ mov dx,ax\r
+ mov bx,table\r
+ mov al,drive\r
+ int aread\r
+ pop di ;restore stack pointer\r
+ mov di,fcb ;restore pointer to fcb\r
+ jnc recfil4 ;if no error continue reading\r
+\r
+ mov ax,fatptr\r
+ call getfat\r
+ cmp lastfat,1\r
+ jnz recfil2\r
+\r
+ cmp bx,0fffh\r
+ jnz noteof\r
+ xor bx,bx\r
+noteof: mov word ptr [di+25],bx\r
+ jmp recfil3\r
+\r
+recfil2:mov dx,bx ;jump around bad sector\r
+ mov ax,lastfat\r
+ call setfat\r
+\r
+recfil3:mov ax,fatptr ;mark sector bad\r
+ mov dx,0ff7h\r
+ call setfat\r
+ mov ax,secsiz ;prepare to dec filsiz by secsiz\r
+ cmp siztmp+2,0\r
+ jnz recfilx\r
+ cmp siztmp,ax\r
+ ja recfilx\r
+ mov ax,siztmp\r
+\r
+recfilx:sub word ptr [di+16],ax\r
+ sbb word ptr [di+18],0\r
+ sub siztmp,ax\r
+ sbb siztmp,0\r
+\r
+ and byte ptr [di+24],10111111b ;mark file dirty\r
+\r
+ mov ax,lastfat ;point to next sector to check\r
+ jmp recfil5\r
+\r
+recfil4:\r
+ mov ax,secsiz ;set bytes remaining to be read\r
+ sub siztmp,ax\r
+ sbb siztmp+2,0\r
+ jnc recok\r
+ xor ax,ax ;if < 0, then set to zero\r
+ mov siztmp,ax\r
+ mov siztmp+2,ax\r
+\r
+recok: mov ax,fatptr ;get next sector to test\r
+ mov lastfat,ax\r
+recfil5:call getfat\r
+ mov fatptr,bx\r
+ jmp recfil1\r
+\r
+recfil6: ;all done\r
+ mov dx,fcb\r
+ mov ah,FCB_CLOSE\r
+ int bdos ;close the file\r
+ call pcrlf\r
+ call report\r
+\r
+;\r
+rexit: mov ah,DISK_RESET\r
+ int bdos\r
+ call wrtfat ;save the fat\r
+int_23: call rest_dir\r
+rabort: int boot ;home, james...\r
+\r
+;----- Restore INT 24 vector and old current directory -----------------;\r
+rest_dir:\r
+ cmp [fudge],0\r
+ je no_fudge\r
+\r
+ mov ax,(set_interrupt_vector shl 8) or 24h\r
+ lds dx,[hardch]\r
+ int 21h\r
+ push cs\r
+ pop ds\r
+\r
+ mov dx,offset dg: userdir ;restore directory\r
+ mov ah,chdir\r
+ int 21h\r
+ mov dl,[user_drive] ;restore old current drive\r
+ mov ah,set_default_drive\r
+ int 21h\r
+\r
+no_fudge:\r
+ ret\r
+\r
+;----- INT 24 Processing -----------------------------------------------;\r
+\r
+int_24_retaddr dw int_24_back\r
+\r
+int_24 proc far\r
+assume ds:nothing,es:nothing,ss:nothing\r
+\r
+ pushf\r
+ push cs\r
+ push [int_24_retaddr]\r
+ push word ptr [hardch+2]\r
+ push word ptr [hardch]\r
+ ret\r
+int_24 endp\r
+\r
+int_24_back:\r
+ cmp al,2 ;abort?\r
+ jnz ireti\r
+ push cs\r
+ pop ds\r
+\r
+assume ds:dg\r
+\r
+ call rest_dir\r
+ int 20h\r
+ireti:\r
+ iret\r
+\r
+ IF KANJI\r
+TESTKANJ:\r
+ CMP AL,81H\r
+ JB NOTLEAD\r
+ CMP AL,9FH\r
+ JBE ISLEAD\r
+ CMP AL,0E0H\r
+ JB NOTLEAD\r
+ CMP AL,0FCH\r
+ JBE ISLEAD\r
+NOTLEAD:\r
+ PUSH AX\r
+ XOR AX,AX ;Set zero\r
+ POP AX\r
+ RET\r
+\r
+ISLEAD:\r
+ PUSH AX\r
+ XOR AX,AX ;Set zero\r
+ INC AX ;Reset zero\r
+ POP AX\r
+ RET\r
+ ENDIF\r
+\r
+code ends\r
+\r
+const segment public byte\r
+\r
+ EXTRN BADVER:BYTE,askmsg:BYTE,drvlet:BYTE,dirmsg:BYTE\r
+ EXTRN recmsg_pre:BYTE,DRVLET1:BYTE,recmsg_post:BYTE\r
+ EXTRN crlf:BYTE,drverr:BYTE,baddrv:BYTE,opnerr:BYTE\r
+\r
+const ends\r
+\r
+data segment byte\r
+\r
+ PUBLIC filsiz\r
+\r
+dirent db 'FILE0000REC'\r
+ db 21 dup (00)\r
+\r
+fndfat dw 0000 ;sector of first good fat\r
+filcnt dw 0000\r
+fatcnt db 00\r
+fatnum db 00\r
+fatsiz dw 0000\r
+firfat dw 0000\r
+fatptr dw 0000\r
+secall dw 0000 ;sectors per cluster\r
+target dw 0000\r
+maxent dw 0000\r
+firrec dw 0000\r
+firdir dw 0000\r
+secsiz dw 0000\r
+siztmp dw 0000\r
+ dw 0000\r
+filsiz dw 0000\r
+ dw 0000\r
+lastfat dw 0000\r
+;\r
+table dw offset dg:fattbl + 6 * 1024\r
+fattbl db 0\r
+\r
+data ends\r
+\r
+ end recover\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\1a
\ No newline at end of file
--- /dev/null
+;\r
+; Disk utilities of MSDOS\r
+;\r
+\r
+INCLUDE DOSSEG.ASM\r
+\r
+CODE SEGMENT BYTE PUBLIC 'CODE'\r
+ ASSUME SS:DOSGROUP,CS:DOSGROUP\r
+\r
+.XLIST\r
+.xcref\r
+INCLUDE DOSSYM.ASM\r
+INCLUDE DEVSYM.ASM\r
+.cref\r
+.list\r
+\r
+TITLE ROM - miscellaneous routines\r
+NAME ROM\r
+\r
+ i_need CLUSNUM,WORD\r
+ i_need NEXTADD,WORD\r
+ i_need LASTPOS,WORD\r
+ i_need SECCLUSPOS,BYTE\r
+ i_need FATBYT,WORD\r
+ i_need RECPOS,4\r
+ i_need THISFCB,DWORD\r
+ i_need TRANS,BYTE\r
+ i_need BYTCNT1,WORD\r
+ i_need CURBUF,DWORD\r
+ i_need BYTSECPOS,WORD\r
+ i_need DMAADD,WORD\r
+ i_need SECPOS,WORD\r
+ i_need VALSEC,WORD\r
+\r
+ procedure GET_random_record,NEAR\r
+ entry GETRRPOS1\r
+ MOV CX,1\r
+ entry GetRRPos\r
+ MOV DI,DX\r
+ CMP BYTE PTR [DI],-1\r
+ JNZ NORMFCB1\r
+ ADD DI,7\r
+NORMFCB1:\r
+ MOV AX,WORD PTR [DI.fcb_RR]\r
+ MOV DX,WORD PTR [DI.fcb_RR+2]\r
+ return\r
+GET_random_record ENDP\r
+\r
+SUBTTL FNDCLUS -- Skip over allocation units\r
+PAGE\r
+ procedure FNDCLUS,NEAR\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+; Inputs:\r
+; CX = No. of clusters to skip\r
+; ES:BP = Base of drive parameters\r
+; [THISFCB] point to FCB\r
+; Outputs:\r
+; BX = Last cluster skipped to\r
+; CX = No. of clusters remaining (0 unless EOF)\r
+; DX = Position of last cluster\r
+; DI destroyed. No other registers affected.\r
+\r
+ PUSH ES\r
+ LES DI,[THISFCB]\r
+ MOV BX,ES:[DI.fcb_LSTCLUS] ; fcb_lstclus is packed with dir clus\r
+ AND BX,0FFFh ; get rid of dir nibble\r
+ MOV DX,ES:[DI.fcb_CLUSPOS]\r
+ OR BX,BX\r
+ JZ NOCLUS\r
+ SUB CX,DX\r
+ JNB FINDIT\r
+ ADD CX,DX\r
+ XOR DX,DX\r
+ MOV BX,ES:[DI.fcb_FIRCLUS]\r
+FINDIT:\r
+ POP ES\r
+ JCXZ RET10\r
+entry SKPCLP\r
+ invoke UNPACK\r
+ CMP DI,0FF8H\r
+ JAE RET10\r
+ XCHG BX,DI\r
+ INC DX\r
+ LOOP SKPCLP\r
+RET10: return\r
+\r
+NOCLUS:\r
+ POP ES\r
+ INC CX\r
+ DEC DX\r
+ return\r
+FNDCLUS ENDP\r
+\r
+SUBTTL BUFSEC -- BUFFER A SECTOR AND SET UP A TRANSFER\r
+PAGE\r
+ procedure BUFSEC,NEAR\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+; Inputs:\r
+; AH = priority of buffer\r
+; AL = 0 if buffer must be read, 1 if no pre-read needed\r
+; ES:BP = Base of drive parameters\r
+; [CLUSNUM] = Physical cluster number\r
+; [SECCLUSPOS] = Sector position of transfer within cluster\r
+; [BYTCNT1] = Size of transfer\r
+; Function:\r
+; Insure specified sector is in buffer, flushing buffer before\r
+; read if necessary.\r
+; Outputs:\r
+; ES:DI = Pointer to buffer\r
+; SI = Pointer to transfer address\r
+; CX = Number of bytes\r
+; [NEXTADD] updated\r
+; [TRANS] set to indicate a transfer will occur\r
+\r
+ MOV DX,[CLUSNUM]\r
+ MOV BL,[SECCLUSPOS]\r
+ CALL FIGREC\r
+ invoke GETBUFFR\r
+ MOV BYTE PTR [TRANS],1 ; A transfer is taking place\r
+ MOV SI,[NEXTADD]\r
+ MOV DI,SI\r
+ MOV CX,[BYTCNT1]\r
+ ADD DI,CX\r
+ MOV [NEXTADD],DI\r
+ LES DI,[CURBUF]\r
+ ADD DI,BUFINSIZ ; Point to buffer\r
+ ADD DI,[BYTSECPOS]\r
+ return\r
+BUFSEC ENDP\r
+\r
+SUBTTL BUFRD, BUFWRT -- PERFORM BUFFERED READ AND WRITE\r
+PAGE\r
+ procedure BUFRD,NEAR\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+; Do a partial sector read via one of the system buffers\r
+; ES:BP Points to DPB\r
+\r
+ PUSH ES\r
+ MOV AX,LBRPRI SHL 8 ; Assume last byte read\r
+ CALL BUFSEC\r
+ MOV BX,ES\r
+ MOV ES,[DMAADD+2]\r
+ MOV DS,BX\r
+ASSUME DS:NOTHING\r
+ XCHG DI,SI\r
+ SHR CX,1\r
+ JNC EVENRD\r
+ MOVSB\r
+EVENRD:\r
+ REP MOVSW\r
+ POP ES\r
+ LDS DI,[CURBUF]\r
+ LEA BX,[DI.BufInSiz]\r
+ SUB SI,BX ; Position in buffer\r
+ invoke PLACEBUF\r
+ CMP SI,ES:[BP.dpb_sector_size]\r
+ JB RBUFPLACED\r
+ invoke PLACEHEAD\r
+RBUFPLACED:\r
+ PUSH SS\r
+ POP DS\r
+ return\r
+BUFRD ENDP\r
+\r
+ procedure BUFWRT,NEAR\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+; Do a partial sector write via one of the system buffers\r
+; ES:BP Points to DPB\r
+\r
+ MOV AX,[SECPOS]\r
+ INC AX ; Set for next sector\r
+ MOV [SECPOS],AX\r
+ CMP AX,[VALSEC] ; Has sector been written before?\r
+ MOV AL,1\r
+ JA NOREAD ; Skip preread if SECPOS>VALSEC\r
+ XOR AL,AL\r
+NOREAD:\r
+ PUSH ES\r
+ CALL BUFSEC\r
+ MOV DS,[DMAADD+2]\r
+ASSUME DS:NOTHING\r
+ SHR CX,1\r
+ JNC EVENWRT\r
+ MOVSB\r
+EVENWRT:\r
+ REP MOVSW\r
+ POP ES\r
+ LDS BX,[CURBUF]\r
+ MOV BYTE PTR [BX.BUFDIRTY],1\r
+ LEA SI,[BX.BufInSiz]\r
+ SUB DI,SI ; Position in buffer\r
+ MOV SI,DI\r
+ MOV DI,BX\r
+ invoke PLACEBUF\r
+ CMP SI,ES:[BP.dpb_sector_size]\r
+ JB WBUFPLACED\r
+ invoke PLACEHEAD\r
+WBUFPLACED:\r
+ PUSH SS\r
+ POP DS\r
+ return\r
+BUFWRT ENDP\r
+\r
+SUBTTL NEXTSEC -- Compute next sector to read or write\r
+PAGE\r
+ procedure NEXTSEC,NEAR\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+; Compute the next sector to read or write\r
+; ES:BP Points to DPB\r
+\r
+ TEST BYTE PTR [TRANS],-1\r
+ JZ CLRET\r
+ MOV AL,[SECCLUSPOS]\r
+ INC AL\r
+ CMP AL,ES:[BP.dpb_cluster_mask]\r
+ JBE SAVPOS\r
+ MOV BX,[CLUSNUM]\r
+ CMP BX,0FF8H\r
+ JAE NONEXT\r
+ invoke UNPACK\r
+ MOV [CLUSNUM],DI\r
+ INC [LASTPOS]\r
+ MOV AL,0\r
+SAVPOS:\r
+ MOV [SECCLUSPOS],AL\r
+CLRET:\r
+ CLC\r
+ return\r
+NONEXT:\r
+ STC\r
+ return\r
+NEXTSEC ENDP\r
+\r
+SUBTTL OPTIMIZE -- DO A USER DISK REQUEST WELL\r
+PAGE\r
+ procedure OPTIMIZE,NEAR\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+; Inputs:\r
+; BX = Physical cluster\r
+; CX = No. of records\r
+; DL = sector within cluster\r
+; ES:BP = Base of drives parameters\r
+; [NEXTADD] = transfer address\r
+; Outputs:\r
+; AX = No. of records remaining\r
+; BX = Transfer address\r
+; CX = No. or records to be transferred\r
+; DX = Physical sector address\r
+; DI = Next cluster\r
+; [CLUSNUM] = Last cluster accessed\r
+; [NEXTADD] updated\r
+; ES:BP unchanged. Note that segment of transfer not set.\r
+\r
+ PUSH DX\r
+ PUSH BX\r
+ MOV AL,ES:[BP.dpb_cluster_mask]\r
+ INC AL ; Number of sectors per cluster\r
+ MOV AH,AL\r
+ SUB AL,DL ; AL = Number of sectors left in first cluster\r
+ MOV DX,CX\r
+ MOV CX,0\r
+OPTCLUS:\r
+; AL has number of sectors available in current cluster\r
+; AH has number of sectors available in next cluster\r
+; BX has current physical cluster\r
+; CX has number of sequential sectors found so far\r
+; DX has number of sectors left to transfer\r
+; ES:BP Points to DPB\r
+; ES:SI has FAT pointer\r
+ invoke UNPACK\r
+ ADD CL,AL\r
+ ADC CH,0\r
+ CMP CX,DX\r
+ JAE BLKDON\r
+ MOV AL,AH\r
+ INC BX\r
+ CMP DI,BX\r
+ JZ OPTCLUS\r
+ DEC BX\r
+FINCLUS:\r
+ MOV [CLUSNUM],BX ; Last cluster accessed\r
+ SUB DX,CX ; Number of sectors still needed\r
+ PUSH DX\r
+ MOV AX,CX\r
+ MUL ES:[BP.dpb_sector_size] ; Number of sectors times sector size\r
+ MOV SI,[NEXTADD]\r
+ ADD AX,SI ; Adjust by size of transfer\r
+ MOV [NEXTADD],AX\r
+ POP AX ; Number of sectors still needed\r
+ POP DX ; Starting cluster\r
+ SUB BX,DX ; Number of new clusters accessed\r
+ ADD [LASTPOS],BX\r
+ POP BX ; BL = sector postion within cluster\r
+ invoke FIGREC\r
+ MOV BX,SI\r
+ return\r
+BLKDON:\r
+ SUB CX,DX ; Number of sectors in cluster we don't want\r
+ SUB AH,CL ; Number of sectors in cluster we accepted\r
+ DEC AH ; Adjust to mean position within cluster\r
+ MOV [SECCLUSPOS],AH\r
+ MOV CX,DX ; Anyway, make the total equal to the request\r
+ JMP SHORT FINCLUS\r
+OPTIMIZE ENDP\r
+\r
+SUBTTL FIGREC -- Figure sector in allocation unit\r
+PAGE\r
+ procedure FIGREC,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DX = Physical cluster number\r
+; BL = Sector postion within cluster\r
+; ES:BP = Base of drive parameters\r
+; Outputs:\r
+; DX = physical sector number\r
+; No other registers affected.\r
+\r
+ PUSH CX\r
+ MOV CL,ES:[BP.dpb_cluster_shift]\r
+ DEC DX\r
+ DEC DX\r
+ SHL DX,CL\r
+ OR DL,BL\r
+ ADD DX,ES:[BP.dpb_first_sector]\r
+ POP CX\r
+ return\r
+FIGREC ENDP\r
+\r
+SUBTTL GETREC -- Figure record in file from fcb\r
+PAGE\r
+ procedure GETREC,NEAR\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+; Inputs:\r
+; DS:DX point to FCB\r
+; Outputs:\r
+; CX = 1\r
+; DX:AX = Record number determined by fcb_EXTENT and fcb_NR fields\r
+; DS:DI point to FCB\r
+; No other registers affected.\r
+\r
+ MOV DI,DX\r
+ CMP BYTE PTR [DI],-1 ; Check for extended FCB\r
+ JNZ NORMFCB2\r
+ ADD DI,7\r
+NORMFCB2:\r
+ MOV CX,1\r
+ MOV AL,[DI.fcb_NR]\r
+ MOV DX,[DI.fcb_EXTENT]\r
+ SHL AL,1\r
+ SHR DX,1\r
+ RCR AL,1\r
+ MOV AH,DL\r
+ MOV DL,DH\r
+ MOV DH,0\r
+ return\r
+GETREC ENDP\r
+\r
+SUBTTL ALLOCATE -- Assign disk space\r
+PAGE\r
+ procedure ALLOCATE,NEAR\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+; Inputs:\r
+; BX = Last cluster of file (0 if null file)\r
+; CX = No. of clusters to allocate\r
+; DX = Position of cluster BX\r
+; ES:BP = Base of drive parameters\r
+; [THISFCB] = Points to FCB\r
+; Outputs:\r
+; IF insufficient space\r
+; THEN\r
+; Carry set\r
+; CX = max. no. of records that could be added to file\r
+; ELSE\r
+; Carry clear\r
+; BX = First cluster allocated\r
+; FAT is fully updated including dirty bit\r
+; fcb_FIRCLUS field of FCB set if file was null\r
+; SI,BP unchanged. All other registers destroyed.\r
+\r
+ PUSH BX ; save the fat byte\r
+ XOR BX,BX\r
+ invoke UNPACK\r
+ MOV [FATBYT],DI\r
+ POP BX\r
+\r
+ PUSH DX\r
+ PUSH CX\r
+ PUSH BX\r
+ MOV AX,BX\r
+CLUSALLOC:\r
+ MOV DX,BX\r
+FINDFRE:\r
+ INC BX\r
+ CMP BX,ES:[BP.dpb_max_cluster]\r
+ JLE TRYOUT\r
+ CMP AX,1\r
+ JG TRYIN\r
+ POP BX\r
+ MOV DX,0FFFH\r
+ invoke RELBLKS\r
+ POP AX ; No. of clusters requested\r
+ SUB AX,CX ; AX=No. of clusters allocated\r
+ POP DX\r
+ invoke RESTFATBYT\r
+ INC DX ; Position of first cluster allocated\r
+ ADD AX,DX ; AX=max no. of cluster in file\r
+ MOV DL,ES:[BP.dpb_cluster_mask]\r
+ MOV DH,0\r
+ INC DX ; DX=records/cluster\r
+ MUL DX ; AX=max no. of records in file\r
+ MOV CX,AX\r
+ SUB CX,WORD PTR [RECPOS] ; CX=max no. of records that could be written\r
+ JA MAXREC\r
+ XOR CX,CX ; If CX was negative, zero it\r
+MAXREC:\r
+ STC\r
+ return\r
+\r
+TRYOUT:\r
+ invoke UNPACK\r
+ JZ HAVFRE\r
+TRYIN:\r
+ DEC AX\r
+ JLE FINDFRE\r
+ XCHG AX,BX\r
+ invoke UNPACK\r
+ JZ HAVFRE\r
+ XCHG AX,BX\r
+ JMP SHORT FINDFRE\r
+HAVFRE:\r
+ XCHG BX,DX\r
+ MOV AX,DX\r
+ invoke PACK\r
+ MOV BX,AX\r
+ LOOP CLUSALLOC\r
+ MOV DX,0FFFH\r
+ invoke PACK\r
+ POP BX\r
+ POP CX ; Don't need this stuff since we're successful\r
+ POP DX\r
+ invoke UNPACK\r
+ invoke RESTFATBYT\r
+ XCHG BX,DI\r
+ OR DI,DI\r
+ retnz\r
+ PUSH ES\r
+ LES DI,[THISFCB]\r
+ AND BX,0FFFh\r
+ MOV ES:[DI.fcb_FIRCLUS],BX\r
+ AND ES:[DI.fcb_LSTCLUS],0F000h ; clear out old lstclus\r
+ OR ES:[DI.fcb_LSTCLUS],BX ; or the new guy in...\r
+ POP ES\r
+ return\r
+ALLOCATE ENDP\r
+\r
+ procedure RESTFATBYT,NEAR\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+ PUSH BX\r
+ PUSH DX\r
+ PUSH DI\r
+ XOR BX,BX\r
+ MOV DX,[FATBYT]\r
+ invoke PACK\r
+ POP DI\r
+ POP DX\r
+ POP BX\r
+ return\r
+RESTFATBYT ENDP\r
+\r
+SUBTTL RELEASE -- DEASSIGN DISK SPACE\r
+PAGE\r
+ procedure RELEASE,NEAR\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+; Inputs:\r
+; BX = Cluster in file\r
+; ES:BP = Base of drive parameters\r
+; Function:\r
+; Frees cluster chain starting with [BX]\r
+; AX,BX,DX,DI all destroyed. Other registers unchanged.\r
+\r
+ XOR DX,DX\r
+entry RELBLKS\r
+; Enter here with DX=0FFFH to put an end-of-file mark\r
+; in the first cluster and free the rest in the chain.\r
+ invoke UNPACK\r
+ retz\r
+ MOV AX,DI\r
+ invoke PACK\r
+ CMP AX,0FF8H\r
+ MOV BX,AX\r
+ JB RELEASE\r
+RET12: return\r
+RELEASE ENDP\r
+\r
+SUBTTL GETEOF -- Find the end of a file\r
+PAGE\r
+ procedure GETEOF,NEAR\r
+ASSUME DS:DOSGROUP,ES:NOTHING\r
+\r
+; Inputs:\r
+; ES:BP Points to DPB\r
+; BX = Cluster in a file\r
+; DS = CS\r
+; Outputs:\r
+; BX = Last cluster in the file\r
+; DI destroyed. No other registers affected.\r
+\r
+ invoke UNPACK\r
+ CMP DI,0FF8H\r
+ JAE RET12\r
+ MOV BX,DI\r
+ JMP SHORT GETEOF\r
+GETEOF ENDP\r
+\r
+do_ext\r
+\r
+CODE ENDS\r
+ END\r
+\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+ TITLE IO.SYS for the ALTOS ACS-86C.\r
+\r
+; I/O system for Version 2.x of MSDOS.\r
+\r
+;This BIOS designed to be linked with the SYSINIT module provided by\r
+;Microsoft\r
+\r
+BIOSIZ EQU 4096 ;Size of BIOS in bytes.\r
+BIOSIZS EQU 100H ;Size of BIOS in Paragraphs.\r
+ANSI EQU 0 ;Ansi switch.\r
+\r
+;Additional Information for the ALTOS machine.\r
+\r
+QSIZE EQU 100 ;Input queue size.\r
+BIOSSEG EQU 0C0H ;I/O system segment.\r
+MAX_MEM EQU 4000H ;Memory size in paragraphs.\r
+\r
+; Constants for commands in Altos ROM.\r
+\r
+ROM_CONSTA EQU 01 ;Return status AL of console selected in CX.\r
+ROM_CONIN EQU 02 ;Get char. from console in CX to AL\r
+ROM_CONOUT EQU 03 ;Write char. in DL to console in CX.\r
+ROM_PMSG EQU 07 ;Write string ES:DX to console in CX.\r
+ROM_DISKIO EQU 08 ;Perform disk I/O from IOPB in ES:CX.\r
+ROM_INIT EQU 10 ;Returns boot console and top memory ES:DX.\r
+\r
+;Things needed to communicate with SYSINIT\r
+\r
+EXTRN SYSINIT:FAR ;The entry point of SYSINIT\r
+EXTRN CURRENT_DOS_LOCATION:WORD ;Where the DOS is when SYSINIT called\r
+EXTRN FINAL_DOS_LOCATION:WORD ;Where I want SYSINIT to put the DOS\r
+EXTRN DEVICE_LIST:DWORD ;Pointer to the DEVICE list.\r
+EXTRN MEMORY_SIZE:WORD ;Size in paragraphs of Physical memory.\r
+EXTRN DEFAULT_DRIVE:BYTE ;Default Drive to use when system booted\r
+EXTRN BUFFERS:BYTE ;Number of default buffers.\r
+ ; Leave as is and SYSINIT uses only 2.\r
+\r
+CODE SEGMENT\r
+ASSUME CS:CODE,DS:CODE,ES:CODE,SS:CODE\r
+\r
+ ORG 0 ;Starts at an offset of zero.\r
+\r
+INIT: JMP HWINIT\r
+\r
+ PAGE\r
+\r
+ SUBTTL Device driver tables.\r
+\r
+;-----------------------------------------------+\r
+; DWORD pointer to next device | 1 word offset.\r
+; (-1,-1 if last device) | 1 word segement.\r
+;-----------------------------------------------+\r
+; Device attribute WORD ; 1 word.\r
+; Bit 15 = 1 for chacter devices. ;\r
+; 0 for Block devices. ;\r
+; ;\r
+; Charcter devices. (Bit 15=1) ;\r
+; Bit 0 = 1 current sti device. ;\r
+; Bit 1 = 1 current sto device. ;\r
+; Bit 2 = 1 current NUL device. ;\r
+; Bit 3 = 1 current Clock device. ;\r
+; ;\r
+; Bit 13 = 1 for non IBM machines. ;\r
+; 0 for IBM machines only. ;\r
+; Bit 14 = 1 IOCTL control bit. ;\r
+;-----------------------------------------------+\r
+; Device strategy pointer. ; 1 word offset.\r
+;-----------------------------------------------+\r
+; Device interrupt pointer. ; 1 word offset.\r
+;-----------------------------------------------+\r
+; Device name field. ; 8 bytes.\r
+; Character devices are any valid name ;\r
+; left justified, in a space filled ;\r
+; field. ;\r
+; Block devices contain # of units in ;\r
+; the first byte. ;\r
+;-----------------------------------------------+\r
+\r
+DEVSTART LABEL WORD\r
+CONDEV: ;Header for device CON\r
+ DW AUXDEV,BIOSSEG ;Link to next device\r
+ DW 8003H ;Attributes - console input, output device\r
+ DW STRATEGY ;Srategy entry point\r
+ DW CON_INT ;Interrupt entry point\r
+ DB "CON " ;Device name\r
+\r
+AUXDEV: ;Header for device AUX\r
+ DW PRNDEV,BIOSSEG\r
+ DW 8000H\r
+ DW STRATEGY\r
+ DW AUX_INT\r
+ DB "AUX "\r
+\r
+PRNDEV: ;Header for device PRN\r
+ DW TIMDEV,BIOSSEG\r
+ DW 8000H\r
+ DW STRATEGY\r
+ DW PRN_INT\r
+ DB "PRN "\r
+\r
+TIMDEV: ;Header for device CLOCK\r
+ DW DSKDEV,BIOSSEG\r
+ DW 8008H\r
+ DW STRATEGY\r
+ DW TIM_INT\r
+ DB "CLOCK "\r
+\r
+DSKDEV: ;Header for disk devices\r
+ DW -1,-1 ;Last device\r
+ DW 2000H ;Is a block device\r
+ DW STRATEGY\r
+ DW DSK_INT\r
+DRVMAX DB 1 ;Number of Units\r
+ DB 7 DUP (?)\r
+\r
+ PAGE\r
+ SUBTTL Dispatch tables for each device.\r
+\r
+DSKTBL: DW DSK_INIT ;0 - Initialize Driver.\r
+ DW MEDIAC ;1 - Return current media code.\r
+ DW GET_BPB ;2 - Get Bios Parameter Block.\r
+ DW CMDERR ;3 - Reserved. (currently returns error)\r
+ DW DSK_RED ;4 - Block read.\r
+ DW BUS_EXIT ;5 - (Not used, return busy flag)\r
+ DW EXIT ;6 - Return status. (Not used)\r
+ DW EXIT ;7 - Flush input buffer. (Not used.)\r
+ DW DSK_WRT ;8 - Block write.\r
+ DW DSK_WRV ;9 - Block write with verify.\r
+ DW EXIT ;10 - Return output status.\r
+ DW EXIT ;11 - Flush output buffer. (Not used.)\r
+ DW EXIT ;12 - IO Control.\r
+\r
+CONTBL: DW EXIT ;0 - Init. (Not used)\r
+ DW EXIT ;1 - Media check (Not used)\r
+ DW EXIT ;2 - Get Bios Parameter Block (Not used)\r
+ DW CMDERR ;3 - Reserved. (Currently returns error)\r
+ DW CON_READ ;4 - Character read. (Destructive)\r
+ DW CON_RDND ;5 - Character read. (Non-destructive)\r
+ DW EXIT ;6 - Return status. (Not used)\r
+ DW CON_FLSH ;7 - Flush Input buffer.\r
+ DW CON_WRIT ;8 - Character write.\r
+ DW CON_WRIT ;9 - Character write with Verify.\r
+ DW CON_WRST ;10 - Character write status.\r
+ DW EXIT ;11 - Flush output buffer. (Not used.)\r
+ DW EXIT ;12 - IO Control.\r
+\r
+AUXTBL: DW EXIT ;0 - Init. (Not used)\r
+ DW EXIT ;1 - Media check (Not used)\r
+ DW EXIT ;2 - Get Bios Parameter Block (Not used)\r
+ DW CMDERR ;3 - Reserved. (Returns an error)\r
+ DW AUX_READ ;4 - Character read. (Destructive)\r
+ DW AUX_RDND ;5 - Character read. (Non-destructive)\r
+ DW EXIT ;6 - Return status. (Not used)\r
+ DW AUX_CLR ;7 - Flush Input buffer.\r
+ DW AUX_WRIT ;8 - Character write.\r
+ DW AUX_WRIT ;9 - Character write with verify.\r
+ DW AUX_WRST ;10 - Character write status.\r
+ DW EXIT ;11 - Flush output buffer. (Not used.)\r
+ DW EXIT ;12 - IO Control.\r
+\r
+TIMTBL: DW EXIT ;0 - Init. (Not used)\r
+ DW EXIT ;1 - Media check (Not used)\r
+ DW EXIT ;2 - Get Bios Parameter Block (Not used)\r
+ DW CMDERR ;3 - Reserved. (Currently returns an error)\r
+ DW TIM_RED ;4 - Character read. (Destructive)\r
+ DW BUS_EXIT ;5 - (Not used, returns busy flag.)\r
+ DW EXIT ;6 - Return status. (Not used)\r
+ DW EXIT ;7 - Flush Input buffer. (Not used)\r
+ DW TIM_WRT ;8 - Character write.\r
+ DW TIM_WRT ;9 - Character write with verify.\r
+ DW EXIT ;10 - Character write status. (Not used)\r
+ DW EXIT ;11 - Flush output buffer. (Not used)\r
+ DW EXIT ;12 - IO Control.\r
+\r
+PRNTBL: DW EXIT ;0 - (Not used)\r
+ DW EXIT ;1 - (Not used)\r
+ DW EXIT ;2 - Block (Not used)\r
+ DW CMDERR ;3 - Reserved. (currently returns error)\r
+ DW EXIT ;4 - (Not used)\r
+ DW BUS_EXIT ;5 - (Not used, returns busy flag.)\r
+ DW EXIT ;6 - (Not used)\r
+ DW EXIT ;7 - (Not used)\r
+ DW PRN_WRT ;8 - Character write.\r
+ DW PRN_WRT ;9 - Character write with verify.\r
+ DW PRN_STA ;10 - Character write status.\r
+ DW EXIT ;11 - (Not used.)\r
+ DW EXIT ;12 - IO Control.\r
+\r
+ PAGE\r
+ SUBTTL Strategy and Software Interrupt routines.\r
+\r
+;Define offsets for io data packet\r
+\r
+IODAT STRUC\r
+CMDLEN DB ? ;LENGTH OF THIS COMMAND\r
+UNIT DB ? ;SUB UNIT SPECIFIER\r
+CMD DB ? ;COMMAND CODE\r
+STATUS DW ? ;STATUS\r
+ DB 8 DUP (?)\r
+MEDIA DB ? ;MEDIA DESCRIPTOR\r
+TRANS DD ? ;TRANSFER ADDRESS\r
+COUNT DW ? ;COUNT OF BLOCKS OR CHARACTERS\r
+START DW ? ;FIRST BLOCK TO TRANSFER\r
+IODAT ENDS\r
+\r
+PTRSAV DD 0 ;Strategy pointer save.\r
+\r
+;\r
+; Simplistic Strategy routine for non-multi-Tasking system.\r
+;\r
+; Currently just saves I/O packet pointers in PTRSAV for\r
+; later processing by the individual interrupt routines.\r
+;\r
+\r
+STRATP PROC FAR\r
+\r
+STRATEGY:\r
+ MOV WORD PTR CS:[PTRSAV],BX\r
+ MOV WORD PTR CS:[PTRSAV+2],ES\r
+ RET\r
+\r
+STRATP ENDP\r
+\r
+;\r
+; Console interrupt routine for processing I/O packets.\r
+;\r
+\r
+CON_INT:\r
+ PUSH SI\r
+ MOV SI,OFFSET CONTBL\r
+ JMP SHORT ENTRY\r
+\r
+;\r
+; Auxilary interrupt routine for processing I/O packets.\r
+;\r
+\r
+AUX_INT:\r
+ PUSH SI\r
+ MOV SI,OFFSET AUXTBL\r
+ JMP SHORT ENTRY\r
+\r
+;\r
+; Printer interrupt routine for processing I/O packets.\r
+;\r
+\r
+PRN_INT:\r
+ PUSH SI\r
+ MOV SI,OFFSET PRNTBL\r
+ JMP SHORT ENTRY\r
+\r
+;\r
+; Clock interrupt routine for processing I/O packets.\r
+;\r
+\r
+TIM_INT:\r
+ PUSH SI\r
+ MOV SI,OFFSET TIMTBL\r
+ JMP SHORT ENTRY\r
+\r
+;\r
+; Disk interrupt routine for processing I/O packets.\r
+;\r
+\r
+DSK_INT:\r
+ PUSH SI\r
+ MOV SI,OFFSET DSKTBL\r
+\r
+;\r
+; Common program for handling the simplistic I/O packet\r
+; processing scheme in MSDOS 2.0\r
+;\r
+\r
+ENTRY: PUSH AX ;Save all nessacary registers.\r
+ PUSH CX\r
+ PUSH DX\r
+ PUSH DI\r
+ PUSH BP\r
+ PUSH DS\r
+ PUSH ES\r
+ PUSH BX\r
+\r
+ LDS BX,CS:[PTRSAV] ;Retrieve pointer to I/O Packet.\r
+\r
+ MOV AL,[BX.UNIT] ;AL = Unit code.\r
+ MOV AH,[BX.MEDIA] ;AH = Media descriptor.\r
+ MOV CX,[BX.COUNT] ;CX = Contains byte/sector count.\r
+ MOV DX,[BX.START] ;DX = Starting Logical sector.\r
+\r
+ XCHG DI,AX ;Move Unit & Media into DI temporarily.\r
+ MOV AL,[BX.CMD] ;Retrieve Command type. (1 => 11)\r
+ XOR AH,AH ;Clear upper half of AX for calculation.\r
+ ADD SI,AX ;Compute entry pointer in dispatch table.\r
+ ADD SI,AX\r
+ CMP AL,11 ;Verify that not more than 11 commands.\r
+ JA CMDERR ;Ah, well, error out.\r
+ XCHG AX,DI ;Move Unit & Media back where they belong.\r
+ LES DI,[BX.TRANS] ;DI contains addess of Transfer address.\r
+ ;ES contains segment.\r
+ PUSH CS\r
+ POP DS ;Data segment same as Code segment.\r
+ JMP [SI] ;Perform I/O packet command.\r
+\r
+ PAGE\r
+ SUBTTL Common error and exit points.\r
+\r
+BUS_EXIT: ;Device busy exit.\r
+ MOV AH,00000011B ;Set busy and done bits.\r
+ JMP SHORT EXIT1\r
+\r
+CMDERR: MOV AL,3 ;Set unknown command error #.\r
+\r
+;\r
+; Common error processing routine.\r
+; AL contains actual error code.\r
+;\r
+; Error # 0 = Write Protect violation.\r
+; 1 = Unkown unit.\r
+; 2 = Drive not ready.\r
+; 3 = Unknown command in I/O packet.\r
+; 4 = CRC error.\r
+; 5 = Bad drive request structure length.\r
+; 6 = Seek error.\r
+; 7 = Unknown media discovered.\r
+; 8 = Sector not found.\r
+; 9 = Printer out of paper.\r
+; 10 = Write fault.\r
+; 11 = Read fault.\r
+; 12 = General failure.\r
+;\r
+\r
+ERR_EXIT:\r
+ MOV AH,10000001B ;Set error and done bits.\r
+ STC ;Set carry bit also.\r
+ JMP SHORT EXIT1 ;Quick way out.\r
+\r
+EXITP PROC FAR ;Normal exit for device drivers.\r
+\r
+EXIT: MOV AH,00000001B ;Set done bit for MSDOS.\r
+EXIT1: LDS BX,CS:[PTRSAV]\r
+ MOV [BX.STATUS],AX ;Save operation compete and status.\r
+\r
+ POP BX ;Restore registers.\r
+ POP ES\r
+ POP DS\r
+ POP BP\r
+ POP DI\r
+ POP DX\r
+ POP CX\r
+ POP AX\r
+ POP SI\r
+ RET ;RESTORE REGS AND RETURN\r
+EXITP ENDP\r
+\r
+ PAGE\r
+ SUBTTL Main console I/O section.\r
+\r
+MCON DW 0001H\r
+PCON DW 0002H\r
+ACON DW 0003H\r
+\r
+CHAR DB ? ;Small typeahead buffer for now.\r
+\r
+;\r
+; Console keyboard handler.\r
+;\r
+\r
+CISTAT: PUSH CX ;Save CX pair.\r
+ MOV AL,[CHAR]\r
+ OR AL,AL\r
+ JNZ CISTA9 ;Character still in buffer.\r
+CISTA1: MOV BX,ROM_CONSTA\r
+ MOV CX,[MCON]\r
+ CALL ROM_CALL ;See if character waiting.\r
+ TEST AL,AL\r
+ JZ CISTA9\r
+ MOV BX,ROM_CONIN\r
+ MOV CX,[MCON]\r
+ CALL ROM_CALL ;Get character from Rom.\r
+ OR AL,AL\r
+ JZ CISTA1 ;Got a null character.\r
+ MOV [CHAR],AL\r
+CISTA9: POP CX ;Can't lose CX pair.\r
+ RET\r
+\r
+;\r
+; Get a character from the buffer queue.\r
+;\r
+\r
+CINP: CALL CISTAT ;Check for character ready in queue.\r
+ JZ CINP ;Cycle until one ready.\r
+ MOV [CHAR],0 ;We have character in AL, clear type a head.\r
+ RET\r
+\r
+;\r
+; Console read non-destructive.\r
+;\r
+\r
+CON_RDND:\r
+ CALL CISTAT ;See if character ready.\r
+ JZ CON_RDN2 ;No, return busy signal.\r
+CON_RDN1:\r
+ LDS BX,CS:[PTRSAV]\r
+ MOV [BX.MEDIA],AL\r
+ JMP EXIT\r
+CON_RDN2:\r
+ JMP BUS_EXIT\r
+\r
+;\r
+; Console destructive read.\r
+;\r
+\r
+CON_READ:\r
+ CALL CINP ;Get character.\r
+ STOSB ;Save it in users buffer.\r
+ LOOP CON_READ ;Loop until CX is exhausted.\r
+ JMP EXIT\r
+\r
+;\r
+; Console flush routine. (ctrl-c, ctrl-f, or ctrl-s inspired)\r
+;\r
+\r
+CON_FLSH:\r
+ MOV [CHAR],0 ;Clear small type a head buffer.\r
+ JMP EXIT\r
+\r
+;\r
+; Console output status routine.\r
+;\r
+\r
+CON_WRST:\r
+ JMP EXIT ;Yes, normal exit.\r
+\r
+;\r
+; Console output routine.\r
+;\r
+\r
+CON_WRIT:\r
+ MOV SI,DI ;Get destination to source.\r
+CON_WRI1:\r
+ LODS BYTE PTR ES:[SI]\r
+ PUSH CX\r
+IF ANSI\r
+ CALL CONOUT ;Call ansi driver.\r
+ ENDIF\r
+IFE ANSI\r
+ CALL OUTCHR\r
+ ENDIF\r
+ POP CX\r
+ LOOP CON_WRI1 ;Keep going until user buffer through.\r
+ JMP EXIT\r
+\r
+;\r
+; Console character output routine.\r
+;\r
+\r
+OUTCHR: MOV BX,ROM_CONOUT\r
+ MOV CX,[MCON] ;Get current console port.\r
+ MOV DL,AL\r
+ CALL ROM_CALL\r
+ RET\r
+\r
+ PAGE\r
+\r
+IF ANSI\r
+\r
+ SUBTTL ANSI interface section.\r
+\r
+;\r
+;ANSI Info and routines. ANSI driver implemented as a finite state automata\r
+;This ANSI driver translates the ANSI standard escape sequences into the\r
+; Zenith Escape sequences used on the Zenith(Heath) Z(H)-19 terminal.\r
+;This is not a full implementation of ANSI, but rather a minimal implementation\r
+; which implements all of the necessary ANSI functions.\r
+;\r
+\r
+ESC EQU 1BH ;Escape character used in this implementation.\r
+STATE DW ST1 ;Current ANSI character state.\r
+PRMPNT DW PARMS ;Current parameter pointer.\r
+PARMS DB 0,0,0,0,0,0,0 ;Allow for up to eight parameters.\r
+LASTPRM DB 0 ;With this being the eight one.\r
+\r
+CMDTABL DB 'A' ;Cursor up. "esc","[",#,"A"\r
+ DW CUU\r
+ DB 'B' ;Cursor down. "esc","[",#,"B"\r
+ DW CUD\r
+ DB 'C' ;Cursor forward. "esc","[",#,"C"\r
+ DW CUF\r
+ DB 'D' ;Cursor back. "esc","[",#,"D"\r
+ DW CUB\r
+ DB 'H' ;Direct cursor posit. "esc","[",x,y,"H"\r
+ DW CUP\r
+ DB 'J' ;Erase. "esc","[",code,"J"\r
+ DW ED\r
+ DB 'K' ;Erase in line. "esc","[",code,"K"\r
+ DW EL\r
+ DB 'f' ;Direct cursor posit. "esc","[",x,y,"f"\r
+ DW CUP\r
+ DB 'm' ;Special video mode. "esc","[",code,"m"\r
+ DW SGR\r
+ DB 's' ;Save cursor posit. "esc","[","s"\r
+ DW PSCP\r
+ DB 'u' ;Move cursor to saved. "esc","[","u"\r
+ DW PRCP\r
+ DB 00 ;End of table.\r
+\r
+;\r
+; ANSI console output driver.\r
+;\r
+\r
+CONOUT: MOV DI,OFFSET STATE ;Retrieve current ansi state.\r
+ JMP [DI] ;Jump to it.\r
+\r
+;\r
+; State one (1).\r
+; Looks for an Escape character.\r
+;\r
+\r
+ST1: CMP AL,ESC ;See if this the first character is ESC.\r
+ JNZ OUTCHR ;No, treat as regular character output.\r
+ MOV WORD PTR [DI],OFFSET ST2 ;Yes, setup state two.\r
+ RET\r
+\r
+;\r
+; State two (2).\r
+; Looks for the "[" character.\r
+;\r
+\r
+ST2: CMP AL,'[' ;See if a valide state two.\r
+ JNZ OUTCHR ;No, treat as regular charcter\r
+ MOV BX,OFFSET PARMS ;Yes, get parameter pointer.\r
+ MOV WORD PTR [PRMPNT],BX ;Setup in pointer index.\r
+ MOV WORD PTR [BX],0 ;Clear first entry.\r
+ MOV WORD PTR [DI],OFFSET ST3;Setup for state three.\r
+ RET\r
+\r
+;\r
+; State three (3).\r
+; Entered one or more times for parameter passing.\r
+;\r
+\r
+ST3: CMP AL,';' ;Look for decimal # seperator.\r
+ JNZ ST3A ;No check phase A.\r
+ INC WORD PTR [PRMPNT] ;Yes, incr. pointer to next param.\r
+ MOV AX,OFFSET LASTPRM ;Check for outside parameter list.\r
+ CMP [PRMPNT],AX\r
+ JBE RETST3 ;Yes, proceed with next parameter.\r
+ MOV [PRMPNT],AX ;No, treat as extentsion to old.\r
+RETST3: MOV DI,[PRMPNT] ;Setup for next parameter.\r
+ MOV BYTE PTR [DI],0 ;Pre-Initialize it to zero.\r
+ RET\r
+\r
+;\r
+; State three A (3A).\r
+; Check for a ascii digit.\r
+;\r
+\r
+ST3A: CMP AL,'0' ;Check for ASCII digit.\r
+ JB ST3B ;No, check for seconday command character.\r
+ CMP AL,'9' ;Still checking for ASCII digit.\r
+ JA ST3B ;No, it must be a secondary.\r
+ SUB AL,'0' ;Convert to binary.\r
+ MOV DI,[PRMPNT] ;Get the current parameter pointer.\r
+ XCHG [DI],AL ;Get existing #.\r
+ MOV AH,10 ;Scale by 10.\r
+ MUL AH\r
+ ADD [DI],AL ;Add to new digit.\r
+ RET\r
+\r
+;\r
+; State three B (3B).\r
+; Wasn't a ascii digit, so check for secondary command.\r
+;\r
+\r
+ST3B: MOV [DI],OFFSET ST1 ;Preset STATE to state 1 just in case.\r
+ MOV DI,OFFSET PARMS-1 ;Get pointer to start of parameters.\r
+ MOV [PRMPNT],DI ;Save it in Parameter pointer.\r
+ MOV DI,OFFSET CMDTABL-3 ;Get start of Secondary command table.\r
+\r
+ST3B1: ADD DI,3 ;Update Command table pointer.\r
+ CMP BYTE PTR [DI],0 ;Check for end of table.\r
+ JNZ ST3B2 ;No, continue processing.\r
+ JMP OUTCHR ;Yes, treat as regular character.\r
+ST3B2: CMP AL,[DI] ;Check for valid. command.\r
+ JNZ ST3B1 ;No, keep checking.\r
+ JMP [DI+1] ;Yes, transfer to that secondary command.\r
+\r
+;\r
+; Get binary parameter from storage and return a one if = 0\r
+;\r
+\r
+GETONE: CALL GETPARM ;Get parameter form list.\r
+ OR AL,AL ;Verify for non-zero.\r
+ JNZ GETRET ;Good, then return to caller.\r
+ INC AL ;Bad, make it at least a one.\r
+GETRET: CBW ;Sign extend AL.\r
+ MOV CX,AX ;Copy of it to CX.\r
+ RET\r
+\r
+GETPARM:INC WORD PTR [PRMPNT] ;Increment parameter pointer.\r
+GOTPARM:MOV DI,[PRMPNT] ;Get parameter pointer.\r
+ MOV AL,[DI] ;Get parameter value.\r
+ RET\r
+\r
+;\r
+; Send escape, character sequence.\r
+;\r
+\r
+OUTESC: MOV AL,ESC ;Send escape character.\r
+ CALL OUTCHR\r
+ MOV AL,BL ;Send follow character.\r
+ JMP OUTCHR\r
+\r
+;\r
+; Cursor Positioning routines.\r
+;\r
+\r
+CUU: MOV BL,'A' ;Cursor up.\r
+ JMP SHORT CURPOS\r
+CUD: MOV BL,'B' ;Cursor down.\r
+ JMP SHORT CURPOS\r
+CUF: MOV BL,'C' ;Cursor forward.\r
+ JMP SHORT CURPOS\r
+CUB: MOV BL,'D' ;Cursor back.\r
+\r
+CURPOS: CALL GETONE ;Get number of positions to move into CX.\r
+MOVCUR: CALL OUTESC ;Send escape, command characters.\r
+ LOOP MOVCUR ;Keep moving until done.\r
+ RET\r
+\r
+;\r
+; Direct cursor positioning routine.\r
+;\r
+\r
+CUP: CALL GETONE ;Get X position.\r
+ MOV DX,AX ;Save in DX.\r
+ CALL GETONE ;Get Y position.\r
+ MOV BL,'Y'\r
+ CALL OUTESC ;Send escape, "Y" sequence.\r
+ MOV AL,DL\r
+ ADD AL,' '-1 ;Convert binary to Character.\r
+ CALL OUTCHR ;Send X posit.\r
+ MOV AL,CL\r
+ ADD AL,' '-1 ;Convert binary to Character.\r
+ JMP OUTCHR ;Send Y posit.\r
+\r
+;\r
+; Erase all/part of screen.\r
+;\r
+\r
+ED: CALL GETPARM ;Get trinary command type.\r
+ MOV BL,'b'\r
+ DEC AL ;See if erase from begining of screen.\r
+ JZ ED1 ;Yes, perform ZDS function.\r
+ MOV BL,'E'\r
+ DEC AL ;See if erase from end of screen.\r
+ JZ ED1 ;Yes, perform ZDS function.\r
+ MOV BL,'J' ;Now we assume erase whole screen.\r
+ED1: JMP OUTESC\r
+\r
+;\r
+; Erase all/part of a line.\r
+;\r
+\r
+EL: CALL GETPARM ;Get trinary command type.\r
+ MOV BL,'o'\r
+ DEC AL ;See if erase from begining of line.\r
+ JZ EL1 ;Yes, perform ZDS function.\r
+ MOV BL,'l'\r
+ DEC AL ;See if erase whole line.\r
+ JZ EL1 ;Yes, perform ZDS function.\r
+ MOV BL,'K' ;Now we assume erase to end of line.\r
+EL1: JMP OUTESC\r
+\r
+;\r
+; Special video modes.\r
+;\r
+\r
+SGR: CALL GETPARM ;Get trinary command type.\r
+ MOV BL,'p'\r
+ CMP AL,7 ;See if enter reverse video mode.\r
+ JZ SGR2 ;Yes, perform ZDS function.\r
+ MOV BL,'q'\r
+ OR AL,AL ;See if exit reverse video mode.\r
+ JNZ SGR3 ;No, ignore.\r
+SGR2: CALL OUTESC\r
+SGR3: RET\r
+\r
+;\r
+; Save / restore cursor position.\r
+;\r
+\r
+PSCP: MOV BL,'j' ;Set save cursor posit. mode.\r
+ JMP OUTESC\r
+\r
+PRCP: MOV BL,'k' ;Restore last cursor save.\r
+ JMP OUTESC\r
+\r
+ ENDIF\r
+\r
+\r
+ PAGE\r
+ SUBTTL Printer buffer handler.\r
+\r
+;\r
+; Printer status routine.\r
+;\r
+\r
+PRN_STA:\r
+ JMP EXIT\r
+\r
+;\r
+; Printer write routine.\r
+;\r
+\r
+PRN_WRT:MOV SI,DI ;Set source = destination index.\r
+\r
+PRN_WR1:LODS BYTE PTR ES:[SI];Get a data byte.\r
+ PUSH CX\r
+ MOV CX,[PCON]\r
+ MOV BX,ROM_CONOUT\r
+ MOV DL,AL\r
+ CALL ROM_CALL\r
+ POP CX\r
+ LOOP PRN_WR1\r
+ RET\r
+\r
+ PAGE\r
+ SUBTTL Auxilary I/O routines.\r
+\r
+AUXCHAR DB 0 ;Temporary AUX ahead storage.\r
+\r
+;\r
+; Status routine for Auxilary port.\r
+;\r
+\r
+AISTAT: MOV AL,[AUXCHAR]\r
+ TEST AL,AL\r
+ JNZ AISTA9 ;Character already waiting.\r
+ MOV CX,[ACON]\r
+ MOV BX,ROM_CONSTA\r
+ CALL ROM_CALL\r
+ TEST AL,AL\r
+ JZ AISTA9 ;Still none waiting.\r
+ MOV CX,[ACON]\r
+ MOV BX,ROM_CONIN\r
+ CALL ROM_CALL\r
+AISTA9: MOV [AUXCHAR],AL\r
+ RET\r
+\r
+;\r
+; Auxilary port read.\r
+;\r
+\r
+AIN: CALL AISTAT ;Get status and/or char.\r
+ JZ AIN ;Cycle until one is ready.\r
+ MOV [AUXCHAR],0\r
+ RET\r
+\r
+;\r
+; Write routine for Auxilary port.\r
+;\r
+\r
+AOUT: MOV CX,[ACON]\r
+ MOV BX,ROM_CONOUT\r
+ MOV DL,AL\r
+ CALL ROM_CALL\r
+ RET\r
+\r
+;\r
+; Non-Destructive Auxilary read routine.\r
+;\r
+\r
+AUX_RDND:\r
+ CALL AISTAT ;Get status and copy of char. waiting if any.\r
+ JZ AUX_RDN2 ;No character waiting, exit.\r
+ JMP CON_RDN1\r
+AUX_RDN2:\r
+ JMP BUS_EXIT\r
+\r
+;\r
+; Destructive Auxilary read routine.\r
+;\r
+\r
+AUX_READ:\r
+ CALL AIN ;Get data character.\r
+ STOSB ;Save it through DI.\r
+ LOOP AUX_READ ;Cycle until user buffer full.\r
+ JMP EXIT\r
+\r
+;\r
+; Auxilary clear type a head.\r
+;\r
+\r
+AUX_CLR:\r
+ MOV [AUXCHAR],0\r
+ JMP EXIT\r
+\r
+;\r
+; Auxilary write port status.\r
+;\r
+\r
+AUX_WRST:\r
+ JMP EXIT\r
+\r
+;\r
+; Auxilary write.\r
+;\r
+\r
+AUX_WRIT:\r
+ MOV SI,DI\r
+AUX_WRI1:\r
+ LODS BYTE PTR ES:[SI] ;Get char. from users buffer.\r
+ CALL AOUT ;Send it to device.\r
+ LOOP AUX_WRI1 ;Cycle until all done.\r
+ JMP EXIT\r
+\r
+ PAGE\r
+ SUBTTL Date/Time Routines.\r
+\r
+TIM_DAYS: DB 2 DUP (?) ;Number of days since 1-1-80.\r
+TIM_MINS: DB ? ;Minutes.\r
+TIM_HRS: DB ? ;Hours.\r
+TIM_HSEC: DB ? ;Hundreths of a second.\r
+TIM_SECS: DB ? ;Seconds.\r
+\r
+;\r
+; Time write routine.\r
+;\r
+\r
+TIM_WRT:\r
+ MOV SI,OFFSET TIM_DAYS\r
+ XCHG SI,DI\r
+ PUSH ES\r
+ MOV AX,DS\r
+ POP DS\r
+ MOV ES,AX\r
+ MOV CX,6\r
+ REP MOVSB\r
+ MOV AL,0\r
+ JMP EXIT\r
+\r
+;\r
+; Time read routine.\r
+;\r
+\r
+TIM_RED:\r
+ MOV SI,OFFSET TIM_DAYS\r
+ MOV CX,6\r
+ REP MOVSB\r
+ MOV AL,0\r
+ JMP EXIT\r
+\r
+ PAGE\r
+ SUBTTL 8089 Monitor structure.\r
+\r
+;\r
+; Structure to reference 8089 and ROM command table.\r
+;\r
+\r
+SIOPB STRUC\r
+ DB 4 DUP (?) ;Monitor Use Only\r
+OPCODE DB ? ;I/O operation code.\r
+DRIVE DB ? ;Logical drive spec.\r
+TRACK DW ? ;Logical track number.\r
+HEAD DB ? ;Logical head number.\r
+SECTOR DB ? ;Logical sector to start with.\r
+SCOUNT DB ? ;Number of logical sectors in buffer.\r
+RETCODE DB ? ;Error code after masking.\r
+RETMASK DB ? ;Error mask.\r
+RETRIES DB ? ;Number of retries before error exit.\r
+DMAOFF DW ? ;Buffer offset address.\r
+DMASEG DW ? ;Buffer segment.\r
+SECLENG DW ? ;Sector Length.\r
+ DB 6 DUP (?) ;8089 use only.\r
+SIOPB ENDS\r
+\r
+IOPB SIOPB <,00H,0,0,0,0,0,0,000H,0,0,0,0,>\r
+\r
+ PAGE\r
+ SUBTTL Drive Tables.\r
+\r
+\r
+;\r
+; MSDOS drive initialization tables and other what not.\r
+;\r
+; Drive 0 is:\r
+; Single sided, Single density, 77 track with 26\r
+; 128 byte sectors per track. One sector for\r
+; boot and header. (256,128 bytes free, old style).\r
+; or\r
+; Single sided, Single density, 77 track with 26\r
+; 128 byte sectors per track. Four sectors for\r
+; boot and header. (255,744 bytes free).\r
+; or\r
+; Single sided, Double Density, 75 track with 12\r
+; 512 byte sectors per track.\r
+; (460,800 bytes)\r
+; Two hidden single density tracks.\r
+;\r
+\r
+DBP STRUC\r
+\r
+JMPNEAR DB 3 DUP (?) ;Jmp Near xxxx for boot.\r
+NAMEVER DB 8 DUP (?) ;Name / Version of OS.\r
+\r
+;------- Start of Drive Parameter Block.\r
+\r
+SECSIZE DW ? ;Sector size in bytes. (dpb)\r
+ALLOC DB ? ;Number of sectors per alloc. block. (dpb)\r
+RESSEC DW ? ;Reserved sectors. (dpb)\r
+FATS DB ? ;Number of FAT's. (dpb)\r
+MAXDIR DW ? ;Number of root directory entries. (dpb)\r
+SECTORS DW ? ;Number of sectors per diskette. (dpb)\r
+MEDIAID DB ? ;Media byte ID. (dpb)\r
+FATSEC DW ? ;Number of FAT Sectors. (dpb)\r
+\r
+;------- End of Drive Parameter Block.\r
+\r
+SECTRK DW ? ;Number of Sectors per track.\r
+\r
+DBP ENDS\r
+\r
+LSDRIV1 DBP <,,128,4,1,2,68,2002,0FEH,6,26>\r
+\r
+LSDRIV2 DBP <,,128,4,4,2,68,2002,0FDH,6,26>\r
+\r
+LDDRIV1 DBP <,,512,1,24,2,128,924,0F8H,3,12>\r
+\r
+LDDRIV2 DBP <,,1024,1,16,2,128,616,0F9H,1,8>\r
+\r
+DSK_INIT:\r
+ MOV AX,1\r
+ MOV SI,OFFSET INITTAB\r
+ JMP GET_BP5\r
+\r
+INITTAB:\r
+ DW LDDRIV2.SECSIZE\r
+\r
+DSTAT EQU 41H ;1793 status port.\r
+DTRACK EQU 43H ;1793 track port.\r
+DSECTOR EQU 45H ;1793 sector port.\r
+DDATA EQU 47H ;1793 data I/O port.\r
+\r
+DDENS EQU 55H ;Density select port.\r
+DDBIT EQU 04H ;Density select bit.\r
+DSELECT EQU 53H ;Drive select port.\r
+\r
+CURDRV DB 0\r
+DRVTAB DB 0EH,0DH,0BH,07H\r
+TRKPT DB 0,1,2,3\r
+TRKTAB DB -1,-1,-1,-1\r
+PREDENS DB 0,0,0,0\r
+\r
+ PAGE\r
+ SUBTTL Media check routine\r
+\r
+;\r
+; Media check routine.\r
+; On entry:\r
+; AL = disk unit number.\r
+; AH = media byte\r
+; On exit:\r
+;\r
+; [MEDIA FLAG] = -1 (FF hex) if disk is changed.\r
+; [MEDIA FLAG] = 0 if don't know.\r
+; [MEDIA FLAG] = 1 if not changed.\r
+;\r
+; [MEDIA] = 0FEH for Standard single density.\r
+; [MEDIA] = 0FDH for Altos single density.\r
+; [MEDIA] = 0F4H for Altos double density.\r
+;\r
+\r
+MEDIAS STRUC\r
+ DB 13 DUP(?) ;Static request header.\r
+MEDIAS1 DB ? ;Media byte.\r
+MEDIAS2 DB ? ;Media status byte flag.\r
+MEDIAS ENDS\r
+\r
+MEDIAC: \r
+ AND AL,03H ;Clear any extraneous bits.\r
+ PUSH AX ;Save drive number requested.\r
+ MOV AL,0D0H ;Terminate with no interrupt.\r
+ CALL DCOM\r
+ AND AL,20H ;See if head load bit set.\r
+ POP AX\r
+ JZ MEDIA2 ;Head not loaded, so see if media changed.\r
+ MOV AH,1 ; AH = 1, disk not changed.\r
+ JMP SHORT MEDIA1\r
+\r
+MEDIA1A:MOV [PREDENS],DL ;Save last density used for read.\r
+\r
+MEDIA1: LDS BX,[PTRSAV] ;Udate media section of data block.\r
+ MOV [BX.MEDIAS2],AH\r
+ MOV AL,0\r
+ JMP EXIT\r
+\r
+MEDIA2: CALL MEDIA4 ;Unload head if selecting new drive.\r
+ MOV CX,2 ;Try each density once.\r
+ MOV BX,OFFSET DRVTAB\r
+ XLAT ;Convert from drive # to select code.\r
+ OUT DSELECT,AL ;Select disk\r
+ MOV AH,0 ;Assume that we don't know.\r
+ MOV DL,[PREDENS] ;Get last density.\r
+ AND DL,DDBIT ;Be sure only Density bit set/clr.\r
+MEDIA3: IN AL,DDENS\r
+ AND AL,0FBH ;Clear density bit.\r
+ OR AL,DL ;Set/clear density bit.\r
+ OUT DDENS,AL ;Select density.\r
+ MOV AL,0C4H ;READ ADDRESS command\r
+ CALL DCOM\r
+ AND AL,98H\r
+ IN AL,DDATA ;Eat last byte to reset DRQ\r
+ JZ MEDIA1A ;Jump if no error in reading address.\r
+ MOV AH,0FFH ; AH = -1 (disk changed) if new density works.\r
+ XOR DL,DDBIT ;Flip density bit.\r
+ LOOP MEDIA3\r
+ MOV AX,2 ;Couldn't read disk at all, AH = 0 for don't\r
+ JMP ERR_EXIT ; know if disk changed, AL = error code 2 -\r
+\r
+MEDIA4: MOV AH,AL ;Save disk drive number in AH.\r
+ XCHG AL,[CURDRV] ;make new drive current, AL = previous\r
+ CMP AL,AH ;Changing drives?\r
+ JZ MEDIA5 ;No, return to caller.\r
+;\r
+; If changing drives, unload head so the head load delay one-shot\r
+; will fire again. Do it by seeking to same track with the H bit reset.\r
+;\r
+ IN AL,DTRACK ;Get current track number\r
+ OUT DDATA,AL ;Make it the track to seek to\r
+ MOV AL,10H ;Seek and unload head\r
+ CALL DCOM\r
+ MOV AL,AH ;Restore current drive number\r
+MEDIA5: RET\r
+\r
+;\r
+; Short routine to send a command to 1793 diskette controller chip and\r
+; wait for 1793 to complete the command.\r
+;\r
+\r
+DCOM: OUT 41H,AL ;Send command to 1793.\r
+ MOV CX,10H\r
+DCOM1: LOOP DCOM1 ;Wait a short time for 1793 to digest it.\r
+\r
+DCOM2: IN AL,41H ;Get 1793's status.\r
+ AND AL,1 ;See if busy.\r
+ JNZ DCOM2 ;Yes, keep checking.\r
+ IN AL,41H ;Get 1793's status for return\r
+ RET\r
+\r
+ PAGE\r
+ SUBTTL Build and return Bios Parameter Block for a diskette.\r
+\r
+;\r
+; Build Bios Parameter Blocks.\r
+;\r
+; On entry: ES:DI contains the address of a scratch sector buffer.\r
+; AL = Unit number.\r
+; AH = Current media byte.\r
+;\r
+; On exit: Return a DWORD pointer to the associated BPB\r
+; in the Request packet.\r
+;\r
+\r
+BPBS STRUC\r
+ DB 13 DUP(?) ;Static request header.\r
+BPB1 DB ? ;Media byte.\r
+BPB2 DW ? ;DWORD transfer address.\r
+ DW ?\r
+BPB3 DW ? ;DWORD pointer to BPB\r
+ DW ?\r
+BPBS ENDS\r
+\r
+GET_BPB:\r
+ PUSH ES\r
+ PUSH DI\r
+ MOV [IOPB.DMASEG],ES\r
+ MOV [IOPB.DMAOFF],DI\r
+ MOV BYTE PTR[IOPB.SECTOR],1\r
+ MOV BYTE PTR[IOPB.SCOUNT],1\r
+ MOV BYTE PTR[IOPB.OPCODE],088H\r
+ MOV BYTE PTR[IOPB.RETRIES],1\r
+ MOV BYTE PTR[IOPB.DRIVE],0\r
+ MOV [IOPB.TRACK],0\r
+ MOV BYTE PTR[IOPB.HEAD],1\r
+ MOV BYTE PTR[IOPB.RETMASK],0DCH\r
+ MOV [IOPB.SECLENG],128\r
+ MOV BX,ROM_DISKIO\r
+ MOV CX,OFFSET IOPB\r
+ PUSH CS\r
+ POP ES\r
+ CALL ROM_CALL ;Read sector zero for information.\r
+ PUSH CS\r
+ POP DS\r
+ POP DI\r
+ POP ES\r
+ MOV AH,[IOPB.RETCODE]\r
+ OR AH,AH\r
+ JNZ GET_BP3 ;Disk error, assume old single density.\r
+\r
+GET_BP1:MOV AL,ES:[DI.MEDIAID] ;Get diskettes media ID.\r
+ MOV SI,OFFSET LSDRIV2\r
+ CMP AL,[SI.MEDIAID]\r
+ JZ GET_BP4\r
+ MOV SI,OFFSET LDDRIV1\r
+ CMP AL,[SI.MEDIAID]\r
+ JZ GET_BP4\r
+ MOV SI,OFFSET LDDRIV2\r
+ CMP AL,[SI.MEDIAID]\r
+ JZ GET_BP4\r
+\r
+GET_BP3:MOV SI,OFFSET LSDRIV1 ;No compares, assume old style for now.\r
+\r
+GET_BP4:MOV AL,[SI.MEDIAID]\r
+ ADD SI,11 ;Convert to DPB pointer\r
+\r
+GET_BP5:LDS BX,[PTRSAV] ;Update I/O data packet.\r
+ MOV [BX.BPB1],AL ;Media byte.\r
+ MOV [BX.BPB3],SI ;DPB pointer.\r
+ MOV [BX.BPB3+2],CS ;Code segment.\r
+ OR AH,AH\r
+ JNZ GET_BP6\r
+ MOV AL,0\r
+ JMP EXIT\r
+GET_BP6:MOV AX,7\r
+ JMP ERR_EXIT\r
+\r
+ PAGE\r
+\r
+ SUBTTL Disk I/O equates.\r
+\r
+; Floppy drives\r
+\r
+; --------------------------\r
+; Hardware command def.\r
+; --------------------------\r
+;\r
+; Read command = 88 hex.\r
+; Write command = A8 hex.\r
+; Format command = F0 hex.\r
+; Seek command = 1E hex.\r
+; Recal command = 0A hex.\r
+; Set DD mode = 80 hex.\r
+;\r
+; --------------------------\r
+; Status bits:\r
+; --------------------------\r
+;\r
+; Busy = 01 hex.\r
+; (not used) = 02 hex.\r
+; TK0(seek) = 04 hex.\r
+; Lost Data = 04 hex.\r
+; CRC error = 08 hex.\r
+; Seek error = 10 hex.\r
+; Not found = 10 hex.\r
+; Write fault = 20 hex.\r
+; Write protect = 40 hex.\r
+; Not ready = 80 hex.\r
+;\r
+; --------------------------\r
+\r
+F_READ EQU 088H ;Floppy read command.\r
+F_WRIT EQU 0A8H ;Floppy write command.\r
+F_FMT EQU 0F0H ;Floppy format command.\r
+F_SEEK EQU 01EH ;Floppy seek command.\r
+F_RECAL EQU 00AH ;Floppy recal. command.\r
+F_DD EQU 080H ;Set Drive double density bit.\r
+\r
+ PAGE\r
+ SUBTTL MSDOS 2.x Disk I/O drivers.\r
+\r
+;\r
+; Disk READ/WRITE functions.\r
+;\r
+; On entry:\r
+; AL = Disk I/O driver number\r
+; AH = Media byte.\r
+; ES = Disk transfer segment.\r
+; DI = Disk transfer offset in ES.\r
+; CX = Number of sectors to transfer\r
+; DX = Logical starting sector.\r
+;\r
+; On exit:\r
+; Normal exit through common exit routine.\r
+;\r
+; Abnormal exit through common error routine.\r
+;\r
+\r
+DSK_RED:\r
+ MOV BX,0DC88H ;Set read mode and Error mask.\r
+ JMP SHORT DSK_COM\r
+DSK_WRV:\r
+DSK_WRT:MOV BX,0FCA8H ;Set write mode and Error mask.\r
+\r
+DSK_COM:MOV SI,OFFSET LSDRIV1\r
+ CMP AH,[SI.MEDIAID]\r
+ JE DSK_CO3\r
+ MOV SI,OFFSET LSDRIV2\r
+ CMP AH,[SI.MEDIAID]\r
+ JE DSK_CO3\r
+ MOV SI,OFFSET LDDRIV1\r
+ CMP AH,[SI.MEDIAID]\r
+ JE DSK_CO2\r
+ MOV SI,OFFSET LDDRIV2\r
+ CMP AH,[SI.MEDIAID]\r
+ JE DSK_CO2\r
+ MOV AL,7\r
+ JMP ERR_EXIT\r
+\r
+DSK_CO2:OR AL,F_DD ;Set double density mode.\r
+\r
+DSK_CO3:MOV [IOPB.DMASEG],ES ;Setup Buffer segment.\r
+ MOV [IOPB.DMAOFF],DI ;Setup buffer offset.\r
+ MOV DI,[SI.SECSIZE] ;Get sector size.\r
+ MOV [IOPB.SECLENG],DI\r
+ MOV [IOPB.RETRIES],1 ;Setup number of retries.\r
+ MOV [IOPB.RETMASK],BH ;Operation error mask.\r
+ MOV [IOPB.OPCODE],BL ;R/W opcode.\r
+ MOV [IOPB.DRIVE],AL ;Drive with density select.\r
+ MOV [IOPB.HEAD],1 ;Only one head on floppy drive.\r
+ MOV BP,CX ;Save number of sectors to R/W\r
+DSK_CO4:PUSH DX ;Save starting sector.\r
+ MOV AX,DX\r
+ MOV DX,0 ;32 bit divide coming up.\r
+ MOV CX,[SI.SECTRK]\r
+ DIV CX ;Get track+head and start sector.\r
+ INC DL\r
+ MOV [IOPB.SECTOR],DL ;Starting sector.\r
+ MOV BL,DL ;Save starting sector for later.\r
+ MOV [IOPB.TRACK],AX ;Track to read/write.\r
+ MOV AX,[SI.SECTRK] ;Now see how many sectors\r
+ INC AL ; we can burst read.\r
+ SUB AL,BL ;BL is the starting sector.\r
+ MOV AH,0\r
+ POP DX ;Retrieve logical sector start.\r
+ CMP AX,BP ;See if on last partial track+head.\r
+ JG DSK_CO5 ;Yes, on last track+head.\r
+ SUB BP,AX ;No, update number of sectors left.\r
+ ADD DX,AX ;Update next starting sector.\r
+ JMP SHORT DSK_CO6\r
+DSK_CO5:MOV AX,BP ;Only read enough of sector\r
+ MOV BP,0 ;to finish buffer and clear # left.\r
+DSK_CO6:MOV [IOPB.SCOUNT],AL\r
+ MOV DI,AX ;Save number sectors for later.\r
+ MOV BX,ROM_DISKIO\r
+ MOV CX,OFFSET IOPB\r
+ PUSH CS\r
+ POP ES\r
+ CALL ROM_CALL ;Do disk operation.\r
+ MOV AL,[IOPB.RETCODE] ;Get error code.\r
+ OR AL,AL\r
+ JNZ DERROR\r
+ MOV AX,DI ;Retrieve number of sectors read.\r
+ MOV CX,[SI.SECSIZE] ;Number of bytes per sector.\r
+ PUSH DX\r
+ MUL CX\r
+ POP DX\r
+ TEST AL,0FH ;Make sure no strange sizes.\r
+ JNZ DSK_CO7 ;Illegal sector size found.\r
+ MOV CL,4\r
+ SHR AX,CL ;Convert number of bytes to para.\r
+ ADD AX,[IOPB.DMASEG]\r
+ MOV [IOPB.DMASEG],AX\r
+ OR BP,BP\r
+ JNZ DSK_CO4 ;Still more to do.\r
+ MOV AL,0\r
+ JMP EXIT ;All done.\r
+DSK_CO7:MOV AL,12\r
+ JMP ERR_EXIT\r
+\r
+ PAGE\r
+ SUBTTL Disk Error processing.\r
+\r
+;\r
+; Disk error routine.\r
+;\r
+\r
+DERROR: LDS BX,CS:[PTRSAV]\r
+ MOV [BX.COUNT],0\r
+ PUSH CS\r
+ POP DS\r
+\r
+ MOV BL,-1\r
+ MOV AH,AL\r
+ MOV BH,14 ;Lenght of table.\r
+ MOV SI,OFFSET DERRTAB\r
+DERROR2:INC BL ;Increment to next error code.\r
+ LODS BYTE PTR CS:[SI]\r
+ CMP AH,AL ;See if error code matches disk status.\r
+ JZ DERROR3 ;Got the right error, exit.\r
+ DEC BH\r
+ JNZ DERROR2 ;Keep checking table.\r
+ MOV BL,12 ;Set general type of error.\r
+DERROR3:MOV AL,BL ;Now we've got the code.\r
+ RET\r
+\r
+DERRTAB DB 40H ; 0. Write protect error\r
+ DB 00H ; 1. Unknown unit.\r
+ DB 80H ; 2. Not ready error.\r
+ DB 0FFH ; 3. Unknown command.\r
+ DB 08H ; 4. CRC error\r
+ DB 00H ; 5. Bad drive request.\r
+ DB 02H ; 6. Seek error\r
+ DB 00H ; 7. Unknown media.\r
+ DB 10H ; 8. Sector not found\r
+ DB 00H ; 9. (Not used.)\r
+ DB 20H ;10. Write fault.\r
+ DB 04H ;11. Read fault.\r
+ DB 07H ;12. General type of failure.\r
+\r
+ PAGE\r
+ SUBTTL Common ROM call routine.\r
+\r
+;\r
+; Save all registers except CX, BX and AX.\r
+\r
+ROMRTN DD 0FE000000H ;Main ROM entry point.\r
+\r
+ROM_CALL:\r
+ PUSH DI\r
+ PUSH SI\r
+ PUSH BP\r
+ PUSH DX\r
+ PUSH ES\r
+ CALL CS:DWORD PTR [ROMRTN]\r
+ POP ES\r
+ POP DX\r
+ POP BP\r
+ POP SI\r
+ POP DI\r
+ RET\r
+\r
+ PAGE\r
+ SUBTTL Initalization code and temporary work areas.\r
+\r
+;\r
+; Overlayed by MSDOS by SYSINIT.\r
+;\r
+\r
+WRKSTK LABEL WORD\r
+ DB 100 DUP (?)\r
+\r
+\r
+HWINIT: XOR BP,BP\r
+ MOV SS,BP\r
+ MOV SP,OFFSET WRKSTK+98 ;Some nice area for stack.\r
+\r
+ PUSH CS\r
+ POP ES\r
+\r
+ MOV BX,ROM_INIT\r
+ CALL ROM_CALL\r
+ MOV AH,0\r
+ MOV MCON,AX\r
+\r
+ MOV AX,SEG SYSINIT\r
+ MOV DS,AX\r
+\r
+ASSUME DS:SEG SYSINIT\r
+\r
+ MOV AX,CS\r
+ ADD AX,BIOSIZS\r
+ MOV DS:[CURRENT_DOS_LOCATION],AX\r
+ MOV DS:[MEMORY_SIZE],MAX_MEM\r
+ MOV AX,CS\r
+ MOV WORD PTR DS:[DEVICE_LIST+2],AX\r
+ MOV WORD PTR DS:[DEVICE_LIST],OFFSET DEVSTART\r
+ MOV AX,CS\r
+ ADD AX,((OFFSET WRKSTK - OFFSET INIT)+50) /16\r
+ MOV DS:[FINAL_DOS_LOCATION],AX\r
+ JMP SYSINIT\r
+\r
+DOSSPOT LABEL WORD\r
+\r
+CODE ENDS\r
+\r
+ END\r
+\1a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+TITLE SORT FILTER FOR MS-DOS\r
+;\r
+; Sort /R /+n\r
+; /R -> reverse sort\r
+; /+n -> sort on column n\r
+;\r
+; Written by: Chris Peters\r
+;\r
+; Modification History:\r
+; 3-18-83 MZ Fix CR-LF at end of buffer\r
+; Fix small file sorting\r
+; Fix CR-LF line termination bug\r
+; Comment the Damn source\r
+;\r
+FALSE EQU 0\r
+TRUE EQU NOT FALSE\r
+\r
+;NOTE: "internat" must be false if KANJI version\r
+internat equ true\r
+;NOTE: see above\r
+\r
+.xlist\r
+.xcref\r
+ INCLUDE DOSSYM.ASM\r
+.cref\r
+.list\r
+\r
+sys MACRO name ; system call macro\r
+ MOV AH,name\r
+ INT 21h\r
+ ENDM\r
+save MACRO reglist ; push those registers\r
+IRP reg,<reglist>\r
+ PUSH reg\r
+ENDM\r
+ENDM\r
+restore MACRO reglist ; pop those registers\r
+IRP reg,<reglist>\r
+ POP reg\r
+ENDM\r
+ENDM\r
+\r
+MAXREC EQU 256 ; MAXIMUM NUL RECORD SIZE\r
+\r
+SPACE EQU 0 ; Offset zero in the allocated block\r
+BUFFER EQU MAXREC ; Offset MAXREC in the allocated block\r
+\r
+SUBTTL Segments used in load order\r
+\r
+\r
+CODE SEGMENT\r
+CODE ENDS\r
+\r
+CONST SEGMENT PUBLIC BYTE\r
+CONST ENDS\r
+\r
+CSTACK SEGMENT STACK\r
+ DB 128 DUP (0) ; initial stack to be clear\r
+CSTACK ENDS\r
+\r
+DG GROUP CODE,CONST,CSTACK\r
+\r
+CODE SEGMENT\r
+ASSUME CS:DG,DS:NOTHING,ES:NOTHING,SS:CSTACK\r
+\r
+COLUMN DW 0 ; COLUMN TO USE FOR KEY + 1\r
+SWITCH DB '/'\r
+\r
+SORT:\r
+;\r
+; check for proper version number of system\r
+;\r
+ sys GET_VERSION\r
+ XCHG AH,AL ; Turn it around to AH.AL\r
+ CMP AX,200H ; Version 2.00 only\r
+ JAE OKDOS ; Success\r
+ MOV DX,OFFSET DG:BADVER ; Get error message\r
+ PUSH CS ; Get DS addressability\r
+ POP DS\r
+ sys STD_CON_STRING_OUTPUT ; Send to STDOUT\r
+ PUSH ES ; long segment\r
+ PUSH COLUMN ; offset zero\r
+LONG_RET PROC FAR\r
+ RET ; long return to OS\r
+LONG_RET ENDP\r
+;\r
+; get proper switch character\r
+;\r
+OKDOS:\r
+ MOV AL,0 ; Get current switch character\r
+ sys CHAR_OPER\r
+ MOV SWITCH,DL\r
+;\r
+; parse command line\r
+;\r
+ MOV SI,80H ; pointer to command line\r
+ CLD ; go left to right\r
+ XOR CX,CX\r
+ LODSB\r
+ MOV CL,AL ; CX = length of command line\r
+SWITCH_LOOP:\r
+ CALL GET_CHAR ; get a character\r
+ CMP AL,SWITCH ; beginning of switch?\r
+ JNZ SWITCH_LOOP ; No, get next character\r
+ CALL GET_CHAR ; get 1st char of switch\r
+ CMP AL,'+' ; Column to sort?\r
+ JZ SWITCH_NUMBER ; Yes, parse a number\r
+ OR AL,20h ; convert to lower case\r
+ CMP AL,'r' ; Reverse sort?\r
+ JNZ SWITCH_LOOP ; No, get next switch\r
+ MOV CS:CODE_PATCH,72h ; sleaze JAE into JB\r
+ JMP SWITCH_LOOP ; get next switch\r
+SWITCH_NUMBER:\r
+ MOV COLUMN,0 ; start off at 0\r
+SWITCH_NEXT_NUMBER:\r
+ CALL GET_CHAR ; get supposed digit\r
+ SUB AL,'0' ; convert to number\r
+ JB SWITCH_LOOP ; less than '0'\r
+ CMP AL,9 ; is it a valid digit?\r
+ JA SWITCH_LOOP ; nope, get next switch\r
+ CBW ; make it a full word\r
+ MOV BX,AX ; save byte away\r
+ MOV AX,10 ; decimal number system\r
+ MUL COLUMN ; take previous result\r
+ ADD AX,BX ; add in low order digit\r
+ MOV COLUMN,AX ; save away value\r
+ JMP SWITCH_NEXT_NUMBER ; get next character\r
+GET_CHAR:\r
+ JCXZ END_GET ; End of line\r
+ DEC CX ; dec char count\r
+ LODSB ; get the character\r
+ RET ; return\r
+END_GET:\r
+ POP AX ; nuke return on stack\r
+;\r
+; set up column for proper sort offset\r
+;\r
+END_SWITCH:\r
+ ADD COLUMN,2\r
+ CMP COLUMN,2\r
+ JZ GOT_COL\r
+ DEC COLUMN\r
+\r
+;\r
+; Get sorting area, no more than 64K\r
+;\r
+GOT_COL:\r
+ MOV BX,1000H ; 64K worth of paragraphs\r
+GET_MEM:\r
+ sys ALLOC ; allocate them from somewhere\r
+ JNC GOT_MEM ; if error, BX has amount free, try to get it\r
+ OR BX,BX ; but, is BX = 0?\r
+ JNZ GET_MEM ; nope, try to allocate it\r
+ JMP SIZERR ; complain\r
+\r
+GOT_MEM:\r
+ MOV DS,AX ; Point DS to buffer\r
+ MOV ES,AX ; and point ES to buffer\r
+ MOV CL,4 ; 2^4 bytes per paragraph\r
+ SHL BX,CL ; Find out how many bytes we have\r
+\r
+;\r
+; clear out temporary record area\r
+;\r
+ MOV CX,MAXREC/2 ; Size of temporary buffer (words)\r
+ MOV AX,' ' ; Character to fill with\r
+ MOV DI,SPACE ; Beginning of temp buffer\r
+ REP STOSW ; Blam.\r
+;\r
+; read in file from standard input\r
+;\r
+ MOV DX,BUFFER + 2 ; DX = place to begin reading\r
+ MOV CX,BX ; CX is the max number to read\r
+ SUB CX,MAXREC + 2 ; remember offset of temp buffer\r
+SORTL:\r
+ XOR BX,BX ; Standard input\r
+ sys READ ; Read it in\r
+ ADD DX,AX ; Bump pointer by count read\r
+ SUB CX,AX ; subtract from remaining the count read\r
+ JZ SIZERR ; if buffer is full then error\r
+ OR AX,AX ; no chars read -> end of file\r
+ JNZ SORTL ; there were chars read. go read again\r
+ JMP SHORT SIZOK ; trim last ^Z terminated record\r
+SIZERR:\r
+ MOV SI,OFFSET DG:ERRMSG ; not enough memory error\r
+ERROR_EXIT:\r
+ PUSH CS ; DS addressability\r
+ POP DS\r
+ LODSW ; get length\r
+ MOV CX,AX ; put into appropriate register\r
+ MOV DX,SI ; get output destination\r
+ MOV BX,2 ; output to standard error\r
+ sys WRITE ; and write it out\r
+ MOV AL,1 ; return an error code\r
+ sys EXIT\r
+\r
+;\r
+; Look for a ^Z. Terminate buffer at 1st ^Z.\r
+;\r
+SIZOK:\r
+ MOV BX,DX ; save end pointer\r
+ MOV CX,DX ; get pointer to end of text\r
+ SUB CX,BUFFER+2 ; dif in pointers is count\r
+ MOV AL,1AH ; char is ^Z\r
+ MOV DI,BUFFER+2 ; point to beginning of text\r
+ REPNZ SCASB ; find one\r
+ JNZ NoBack ; nope, try to find CRLF\r
+ DEC BX ; pretend that we didn't see ^Z\r
+NoBack:\r
+ SUB BX,CX ; sub from endpointer the number left\r
+ SUB BX,2 ; Hope for a CR LF at end\r
+ CMP WORD PTR [BX],0A0Dh ; Was there one there?\r
+ JZ GOTEND ; yep, here is the end\r
+ ADD BX,2 ; nope, bump back to SCASB spot\r
+ CMP BYTE PTR [BX],AL ; Was there ^Z there?\r
+ JZ GOTEND ; yep, chop it\r
+ INC BX ; Nope, skip last char\r
+GOTEND:\r
+ MOV BP,BX ; BP = filesize-2(CRLF)+temp buffer+2\r
+ MOV WORD PTR DS:[BP],0 ; 0 at end of the file\r
+;\r
+; We now turn the entire buffer into a linked list of chains by\r
+; replacing CRLFs with the length of the following line (with 2 for CRLF)\r
+;\r
+ MOV BX,BUFFER ; pointer to line head (length)\r
+ MOV DI,BUFFER+2 ; pointer to line text\r
+REPLACE_LOOP:\r
+ MOV AL,13 ; char to look for is CR\r
+ MOV CX,BP ; count = end pointer\r
+ SUB CX,DI ; chop off start point to get length\r
+ INC CX ; add 1???\r
+REPLACE_SCAN:\r
+ REPNZ SCASB ; look for CR\r
+ JNZ REPLACE_SKIP ; count exhausted\r
+ CMP BYTE PTR [DI],10 ; LF there?\r
+ JNZ REPLACE_SCAN ; nope, continue scanning\r
+REPLACE_SKIP:\r
+ MOV AX,DI ; AX to point after CR\r
+ DEC AX ; AX to point to CR\r
+ save <AX> ; save pointer\r
+ SUB AX,BX ; AX is length of line found\r
+ MOV [BX],AX ; stuff it in previous link\r
+ restore <BX> ; get pointer to next\r
+ INC DI ; skip LF???\r
+ JCXZ END_REPLACE_LOOP ; no more to scan -> go sort\r
+ JMP REPLACE_LOOP ; look for next\r
+\r
+END_REPLACE_LOOP:\r
+ MOV WORD PTR [BX],0 ; terminate file with nul\r
+ LEA BP,[BX+2] ; remember the null line at end\r
+ MOV DI,BUFFER ; DI is start of unsorted section\r
+\r
+;\r
+; begin sort. Outer loop steps over all unsorted lines\r
+;\r
+OUTER_SORT_LOOP:\r
+ MOV BX,DI ; BX is start of unsorted section\r
+ MOV SI,BX ; SI is scanning place link\r
+ CMP WORD PTR [BX],0 ; are we at the end of the buffer?\r
+ JNZ INNER_SORT_LOOP ; No, do inner process\r
+ JMP END_OUTER_SORT_LOOP ; yes, go dump out\r
+\r
+;\r
+; BX points to best guy found so far. We scan through the sorted section\r
+; to find an appropriate insertion point\r
+;\r
+INNER_SORT_LOOP:\r
+ ADD SI,[SI] ; link to next fellow\r
+ MOV AX,[SI] ; get length of comparison guy\r
+ OR AX,AX ; test for end of buffer\r
+ JZ END_INNER_SORT_LOOP ; if zero then figure out insertion\r
+ save <SI,DI> ; save SI,DI\r
+ MOV DI,BX ; DI = pointer to tester link\r
+ SUB AX,COLUMN ; adjust length for column\r
+ JA AXOK ; more chars in tester than column?\r
+ MOV SI,SPACE ; point SI to blank area\r
+ MOV AX,MAXREC ; make AX be max length\r
+AXOK:\r
+ MOV DX,[DI] ; get length of best guy\r
+ SUB DX,COLUMN ; adjust length for column\r
+ JA DXOK ; there are more chars after column\r
+ MOV DI,SPACE ; point air to a space\r
+ MOV DX,MAXREC ; really big record\r
+DXOK:\r
+ MOV CX,AX ; AX is shortest record\r
+ CMP AX,DX ; perhaps DX is shorter\r
+ JB SMALL ; nope, leace CX alone\r
+ MOV CX,DX ; DX is shorter, put length in CX\r
+SMALL:\r
+ ADD DI,COLUMN ; offset into record\r
+ ADD SI,COLUMN ; offset into other record\r
+if not internat\r
+ REPZ CMPSB ; compare every one\r
+ endif\r
+if internat\r
+ push bx\r
+ push ax\r
+ mov bx,offset dg:table\r
+tloop: lodsb\r
+ xlat byte ptr cs:[bx]\r
+ mov ah,al\r
+ mov al,es:[di]\r
+ inc di\r
+ xlat byte ptr cs:[bx]\r
+ cmp ah,al\r
+ loopz tloop\r
+ pop ax\r
+ pop bx\r
+ endif\r
+ restore <DI,SI> ; get head pointers back\r
+ JNZ TESTED_NOT_EQUAL ; didn't exhaust counter, conditions set\r
+ CMP AX,DX ; check string lengths\r
+TESTED_NOT_EQUAL:\r
+;\r
+; note! jae is patched to a jbe if file is to be sorted in reverse!\r
+;\r
+CODE_PATCH LABEL BYTE\r
+ JAE INNER_SORT_LOOP ; if this one wasn't better then go again\r
+ MOV BX,SI ; it was better, save header\r
+ JMP INNER_SORT_LOOP ; and scan again\r
+\r
+END_INNER_SORT_LOOP:\r
+ MOV SI,BX ; SI is now the best person\r
+ CMP SI,DI ; check best for current\r
+ JZ END_INSERT ; best equals current, all done\r
+\r
+;\r
+; SI points to best line found so far\r
+; DI points to a place to insert this line\r
+; DI is guaranteed to be < SI\r
+; make room for line at destination\r
+;\r
+ MOV DX,[SI] ; get length of line\r
+ save <SI,DI> ; save positions of people\r
+ STD ; go right to left\r
+ MOV CX,BP ; get end of file pointer\r
+ SUB CX,DI ; get length from destination to end\r
+ MOV SI,BP ; start from end\r
+ DEC SI ; SI points to end of file\r
+ MOV DI,SI ; destination is end of file\r
+ ADD DI,DX ; DI points to new end of file\r
+ REP MOVSB ; blam. Move every one up\r
+ CLD ; back left to right\r
+ restore <DI,SI> ; get old source and destination\r
+;\r
+; MOVE NEW LINE INTO PLACE\r
+;\r
+ save <DI> ; save destination\r
+ ADD SI,DX ; adjust for previous movement\r
+ save <SI> ; save this value\r
+ MOV CX,DX ; get number to move\r
+ REP MOVSB ; blam. move the new line in\r
+ restore <SI,DI> ; get back destination and new source\r
+;\r
+; DELETE LINE FROM OLD PLACE\r
+;\r
+ save <DI> ; save destination\r
+ MOV CX,BP ; pointer to end\r
+ ADD CX,DX ; remember bump\r
+ SUB CX,SI ; get count of bytes to move\r
+ INC CX ; turn it into a word\r
+ SHR CX,1 ; or a count of words\r
+ MOV DI,SI ; new destination of move\r
+ ADD SI,DX ; offset of block\r
+ REP MOVSW ; blam, squeeze out the space\r
+ restore <DI> ; get back original destination\r
+ MOV WORD PTR DS:[BP-2],0 ; remake the end of file mark\r
+\r
+END_INSERT:\r
+ ADD DI,[DI] ; link to next guy\r
+ JMP OUTER_SORT_LOOP ; and continue\r
+;\r
+; PUT BACK IN THE CR-LF\r
+;\r
+END_OUTER_SORT_LOOP:\r
+ MOV DI,BUFFER ; start at beginning (where else)\r
+ MOV CX,[DI] ; count of butes\r
+\r
+INSERT_LOOP:\r
+ ADD DI,CX ; point to next length\r
+ MOV CX,[DI] ; get length\r
+ MOV WORD PTR [DI],0A0DH ; replace length with CRLF\r
+ CMP CX,0 ; check for end of file\r
+ JNZ INSERT_LOOP ; nope, try again\r
+\r
+WRITE_FILE:\r
+ MOV DX,BUFFER+2 ; get starting point\r
+ MOV CX,BP ; pointer to end of buffer\r
+ SUB CX,DX ; dif in pointers is number of bytes\r
+ MOV BX,1 ; to standard output\r
+ sys WRITE ; write 'em out\r
+ JC BADWRT ; some bizarre error -> flag it\r
+ CMP AX,CX ; did we write what was expected?\r
+ JZ WRTOK ; yes, say bye bye\r
+BADWRT:\r
+ MOV SI,OFFSET dg:ERRMSG2 ; strange write error\r
+ JMP ERROR_EXIT ; bye bye\r
+WRTOK:\r
+ XOR AL,AL ; perfect return (by convention)\r
+ sys EXIT ; bye!\r
+\r
+CODE ENDS\r
+\r
+CONST SEGMENT PUBLIC BYTE\r
+ EXTRN BADVER:BYTE,ERRMSG:BYTE,ERRMSG2:BYTE\r
+if internat\r
+ extrn table:byte\r
+ endif\r
+CONST ENDS\r
+\r
+SUBTTL Initialized Data\r
+PAGE\r
+CSTACK SEGMENT STACK\r
+ DB 96 dup (0)\r
+CSTACK ENDS\r
+\r
+ END SORT\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\r
+\r
+\1a
\ No newline at end of file
--- /dev/null
+;
+; Standard FCB calls for MSDOS (first 12 function calls)
+;
+
+.xlist
+.xcref
+INCLUDE STDSW.ASM
+.cref
+.list
+
+TITLE STDFCB - FCB calls for MSDOS
+NAME STDFCB
+
+INCLUDE FCB.ASM
+
+\1a
\ No newline at end of file
--- /dev/null
+;
+; Standard device IO for MSDOS (first 12 function calls)
+;
+
+.xlist
+.xcref
+INCLUDE STDSW.ASM
+INCLUDE DOSSEG.ASM
+.cref
+.list
+
+TITLE STDIO - device IO for MSDOS
+NAME STDIO
+
+INCLUDE IO.ASM
+
+\1a
\ No newline at end of file
--- /dev/null
+;
+; Pseudo EXEC system call for MSDOS
+;
+
+.xlist
+.xcref
+INCLUDE STDSW.ASM
+.cref
+.list
+
+TITLE STDPROC - process maintenance for MSDOS
+NAME STDPROC
+
+INCLUDE PROC.ASM
+
+\1a
\ No newline at end of file
--- /dev/null
+TRUE EQU 0FFFFH\r
+FALSE EQU NOT TRUE\r
+\r
+; Use the switches below to produce the standard Microsoft version or the IBM\r
+; version of the operating system\r
+MSVER EQU false\r
+IBM EQU true\r
+WANG EQU FALSE\r
+ALTVECT EQU FALSE\r
+\r
+; Set this switch to cause DOS to move itself to the end of memory\r
+HIGHMEM EQU FALSE\r
+\r
+ IF IBM\r
+ESCCH EQU 0 ; character to begin escape seq.\r
+CANCEL EQU 27\r
+TOGLINS EQU TRUE ;One key toggles insert mode\r
+TOGLPRN EQU TRUE ;One key toggles printer echo\r
+ZEROEXT EQU TRUE\r
+ ELSE\r
+ IF WANG ;Are we assembling for WANG?\r
+ESCCH EQU 1FH ;Yes. Use 1FH for escape character\r
+ ELSE\r
+ESCCH EQU 1BH\r
+ ENDIF\r
+CANCEL EQU "X"-"@" ;Cancel with Ctrl-X\r
+TOGLINS EQU WANG ;Separate keys for insert mode on\r
+ ;and off if not WANG\r
+TOGLPRN EQU FALSE ;Separate keys for printer echo on\r
+ ;and off\r
+ZEROEXT EQU TRUE\r
+ ENDIF\r
+\r
+\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a
\ No newline at end of file
--- /dev/null
+ procedure $STD_CON_STRING_INPUT,NEAR ;System call 10
+ASSUME DS:NOTHING,ES:NOTHING
+
+; Inputs:
+; DS:DX Point to an input buffer
+; Function:
+; Fill buffer from console input until CR
+; Returns:
+; None
+
+ MOV AX,SS
+ MOV ES,AX
+ MOV SI,DX
+ XOR CH,CH
+ LODSW
+ OR AL,AL
+ retz ;Buffer is 0 length!!?
+ MOV BL,AH ;Init template counter
+ MOV BH,CH ;Init template counter
+ CMP AL,BL
+ JBE NOEDIT ;If length of buffer inconsistent with contents
+ CMP BYTE PTR [BX+SI],c_CR
+ JZ EDITON ;If CR correctly placed EDIT is OK
+NOEDIT:
+ MOV BL,CH ;Reset buffer
+EDITON:
+ MOV DL,AL
+ DEC DX ;DL is # of bytes we can put in the buffer
+NEWLIN:
+ MOV AL,[CARPOS]
+ MOV [STARTPOS],AL ;Remember position in raw buffer
+ PUSH SI
+ MOV DI,OFFSET DOSGROUP:INBUF ;Build the new line here
+ MOV [INSMODE],CH ;Insert mode off
+ MOV BH,CH ;No chars from template yet
+ MOV DH,CH ;No chars to new line yet
+ invoke $STD_CON_INPUT_NO_ECHO ;Get first char
+ CMP AL,c_LF ;Linefeed
+ JNZ GOTCH ;Filter out LF so < works
+ entry GETCH
+ invoke $STD_CON_INPUT_NO_ECHO
+GOTCH:
+ CMP AL,"F"-"@" ;Ignore ^F
+ JZ GETCH
+ CMP AL,[ESCCHAR]
+ JZ ESC
+ CMP AL,c_DEL
+ JZ BACKSPJ
+ CMP AL,c_BS
+ JZ BACKSPJ
+ CMP AL,c_CR
+ JZ ENDLIN
+ CMP AL,c_LF
+ JZ PHYCRLF
+ CMP AL,CANCEL
+ JZ KILNEW
+SAVCH:
+ CMP DH,DL
+ JAE BUFFUL ;No room
+ STOSB
+ INC DH ;Got a char
+ invoke BUFOUT ;Print control chars nicely
+ CMP BYTE PTR [INSMODE],0
+ JNZ GETCH ;In insert mode, get more chars
+ CMP BH,BL
+ JAE GETCH ;We are out of chars in template
+ INC SI ;Skip to next char in template
+ INC BH
+ JMP SHORT GETCH
+
+BACKSPJ: JMP SHORT BACKSP
+
+BUFFUL:
+ MOV AL,7 ;Bell
+ invoke OUT
+ JMP SHORT GETCH
+
+ESC:
+ transfer OEMFunctionKey
+
+ENDLIN:
+ STOSB ;Put the CR in the buffer
+ invoke OUT ;Echo it
+ POP DI ;Get start of buffer
+ MOV [DI-1],DH ;Tell user how many bytes
+ INC DH ;DH is length including CR
+COPYNEW:
+ MOV BP,ES ;XCHG ES,DS
+ MOV BX,DS
+ MOV ES,BX
+ MOV DS,BP
+ MOV SI,OFFSET DOSGROUP:INBUF
+ MOV CL,DH
+ REP MOVSB ;Copy final line to user buffer
+ return ;All done
+
+;Output a CRLF
+ entry CRLF
+ MOV AL,c_CR
+ invoke OUT
+ MOV AL,c_LF
+ JMP OUT
+
+;Output a CRLF which is not terminate buffer
+PHYCRLF:
+ invoke CRLF
+ JMP GETCH
+
+;Zap the line without zapping the template
+ entry KILNEW
+ MOV AL,"\"
+ invoke OUT ;Print the CANCEL indicator
+ POP SI ;Remember start of edit buffer
+PUTNEW:
+ invoke CRLF ;Go to next line on screen
+ MOV AL,[STARTPOS]
+ invoke TAB ;Tab over
+ JMP NEWLIN ;Start over again
+
+;Back up one char
+ entry BACKSP
+ OR DH,DH
+ JZ OLDBAK ;No chars in line, do nothing to line
+ CALL BACKUP ;Do the backup
+ MOV AL,ES:[DI] ;Get the deleted char
+ CMP AL," "
+ JAE OLDBAK ;Was a normal char
+ CMP AL,c_HT
+ JZ BAKTAB ;Was a tab, fix up users display
+ CALL BACKMES ;Was a control char, zap the '^'
+OLDBAK:
+ CMP BYTE PTR [INSMODE],0
+ JNZ GETCH1 ;In insert mode, get more chars
+ OR BH,BH
+ JZ GETCH1 ;Not advanced in template, stay where we are
+ DEC BH ;Go back in template
+ DEC SI
+GETCH1:
+ JMP GETCH
+
+BAKTAB:
+ PUSH DI
+ DEC DI ;Back up one char
+ STD ;Go backward
+ MOV CL,DH ;Number of chars currently in line
+ MOV AL," "
+ PUSH BX
+ MOV BL,7 ;Max
+ JCXZ FIGTAB ;At start, do nothing
+FNDPOS:
+ SCASB ;Look back
+ JNA CHKCNT
+ CMP BYTE PTR ES:[DI+1],9
+ JZ HAVTAB ;Found a tab
+ DEC BL ;Back one char if non tab control char
+CHKCNT:
+ LOOP FNDPOS
+FIGTAB:
+ SUB BL,[STARTPOS]
+HAVTAB:
+ SUB BL,DH
+ ADD CL,BL
+ AND CL,7 ;CX has correct number to erase
+ CLD ;Back to normal
+ POP BX
+ POP DI
+ JZ OLDBAK ;Nothing to erase
+TABBAK:
+ invoke BACKMES
+ LOOP TABBAK ;Erase correct number of chars
+ JMP SHORT OLDBAK
+
+BACKUP:
+ DEC DH ;Back up in line
+ DEC DI
+BACKMES:
+ MOV AL,c_BS ;Backspace
+ invoke OUT
+ MOV AL," " ;Erase
+ invoke OUT
+ MOV AL,c_BS ;Backspace
+ JMP OUT ;Done
+
+;User really wants an ESC character in his line
+ entry TwoEsc
+ MOV AL,[ESCCHAR]
+ JMP SAVCH
+
+;Copy the rest of the template
+ entry COPYLIN
+ MOV CL,BL ;Total size of template
+ SUB CL,BH ;Minus position in template, is number to move
+ JMP SHORT COPYEACH
+
+ entry CopyStr
+ invoke FINDOLD ;Find the char
+ JMP SHORT COPYEACH ;Copy up to it
+
+;Copy one char from template to line
+ entry COPYONE
+ MOV CL,1
+;Copy CX chars from template to line
+COPYEACH:
+ MOV BYTE PTR [INSMODE],0 ;All copies turn off insert mode
+ CMP DH,DL
+ JZ GETCH2 ;At end of line, can't do anything
+ CMP BH,BL
+ JZ GETCH2 ;At end of template, can't do anything
+ LODSB
+ STOSB
+ invoke BUFOUT
+ INC BH ;Ahead in template
+ INC DH ;Ahead in line
+ LOOP COPYEACH
+GETCH2:
+ JMP GETCH
+
+;Skip one char in template
+ entry SKIPONE
+ CMP BH,BL
+ JZ GETCH2 ;At end of template
+ INC BH ;Ahead in template
+ INC SI
+ JMP GETCH
+
+ entry SKIPSTR
+ invoke FINDOLD ;Find out how far to go
+ ADD SI,CX ;Go there
+ ADD BH,CL
+ JMP GETCH
+
+;Get the next user char, and look ahead in template for a match
+;CX indicates how many chars to skip to get there on output
+;NOTE: WARNING: If the operation cannot be done, the return
+; address is popped off and a jump to GETCH is taken.
+; Make sure nothing extra on stack when this routine
+; is called!!! (no PUSHes before calling it).
+FINDOLD:
+ invoke $STD_CON_INPUT_NO_ECHO
+ CMP AL,[ESCCHAR] ; did he type a function key?
+ JNZ FindSetup ; no, set up for scan
+ invoke $STD_CON_INPUT_NO_ECHO ; eat next char
+ JMP NotFnd ; go try again
+FindSetup:
+ MOV CL,BL
+ SUB CL,BH ;CX is number of chars to end of template
+ JZ NOTFND ;At end of template
+ DEC CX ;Cannot point past end, limit search
+ JZ NOTFND ;If only one char in template, forget it
+ PUSH ES
+ PUSH DS
+ POP ES
+ PUSH DI
+ MOV DI,SI ;Template to ES:DI
+ INC DI
+ REPNE SCASB ;Look
+ POP DI
+ POP ES
+ JNZ NOTFND ;Didn't find the char
+ NOT CL ;Turn how far to go into how far we went
+ ADD CL,BL ;Add size of template
+ SUB CL,BH ;Subtract current pos, result distance to skip
+ return
+
+NOTFND:
+ POP BP ;Chuck return address
+ JMP GETCH
+
+ entry REEDIT
+ MOV AL,"@" ;Output re-edit character
+ invoke OUT
+ POP DI
+ PUSH DI
+ PUSH ES
+ PUSH DS
+ invoke COPYNEW ;Copy current line into template
+ POP DS
+ POP ES
+ POP SI
+ MOV BL,DH ;Size of line is new size template
+ JMP PUTNEW ;Start over again
+
+ entry EXITINS
+ entry ENTERINS
+ NOT BYTE PTR [INSMODE]
+ JMP GETCH
+
+;Put a real live ^Z in the buffer (embedded)
+ entry CTRLZ
+ MOV AL,"Z"-"@"
+ JMP SAVCH
+$STD_CON_STRING_INPUT ENDP
--- /dev/null
+TITLE MS-DOS SYS Program\r
+; SYS - Copies system programs IBMBIO.COM/IO.SYS and IBMDOS.COM/MSDOS.SYS\r
+; 1.6 05/21/82 Added rev number message\r
+; 1.61 06/04/82 Allow SYS to blank disk TimP at SCP\r
+; 1.70 06/30/82 NON contiguous DOS allowed on 2.00 IBM. Allows SYS to\r
+; 1.0 1.1 disks.\r
+; 1.71 07/02/82 Put in CHDIRs to make sure everything done in root dir.\r
+; 1.80 04/26/83 MZ make sys work in small machines; use full 2.0 system\r
+; calls\r
+; 1.81 07/22/83 ARR Added check in IBM version for valid FAT ID on\r
+; destination because of IBM problem with SYSing to\r
+; unformatted disks which are really formatted.\r
+; Prints NoDest message for ridic IBM reasons, should\r
+; have a better message.\r
+\r
+FALSE EQU 0\r
+TRUE EQU NOT FALSE\r
+\r
+IBMJAPVER EQU FALSE\r
+IBMVER EQU FALSE\r
+MSVER EQU TRUE\r
+\r
+.xlist\r
+.xcref\r
+ INCLUDE DOSSYM.ASM\r
+.cref\r
+.list\r
+\r
+\r
+DOSVER_LOW EQU 0136H ; Lowest acceptable DOS version number\r
+DOSVER_HIGH EQU 020BH ; Highest acceptable DOS version\r
+\r
+CODE SEGMENT WORD PUBLIC\r
+CODE ENDS\r
+\r
+CONST SEGMENT BYTE PUBLIC\r
+CONST ENDS\r
+\r
+DATA SEGMENT BYTE PUBLIC\r
+DATA ENDS\r
+\r
+DG GROUP CODE,DATA,CONST\r
+\r
+DATA SEGMENT PUBLIC BYTE\r
+\r
+ EXTRN BADDRV:BYTE, BADDRVLen:WORD\r
+ EXTRN BADPARM:BYTE, BADPARMLen:WORD\r
+ EXTRN GETSYS:BYTE, GETSYSLen:WORD\r
+ EXTRN SYSDRV:BYTE\r
+ EXTRN NODEST:BYTE, NODESTLen:WORD\r
+ EXTRN BADSIZ:BYTE, BADSIZLen:WORD\r
+ EXTRN DONE:BYTE, DONELen:WORD\r
+ EXTRN BADVER:BYTE\r
+\r
+ IF IBMJAPVER\r
+ EXTRN BADDISK:BYTE, BADDISKLen:WORD\r
+ ENDIF\r
+\r
+DEFALT DB 0\r
+ IF MSVER\r
+BIOSName DB "A:\IO.SYS",0\r
+DOSName DB "A:\MSDOS.SYS",0\r
+ ENDIF\r
+ IF IBMVER OR IBMJAPVER\r
+BIOSName DB "A:\IBMBIO.COM",0\r
+DOSName DB "A:\IBMDOS.COM",0\r
+ ENDIF\r
+\r
+BIOSInFH DW ? ; file handle of source BIOS\r
+BIOSLenLow DW 2 DUP (?) ; 32-bit length of BIOS\r
+BIOSLenHigh DW 2 DUP (?) ; 32-bit length of BIOS\r
+BIOSTime DW 2 DUP (?) ; place to store time of BIOS write\r
+BIOSOutFH DW ? ; fh of BIOS destination\r
+\r
+DOSInFH DW ? ; file handle of source DOS\r
+DOSLenLow DW 2 DUP (?) ; 32-bit length of DOS\r
+DOSLenHigh DW 2 DUP (?) ; 32-bit length of DOS\r
+DOSTime DW 2 DUP (?) ; place to store time of DOS write\r
+DOSOutFH DW ? ; fh of DOS destination\r
+\r
+AllName DB "A:\*.*",0\r
+\r
+cbBuf DW ? ; number of bytes in buffer\r
+pDOS DW ? ; offset of beginning of DOS in buffer\r
+pDOSEnd DW ? ; offset of end of DOS in buffer\r
+\r
+ IF IBMVER OR IBMJAPVER\r
+BOOT DW 256 DUP (0)\r
+ IF IBMJAPVER\r
+LLISTBUF DW 256 DUP (0)\r
+ ENDIF\r
+ ENDIF\r
+\r
+ IF IBMJAPVER\r
+RELOC DW 1 DUP(?)\r
+STARTSECTOR DW 1 DUP(?)\r
+ ENDIF\r
+\r
+BUF LABEL BYTE ; beginning of area for file reads\r
+\r
+DATA ENDS\r
+\r
+CODE SEGMENT PUBLIC\r
+\r
+ ASSUME CS:DG,DS:DG,ES:DG,SS:DG\r
+\r
+ ORG 100H\r
+\r
+Start:\r
+ JMP SHORT CheckVersion\r
+\r
+ IF IBMVER\r
+ DW OFFSET DG:BOOT\r
+ ENDIF\r
+HEADER DB "Vers 1.81"\r
+CheckVersion:\r
+ PUSH AX ; save drive letter validity\r
+ MOV AH,GET_VERSION\r
+ INT 21H ; get dos version\r
+ XCHG AH,AL ; Turn it around to AH.AL\r
+ CMP AX,DOSVER_LOW ; is it too low?\r
+ JB GOTBADDOS ; yes, error\r
+ CMP AX,DOSVER_HIGH ; too high?\r
+ JBE OKDOS ; yes, go check drive letter\r
+GOTBADDOS:\r
+ MOV DX,OFFSET DG:BADVER ; message to dump\r
+ MOV AH,STD_CON_STRING_OUTPUT ; standard output device\r
+ INT 21H\r
+ INT 20H ; old style exit for compatability\r
+\r
+OKDOS: POP AX ; get drive validity\r
+ JMP SHORT SYS ; go process\r
+\r
+ERR0: MOV DX,OFFSET DG:BADPARM ; no drive letter\r
+ MOV CX,BadParmLen\r
+ JMP DisplayError\r
+\r
+ERR1: MOV DX,OFFSET DG:BADDRV ; drive letter invalid\r
+ MOV CX,BadDrvLen\r
+ JMP DisplayError\r
+\r
+ERR2: MOV AL,DEFALT ; get default drive number\r
+ ADD AL,'A'-1 ; turn into letter\r
+ MOV SYSDRV,AL ; place into middle of message\r
+ MOV DX,OFFSET DG:GETSYS\r
+ MOV CX,GETSYSLen ; length for output\r
+ MOV BX,stderr ; use stderr\r
+ MOV AH,Write ; Ask for system disk\r
+ INT 21H\r
+ CALL GetKeystroke ; wait for him to type simething\r
+ XOR AL,AL ; valid drive spec now...\r
+SYS:\r
+ CMP DS:(BYTE PTR 5DH)," " ; Was file specified?\r
+ JNZ ERR0 ; yes, no files are allowed -> error\r
+ CMP AL,-1 ; Invalid drive spec?\r
+ JZ ERR1 ; yes, must have valid drive -> error\r
+ CMP DS:(BYTE PTR 5CH),0 ; No drive specified?\r
+ JZ ERR1 ; yes, cannot sys to default drive error\r
+ MOV AH,GET_DEFAULT_DRIVE ; Get default drive\r
+ INT 21H\r
+ INC AL ; turn from phys drive to logical drive\r
+ MOV DEFALT,AL ; save it for possible printing\r
+ CMP DS:(BYTE PTR 5CH),AL ; did he specify the default drive?\r
+ JZ ERR1 ; yes, default drive not allowed\r
+\r
+ IF IBMVER ; Check for "valid" destination\r
+ PUSH AX\r
+ MOV AL,BYTE PTR DS:[5Ch]\r
+ DEC AL\r
+ MOV BX,OFFSET DG:BUF ; Temp space\r
+ MOV DX,1 ; Sector 1 (first sec of FAT)\r
+ MOV CX,DX ; One sector\r
+ INT 25H ; Read Fat sector\r
+ POP AX ; Flags\r
+ POP AX ; Real AX\r
+ JC OKFAT ; Don't error here, let a CREATE or\r
+ ; some other call to the dest\r
+ ; generate a more useful INT 24H\r
+ ; error\r
+ CMP BYTE PTR [BUF],0F8H\r
+ JAE OKFAT\r
+ JMP ERR3\r
+OKFAT:\r
+ ENDIF\r
+\r
+ ADD AL,'A'-1 ; turn into letter\r
+ MOV BIOSName,AL ; twiddle source name\r
+ MOV DOSName,AL ; twiddle source name\r
+ CLD\r
+ MOV DX,OFFSET DG:BIOSName ; source name\r
+ MOV DI,OFFSET DG:BIOSInFH ; pointer to block of data\r
+ CALL OpenFile\r
+ JC Err2 ; not found, go and try again\r
+ MOV DX,OFFSET DG:DOSName ; source of DOS\r
+ MOV DI,OFFSET DG:DOSInFH ; pointer to block of data\r
+ CALL OpenFile ; Look for DOS\r
+ JC ERR2 ; not there, go ask for a system disk\r
+ MOV CX,SP ; get lowest available spot\r
+ SUB CX,0200h+(OFFSET DG:BUF); leave room for all sorts of things\r
+ MOV cbBuf,CX ; store length away\r
+ CALL FillMem ; load up memory with files\r
+\r
+ IF IBMJAPVER\r
+ CALL READ_BOOT ; need to copy boot sector too\r
+ ENDIF\r
+\r
+ MOV AL,DS:(BYTE PTR 5CH) ; get drive of destination\r
+\r
+ IF IBMJAPVER\r
+ CALL CHECK_TRAN ; check for bootable device\r
+ JZ DOSWRT ; ok to boot\r
+ MOV DX,OFFSET DG:BADDISK ; incorrect format to boot\r
+ MOV CX,BadDiskLen\r
+ JMP DisplayError ; go error and quit\r
+DOSWRT:\r
+ ENDIF\r
+\r
+ ADD AL,'A'-1 ; convert to letter\r
+ MOV BIOSName,AL ; point names at destination drive\r
+ MOV DOSName,AL\r
+ MOV AllName,AL ; look for any files\r
+\r
+ MOV AH,Find_First ; look for files\r
+ MOV DX,OFFSET DG:AllName ; path of where to look\r
+ MOV CX,Attr_Hidden+Attr_System ; attributes to find\r
+ INT 21H\r
+ JC PutSys ; no files - go and copy\r
+\r
+ IF MSVER\r
+ MOV DL,DS:(BYTE PTR 5CH) ; get drive number\r
+ MOV AH,GET_DRIVE_FREESPACE ; get free space available\r
+ INT 21H\r
+ MUL CX ; Compute size of cluster (secsiz*secperclus)\r
+ XCHG CX,AX ; move it to correct spot\r
+ MOV DX,OFFSET DG:BIOSName ; who to open\r
+ MOV AX,BIOSLenLow+2 ; get low part of size\r
+ MOV BX,BIOSLenHigh+2 ; get high size\r
+ CALL CHKLEN ; open and snoop size\r
+ JNZ ERR4 ; Must fit exact so MSDOS is in right place\r
+ MOV DX,OFFSET DG:DOSName ; other guy to open\r
+ MOV AX,DOSLenLow+2 ; get low part of size\r
+ MOV BX,DOSLenHigh+2 ; get high size\r
+ CALL CHKLEN ; open and snoop second size\r
+ JA ERR4 ; Must be enough (or too much) space\r
+ ENDIF\r
+\r
+ IF IBMVER OR IBMJAPVER\r
+ MOV DX,OFFSET DG:BIOSName ; open BIOS\r
+ MOV CX,7 ; attributes\r
+ MOV AH,Find_First\r
+ INT 21H\r
+ JNC FindDos\r
+Err3J: JMP Err3 ; not found, go and complain\r
+FindDos:\r
+ MOV DX,OFFSET DG:DOSName ; open DOS\r
+ MOV AH,Find_First\r
+ INT 21H\r
+ JC Err3J ; Not found, go complain\r
+ ENDIF\r
+\r
+PUTSYS:\r
+ MOV DX,OFFSET DG:BIOSName ; who to change mode\r
+ MOV CX,0 ; undo attributes\r
+ MOV AX,(ChMod SHL 8) + 1 ; set the attributes\r
+ INT 21h\r
+ MOV DX,OFFSET DG:DOSName ; who to change mode\r
+ MOV CX,0 ; undo attributes\r
+ MOV AX,(ChMod SHL 8) + 1 ; set the attributes\r
+ INT 21h\r
+ MOV DX,OFFSET DG:BIOSName ; destination of BIOS\r
+ MOV CX,7 ; fancy attributes\r
+ MOV AH,Creat ; make a new one\r
+ INT 21h\r
+ MOV BIOSOutFH,AX ; save handle\r
+ MOV DX,OFFSET DG:DOSName ; destination of DOS\r
+ MOV AH,Creat ; make a new one\r
+ INT 21h\r
+ MOV DOSOutFH,AX ; save handle\r
+Copy:\r
+ CALL DumpMem ; flush out memory\r
+ MOV AX,DOSLenHigh ; more DOS?\r
+ OR AX,DOSLenLow ; more low dos\r
+ OR AX,BIOSLenHigh ; more high BIOS\r
+ OR AX,BIOSLenLow ; more low BIOS\r
+ JZ AllDone ; nope, all done\r
+ CALL FillMem ; reload world\r
+ JMP Copy\r
+ERR4:\r
+ MOV DX,OFFSET DG:BADSIZ\r
+ MOV CX,BadSizLen\r
+ JMP DisplayError\r
+AllDone:\r
+ MOV CX,BIOSTime ; get time and date\r
+ MOV DX,BIOSTime+2\r
+ MOV BX,BIOSOutFH ; where to stuff the time\r
+ MOV AX,(File_Times SHL 8) + 1\r
+ INT 21h\r
+ MOV AH,Close\r
+ INT 21h\r
+\r
+ MOV CX,DOSTime ; get time and date\r
+ MOV DX,DOSTime+2\r
+ MOV BX,DOSOutFH ; where to stuff the time\r
+ MOV AX,(File_Times SHL 8) + 1\r
+ INT 21h\r
+ MOV AH,Close\r
+ INT 21h\r
+\r
+ IF IBMVER OR IBMJAPVER\r
+ CALL PUTBOOT ; copy the boot sector also\r
+ ENDIF\r
+\r
+ MOV DX,OFFSET DG:DONE ; all finished message\r
+ MOV CX,DoneLen\r
+ XOR AL,AL ; ok error code\r
+SERROR:\r
+ PUSH AX\r
+ MOV BX,stderr\r
+ MOV AH,Write ; convenient place to display message\r
+ INT 21H\r
+ POP AX\r
+ErrorExit:\r
+ MOV AH,EXIT ; bye and return error code\r
+ INT 21h\r
+\r
+DisplayError:\r
+ MOV AL,1\r
+ JMP SERROR\r
+FillMem:\r
+ MOV CX,cbBuf ; get length of buffer\r
+ MOV BX,BIOSInFH ; get bios source handle\r
+ MOV DX,OFFSET DG:BUF ; point to beginning of buffer\r
+ PUSH CX ; save away total length\r
+ CMP BIOSLenHigh,0 ; > 64K to read?\r
+ JA UseCX ; use CX\r
+ CMP BIOSLenLow,CX ; more left to read?\r
+ JA UseCX ; use CX\r
+ MOV CX,BIOSLenLow ; move new\r
+UseCX:\r
+ MOV AH,Read\r
+ INT 21h ; read in what we can\r
+ ADD DX,AX ; update pointer for DOS Read\r
+ MOV pDOS,DX ; point to beginning of DOS\r
+ SUB BIOSLenLow,AX ; decrement remaining\r
+ SBB BIOSLenHigh,0 ; do 32 bit\r
+ POP CX ; get original length\r
+ SUB CX,AX ; this much is left\r
+\r
+ MOV BX,DOSInFH ; get bios source handle\r
+ CMP DOSLenHigh,0 ; > 64K to read?\r
+ JA UseCXDOS ; use CX\r
+ CMP DOSLenLow,CX ; more left to read?\r
+ JA UseCXDOS ; use CX\r
+ MOV CX,DOSLenLow ; move new\r
+UseCXDOS:\r
+ MOV AH,Read\r
+ INT 21h ; read in what we can\r
+ ADD DX,AX ; update pointer for DOS Read\r
+ MOV pDOSEnd,DX ; point to End of dos DOS\r
+ SUB DOSLenLow,AX ; decrement remaining\r
+ SBB DOSLenHigh,0 ; do 32 bit arithmetic\r
+ return\r
+\r
+OpenFile:\r
+ MOV AX,(OPEN SHL 8) + 0 ; open for reading only\r
+ INT 21H ; Look for BIOS\r
+ retc ; not found, go and try again\r
+ STOSW ; stash away handle\r
+ MOV BX,AX ; get ready for seeks\r
+ MOV AX,(LSeek SHL 8) + 2 ; seek relative to eof\r
+ XOR CX,CX ; zero offset\r
+ XOR DX,DX ; zero offset\r
+ INT 21h ; get offsets\r
+ STOSW ; save low part of size\r
+ STOSW ; save low part of size\r
+ MOV AX,DX\r
+ STOSW ; save high part of size\r
+ STOSW ; save high part of size\r
+ XOR DX,DX ; zero offset\r
+ MOV AX,(LSeek SHL 8) + 0 ; seek relative to beginning\r
+ INT 21h\r
+ MOV AX,(File_Times SHL 8) + 0\r
+ INT 21h ; get last write times\r
+ MOV AX,CX\r
+ STOSW ; save time\r
+ MOV AX,DX\r
+ STOSW ; save date\r
+ return\r
+\r
+ERR3:\r
+ MOV DX,OFFSET DG:NODEST\r
+ MOV CX,NoDestLen\r
+ JMP DisplayError\r
+\r
+DumpMem:\r
+ MOV DX,OFFSET DG:BUF ; get offset of bios start\r
+ MOV CX,pDOS ; beginning of next guy\r
+ SUB CX,DX ; difference is length\r
+ JZ DumpDos ; no bios to move\r
+ MOV BX,BIOSOutFH ; where to output\r
+ MOV AH,Write\r
+ INT 21h ; wham\r
+DumpDos:\r
+ MOV DX,pDOS ; beginning of dos\r
+ MOV CX,pDOSEnd ; end of dos\r
+ SUB CX,DX ; difference is length\r
+ retz ; if zero no write\r
+ MOV BX,DOSOutFH ; where to output\r
+ MOV AH,Write\r
+ INT 21h ; wham\r
+ ret\r
+\r
+ IF MSVER\r
+CHKLEN:\r
+; CX has size of cluster, DX has pointer to file name\r
+; Returns with flags set on (size of file) - (size of hole)\r
+ PUSH AX ; old size low\r
+ PUSH BX ; old size high\r
+ PUSH CX ; old cluster size\r
+ MOV AH,Find_First\r
+ MOV CX,7 ; attributes to search for\r
+ INT 21H\r
+ JC ERR3 ; cannot find file, error\r
+ POP CX ; get cluster size back\r
+ MOV DX,DS:[80h+find_buf_size_h] ; get destination size high\r
+ MOV AX,DS:[80h+find_buf_size_l] ; get size low\r
+ ADD AX,CX ; add cluster size\r
+ ADC DX,0 ; 32 bit add\r
+ SUB AX,1 ; adding CLUSSIZE-1\r
+ SBB DX,0 ; 32 bit dec\r
+ DIV CX ; compute new cluster size\r
+ POP DX ; get old high\r
+ POP BX ; get old low\r
+ PUSH AX ; save away dividend\r
+ MOV AX,BX ; put into correct register\r
+ ADD AX,CX ; do the same as above (+CLUSSIZE-1)/CLUSSIZE\r
+ ADC DX,0 ; 32 bit add\r
+ SUB AX,1 ; adding CLUSSIZE-1\r
+ SBB DX,0 ; 32 bit dec\r
+ DIV CX ; compute old cluster size\r
+ POP DX ; get new size\r
+ CMP AX,DX ; is old >= new?\r
+ return\r
+ ENDIF\r
+\r
+ IF IBMJAPVER\r
+PUTBOOT:\r
+ CALL READ_LLIST ; Get the list sector and set new boot sector\r
+ MOV AL,DS:(BYTE PTR 5CH)\r
+ DEC AL ; A=0\r
+ MOV CX,1\r
+ XOR DX,DX\r
+ MOV BX,OFFSET DG:BOOT\r
+ INT 26H ; Write out new boot sector\r
+ POPF\r
+ CALL WRITE_LLIST ; Make and write out new list sector\r
+ RET\r
+ ENDIF\r
+\r
+ IF IBMVER\r
+PUTBOOT:\r
+ MOV AH,GET_DPB\r
+ MOV DL,BYTE PTR DS:[5Ch] ; Target drive\r
+ INT 21H\r
+ASSUME DS:NOTHING\r
+ MOV AL,[BX+16H] ; Media byte\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:DG\r
+ CMP AL,0FEH\r
+ JB RET1\r
+ TEST AL,1\r
+ JZ GOTBOOT\r
+ MOV BX,OFFSET DG:BOOT\r
+ MOV WORD PTR [BX+17],112 ; Set number of dir entries\r
+ MOV WORD PTR [BX+19],2*8*40 ; Set number of sectors\r
+ INC BYTE PTR [BX+21] ; Media = ff\r
+ INC WORD PTR [BX+26] ; Number of heads = 2\r
+\r
+GOTBOOT:\r
+ MOV AL,BYTE PTR DS:[5Ch]\r
+ DEC AL\r
+ MOV BX,OFFSET DG:BOOT ; Boot sector\r
+ XOR DX,DX ; Sector 0\r
+ MOV CX,DX\r
+ INC CX ; One sector\r
+ INT 26H ; Write out 8 sector boot sector\r
+ POP AX ; Flags\r
+RET1: RET\r
+ ENDIF\r
+\r
+ IF IBMJAPVER\r
+READ_BOOT:\r
+ MOV AL,[DEFALT]\r
+ DEC AL ; A=0\r
+ MOV CX,1\r
+ XOR DX,DX\r
+ MOV BX,OFFSET DG:BOOT\r
+ INT 25H\r
+ POPF\r
+ MOV AX,[BOOT+108H] ; Get old first sector of data\r
+ MOV [RELOC],AX\r
+ RET\r
+\r
+READ_LLIST:\r
+ MOV AL,DS:(BYTE PTR 5CH)\r
+ DEC AL ; A=0\r
+ MOV CX,1\r
+ MOV DX,[STARTSECTOR]\r
+ MOV BX,OFFSET DG:LLISTBUF\r
+ INT 25H\r
+ POPF\r
+ RET\r
+\r
+WRITE_LLIST:\r
+ MOV AX,[STARTSECTOR]\r
+ MOV DX,AX\r
+ SUB AX,[RELOC] ; True reloc factor\r
+ MOV CL,BYTE PTR [LLISTBUF+0CH] ; Number of entries needing reloc\r
+ XOR CH,CH\r
+ JCXZ NO_RELOCS\r
+ MOV BX,OFFSET DG:LLISTBUF + 10H\r
+RELLOOP:\r
+ ADD WORD PTR [BX+2],AX\r
+ ADD BX,10H\r
+ LOOP RELLOOP\r
+NO_RELOCS:\r
+ MOV AL,DS:(BYTE PTR 5CH)\r
+ DEC AL ; A=0\r
+ MOV CX,1\r
+ MOV BX,OFFSET DG:LLISTBUF\r
+ INT 26H\r
+ POPF\r
+ RET\r
+\r
+CHECK_TRAN:\r
+; All registers preserved. Returns zero if SYS OK, NZ if SYS FAIL\r
+; AL is drive (1=A,...) AL=0 is not valid\r
+\r
+ PUSH BX\r
+ PUSH AX\r
+ PUSH DS\r
+ MOV DL,AL\r
+ MOV AH,GET_DPB\r
+ INT 21H\r
+ MOV AX,[BX.dpb_first_sector] ; Get new first sector of data\r
+ MOV BH,[BX.dpb_media]\r
+ POP DS\r
+ MOV [STARTSECTOR],AX\r
+ MOV [BOOT+108H],AX ; Set new start of data in boot\r
+ POP AX\r
+ PUSH AX\r
+ MOV BL,AL\r
+ INT 11H ; IBM EQUIP CALL\r
+ ROL AL,1\r
+ ROL AL,1\r
+ AND AL,3\r
+ JNZ NOT_SINGLE\r
+ INC AL\r
+NOT_SINGLE:\r
+ INC AL ; AL is now MAX floppy #\r
+ CMP BL,AL\r
+ POP AX\r
+ JBE CHECK_FLOP ; Is a floppy\r
+ XOR BL,BL ; Is Hard file\r
+ POP BX\r
+ RET\r
+\r
+CHECK_FLOP:\r
+ CMP BH,0FBH ; Only floppy that boots\r
+ POP BX\r
+ RET\r
+ ENDIF\r
+\r
+GetKeystroke:\r
+ MOV AX,(Std_CON_Input_Flush SHL 8) + Std_CON_Input_No_Echo\r
+ INT 21H\r
+ MOV AX,(Std_CON_Input_Flush SHL 8) + 0\r
+ INT 21H\r
+\r
+ return\r
+\r
+CODE ENDS\r
+ END START\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\r
+\r
+\1a
\ No newline at end of file
--- /dev/null
+;
+; system call entry points 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 YEAR,WORD
+ i_need DAY,BYTE
+ i_need WeekDay,BYTE
+ i_need TimeBuf,6
+ i_need BCLOCK,DWORD
+ i_need DskErr,BYTE
+ i_need Attrib,BYTE
+ i_need Name1,BYTE
+ i_need Name2,BYTE
+ i_need Name3,BYTE
+ i_need DelAll,BYTE
+ i_need ThisDPB,DWORD
+ i_need CurBuf,DWORD
+ i_need LastEnt,WORD
+ i_need ThisDrv,BYTE
+ i_need DirStart,WORD
+ i_need DevPt,DWORD
+ i_need Creating,BYTE
+ i_need VolID,BYTE
+ i_need FoundDel,BYTE
+
+SUBTTL DATE AND TIME - SYSTEM CALLS 42,43,44,45; S/G DATE,TIME
+PAGE
+ procedure $GET_DATE,NEAR ;System call 42
+ASSUME DS:NOTHING,ES:NOTHING
+
+; Inputs:
+; None
+; Function:
+; Return current date
+; Returns:
+; Date in CX:DX
+
+ PUSH SS
+ POP DS
+ASSUME DS:DOSGROUP
+ invoke READTIME ;Check for rollover to next day
+ MOV AX,[YEAR]
+ MOV BX,WORD PTR [DAY]
+ invoke get_user_stack ;Get pointer to user registers
+ASSUME DS:NOTHING
+ MOV [SI.user_DX],BX ;DH=month, DL=day
+ ADD AX,1980 ;Put bias back
+ MOV [SI.user_CX],AX ;CX=year
+ MOV AL,BYTE PTR [WEEKDAY]
+ RET
+$GET_DATE ENDP
+
+ procedure $SET_DATE,NEAR ;System call 43
+ASSUME DS:NOTHING,ES:NOTHING
+
+; Inputs:
+; CX:DX valid date
+; Function:
+; Set current date
+; Returns:
+; AL = -1 date bad, = 0 OK
+
+ MOV AL,-1 ;Be ready to flag error
+ SUB CX,1980 ;Fix bias in year
+ JC RET24 ;Error if not big enough
+ CMP CX,119 ;Year must be less than 2100
+ JA RET24
+ OR DH,DH
+ JZ RET24
+ OR DL,DL
+ JZ RET24 ;Error if either month or day is 0
+ CMP DH,12 ;Check against max. month
+ JA RET24
+ PUSH SS
+ POP DS
+ASSUME DS:DOSGROUP
+ invoke DODATE
+RET24: RET
+$SET_DATE ENDP
+
+ procedure $GET_TIME,NEAR ;System call 44
+ASSUME DS:NOTHING,ES:NOTHING
+
+; Inputs:
+; None
+; Function:
+; Get current time
+; Returns:
+; Time in CX:DX
+
+ PUSH SS
+ POP DS
+ASSUME DS:DOSGROUP
+ invoke READTIME
+ invoke get_user_stack ;Get pointer to user registers
+ MOV [SI.user_DX],DX
+ MOV [SI.user_CX],CX
+ XOR AL,AL
+RET26: RET
+$GET_TIME ENDP
+
+ procedure $SET_TIME,NEAR ;System call 45
+;Time is in CX:DX in hours, minutes, seconds, 1/100 sec.
+ASSUME DS:NOTHING,ES:NOTHING
+
+; Inputs:
+; CX:DX = Time
+; Function:
+; Set time
+; Returns:
+; AL = -1 time bad, = 0 OK
+
+ MOV AL,-1 ;Flag in case of error
+ CMP CH,24 ;Check hours
+ JAE RET26
+ CMP CL,60 ;Check minutes
+ JAE RET26
+ CMP DH,60 ;Check seconds
+ JAE RET26
+ CMP DL,100 ;Check 1/100's
+ JAE RET26
+ PUSH CX
+ PUSH DX
+ PUSH SS
+ POP DS
+ASSUME DS:DOSGROUP
+ MOV BX,OFFSET DOSGROUP:TIMEBUF
+ MOV CX,6
+ XOR DX,DX
+ MOV AX,DX
+ PUSH BX
+ invoke SETREAD
+ASSUME ES:DOSGROUP
+ PUSH DS
+ LDS SI,[BCLOCK]
+ASSUME DS:NOTHING
+ invoke DEVIOCALL2 ;Get correct day count
+ POP DS
+ASSUME DS:DOSGROUP
+ POP BX
+ invoke SETWRITE
+ POP WORD PTR [TIMEBUF+4]
+ POP WORD PTR [TIMEBUF+2]
+ LDS SI,[BCLOCK]
+ASSUME DS:NOTHING
+ invoke DEVIOCALL2 ;Set the time
+ XOR AL,AL
+ RET
+$SET_TIME ENDP
+
+SUBTTL DISK R/W ROUTINES
+PAGE
+ procedure $FCB_SEQ_READ,NEAR ; System call 20
+ASSUME DS:NOTHING,ES:NOTHING
+
+; Inputs:
+; DS:DX Points to openned FCB
+; Function:
+; Read next record from file to disk transfer address
+; Returns:
+; AL = 1 EOF record is empty
+; AL = 3 EOF record is partial zero filled
+; AL = 2 No room at disk transfer address
+; AL = 0 All OK
+
+ invoke GETREC
+ invoke LOAD
+ JMP SHORT FINSEQ
+
+ entry $FCB_SEQ_WRITE ; System call 21
+ASSUME DS:NOTHING,ES:NOTHING
+
+; Inputs:
+; DS:DX Points to openned FCB
+; Function:
+; Write next record to file from disk transfer address
+; Returns:
+; AL = 1 Disk full
+; AL = 2 No room in disk transfer segment
+; AL = 0 All OK
+
+ invoke GETREC
+ invoke STORE
+FINSEQ:
+ JCXZ SETNREX
+ ADD AX,1
+ ADC DX,0
+ JMP SHORT SETNREX
+
+ entry $FCB_RANDOM_READ ; System call 33
+ASSUME DS:NOTHING,ES:NOTHING
+
+; Inputs:
+; DS:DX Points to openned FCB
+; Function:
+; Read record addressed by random record field from file to
+; disk transfer address
+; Returns:
+; AL = 1 EOF record is empty
+; AL = 3 EOF record is partial zero filled
+; AL = 2 No room at disk transfer address
+; AL = 0 All OK
+
+ invoke GETRRPOS1
+ invoke LOAD
+ JMP SHORT FINRND
+
+ entry $FCB_RANDOM_WRITE ; System call 34
+ASSUME DS:NOTHING,ES:NOTHING
+
+; Inputs:
+; DS:DX Points to openned FCB
+; Function:
+; Write record addressed by random record field to file from
+; disk transfer address
+; Returns:
+; AL = 1 Disk full
+; AL = 2 No room in disk transfer segment
+; AL = 0 All OK
+
+ invoke GETRRPOS1
+ invoke STORE
+ JMP SHORT FINRND
+
+ entry $FCB_RANDOM_READ_BLOCK ; System call 39
+ASSUME DS:NOTHING,ES:NOTHING
+
+; Inputs:
+; DS:DX Points to openned FCB
+; CX = Record count
+; Function:
+; Read CX records starting at random record field from file
+; to disk transfer address
+; Returns:
+; AL = 1 EOF record is empty
+; AL = 3 EOF record is partial zero filled
+; AL = 2 No room at disk transfer address
+; AL = 0 All OK
+; CX = Actual number of records read
+
+ invoke GETRRPOS
+ invoke LOAD
+ JMP SHORT FINBLK
+
+ entry $FCB_RANDOM_WRITE_BLOCK ; System call 40
+ASSUME DS:NOTHING,ES:NOTHING
+
+; Inputs:
+; DS:DX Points to openned FCB
+; CX = Record count
+; Function:
+; Write CX records starting at random record field to file
+; from disk transfer address
+; If CX = 0 File is set to length determined from random record field
+; Returns:
+; AL = 1 Disk full
+; AL = 2 No room in disk transfer segment
+; AL = 0 All OK
+; CX = Actual number of records written
+
+ invoke GETRRPOS
+ invoke STORE
+FINBLK:
+ invoke get_user_stack
+ MOV [SI.user_CX],CX
+ entry FINNOSAV
+ JCXZ FINRND
+ ADD AX,1
+ ADC DX,0
+FINRND:
+ MOV WORD PTR ES:[DI.fcb_RR],AX
+ MOV ES:[DI.fcb_RR+2],DL
+ OR DH,DH
+ JZ SETNREX
+ MOV ES:[DI.fcb_RR+3],DH ; Save 4 byte of RECPOS only if significant
+SETNREX:
+ MOV CX,AX
+ AND AL,7FH
+ MOV ES:[DI.fcb_NR],AL
+ AND CL,80H
+ SHL CX,1
+ RCL DX,1
+ MOV AL,CH
+ MOV AH,DL
+ MOV ES:[DI.fcb_EXTENT],AX
+ MOV AL,BYTE PTR [DSKERR]
+RET4:
+ RET
+$FCB_SEQ_READ ENDP
+
+SUBTTL $FCB_DELETE -- SYSTEM CALL 19
+PAGE
+ procedure $FCB_DELETE,NEAR ; System call 19
+ASSUME DS:NOTHING,ES:NOTHING
+
+; Inputs:
+; DS:DX point to unopened FCB
+; Function:
+; Delete all matching entries
+; Returns:
+; AL = -1 if no entries matched, otherwise 0
+
+ invoke MOVNAME
+ASSUME ES:DOSGROUP
+ MOV AL,-1
+ MOV BYTE PTR [FoundDel],AL
+ JC RET4
+ MOV AL,BYTE PTR [ATTRIB]
+ AND AL,attr_hidden+attr_system+attr_directory+attr_volume_id+attr_read_only
+ ; Look only at hidden bits
+ CMP AL,attr_hidden+attr_system+attr_directory+attr_volume_id+attr_read_only
+ ; All must be set
+ JNZ NOTALL
+ MOV CX,11
+ MOV AL,"?"
+ MOV DI,OFFSET DOSGROUP:NAME1
+ REPE SCASB ; See if name is *.*
+ JNZ NOTALL
+ MOV BYTE PTR [DELALL],0 ; DEL *.* - flag deleting all
+NOTALL:
+ invoke FINDNAME
+ASSUME DS:DOSGROUP
+ MOV AL,-1
+ JC RET4
+ OR AH,AH ; Check if device name
+ JS RET4 ; Can't delete I/O devices
+DELFILE:
+ LES BP,[THISDPB]
+ MOV AH,BYTE PTR [DELALL]
+ PUSH DS
+ LDS DI,[CURBUF]
+ASSUME DS:NOTHING
+ TEST [Attrib],attr_read_only ; are we deleting RO files too?
+ JNZ DoDelete ; yes
+ TEST DS:[BX.dir_attr],attr_read_only
+ JZ DoDelete ; not read only
+ POP DS
+ JMP SHORT DelNxt
+DoDelete:
+ MOV BYTE PTR [FoundDel],0
+ MOV [DI.BUFDIRTY],1
+ MOV BYTE PTR [BX],AH
+ MOV BX,[SI]
+ POP DS
+ASSUME DS:DOSGROUP
+ OR BX,BX
+ JZ DELNXT
+ CMP BX,ES:[BP.dpb_max_cluster]
+ JA DELNXT
+ invoke RELEASE
+DELNXT:
+ invoke GETENTRY ; Registers need to be reset
+ invoke NEXTENT
+ JNC DELFILE
+ CALL FLUSHRET1
+ MOV AL,BYTE PTR [FoundDel]
+ RET
+
+$FCB_DELETE ENDP
+
+SUBTTL $FCB_RENAME -- SYSTEM CALL 23; RENAME FILES
+PAGE
+ERRETJ: JMP ERRET
+
+ procedure $FCB_RENAME,NEAR ; System call 23
+ASSUME DS:NOTHING,ES:NOTHING
+
+; Inputs:
+; DS:DX point to a modified FCB (DS:DX+11H points to destination
+; name)
+; Function:
+; Rename all matching entries to indicated name
+; Returns:
+; AL = -1 if no entries matched, otherwise 0
+
+ invoke MOVNAME
+ASSUME ES:DOSGROUP
+ JC ERRETJ
+ ADD SI,5
+ MOV DI,OFFSET DOSGROUP:NAME2
+ invoke LODNAME
+ JC ERRETJ ; Report error if second name invalid
+ invoke FINDNAME
+ASSUME DS:DOSGROUP
+ JC ERRETJ
+ OR AH,AH ; Check if I/O device name
+ JS ERRETJ ; If so, can't rename it
+ MOV SI,OFFSET DOSGROUP:NAME1
+ MOV DI,OFFSET DOSGROUP:NAME3
+ MOV CX,13
+ REP MOVSB ; Copy name to search for --include attribute byte
+RENFIL:
+ MOV DI,OFFSET DOSGROUP:NAME1
+ MOV SI,OFFSET DOSGROUP:NAME2
+ MOV CX,11
+NEWNAM:
+ LODSB
+ CMP AL,"?"
+ JNZ NOCHG
+ PUSH DS
+ MOV DS,WORD PTR [CURBUF+2]
+ MOV AL,[BX]
+ POP DS
+NOCHG:
+ STOSB
+ INC BX
+ LOOP NEWNAM
+ INC DI
+ MOV BYTE PTR [DI],attr_all ;Sets ATTRIB
+ ; Stop duplicates with any attributes
+ invoke DEVNAME ; Check if giving it a device name
+ JNC RENERR
+ XOR AX,AX
+ PUSH [LASTENT]
+ invoke FINDENTRY ; See if new name already exists
+ POP AX
+ JNC RENERR ; Error if found
+ LES BP,[THISDPB]
+ invoke GETENT ; Re-read matching entry
+ MOV DI,BX ; Leave BX,DX until call to NEXTENT
+ MOV ES,WORD PTR [CURBUF+2]
+ MOV SI,OFFSET DOSGROUP:NAME1
+ MOV CX,11
+ REP MOVSB ; Replace old name with new one
+ MOV DI,WORD PTR [CURBUF]
+ MOV ES:[DI.BUFDIRTY],1 ; Directory changed
+ PUSH SS
+ POP ES
+ MOV SI,OFFSET DOSGROUP:NAME3
+ MOV DI,OFFSET DOSGROUP:NAME1
+ MOV CX,13 ; Include attribute byte
+ REP MOVSB ; Copy name back into search buffer
+ invoke NEXTENT
+ JNC RENFIL
+ JMP FLUSHRET1
+
+RENERR:
+ CALL FLUSHRET1
+ERRET:
+ MOV AL,-1
+ RET
+$FCB_RENAME ENDP
+
+SUBTTL $FCB_OPEN -- SYSTEM CALL 15; OPEN A FILE
+PAGE
+ procedure $FCB_OPEN,NEAR ; System call 15
+ASSUME DS:NOTHING,ES:NOTHING
+
+; Inputs:
+; DS:DX point to an unopened FCB
+; Function:
+; Open indicated file and fill in FCB
+; Returns:
+; AL = -1 if no entries matched, otherwise 0
+; FOR INTERNAL USE
+; [CURBUF+2]:SI and [CURBUF+2]:BX Preserved
+
+ invoke GETFILE
+ASSUME DS:DOSGROUP,ES:NOTHING
+
+ entry DOOPEN
+
+; Enter here to perform $FCB_OPEN on file already found
+; in directory. AH=device ID number, DS=CS, BX points to directory
+; entry in [CURBUF], SI points to First Cluster field, and
+; ES:DI point to the FCB to be opened. This entry point
+; is used by $FCB_CREATE.
+ JC ERRET
+ PUSH SI
+ PUSH AX ; Save I/O driver number
+ XOR AL,AL
+ OR AH,AH
+ JS OPENDEV
+ MOV AL,[THISDRV]
+ MOV DS,WORD PTR [CURBUF+2]
+ASSUME DS:NOTHING
+ INC AX
+OPENDEV:
+ STOSB
+ XOR AX,AX
+IF ZEROEXT
+ ADD DI,11
+ STOSW ; Zero low byte of extent field if ZERPEXT only
+ELSE
+ ADD DI,12 ; Point to high half of CURRENT BLOCK field
+ STOSB ; Set it to zero (CP/M programs set low byte)
+ENDIF
+ MOV AL,128 ; Default record size
+ STOSW ; Set record size
+ LODSW ; Get starting cluster
+ MOV DX,AX ; Save it for the moment
+ MOVSW ; Transfer size to FCB
+ MOVSW
+ MOV AX,[SI-8] ; Get date
+ STOSW ; Save date in FCB
+ MOV AX,[SI-10] ; Get time
+ STOSW ; Save it in FCB
+ POP AX ; Restore I/O driver number
+ POP SI
+ MOV AL,AH
+ OR AL,40H ; Not dirty
+ STOSB
+ JS SAVDEVPT ; If device, go save pointer to it
+ MOV AX,DX ; Restore starting cluster
+ STOSW ; first cluster
+ PUSH AX ; save cluster
+ XOR AX,AX
+ STOSW ; clus pos
+ POP AX ; last cluster
+ STOSB
+ MOV AL,AH
+ MOV AH,BYTE PTR [DIRSTART]
+ PUSH CX
+ MOV CL,4
+ SHL AH,CL
+ OR AL,AH
+ STOSB
+ MOV AX,[DIRSTART]
+ MOV CL,4
+ SHL AX,CL
+ POP CX
+ MOV AL,AH
+ STOSB
+OPEN_RET:
+ XOR AX,AX
+ RET
+
+SAVDEVPT:
+ASSUME DS:DOSGROUP
+ LDS AX,[DEVPT]
+ASSUME DS:NOTHING
+ STOSW
+ MOV ES:[DI],DS
+ JMP SHORT OPEN_RET
+$FCB_OPEN ENDP
+
+SUBTTL $FCB_CLOSE -- SYSTEM CALL 16; CLOSE FILE
+PAGE
+ procedure $FCB_CLOSE,NEAR ; System call 16
+ASSUME DS:NOTHING,ES:NOTHING
+
+; Inputs:
+; DS:DX point to an opened FCB
+; Function:
+; Close the indicated file
+; Returns:
+; AL = -1 if disk has been changed, otherwise 0
+
+ MOV DI,DX
+ CMP BYTE PTR [DI],-1 ; Check for extended FCB
+ JNZ NORMFCB3
+ ADD DI,7
+NORMFCB3:
+ TEST [DI.fcb_DEVID],devid_file_clean+devid_device
+ ; Allow only dirty files
+ JNZ OKRET1 ; can't close I/O device or not written
+ invoke MOVNAMENOSET
+ JC BADCLOSE ; Bad file name
+ entry FCB_CLOSE_INNER
+ PUSH DX
+ PUSH DS
+ MOV SI,DX
+ MOV BX,[SI.fcb_LSTCLUS+1]
+ MOV CL,4
+ SHR BX,CL
+ PUSH BX
+ PUSH SS
+ POP DS
+ASSUME DS:DOSGROUP
+ invoke FATREAD
+ POP BX
+ invoke SETDIRSRCH
+ invoke FINDENTRY
+ POP ES
+ POP DI
+ JC BADCLOSE
+ LDS BX,[CURBUF]
+ASSUME DS:NOTHING
+
+ ; note that SI points to dir_first...
+
+ OR BYTE PTR [SI-dir_first+dir_attr],attr_archive
+ MOV CX,ES:[DI.fcb_FIRCLUS]
+ MOV [SI-dir_first+dir_first],CX
+ MOV DX,ES:WORD PTR [DI.fcb_FILSIZ]
+ MOV [SI-dir_first+dir_size_l],DX
+ MOV DX,ES:WORD PTR [DI.fcb_FILSIZ+2]
+ MOV [SI-dir_first+dir_size_h],DX
+ MOV DX,ES:[DI.fcb_FDATE]
+ MOV [SI-dir_first+dir_date],DX
+ MOV DX,ES:[DI.fcb_FTIME]
+ MOV [SI-dir_first+dir_time],DX
+ MOV [BX.BUFDIRTY],1
+ PUSH SS
+ POP DS
+ASSUME DS:DOSGROUP
+FLUSHRET1:
+ LES BP,[THISDPB]
+ MOV AL,ES:[BP.dpb_drive]
+ invoke FLUSHBUF
+OKRET1:
+ XOR AL,AL
+ RET
+
+BADCLOSE:
+ MOV AL,-1
+ RET
+$FCB_CLOSE ENDP
+
+SUBTTL $FCB_CREATE -- SYSTEM CALL 22; MAKE AND OPEN A NEW FILE
+PAGE
+ procedure $FCB_CREATE,NEAR ; System call 22
+ASSUME DS:NOTHING,ES:NOTHING
+
+; Inputs:
+; DS:DX point to an unopened FCB
+; Function:
+; If file does not exist, create it and open it
+; If file exists, free up its contents and open the file
+; Returns:
+; AL = -1 if file cannot be created, otherwise 0
+
+ invoke MOVNAME
+ASSUME ES:DOSGROUP
+ JC ERRET3
+ MOV DI,OFFSET DOSGROUP:NAME1
+ MOV CX,11
+ MOV AL,"?"
+ REPNE SCASB
+ JZ ERRET3
+ MOV BYTE PTR [CREATING],-1
+ PUSH DX
+ PUSH DS
+ invoke FINDNAME
+ASSUME DS:DOSGROUP
+NWENTY:
+ LES BP,[THISDPB]
+ASSUME ES:NOTHING
+ JNC EXISTENT
+ invoke BUILDDIR
+ JC ERRPOP
+ invoke GETENT ; Point at that free entry
+ JMP SHORT FREESPOT
+ERRPOP:
+ POP DS
+ POP DX
+ASSUME DS:NOTHING
+ERRET3:
+ JMP SHORT BADCLOSE
+
+ entry NEWENTRY
+ POP DX ; Return address
+ POP ES ; ES
+ POP CX ; DI
+ PUSH DX
+ PUSH CX
+ PUSH ES
+ JMP NWENTY
+
+EXISTENT:
+ASSUME DS:DOSGROUP
+ JNZ ERRPOP ; Error if attributes don't match
+ OR AH,AH ; Check if file is I/O device
+ JS OPENJMP ; If so, no action
+ PUSH DS
+ LDS DI,[CURBUF]
+ASSUME DS:NOTHING
+ MOV CX,[SI] ; Get pointer to clusters
+ MOV SI,[DI.BUFSECNO]
+ POP DS
+ASSUME DS:DOSGROUP
+ JCXZ FREESPOT
+ CMP CX,ES:[BP.dpb_max_cluster]
+ JA FREESPOT
+ SUB BX,DI
+ PUSH BX
+ PUSH SI ; Save sector number
+ MOV BX,CX
+ invoke RELEASE ; Free any data already allocated
+ POP DX
+ XOR AL,AL
+ invoke GETBUFFR
+ POP BX
+ ADD BX,WORD PTR [CURBUF]
+FREESPOT:
+ TEST BYTE PTR [ATTRIB],attr_volume_id
+ JZ NOTVOLID
+ CMP BYTE PTR [VOLID],0
+ JNZ ERRPOP ; Can't create a second volume ID
+NOTVOLID:
+ MOV ES,WORD PTR [CURBUF+2]
+ MOV DI,BX
+ MOV SI,OFFSET DOSGROUP:NAME1
+ MOV CX,5
+ MOVSB
+ REP MOVSW
+ MOV AL,[ATTRIB]
+ STOSB
+ MOV CL,5
+ XOR AX,AX
+ REP STOSW
+ invoke DATE16
+ XCHG AX,DX
+ STOSW
+ XCHG AX,DX
+ STOSW
+ XOR AX,AX
+ PUSH DI
+ STOSW
+ STOSW
+ STOSW
+ MOV SI,WORD PTR [CURBUF]
+ MOV ES:[SI.BUFDIRTY],1
+ LES BP,[THISDPB]
+ MOV AL,ES:[BP.dpb_drive]
+ PUSH AX
+ PUSH BX
+ invoke FLUSHBUF
+ POP BX
+ POP AX
+ POP SI
+ MOV AH,AL ; Get I/O driver number back
+OPENJMP:
+ CLC ; Clear carry so OPEN won't fail
+ POP ES
+ POP DI
+ASSUME ES:NOTHING
+ JMP DOOPEN
+$FCB_CREATE ENDP
+
+do_ext
+
+CODE ENDS
+ END
+
+\1a
\ No newline at end of file
--- /dev/null
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ MS-DOS 2.0\r
+\r
+ System Calls Reference\r
+\f\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+| |\r
+| C A V E A T P R O G R A M M E R |\r
+| |\r
+| Certain structures, constants and system calls below |\r
+| are private to the DOS and are extremely |\r
+| version-dependent. They may change at any time at the |\r
+| implementors' whim. As a result, they must not be |\r
+| documented to the general public. If an extreme case |\r
+| arises, they must be documented with this warning. |\r
+| |\r
+| Those structures and constants that are subject to the |\r
+| above will be marked and bracketed with the flag: |\r
+| |\r
+| C A V E A T P R O G R A M M E R |\r
+| |\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+\f\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ Section 1\r
+\r
+ Extensions to existing call structure\r
+\f\r
+\r
+ Name: * Alloc - allocate memory\r
+\r
+ Assembler usage:\r
+ MOV BX,size\r
+ MOV AH,Alloc\r
+ INT 21h\r
+ ; AX:0 is pointer to allocated memory\r
+ ; if alloc fails, BX is the largest block available\r
+\r
+ Description:\r
+ Alloc returns a pointer to a free block of memory\r
+ that has the requested size in paragraphs.\r
+\r
+ Error return:\r
+ AX = error_not_enough_memory\r
+ The largest available free block is smaller\r
+ than that requested or there is no free block.\r
+ = error_arena_trashed\r
+ The internal consistency of the memory arena\r
+ has been destroyed. This is due to a user\r
+ program changing memory that does not belong\r
+ to it.\r
+\f\r
+\r
+ Name: * CharOper - change incompatible configuration\r
+ parameters\r
+\r
+ Assembler usage:\r
+ MOV AH, CharOper\r
+ MOV AL, func\r
+ MOV DL, data\r
+ INT 21h\r
+ ; on read functions, data is returned in DL\r
+\r
+ Description:\r
+ CharOper allows a program to change system\r
+ parameters to allow for switch indicators and whether\r
+ devices are available at every level of the directory\r
+ tree.\r
+\r
+ A function code is passed in AL:\r
+\r
+ AL Function\r
+ -- --------\r
+ 0 DL, on return, will contain the DOS switch\r
+ character. On most systems this will default to\r
+ '-'.\r
+ 1 Set the switch character to the character in DL.\r
+ 2 Read the device availability byte into DL. If\r
+ this byte is 0, then devices must be accessed in\r
+ file I/O calls by /dev/device. If this byte is\r
+ non-zero, then the devices are available at every\r
+ node of the directory tree (i.e. CON is the\r
+ console device not the file CON). This byte is\r
+ generally 0.\r
+ 3 Set the device availability byte to the value in\r
+ DL.\r
+\r
+ Error returns:\r
+ AL = FF\r
+ The function code specified in AL is not in\r
+ the range 0:3\r
+\f\r
+\r
+ Name: * CurrentDir - return text of current directory\r
+\r
+ Assembler usage:\r
+ MOV AH,CurrentDir\r
+ LDS SI,area\r
+ MOV DL,drive\r
+ INT 21h\r
+ ; DS:SI is a pointer to 64 byte area that contains\r
+ ; drive current directory.\r
+\r
+ Description:\r
+ CurrentDir returns the current directory for a\r
+ particular drive. The directory is root-relative and\r
+ does not contain the drive specifier. The drive code\r
+ passed in DL is 0=default, 1=A, 2=B, etc.\r
+\r
+ Error returns:\r
+ AX = error_invalid_drive\r
+ The drive specified in DL was invalid.\r
+\f\r
+\r
+ Name: * Dealloc - free allocated memory\r
+\r
+ Assembler usage:\r
+ MOV ES,block\r
+ MOV AH,dealloc\r
+ INT 21h\r
+\r
+ Description:\r
+ Dealloc returns a piece of memory to the system\r
+ pool that was allocated by alloc.\r
+\r
+ Error return:\r
+ AX = error_invalid_block\r
+ The block passed in ES is not one allocated\r
+ via Alloc.\r
+ = error_arena_trashed\r
+ The internal consistency of the memory arena\r
+ has been destroyed. This is due to a user\r
+ program changing memory that does not belong\r
+ to it.\r
+\f\r
+\r
+ Name: * FileTimes - get/set the write times of a\r
+ handle\r
+\r
+ Assembler usage:\r
+ MOV AH, FileTimes\r
+ MOV AL, func\r
+ MOV BX, handle\r
+ ; if AL = 1 then then next two are mandatory\r
+ MOV CX, time\r
+ MOV DX, date\r
+ INT 21h\r
+ ; if AL = 0 then CX/DX has the last write time/date\r
+ ; for the handle.\r
+\r
+ Description:\r
+ FileTimes returns or sets the last-write time for\r
+ a handle. These times are not recorded until the file\r
+ is closed.\r
+\r
+ A function code is passed in AL:\r
+\r
+ AL Function\r
+ -- --------\r
+ 0 Return the time/date of the handle in CX/DX\r
+ 1 Set the time/date of the handle to CX/DX\r
+\r
+ Error returns:\r
+ AX = error_invalid_function\r
+ The function passed in AL was not in the range\r
+ 0:1.\r
+ = error_invalid_handle\r
+ The handle passed in BX was not currently\r
+ open.\r
+\f\r
+\r
+ Name: * FindFirst - find matching file\r
+\r
+ Assembler usage:\r
+ MOV AH, FindFirst\r
+ LDS DX, pathname\r
+ MOV CX, attr\r
+ INT 21h\r
+ ; DMA address has datablock\r
+\r
+ Description:\r
+ FindFirst takes a pathname with wildcards in the\r
+ last component (passed in DS:DX), a set of attributes\r
+ (passed in CX) and attempts to find all files that\r
+ match the pathname and have a subset of the required\r
+ attributes. A datablock at the current DMA is written\r
+ that contains information in the following form:\r
+\r
+ find_buf STRUC\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+| C A V E A T P R O G R A M M E R |\r
+| |\r
+ find_buf_sattr DB ? ; attribute of search\r
+ find_buf_drive DB ? ; drive of search\r
+ find_buf_name DB 11 DUP (?); search name\r
+ find_buf_LastEnt DW ? ; LastEnt\r
+ find_buf_ThisDPB DD ? ; This DPB\r
+ find_buf_DirStart DW ? ; DirStart\r
+| |\r
+| C A V E A T P R O G R A M M E R |\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+\r
+ find_buf_attr DB ? ; attribute found\r
+ find_buf_time DW ? ; time\r
+ find_buf_date DW ? ; date\r
+ find_buf_size_l DW ? ; low(size)\r
+ find_buf_size_h DW ? ; high(size)\r
+ find_buf_pname DB 13 DUP (?) ; packed name\r
+ find_buf ENDS\r
+\r
+ To obtain the subsequent matches of the pathname,\r
+ see the description of FindNext\r
+\r
+ Error Returns:\r
+ AX = error_file_not_found\r
+ The path specified in DS:DX was an invalid\r
+ path.\r
+ = error_no_more_files\r
+ There were no files matching this\r
+ specification.\r
+\f\r
+\r
+ Name: * FindNext - step through a directory matching\r
+ files\r
+\r
+ Assembler usage:\r
+ ; DMA points at area returned by find_first\r
+ MOV AH, findnext\r
+ INT 21h\r
+ ; next entry is at dma\r
+\r
+ Description:\r
+ FindNext finds the next matching entry in a\r
+ directory. The current DMA address must point at a\r
+ block returned by FindFirst (see FindFirst).\r
+\r
+ Error Returns:\r
+ AX = error_no_more_files\r
+ There are no more files matching this pattern.\r
+\f\r
+\r
+ Name: * GetDMA - get current DMA transfer address\r
+\r
+ Assembler usage:\r
+ MOV AH,GetDMA\r
+ INT 21h\r
+ ; ES:BX has current DMA transfer address\r
+\r
+ Description:\r
+ Return DMA transfer address.\r
+\r
+ Error returns:\r
+ None.\r
+\f\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+| C A V E A T P R O G R A M M E R |\r
+| |\r
+\r
+ Name: * GetDSKPT(DL) - get pointer to drive parameter\r
+ block\r
+\r
+ Assembler usage:\r
+ MOV AH,GetDSKPT\r
+ INT 21h\r
+ ; DS:BX has address of drive parameter block\r
+\r
+ Description:\r
+ Return pointer to default drive parameter block.\r
+\r
+ Error returns:\r
+ None.\r
+\r
+ Assembler usage:\r
+ MOV DL,DrvNUM\r
+ MOV AH,GetDSKPTDL\r
+ INT 21h\r
+ ; DS:BX has address of drive parameter block\r
+\r
+ Description:\r
+ Return pointer to drive parameter block for drive\r
+ designated in DL (0=Default, A=1, B=2 ...)\r
+\r
+ Error returns:\r
+ AL = FF\r
+ The drive given in DL is invalid.\r
+| |\r
+| C A V E A T P R O G R A M M E R |\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+\f\r
+\r
+ Name: * GetFreespace - get Disk free space\r
+\r
+ Assembler usage:\r
+ MOV AH,GetFreespace\r
+ MOV DL,Drive ;0 = default, A = 1\r
+ INT 21h\r
+ ; BX = Number of free allocation units on drive\r
+ ; DX = Total number of allocation units on drive\r
+ ; CX = Bytes per sector\r
+ ; AX = Sectors per allocation unit\r
+\r
+ Description:\r
+ Return Free space on disk along with additional\r
+ information about the disk.\r
+\r
+ Error returns:\r
+ AX = FFFF\r
+ The drive number given in DL was invalid.\r
+\r
+ NOTE: This call returns the same information in the same\r
+ registers (except for the FAT pointer) as the get FAT\r
+ pointer calls did in previous versions of the DOS.\r
+\f\r
+\r
+ Name: * GetInDOSF - get DOS critical-section flag\r
+\r
+ Assembler usage:\r
+ MOV AH,GetInDOSF\r
+ INT 21h\r
+ ; ES:BX has location of the flag\r
+ MOV CritSEG, ES\r
+ MOV CritOFF, BX\r
+ ...\r
+ IntVec:\r
+ MOV AX, DWORD PTR Crit\r
+ CMP AX,0\r
+ JZ DoFunc\r
+ IRET\r
+ DoFunc: ...\r
+\r
+ Description:\r
+ Return location of indos flag. On return ES:BX is\r
+ the address of a byte memory cell inside the DOS. If\r
+ used in an interrupt service routine, it indicates\r
+ whether or not the DOS was interrupted in a critical\r
+ section. If the cell was zero, then the DOS was not\r
+ in a critical section and thus can be called by the\r
+ interrupt routine. If the cell was non-zero, the DOS\r
+ should be considered to be in an uninterruptable state\r
+ and for reliability, no DOS calls should be given.\r
+\r
+ Error returns:\r
+ None.\r
+\f\r
+\r
+ Name: * GetVector - get interrupt vector\r
+\r
+ Assembler usage:\r
+ MOV AH,GetVector\r
+ MOV AL,interrupt\r
+ INT 21h\r
+ ; ES:BX now has long pointer to interrupt routine\r
+\r
+ Description:\r
+ Return interrupt vector associated with an\r
+ interrupt.\r
+\r
+ Error returns:\r
+ None.\r
+\f\r
+\r
+ Name: * GetVerifyFlag - return current setting of the\r
+ verify after write flag.\r
+\r
+ Assembler usage:\r
+ MOV AH,GetVerifyFlag\r
+ INT 21h\r
+ ; AL is the current verify flag value\r
+\r
+ Description:\r
+ The current value of the verify flag is returned\r
+ in AL.\r
+\r
+ Error returns:\r
+ None.\r
+\f\r
+\r
+ Name: * GetVersion - get DOS version number\r
+\r
+ Assembler usage:\r
+ MOV AH,GetVersion\r
+ INT 21h\r
+ ; AL is the major version number\r
+ ; AH is the minor version number\r
+ ; BH is the OEM number\r
+ ; BL:CX is the (24 bit) user number\r
+\r
+ Description:\r
+ Return MS-DOS version number. On return AL.AH\r
+ will be the two part version designation, ie. for\r
+ MS-DOS 1.28 AL would be 1 and AH would be 28. For pre\r
+ 1.28 DOS AL = 0. Note that version 1.1 is the same as\r
+ 1.10, not the same as 1.01.\r
+\r
+ Error returns:\r
+ None.\r
+\f\r
+\r
+ Name: * International - return country dependent\r
+ information\r
+\r
+ Assembler usage:\r
+ LDS DX, blk\r
+ MOV AH, International\r
+ MOV AL, func\r
+ INT 21h\r
+\r
+ Description:\r
+ This call returns in the block of memory pointed\r
+ to by DS:DX, the following information pertinent to\r
+ international applications:\r
+\r
+ +---------------------------+\r
+ | WORD Date/time format |\r
+ +---------------------------+\r
+ | BYTE ASCIZ string |\r
+ | currency symbol |\r
+ +---------------------------+\r
+ | BYTE ASCIZ string |\r
+ | thousands separator |\r
+ +---------------------------+\r
+ | BYTE ASCIZ string decimal |\r
+ | separator |\r
+ +---------------------------+\r
+\r
+ The date/time format has the following values and\r
+ meanings:\r
+\r
+ 0 - USA standard h:m:s m/d/y\r
+ 1 - Europe standard h:m:s d/m/y\r
+ 2 - Japan standard y/m/d h:m:s\r
+\r
+ The value passed in AL is either 0 (for current\r
+ country) or a country code (to be defined later.\r
+ Currently the country code must be zero).\r
+\r
+ Error returns:\r
+ AX = error_invalid_function\r
+ The function passed in AL was not 0\r
+ (currently).\r
+\f\r
+\r
+ Name: * KeepProcess - terminate process and remain\r
+ resident\r
+\r
+ Assembler usage:\r
+ MOV AL, exitcode\r
+ MOV DX, parasize\r
+ MOV AH, KeepProcess\r
+ INT 21h\r
+\r
+ Description:\r
+ This call terminates the current process and\r
+ attempts to set the initial allocation block to a\r
+ specific size in paragraphs. It will not free up any\r
+ other allocation blocks belonging to that process.\r
+ The exit code passed in AX is retrievable by the\r
+ parent via Wait.\r
+\r
+ Error Returns:\r
+ None.\r
+\f\r
+\r
+ Name: * Rename - move a directory entry\r
+\r
+ Assembler usage:\r
+ LDS DX, source\r
+ LES DI, dest\r
+ MOV AH, Rename\r
+ INT 21h\r
+\r
+ Description:\r
+ Rename will attempt to rename a file into another\r
+ path. The paths must be on the same device.\r
+\r
+ Error returns:\r
+ AX = error_file_not_found\r
+ The file name specifed by DS:DX was not found.\r
+ = error_not_same_device\r
+ The source and destination are on different\r
+ drives.\r
+ = error_access_denied\r
+ The path specified in DS:DX was a directory or\r
+ the file specified by ES:DI exists or the\r
+ destination directory entry could not be\r
+ created.\r
+\f\r
+\r
+ Name: * SetBlock - modify allocated blocks\r
+\r
+ Assembler usage:\r
+ MOV ES,block\r
+ MOV BX,newsize\r
+ MOV AH,setblock\r
+ INT 21h\r
+ ; if setblock fails for growing, BX will have the\r
+ ; maximum size possible\r
+\r
+ Description:\r
+ Setblock will attempt to grow/shrink an allocated\r
+ block of memory.\r
+\r
+ Error return:\r
+ AX = error_invalid_block\r
+ The block passed in ES is not one allocated\r
+ via Alloc.\r
+ = error_arena_trashed\r
+ The internal consistency of the memory arena\r
+ has been destroyed. This is due to a user\r
+ program changing memory that does not belong\r
+ to it.\r
+ = error_not_enough_memory\r
+ There was not enough free memory after the\r
+ specified block to satisfy the grow request.\r
+\f\r
+\r
+ Name: * SetCtrlCTrapping - turn on/off broad ^C\r
+ checking\r
+\r
+ Assembler usage:\r
+ MOV DL,val\r
+ MOV AH,SetCtrlCTrapping\r
+ MOV AL,func\r
+ INT 21h\r
+ ; If AL was 0, then DL has the current value of the\r
+ ; ^C check\r
+\r
+ Description:\r
+ MSDOS ordinarily checks for a ^C on the\r
+ controlling device only when doing a function 1-12\r
+ operation to that device. SetCtrlCTrapping allows the\r
+ user to expand this checking to include any system\r
+ call. For example, with the ^C trapping off, all disk\r
+ I/O will proceed without interruption while with ^C\r
+ trapping on, the ^C interrupt is given at the system\r
+ call that initiates the disk operation.\r
+\r
+ Error return:\r
+ AL = FF\r
+ The function passed in AL was not in the range\r
+ 0:1.\r
+\f\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+| C A V E A T P R O G R A M M E R |\r
+| |\r
+\r
+ Name: * Set_OEM_Handler - set handler for OEM\r
+ specific INT 21H calls.\r
+\r
+ Assembler usage:\r
+ LDS DX,handler_address\r
+ MOV AH,Set_OEM_Handler\r
+ INT 21H\r
+\r
+ Description:\r
+ Set handler address for 0F9H-0FFH INT 21H system\r
+ calls to DS:DX. To return the 0F9H-0FFH calls to\r
+ the uninitialized state, give DS=DX=-1.\r
+\r
+ Error returns:\r
+ None.\r
+\r
+ Handler entry:\r
+ All registers as user set them when INT 21H\r
+ issued (including SS:SP). INT 21 return is on\r
+ stack, so the correct method for the OEM handler\r
+ to return to the user is to give an IRET. The\r
+ OEM handler is free to make any INT 21H system\r
+ call (including the 0F9H- 0FFH group if the OEM\r
+ handler is re-entrant).\r
+\r
+\r
+ The AH INT 21H function codes 0F8H through 0FFH are\r
+ reserved for OEM extensions to the INT 21H calling\r
+ convention. These calls have two states, initialized\r
+ and uninitialized. There will be one handler for all 7\r
+ (0F9-0FFH) functions. When the DOS is first\r
+ initialized, these calls are uninitialized. The AH=0F8H\r
+ call is the call which will set the handler address for\r
+ the 0F9-0FFH calls. If the 0F9-0FFH calls are\r
+ uninitialized, an attempt to call them results in the\r
+ normal invalid system call number return.\r
+ OEMs should NOT document the 0F8 call.\r
+| |\r
+| C A V E A T P R O G R A M M E R |\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+\f\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ Section 2\r
+\r
+ XENIX-compatible system calls\r
+\f\r
+\r
+\r
+ Previous to version 2.0, MSDOS had a simple single\r
+ directory structure that sufficed for small (160k to 320K)\r
+ diskettes. As the need for hard disk support grows, and\r
+ as MSDOS 2.0 will support a wide variety of hard disks,\r
+ the need for better disk organization also grows. Merely\r
+ expanding the directory is not an effective solution;\r
+ doing a 'DIR' on a directory with 1000 files is not a\r
+ user-friendly characteristic.\r
+\r
+ People, by nature, think in hierarchical terms:\r
+ organization charts and family trees, for example. It\r
+ would be nice to allow users to organize their files on\r
+ disk in a similar manner. Consider the following:\r
+\r
+ In a particular business, both sales and accounting\r
+ share a computer with a large disk and the individual\r
+ employees use it for preparation of reports and\r
+ maintaining accounting information. One would naturally\r
+ view the organization of files on the disk in this\r
+ fashion:\r
+\r
+ +-disk-+\r
+ / \\r
+ / \\r
+ / \\r
+ sales accounting\r
+ / | | \\r
+ / | | \\r
+ / | | \\r
+ John Mary Steve Sue\r
+ / | (A) | | | \\r
+ / | | | | \\r
+ / | | | | \\r
+ report accts. report accts. report report\r
+ receiv. receiv\r
+\r
+ In MSDOS 2.0 the user can arrange his files in such a\r
+ manner that files that are not part of his current task do\r
+ not interfere with that task. Pre-2.0 versions of MSDOS\r
+ has a single directory that contains files. MSDOS extends\r
+ this concept to allow a directory to contain both files\r
+ and directories and to introduce the notion of the\r
+ 'current' directory.\r
+\r
+ To specify a filename, the user could use one of two\r
+ methods, either specify a path from the root node to the\r
+ file, or specify a path from the current node to the file.\r
+ A path is a series of directory names separated by '/' and\r
+ ending with a filename. A path that starts at the root\r
+ begins with a '/'.\r
+\r
+ There is a special directory entry in each directory,\r
+ denoted by '..' that is the parent of the directory. The\r
+ root directory's parent is itself (who created God?).\r
+\r
+ Using a directory structure like the hierarchy above,\r
+ and assuming that the current directory is at point (D),\r
+ to reference the report under John, the following are all\r
+ equivalent:\r
+\r
+ report\r
+ /sales/John/report\r
+ ../John/report\r
+\r
+ To refer to the report under Mary, the following are\r
+ all equivalent:\r
+\r
+ ../Mary/report\r
+ /sales/Mary/report\r
+\r
+ To refer to the report under Sue, the following are\r
+ all equivalent.\r
+\r
+ ../../accounting/Sue/report\r
+ /accounting/Sue/report\r
+\r
+ There is no restriction in MSDOS 2.0 on the depth of a\r
+ tree (the length of the longest path from root to leaf)\r
+ except in the number of allocation units available. The\r
+ root directory will have a fixed number of entries, 64 for\r
+ the single sided diskettes to XXX for a large hard disk.\r
+ For non-root directories, there is no limit to the number\r
+ of files per directory excepting in the number of\r
+ allocation units available.\r
+\r
+ Old (pre-2.0) disks will appear to MSDOS 2.0 as having\r
+ only a root directory with files in it and no\r
+ subdirectories whatever.\r
+\r
+ Implementation of the tree-structure is simple. The\r
+ root directory is the pre-2.0 directory. Subdirectories\r
+ of the root have a special attribute set indicating that\r
+ they are directories. The subdirectories themselves are\r
+ files, linked through the FAT as usual. Their contents\r
+ are identical in character to the contents of the root\r
+ directory.\r
+\r
+ Pre-2.0 programs that use system calls not described\r
+ below will not be able to make use of files in other\r
+ directories. They will only be able to access files in\r
+ the current directory. This is no great loss of\r
+ functionality as users will aggregate their files into\r
+ sub-directories on basis of functionality; the files that\r
+ are being used will be found in the current directory.\r
+ Those that are not necessary for the current task will be\r
+ placed in other directories. Out of sight, out of mind.\r
+\r
+ There are also new attributes in 2.0. These and the\r
+ old attributes apply to the tree structured directories in\r
+ the following manner:\r
+\r
+ Attribute Meaning/Function Meaning/Function\r
+ for files for directories\r
+\r
+ volume_id Present at the root. Meaningless.\r
+ Only one file may have\r
+ this set.\r
+\r
+ directory Meaningless. Indicates that the\r
+ directory entry is a\r
+ directory. Cannot be\r
+ changed with ChMod.\r
+\r
+ read_only Old fcb-create, new Meaningless.\r
+ Creat, new open (for\r
+ write or read/write)\r
+ will fail.\r
+\r
+ archive Set when file is Meaningless.\r
+ written. Set/reset via\r
+ ChMod.\r
+\r
+ hidden/ Prevents file from Prevents directory\r
+ system being found in search entry from being\r
+ first/search next. found. ChDir to\r
+ New open will fail. directory will still\r
+ work.\r
+\f\r
+\r
+ Name: * ChDir - Change the current directory\r
+\r
+ Assembler usage:\r
+ LDS DX, name\r
+ MOV AH, ChDir\r
+ INT 21h\r
+\r
+ Description:\r
+ ChDir is given the ASCIZ name of the directory\r
+ which is to become the current directory. If any\r
+ member of the specified pathname does not exist, then\r
+ the current directory is unchanged. Otherwise, the\r
+ current directory is set to the string.\r
+\r
+ Error returns:\r
+ AX = error_path_not_found\r
+ The path specified in DS:DX either indicated a\r
+ file or the path was invalid.\r
+\f\r
+\r
+ Name: * ChMod - change write protection\r
+\r
+ Assembler usage:\r
+ LDS DX, name\r
+ MOV CX, attribute\r
+ MOV AL, func\r
+ MOV AH, ChMod\r
+ INT 21h\r
+\r
+ Description:\r
+ Given an ASCIZ name, ChMod will set/get the\r
+ attributes of the file to those given in CX.\r
+\r
+ A function code is passed in AL:\r
+\r
+ AL Function\r
+ -- --------\r
+ 0 Return the attributes of the file in CX\r
+ 1 Set the attributes of the file to those in CX\r
+\r
+ Error returns:\r
+ AX = error_path_not_found\r
+ The path specified was invalid.\r
+ = error_access_denied\r
+ The attributes specified in CX contained one\r
+ that could not be changed (directory, volume\r
+ ID).\r
+ = error_invalid_function\r
+ The function passed in AL was not in the range\r
+ 0:1.\r
+\f\r
+\r
+ Name: * Close - close a file handle\r
+\r
+ Assembler usage:\r
+ MOV BX, handle\r
+ MOV AH, Close\r
+ INT 21h\r
+\r
+ Description:\r
+ In BX is passed a file handle (like that returned\r
+ by Open, Creat or Dup); the Close call will close the\r
+ associated file. Internal buffers are flushed.\r
+\r
+ Error return:\r
+ AX = error_invalid_handle\r
+ The handle passed in BX was not currently\r
+ open.\r
+\f\r
+\r
+ Name: * Creat - create a file\r
+\r
+ Assembler usage:\r
+ LDS DX, name\r
+ MOV AH, Creat\r
+ MOV CX, attribute\r
+ INT 21h\r
+ ; AX now has the handle\r
+\r
+ Description:\r
+ Creat creates a new file or truncates an old file\r
+ to zero length in preparation for writing. If the\r
+ file did not exist, then the file is created in the\r
+ appropriate directory and the file is given the\r
+ read/write protection code of access.\r
+\r
+ CX contains the default attributes to be set for\r
+ the file. Currently, the read-only bit must be off.\r
+\r
+ Error returns:\r
+ AX = error_access_denied\r
+ The attributes specified in CX contained one\r
+ that could not be created (directory, volume\r
+ ID), a file already existed with a more\r
+ inclusive set of attributes, or a directory\r
+ existed with the same name.\r
+ = error_path_not_found\r
+ The path specified was invalid.\r
+ = error_too_many_open_files\r
+ The file was created with the specified\r
+ attributes, but there were no free handles\r
+ available for the process or that the internal\r
+ system tables were full.\r
+\f\r
+\r
+ Name: * Dup - duplicate a file handle\r
+\r
+ Assembler usage:\r
+ MOV BX, fh\r
+ MOV AH, Dup\r
+ INT 21h\r
+ ; AX has the returned handle\r
+\r
+ Description:\r
+ Dup takes an already opened file handle and\r
+ returns a new handle that refers to the same file at\r
+ the same position.\r
+\r
+ Error returns:\r
+ AX = error_invalid_handle\r
+ The handle passed in BX was not currently\r
+ open.\r
+ = error_too_many_open_files\r
+ There were no free handles available in the\r
+ current process or the internal system tables\r
+ were full.\r
+\f\r
+\r
+ Name: * Dup2 - force a duplicate of a handle\r
+\r
+ Assembler usage:\r
+ MOV BX, fh\r
+ MOV CX, newfh\r
+ MOV AH, Dup2\r
+ INT 21h\r
+\r
+ Description:\r
+ Dup2 will cause newfh to refer to the same stream\r
+ as fh. If there was an open file on newfh, then it is\r
+ closed first.\r
+\r
+ Error returns:\r
+ AX = error_invalid_handle\r
+ The handle passed in BX was not currently\r
+ open.\r
+\f\r
+\r
+ Name: * Exec - load / execute a program\r
+\r
+ Assembler usage:\r
+ LDS DX, name\r
+ LES BX, blk\r
+ MOV AH, Exec\r
+ MOV AL, func\r
+ INT 21h\r
+\r
+ Description:\r
+ This call allows a program to load another program\r
+ into memory and (default) begin execution of it.\r
+ DS:DX points to the ASCIZ name of the file to be\r
+ loaded. ES:BX points to a parameter block for the\r
+ load.\r
+\r
+ A function code is passed in AL:\r
+\r
+ AL Function\r
+ -- --------\r
+ 0 Load and execute the program. A program header is\r
+ established for the program and the terminate and\r
+ ^C addresses are set to the instruction after the\r
+ EXEC system call.\r
+\r
+ NOTE: When control is returned, via a ^C or\r
+ terminate, from the program being EXECed ALL\r
+ registers are altered including the stack.\r
+ This is because control is returned from the\r
+ EXECed program, not the system. To regain\r
+ your stack, store an SS:SP value in a data\r
+ location reachable from your CS.\r
+\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+| C A V E A T P R O G R A M M E R |\r
+| |\r
+ 1 Load, create the program header but do not begin\r
+ execution. The CS:IP/SS:SP of the program are\r
+ returned in the area provided by the user.\r
+| |\r
+| C A V E A T P R O G R A M M E R |\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+\r
+ 3 Load, do not create the program header, and do not\r
+ begin execution. This is useful in loading\r
+ program overlays.\r
+\r
+ For each value of AL, the block has the following\r
+ format:\r
+\r
+ AL = 0 -> load/execute program\r
+\r
+ +---------------------------+\r
+ | WORD segment address of |\r
+ | environment. |\r
+ +---------------------------+\r
+ | DWORD pointer to command |\r
+ | line at 80h |\r
+ +---------------------------+\r
+ | DWORD pointer to default |\r
+ | FCB to be passed at 5Ch |\r
+ +---------------------------+\r
+ | DWORD pointer to default |\r
+ | FCB to be passed at 6Ch |\r
+ +---------------------------+\r
+\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+| C A V E A T P R O G R A M M E R |\r
+| |\r
+ AL = 1 -> load program\r
+\r
+ +---------------------------+\r
+ | WORD segment address of |\r
+ | environment. |\r
+ +---------------------------+\r
+ | DWORD pointer to command |\r
+ | line at 80h |\r
+ +---------------------------+\r
+ | DWORD pointer to default |\r
+ | FCB to be passed at 5Ch |\r
+ +---------------------------+\r
+ | DWORD pointer to default |\r
+ | FCB to be passed at 6Ch |\r
+ +---------------------------+\r
+ | DWORD returned value of |\r
+ | SS:SP |\r
+ +---------------------------+\r
+ | DWORD returned value of |\r
+ | CS:IP |\r
+ +---------------------------+\r
+| |\r
+| C A V E A T P R O G R A M M E R |\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+\r
+ AL = 3 -> load overlay\r
+\r
+ +---------------------------+\r
+ | WORD segment address where|\r
+ | file will be loaded. |\r
+ +---------------------------+\r
+ | WORD relocation factor to |\r
+ | be applied to the image. |\r
+ +---------------------------+\r
+\r
+ Note that all open files of a process are\r
+ duplicated in the child process after an Exec. This\r
+ is extremely powerful; the parent process has control\r
+ over the meanings of stdin, stdout, stderr, stdaux and\r
+ stdprn. The parent could, for example, write a series\r
+ of records to a file, open the file as standard input,\r
+ open a listing file as standard output and then Exec a\r
+ sort program that takes its input from stdin and\r
+ writes to stdout.\r
+\r
+ Also inherited (or passed from the parent) is an\r
+ 'environment'. This is a block of text strings (less\r
+ than 32K bytes total) that convey various\r
+ configurations parameters. The format of the\r
+ environment is as follows:\r
+\r
+ (paragraph boundary)\r
+ +---------------------------+\r
+ | BYTE asciz string 1 |\r
+ +---------------------------+\r
+ | BYTE asciz string 2 |\r
+ +---------------------------+\r
+ | ... |\r
+ +---------------------------+\r
+ | BYTE asciz string n |\r
+ +---------------------------+\r
+ | BYTE of zero |\r
+ +---------------------------+\r
+\r
+ Typically the environment strings have the form:\r
+\r
+ parameter=value\r
+\r
+ for example, COMMAND.COM always passes its execution\r
+ search path as:\r
+\r
+ PATH=A:/BIN;B:/BASIC/LIB\r
+\r
+ A zero value of the environment address will cause the\r
+ child process to inherit the parent's environment\r
+ unchanged.\r
+\r
+ Note that on a successful return from EXEC, all\r
+ registers, except for CS:IP, are changed.\r
+\r
+ Error return:\r
+ AX = error_invalid_function\r
+ The function passed in AL was not 0, 1 or 3.\r
+ = error_bad_environment\r
+ The environment was larger than 32Kb.\r
+ = error_bad_format\r
+ The file pointed to by DS:DX was an EXE format\r
+ file and contained information that was\r
+ internally inconsistent.\r
+ = error_not_enough_memory\r
+ There was not enough memory for the process to\r
+ be created.\r
+ = error_file_not_found\r
+ The path specified was invalid or not found.\r
+\f\r
+\r
+ Name: * Exit - terminate a process\r
+\r
+ Assembler usage:\r
+ MOV AL, code\r
+ MOV AH, Exit\r
+ INT 21h\r
+\r
+ Description:\r
+ Exit will terminate the current process,\r
+ transferring control to the invoking process. In\r
+ addition, a return code may be sent. All files open\r
+ at the time are closed.\r
+\r
+ Error returns:\r
+ None.\r
+\f\r
+\r
+ Name: * Ioctl - I/O control for devices\r
+\r
+ Assembler usage:\r
+ MOV BX, Handle\r
+\r
+ (or MOV BL, drive for calls AL=4,5\r
+ 0=default,A=1...)\r
+\r
+ MOV DX, Data\r
+\r
+ (or LDS DX, buf and\r
+ MOV CX, count for calls AL=2,3,4,5)\r
+\r
+ MOV AH, Ioctl\r
+ MOV AL, func\r
+ INT 21h\r
+ ; For calls AL=2,3,4,5 AX is the number of bytes\r
+ ; transferred (same as READ and WRITE).\r
+ ; For calls AL=6,7 AL is status returned, AL=0 if\r
+ ; status is not ready, AL=0FFH otherwise.\r
+\r
+ Description:\r
+ Set or Get device information associated with open\r
+ Handle, or send/receive control string to device\r
+ Handle or device.\r
+\r
+ The following values are allowed for func:\r
+\r
+ Request Function\r
+ ------ --------\r
+ 0 Get device information (returned in DX)\r
+ 1 Set device information (as determined by DX)\r
+ 2 Read CX number of bytes into DS:DX from device\r
+ control channel.\r
+ 3 Write CX number of bytes from DS:DX to device\r
+ control channel.\r
+ 4 Same as 2 only drive number in BL\r
+ 0=default,A=1,B=2,...\r
+ 5 Same as 3 only drive number in BL\r
+ 0=default,A=1,B=2,...\r
+ 6 Get input status\r
+ 7 Get output status\r
+\r
+ Ioctl can be used to get information about device\r
+ channels. It is ok to make Ioctl calls on regular\r
+ files but only calls 0,6 and 7 are defined in that\r
+ case (AL=0,6,7), all other calls return an\r
+ error_invalid_function error.\r
+\r
+ CALLS AL=0 and AL=1\r
+\r
+ The bits of DX are defined as follows for calls\r
+ AL=0 and AL=1. Note that the upper byte MUST be zero\r
+ on a set call.\r
+\r
+ |\r
+ 15 14 13 12 11 10 9 8|7 6 5 4 3 2 1 0\r
+ +--+--+--+--+--+--+-+-+-+-+-+-+-+-+-+-+\r
+ | R| C| |I|E|R|S|I|I|I|I|\r
+ | e| T| |S|O|A|P|S|S|S|S|\r
+ | s| R| Reserved |D|F|W|E|C|N|C|C|\r
+ | | L| |E| | |C|L|U|O|I|\r
+ | | | |V| | |L|K|L|T|N|\r
+ +--+--+--+--+--+--+-+-+-+-+-+-+-+-+-+-+\r
+ |\r
+\r
+ ISDEV = 1 if this channel is a device\r
+ = 0 if this channel is a disk file (Bits 8-15 =\r
+ 0 in this case)\r
+\r
+ If ISDEV = 1\r
+\r
+ EOF = 0 if End Of File on input\r
+ RAW = 1 if this device is in Raw mode\r
+ = 0 if this device is cooked\r
+ ISCLK = 1 if this device is the clock device\r
+ ISNUL = 1 if this device is the null device\r
+ ISCOT = 1 if this device is the console output\r
+ ISCIN = 1 if this device is the console input\r
+ SPECL = 1 if this device is special\r
+\r
+ CTRL = 0 if this device can NOT do control strings\r
+ via calls AL=2 and AL=3.\r
+ CTRL = 1 if this device can process control\r
+ strings via calls AL=2 and AL=3.\r
+ NOTE that this bit cannot be set.\r
+\r
+ If ISDEV = 0\r
+ EOF = 0 if channel has been written\r
+ Bits 0-5 are the block device number for the\r
+ channel (0 = A, 1 = B, ...)\r
+\r
+ Bits 15,8-13,4 are reserved and should not be altered.\r
+\r
+ Calls 2..5:\r
+ These four calls allow arbitrary control strings to be\r
+ sent or received from a device. The Call syntax is\r
+ the same as the READ and WRITE calls, except for 4 and\r
+ 5 which take a drive number in BL instead of a handle\r
+ in BX.\r
+\r
+ An error_invalid_function error is returned if the\r
+ CTRL bit (see above) is 0.\r
+\r
+ An error_access_denied is returned by calls AL=4,5 if\r
+ the drive number is invalid.\r
+\r
+ Calls 6,7:\r
+ These two calls allow the user to check if a file\r
+ handle is ready for input or output. Status of\r
+ handles open to a device is the intended use of these\r
+ calls, but status of a handle open to a disk file is\r
+ OK and is defined as follows:\r
+\r
+ Input:\r
+ Always ready (AL=FF) until EOF reached, then\r
+ always not ready (AL=0) unless current\r
+ position changed via LSEEK.\r
+ Output:\r
+ Always ready (even if disk full).\r
+\r
+ IMPORTANT NOTE:\r
+ The status is defined at the time the system is\r
+ CALLED. On future versions, by the time control is\r
+ returned to the user from the system, the status\r
+ returned may NOT correctly reflect the true current\r
+ state of the device or file.\r
+\r
+ Error returns:\r
+ AX = error_invalid_handle\r
+ The handle passed in BX was not currently\r
+ open.\r
+ = error_invalid_function\r
+ The function passed in AL was not in the range\r
+ 0:7.\r
+ = error_invalid_data\r
+ = error_access_denied (calls AL=4..7)\r
+\f\r
+\r
+ Name: * LSeek - move file read/write pointer\r
+\r
+ Assembler usage:\r
+ MOV DX, offsetlow\r
+ MOV CX, offsethigh\r
+ MOV AL, method\r
+ MOV BX, handle\r
+ MOV AH, LSeek\r
+ INT 21h\r
+ ; DX:AX has the new location of the pointer\r
+\r
+ Description:\r
+ LSeek moves the read/write pointer according to\r
+ method:\r
+\r
+ Method Function\r
+ ------ --------\r
+ 0 The pointer is moved to offset bytes from the\r
+ beginning of the file.\r
+ 1 The pointer is moved to the current location\r
+ plus offset.\r
+ 2 The pointer is moved to the end of file plus\r
+ offset.\r
+\r
+ Offset should be regarded as a 32-bit integer with\r
+ CX occupying the most significant 16 bits.\r
+\r
+ Error returns:\r
+ AX = error_invalid_handle\r
+ The handle passed in BX was not currently\r
+ open.\r
+ = error_invalid_function\r
+ The function passed in AL was not in the range\r
+ 0:2.\r
+\f\r
+\r
+ Name: * MkDir - Create a directory entry\r
+\r
+ Assembler usage:\r
+ LDS DX, name\r
+ MOV AH, MkDir\r
+ INT 21h\r
+\r
+ Description:\r
+ Given a pointer to an ASCIZ name, create a new\r
+ directory entry at the end.\r
+\r
+ Error returns:\r
+ AX = error_path_not_found\r
+ The path specified was invalid or not found.\r
+ = error_access_denied\r
+ The directory could not be created (no room in\r
+ parent directory), the directory/file already\r
+ existed or a device name was specified.\r
+\f\r
+\r
+ Name: * Open - access a file\r
+\r
+ Assembler usage:\r
+ LDS DX, name\r
+ MOV AH, Open\r
+ MOV AL, access\r
+ INT 21h\r
+ ; AX has error or file handle\r
+ ; If successful open\r
+\r
+ Description:\r
+ Open associates a 16-bit file handle with a file.\r
+\r
+ The following values are allowed for access:\r
+\r
+ ACCESS Function\r
+ ------ --------\r
+ 0 file is opened for reading\r
+ 1 file is opened for writing\r
+ 2 file is opened for both reading and writing.\r
+\r
+ DS:DX point to an ASCIZ name of the file to be\r
+ opened.\r
+\r
+ The read/write pointer is set at the first byte of\r
+ the file and the record size of the file is 1 byte.\r
+ The returned file handle must be used for subsequent\r
+ I/O to the file.\r
+\r
+ The DOS, on initialization, will have a maximum\r
+ number of files. See the configuration file document\r
+ for information on changing this default.\r
+\r
+ Error returns:\r
+ AX = error_invalid_access\r
+ The access specified in AL was not in the\r
+ range 0:2.\r
+ = error_file_not_found\r
+ The path specified was invalid or not found.\r
+ = error_access_denied\r
+ The user attempted to open a directory or\r
+ volume-id, or open a read-only file for\r
+ writing.\r
+ = error_too_many_open_files\r
+ There were no free handles available in the\r
+ current process or the internal system tables\r
+ were full.\r
+\f\r
+\r
+ Name: * Read - Do file/device I/O\r
+\r
+ Assembler usage:\r
+ LDS DX, buf\r
+ MOV CX, count\r
+ MOV BX, handle\r
+ MOV AH, Read\r
+ INT 21h\r
+ ; AX has number of bytes read\r
+\r
+ Description:\r
+ Read transfers count bytes from a file into a\r
+ buffer location. It is not guaranteed that all count\r
+ bytes will be read; for example, reading from the\r
+ keyboard will read at most one line of text. If the\r
+ returned value is zero, then the program has tried to\r
+ read from the end of file.\r
+\r
+ All I/O is done using normalized pointers; no\r
+ segment wraparound will occur.\r
+\r
+ Error returns:\r
+ AX = error_invalid_handle\r
+ The handle passed in BX was not currently\r
+ open.\r
+ = error_access_denied\r
+ The handle passed in BX was opened in a mode\r
+ that did not allow reading.\r
+\f\r
+\r
+ Name: * RmDir - Remove a directory entry\r
+\r
+ Assembler usage:\r
+ LDS DX, name\r
+ MOV AH, RmDir\r
+ INT 21h\r
+\r
+ Description:\r
+ RmDir is given an asciz name of a directory. That\r
+ directory is removed from its parent\r
+\r
+ Error returns:\r
+ AX = error_path_not_found\r
+ The path specified was invalid or not found.\r
+ = error_access_denied\r
+ The path specified was not empty, not a\r
+ directory, the root directory or contained\r
+ invalid information.\r
+ = error_current_directory\r
+ The path specified was the current directory\r
+ on a drive.\r
+\f\r
+\r
+ Name: * Unlink - delete a directory entry\r
+\r
+ Assembler usage:\r
+ LDS DX, name\r
+ MOV AH, Unlink\r
+ INT 21h\r
+\r
+ Description:\r
+ Unlink removes a directory entry associated with a\r
+ filename. If the file is currently open on another\r
+ handle, then no removal will take place.\r
+\r
+ Error returns:\r
+ AX = error_file_not_found\r
+ The path specified was invalid or not found.\r
+ = error_access_denied\r
+ The path specified was a directory or\r
+ read-only.\r
+\f\r
+\r
+ Name: * Wait - retrieve the return code of a child\r
+\r
+ Assembler usage:\r
+ MOV AH, Wait\r
+ INT 21h\r
+ ; AX has the exit code\r
+\r
+ Description:\r
+ Wait will return the Exit code specified by a\r
+ child process. It will return this Exit code only\r
+ once. The low byte of this code is that sent by the\r
+ Exit routine. The high byte is one of the following:\r
+\r
+ 0 - terminate/abort\r
+ 1 - ^C\r
+ 2 - Hard error\r
+ 3 - Terminate and stay resident\r
+\r
+ Error returns:\r
+ None.\r
+\f\r
+\r
+ Name: * Write - write to a file\r
+\r
+ Assembler usage:\r
+ LDS DX, buf\r
+ MOV CX, count\r
+ MOV BX, handle\r
+ MOV AH, Write\r
+ INT 21h\r
+ ; AX has number of bytes written\r
+\r
+ Description:\r
+ Write transfers count bytes from a buffer into\r
+ a file. It should be regarded as an error if the\r
+ number of bytes written is not the same as the number\r
+ requested.\r
+\r
+ It is important to note that the write system\r
+ call with a count of zero (CX = 0) will truncate\r
+ the file at the current position.\r
+\r
+ All I/O is done using normalized pointers; no\r
+ segment wraparound will occur.\r
+\r
+ Error Returns:\r
+ AX = error_invalid_handle\r
+ The handle passed in BX was not currently\r
+ open.\r
+ = error_access_denied\r
+ The handle was not opened in a mode that\r
+ allowed writing.\r
+\f\r
+\r
+The following XENIX convention is followed for the new 2.0\r
+system calls:\r
+\r
+ o If no error occurred, then the carry flag will be\r
+ reset and register AX will contain the appropriate\r
+ information.\r
+\r
+ o If an error occurred, then the carry flag will be\r
+ set and register AX will contain the error code.\r
+\r
+The following code sample illustrates the recommended method\r
+of detecting these errors:\r
+\r
+ ...\r
+ MOV errno,0\r
+ INT 21h\r
+ JNC continue\r
+ MOV errno,AX\r
+continue:\r
+ ...\r
+\r
+The word variable errno will now have the correct error code\r
+for that system call.\r
+\r
+The current equates for the error codes are:\r
+\r
+no_error_occurred EQU 0\r
+\r
+error_invalid_function EQU 1\r
+error_file_not_found EQU 2\r
+error_path_not_found EQU 3\r
+error_too_many_open_files EQU 4\r
+error_access_denied EQU 5\r
+error_invalid_handle EQU 6\r
+error_arena_trashed EQU 7\r
+error_not_enough_memory EQU 8\r
+error_invalid_block EQU 9\r
+error_bad_environment EQU 10\r
+error_bad_format EQU 11\r
+error_invalid_access EQU 12\r
+error_invalid_data EQU 13\r
+error_invalid_drive EQU 15\r
+error_current_directory EQU 16\r
+error_not_same_device EQU 17\r
+error_no_more_files EQU 18\r
+\r
+\f\r
+System call assignments:\r
+\r
+ABORT EQU 0 ; 0 0\r
+STD_CON_INPUT EQU 1 ; 1 1\r
+STD_CON_OUTPUT EQU 2 ; 2 2\r
+STD_AUX_INPUT EQU 3 ; 3 3\r
+STD_AUX_OUTPUT EQU 4 ; 4 4\r
+STD_PRINTER_OUTPUT EQU 5 ; 5 5\r
+RAW_CON_IO EQU 6 ; 6 6\r
+RAW_CON_INPUT EQU 7 ; 7 7\r
+STD_CON_INPUT_NO_ECHO EQU 8 ; 8 8\r
+STD_CON_STRING_OUTPUT EQU 9 ; 9 9\r
+STD_CON_STRING_INPUT EQU 10 ; 10 A\r
+STD_CON_INPUT_STATUS EQU 11 ; 11 B\r
+STD_CON_INPUT_FLUSH EQU 12 ; 12 C\r
+DISK_RESET EQU 13 ; 13 D\r
+SET_DEFAULT_DRIVE EQU 14 ; 14 E\r
+FCB_OPEN EQU 15 ; 15 F\r
+FCB_CLOSE EQU 16 ; 16 10\r
+DIR_SEARCH_FIRST EQU 17 ; 17 11\r
+DIR_SEARCH_NEXT EQU 18 ; 18 12\r
+FCB_DELETE EQU 19 ; 19 13\r
+FCB_SEQ_READ EQU 20 ; 20 14\r
+FCB_SEQ_WRITE EQU 21 ; 21 15\r
+FCB_CREATE EQU 22 ; 22 16\r
+FCB_RENAME EQU 23 ; 23 17\r
+GET_DEFAULT_DRIVE EQU 25 ; 25 19\r
+SET_DMA EQU 26 ; 26 1A\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+| C A V E A T P R O G R A M M E R |\r
+| |\r
+GET_DEFAULT_DPB EQU 31 ; 31 1F\r
+| |\r
+| C A V E A T P R O G R A M M E R |\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+FCB_RANDOM_READ EQU 33 ; 33 21\r
+FCB_RANDOM_WRITE EQU 34 ; 34 22\r
+GET_FCB_FILE_LENGTH EQU 35 ; 35 23\r
+GET_FCB_POSITION EQU 36 ; 36 24\r
+SET_INTERRUPT_VECTOR EQU 37 ; 37 25\r
+CREATE_PROCESS_DATA_BLOCK EQU 38 ; 38 26\r
+FCB_RANDOM_READ_BLOCK EQU 39 ; 39 27\r
+FCB_RANDOM_WRITE_BLOCK EQU 40 ; 40 28\r
+PARSE_FILE_DESCRIPTOR EQU 41 ; 41 29\r
+GET_DATE EQU 42 ; 42 2A\r
+SET_DATE EQU 43 ; 43 2B\r
+GET_TIME EQU 44 ; 44 2C\r
+SET_TIME EQU 45 ; 45 2D\r
+SET_VERIFY_ON_WRITE EQU 46 ; 46 2E\r
+; Extended functionality group\r
+GET_DMA EQU 47 ; 47 2F\r
+GET_VERSION EQU 48 ; 48 30\r
+KEEP_PROCESS EQU 49 ; 49 31\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+| C A V E A T P R O G R A M M E R |\r
+| |\r
+GET_DPB EQU 50 ; 50 32\r
+| |\r
+| C A V E A T P R O G R A M M E R |\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+SET_CTRL_C_TRAPPING EQU 51 ; 51 33\r
+GET_INDOS_FLAG EQU 52 ; 52 34\r
+GET_INTERRUPT_VECTOR EQU 53 ; 53 35\r
+GET_DRIVE_FREESPACE EQU 54 ; 54 36\r
+CHAR_OPER EQU 55 ; 55 37\r
+INTERNATIONAL EQU 56 ; 56 38\r
+; XENIX CALLS\r
+; Directory Group\r
+MKDIR EQU 57 ; 57 39\r
+RMDIR EQU 58 ; 58 3A\r
+CHDIR EQU 59 ; 59 3B\r
+; File Group\r
+CREAT EQU 60 ; 60 3C\r
+OPEN EQU 61 ; 61 3D\r
+CLOSE EQU 62 ; 62 3E\r
+READ EQU 63 ; 63 3F\r
+WRITE EQU 64 ; 64 40\r
+UNLINK EQU 65 ; 65 41\r
+LSEEK EQU 66 ; 66 42\r
+CHMOD EQU 67 ; 67 43\r
+IOCTL EQU 68 ; 68 44\r
+XDUP EQU 69 ; 69 45\r
+XDUP2 EQU 70 ; 70 46\r
+CURRENT_DIR EQU 71 ; 71 47\r
+; Memory Group\r
+ALLOC EQU 72 ; 72 48\r
+DEALLOC EQU 73 ; 73 49\r
+SETBLOCK EQU 74 ; 74 4A\r
+; Process Group\r
+EXEC EQU 75 ; 75 4B\r
+EXIT EQU 76 ; 76 4C\r
+WAIT EQU 77 ; 77 4D\r
+FIND_FIRST EQU 78 ; 78 4E\r
+; Special Group\r
+FIND_NEXT EQU 79 ; 79 4F\r
+; SPECIAL SYSTEM GROUP\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+| C A V E A T P R O G R A M M E R |\r
+| |\r
+SET_CURRENT_PDB EQU 80 ; 80 50\r
+GET_CURRENT_PDB EQU 81 ; 81 51\r
+GET_IN_VARS EQU 82 ; 82 52\r
+SETDPB EQU 83 ; 83 53\r
+| |\r
+| C A V E A T P R O G R A M M E R |\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+GET_VERIFY_ON_WRITE EQU 84 ; 84 54\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+| C A V E A T P R O G R A M M E R |\r
+| |\r
+DUP_PDB EQU 85 ; 85 55\r
+| |\r
+| C A V E A T P R O G R A M M E R |\r
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r
+RENAME EQU 86 ; 86 56\r
+FILE_TIMES EQU 87 ; 87 57\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+TITLE BIOS SYSTEM INITIALIZATION\r
+\r
+FALSE EQU 0\r
+TRUE EQU NOT FALSE\r
+\r
+IBMVER EQU FALSE\r
+IBM EQU IBMVER\r
+IBMJAPVER EQU FALSE ; If TRUE set KANJI true also\r
+MSVER EQU TRUE \r
+ALTVECT EQU FALSE ; Switch to build ALTVECT version\r
+HIGHMEM EQU FALSE\r
+KANJI EQU FALSE\r
+\r
+ IF IBMVER OR IBMJAPVER\r
+NOEXEC EQU TRUE\r
+ ELSE\r
+NOEXEC EQU FALSE\r
+ ENDIF\r
+\r
+; Set to agree with those in DOST:MSHEAD.ASM, ALTVECT version only\r
+MAJOR_VERSION EQU 2\r
+MINOR_VERSION EQU 0B ;2.11\r
+\r
+DOSSIZE EQU 5000H\r
+\r
+; Internal DOS data returned by DOSINIT\r
+\r
+SYSINITVAR STRUC\r
+DPBHEAD DD ? ; Pointer to head of DPB-FAT list\r
+sft_addr DD ? ; Pointer to first FCB table\r
+; The following address points to the CLOCK device\r
+BCLOCK DD ?\r
+; The following address is used by DISKSTATCHK it is always\r
+; points to the console input device header\r
+BCON DD ? ; Console device entry points\r
+NUMIO DB 0 ; Number of disk tables\r
+MAXSEC DW 0 ; Maximum allowed sector size\r
+BUFFHEAD DD ? ; Head of buffer queue\r
+DEVHEAD DD ?\r
+SYSINITVAR ENDS\r
+\r
+ INCLUDE DOSSYM.ASM\r
+ INCLUDE DEVSYM.ASM\r
+\r
+ IF NOT IBM\r
+ IF NOT IBMJAPVER\r
+ EXTRN RE_INIT:FAR\r
+ ENDIF\r
+ ENDIF\r
+\r
+SYSINITSEG SEGMENT PUBLIC 'SYSTEM_INIT'\r
+\r
+ASSUME CS:SYSINITSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING\r
+\r
+ EXTRN BADOPM:BYTE,CRLFM:BYTE,BADCOM:BYTE\r
+ EXTRN BADSIZ_PRE:BYTE,BADLD_PRE:BYTE\r
+ EXTRN BADSIZ_POST:BYTE,BADLD_POST:BYTE\r
+ EXTRN SYSSIZE:BYTE,BADCOUNTRY:BYTE\r
+\r
+ PUBLIC CURRENT_DOS_LOCATION\r
+ PUBLIC FINAL_DOS_LOCATION\r
+ PUBLIC DEVICE_LIST\r
+ PUBLIC MEMORY_SIZE\r
+ PUBLIC DEFAULT_DRIVE\r
+ PUBLIC BUFFERS\r
+ PUBLIC FILES\r
+ PUBLIC SYSINIT\r
+\r
+ IF HIGHMEM\r
+ PUBLIC DPBBUF_SIZ\r
+ ENDIF\r
+\r
+SYSINIT:\r
+ JMP GOINIT\r
+\r
+DOSINFO LABEL DWORD\r
+ DW 0000\r
+CURRENT_DOS_LOCATION DW 0000\r
+\r
+MSDOS LABEL DWORD\r
+ENTRY_POINT LABEL DWORD\r
+ DW 0000\r
+FINAL_DOS_LOCATION DW 0000\r
+DEVICE_LIST DD 00000000\r
+\r
+ IF HIGHMEM\r
+DPBBUF_SIZ DW (4472 + 15) / 16\r
+ ENDIF\r
+\r
+MEMORY_SIZE DW 0001\r
+DEFAULT_DRIVE DB 00\r
+BUFFERS DB 2\r
+FILES DB 8\r
+COMMAND_LINE DB 2,0,"P" ; Default Command.com Args\r
+ DB 29 DUP (0)\r
+ZERO DB 0\r
+\r
+ IF NOT NOEXEC\r
+COMEXE EXEC0 <0,COMMAND_LINE,DEFAULT_DRIVE,ZERO>\r
+ ENDIF\r
+\r
+COUNT DW 0000\r
+CHRPTR DW 0000\r
+\r
+BUFPTR LABEL DWORD ; LEAVE THIS STUFF IN ORDER!\r
+MEMLO DW 0\r
+PRMBLK LABEL WORD\r
+MEMHI DW 0\r
+LDOFF DW 0\r
+AREA DW 0\r
+\r
+PACKET DB 22\r
+ DB 0\r
+ DB 0 ; INITIALIZE CODE\r
+ DW 0\r
+ DB 8 DUP (?)\r
+UNITCOUNT DB 0\r
+BREAK_ADDR DD 0\r
+BPB_ADDR DD 0\r
+\r
+GOINIT:\r
+ CLD\r
+ XOR SI,SI\r
+ MOV DI,SI\r
+\r
+ IF MSVER\r
+ MOV CX,[MEMORY_SIZE]\r
+ CMP CX,1\r
+ JNZ NOSCAN\r
+ MOV CX,2048 ; START SCANNING AT 32K BOUNDARY\r
+ XOR BX,BX\r
+\r
+MEMSCAN:INC CX\r
+ JZ SETEND\r
+ MOV DS,CX\r
+ MOV AL,[BX]\r
+ NOT AL\r
+ MOV [BX],AL\r
+ CMP AL,[BX]\r
+ NOT AL\r
+ MOV [BX],AL\r
+ JZ MEMSCAN\r
+SETEND:\r
+ MOV [MEMORY_SIZE],CX\r
+ ENDIF\r
+\r
+ IF IBMVER OR IBMJAPVER\r
+ MOV CX,[MEMORY_SIZE]\r
+ ENDIF\r
+\r
+NOSCAN:\r
+ MOV AX,CS\r
+ MOV DS,AX\r
+ASSUME DS:SYSINITSEG\r
+\r
+ IF HIGHMEM\r
+ SUB CX,(DOSSIZE / 16) ; Leave room for DOS\r
+ SUB CX,CS:[DPBBUF_SIZ] ; Allow OEM to tune\r
+ ENDIF\r
+\r
+ MOV AX,OFFSET SYSSIZE + 15\r
+ SHR AX,1 ; Divide by 16 for paras\r
+ SHR AX,1\r
+ SHR AX,1\r
+ SHR AX,1\r
+ SUB CX,AX\r
+ MOV ES,CX\r
+ MOV CX,OFFSET SYSSIZE + 1\r
+ SHR CX,1 ; Divide by 2 to get words\r
+ REP MOVSW ; RELOCATE SYSINIT\r
+\r
+ ASSUME ES:SYSINITSEG\r
+\r
+ PUSH ES\r
+ MOV AX,OFFSET SYSIN\r
+ PUSH AX\r
+\r
+AAA PROC FAR\r
+ RET\r
+AAA ENDP\r
+;\r
+; MOVE THE DOS TO ITS PROPER LOCATION\r
+;\r
+SYSIN:\r
+\r
+ ASSUME DS:NOTHING,ES:SYSINITSEG,SS:NOTHING\r
+\r
+ MOV AX,[CURRENT_DOS_LOCATION]\r
+ MOV DS,AX\r
+ MOV AX,[FINAL_DOS_LOCATION]\r
+ MOV ES,AX\r
+\r
+ ASSUME ES:NOTHING\r
+\r
+ XOR SI,SI\r
+ MOV DI,SI\r
+ MOV CX,DOSSIZE/2\r
+ REP MOVSW\r
+\r
+ LDS SI,[DEVICE_LIST]\r
+ MOV DX,[MEMORY_SIZE]\r
+\r
+ CLI\r
+ MOV AX,CS\r
+ MOV SS,AX\r
+ MOV SP,OFFSET LOCSTACK\r
+\r
+ ASSUME SS:SYSINITSEG\r
+\r
+ IF NOT ALTVECT\r
+ STI ; Leave INTs disabled for ALTVECT\r
+ ENDIF\r
+LOCSTACK LABEL BYTE\r
+\r
+ CALL MSDOS\r
+ MOV WORD PTR [DOSINFO+2],ES ; SAVE POINTER TO DOS INFO\r
+ MOV WORD PTR [DOSINFO],DI\r
+\r
+ IF NOT IBM\r
+ IF NOT IBMJAPVER\r
+ CALL RE_INIT ; Re-call the BIOS\r
+ ENDIF\r
+ ENDIF\r
+\r
+ STI\r
+ CLD\r
+\r
+ IF HIGHMEM\r
+ PUSH DS\r
+ MOV BX,DS\r
+ ADD BX,10H\r
+ MOV ES,BX\r
+ PUSH CS\r
+ POP DS\r
+ XOR SI,SI\r
+ MOV DI,SI\r
+ MOV CX,OFFSET SYSSIZE + 1\r
+ SHR CX,1 ; Divide by 2 to get words\r
+ REP MOVSW\r
+ POP DS\r
+ PUSH ES\r
+ MOV AX,OFFSET SECONDRELOC\r
+ PUSH AX\r
+BBB PROC FAR\r
+ RET\r
+BBB ENDP\r
+\r
+SECONDRELOC:\r
+ MOV AX,CS\r
+ CLI\r
+ MOV SS,AX\r
+ MOV SP,OFFSET LOCSTACK\r
+ STI\r
+ ELSE\r
+ MOV BX,CS\r
+ SUB BX,10H\r
+ MOV ES,BX\r
+ XOR SI,SI\r
+ MOV DI,SI\r
+ MOV CX,80H\r
+ REP MOVSW\r
+ MOV AH,SET_CURRENT_PDB\r
+ INT 21H\r
+ ENDIF\r
+\r
+ PUSH DS\r
+ PUSH CS\r
+ POP DS\r
+ MOV DX,OFFSET INT24 ; SET UP INT 24 HANDLER\r
+ MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 24H\r
+ INT 21H\r
+\r
+ IF ALTVECT\r
+ MOV DX,OFFSET BOOTMES\r
+ CALL PRINT ; Print message DOSINIT couldn't\r
+ ENDIF\r
+\r
+ POP DS\r
+\r
+ MOV DL,[DEFAULT_DRIVE]\r
+ OR DL,DL\r
+ JZ NODRVSET\r
+ DEC DL ; A = 0\r
+ MOV AH,SET_DEFAULT_DRIVE\r
+ INT 21H ; SELECT THE DISK\r
+NODRVSET:\r
+\r
+ CALL DOCONF ; DO THE CONFIG STUFF\r
+\r
+ IF HIGHMEM\r
+ PUSH DS\r
+ MOV AX,OFFSET SYSSIZE + 15\r
+ MOV CL,4\r
+ SHR AX,CL ; Divide by 16 to get para\r
+ MOV CX,ES\r
+ SUB CX,AX\r
+ MOV ES,CX\r
+ PUSH CS\r
+ POP DS\r
+ XOR SI,SI\r
+ MOV DI,SI\r
+ MOV CX,OFFSET SYSSIZE + 1\r
+ SHR CX,1 ; Divide by 2 to get words\r
+ REP MOVSW\r
+ POP DS\r
+ PUSH ES\r
+ MOV AX,OFFSET THIRDRELOC\r
+ PUSH AX\r
+CCC PROC FAR\r
+ RET\r
+CCC ENDP\r
+\r
+THIRDRELOC:\r
+ MOV AX,CS\r
+ CLI\r
+ MOV SS,AX\r
+ MOV SP,OFFSET LOCSTACK\r
+ STI\r
+ ENDIF\r
+\r
+ IF NOEXEC\r
+ MOV BP,DS ; SAVE COMMAND.COM SEGMENT\r
+\r
+ PUSH DS\r
+ POP ES\r
+\r
+ MOV BX,CS\r
+ SUB BX,10H\r
+ MOV DS,BX\r
+ XOR SI,SI\r
+ MOV DI,SI\r
+ MOV CX,80H\r
+ REP MOVSW\r
+ MOV BX,ES\r
+ MOV AH,SET_CURRENT_PDB\r
+ INT 21H\r
+\r
+ MOV ES:[PDB_PARENT_PID],ES ; WE ARE THE ROOT\r
+ ENDIF\r
+\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:SYSINITSEG\r
+ MOV AL,[FILES]\r
+ CBW\r
+ MOV CX,AX\r
+ XOR BX,BX ; Close standard input\r
+ MOV AH,CLOSE\r
+ INT 21H\r
+ MOV BX,2\r
+RCCLLOOP: ; Close everybody but standard output\r
+ MOV AH,CLOSE\r
+ INT 21H\r
+ INC BX\r
+ LOOP RCCLLOOP\r
+\r
+ MOV DX,OFFSET CONDEV\r
+ MOV AL,2\r
+ MOV AH,OPEN ; OPEN CON FOR READ/WRITE\r
+ STC\r
+ INT 21H\r
+ JNC GOAUX\r
+ CALL BADFIL\r
+ JMP SHORT GOAUX2\r
+\r
+GOAUX: PUSH AX\r
+ MOV BX,1 ; close standard output\r
+ MOV AH,CLOSE\r
+ INT 21H\r
+ POP AX\r
+\r
+ MOV BX,AX ; New device handle\r
+ MOV AH,XDUP\r
+ INT 21H ; Dup to 1, STDOUT\r
+ MOV AH,XDUP\r
+ INT 21H ; Dup to 2, STDERR\r
+\r
+GOAUX2: MOV DX,OFFSET AUXDEV\r
+ MOV AL,2 ; READ/WRITE ACCESS\r
+ CALL OPEN_DEV\r
+\r
+ MOV DX,OFFSET PRNDEV\r
+ MOV AL,1 ; WRITE ONLY\r
+ CALL OPEN_DEV\r
+;\r
+; SET UP THE PARAMETERS FOR COMMAND\r
+;\r
+GOSET:\r
+ MOV SI,OFFSET COMMAND_LINE+1\r
+\r
+ IF NOEXEC\r
+ MOV DI,81H\r
+ ELSE\r
+ PUSH DS\r
+ POP ES\r
+ MOV DI,SI\r
+ ENDIF\r
+\r
+ MOV CL,-1\r
+COMTRANLP: ; FIND LENGTH OF COMMAND LINE\r
+ INC CL\r
+ LODSB\r
+ STOSB ; COPY COMMAND LINE IN\r
+ OR AL,AL\r
+ JNZ COMTRANLP\r
+ DEC DI\r
+ MOV AL,0DH\r
+ STOSB\r
+\r
+ IF NOEXEC\r
+ MOV ES:[80H],CL\r
+ MOV AL,[DEFAULT_DRIVE]\r
+ MOV ES:[5CH],AL\r
+ ELSE\r
+ MOV [COMMAND_LINE],CL ; Count\r
+ ENDIF\r
+\r
+ PUSH CS\r
+ POP ES\r
+\r
+ ASSUME ES:SYSINITSEG\r
+\r
+ MOV DX,OFFSET COMMND ; NOW POINTING TO FILE DESCRIPTION\r
+\r
+ IF NOEXEC\r
+ MOV ES,BP ; SET LOAD ADDRESS\r
+ MOV BX,100H\r
+ CALL LDFIL ; READ IN COMMAND\r
+ JC COMERR\r
+ MOV DS,BP\r
+ CLI\r
+ MOV DX,80H\r
+ MOV SS,BP\r
+ MOV SP,DX\r
+ STI\r
+\r
+ XOR AX,AX ; PUSH A WORD OF ZEROS\r
+ PUSH AX\r
+ MOV AH,SET_DMA ; SET DISK TRANFER ADDRESS\r
+ INT 21H\r
+ PUSH BP ; SET HIGH PART OF JUMP ADDRESS\r
+ MOV AX,100H\r
+ PUSH AX ; SET LOW PART OF JUMP ADDRESS\r
+CCC PROC FAR\r
+ RET ; CRANK UP COMMAND!\r
+CCC ENDP\r
+\r
+ ELSE\r
+ MOV BX,OFFSET COMEXE\r
+ MOV WORD PTR [BX.EXEC0_COM_LINE+2],CS\r
+ MOV WORD PTR [BX.EXEC0_5C_FCB+2],CS\r
+ MOV WORD PTR [BX.EXEC0_6C_FCB+2],CS\r
+\r
+ XOR AX,AX\r
+ MOV AH,EXEC\r
+ STC ; IN CASE OF INT 24\r
+ INT 21H ; GO START UP COMMAND\r
+ ENDIF\r
+\r
+COMERR:\r
+ MOV DX,OFFSET BADCOM ; WANT TO PRINT COMMAND ERROR\r
+ CALL BADFIL\r
+STALL: JMP STALL\r
+\r
+DOCONF:\r
+ PUSH CS\r
+ POP DS\r
+\r
+ ASSUME DS:SYSINITSEG\r
+\r
+ MOV BX,0FFFFH\r
+ MOV AH,ALLOC\r
+ INT 21H ; FIRST TIME FAILS\r
+ MOV AH,ALLOC\r
+ INT 21H ; SECOND TIME GETS IT\r
+ MOV [AREA],AX\r
+\r
+ IF HIGHMEM\r
+ ADD AX,BX\r
+ ENDIF\r
+\r
+ MOV [MEMHI],AX\r
+\r
+ MOV AX,(CHAR_OPER SHL 8) ; GET SWITCH CHARACTER\r
+ INT 21H\r
+ MOV [COMMAND_LINE+1],DL\r
+\r
+ MOV DX,OFFSET CONFIG ; NOW POINTING TO FILE DESCRIPTION\r
+ MOV AX,OPEN SHL 8 ; OPEN FILE "CONFIG.SYS"\r
+ STC ; IN CASE OF INT 24\r
+ INT 21H ; FUNCTION REQUEST\r
+ JC ENDFILE\r
+ JMP NOPROB ; PROBLEM WITH OPEN\r
+\r
+ENDFILE:\r
+ PUSH CS\r
+ POP DS\r
+ CALL ROUND\r
+ MOV AL,[FILES]\r
+ SUB AL,5\r
+ JBE DOBUFF\r
+ CBW\r
+\r
+ IF HIGHMEM\r
+ PUSH AX\r
+ MOV BL,SIZE SF_ENTRY\r
+ MUL BL\r
+ ADD AX,15+6\r
+ MOV CL,4\r
+ SHR AX,CL\r
+ SUB [MEMHI],AX\r
+ POP AX\r
+ ENDIF\r
+\r
+ MOV BX,[MEMLO]\r
+ MOV DX,[MEMHI]\r
+ LDS DI,[DOSINFO] ; GET POINTER TO DOS DATA\r
+ LDS DI,[DI+SFT_ADDR] ; DS:BP POINTS TO SFT\r
+ MOV WORD PTR [DI+SFT_LINK],BX\r
+ MOV WORD PTR [DI+SFT_LINK+2],DX ; SET POINTER TO NEW SFT\r
+ PUSH CS\r
+ POP DS\r
+ LES DI,DWORD PTR [MEMLO] ; POINT TO NEW SFT\r
+ MOV WORD PTR ES:[DI+SFT_LINK],-1\r
+ MOV ES:[DI+SFT_COUNT],AX\r
+ MOV BL,SIZE SF_ENTRY\r
+ MUL BL ; AX = NUMBER OF BYTES TO CLEAR\r
+ MOV CX,AX\r
+\r
+ IF HIGHMEM\r
+ MOV AX,6\r
+ ELSE\r
+ ADD [MEMLO],AX ; ALLOCATE MEMORY\r
+ MOV AX,6\r
+ ADD [MEMLO],AX ; REMEMBER THE HEADER TOO\r
+ ENDIF\r
+\r
+ ADD DI,AX\r
+ XOR AX,AX\r
+ REP STOSB ; CLEAN OUT THE STUFF\r
+\r
+DOBUFF: CALL ROUND\r
+\r
+ DEC [BUFFERS]\r
+ JZ BUF1\r
+\r
+ PUSH DS\r
+ LES DI,BUFPTR\r
+ LDS BX,DOSINFO\r
+\r
+ IF HIGHMEM\r
+ MOV AX,[BX.MAXSEC]\r
+ ADD AX,BUFINSIZ + 15\r
+ MOV CL,4\r
+ SHR AX,CL\r
+ SUB CS:[MEMHI],AX\r
+ MOV ES,CS:[MEMHI]\r
+ ENDIF\r
+\r
+ MOV AX,WORD PTR [BX.BUFFHEAD]\r
+ MOV WORD PTR ES:[DI.NEXTBUF],AX\r
+ MOV AX,WORD PTR [BX.BUFFHEAD+2]\r
+ MOV WORD PTR ES:[DI.NEXTBUF+2],AX\r
+\r
+ MOV WORD PTR [BX.BUFFHEAD],DI\r
+ MOV WORD PTR [BX.BUFFHEAD+2],ES\r
+\r
+ MOV WORD PTR ES:[DI.BUFDRV],00FFH ; NEW BUFFER FREE\r
+ MOV BX,[BX.MAXSEC]\r
+ POP DS\r
+\r
+ IF NOT HIGHMEM\r
+ ADD BX,BUFINSIZ\r
+ ADD [MEMLO],BX\r
+ ENDIF\r
+\r
+ JMP DOBUFF\r
+\r
+BUF1: CALL ROUND\r
+ MOV BX,[MEMHI]\r
+ MOV AX,[AREA]\r
+ MOV ES,AX ; CALC WHAT WE NEEDED\r
+ SUB BX,AX\r
+\r
+ IF HIGHMEM\r
+ DEC BX ; Arena\r
+ PUSH BX\r
+ ENDIF\r
+\r
+ MOV AH,SETBLOCK\r
+ INT 21H ; GIVE THE REST BACK\r
+\r
+ IF NOT HIGHMEM\r
+ PUSH ES\r
+ MOV AX,ES\r
+ DEC AX\r
+ MOV ES,AX\r
+ MOV ES:[arena_owner],8 ; Set impossible owner\r
+ POP ES\r
+ ENDIF\r
+\r
+ IF HIGHMEM\r
+ MOV BX,0FFFFH\r
+ MOV AH,ALLOC\r
+ INT 21H\r
+ MOV AH,ALLOC\r
+ INT 21H\r
+\r
+ PUSH ES\r
+ DEC AX\r
+ MOV ES,AX\r
+ MOV ES:[arena_owner],8 ; Set impossible owner\r
+ POP ES\r
+\r
+ IF NOT NOEXEC\r
+ MOV ES,[AREA]\r
+ MOV AH,DEALLOC\r
+ INT 21H\r
+ ENDIF\r
+\r
+ POP BX\r
+ MOV AX,[AREA]\r
+ MOV DS,AX\r
+ ADD AX,BX\r
+ MOV ES,AX\r
+ ELSE\r
+ IF NOEXEC\r
+ MOV BX,0FFFFH ; ALLOCATE THE REST OF MEM FOR COMMAND\r
+ MOV AH,ALLOC\r
+ INT 21H\r
+ MOV AH,ALLOC\r
+ INT 21H\r
+ MOV DS,AX\r
+ ENDIF\r
+ ENDIF\r
+\r
+ RET\r
+\r
+BADOP: MOV DX,OFFSET BADOPM ; WANT TO PRINT COMMAND ERROR\r
+ CALL PRINT\r
+ JMP COFF\r
+\r
+NOPROB: ; GET FILE SIZE (NOTE < 64K!!)\r
+ MOV BX,AX\r
+ XOR CX,CX\r
+ XOR DX,DX\r
+ MOV AX,(LSEEK SHL 8) OR 2\r
+ INT 21H\r
+ MOV [COUNT],AX\r
+ XOR DX,DX\r
+ MOV AX,LSEEK SHL 8 ; Reset pointer to beginning of file\r
+ INT 21H\r
+ MOV DX,CS\r
+\r
+ IF HIGHMEM\r
+ MOV AX,OFFSET SYSSIZE + 15\r
+ MOV CL,4\r
+ SHR AX,CL\r
+ ADD DX,AX\r
+ ELSE\r
+ MOV AX,[COUNT]\r
+ ADD AX,15\r
+ MOV CL,4\r
+ SHR AX,CL ; NUMBER OF SEGMENTS\r
+ SUB DX,AX\r
+ SUB DX,11H ; ROOM FOR HEADER\r
+ ENDIF\r
+\r
+ MOV DS,DX\r
+ MOV ES,DX\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+ XOR DX,DX\r
+ MOV CX,[COUNT]\r
+ MOV AH,READ\r
+ STC ; IN CASE OF INT 24\r
+ INT 21H ; Function request\r
+ PUSHF\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:SYSINITSEG\r
+ PUSH AX\r
+ MOV AH,CLOSE\r
+ INT 21H\r
+ POP AX\r
+ POPF\r
+ JC CONFERR ; IF NOT WE'VE GOT A PROBLEM\r
+ CMP CX,AX\r
+ JZ GETCOM ; COULDN'T READ THE FILE\r
+CONFERR:\r
+ MOV DX,OFFSET CONFIG ; WANT TO PRINT CONFIG ERROR\r
+ CALL BADFIL\r
+ENDFILV:JMP ENDFILE\r
+\r
+GETCOM:\r
+ CALL ORGANIZE ; ORGANIZE THE FILE\r
+ CALL GETCHR\r
+\r
+CONFLP: JC ENDFILV\r
+ MOV AH,AL\r
+ CALL GETCHR\r
+\r
+ CMP AH,'B' ; BUFFER COMMAND?\r
+ JNZ TRYC\r
+ CALL GETNUM\r
+ JZ COFF\r
+ CMP AX,100\r
+ JAE badop\r
+ MOV [BUFFERS],AL\r
+ JMP SHORT COFF\r
+\r
+TRYC: CMP AH,'C'\r
+ JZ GOTC\r
+ JMP TRYD\r
+GOTC:\r
+ CMP AL,'O' ; FIRST LETTER OF "ON"\r
+ JNZ COFF\r
+ CALL GETCHR\r
+ JC ENDFILV\r
+ CMP AL,'N' ; SECOND LETTER OF "ON"\r
+ JNZ COFF\r
+ MOV AH,SET_CTRL_C_TRAPPING ; TURN ON CONTROL-C CHECK\r
+ MOV AL,1\r
+ MOV DL,AL\r
+ INT 21H\r
+\r
+COFF: PUSH CS\r
+ POP DS\r
+ CALL NEWLINE\r
+ JMP CONFLP\r
+\r
+TRYD: CMP AH,'D'\r
+ JZ GOTD\r
+ JMP TRYF\r
+GOTD: MOV BX,CS\r
+ MOV DS,BX\r
+\r
+ MOV WORD PTR [BPB_ADDR],SI\r
+ MOV WORD PTR [BPB_ADDR+2],ES\r
+\r
+ CALL ROUND\r
+\r
+ IF HIGHMEM\r
+ PUSH DS\r
+ PUSH ES\r
+ POP DS\r
+ MOV DX,SI\r
+ MOV AX,OPEN SHL 8\r
+ STC ; In case INT 24H\r
+ INT 21H\r
+ POP DS\r
+ JC BADBRK\r
+ MOV BX,AX\r
+ XOR DX,DX\r
+ MOV CX,DX\r
+ MOV AX,(LSEEK SHL 8) OR 2\r
+ INT 21H\r
+ PUSH AX\r
+ MOV AH,CLOSE\r
+ INT 21H\r
+ POP AX ; DX:AX is size of file\r
+ ADD AX,15\r
+ ADC DX,0\r
+ MOV CL,4\r
+ SHR AX,CL\r
+ MOV CL,12\r
+ SHL DX,CL\r
+ OR AX,DX ; AX is size in PARA\r
+ MOV CX,[MEMHI]\r
+ SUB [MEMHI],AX\r
+ JNC SIZEOK\r
+ MOV [MEMHI],CX ; Not enough memory\r
+ JMP SHORT BADBRK\r
+SIZEOK:\r
+ MOV BX,CS\r
+ ENDIF\r
+\r
+ XOR AX,AX\r
+ MOV WORD PTR [ENTRY_POINT],AX\r
+ MOV AX,[MEMHI]\r
+ MOV WORD PTR [ENTRY_POINT+2],AX ; SET ENTRY POINT\r
+\r
+\r
+ IF NOT NOEXEC\r
+ MOV [LDOFF],AX ; SET LOAD OFFSET\r
+ ENDIF\r
+\r
+ PUSH ES\r
+ POP DS\r
+ MOV DX,SI ; DS:DX POINTS TO FILE NAME\r
+\r
+ IF NOEXEC\r
+ LES BX,DWORD PTR CS:[MEMLO]\r
+ CALL LDFIL ; LOAD IN THE DEVICE DRIVER\r
+ ELSE\r
+ MOV ES,BX\r
+ MOV BX,OFFSET PRMBLK ; ES:BX POINTS TO PARAMETERS\r
+ MOV AL,3\r
+ MOV AH,EXEC\r
+ STC ; IN CASE OF INT 24\r
+ INT 21H ; LOAD IN THE DEVICE DRIVER\r
+ ENDIF\r
+\r
+ PUSH DS\r
+ POP ES ; ES:SI BACK TO CONFIG.SYS\r
+ PUSH CS\r
+ POP DS ; DS BACK TO SYSINIT\r
+ JNC GOODLD\r
+BADBRK: CALL BADLOAD\r
+ JMP COFF\r
+\r
+GOODLD: PUSH ES ; INITIALIZE THE DEVICE\r
+ PUSH SI\r
+\r
+ PUSH CS\r
+ POP ES\r
+ MOV BX,SDEVSTRAT\r
+ CALL CALLDEV\r
+ MOV BX,SDEVINT\r
+ CALL CALLDEV\r
+\r
+ PUSH CS\r
+ POP DS\r
+\r
+ IF NOT HIGHMEM\r
+ MOV AX,WORD PTR [BREAK_ADDR+2] ; REMOVE THE INIT CODE\r
+ CMP AX,[MEMORY_SIZE]\r
+ JB BREAKOK\r
+ POP SI\r
+ POP ES\r
+ JMP BADBRK\r
+BREAKOK:\r
+\r
+ MOV [MEMHI],AX\r
+ MOV AX,WORD PTR [BREAK_ADDR]; REMOVE THE INIT CODE\r
+ MOV [MEMLO],AX\r
+ ENDIF\r
+\r
+ LDS DX,[ENTRY_POINT] ; SET DS:DX TO HEADER\r
+ MOV SI,DX\r
+ ADD SI,SDEVATT ; DS:SI POINTS TO ATTRIBUTES\r
+ LES DI,CS:[DOSINFO] ; ES:DI POINT TO DOS INFO\r
+ MOV AX,DS:[SI] ; GET ATTRIBUTES\r
+ TEST AX,DEVTYP ; TEST IF BLOCK DEV\r
+ JZ ISBLOCK\r
+\r
+ TEST AX,ISCIN ; IS IT A CONSOLE IN?\r
+ JZ TRYCLK\r
+ MOV WORD PTR ES:[DI.BCON],DX\r
+ MOV WORD PTR ES:[DI.BCON+2],DS\r
+\r
+TRYCLK: TEST AX,ISCLOCK ; IS IT A CLOCK DEVICE?\r
+ JZ GOLINK\r
+ MOV WORD PTR ES:[DI+BCLOCK],DX\r
+ MOV WORD PTR ES:[DI+BCLOCK+2],DS\r
+GOLINK: JMP LINKIT\r
+\r
+ISBLOCK:\r
+ MOV AL,CS:[UNITCOUNT] ; IF NO UNITS FOUND....\r
+ OR AL,AL\r
+ JNZ PERDRV\r
+\r
+ IF NOT HIGHMEM\r
+ MOV CS:[MEMLO],0 ; ...ERASE THE DEVICE\r
+ ENDIF\r
+\r
+ MOV AX,-1\r
+ JMP ENDDEV\r
+\r
+PERDRV:\r
+ CBW\r
+ MOV CX,AX\r
+ MOV DH,AH\r
+ MOV DL,ES:[DI.NUMIO] ; GET NUMBER OF DEVICES\r
+ ADD ES:[DI.NUMIO],AL ; UPDATE THE AMOUNT\r
+\r
+ LDS BX,CS:[BPB_ADDR] ; POINT TO BPB ARRAY\r
+PERUNIT:\r
+ LES BP,CS:[DOSINFO]\r
+ LES BP,DWORD PTR ES:[BP.DPBHEAD]; GET FIRST DPB\r
+\r
+SCANDPB:CMP WORD PTR ES:[BP.DPB_NEXT_DPB],-1\r
+ JZ FOUNDPB\r
+ LES BP,ES:[BP.DPB_NEXT_DPB]\r
+ JMP SCANDPB\r
+FOUNDPB:\r
+ MOV AX,CS:[MEMLO]\r
+ MOV WORD PTR ES:[BP.DPB_NEXT_DPB],AX\r
+\r
+ IF HIGHMEM\r
+ MOV AX,(DPBSIZ + 15) / 16\r
+ SUB CS:[MEMHI],AX\r
+ ENDIF\r
+\r
+ MOV AX,CS:[MEMHI]\r
+ MOV WORD PTR ES:[BP.DPB_NEXT_DPB+2],AX\r
+ LES BP,DWORD PTR CS:[MEMLO]\r
+\r
+ IF NOT HIGHMEM\r
+ ADD WORD PTR CS:[MEMLO],DPBSIZ\r
+ ENDIF\r
+\r
+ MOV WORD PTR ES:[BP.DPB_NEXT_DPB],-1\r
+ MOV ES:[BP.DPB_FIRST_ACCESS],-1\r
+\r
+ MOV SI,[BX] ; DS:SI POINTS TO BPB\r
+ INC BX\r
+ INC BX ; POINT TO NEXT GUY\r
+ MOV WORD PTR ES:[BP.DPB_DRIVE],DX\r
+ MOV AH,SETDPB ; HIDDEN SYSTEM CALL\r
+ INT 21H\r
+ MOV AX,ES:[BP.DPB_SECTOR_SIZE]\r
+ PUSH ES\r
+ LES DI,CS:[DOSINFO] ; ES:DI POINT TO DOS INFO\r
+ CMP AX,ES:[DI.MAXSEC]\r
+ POP ES\r
+ JBE NOTMAX\r
+ POP SI\r
+ POP ES\r
+ MOV DX,OFFSET BADSIZ_PRE\r
+ MOV BX,OFFSET BADSIZ_POST\r
+ CALL PRNERR\r
+ JMP COFF\r
+\r
+NOTMAX: PUSH DS\r
+ PUSH DX\r
+ LDS DX,CS:[ENTRY_POINT]\r
+ MOV WORD PTR ES:[BP.DPB_DRIVER_ADDR],DX\r
+ MOV WORD PTR ES:[BP.DPB_DRIVER_ADDR+2],DS\r
+ POP DX\r
+ POP DS\r
+ INC DX\r
+ INC DH\r
+ LOOP PERUNIT\r
+\r
+LINKIT:\r
+ LES DI,CS:[DOSINFO] ; ES:DI = DOS TABLE\r
+ MOV CX,WORD PTR ES:[DI.DEVHEAD] ; DX:CX = HEAD OF LIST\r
+ MOV DX,WORD PTR ES:[DI.DEVHEAD+2]\r
+\r
+ LDS SI,CS:[ENTRY_POINT] ; DS:SI = DEVICE LOCATION\r
+ MOV WORD PTR ES:[DI.DEVHEAD],SI ; SET HEAD OF LIST IN DOS\r
+ MOV WORD PTR ES:[DI.DEVHEAD+2],DS\r
+ MOV AX,DS:[SI] ; GET POINTER TO NEXT DEVICE\r
+ MOV WORD PTR CS:[ENTRY_POINT],AX; AND SAVE IT\r
+\r
+ MOV WORD PTR DS:[SI],CX ; LINK IN THE DRIVER\r
+ MOV WORD PTR DS:[SI+2],DX\r
+ENDDEV:\r
+ POP SI\r
+ POP ES\r
+ INC AX ; AX = FFFF?\r
+ JZ COFFV\r
+ JMP GOODLD ; OTHERWISE PRETEND WE LOADED IT IN\r
+COFFV: JMP COFF\r
+\r
+TRYQ:\r
+ CMP AH,'Q'\r
+ JNZ TRYW\r
+ CALL GETNUM\r
+ JZ COFFV\r
+ OR AH,AH\r
+ JNZ COFFV\r
+ MOV AH,INTERNATIONAL ; AL is country code\r
+ MOV DX,-1 ; Set country\r
+ INT 21H\r
+ JNC COFFV\r
+ MOV DX,OFFSET BADCOUNTRY\r
+ CALL PRINT\r
+ JMP COFFV\r
+\r
+TRYF:\r
+ CMP AH,'F'\r
+ JNZ TRYQ\r
+ CALL GETNUM\r
+ JZ COFFV\r
+ CMP AX,100\r
+ JAE TryX\r
+ MOV [FILES],AL\r
+ JMP COFFV\r
+TRYW:\r
+ CMP AH,'W'\r
+ JNZ TRYA\r
+ MOV DL,AL\r
+ MOV AX,(CHAR_OPER SHL 8) OR 1 ; SET SWITCH CHARACTER\r
+ MOV [COMMAND_LINE+1],DL\r
+ INT 21H\r
+ JMP COFF\r
+\r
+TRYA:\r
+ CMP AH,'A'\r
+ JNZ TRYS\r
+ CMP AL,'F' ; FIRST LETTER OF "FALSE"\r
+ JNZ COFFJ\r
+ MOV AX,(CHAR_OPER SHL 8) OR 3 ; TURN ON "/DEV" PREFIX\r
+ XOR DL,DL\r
+ INT 21H\r
+COFFJ: JMP COFF\r
+\r
+TRYS:\r
+ CMP AH,'S'\r
+ JNZ TRYX\r
+ MOV [COMMAND_LINE+1],0\r
+ MOV DI,OFFSET COMMND + 1\r
+ MOV [DI-1],AL\r
+STORESHELL:\r
+ CALL GETCHR\r
+ OR AL,AL\r
+ JZ GETSHPARMS\r
+ CMP AL," "\r
+ JB ENDSH\r
+ MOV [DI],AL\r
+ INC DI\r
+ JMP STORESHELL\r
+\r
+ENDSH:\r
+ MOV BYTE PTR [DI],0\r
+ CALL GETCHR\r
+ CMP AL,10\r
+ JNZ CONV\r
+ CALL GETCHR\r
+CONV: JMP CONFLP\r
+\r
+TRYX:\r
+ JMP BADOP\r
+\r
+GETSHPARMS:\r
+ MOV BYTE PTR [DI],0\r
+ MOV DI,OFFSET COMMAND_LINE+1\r
+PARMLOOP:\r
+ CALL GETCHR\r
+ CMP AL," "\r
+ JB ENDSH\r
+ MOV [DI],AL\r
+ INC DI\r
+ JMP PARMLOOP\r
+\r
+GETCHR: MOV CX,COUNT\r
+ JCXZ NOCHAR\r
+ MOV SI,CHRPTR\r
+ MOV AL,ES:[SI]\r
+ DEC COUNT\r
+ INC CHRPTR\r
+ CLC\r
+ RET\r
+NOCHAR: STC\r
+ RET\r
+\r
+ORGANIZE:\r
+ MOV CX,[COUNT]\r
+ JCXZ NOCHAR\r
+ CALL MAPCASE\r
+ XOR SI,SI\r
+ MOV DI,SI\r
+\r
+ORG1: CALL GET ; SKIP LEADING CONTROL CHARACTERS\r
+ CMP AL,' '\r
+ JB ORG1\r
+\r
+ PUSH CX\r
+ PUSH SI\r
+ PUSH DI\r
+ MOV BP,SI\r
+ DEC BP\r
+ MOV SI,OFFSET COMTAB ; Prepare to search command table\r
+ MOV CH,0\r
+FINDCOM:\r
+ MOV DI,BP\r
+ MOV CL,[SI]\r
+ INC SI\r
+ JCXZ NOCOM\r
+ REPE CMPSB\r
+ LAHF\r
+ ADD SI,CX ; Bump to next position without affecting flags\r
+ SAHF\r
+ LODSB ; Get indicator letter\r
+ JNZ FINDCOM\r
+ POP DI\r
+ POP SI\r
+ POP CX\r
+ JMP SHORT GOTCOM\r
+\r
+NOCOM:\r
+ POP DI\r
+ POP SI\r
+ POP CX\r
+ MOV AL,'Z'\r
+GOTCOM: STOSB ; SAVE INDICATOR CHAR IN BUFFER\r
+\r
+ORG2: CALL GET2 ; SKIP NAME UNTIL DELIMETER\r
+ CALL DELIM ;\r
+ JNZ ORG2\r
+\r
+ CALL GET ; GET CHARS TO RIGHT OF EQUALS SIGN\r
+ STOSB\r
+\r
+ORG4: CALL GET2\r
+ STOSB\r
+ CMP AL,' '\r
+ JA ORG4\r
+ CMP AL,10\r
+ JZ ORG1\r
+\r
+ MOV BYTE PTR ES:[DI-1],0\r
+ORG5: CALL GET2\r
+ STOSB\r
+ CMP AL,10\r
+ JNZ ORG5\r
+ JMP ORG1\r
+\r
+GET2:\r
+ JCXZ NOGET\r
+ MOV AL,ES:[SI]\r
+ INC SI\r
+ DEC CX\r
+ RET\r
+\r
+GET: JCXZ NOGET\r
+ MOV AL,ES:[SI]\r
+ INC SI\r
+ DEC CX\r
+ CALL DELIM\r
+ JZ GET\r
+GRET: RET\r
+\r
+\r
+DELIM: CMP AL,' '\r
+ JZ GRET\r
+ CMP AL,9\r
+ JZ GRET\r
+ CMP AL,'='\r
+ JZ GRET\r
+ CMP AL,','\r
+ JZ GRET\r
+ CMP AL,';'\r
+ RET\r
+\r
+\r
+NOGET: POP CX\r
+ MOV COUNT,DI\r
+ XOR SI,SI\r
+ MOV CHRPTR,SI\r
+ RET\r
+;\r
+; NEWLINE RETURNS WITH FIRST CHARACTER OF NEXT LINE\r
+;\r
+NEWLINE:CALL GETCHR ; SKIP NON-CONTROL CHARACTERS\r
+ JC NONEW\r
+ CMP AL,10 ; LOOK FOR LINE FEED\r
+ JNZ NEWLINE\r
+ CALL GETCHR\r
+NONEW: RET\r
+\r
+MAPCASE:\r
+ PUSH CX\r
+ PUSH SI\r
+ PUSH DS\r
+ PUSH ES\r
+ POP DS\r
+ XOR SI,SI\r
+CONVLOOP:\r
+ LODSB\r
+\r
+ IF KANJI\r
+ CALL TESTKANJ\r
+ JZ NORMCONV\r
+ INC SI ; Skip next char\r
+ DEC CX\r
+ JCXZ CONVDONE ; Just ignore 1/2 kanji error\r
+; Fall through, know AL is not in 'a'-'z' range\r
+NORMCONV:\r
+ ENDIF\r
+\r
+ CMP AL,'a'\r
+ JB NOCONV\r
+ CMP AL,'z'\r
+ JA NOCONV\r
+ SUB AL,20H\r
+ MOV [SI-1],AL\r
+NOCONV:\r
+ LOOP CONVLOOP\r
+CONVDONE:\r
+ POP DS\r
+ POP SI\r
+ POP CX\r
+ RET\r
+\r
+ IF KANJI\r
+TESTKANJ:\r
+ CMP AL,81H\r
+ JB NOTLEAD\r
+ CMP AL,9FH\r
+ JBE ISLEAD\r
+ CMP AL,0E0H\r
+ JB NOTLEAD\r
+ CMP AL,0FCH\r
+ JBE ISLEAD\r
+NOTLEAD:\r
+ PUSH AX\r
+ XOR AX,AX ; Set zero\r
+ POP AX\r
+ RET\r
+\r
+ISLEAD:\r
+ PUSH AX\r
+ XOR AX,AX ; Set zero\r
+ INC AX ; Reset zero\r
+ POP AX\r
+ RET\r
+ ENDIF\r
+\r
+ASSUME DS:NOTHING\r
+\r
+ROUND: MOV AX,[MEMLO]\r
+\r
+ IF NOT HIGHMEM\r
+ ADD AX,15\r
+ ENDIF\r
+\r
+ SHR AX,1\r
+ SHR AX,1\r
+ SHR AX,1\r
+ SHR AX,1\r
+ ADD [MEMHI],AX\r
+ XOR AX,AX\r
+ MOV [MEMLO],AX\r
+ RET\r
+\r
+CALLDEV:MOV DS,WORD PTR CS:[ENTRY_POINT+2]\r
+ ADD BX,WORD PTR CS:[ENTRY_POINT]; Do a little relocation\r
+ MOV AX,DS:[BX]\r
+ PUSH WORD PTR CS:[ENTRY_POINT]\r
+ MOV WORD PTR CS:[ENTRY_POINT],AX\r
+ MOV BX,OFFSET PACKET\r
+ CALL [ENTRY_POINT]\r
+ POP WORD PTR CS:[ENTRY_POINT]\r
+ RET\r
+\r
+BADNUM: POP AX ; POP RETURN ADDRESS\r
+ JMP BADOP\r
+\r
+ToDigit:\r
+ SUB AL,'0'\r
+ JB NotDig\r
+ CMP AL,9\r
+ JA NotDig\r
+ CLC\r
+ RET\r
+NotDig: STC\r
+ RET\r
+\r
+GETNUM: XOR BX,BX ; running count is zero\r
+B2: CALL ToDigit ; do we have a digit\r
+ JC BadNum ; no, bomb\r
+ XCHG AX,BX ; put total in AX\r
+ PUSH BX ; save digit\r
+ MOV BX,10 ; base of arithmetic\r
+ MUL BX ; shift by one decimal digit\r
+ POP BX ; get back digit\r
+ ADD AL,BL ; get total\r
+ ADC AH,0 ; make that 16 bits\r
+ JC BADNUM ; too big a number\r
+ XCHG AX,BX ; stash total\r
+ CALL GETCHR ; GET NEXT DIGIT\r
+ JC B1 ; no more characters\r
+ OR AL,AL ; end of line separator?\r
+ JNZ B2 ; no, try as a valid character\r
+ INC COUNT ; one more character to scan\r
+ DEC CHRPTR ; back up over separator\r
+B1: MOV AX,BX ; get proper count\r
+ OR AX,AX\r
+ RET\r
+;\r
+; ES:SI POINTS TO FILE NAME (NUL TERMINATED)\r
+; DS:DX POINTS TO STRING TO OUTPUT IN FRONT OF NAME ($ TERM)\r
+;\r
+BADFIL:\r
+ PUSH CS\r
+ POP ES\r
+ MOV SI,DX\r
+BADLOAD:\r
+ MOV DX,OFFSET BADLD_PRE ; WANT TO PRINT CONFIG ERROR\r
+ MOV BX,OFFSET BADLD_POST\r
+PRNERR:\r
+ PUSH CS\r
+ POP DS\r
+ MOV AH,STD_CON_STRING_OUTPUT\r
+ INT 21H\r
+PRN1: MOV DL,ES:[SI]\r
+ OR DL,DL\r
+ JZ PRN2\r
+ MOV AH,STD_CON_OUTPUT\r
+ INT 21H\r
+ INC SI\r
+ JMP PRN1\r
+PRN2: MOV DX,BX\r
+PRINT: MOV AH,STD_CON_STRING_OUTPUT\r
+ INT 21H\r
+ RET\r
+;\r
+; LOAD FILE CALLED [DS:DX] AT MEMORY LOCATION ES:BX\r
+;\r
+LDFIL:\r
+ PUSH AX\r
+ PUSH BX\r
+ PUSH CX\r
+ PUSH DX\r
+ PUSH SI\r
+ PUSH DS\r
+ PUSH BX\r
+\r
+ XOR AX,AX ; OPEN THE FILE\r
+ MOV AH,OPEN\r
+ STC ; IN CASE OF INT 24\r
+ INT 21H\r
+ POP DX ; Trans addr is DS:DX\r
+ JC LDRET\r
+\r
+ PUSH ES ; READ THE FILE IN\r
+ POP DS\r
+ MOV BX,AX ; Handle in BX\r
+ MOV CX,0FF00H\r
+ MOV AH,READ\r
+ STC ; IN CASE OF INT 24\r
+ INT 21H\r
+ JC LDRET\r
+ MOV SI,DX ; CHECK FOR EXE FILE\r
+ CMP WORD PTR [SI],"ZM"\r
+ JNZ LDCLS\r
+LDERR: STC\r
+ JMP SHORT LDRET\r
+\r
+LDCLS: MOV AH,CLOSE ; CLOSE THE FILE\r
+ STC\r
+ INT 21H\r
+\r
+LDRET: POP DS\r
+ POP SI\r
+ POP DX\r
+ POP CX\r
+ POP BX\r
+ POP AX\r
+ RET\r
+;\r
+; OPEN DEVICE POINTED TO BY DX, AL HAS ACCESS CODE\r
+; IF UNABLE TO OPEN DO A DEVICE OPEN NULL DEVICE INSTEAD\r
+;\r
+OPEN_DEV:\r
+ CALL OPEN_FILE\r
+ JNC OPEN_DEV3\r
+OPEN_DEV1:\r
+ MOV DX,OFFSET NULDEV\r
+ CALL OPEN_FILE\r
+OPEN_DEV2:\r
+ RET\r
+OPEN_DEV3:\r
+ XOR AX,AX ; GET DEVICE INFO\r
+ MOV AH,IOCTL\r
+ INT 21H\r
+ TEST DL,10000000B\r
+ JNZ OPEN_DEV2\r
+ MOV AH,CLOSE\r
+ INT 21H\r
+ JMP OPEN_DEV1\r
+\r
+OPEN_FILE:\r
+ MOV AH,OPEN\r
+ STC\r
+ INT 21H\r
+ RET\r
+\r
+INT24: ADD SP,6 ; RESTORE MACHINE STATE\r
+ POP AX\r
+ POP BX\r
+ POP CX\r
+ POP DX\r
+ POP SI\r
+ POP DI\r
+ POP BP\r
+ POP DS\r
+ POP ES\r
+ PUSH AX\r
+ MOV AH,GET_DEFAULT_DRIVE ; INITIALIZE DOS\r
+ INT 21H\r
+ POP AX\r
+ IRET ; BACK TO USER\r
+\r
+ IF ALTVECT\r
+BOOTMES DB 13\r
+TEN: DB 10\r
+ DB "MS-DOS version "\r
+ DB MAJOR_VERSION + "0"\r
+ DB "."\r
+ DB (MINOR_VERSION / 10) + "0"\r
+ DB (MINOR_VERSION MOD 10) + "0"\r
+ DB 13,10\r
+ DB "Copyright 1981,82 Microsoft Corp.",13,10,"$"\r
+ ENDIF\r
+\r
+NULDEV DB "\DEV\NUL",0\r
+CONDEV DB "\DEV\CON",0\r
+AUXDEV DB "\DEV\AUX",0\r
+PRNDEV DB "\DEV\PRN",0\r
+\r
+CONFIG DB "\CONFIG.SYS",0\r
+\r
+COMMND DB "\COMMAND.COM",0\r
+\r
+COMTAB LABEL BYTE\r
+ DB 7,"BUFFERS",'B'\r
+ DB 5,"BREAK",'C'\r
+ DB 5,"SHELL",'S'\r
+ DB 6,"DEVICE",'D'\r
+ DB 5,"FILES",'F'\r
+ DB 8,"SWITCHAR",'W'\r
+ DB 8,"AVAILDEV",'A'\r
+ DB 7,"COUNTRY",'Q'\r
+ DB 0\r
+\r
+\r
+SYSINITSEG ENDS\r
+ END\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\r
+\r
+\1a
\ No newline at end of file
--- /dev/null
+ TITLE Message file for MS-DOS SYS Program
+
+FALSE EQU 0
+TRUE EQU NOT FALSE
+
+ INCLUDE DOSSYM.ASM
+
+Message MACRO label,text
+ PUBLIC label,label&Len
+label DB text
+label&Len DW $-label
+ENDM
+
+
+IBMJAPVER EQU FALSE
+
+CONST SEGMENT PUBLIC BYTE
+
+; only this message must be terminated with a $
+ PUBLIC BadVer
+BADVER DB "Incorrect DOS version",13,10,"$"
+
+ IF IBMJAPVER
+ Message BadDisk,<"Destination disk cannot be booted">
+ ENDIF
+
+ Message BadDrv,<"Invalid drive specification">
+ Message BadParm,<"Invalid parameter">
+ Message NoDest,<"No room for system on destination disk">
+ Message BadSiz,<"Incompatible system size">
+ Message Done,<"System transferred">
+
+ PUBLIC GetSys,SysDrv,GetSysLen
+GETSYS DB "Insert system disk in drive "
+SYSDRV DB "A",13,10
+ DB "and strike any key when ready",13,10
+GetSysLen DW GetSysLen-GetSys
+
+CONST ENDS
+
+DATA SEGMENT BYTE PUBLIC
+DATA ENDS
+
+CODE SEGMENT
+DG GROUP CODE,CONST,DATA
+ ASSUME CS:DG,DS:DG,ES:DG,SS:DG
+
+CODE ENDS
+ END
+
+\1a
\ No newline at end of file
--- /dev/null
+TITLE PART1 - COMMAND Transient routines.\r
+\r
+ INCLUDE COMSW.ASM\r
+\r
+.xlist\r
+.xcref\r
+ INCLUDE DOSSYM.ASM\r
+ INCLUDE DEVSYM.ASM\r
+ INCLUDE COMSEG.ASM\r
+.list\r
+.cref\r
+\r
+ INCLUDE COMEQU.ASM\r
+\r
+\r
+DATARES SEGMENT PUBLIC\r
+ EXTRN BATCH:WORD,BATLOC:DWORD,PARMBUF:BYTE\r
+ EXTRN RESTDIR:BYTE,EXTCOM:BYTE,ECHOFLAG:BYTE\r
+ EXTRN SINGLECOM:WORD,VERVAL:WORD,FORFLAG:BYTE\r
+ EXTRN RE_INSTR:BYTE,RE_OUT_APP:BYTE,PIPE1:BYTE,PIPE2:BYTE\r
+ EXTRN RE_OUTSTR:BYTE,PIPEFLAG:BYTE,PIPEFILES:BYTE,PIPEPTR:WORD\r
+ EXTRN INPIPEPTR:WORD,OUTPIPEPTR:WORD,EXEC_BLOCK:BYTE,ENVIRSEG:WORD\r
+DATARES ENDS\r
+\r
+TRANDATA SEGMENT PUBLIC\r
+ EXTRN BADBAT:BYTE,NEEDBAT:BYTE,BADNAM:BYTE\r
+ EXTRN SYNTMES:BYTE,BADDRV:BYTE,BYTMES_POST:BYTE\r
+ EXTRN DIRMES_PRE:BYTE,DIRMES_POST:BYTE,BYTMES_PRE:BYTE\r
+ EXTRN NOTFND:BYTE,PIPEEMES:BYTE,BADPMES:BYTE,COMTAB:BYTE\r
+TRANDATA ENDS\r
+\r
+TRANSPACE SEGMENT PUBLIC\r
+ EXTRN UCOMBUF:BYTE,COMBUF:BYTE,USERDIR1:BYTE,EXECPATH:BYTE\r
+ EXTRN DIRCHAR:BYTE,EXEC_ADDR:DWORD,RCH_ADDR:DWORD,CHKDRV:BYTE\r
+ EXTRN CURDRV:BYTE,PARM1:BYTE,PARM2:BYTE,COMSW:WORD,ARG1S:WORD\r
+ EXTRN ARG2S:WORD,ARGTS:WORD,SPECDRV:BYTE,BYTCNT:WORD,IDLEN:BYTE\r
+ EXTRN DIRBUF:BYTE,ID:BYTE,COM:BYTE,LINCNT:BYTE,INTERNATVARS:BYTE\r
+ EXTRN HEADCALL:DWORD,RESSEG:WORD,TPA:WORD,SWITCHAR:BYTE\r
+ EXTRN STACK:WORD,FILTYP:BYTE,FILECNT:WORD,LINLEN:BYTE\r
+\r
+\r
+ IF KANJI\r
+ EXTRN KPARSE:BYTE\r
+ ENDIF\r
+TRANSPACE ENDS\r
+\r
+; ********************************************************************\r
+; START OF TRANSIENT PORTION\r
+; This code is loaded at the end of memory and may be overwritten by\r
+; memory-intensive user programs.\r
+\r
+TRANCODE SEGMENT PUBLIC PARA\r
+ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING\r
+\r
+\r
+ EXTRN SCANOFF:NEAR,DELIM:NEAR,SAVUDIR:NEAR,SAVUDIR1:NEAR\r
+ EXTRN PATHCHRCMP:NEAR,PRINT:NEAR,RESTUDIR:NEAR\r
+ EXTRN CRLF2:NEAR,PRINT_PROMPT:NEAR,GETBATBYT:NEAR,PRESCAN:NEAR\r
+ EXTRN CRPRINT:NEAR,DISP32BITS:NEAR,FCB_TO_ASCZ:NEAR\r
+ EXTRN ERROR_PRINT:NEAR,FREE_TPA:NEAR,ALLOC_TPA:NEAR\r
+ EXTRN $EXIT:NEAR,FORPROC:NEAR,FIND_NAME_IN_ENVIRONMENT:NEAR\r
+ EXTRN UPCONV:NEAR,BATOPEN:NEAR,BATCLOSE:NEAR,IOSET:NEAR,FIND_PATH:NEAR\r
+ EXTRN TESTDOREIN:NEAR,TESTDOREOUT:NEAR\r
+\r
+ PUBLIC SWLIST,CERROR,SETREST1,DOCOM,DOCOM1,DRVBAD,NOTFNDERR\r
+ PUBLIC COMMAND,TCOMMAND,SWITCH,PIPEERRSYN,GETKEYSTROKE,SETREST\r
+ PUBLIC CHKCNT\r
+\r
+\r
+ IF KANJI\r
+ EXTRN TESTKANJ:NEAR\r
+ ENDIF\r
+\r
+ ORG 0\r
+ZERO = $\r
+\r
+ ORG 100H ; Allow for 100H parameter area\r
+\r
+SETDRV:\r
+ MOV AH,SET_DEFAULT_DRIVE\r
+ INT int_command\r
+TCOMMAND:\r
+ MOV DS,[RESSEG]\r
+ASSUME DS:RESGROUP\r
+ MOV AX,-1\r
+ XCHG AX,[VERVAL]\r
+ CMP AX,-1\r
+ JZ NOSETVER2\r
+ MOV AH,SET_VERIFY_ON_WRITE ; AL has correct value\r
+ INT int_command\r
+NOSETVER2:\r
+ CALL [HEADCALL] ; Make sure header fixed\r
+ XOR BP,BP ; Flag transient not read\r
+ CMP [SINGLECOM],-1\r
+ JNZ COMMAND\r
+$EXITPREP:\r
+ PUSH CS\r
+ POP DS\r
+ JMP $EXIT ; Have finished the single command\r
+ASSUME DS:NOTHING\r
+COMMAND:\r
+ CLD\r
+ MOV AX,CS\r
+ MOV SS,AX\r
+ASSUME SS:TRANGROUP\r
+ MOV SP,OFFSET TRANGROUP:STACK\r
+ MOV ES,AX\r
+ASSUME ES:TRANGROUP\r
+ MOV DS,[RESSEG]\r
+ASSUME DS:RESGROUP\r
+ STI\r
+\r
+ MOV [UCOMBUF],COMBUFLEN ; Init UCOMBUF\r
+ MOV [COMBUF],COMBUFLEN ; Init COMBUF (Autoexec doing DATE)\r
+ OR BP,BP ; See if just read\r
+ JZ TESTRDIR ; Not read, check user directory\r
+ MOV WORD PTR [UCOMBUF+1],0D01H ; Reset buffer\r
+ JMP SHORT NOSETBUF\r
+TESTRDIR:\r
+ CMP [RESTDIR],0\r
+ JZ NOSETBUF ; User directory OK\r
+ PUSH DS\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:TRANGROUP\r
+ MOV DX,OFFSET TRANGROUP:USERDIR1\r
+ MOV AH,CHDIR\r
+ INT int_command ; Restore users directory\r
+ POP DS\r
+ASSUME DS:RESGROUP\r
+NOSETBUF:\r
+ CMP [PIPEFILES],0\r
+ JZ NOPCLOSE ; Don't bother if they don't exist\r
+ CMP [PIPEFLAG],0\r
+ JNZ NOPCLOSE ; Don't del if still piping\r
+ CALL PIPEDEL\r
+NOPCLOSE:\r
+ MOV [EXTCOM],0 ; Flag internal command\r
+ MOV [RESTDIR],0 ; Flag users dirs OK\r
+ MOV AX,CS ; Get segment we're in\r
+ MOV DS,AX\r
+ASSUME DS:TRANGROUP\r
+ PUSH AX\r
+ MOV DX,OFFSET TRANGROUP:INTERNATVARS\r
+ MOV AX,INTERNATIONAL SHL 8\r
+ INT 21H\r
+ POP AX\r
+ SUB AX,[TPA] ; AX=size of TPA in paragraphs\r
+ MOV DX,16\r
+ MUL DX ; DX:AX=size of TPA in bytes\r
+ OR DX,DX ; See if over 64K\r
+ JZ SAVSIZ ; OK if not\r
+ MOV AX,-1 ; If so, limit to 65535 bytes\r
+SAVSIZ:\r
+ MOV [BYTCNT],AX ; Max no. of bytes that can be buffered\r
+ MOV DS,[RESSEG] ; All batch work must use resident seg.\r
+ASSUME DS:RESGROUP\r
+ TEST [ECHOFLAG],-1\r
+ JZ GETCOM ; Don't do the CRLF\r
+ CALL SINGLETEST\r
+ JB GETCOM\r
+ CALL CRLF2\r
+GETCOM:\r
+ MOV AH,GET_DEFAULT_DRIVE\r
+ INT int_command\r
+ MOV [CURDRV],AL\r
+ TEST [ECHOFLAG],-1\r
+ JZ NOPDRV ; No prompt if echo off\r
+ CALL SINGLETEST\r
+ JB NOPDRV\r
+ CALL PRINT_PROMPT ; Prompt the user\r
+NOPDRV:\r
+ TEST [PIPEFLAG],-1 ; Pipe has highest presedence\r
+ JZ NOPIPE\r
+ JMP PIPEPROC ; Continue the pipeline\r
+NOPIPE:\r
+ TEST [FORFLAG],-1 ; FOR has next highest precedence\r
+ JZ TESTFORBAT\r
+ JMP FORPROC ; Continue the FOR\r
+TESTFORBAT:\r
+ MOV [RE_INSTR],0 ; Turn redirection back off\r
+ MOV [RE_OUTSTR],0\r
+ MOV [RE_OUT_APP],0\r
+ TEST [BATCH],-1 ; Batch has lowest precedence\r
+ JZ ISNOBAT\r
+ JMP READBAT ; Continue BATCH\r
+\r
+ISNOBAT:\r
+ CMP [SINGLECOM],0\r
+ JZ REGCOM\r
+ MOV SI,-1\r
+ XCHG SI,[SINGLECOM]\r
+ MOV DI,OFFSET TRANGROUP:COMBUF + 2\r
+ XOR CX,CX\r
+SINGLELOOP:\r
+ LODSB\r
+ STOSB\r
+ INC CX\r
+ CMP AL,0DH\r
+ JNZ SINGLELOOP\r
+ DEC CX\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:TRANGROUP\r
+ MOV [COMBUF + 1],CL\r
+ JMP DOCOM\r
+\r
+REGCOM:\r
+ PUSH CS\r
+ POP DS ; Need local segment to point to buffer\r
+ MOV DX,OFFSET TRANGROUP:UCOMBUF\r
+ MOV AH,STD_CON_STRING_INPUT\r
+ INT int_command ; Get a command\r
+ MOV CL,[UCOMBUF]\r
+ XOR CH,CH\r
+ ADD CX,3\r
+ MOV SI,OFFSET TRANGROUP:UCOMBUF\r
+ MOV DI,OFFSET TRANGROUP:COMBUF\r
+ REP MOVSB ; Transfer it to the cooked buffer\r
+ JMP DOCOM\r
+\r
+; All batch proccessing has DS set to segment of resident portion\r
+ASSUME DS:RESGROUP,ES:TRANGROUP\r
+\r
+NEEDENV:\r
+ PUSH DS\r
+ PUSH SI\r
+ PUSH DI\r
+\r
+ MOV DI,OFFSET TRANGROUP:ID\r
+ ADD AL,"0"\r
+ STOSB\r
+GETENV1:\r
+ CALL GETBATBYT\r
+ STOSB\r
+ CMP AL,13\r
+ JZ GETENV2\r
+ CMP AL,"%"\r
+ JNZ GETENV1\r
+ MOV BYTE PTR ES:[DI-1],"="\r
+GETENV2:\r
+ MOV SI,OFFSET TRANGROUP:ID\r
+ PUSH CS\r
+ POP DS ; DS:SI POINTS TO NAME\r
+ASSUME DS:TRANGROUP,ES:RESGROUP\r
+ CALL FIND_NAME_IN_environment\r
+ PUSH ES\r
+ POP DS\r
+ PUSH CS\r
+ POP ES\r
+ASSUME DS:RESGROUP,ES:TRANGROUP\r
+ MOV SI,DI\r
+ POP DI ; get back pointer to command line\r
+ JNC GETENV4\r
+\r
+GETENV3: ; Parameter not found\r
+ PUSH CS\r
+ POP DS\r
+ MOV SI,OFFSET TRANGROUP:ID\r
+\r
+GETENV4:\r
+ LODSB ; From resident segment\r
+ OR AL,AL ; Check for end of parameter\r
+ JZ GETENV6\r
+ CMP AL,13\r
+ JZ GETENV6\r
+ CMP AL,"="\r
+ JZ GETENVX\r
+ STOSB\r
+ JMP GETENV4\r
+\r
+GETENVX:\r
+ MOV AL,"%"\r
+ STOSB\r
+GETENV6:\r
+ POP SI\r
+ POP DS\r
+ CMP AL,13\r
+ JZ SAVBATBYTJ\r
+ JMP RDBAT\r
+\r
+NEEDPARM:\r
+ CALL GETBATBYT\r
+ CMP AL,"%" ; Check for two consecutive %\r
+ JZ SAVBATBYTJ\r
+ CMP AL,13 ; Check for end-of-line\r
+ JNZ PAROK\r
+SAVBATBYTJ:\r
+ JMP SAVBATBYT\r
+PAROK:\r
+ SUB AL,"0"\r
+ JB NEEDENV ; look for parameter in the environment\r
+ CMP AL,9\r
+ JA NEEDENV\r
+\r
+ CBW\r
+ MOV SI,AX\r
+ SHL SI,1 ; Two bytes per entry\r
+ PUSH ES\r
+ PUSH DI\r
+ MOV ES,[BATCH]\r
+ XOR CX,CX\r
+ MOV AX,CX\r
+ MOV DI,CX\r
+ DEC CX\r
+ REPNZ SCASB\r
+ ADD DI,SI\r
+ MOV SI,ES:[DI]\r
+ POP DI\r
+ POP ES\r
+ CMP SI,-1 ; Check if parameter exists\r
+ JZ RDBAT ; Ignore if it doesn't\r
+RDPARM:\r
+ LODSB ; From resident segment\r
+ CMP AL,0DH ; Check for end of parameter\r
+ JZ RDBAT\r
+ STOSB\r
+ JMP RDPARM\r
+\r
+PROMPTBAT:\r
+ MOV DX,OFFSET TRANGROUP:NEEDBAT\r
+ CALL [RCH_ADDR]\r
+ JZ AskForBat ; Media is removable\r
+NoAskForBat:\r
+ MOV ES,[BATCH] ; Turn off batch\r
+ MOV AH,DEALLOC\r
+ INT int_command ; free up the batch piece\r
+ MOV [BATCH],0 ; AFTER DEALLOC in case of ^C\r
+ MOV [FORFLAG],0 ; Turn off for processing\r
+ MOV [PIPEFLAG],0 ; Turn off any pipe\r
+ PUSH CS\r
+ POP DS\r
+ MOV DX,OFFSET TRANGROUP:BADBAT\r
+ CALL ERROR_PRINT ; Tell user no batch file\r
+ JMP TCOMMAND\r
+\r
+ASKFORBAT:\r
+ PUSH CS\r
+ POP DS\r
+ CALL ERROR_PRINT ; Prompt for batch file\r
+ CALL GetKeystroke\r
+ JMP TCOMMAND\r
+;**************************************************************************\r
+; read the next keystroke\r
+\r
+GetKeystroke:\r
+ MOV AX,(STD_CON_INPUT_FLUSH SHL 8) OR STD_CON_INPUT_no_echo\r
+ INT int_command ; Get character with KB buffer flush\r
+ MOV AX,(STD_CON_INPUT_FLUSH SHL 8) + 0\r
+ INT int_command\r
+ return\r
+\r
+READBAT:\r
+ CALL BATOPEN\r
+ JC PROMPTBAT\r
+ MOV DI,OFFSET TRANGROUP:COMBUF+2\r
+TESTNOP:\r
+ CALL GETBATBYT\r
+ CMP AL,':' ; Label/Comment?\r
+ JNZ NOTLABEL\r
+NOPLINE: ; Consume the line\r
+ CALL GETBATBYT\r
+ CMP AL,0DH\r
+ JNZ NOPLINE\r
+ CALL GETBATBYT ; Eat Linefeed\r
+ TEST [BATCH],-1\r
+ JNZ TESTNOP\r
+ JMP TCOMMAND ; Hit EOF\r
+\r
+RDBAT:\r
+ CALL GETBATBYT\r
+NOTLABEL:\r
+ CMP AL,"%" ; Check for parameter\r
+ JNZ SAVBATBYT\r
+ JMP NEEDPARM\r
+SAVBATBYT:\r
+ STOSB\r
+ CMP AL,0DH\r
+ JNZ RDBAT\r
+ SUB DI,OFFSET TRANGROUP:COMBUF+3\r
+ MOV AX,DI\r
+ MOV ES:[COMBUF+1],AL ; Set length of line\r
+ CALL GETBATBYT ; Eat linefeed\r
+ CALL BATCLOSE\r
+ TEST [ECHOFLAG],-1\r
+ PUSH CS\r
+ POP DS ; Go back to local segment\r
+ JZ NOECHO2\r
+ASSUME DS:TRANGROUP\r
+ MOV DX,OFFSET TRANGROUP:COMBUF+2\r
+ CALL CRPRINT\r
+DOCOM:\r
+; All segments are local for command line processing\r
+ CALL CRLF2\r
+DOCOM1:\r
+\r
+NOECHO2:\r
+ CALL PRESCAN ; Cook the input buffer\r
+ JZ NOPIPEPROC\r
+ JMP PIPEPROCSTRT ; Fire up the pipe\r
+NOPIPEPROC:\r
+ MOV SI,OFFSET TRANGROUP:COMBUF+2\r
+ MOV DI,OFFSET TRANGROUP:IDLEN\r
+ MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H ; Make FCB with blank scan-off\r
+ INT int_command\r
+ CMP AL,1 ; Check for ambiguous command name\r
+ JZ BADCOMJ1 ; Ambiguous commands not allowed\r
+ CMP AL,-1\r
+ JNZ DRVGD\r
+ JMP DRVBAD\r
+\r
+BADCOMJ1:\r
+ JMP BADCOM\r
+\r
+DRVGD:\r
+ MOV AL,[DI]\r
+ MOV [SPECDRV],AL\r
+ MOV AL," "\r
+ MOV CX,9\r
+ INC DI\r
+ REPNE SCASB ; Count no. of letters in command name\r
+ MOV AL,9\r
+ SUB AL,CL\r
+ MOV [IDLEN],AL\r
+ MOV DI,81H\r
+ XOR CX,CX\r
+ PUSH SI\r
+COMTAIL:\r
+ LODSB\r
+ STOSB ; Move command tail to 80H\r
+ CMP AL,13\r
+ LOOPNZ COMTAIL\r
+ NOT CL\r
+ MOV BYTE PTR DS:[80H],CL\r
+ POP SI\r
+; If the command has 0 parameters must check here for\r
+; any switches that might be present.\r
+; SI -> first character after the command.\r
+ CALL SWITCH ; Is the next character a SWITCHAR\r
+ MOV [COMSW],AX\r
+ MOV DI,FCB\r
+ MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H\r
+ INT int_command\r
+ MOV [PARM1],AL ; Save result of parse\r
+\r
+PRBEG:\r
+ LODSB\r
+ CMP AL,[SWITCHAR]\r
+ JZ PRFIN\r
+ CMP AL,13\r
+ JZ PRFIN\r
+ CALL DELIM\r
+ JNZ PRBEG\r
+PRFIN:\r
+ DEC SI\r
+ CALL SWITCH\r
+ MOV [ARG1S],AX\r
+ MOV DI,FCB+10H\r
+ MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H\r
+ INT int_command ; Parse file name\r
+ MOV [PARM2],AL ; Save result\r
+ CALL SWITCH\r
+ MOV [ARG2S],AX\r
+ OR AX,[ARG1S]\r
+ MOV [ARGTS],AX\r
+SWTLP: ; Find any remaining switches\r
+ CMP BYTE PTR [SI],0DH\r
+ JZ GOTALLSW\r
+ INC SI\r
+ CALL SWITCH\r
+ OR [ARGTS],AX\r
+ JMP SHORT SWTLP\r
+\r
+GOTALLSW:\r
+ MOV AL,[IDLEN]\r
+ MOV DL,[SPECDRV]\r
+ OR DL,DL ; Check if drive was specified\r
+ JZ OK\r
+ JMP DRVCHK\r
+OK:\r
+ DEC AL ; Check for null command\r
+ JNZ FNDCOM\r
+ MOV DS,[RESSEG]\r
+ASSUME DS:RESGROUP\r
+ CMP [SINGLECOM],-1\r
+ JZ EXITJ\r
+ JMP GETCOM\r
+\r
+EXITJ:\r
+ JMP $EXITPREP\r
+ASSUME DS:TRANGROUP\r
+\r
+RETSW:\r
+ XCHG AX,BX ; Put switches in AX\r
+ return\r
+\r
+SWITCH:\r
+ XOR BX,BX ; Initialize - no switches set\r
+SWLOOP:\r
+ CALL SCANOFF ; Skip any delimiters\r
+ CMP AL,[SWITCHAR] ; Is it a switch specifier?\r
+ JNZ RETSW ; No -- we're finished\r
+ OR BX,GOTSWITCH ; Indicate there is a switch specified\r
+ INC SI ; Skip over the switch character\r
+ CALL SCANOFF\r
+ CMP AL,0DH\r
+ JZ RETSW ; Oops\r
+ INC SI\r
+; Convert lower case input to upper case\r
+ CALL UPCONV\r
+ MOV DI,OFFSET TRANGROUP:SWLIST\r
+ MOV CX,SWCOUNT\r
+ REPNE SCASB ; Look for matching switch\r
+ JNZ BADSW\r
+ MOV AX,1\r
+ SHL AX,CL ; Set a bit for the switch\r
+ OR BX,AX\r
+ JMP SHORT SWLOOP\r
+\r
+BADSW:\r
+ JMP SHORT SWLOOP\r
+\r
+SWLIST DB "VBAPW"\r
+SWCOUNT EQU $-SWLIST\r
+\r
+DRVBAD:\r
+ MOV DX,OFFSET TRANGROUP:BADDRV\r
+ JMP CERROR\r
+\r
+FNDCOM:\r
+ MOV SI,OFFSET TRANGROUP:COMTAB ; Prepare to search command table\r
+ MOV CH,0\r
+FINDCOM:\r
+ MOV DI,OFFSET TRANGROUP:IDLEN\r
+ MOV CL,[SI]\r
+ JCXZ EXTERNAL\r
+ REPE CMPSB\r
+ LAHF\r
+ ADD SI,CX ; Bump to next position without affecting flags\r
+ SAHF\r
+ LODSB ; Get flag for drive check\r
+ MOV [CHKDRV],AL\r
+ LODSW ; Get address of command\r
+ JNZ FINDCOM\r
+ MOV DX,AX\r
+ CMP [CHKDRV],0\r
+ JZ NOCHECK\r
+ MOV AL,[PARM1]\r
+ OR AL,[PARM2] ; Check if either parm. had invalid drive\r
+ CMP AL,-1\r
+ JZ DRVBAD\r
+NOCHECK:\r
+ CALL IOSET\r
+ CALL DX ; Call the internal\r
+COMJMP:\r
+ JMP TCOMMAND\r
+\r
+SETDRV1:\r
+ JMP SETDRV\r
+\r
+DRVCHK:\r
+ DEC DL ; Adjust for correct drive number\r
+ DEC AL ; Check if anything else is on line\r
+ JZ SETDRV1\r
+EXTERNAL:\r
+ MOV [FILTYP],0\r
+ MOV DL,[SPECDRV]\r
+ MOV [IDLEN],DL\r
+ CALL SAVUDIR ; Drive letter already checked\r
+ MOV AL,'?'\r
+ MOV DI,OFFSET TRANGROUP:COM\r
+ STOSB ; Look for any extension\r
+ STOSB\r
+ STOSB\r
+ MOV DX,OFFSET TRANGROUP:DIRBUF ; Command will end up here\r
+ MOV AH,SET_DMA\r
+ INT int_command\r
+ PUSH ES\r
+ CALL FIND_PATH\r
+ MOV SI,DI\r
+ POP ES\r
+\r
+ MOV DI,OFFSET TRANGROUP:EXECPATH\r
+ MOV BYTE PTR [DI],0 ; Initialize to current directory\r
+RESEARCH:\r
+ MOV AH,DIR_SEARCH_FIRST\r
+COMSRCH:\r
+ PUSH CS\r
+ POP DS\r
+ MOV DX,OFFSET TRANGROUP:IDLEN\r
+ INT int_command\r
+ OR AL,AL\r
+ MOV AH,DIR_SEARCH_NEXT ; Do search-next next\r
+ JNZ PATHCHK\r
+ CMP WORD PTR [DIRBUF+9],4F00H + "C"\r
+ JNZ CHKEXE\r
+ CMP [DIRBUF+11],"M"\r
+ JNZ CHKEXE\r
+ OR [FILTYP],4\r
+ JMP EXECUTE ; If we find a COM were done\r
+\r
+CHKEXE:\r
+ CMP WORD PTR [DIRBUF+9],5800H + "E"\r
+ JNZ CHKBAT\r
+ CMP [DIRBUF+11],"E"\r
+ JNZ CHKBAT\r
+ OR [FILTYP],1 ; Flag an EXE found\r
+ JMP COMSRCH ; Continue search\r
+\r
+CHKBAT:\r
+ CMP WORD PTR [DIRBUF+9],4100H + "B"\r
+ JNZ COMSRCH\r
+ CMP [DIRBUF+11],"T"\r
+ JNZ COMSRCH\r
+ OR [FILTYP],2 ; Flag BAT found\r
+ JMP COMSRCH ; Continue search\r
+\r
+PATHCHK:\r
+ TEST [FILTYP],1\r
+ JZ TESTBAT\r
+ MOV WORD PTR [DIRBUF+9],5800H+"E"\r
+ MOV [DIRBUF+11],"E"\r
+ JMP EXECUTE ; Found EXE\r
+\r
+TESTBAT:\r
+ TEST [FILTYP],2\r
+ JZ NEXTPATH ; Found nothing, try next path\r
+ MOV WORD PTR [DIRBUF+9],4100H+"B"\r
+ MOV [DIRBUF+11],"T"\r
+ MOV DX,OFFSET TRANGROUP:DIRBUF ; Found BAT\r
+ MOV AH,FCB_OPEN\r
+ INT int_command\r
+ OR AL,AL\r
+ JZ BATCOMJ ; Bat exists\r
+ CALL RESTUDIR\r
+ JMP BADCOM\r
+\r
+BATCOMJ:\r
+ JMP BATCOM\r
+\r
+NEXTPATH:\r
+ MOV DX,OFFSET TRANGROUP:USERDIR1 ; Restore users dir\r
+ MOV AH,CHDIR\r
+ INT int_command\r
+ MOV DS,[RESSEG]\r
+ASSUME DS:RESGROUP\r
+ MOV [RESTDIR],0\r
+BADPATHEL:\r
+ MOV DI,OFFSET TRANGROUP:EXECPATH ; Build a full path here\r
+ MOV DX,SI\r
+ MOV DS,[ENVIRSEG] ; Point into environment\r
+ASSUME DS:NOTHING\r
+ LODSB\r
+\r
+ IF KANJI\r
+ MOV [KPARSE],0\r
+ ENDIF\r
+\r
+ OR AL,AL\r
+ JZ BADCOMJ ; NUL, command not found\r
+ XOR BL,BL ; Make BL a NUL\r
+PSKIPLP: ; Get the path\r
+ STOSB\r
+ OR AL,AL\r
+ JZ LASTPATH\r
+ CMP AL,';'\r
+ JZ GOTNEXTPATH\r
+ CMP DI,15+DirStrLen+(OFFSET TRANGROUP:EXECPATH)\r
+ JB OKPath\r
+SKIPPathElem:\r
+ LODSB ; scan to end of path element\r
+ OR AL,AL\r
+ JZ BadPathEl\r
+ CMP AL,';'\r
+ JZ BadPathEl\r
+ JMP SkipPathElem\r
+\r
+OKPath:\r
+ IF KANJI\r
+ MOV [KPARSE],0\r
+ CALL TESTKANJ\r
+ JZ NXTPTCHR\r
+ INC [KPARSE]\r
+ MOVSB\r
+NXTPTCHR:\r
+ ENDIF\r
+\r
+ LODSB\r
+ JMP SHORT PSKIPLP\r
+\r
+BADCOMJ:\r
+ JMP BADCOM\r
+\r
+LASTPATH:\r
+ MOV BYTE PTR ES:[DI-1],';' ; Fix up the NUL in EXECPATH\r
+ DEC SI ; Point to the NUL in PATHSTRING\r
+ MOV BL,[SI-1] ; Change substi char to char before NUL\r
+\r
+GOTNEXTPATH:\r
+ DEC DI ; Point to the end of the dir\r
+ PUSH BX\r
+ PUSH SI\r
+ PUSH DX\r
+ MOV SI,DX\r
+ XOR DL,DL\r
+ CMP BYTE PTR [SI+1],DRVCHAR\r
+ JNZ DEFDRVPATH ; No drive spec\r
+ MOV DL,[SI]\r
+ SUB DL,'@'\r
+DEFDRVPATH:\r
+ PUSH DS\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:TRANGROUP\r
+ MOV [IDLEN],DL ; New drive\r
+ PUSH DI\r
+ CALL SAVUDIR ; Save the users dir\r
+ POP DI\r
+ JNC PATHTRY\r
+ MOV DX,OFFSET TRANGROUP:BADPMES ; Tell the user bad stuff in path\r
+ CALL PRINT\r
+PATHTRY:\r
+ POP DS\r
+ASSUME DS:NOTHING\r
+ POP DX\r
+ POP SI\r
+ POP BX\r
+ XCHG BL,[SI-1] ; Stick in NUL, or same thing if LASTPATH\r
+CDPATH:\r
+ MOV AH,CHDIR\r
+ INT int_command\r
+ MOV [SI-1],BL ; Fix the path string back up\r
+ MOV DS,[RESSEG]\r
+ASSUME DS:RESGROUP\r
+ INC [RESTDIR] ; Say users dir needs restoring\r
+ JNC ResearchJ\r
+ JMP BADPATHEL ; Ignore a directory which doesn't exist\r
+ResearchJ:\r
+ JMP RESEARCH ; Try looking in this one\r
+\r
+BATCOM:\r
+ASSUME DS:TRANGROUP\r
+; Batch parameters are read with ES set to segment of resident part\r
+ CALL IOSET ; Set up any redirection\r
+ MOV ES,[RESSEG]\r
+ASSUME ES:RESGROUP\r
+;Since BATCH has lower precedence than PIPE or FOR. If a new BATCH file\r
+;is being started it MUST be true that no FOR or PIPE is currently in\r
+;progress.\r
+ MOV [FORFLAG],0 ; Turn off for processing\r
+ MOV [PIPEFLAG],0 ; Turn off any pipe\r
+ TEST [BATCH],-1\r
+ JNZ CHAINBAT ; Don't need allocation if chaining\r
+ CALL FREE_TPA\r
+ASSUME ES:RESGROUP\r
+ MOV BX,6 ; 64 + 32 bytes\r
+ MOV AH,ALLOC\r
+ INT int_command ; Suck up a little piece for batch processing\r
+ MOV [BATCH],AX\r
+ CALL ALLOC_TPA\r
+CHAINBAT:\r
+ PUSH ES\r
+ MOV ES,[BATCH]\r
+ASSUME ES:NOTHING\r
+ MOV DL,[DIRBUF]\r
+ XOR DI,DI\r
+ CALL SAVUDIR1 ; ES:DI set up, get dir containing Batch file\r
+ XOR AX,AX\r
+ MOV CX,AX\r
+ DEC CX\r
+ REPNZ SCASB ; Find the NUL\r
+ DEC DI ; Point at the NUL\r
+ MOV AL,[DIRCHAR]\r
+ CMP AL,ES:[DI-1]\r
+ JZ NOPUTSLASH\r
+ STOSB\r
+NOPUTSLASH:\r
+ MOV SI,OFFSET TRANGROUP:DIRBUF+1\r
+ CALL FCB_TO_ASCZ ; Tack on batch file name\r
+ MOV AX,-1\r
+ MOV BX,DI\r
+ MOV CX,10\r
+ REP STOSW ; Init Parmtab to no parms\r
+ POP ES\r
+ASSUME ES:RESGROUP\r
+ CALL RESTUDIR\r
+ MOV SI,OFFSET TRANGROUP:COMBUF+2\r
+ MOV DI,OFFSET RESGROUP:PARMBUF\r
+ MOV CX,10\r
+EACHPARM:\r
+ CALL SCANOFF\r
+ CMP AL,0DH\r
+ JZ HAVPARM\r
+ JCXZ MOVPARM ; Only first 10 parms get pointers\r
+ PUSH ES\r
+ MOV ES,[BATCH]\r
+ MOV ES:[BX],DI ; Set pointer table to point to actual parameter\r
+ POP ES\r
+ INC BX\r
+ INC BX\r
+MOVPARM:\r
+ LODSB\r
+ CALL DELIM\r
+ JZ ENDPARM ; Check for end of parameter\r
+ STOSB\r
+ CMP AL,0DH\r
+ JZ HAVPARM\r
+ JMP SHORT MOVPARM\r
+ENDPARM:\r
+ MOV AL,0DH\r
+ STOSB ; End-of-parameter marker\r
+ JCXZ EACHPARM\r
+ DEC CX\r
+ JMP SHORT EACHPARM\r
+HAVPARM:\r
+ XOR AL,AL\r
+ STOSB ; Nul terminate the parms\r
+ XOR AX,AX\r
+ PUSH ES\r
+ POP DS ; Simply batch FCB setup\r
+ASSUME DS:RESGROUP\r
+ MOV WORD PTR [BATLOC],AX ; Start at beginning of file\r
+ MOV WORD PTR [BATLOC+2],AX\r
+ CMP [SINGLECOM],-1\r
+ JNZ NOBATSING\r
+ MOV [SINGLECOM],0FFF0H ; Flag single command BATCH job\r
+NOBATSING:\r
+ JMP TCOMMAND\r
+ASSUME DS:TRANGROUP,ES:TRANGROUP\r
+\r
+EXECUTE:\r
+ CALL RESTUDIR\r
+NeoExecute:\r
+ CMP BYTE PTR [DI],0 ; Command in current directory\r
+ JZ NNSLSH\r
+ MOV AL,[DI-1]\r
+\r
+ IF KANJI\r
+ CMP [KPARSE],0\r
+ JNZ StuffPath ; Last char is second KANJI byte, might be '\'\r
+ ENDIF\r
+\r
+ CALL PATHCHRCMP\r
+ JZ HAVEXP ; Don't double slash\r
+StuffPath:\r
+ MOV AL,[DIRCHAR]\r
+ STOSB\r
+ JMP SHORT HAVEXP\r
+\r
+NNSLSH:\r
+ MOV AL,[DIRBUF] ; Specify a drive\r
+ ADD AL,'@'\r
+ STOSB\r
+ MOV AL,DRVCHAR\r
+ STOSB\r
+HAVEXP:\r
+ MOV SI,OFFSET TRANGROUP:DIRBUF+1\r
+ CALL FCB_TO_ASCZ ; Tack on the filename\r
+ CALL IOSET\r
+ MOV ES,[TPA]\r
+ MOV AH,DEALLOC\r
+ INT int_command ; Now running in "free" space\r
+ MOV ES,[RESSEG]\r
+ASSUME ES:RESGROUP\r
+ INC [EXTCOM] ; Indicate external command\r
+ MOV [RESTDIR],0 ; Since USERDIR1 is in transient, insure\r
+ ; this flag value for re-entry to COMMAND\r
+ MOV DI,FCB\r
+ MOV SI,DI\r
+ MOV CX,052H\r
+ REP MOVSW ; Transfer parameters to resident header\r
+ MOV DX,OFFSET TRANGROUP:EXECPATH\r
+ MOV BX,OFFSET RESGROUP:EXEC_BLOCK\r
+ MOV AX,EXEC SHL 8\r
+ JMP [EXEC_ADDR] ; Jmp to the EXEC in the resident\r
+\r
+BADCOM:\r
+ PUSH CS\r
+ POP DS\r
+ MOV DX,OFFSET TRANGROUP:BADNAM\r
+CERROR:\r
+ CALL ERROR_PRINT\r
+ JMP TCOMMAND\r
+\r
+SINGLETEST:\r
+ASSUME DS:RESGROUP\r
+ CMP [SINGLECOM],0\r
+ JZ RET5\r
+ CMP [SINGLECOM],0EFFFH\r
+ return\r
+\r
+\r
+ASSUME DS:TRANGROUP\r
+SETREST1:\r
+ MOV AL,1\r
+SETREST:\r
+ PUSH DS\r
+ MOV DS,[RESSEG]\r
+ASSUME DS:RESGROUP\r
+ MOV [RESTDIR],AL\r
+ POP DS\r
+ASSUME DS:TRANGROUP\r
+RET5:\r
+ return\r
+\r
+CHKCNT:\r
+ TEST [FILECNT],-1\r
+ JNZ ENDDIR\r
+NOTFNDERR:\r
+ MOV DX,OFFSET TRANGROUP:NOTFND\r
+ JMP CERROR\r
+\r
+ENDDIR:\r
+; Make sure last line ends with CR/LF\r
+ MOV AL,[LINLEN]\r
+ CMP AL,[LINCNT] ; Will be equal if just had CR/LF\r
+ JZ MESSAGE\r
+ CALL CRLF2\r
+MESSAGE:\r
+ MOV DX,OFFSET TRANGROUP:DIRMES_PRE\r
+ CALL PRINT\r
+ MOV SI,[FILECNT]\r
+ XOR DI,DI\r
+ CALL DISP32BITS\r
+ MOV DX,OFFSET TRANGROUP:DIRMES_POST\r
+ CALL PRINT\r
+ MOV AH,GET_DRIVE_FREESPACE\r
+ MOV DL,BYTE PTR DS:[FCB]\r
+ INT int_command\r
+ CMP AX,-1\r
+ retz\r
+ MOV DX,OFFSET TRANGROUP:BYTMES_PRE\r
+ CALL PRINT\r
+ MUL CX ; AX is bytes per cluster\r
+ MUL BX\r
+ MOV DI,DX\r
+ MOV SI,AX\r
+ CALL DISP32BITS\r
+ MOV DX,OFFSET TRANGROUP:BYTMES_POST\r
+ JMP PRINT\r
+\r
+ASSUME DS:RESGROUP\r
+\r
+PIPEDEL:\r
+ PUSH DX\r
+ MOV DX,OFFSET RESGROUP:PIPE1 ; Clean up in case ^C\r
+ MOV AH,UNLINK\r
+ INT int_command\r
+ MOV DX,OFFSET RESGROUP:PIPE2\r
+ MOV AH,UNLINK\r
+ INT int_command\r
+ XOR AX,AX\r
+ MOV WORD PTR [PIPEFLAG],AX ; Pipe files and pipe gone\r
+ MOV [ECHOFLAG],1 ; Make sure ^C to pipe doesn't leave ECHO OFF\r
+ POP DX\r
+ return\r
+\r
+PIPEERRSYN:\r
+ MOV DX,OFFSET TRANGROUP:SYNTMES\r
+ JMP SHORT PIPPERR\r
+PIPEERR:\r
+ MOV DX,OFFSET TRANGROUP:PIPEEMES\r
+PIPPERR:\r
+ CALL PIPEDEL\r
+ PUSH CS\r
+ POP DS\r
+ JMP CERROR\r
+\r
+PIPEPROCSTRT:\r
+ASSUME DS:TRANGROUP,ES:TRANGROUP\r
+ MOV DS,[RESSEG]\r
+ASSUME DS:RESGROUP\r
+ INC [PIPEFILES] ; Flag that the pipe files exist\r
+ MOV AH,19H ; Get current drive\r
+ INT int_command\r
+ ADD AL,'A'\r
+ MOV [PIPE2],AL ; Make pipe files in root of def drv\r
+ MOV BX,OFFSET RESGROUP:PIPE1\r
+ MOV [BX],AL\r
+ MOV DX,BX\r
+ XOR CX,CX\r
+ MOV AH,CREAT\r
+ INT int_command\r
+ JC PIPEERR ; Couldn't create\r
+ MOV BX,AX\r
+ MOV AH,CLOSE ; Don't proliferate handles\r
+ INT int_command\r
+ MOV DX,OFFSET RESGROUP:PIPE2\r
+ MOV AH,CREAT\r
+ INT int_command\r
+ JC PIPEERR\r
+ MOV BX,AX\r
+ MOV AH,CLOSE\r
+ INT int_command\r
+ CALL TESTDOREIN ; Set up a redirection if specified\r
+ MOV [ECHOFLAG],0 ; No echo on pipes\r
+ MOV SI,[PIPEPTR]\r
+ CMP [SINGLECOM],-1\r
+ JNZ NOSINGP\r
+ MOV [SINGLECOM],0F000H ; Flag single command pipe\r
+NOSINGP:\r
+ JMP SHORT FIRSTPIPE\r
+\r
+PIPEPROC:\r
+ASSUME DS:RESGROUP\r
+ MOV [ECHOFLAG],0 ; No echo on pipes\r
+ MOV SI,[PIPEPTR]\r
+ LODSB\r
+ CMP AL,'|'\r
+ JNZ PIPEEND ; Pipe done\r
+ MOV DX,[INPIPEPTR] ; Get the input file name\r
+ MOV AX,(OPEN SHL 8)\r
+ INT int_command\r
+PIPEERRJ:\r
+ JC PIPEERR ; Lost the pipe file\r
+ MOV BX,AX\r
+ MOV AL,0FFH\r
+ XCHG AL,[BX.PDB_JFN_Table]\r
+ MOV DS:[PDB_JFN_Table],AL ; Redirect\r
+FIRSTPIPE:\r
+ MOV DI,OFFSET TRANGROUP:COMBUF + 2\r
+ XOR CX,CX\r
+ CMP BYTE PTR [SI],0DH ; '|<CR>'\r
+ JNZ PIPEOK1\r
+PIPEERRSYNJ:\r
+ JMP PIPEERRSYN\r
+PIPEOK1:\r
+ CMP BYTE PTR [SI],'|' ; '||'\r
+ JZ PIPEERRSYNJ\r
+PIPECOMLP:\r
+ LODSB\r
+ STOSB\r
+\r
+ IF KANJI\r
+ CALL TESTKANJ\r
+ JZ NOTKANJ5\r
+ MOVSB\r
+ JMP PIPECOMLP\r
+\r
+NOTKANJ5:\r
+ ENDIF\r
+\r
+ CMP AL,0DH\r
+ JZ LASTPIPE\r
+ INC CX\r
+ CMP AL,'|'\r
+ JNZ PIPECOMLP\r
+ MOV BYTE PTR ES:[DI-1],0DH\r
+ DEC CX\r
+ MOV [COMBUF+1],CL\r
+ DEC SI\r
+ MOV [PIPEPTR],SI ; On to next pipe element\r
+ MOV DX,[OUTPIPEPTR]\r
+ PUSH CX\r
+ XOR CX,CX\r
+ MOV AX,(CREAT SHL 8)\r
+ INT int_command\r
+ POP CX\r
+ JC PIPEERRJ ; Lost the file\r
+ MOV BX,AX\r
+ MOV AL,0FFH\r
+ XCHG AL,[BX.PDB_JFN_Table]\r
+ MOV DS:[PDB_JFN_Table+1],AL\r
+ XCHG DX,[INPIPEPTR] ; Swap for next element of pipe\r
+ MOV [OUTPIPEPTR],DX\r
+ JMP SHORT PIPECOM\r
+\r
+LASTPIPE:\r
+ MOV [COMBUF+1],CL\r
+ DEC SI\r
+ MOV [PIPEPTR],SI ; Point at the CR (anything not '|' will do)\r
+ CALL TESTDOREOUT ; Set up the redirection if specified\r
+PIPECOM:\r
+ PUSH CS\r
+ POP DS\r
+ JMP NOPIPEPROC ; Process the pipe element\r
+\r
+PIPEEND:\r
+ CALL PIPEDEL\r
+ CMP [SINGLECOM],0F000H\r
+ JNZ NOSINGP2\r
+ MOV [SINGLECOM],-1 ; Make it return\r
+NOSINGP2:\r
+ JMP TCOMMAND\r
+\r
+TRANCODE ENDS\r
+ END\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+TITLE PART2 - COMMAND Transient routines.\r
+\r
+ INCLUDE COMSW.ASM\r
+\r
+.xlist\r
+.xcref\r
+ INCLUDE DOSSYM.ASM\r
+ INCLUDE DEVSYM.ASM\r
+ INCLUDE COMSEG.ASM\r
+.list\r
+.cref\r
+\r
+ INCLUDE COMEQU.ASM\r
+\r
+CODERES SEGMENT PUBLIC\r
+ EXTRN LODCOM1:NEAR\r
+CODERES ENDS\r
+\r
+DATARES SEGMENT PUBLIC\r
+ EXTRN PARENT:WORD,IO_SAVE:WORD,PERMCOM:BYTE\r
+ EXTRN PIPEFLAG:BYTE,ENVIRSEG:WORD\r
+ if ibmver\r
+ EXTRN SYS_CALL:DWORD\r
+ endif\r
+DATARES ENDS\r
+\r
+TRANDATA SEGMENT PUBLIC\r
+\r
+ EXTRN PATH_TEXT:BYTE,PROMPT_TEXT:BYTE\r
+ EXTRN BADDEV:BYTE,SYNTMES:BYTE,ENVERR:BYTE\r
+TRANDATA ENDS\r
+\r
+TRANSPACE SEGMENT PUBLIC\r
+\r
+ EXTRN CURDRV:BYTE,DIRCHAR:BYTE,PWDBUF:BYTE\r
+ EXTRN INTERNATVARS:BYTE,RESSEG:WORD,TPA:WORD\r
+\r
+TRANSPACE ENDS\r
+\r
+\r
+TRANCODE SEGMENT PUBLIC BYTE\r
+ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING\r
+\r
+ EXTRN CERROR:NEAR,ZPRINT:NEAR\r
+ EXTRN CRLF2:NEAR,SCANOFF:NEAR,FREE_TPA:NEAR,ALLOC_TPA:NEAR\r
+ EXTRN OUT:NEAR,DRVBAD:NEAR,SETPATH:NEAR,PRINT:NEAR\r
+ EXTRN FCB_TO_ASCZ:NEAR\r
+\r
+ PUBLIC PRINT_DRIVE,$EXIT,MOVE_NAME\r
+ PUBLIC UPCONV,ADD_PROMPT,CTTY,PRINT_DEFAULT_DIRECTORY\r
+ PUBLIC ADD_NAME_TO_ENVIRONMENT,PWD,SCAN_DOUBLE_NULL\r
+ PUBLIC FIND_NAME_IN_ENVIRONMENT,STORE_CHAR\r
+ PUBLIC FIND_PATH,DELETE_PATH,FIND_PROMPT\r
+ PUBLIC SCASB2\r
+\r
+ IF KANJI\r
+ PUBLIC TESTKANJ\r
+ ENDIF\r
+\r
+BREAK <Environment utilities>\r
+ASSUME DS:TRANGROUP\r
+\r
+ADD_PROMPT:\r
+ CALL DELETE_PROMPT ; DELETE ANY EXISTING PROMPT\r
+ CALL SCAN_DOUBLE_NULL\r
+ADD_PROMPT2:\r
+ PUSH SI\r
+ CALL GETARG\r
+ POP SI\r
+ retz ; PRE SCAN FOR ARGUMENTS\r
+ CALL MOVE_NAME ; MOVE IN NAME\r
+ CALL GETARG\r
+ JMP SHORT ADD_NAME\r
+;\r
+; Input: DS:SI points to a CR terminated string\r
+; Output: carry flag is set if no room\r
+; otherwise name is added to environment\r
+;\r
+ADD_NAME_TO_ENVIRONMENT:\r
+ CALL GETARG\r
+ JZ DISP_ENV\r
+;\r
+; check if line contains exactly one equals sign\r
+;\r
+ XOR BX,BX ;= COUNT IS 0\r
+ PUSH SI ;SAVE POINTER TO BEGINNING OF LINE\r
+EQLP:\r
+ LODSB ;GET A CHAR\r
+ CMP AL,13 ;IF CR WE'RE ALL DONE\r
+ JZ QUEQ\r
+ CMP AL,"=" ;LOOK FOR = SIGN\r
+ JNZ EQLP ;NOT THERE, GET NEXT CHAR\r
+ INC BL ;OTHERWISE INCREMENT EQ COUNT\r
+ CMP BYTE PTR [SI],13 ;LOOK FOR CR FOLLOWING = SIGN\r
+ JNZ EQLP\r
+ INC BH ;SET BH=1 MEANS NO PARAMETERS\r
+ JMP EQLP ;AND LOOK FOR MORE\r
+QUEQ:\r
+ POP SI ;RESTORE BEGINNING OF LINE\r
+ DEC BL ;ZERO FLAG MEANS ONLY ONE EQ\r
+ JZ ONEQ ;GOOD LINE\r
+ MOV DX,OFFSET TRANGROUP:SYNTMES\r
+ JMP CERROR\r
+\r
+ONEQ:\r
+ PUSH BX\r
+ CALL DELETE_NAME_IN_ENVIRONMENT\r
+ POP BX\r
+ DEC BH\r
+ retz\r
+\r
+ CALL SCAN_DOUBLE_NULL\r
+ CALL MOVE_NAME\r
+ADD_NAME:\r
+ LODSB\r
+ CMP AL,13\r
+ retz\r
+ CALL STORE_CHAR\r
+ JMP ADD_NAME\r
+\r
+DISP_ENV:\r
+ MOV DS,[RESSEG]\r
+ASSUME DS:RESGROUP\r
+ MOV DS,[ENVIRSEG]\r
+ASSUME DS:NOTHING\r
+ XOR SI,SI\r
+PENVLP:\r
+ CMP BYTE PTR [SI],0\r
+ retz\r
+\r
+ MOV DX,SI\r
+ CALL ZPRINT\r
+ CALL CRLF2\r
+PENVLP2:\r
+ LODSB\r
+ OR AL,AL\r
+ JNZ PENVLP2\r
+ JMP PENVLP\r
+\r
+ASSUME DS:TRANGROUP\r
+DELETE_PATH:\r
+ MOV SI,OFFSET TRANGROUP:PATH_TEXT\r
+ JMP SHORT DELETE_NAME_IN_environment\r
+\r
+DELETE_PROMPT:\r
+ MOV SI,OFFSET TRANGROUP:PROMPT_TEXT\r
+\r
+DELETE_NAME_IN_environment:\r
+;\r
+; Input: DS:SI points to a "=" terminated string\r
+; Output: carry flag is set if name not found\r
+; otherwise name is deleted\r
+;\r
+ PUSH SI\r
+ PUSH DS\r
+ CALL FIND ; ES:DI POINTS TO NAME\r
+ JC DEL1\r
+ MOV SI,DI ; SAVE IT\r
+ CALL SCASB2 ; SCAN FOR THE NUL\r
+ XCHG SI,DI\r
+ CALL GETENVSIZ\r
+ SUB CX,SI\r
+ PUSH ES\r
+ POP DS ; ES:DI POINTS TO NAME, DS:SI POINTS TO NEXT NAME\r
+ REP MOVSB ; DELETE THE NAME\r
+DEL1:\r
+ POP DS\r
+ POP SI\r
+ return\r
+\r
+FIND_PATH:\r
+ MOV SI,OFFSET TRANGROUP:PATH_TEXT\r
+ JMP SHORT FIND_NAME_IN_environment\r
+\r
+FIND_PROMPT:\r
+ MOV SI,OFFSET TRANGROUP:PROMPT_TEXT\r
+\r
+FIND_NAME_IN_environment:\r
+;\r
+; Input: DS:SI points to a "=" terminated string\r
+; Output: ES:DI points to the arguments in the environment\r
+; zero is set if name not found\r
+; carry flag is set if name not valid format\r
+;\r
+ CALL FIND ; FIND THE NAME\r
+ retc ; CARRY MEANS NOT FOUND\r
+ JMP SCASB1 ; SCAN FOR = SIGN\r
+;\r
+; On return of FIND1, ES:DI points to beginning of name\r
+;\r
+FIND:\r
+ CLD\r
+ CALL COUNT0 ; CX = LENGTH OF NAME\r
+ MOV ES,[RESSEG]\r
+ASSUME ES:RESGROUP\r
+ MOV ES,[ENVIRSEG]\r
+ASSUME ES:NOTHING\r
+ XOR DI,DI\r
+FIND1:\r
+ PUSH CX\r
+ PUSH SI\r
+ PUSH DI\r
+FIND11:\r
+ LODSB\r
+\r
+ IF KANJI\r
+ CALL TESTKANJ\r
+ JZ NOTKANJ3\r
+ DEC SI\r
+ LODSW\r
+ INC DI\r
+ INC DI\r
+ CMP AX,ES:[DI-2]\r
+ JNZ FIND12\r
+ DEC CX\r
+ LOOP FIND11\r
+ JMP SHORT FIND12\r
+\r
+NOTKANJ3:\r
+ ENDIF\r
+\r
+ CALL UPCONV\r
+ INC DI\r
+ CMP AL,ES:[DI-1]\r
+ JNZ FIND12\r
+ LOOP FIND11\r
+FIND12:\r
+ POP DI\r
+ POP SI\r
+ POP CX\r
+ retz\r
+ PUSH CX\r
+ CALL SCASB2 ; SCAN FOR A NUL\r
+ POP CX\r
+ CMP BYTE PTR ES:[DI],0\r
+ JNZ FIND1\r
+ STC ; INDICATE NOT FOUND\r
+ return\r
+\r
+COUNT0:\r
+ PUSH DS\r
+ POP ES\r
+ MOV DI,SI\r
+\r
+COUNT1:\r
+ PUSH DI ; COUNT NUMBER OF CHARS UNTIL "="\r
+ CALL SCASB1\r
+ JMP SHORT COUNTX\r
+COUNT2:\r
+ PUSH DI ; COUNT NUMBER OF CHARS UNTIL NUL\r
+ CALL SCASB2\r
+COUNTX:\r
+ POP CX\r
+ SUB DI,CX\r
+ XCHG DI,CX\r
+ return\r
+\r
+MOVE_NAME:\r
+ CMP BYTE PTR DS:[SI],13\r
+ retz\r
+ LODSB\r
+\r
+ IF KANJI\r
+ CALL TESTKANJ\r
+ JZ NOTKANJ1\r
+ CALL STORE_CHAR\r
+ LODSB\r
+ CALL STORE_CHAR\r
+ JMP SHORT MOVE_NAME\r
+\r
+NOTKANJ1:\r
+ ENDIF\r
+\r
+ CALL UPCONV\r
+ CALL STORE_CHAR\r
+ CMP AL,"="\r
+ JNZ MOVE_NAME\r
+ return\r
+\r
+GETARG:\r
+ MOV SI,80H\r
+ LODSB\r
+ OR AL,AL\r
+ retz\r
+ CALL SCANOFF\r
+ CMP AL,13\r
+ return\r
+\r
+SCAN_DOUBLE_NULL:\r
+ MOV ES,[RESSEG]\r
+ASSUME ES:RESGROUP\r
+ MOV ES,[ENVIRSEG]\r
+ASSUME ES:NOTHING\r
+ XOR DI,DI\r
+SDN1:\r
+ CALL SCASB2\r
+ CMP BYTE PTR ES:[DI],0\r
+ JNZ SDN1\r
+ return\r
+\r
+SCASB1:\r
+ MOV AL,"=" ; SCAN FOR AN =\r
+ JMP SHORT SCASBX\r
+SCASB2:\r
+ XOR AL,AL ; SCAN FOR A NUL\r
+SCASBX:\r
+ MOV CX,100H\r
+ REPNZ SCASB\r
+ return\r
+\r
+ IF KANJI\r
+TESTKANJ:\r
+ CMP AL,81H\r
+ JB NOTLEAD\r
+ CMP AL,9FH\r
+ JBE ISLEAD\r
+ CMP AL,0E0H\r
+ JB NOTLEAD\r
+ CMP AL,0FCH\r
+ JBE ISLEAD\r
+NOTLEAD:\r
+ PUSH AX\r
+ XOR AX,AX ;Set zero\r
+ POP AX\r
+ return\r
+\r
+ISLEAD:\r
+ PUSH AX\r
+ XOR AX,AX ;Set zero\r
+ INC AX ;Reset zero\r
+ POP AX\r
+ return\r
+ ENDIF\r
+\r
+UPCONV:\r
+ CMP AL,"a"\r
+ JB RET22C\r
+ CMP AL,"z"\r
+ JA RET22C\r
+ SUB AL,20H ; Lower-case changed to upper-case\r
+RET22C:\r
+ CALL DWORD PTR CS:[INTERNATVARS.Map_call]\r
+ return\r
+;\r
+; STORE A CHAR IN environment, GROWING IT IF NECESSARY\r
+;\r
+STORE_CHAR:\r
+ PUSH CX\r
+ PUSH BX\r
+ CALL GETENVSIZ\r
+ MOV BX,CX\r
+ SUB BX,2 ; SAVE ROOM FOR DOUBLE NULL\r
+ CMP DI,BX\r
+ JB STORE1\r
+\r
+ PUSH AX\r
+ PUSH CX\r
+ PUSH BX ; Save Size of environment\r
+ CALL FREE_TPA\r
+ POP BX\r
+ ADD BX,2 ; Recover true environment size\r
+ MOV CL,4\r
+ SHR BX,CL ; Convert back to paragraphs\r
+ INC BX ; Try to grow environment by one para\r
+ MOV AH,SETBLOCK\r
+ INT int_command\r
+ PUSHF\r
+ PUSH ES\r
+ MOV ES,[RESSEG]\r
+ CALL ALLOC_TPA\r
+ POP ES\r
+ POPF\r
+ POP CX\r
+ POP AX\r
+ JNC STORE1\r
+ MOV DX,OFFSET TRANGROUP:ENVERR\r
+ JMP CERROR\r
+STORE1:\r
+ STOSB\r
+ MOV WORD PTR ES:[DI],0 ; NULL IS AT END\r
+ POP BX\r
+ POP CX\r
+ return\r
+\r
+GETENVSIZ:\r
+;Get size of environment in bytes, rounded up to paragraph boundry\r
+;ES has environment segment\r
+;Size returned in CX, all other registers preserved\r
+\r
+ PUSH ES\r
+ PUSH AX\r
+ MOV AX,ES\r
+ DEC AX ;Point at arena\r
+ MOV ES,AX\r
+ MOV AX,ES:[arena_size]\r
+ MOV CL,4\r
+ SHL AX,CL ;Convert to bytes\r
+ MOV CX,AX\r
+ POP AX\r
+ POP ES\r
+ return\r
+\r
+PRINT_DRIVE:\r
+ MOV AH,GET_DEFAULT_DRIVE\r
+ INT int_command\r
+ ADD AL,"A"\r
+ JMP OUT\r
+\r
+ASSUME DS:TRANGROUP,ES:TRANGROUP\r
+PWD:\r
+ CALL PRINT_DIRECTORY\r
+ CALL CRLF2\r
+ return\r
+\r
+PRINT_DEFAULT_DIRECTORY:\r
+ MOV BYTE PTR DS:[FCB],0\r
+PRINT_DIRECTORY:\r
+ MOV DL,DS:[FCB]\r
+ MOV AL,DL\r
+ ADD AL,'@'\r
+ CMP AL,'@'\r
+ JNZ GOTDRIVE\r
+ ADD AL,[CURDRV]\r
+ INC AL\r
+GOTDRIVE:\r
+ PUSH AX\r
+ MOV SI,OFFSET TRANGROUP:PWDBUF+3\r
+ MOV AH,CURRENT_DIR\r
+ INT int_command\r
+ JNC DPBISOK\r
+ PUSH CS\r
+ POP DS\r
+ JMP DRVBAD\r
+DPBISOK:\r
+ MOV DI,OFFSET TRANGROUP:PWDBUF\r
+ MOV DX,DI\r
+ POP AX\r
+ MOV AH,DRVCHAR\r
+ STOSW\r
+ MOV AL,[DIRCHAR]\r
+ STOSB\r
+ JMP ZPRINT\r
+\r
+$EXIT:\r
+ PUSH ES\r
+ MOV ES,[RESSEG]\r
+ASSUME ES:RESGROUP\r
+ MOV AX,[PARENT]\r
+ MOV WORD PTR ES:[PDB_Parent_PID],AX\r
+\r
+IF IBM\r
+ CMP [PERMCOM],0\r
+ JNZ NORESETVEC ;Don't reset the vector if a PERMCOM\r
+ LDS DX,DWORD PTR ES:[SYS_CALL]\r
+ASSUME DS:NOTHING\r
+ MOV AX,(SET_INTERRUPT_VECTOR SHL 8) + INT_COMMAND\r
+ INT int_command\r
+NORESETVEC:\r
+ENDIF\r
+\r
+ POP ES\r
+ASSUME ES:TRANGROUP\r
+ MOV ES,[TPA]\r
+ MOV AH,DEALLOC\r
+ INT int_command ; Now running in "free" space\r
+ MOV AX,(EXIT SHL 8)\r
+ INT int_command\r
+\r
+CTTY:\r
+ CALL SETPATH ; Get spec\r
+ MOV AX,(OPEN SHL 8) OR 2 ; Read and write\r
+ INT int_command ; Open new device\r
+ JC ISBADDEV\r
+ MOV BX,AX\r
+ MOV AX,IOCTL SHL 8\r
+ INT int_command\r
+ TEST DL,80H\r
+ JNZ DEVISOK\r
+ MOV AH,CLOSE ; Close initial handle\r
+ INT int_command\r
+ISBADDEV:\r
+ MOV DX,OFFSET TRANGROUP:BADDEV\r
+ CALL PRINT\r
+ JMP RESRET\r
+\r
+DEVISOK:\r
+ XOR DH,DH\r
+ OR DL,3 ; Make sure has CON attributes\r
+ MOV AX,(IOCTL SHL 8) OR 1\r
+ INT int_command\r
+ PUSH BX ; Save handle\r
+ MOV CX,3\r
+ XOR BX,BX\r
+ICLLOOP: ; Close basic handles\r
+ MOV AH,CLOSE\r
+ INT int_command\r
+ INC BX\r
+ LOOP ICLLOOP\r
+ POP BX ; Get handle\r
+ MOV AH,XDUP\r
+ INT int_command ; Dup it to 0\r
+ MOV AH,XDUP\r
+ INT int_command ; Dup to 1\r
+ MOV AH,XDUP\r
+ INT int_command ; Dup to 2\r
+ MOV AH,CLOSE ; Close initial handle\r
+ INT int_command\r
+RESRET:\r
+ MOV DS,[RESSEG]\r
+ASSUME DS:RESGROUP\r
+ PUSH DS\r
+ MOV AX,WORD PTR DS:[PDB_JFN_Table] ; Get new 0 and 1\r
+ MOV [IO_SAVE],AX\r
+ MOV AX,OFFSET RESGROUP:LODCOM1\r
+ PUSH AX\r
+ZMMMM PROC FAR\r
+ RET ; Force header to be checked\r
+ZMMMM ENDP\r
+\r
+TRANCODE ENDS\r
+ END\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+TITLE PART3 - COMMAND Transient routines.\r
+\r
+ INCLUDE COMSW.ASM\r
+\r
+.xlist\r
+.xcref\r
+ INCLUDE DOSSYM.ASM\r
+ INCLUDE DEVSYM.ASM\r
+ INCLUDE COMSEG.ASM\r
+.list\r
+.cref\r
+\r
+ INCLUDE COMEQU.ASM\r
+\r
+\r
+DATARES SEGMENT PUBLIC\r
+ EXTRN BATCH:WORD,BATLOC:DWORD\r
+ EXTRN RETCODE:WORD,ECHOFLAG:BYTE\r
+ EXTRN SINGLECOM:WORD,FORFLAG:BYTE,UFORDRV:BYTE\r
+ EXTRN FORSET:BYTE,FORCOM:BYTE,FORVAR:BYTE,FORPTR:WORD\r
+ EXTRN FORUFCB:BYTE,FORFCB:BYTE,RE_INSTR:BYTE,RE_OUT_APP:BYTE\r
+ EXTRN RE_OUTSTR:BYTE,PIPEFLAG:BYTE\r
+\r
+DATARES ENDS\r
+\r
+TRANDATA SEGMENT PUBLIC\r
+\r
+ EXTRN BADLAB:BYTE,SYNTMES:BYTE,FORNESTMES:BYTE\r
+ EXTRN NOTFND:BYTE,FULDIR:BYTE,IFTAB:BYTE\r
+TRANDATA ENDS\r
+\r
+TRANSPACE SEGMENT PUBLIC\r
+\r
+ EXTRN BATHAND:WORD,RESSEG:WORD,DIRBUF:BYTE,COMBUF:BYTE\r
+ EXTRN GOTOLEN:WORD,IFNOTFLAG:BYTE\r
+\r
+TRANSPACE ENDS\r
+\r
+\r
+TRANCODE SEGMENT PUBLIC BYTE\r
+ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING\r
+\r
+ EXTRN SCANOFF:NEAR,DOCOM:NEAR,DOCOM1:NEAR,CERROR:NEAR\r
+ EXTRN PRINT:NEAR,TCOMMAND:NEAR,DELIM:NEAR,GETBATBYT:NEAR\r
+ EXTRN FCB_TO_ASCZ:NEAR\r
+\r
+ PUBLIC GOTO,$IF,IFERLEV,SHIFT,IFEXISTS\r
+ PUBLIC STRCOMP,MesTran,$FOR,IFNOT\r
+ PUBLIC FORPROC,BATOPEN,BATCLOSE\r
+ PUBLIC IOSET,TESTDOREIN,TESTDOREOUT\r
+\r
+ ASSUME DS:RESGROUP\r
+FORTERM:\r
+ MOV [FORFLAG],0\r
+ CMP [SINGLECOM],0FF00H\r
+ JNZ NOFORP2\r
+ MOV [SINGLECOM],-1 ; Cause a terminate\r
+NOFORP2:\r
+ JMP TCOMMAND\r
+\r
+FORPROC:\r
+ASSUME DS:RESGROUP\r
+ CMP [FORUFCB],-1\r
+ JZ NORMFOR\r
+ MOV DX,OFFSET TRANGROUP:DIRBUF\r
+ PUSH DS\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:TRANGROUP\r
+ MOV AH,SET_DMA\r
+ INT int_command\r
+ POP DS\r
+ASSUME DS:RESGROUP\r
+ MOV DX,OFFSET RESGROUP:FORFCB\r
+ MOV AH,DIR_SEARCH_NEXT\r
+ CMP [FORUFCB],0\r
+ JZ DOFORSRCH\r
+ MOV AH,DIR_SEARCH_FIRST\r
+ MOV [FORUFCB],0\r
+DOFORSRCH:\r
+ INT int_command\r
+ OR AL,AL\r
+ JNZ FORTERM\r
+ PUSH DS\r
+ POP ES\r
+ASSUME ES:RESGROUP\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:TRANGROUP\r
+ MOV SI,OFFSET TRANGROUP:DIRBUF\r
+ MOV DI,OFFSET RESGROUP:FORSET\r
+ MOV [FORPTR],DI\r
+ LODSB ;Get drive spec\r
+ ADD AL,'@'\r
+ CMP AL,'@'\r
+ JZ NDRV8\r
+ CMP [UFORDRV],0\r
+ JZ NDRV8\r
+ MOV AH,':'\r
+ STOSW\r
+NDRV8:\r
+ CALL FCB_TO_ASCZ\r
+ MOV BYTE PTR ES:[DI-1],0DH\r
+ PUSH ES\r
+ POP DS\r
+ASSUME DS:RESGROUP\r
+NORMFOR:\r
+ PUSH CS\r
+ POP ES\r
+ASSUME ES:TRANGROUP\r
+ MOV BX,[FORPTR]\r
+ CMP BYTE PTR [BX],0\r
+ JZ FORTERM\r
+ MOV SI,BX\r
+PARMSUB0:\r
+ LODSB\r
+ CMP AL,0DH\r
+ JNZ PARMSUB0\r
+ MOV DX,SI ; DX points to next parm\r
+ MOV SI,OFFSET RESGROUP:FORCOM\r
+ MOV DI,OFFSET TRANGROUP:COMBUF+2\r
+ XOR CX,CX\r
+TFORCOM:\r
+ LODSB\r
+ CMP AL,'%'\r
+ JNZ NOFORPARM\r
+ MOV AH,[FORVAR]\r
+ CMP AH,[SI]\r
+ JNZ NOFORPARM\r
+ INC SI\r
+ PUSH SI\r
+ MOV SI,BX\r
+PARMSUB:\r
+ LODSB\r
+ CMP AL,0DH\r
+ JZ PARMSUBDONE\r
+ INC CX\r
+ STOSB\r
+ JMP SHORT PARMSUB\r
+PARMSUBDONE:\r
+ POP SI ; Get back command line pointer\r
+ JMP TFORCOM\r
+NOFORPARM:\r
+ STOSB\r
+ INC CX\r
+ CMP AL,0DH\r
+ JNZ TFORCOM\r
+ DEC CX\r
+ MOV [COMBUF+1],CL\r
+ MOV [FORPTR],DX ; Point to next set element\r
+ TEST [ECHOFLAG],-1\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:TRANGROUP\r
+ JZ NOECHO3\r
+ MOV BYTE PTR ES:[DI-1],'$'\r
+ MOV DX,OFFSET TRANGROUP:COMBUF+2\r
+ CALL PRINT\r
+ MOV BYTE PTR ES:[DI-1],0DH\r
+ JMP DOCOM\r
+NOECHO3:\r
+ JMP DOCOM1\r
+\r
+ASSUME DS:TRANGROUP,ES:TRANGROUP\r
+\r
+FORNESTERR:\r
+ PUSH DS\r
+ MOV DS,[RESSEG]\r
+ASSUME DS:RESGROUP\r
+ MOV DX,OFFSET TRANGROUP:FORNESTMES\r
+ CMP [SINGLECOM],0FF00H\r
+ JNZ NOFORP3\r
+ MOV [SINGLECOM],-1 ; Cause termination\r
+NOFORP3:\r
+ POP DS\r
+ASSUME DS:TRANGROUP\r
+ JMP CERROR\r
+\r
+$FOR:\r
+ MOV SI,81H\r
+ XOR CX,CX\r
+ MOV ES,[RESSEG]\r
+ASSUME ES:RESGROUP\r
+ MOV DI,OFFSET RESGROUP:FORSET\r
+ XOR AL,AL\r
+ MOV [UFORDRV],AL\r
+ XCHG AL,[FORFLAG]\r
+ OR AL,AL\r
+ JNZ FORNESTERR\r
+ MOV [FORPTR],DI\r
+ MOV [FORUFCB],-1\r
+ CALL SCANOFF\r
+ LODSW\r
+ CMP AL,'%'\r
+ JNZ FORERRORJ\r
+ MOV [FORVAR],AH\r
+ CALL SCANOFF\r
+ CMP AL,0DH\r
+ JZ FORERRORJ2\r
+ LODSW\r
+ CMP AX,('N' SHL 8) OR 'I'\r
+ JZ FOROK1\r
+ CMP AX,('n' SHL 8) OR 'i'\r
+ JNZ FORERRORJ\r
+FOROK1:\r
+ CALL SCANOFF\r
+ LODSB\r
+ CMP AL,'('\r
+ JNZ FORERRORJ\r
+ CALL SCANOFF\r
+ CMP AL,')' ; Special check for null set\r
+ JNZ FORSETLP\r
+ MOV DS,[RESSEG]\r
+ JMP FORTERM\r
+FORSETLP:\r
+ LODSB\r
+ CMP AL,0DH\r
+FORERRORJ2:\r
+ JZ FORERRORJ3\r
+ CMP AL,')'\r
+ JZ FORSETEND\r
+ STOSB\r
+ CMP AL,'*'\r
+ JZ SETFORSCAN\r
+ CMP AL,'?'\r
+ JNZ NOFORSCAN\r
+SETFORSCAN:\r
+ MOV [FORUFCB],1\r
+NOFORSCAN:\r
+ CALL DELIM\r
+ JNZ FORSETLP\r
+ MOV BYTE PTR ES:[DI-1],0DH\r
+ CALL SCANOFF\r
+ JMP FORSETLP\r
+\r
+FORSETEND:\r
+ MOV AX,000DH\r
+ CMP BYTE PTR ES:[DI-1],0DH\r
+ JNZ FORSETTERM\r
+ XOR AX,AX\r
+FORSETTERM:\r
+ STOSW\r
+ CALL SCANOFF\r
+ LODSW\r
+ CMP AX,('O' SHL 8) OR 'D'\r
+ JZ FOROK2\r
+ CMP AX,('o' SHL 8) OR 'd'\r
+FORERRORJ:\r
+ JNZ FORERROR\r
+FOROK2:\r
+ CALL SCANOFF\r
+ CMP AL,0DH\r
+FORERRORJ3:\r
+ JZ FORERROR\r
+ MOV DI,OFFSET RESGROUP:FORCOM\r
+FORCOMLP:\r
+ LODSB\r
+ STOSB\r
+ CMP AL,0DH\r
+ JNZ FORCOMLP\r
+ INC [FORFLAG]\r
+ CMP [SINGLECOM],-1\r
+ JNZ NOFORP\r
+ MOV [SINGLECOM],0FF00H ; Flag single command for\r
+NOFORP:\r
+ CMP [FORUFCB],1\r
+ retnz\r
+ PUSH ES\r
+ POP DS\r
+ASSUME DS:RESGROUP\r
+ MOV DI,OFFSET RESGROUP:FORFCB\r
+ MOV SI,OFFSET RESGROUP:FORSET\r
+ CMP BYTE PTR [SI+1],':'\r
+ JNZ NOSETUDRV\r
+ INC [UFORDRV]\r
+NOSETUDRV:\r
+ MOV AX,PARSE_FILE_DESCRIPTOR SHL 8\r
+ INT int_command\r
+ return\r
+\r
+\r
+ASSUME DS:TRANGROUP,ES:TRANGROUP\r
+\r
+IFERRORP:\r
+ POP AX\r
+IFERROR:\r
+FORERROR:\r
+ MOV DX,OFFSET TRANGROUP:SYNTMES\r
+ JMP CERROR\r
+\r
+$IF:\r
+ MOV [IFNOTFLAG],0\r
+ MOV SI,81H\r
+IFREENT:\r
+ CALL SCANOFF\r
+ CMP AL,0DH\r
+ JZ IFERROR\r
+ MOV BP,SI\r
+ MOV DI,OFFSET TRANGROUP:IFTAB ; Prepare to search if table\r
+ MOV CH,0\r
+IFINDCOM:\r
+ MOV SI,BP\r
+ MOV CL,[DI]\r
+ INC DI\r
+ JCXZ IFSTRING\r
+ JMP SHORT FIRSTCOMP\r
+IFCOMP:\r
+ JNZ IFDIF\r
+FIRSTCOMP:\r
+ LODSB\r
+ MOV AH,ES:[DI]\r
+ INC DI\r
+ CMP AL,AH\r
+ JZ IFLP\r
+ OR AH,20H ; Try lower case\r
+ CMP AL,AH\r
+IFLP:\r
+ LOOP IFCOMP\r
+IFDIF:\r
+ LAHF\r
+ ADD DI,CX ; Bump to next position without affecting flags\r
+ MOV BX,[DI] ; Get handler address\r
+ INC DI\r
+ INC DI\r
+ SAHF\r
+ JNZ IFINDCOM\r
+ LODSB\r
+ CMP AL,0DH\r
+IFERRORJ:\r
+ JZ IFERROR\r
+ CALL DELIM\r
+ JNZ IFINDCOM\r
+ CALL SCANOFF\r
+ JMP BX\r
+\r
+IFNOT:\r
+ NOT [IFNOTFLAG]\r
+ JMP IFREENT\r
+\r
+\r
+IFSTRING:\r
+ PUSH SI\r
+ XOR CX,CX\r
+FIRST_STRING:\r
+ LODSB\r
+ CMP AL,0DH\r
+ JZ IFERRORP\r
+ CALL DELIM\r
+ JZ EQUAL_CHECK\r
+ INC CX\r
+ JMP SHORT FIRST_STRING\r
+EQUAL_CHECK:\r
+ CMP AL,'='\r
+ JZ EQUAL_CHECK2\r
+ CMP AL,0DH\r
+ JZ IFERRORP\r
+ LODSB\r
+ JMP SHORT EQUAL_CHECK\r
+EQUAL_CHECK2:\r
+ LODSB\r
+ CMP AL,'='\r
+ JNZ IFERRORP\r
+ CALL SCANOFF\r
+ CMP AL,0DH\r
+ JZ IFERRORP\r
+ POP DI\r
+ REPE CMPSB\r
+ JZ MATCH\r
+ CMP BYTE PTR [SI-1],0DH\r
+ JZ IFERRORJ\r
+SKIPSTRINGEND:\r
+ LODSB\r
+NOTMATCH:\r
+ CMP AL,0DH\r
+IFERRORJ2:\r
+ JZ IFERRORJ\r
+ CALL DELIM\r
+ JNZ SKIPSTRINGEND\r
+ MOV AL,-1\r
+ JMP SHORT IFRET\r
+MATCH:\r
+ LODSB\r
+ CALL DELIM\r
+ JNZ NOTMATCH\r
+ XOR AL,AL\r
+ JMP SHORT IFRET\r
+\r
+IFEXISTS:\r
+ MOV DI,OFFSET TRANGROUP:DIRBUF\r
+ MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H\r
+ INT int_command\r
+ MOV AH,FCB_OPEN\r
+ MOV DX,DI\r
+ INT int_command\r
+IFRET:\r
+ TEST [IFNOTFLAG],-1\r
+ JZ REALTEST\r
+ NOT AL\r
+REALTEST:\r
+ OR AL,AL\r
+ JZ IFTRUE\r
+ JMP TCOMMAND\r
+IFTRUE:\r
+ CALL SCANOFF\r
+ MOV CX,SI\r
+ SUB CX,81H\r
+ SUB DS:[80H],CL\r
+ MOV CL,DS:[80H]\r
+ MOV [COMBUF+1],CL\r
+ MOV DI,OFFSET TRANGROUP:COMBUF+2\r
+ REP MOVSB\r
+ MOV AL,0DH\r
+ STOSB\r
+ JMP DOCOM1\r
+\r
+IFERLEV:\r
+ MOV BH,10\r
+ XOR BL,BL\r
+GETNUMLP:\r
+ LODSB\r
+ CMP AL,0DH\r
+ JZ IFERRORJ2\r
+ CALL DELIM\r
+ JZ GOTNUM\r
+ SUB AL,'0'\r
+ XCHG AL,BL\r
+ MUL BH\r
+ ADD AL,BL\r
+ XCHG AL,BL\r
+ JMP SHORT GETNUMLP\r
+GOTNUM:\r
+ PUSH DS\r
+ MOV DS,[RESSEG]\r
+ASSUME DS:RESGROUP\r
+ MOV AH,BYTE PTR [RETCODE]\r
+ POP DS\r
+ASSUME DS:TRANGROUP\r
+ XOR AL,AL\r
+ CMP AH,BL\r
+ JAE IFRET\r
+ DEC AL\r
+ JMP SHORT IFRET\r
+\r
+ASSUME DS:TRANGROUP\r
+\r
+SHIFT:\r
+ MOV DS,[RESSEG]\r
+ASSUME DS:RESGROUP\r
+ MOV AX,[BATCH]\r
+ TEST AX,-1\r
+ retz\r
+ MOV ES,AX\r
+ MOV DS,AX\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+ XOR CX,CX\r
+ MOV AX,CX\r
+ MOV DI,CX\r
+ DEC CX\r
+ REPNZ SCASB\r
+ MOV SI,DI\r
+ INC SI\r
+ INC SI\r
+ MOV CX,9\r
+ REP MOVSW ; Perform shift of existing parms\r
+ CMP WORD PTR [DI],-1\r
+ retz ; No new parm\r
+ MOV SI,[DI]\r
+ MOV WORD PTR [DI],-1 ; Assume no parm\r
+ MOV DS,[RESSEG]\r
+ASSUME DS:RESGROUP\r
+SKIPCRLP:\r
+ LODSB\r
+ CMP AL,0DH\r
+ JNZ SKIPCRLP\r
+ CMP BYTE PTR [SI],0\r
+ retz ; End of parms\r
+ MOV ES:[DI],SI ; Pointer to next parm as %9\r
+ return\r
+\r
+\r
+ASSUME DS:TRANGROUP,ES:TRANGROUP\r
+GOTO:\r
+ MOV DS,[RESSEG]\r
+ASSUME DS:RESGROUP\r
+ TEST [BATCH],-1\r
+ retz ; If not in batch mode, a nop\r
+ XOR DX,DX\r
+ MOV WORD PTR [BATLOC],DX ; Back to start\r
+ MOV WORD PTR [BATLOC+2],DX\r
+ CALL BATOPEN ; Find the batch file\r
+ MOV DI,FCB+1 ; Get the label\r
+ MOV CX,11\r
+ MOV AL,' '\r
+ REPNE SCASB\r
+ JNZ NOINC\r
+ INC CX\r
+NOINC:\r
+ SUB CX,11\r
+ NEG CX\r
+ MOV [GOTOLEN],CX\r
+ CALL GETBATBYT\r
+ CMP AL,':'\r
+ JZ CHKLABEL\r
+LABLKLP: ; Look for the label\r
+ CALL GETBATBYT\r
+ CMP AL,0AH\r
+ JNZ LABLKTST\r
+ CALL GETBATBYT\r
+ CMP AL,':'\r
+ JZ CHKLABEL\r
+LABLKTST:\r
+ TEST [BATCH],-1\r
+ JNZ LABLKLP\r
+ CALL BATCLOSE\r
+ PUSH CS\r
+ POP DS\r
+ MOV DX,OFFSET TRANGROUP:BADLAB\r
+ JMP CERROR\r
+\r
+CHKLABEL:\r
+ MOV DI,FCB+1\r
+ MOV CX,[GOTOLEN]\r
+NEXTCHRLP:\r
+ PUSH CX\r
+ CALL GETBATBYT\r
+ POP CX\r
+ OR AL,20H\r
+ CMP AL,ES:[DI]\r
+ JNZ TRYUPPER\r
+ JMP SHORT NEXTLABCHR\r
+TRYUPPER:\r
+ SUB AL,20H\r
+ CMP AL,ES:[DI]\r
+ JNZ LABLKTST\r
+NEXTLABCHR:\r
+ INC DI\r
+ LOOP NEXTCHRLP\r
+ CALL GETBATBYT\r
+ CMP AL,' '\r
+ JA LABLKTST\r
+ CMP AL,0DH\r
+ JZ SKIPLFEED\r
+TONEXTBATLIN:\r
+ CALL GETBATBYT\r
+ CMP AL,0DH\r
+ JNZ TONEXTBATLIN\r
+SKIPLFEED:\r
+ CALL GETBATBYT\r
+BATCLOSE:\r
+ MOV BX,CS:[BATHAND]\r
+ MOV AH,CLOSE\r
+ INT int_command\r
+ return\r
+\r
+BATOPEN:\r
+;Open the BATCH file, If open fails, AL is drive of batch file (A=1)\r
+ASSUME DS:RESGROUP,ES:TRANGROUP\r
+ PUSH DS\r
+ MOV DS,[BATCH]\r
+ASSUME DS:NOTHING\r
+ XOR DX,DX\r
+ MOV AX,OPEN SHL 8\r
+ INT int_command ; Open the batch file\r
+ JC SETERRDL\r
+ POP DS\r
+ASSUME DS:RESGROUP\r
+ MOV [BATHAND],AX\r
+ MOV BX,AX\r
+ MOV DX,WORD PTR [BATLOC]\r
+ MOV CX,WORD PTR [BATLOC+2]\r
+ MOV AX,LSEEK SHL 8 ; Go to the right spot\r
+ INT int_command\r
+ return\r
+\r
+SETERRDL:\r
+ MOV BX,DX\r
+ MOV AL,[BX] ; Get drive spec\r
+ SUB AL,'@' ; A = 1\r
+ POP DS\r
+ STC ; SUB mucked over carry\r
+ return\r
+\r
+MESTRAN:\r
+ASSUME DS:NOTHING,ES:NOTHING\r
+ LODSB\r
+ CMP AL,"$"\r
+ retz\r
+ STOSB\r
+ JMP MESTRAN\r
+IOSET:\r
+; ALL REGISTERS PRESERVED\r
+ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING\r
+ PUSH DS\r
+ PUSH DX\r
+ PUSH AX\r
+ PUSH BX\r
+ PUSH CX\r
+ MOV DS,[RESSEG]\r
+ASSUME DS:RESGROUP\r
+ CMP [PIPEFLAG],0\r
+ JNZ NOREDIR ; Don't muck up the pipe\r
+ CALL TESTDOREIN\r
+ CALL TESTDOREOUT\r
+NOREDIR:\r
+ POP CX\r
+ POP BX\r
+ POP AX\r
+ POP DX\r
+ POP DS\r
+ASSUME DS:NOTHING\r
+ return\r
+\r
+TESTDOREIN:\r
+ASSUME DS:RESGROUP\r
+ CMP [RE_INSTR],0\r
+ retz\r
+ MOV DX,OFFSET RESGROUP:RE_INSTR\r
+ MOV AX,(OPEN SHL 8)\r
+ INT int_command\r
+ MOV DX,OFFSET TRANGROUP:NOTFND\r
+ JC REDIRERR\r
+ MOV BX,AX\r
+ MOV AL,0FFH\r
+ XCHG AL,[BX.PDB_JFN_Table]\r
+ MOV DS:[PDB_JFN_Table],AL\r
+ return\r
+\r
+REDIRERR:\r
+ PUSH CS\r
+ POP DS\r
+ JMP CERROR\r
+\r
+TESTDOREOUT:\r
+ASSUME DS:RESGROUP\r
+ CMP [RE_OUTSTR],0\r
+ JZ NOREOUT\r
+ CMP [RE_OUT_APP],0\r
+ JZ REOUTCRT\r
+ MOV DX,OFFSET RESGROUP:RE_OUTSTR\r
+ MOV AX,(OPEN SHL 8) OR 1\r
+ INT int_command\r
+ JC REOUTCRT\r
+ XOR DX,DX\r
+ XOR CX,CX\r
+ MOV BX,AX\r
+ MOV AX,(LSEEK SHL 8) OR 2\r
+ INT int_command\r
+ JMP SHORT SET_REOUT\r
+REOUTCRT:\r
+ MOV DX,OFFSET RESGROUP:RE_OUTSTR\r
+ XOR CX,CX\r
+ MOV AH,CREAT\r
+ INT int_command\r
+ MOV DX,OFFSET TRANGROUP:FULDIR\r
+ JC REDIRERR\r
+ MOV BX,AX\r
+SET_REOUT:\r
+ MOV AL,0FFH\r
+ XCHG AL,[BX.PDB_JFN_Table]\r
+ MOV DS:[PDB_JFN_Table+1],AL\r
+NOREOUT:\r
+ return\r
+\r
+STRCOMP:\r
+; Compare ASCIZ DS:SI with ES:DI.\r
+; SI,DI destroyed.\r
+ CMPSB\r
+ retnz ; Strings not equal\r
+ cmp byte ptr [SI-1],0 ; Hit NUL terminator?\r
+ retz ; Yes, strings equal\r
+ jmp short STRCOMP ; Equal so far, keep going\r
+\r
+\r
+\r
+TRANCODE ENDS\r
+ END\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+TITLE PART4 - COMMAND Transient routines.\r
+\r
+ INCLUDE COMSW.ASM\r
+\r
+.xlist\r
+.xcref\r
+ INCLUDE DOSSYM.ASM\r
+ INCLUDE DEVSYM.ASM\r
+ INCLUDE COMSEG.ASM\r
+.list\r
+.cref\r
+\r
+ INCLUDE COMEQU.ASM\r
+\r
+\r
+DATARES SEGMENT PUBLIC\r
+ EXTRN RESTDIR:BYTE\r
+DATARES ENDS\r
+\r
+TRANDATA SEGMENT PUBLIC\r
+ EXTRN BADDRV:BYTE,BADSWT:BYTE\r
+ EXTRN BADDAT:BYTE,NEWDAT:BYTE,BADTIM:BYTE\r
+ EXTRN DMES:BYTE,CURDAT_PRE:BYTE,CURDAT_MID:BYTE,CURDAT_POST:BYTE\r
+ EXTRN RENERR:BYTE,VERMES_PRE:BYTE,VERMES_POST:BYTE\r
+ EXTRN DIRHEAD_PRE:BYTE,DIRHEAD_POST:BYTE\r
+ EXTRN ACRLF:BYTE,BADARGS:BYTE,NOTFND:BYTE\r
+ EXTRN NEWTIM:BYTE,BADCD:BYTE,BADMKD:BYTE,CLSSTRING:BYTE\r
+ EXTRN CURTIM_PRE:BYTE,CURTIM_POST:BYTE,PauseMes:BYTE\r
+ EXTRN BADRMD:BYTE\r
+TRANDATA ENDS\r
+\r
+TRANSPACE SEGMENT PUBLIC\r
+ EXTRN COMBUF:BYTE,DIRCHAR:BYTE,USERDIR1:BYTE\r
+ EXTRN BYTCNT:WORD,CURDRV:BYTE,COMSW:WORD,ARGTS:WORD\r
+ EXTRN LINCNT:BYTE,LINLEN:BYTE,FILECNT:WORD,CHARBUF:BYTE\r
+ EXTRN DIRBUF:BYTE,BITS:WORD,PATHPOS:WORD\r
+ EXTRN DESTISDIR:BYTE,DESTTAIL:WORD,DESTINFO:BYTE,FULLSCR:WORD\r
+ EXTRN INTERNATVARS:BYTE,RESSEG:WORD,TPA:WORD\r
+TRANSPACE ENDS\r
+\r
+\r
+TRANCODE SEGMENT PUBLIC BYTE\r
+ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING\r
+\r
+ EXTRN NOTEST2:NEAR,PRINTVOL:NEAR,Print_Date:NEAR\r
+ EXTRN CERROR:NEAR,SWITCH:NEAR,PWD:NEAR,SETREST:NEAR,MESTRAN:NEAR\r
+ EXTRN NOTFNDERR:NEAR,CHKCNT:NEAR,GETKEYSTROKE:NEAR\r
+ EXTRN SETPATH:NEAR,PATHCRUNCH:NEAR,PRINT:NEAR,ZPRINT:NEAR\r
+ EXTRN DISPSIZE:NEAR,OUT:NEAR,OUT2:NEAR,ERROR_PRINT:NEAR\r
+ EXTRN SCANOFF:NEAR,OUTBYTE:NEAR,GETNUM:NEAR,ERROR_OUTPUT:NEAR\r
+\r
+\r
+ PUBLIC PRINT_TIME,CATALOG\r
+ PUBLIC BADCDERR,PRINT_VERSION,CLS,SAVUDIR,SAVUDIR1\r
+ PUBLIC TYPEFIL,CRENAME,$RMDIR\r
+ PUBLIC CTIME,$CHDIR,ONESPC,DATINIT\r
+ PUBLIC $MKDIR,VERSION,RESTUDIR1\r
+ PUBLIC RESTUDIR,CRLF2,ERASE\r
+ PUBLIC volume,date,P_date,PAUSE\r
+ \r
+\r
+CATALOG:\r
+ CALL OKVOLARG\r
+ MOV AL,"?" ; *.* is default file spec.\r
+ MOV DI,5DH\r
+ MOV CX,11\r
+ REP STOSB\r
+ MOV SI,81H\r
+ CALL SWITCH\r
+ MOV DI,FCB\r
+ MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 0DH ; Parse with default name and extension\r
+ INT int_command\r
+\r
+; Begin by processing any switches that may have been specified.\r
+; BITS will contain any information about switches that was\r
+; found when the command line was parsed.\r
+\r
+SETSWT:\r
+ MOV AX,[COMSW] ; Get switches from command\r
+ OR AX,[ARGTS] ; OR in switches from all of tail\r
+ MOV [BITS],AX\r
+ MOV BYTE PTR[FULLSCR],LINPERPAG\r
+ TEST AL,1 ; Look for W switch\r
+ MOV AL,NORMPERLIN\r
+ JZ DIR\r
+ MOV AL,WIDEPERLIN\r
+DIR:\r
+ MOV [LINLEN],AL ; Set number of entries per line\r
+ MOV [LINCNT],AL\r
+ MOV [FILECNT],0 ; Keep track of how many files found\r
+ MOV DX,OFFSET TRANGROUP:DIRBUF ; Set Disk transfer address\r
+ MOV AH,SET_DMA\r
+ INT int_command\r
+ CALL PATHCRUNCH ; Get where we're going\r
+ PUSHF\r
+ JNC NOTEST\r
+ CMP [DESTISDIR],0 ; No CHDIRs worked\r
+ JZ NOTEST ; see if they should have\r
+ JMP BADCDERR\r
+\r
+NOTEST:\r
+ MOV SI,FCB\r
+ MOV DI,OFFSET TRANGROUP:DIRBUF\r
+ MOV DX,DI\r
+ MOV CX,12\r
+ REP MOVSB\r
+ MOV AH,FCB_OPEN\r
+ INT int_command\r
+ MOV DX,OFFSET TRANGROUP:DIRHEAD_PRE ; Print "Directory of"\r
+ PUSH AX ; save return code\r
+ CALL PRINT\r
+ CALL PWD ; print the path\r
+ MOV DX,OFFSET TRANGROUP:DIRHEAD_POST\r
+ CALL PRINT\r
+ POP AX\r
+ OR AL,AL\r
+ JNZ OKDODIR ; Go ahead and dir if open fail\r
+ TEST [DIRBUF+fcb_DEVID],devid_device\r
+ JZ OKDODIR\r
+ JMP NOTFNDERR ; Can't DIR a device\r
+OKDODIR:\r
+ MOV AH,DIR_SEARCH_FIRST\r
+ MOV BYTE PTR DS:[FCB-7],0FFH\r
+ MOV BYTE PTR DS:[FCB-1],010H\r
+ POPF\r
+ JC SHOWDIR ; Current dir\r
+ JZ DOFIRST ; FCB is *.*\r
+ MOV AL,"?"\r
+ MOV DI,5DH\r
+ MOV CX,11\r
+ REP STOSB ; Remake default FCB\r
+ MOV SI,[DESTTAIL]\r
+ MOV DI,FCB\r
+ MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 0EH ; Parse with default drive, name and extension\r
+ INT int_command\r
+ MOV AH,DIR_SEARCH_FIRST\r
+DOFIRST:\r
+ MOV DX,FCB-7\r
+ INT int_command\r
+ PUSH AX\r
+ CALL RESTUDIR\r
+ POP AX\r
+ JMP SHORT DIRSTART\r
+\r
+SHOWDIR:\r
+ MOV DX,FCB-7 ; DX -> Unopened FCB\r
+ INT int_command ; Search for a file to match FCB\r
+DIRSTART:\r
+ INC AL ; FF = file not found\r
+ JNZ AGAIN ; Either an error or we are finished\r
+ JMP CHKCNT\r
+NEXENTJ:\r
+ JMP NEXENT\r
+AGAIN:\r
+ INC [FILECNT] ; Keep track of how many we find\r
+ MOV SI,OFFSET TRANGROUP:DIRBUF+8 ; SI -> information returned by sys call\r
+ CALL SHONAME\r
+ TEST BYTE PTR[BITS],WSWITCH ; W switch set?\r
+ JNZ NEXENTJ ; If so, no size, date, or time\r
+ MOV SI,OFFSET TRANGROUP:DIRBUF+8+dir_attr\r
+ TEST BYTE PTR [SI],attr_directory\r
+ JZ FILEENT\r
+ MOV DX,OFFSET TRANGROUP:DMES\r
+ CALL PRINT\r
+ JMP SHORT NOFSIZ\r
+FILEENT:\r
+ CALL DISPSIZE ; Print size of file\r
+NOFSIZ:\r
+ MOV AX,WORD PTR [DIRBUF+8+dir_date] ; Get date\r
+ OR AX,AX\r
+ JZ NEXENT ; Skip if no date\r
+ MOV DI,OFFSET TRANGROUP:CHARBUF\r
+ PUSH AX\r
+ MOV AX," "\r
+ STOSW\r
+ POP AX\r
+ MOV BX,AX\r
+ AND AX,1FH ; get day\r
+ MOV DL,AL\r
+ MOV AX,BX\r
+ MOV CL,5\r
+ SHR AX,CL ; Align month\r
+ AND AL,0FH ; Get month\r
+ MOV DH,AL\r
+ MOV CL,BH\r
+ SHR CL,1 ; Align year\r
+ XOR CH,CH\r
+ ADD CX,80 ; Relative 1980\r
+ CMP CL,100\r
+ JB MILLENIUM\r
+ SUB CL,100\r
+MILLENIUM:\r
+ CALL DATE_CXDX\r
+ MOV CX,WORD PTR[DIRBUF+8+dir_time] ; Get time\r
+ JCXZ PRBUF ; Time field present?\r
+ MOV AX," "\r
+ STOSW\r
+ SHR CX,1\r
+ SHR CX,1\r
+ SHR CX,1\r
+ SHR CL,1\r
+ SHR CL,1 ; Hours in CH, minutes in CL\r
+ MOV BL,[INTERNATVARS.Time_24]\r
+ OR BL,80H ; Tell P_TIME called from DIR\r
+ CALL P_TIME ; Don't care about DX, never used with DIR\r
+PRBUF:\r
+ XOR AX,AX\r
+ STOSB\r
+ MOV DX,OFFSET TRANGROUP:CHARBUF\r
+ CALL ZPRINT\r
+NEXENT:\r
+ DEC [LINCNT]\r
+ JNZ SAMLIN\r
+NEXLIN:\r
+ MOV AL,[LINLEN]\r
+ MOV [LINCNT],AL\r
+ CALL CRLF2\r
+ TEST BYTE PTR[BITS],PSWITCH ; P switch present?\r
+ JZ SCROLL ; If not, just continue\r
+ DEC BYTE PTR[FULLSCR]\r
+ JNZ SCROLL\r
+ MOV BYTE PTR[FULLSCR],LINPERPAG\r
+ MOV DX,OFFSET TRANGROUP:PAUSEMES\r
+ CALL PRINT\r
+ CALL GetKeystroke\r
+ CALL CRLF2\r
+SCROLL:\r
+ MOV AH,DIR_SEARCH_NEXT\r
+ JMP SHOWDIR\r
+\r
+SAMLIN:\r
+ MOV AL,9 ; Output a tab\r
+ CALL OUT\r
+ JMP SHORT SCROLL\r
+\r
+SHONAME:\r
+ MOV DI,OFFSET TRANGROUP:CHARBUF\r
+ MOV CX,8\r
+ REP MOVSB\r
+ MOV AL," "\r
+ STOSB\r
+ MOV CX,3\r
+ REP MOVSB\r
+ XOR AX,AX\r
+ STOSB\r
+ PUSH DX\r
+ MOV DX,OFFSET TRANGROUP:CHARBUF\r
+ CALL ZPRINT\r
+ POP DX\r
+ return\r
+\r
+ONESPC:\r
+ MOV AL," "\r
+ JMP OUT\r
+\r
+CRLF2:\r
+ PUSH DX\r
+ MOV DX,OFFSET TRANGROUP:ACRLF\r
+PR:\r
+ PUSH DS\r
+ PUSH CS\r
+ POP DS\r
+ CALL PRINT\r
+ POP DS\r
+ POP DX\r
+ return\r
+\r
+PAUSE:\r
+ MOV DX,OFFSET TRANGROUP:PAUSEMES\r
+ CALL ERROR_PRINT\r
+ CALL GetKeystroke\r
+ CALL CRLF2\r
+ return\r
+\r
+ERASE:\r
+ MOV DX,OFFSET TRANGROUP:BADARGS\r
+ MOV SI,80H\r
+ LODSB\r
+ OR AL,AL\r
+ JZ ERRJ2\r
+ CALL SCANOFF\r
+ CMP AL,13 ; RETURN KEY?\r
+ JZ ERRJ2 ; IF SO NO PARAMETERS SPECIFIED\r
+\r
+ERA1:\r
+ CALL PATHCRUNCH\r
+ JNC NOTEST2J\r
+ CMP [DESTISDIR],0 ; No CHDIRs worked\r
+ JZ NOTEST2J ; see if they should have\r
+BADCDERR:\r
+ MOV DX,OFFSET TRANGROUP:BADCD\r
+ERRJ2:\r
+ JMP CERROR\r
+\r
+NOTEST2J:\r
+ JMP NOTEST2\r
+\r
+CRENAME:\r
+ CALL PATHCRUNCH\r
+ JNC NOTEST3\r
+ CMP [DESTISDIR],0 ; No CHDIRs worked\r
+ JZ NOTEST3 ; see if they should have\r
+ JMP BADCDERR\r
+\r
+NOTEST3:\r
+ MOV SI,[PATHPOS]\r
+ MOV DI,FCB+10H\r
+ CALL SCANOFF\r
+ MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H\r
+ INT int_command\r
+ CMP BYTE PTR DS:[FCB+10H+1]," " ; Check if parameter exists\r
+ MOV DX,OFFSET TRANGROUP:BADARGS\r
+ JZ ERRJ ; Error if missing parameter\r
+ MOV AH,FCB_RENAME\r
+ MOV DX,FCB\r
+ INT int_command\r
+ PUSH AX\r
+ CALL RESTUDIR\r
+ POP AX\r
+ MOV DX,OFFSET TRANGROUP:RENERR\r
+ INC AL\r
+ retnz\r
+ERRJ:\r
+ JMP CERROR\r
+\r
+ASSUME DS:TRANGROUP,ES:TRANGROUP\r
+TYPEFIL:\r
+ mov si,81H\r
+ call SCANOFF ; Skip to first non-delim\r
+ cmp al,0DH\r
+ jnz GOTTARG\r
+ jmp NOARGERR ; No args\r
+GOTTARG:\r
+ CALL SETPATH\r
+ MOV AX,OPEN SHL 8\r
+ INT int_command\r
+ MOV DX,OFFSET TRANGROUP:NOTFND\r
+ JC ERRJ\r
+ MOV BX,AX ; Handle\r
+ MOV DS,[TPA]\r
+ XOR DX,DX\r
+ASSUME DS:NOTHING\r
+TYPELP:\r
+ MOV CX,[BYTCNT]\r
+ MOV AH,READ\r
+ INT int_command\r
+ MOV CX,AX\r
+ JCXZ RET56\r
+ PUSH BX\r
+ MOV BX,1\r
+ MOV AH,WRITE\r
+ INT int_command\r
+ POP BX\r
+ JC ERROR_OUTPUTJ\r
+ CMP AX,CX\r
+ JZ TYPELP\r
+ DEC CX\r
+ CMP AX,CX\r
+ retz ; One less byte OK (^Z)\r
+ERROR_OUTPUTJ:\r
+ MOV BX,1\r
+ MOV AX,IOCTL SHL 8\r
+ INT int_command\r
+ TEST DL,devid_ISDEV\r
+ retnz ; If device, no error message\r
+ JMP ERROR_OUTPUT\r
+\r
+RESTUDIR1:\r
+ PUSH DS\r
+ MOV DS,[RESSEG]\r
+ASSUME DS:RESGROUP\r
+ CMP [RESTDIR],0\r
+ POP DS\r
+ASSUME DS:TRANGROUP\r
+ retz\r
+RESTUDIR:\r
+ MOV DX,OFFSET TRANGROUP:USERDIR1\r
+ MOV AH,CHDIR\r
+ INT int_command ; Restore users DIR\r
+ XOR AL,AL\r
+ CALL SETREST\r
+RET56:\r
+ return\r
+\r
+\r
+VOLUME:\r
+ mov si,81H\r
+ call SCANOFF ; Skip to first non-delim\r
+ CMP BYTE PTR DS:[FCB],0 ;Default drive?\r
+ JZ CHECKNOARG ;Yes\r
+ INC SI\r
+ INC SI ;Skip over d:\r
+ MOV BX,SI\r
+ CALL SCANOFF\r
+ CMP BX,SI\r
+ JNZ OKVOLARG ; If we skipped some delims at this point, OK\r
+CHECKNOARG:\r
+ cmp al,0DH\r
+ JZ OKVOLARG\r
+BADVOLARG:\r
+ MOV DX,OFFSET TRANGROUP:BADDRV\r
+ JMP CERROR\r
+\r
+OKVOLARG:\r
+ CALL CRLF2\r
+ PUSH DS\r
+ POP ES\r
+ MOV DI,FCB-7 ; Set up extended FCB\r
+ MOV AX,-1\r
+ STOSB\r
+ XOR AX,AX\r
+ STOSW\r
+ STOSW\r
+ STOSB\r
+ MOV AL,8 ; Look for volume label\r
+ STOSB\r
+ INC DI ; Skip drive byte\r
+ MOV CX,11\r
+ MOV AL,'?'\r
+ REP STOSB\r
+ MOV DX,OFFSET TRANGROUP:DIRBUF\r
+ MOV AH,SET_DMA\r
+ INT int_command\r
+ MOV DX,FCB-7\r
+ MOV AH,DIR_SEARCH_FIRST\r
+ INT int_command\r
+ JMP PRINTVOL\r
+\r
+VERSION:\r
+ CALL CRLF2\r
+ CALL PRINT_VERSION\r
+ JMP CRLF2\r
+\r
+PRINT_VERSION:\r
+ MOV DI,OFFSET TRANGROUP:CHARBUF\r
+ MOV SI,OFFSET TRANGROUP:VERMES_PRE\r
+ CALL MESTRAN\r
+ MOV AH,GET_VERSION\r
+ INT int_command\r
+ PUSH AX\r
+ XOR AH,AH\r
+ MOV CL,10\r
+ DIV CL\r
+ MOV CL,4\r
+ SHL AL,CL\r
+ OR AL,AH\r
+ MOV CX,1110H\r
+ MOV DL,AL\r
+ CALL OUTBYTE\r
+ MOV AL,'.'\r
+ STOSB\r
+ POP AX\r
+ MOV AL,AH\r
+ XOR AH,AH\r
+ MOV CL,10\r
+ DIV CL\r
+ MOV CL,4\r
+ SHL AL,CL\r
+ OR AL,AH\r
+ MOV CX,1010H\r
+ MOV DL,AL\r
+ CALL OUTBYTE\r
+ MOV SI,OFFSET TRANGROUP:VERMES_POST\r
+ CALL MESTRAN\r
+ XOR AX,AX\r
+ STOSB\r
+ MOV DX,OFFSET TRANGROUP:CHARBUF\r
+ JMP ZPRINT\r
+\r
+ASSUME DS:TRANGROUP\r
+\r
+CLS:\r
+ IF IBMVER\r
+ MOV BX,1\r
+ MOV AX,IOCTL SHL 8\r
+ INT int_command\r
+ TEST DL,devid_ISDEV\r
+ JZ ANSICLS ; If a file put out ANSI\r
+ TEST DL,devid_SPECIAL\r
+ JZ ANSICLS ; If not special CON, do ANSI\r
+ MOV AX,(GET_INTERRUPT_VECTOR SHL 8) OR 29H\r
+ INT int_command\r
+ MOV DX,ES\r
+ MOV AX,(GET_INTERRUPT_VECTOR SHL 8) OR 20H\r
+ INT int_command\r
+ MOV AX,ES\r
+ CMP DX,AX\r
+ JA ANSICLS ; If not default driver, do ANSI\r
+ MOV AH,11 ; Set overscan to black\r
+ XOR BX,BX\r
+ INT 16\r
+ MOV AH,15\r
+ INT 16\r
+ MOV DL,AH\r
+ DEC DL\r
+\r
+ IF KANJI\r
+ MOV DH,23\r
+ ELSE\r
+ MOV DH,25\r
+ ENDIF\r
+\r
+ XOR AX,AX\r
+ MOV CX,AX\r
+\r
+ IF KANJI\r
+ MOV BH,0\r
+ ELSE\r
+ MOV BH,7\r
+ ENDIF\r
+\r
+ MOV AH,6\r
+ INT 16\r
+ XOR DX,DX\r
+ MOV BH,0\r
+ MOV AH,2\r
+ INT 16\r
+ return\r
+\r
+ANSICLS:\r
+ ENDIF\r
+\r
+ MOV SI,OFFSET TRANGROUP:CLSSTRING\r
+ LODSB\r
+ MOV CL,AL\r
+ XOR CH,CH\r
+ MOV AH,RAW_CON_IO\r
+CLRLOOP:\r
+ LODSB\r
+ MOV DL,AL\r
+ INT int_command\r
+ LOOP CLRLOOP\r
+ return\r
+\r
+$CHDIR:\r
+ MOV AX,[COMSW]\r
+ OR AX,[ARGTS]\r
+ MOV DX,OFFSET TRANGROUP:BADSWT\r
+ JNZ CERRORJ3\r
+ mov si,81H\r
+ call SCANOFF ; Skip to first non-delim\r
+ cmp al,0DH\r
+ jz PWDJ ; No args\r
+ inc si ; Skip first char\r
+ lodsw\r
+ cmp ax,(0DH SHL 8) OR ':' ; d:<CR> ?\r
+ jnz REALCD ; no\r
+PWDJ:\r
+ jmp PWD ; Drive only specified\r
+REALCD:\r
+ CALL SETPATH\r
+ TEST [DESTINFO],2\r
+ JNZ BADCDERRJ\r
+ MOV AH,CHDIR\r
+ INT int_command\r
+ retnc\r
+BADCDERRJ:\r
+ JMP BADCDERR\r
+\r
+$MKDIR:\r
+ CALL SETRMMK\r
+ JNZ BADMDERR\r
+ MOV AH,MKDIR\r
+ INT int_command\r
+ retnc\r
+BADMDERR:\r
+ MOV DX,OFFSET TRANGROUP:BADMKD\r
+CERRORJ3:\r
+ JMP CERROR\r
+\r
+NOARGERR:\r
+ MOV DX,OFFSET TRANGROUP:BADARGS\r
+ JMP SHORT CERRORJ3\r
+\r
+SETRMMK:\r
+ mov si,81H\r
+ call SCANOFF ; Skip to first non-delim\r
+ cmp al,0DH\r
+ jz NOARGERR ; No args\r
+ MOV AX,[COMSW]\r
+ OR AX,[ARGTS]\r
+ MOV DX,OFFSET TRANGROUP:BADSWT\r
+ JNZ CERRORJ3\r
+ CALL SETPATH\r
+ TEST [DESTINFO],2\r
+ return\r
+\r
+$RMDIR:\r
+ CALL SETRMMK\r
+ JNZ BADRDERR\r
+ MOV AH,RMDIR\r
+ INT int_command\r
+ retnc\r
+BADRDERR:\r
+ MOV DX,OFFSET TRANGROUP:BADRMD\r
+ JMP CERROR\r
+\r
+SAVUDIR:\r
+; DL is drive number A=1\r
+ MOV DI,OFFSET TRANGROUP:USERDIR1\r
+SAVUDIR1:\r
+ MOV AL,DL\r
+ ADD AL,'@'\r
+ CMP AL,'@'\r
+ JNZ GOTUDRV\r
+ ADD AL,[CURDRV]\r
+ INC AL ; A = 1\r
+GOTUDRV:\r
+ STOSB\r
+ MOV AH,[DIRCHAR]\r
+ MOV AL,DRVCHAR\r
+ STOSW\r
+ PUSH ES\r
+ POP DS\r
+ASSUME DS:NOTHING\r
+ MOV SI,DI\r
+ MOV AH,CURRENT_DIR ; Get the Directory Text\r
+ INT int_command\r
+ retc\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:TRANGROUP\r
+ return\r
+\r
+ASSUME DS:TRANGROUP,ES:TRANGROUP\r
+\r
+; Date and time are set during initialization and use\r
+; this routines since they need to do a long return\r
+\r
+DATINIT PROC FAR\r
+ PUSH ES\r
+ PUSH DS ; Going to use the previous stack\r
+ MOV AX,CS ; Set up the appropriate segment registers\r
+ MOV ES,AX\r
+ MOV DS,AX\r
+ MOV DX,OFFSET TRANGROUP:INTERNATVARS ;Set up internat vars\r
+ MOV AX,INTERNATIONAL SHL 8\r
+ INT 21H\r
+ MOV WORD PTR DS:[81H],13 ; Want to prompt for date during initialization\r
+ MOV [COMBUF],COMBUFLEN ; Init COMBUF\r
+ MOV WORD PTR [COMBUF+1],0D01H\r
+ CALL DATE\r
+ CALL CTIME\r
+ POP DS\r
+ POP ES\r
+ RET\r
+DATINIT ENDP\r
+\r
+; DATE - Gets and sets the time\r
+\r
+DATE_CXDX:\r
+ MOV BX,CX\r
+P_DATE:\r
+ MOV AX,BX\r
+ MOV CX,DX\r
+ MOV DL,100\r
+ DIV DL\r
+ XCHG AL,AH\r
+ XCHG AX,DX\r
+ MOV BH,"0"-" " ; Enable leading zero suppression\r
+ MOV AX,WORD PTR [INTERNATVARS.Date_tim_format]\r
+ OR AX,AX\r
+ JZ USPDAT\r
+ DEC AX\r
+ JZ EUPDAT\r
+ MOV BH,0 ; Disable leading zero suppression\r
+ CALL P_YR\r
+ CALL P_DSEP\r
+ CALL P_MON\r
+ CALL P_DSEP\r
+ CALL P_DAY\r
+ return\r
+\r
+USPDAT:\r
+ CALL P_MON\r
+ CALL P_DSEP\r
+ CALL P_DAY\r
+PLST:\r
+ CALL P_DSEP\r
+ CALL P_YR\r
+ return\r
+\r
+EUPDAT:\r
+ CALL P_DAY\r
+ CALL P_DSEP\r
+ CALL P_MON\r
+ JMP PLST\r
+\r
+P_MON:\r
+ MOV AL,CH\r
+ CALL OUT2\r
+ return\r
+\r
+P_DSEP:\r
+ MOV AL,BYTE PTR [INTERNATVARS.Date_sep]\r
+ STOSB\r
+ return\r
+\r
+P_DAY:\r
+ MOV AL,CL\r
+ CALL OUT2\r
+ return\r
+\r
+P_YR:\r
+ MOV AL,DH\r
+ OR AL,AL\r
+ JZ TWODIGYR ; Two instead of 4 digit year\r
+ CALL OUT2\r
+TWODIGYR:\r
+ MOV AL,DL\r
+ CALL OUT2\r
+ return\r
+\r
+DATE:\r
+ MOV SI,81H ; Accepting argument for date inline\r
+ CALL SCANOFF\r
+ CMP AL,13\r
+ JZ PRMTDAT\r
+ JMP COMDAT\r
+\r
+PRMTDAT:\r
+ MOV DX,OFFSET TRANGROUP:CURDAT_PRE\r
+ CALL PRINT ; Print "Current date is "\r
+ CALL PRINT_DATE\r
+ MOV DX,OFFSET TRANGROUP:CURDAT_POST\r
+ CALL PRINT\r
+GETDAT:\r
+ MOV DX,OFFSET TRANGROUP:NEWDAT\r
+ CALL ERROR_PRINT ; Print "Enter new date: "\r
+ MOV AH,STD_CON_STRING_INPUT\r
+ MOV DX,OFFSET TRANGROUP:COMBUF\r
+ INT int_command ; Get input line\r
+ CALL CRLF2\r
+ MOV SI,OFFSET TRANGROUP:COMBUF+2\r
+ CMP BYTE PTR[SI],13 ; Check if new date entered\r
+ retz\r
+COMDAT:\r
+ MOV AX,WORD PTR [INTERNATVARS.Date_tim_format]\r
+ OR AX,AX\r
+ JZ USSDAT\r
+ DEC AX\r
+ JZ EUSDAT\r
+ CALL GET_YR\r
+ JC DATERRJ\r
+ CALL GET_DSEP\r
+ JC DATERRJ\r
+ CALL GET_MON\r
+ JC DATERRJ\r
+ CALL GET_DSEP\r
+ JC DATERRJ\r
+ CALL GET_DAY\r
+DAT_SET:\r
+ JC DATERR\r
+ LODSB\r
+ CMP AL,13\r
+ JNZ DATERR\r
+ MOV AH,SET_DATE\r
+ INT int_command\r
+ OR AL,AL\r
+ JNZ DATERR\r
+ return\r
+\r
+USSDAT:\r
+ CALL GET_MON\r
+ JC DATERR\r
+ CALL GET_DSEP\r
+DATERRJ:\r
+ JC DATERR\r
+ CALL GET_DAY\r
+TGET:\r
+ JC DATERR\r
+ CALL GET_DSEP\r
+ JC DATERR\r
+ CALL GET_YR\r
+ JMP DAT_SET\r
+\r
+EUSDAT:\r
+ CALL GET_DAY\r
+ JC DATERR\r
+ CALL GET_DSEP\r
+ JC DATERR\r
+ CALL GET_MON\r
+ JMP TGET\r
+\r
+GET_MON:\r
+ CALL GETNUM ; Get one or two digit number\r
+ retc\r
+ MOV DH,AH ; Put in position\r
+ return\r
+\r
+GET_DAY:\r
+ CALL GETNUM\r
+ MOV DL,AH ; Put in position\r
+ return\r
+\r
+GET_YR:\r
+ CALL GETNUM\r
+ retc\r
+ MOV CX,1900\r
+ CALL GET_DSEP\r
+ PUSHF\r
+ DEC SI\r
+ POPF\r
+ JZ BIAS\r
+ CMP BYTE PTR[SI],13\r
+ JZ BIAS\r
+ MOV AL,100\r
+ MUL AH\r
+ MOV CX,AX\r
+ CALL GETNUM\r
+ retc\r
+BIAS:\r
+ MOV AL,AH\r
+ MOV AH,0\r
+ ADD CX,AX\r
+\r
+ IF IBM AND KANJI\r
+;\r
+; Gross hack for PC-J machine: CMOS clock cannot handle years after 2079\r
+;\r
+ CMP CX,2080\r
+ JB YearOk\r
+ STC\r
+ return\r
+YearOk: CLC\r
+ ENDIF\r
+ return\r
+\r
+DATERR:\r
+ MOV DX,OFFSET TRANGROUP:BADDAT\r
+ CALL PRINT\r
+ JMP GETDAT\r
+\r
+GET_DSEP:\r
+ LODSB\r
+ CMP AL,'/'\r
+ retz\r
+ CMP AL,'.'\r
+ retz\r
+ CMP AL,'-'\r
+ retz\r
+ STC\r
+ return\r
+\r
+; TIME gets and sets the time\r
+\r
+CTIME:\r
+ MOV SI,81H ; Accepting argument for time inline\r
+ CALL SCANOFF\r
+ CMP AL,13\r
+ JZ PRMTTIM\r
+ MOV BX,".:"\r
+ CALL INLINE\r
+ JMP COMTIM\r
+\r
+PRINT_TIME:\r
+ MOV AH,GET_TIME\r
+ INT int_command ; Get time in CX:DX\r
+ PUSH DI\r
+ PUSH ES\r
+ PUSH CS\r
+ POP ES\r
+ MOV DI,OFFSET TRANGROUP:CHARBUF\r
+ MOV BL,1 ; Always 24 hour time\r
+ CALL P_TIME\r
+ XOR AX,AX\r
+ STOSB\r
+ MOV DX,OFFSET TRANGROUP:CHARBUF\r
+ CALL ZPRINT\r
+ POP ES\r
+ POP DI\r
+ return\r
+\r
+P_TIME:\r
+ MOV AL,CH\r
+ TEST BL,07FH ; Ignore high bit\r
+ JNZ T24 ; 24 hr time?\r
+ MOV BH,"a" ; Assume A.M.\r
+ CMP AL,12 ; In the afternoon?\r
+ JB MORN\r
+ MOV BH,"p"\r
+ JE MORN\r
+ SUB AL,12 ; Keep it to 12 hours or less\r
+MORN:\r
+ OR AL,AL ; Before 1 am?\r
+ JNZ T24\r
+ MOV AL,12\r
+T24:\r
+ PUSH BX\r
+ MOV BH,"0"-" " ; Enable leading zero suppression\r
+ CALL OUT2\r
+ CALL P_TSEP\r
+ MOV AL,CL\r
+ CALL OUT2\r
+ POP BX\r
+ PUSH BX\r
+ TEST BL,80H\r
+ JNZ PAP ; If from DIR, go directly to am pm\r
+ MOV BH,0 ; Disable leading zero suppression\r
+ CALL P_TSEP\r
+ MOV AL,DH\r
+ CALL OUT2\r
+ IF NOT IBMJAPAN\r
+ MOV AL,"."\r
+ STOSB\r
+ MOV AL,DL\r
+ CALL OUT2\r
+ ENDIF\r
+PAP:\r
+ POP BX\r
+ TEST BL,07FH ; Ignore high bit\r
+ retnz ; 24 hour time, no am pm\r
+ MOV AL,BH\r
+ STOSB ; Store 'a' or 'p'\r
+ return\r
+\r
+P_TSEP:\r
+ MOV AL,[INTERNATVARS.Time_sep]\r
+ STOSB\r
+ return\r
+\r
+\r
+PRMTTIM:\r
+ MOV DX,OFFSET TRANGROUP:CURTIM_PRE\r
+ CALL PRINT ; Print "Current time is "\r
+ CALL PRINT_TIME\r
+ MOV DX,OFFSET TRANGROUP:CURTIM_POST\r
+ CALL PRINT\r
+GETTIM:\r
+ XOR CX,CX ; Initialize hours and minutes to zero\r
+ MOV DX,OFFSET TRANGROUP:NEWTIM\r
+ MOV BX,".:"\r
+ CALL GETBUF\r
+COMTIM:\r
+ retz ; If no time present, don't change it\r
+ JC TIMERR\r
+ MOV CX,DX\r
+ XOR DX,DX\r
+ LODSB\r
+ CMP AL,13\r
+ JZ SAVTIM\r
+ CMP AL,BL\r
+ JZ GOTSEC\r
+ CMP AL,BH\r
+ JNZ TIMERR\r
+GOTSEC:\r
+ CALL GETNUM\r
+ JC TIMERR\r
+ MOV DH,AH ; Position seconds\r
+ LODSB\r
+ CMP AL,13\r
+ JZ SAVTIM\r
+ CMP AL,"."\r
+ JNZ TIMERR\r
+ CALL GETNUM\r
+ JC TIMERR\r
+ MOV DL,AH\r
+ LODSB\r
+ CMP AL,13\r
+ JNZ TIMERR\r
+SAVTIM:\r
+ MOV AH,SET_TIME\r
+ INT int_command\r
+ OR AL,AL\r
+ retz ; Error in time?\r
+TIMERR:\r
+ MOV DX,OFFSET TRANGROUP:BADTIM\r
+ CALL PRINT ; Print error message\r
+ JMP GETTIM ; Try again\r
+\r
+GETBUF:\r
+ CALL ERROR_PRINT ; Print "Enter new time: "\r
+ MOV AH,STD_CON_STRING_INPUT\r
+ MOV DX,OFFSET TRANGROUP:COMBUF\r
+ INT int_command ; Get input line\r
+ CALL CRLF2\r
+ MOV SI,OFFSET TRANGROUP:COMBUF+2\r
+ CMP BYTE PTR[SI],13 ; Check if new time entered\r
+ retz\r
+INLINE:\r
+ CALL GETNUM ; Get one or two digit number\r
+ retc\r
+ MOV DH,AH ; Put in position\r
+ LODSB\r
+ CMP AL,BL\r
+ JZ NEXT\r
+ CMP AL,BH\r
+ JZ NEXT\r
+ DEC SI ; Clears zero flag\r
+ CLC\r
+ MOV DL,0\r
+ return ; Time may have only an hour specified\r
+\r
+NEXT:\r
+ CALL GETNUM\r
+ MOV DL,AH ; Put in position\r
+ return\r
+\r
+\r
+TRANCODE ENDS\r
+ END\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+TITLE PART5 - COMMAND Transient routines.\r
+\r
+ INCLUDE COMSW.ASM\r
+\r
+.xlist\r
+.xcref\r
+ INCLUDE DOSSYM.ASM\r
+ INCLUDE DEVSYM.ASM\r
+ INCLUDE COMSEG.ASM\r
+.list\r
+.cref\r
+\r
+ INCLUDE COMEQU.ASM\r
+\r
+CODERES SEGMENT PUBLIC\r
+\r
+ IF IBMVER\r
+ EXTRN EXEC_WAIT:NEAR\r
+ ENDIF\r
+\r
+CODERES ENDS\r
+\r
+\r
+DATARES SEGMENT PUBLIC\r
+ EXTRN BATCH:WORD,BATLOC:DWORD,BATBYT:BYTE,ECHOFLAG:BYTE\r
+ EXTRN SINGLECOM:WORD,RE_OUTSTR:BYTE,PIPEFLAG:BYTE,PIPEPTR:WORD\r
+ EXTRN RE_INSTR:BYTE,RE_OUT_APP:BYTE,PARMBUF:BYTE,PIPESTR:BYTE\r
+ EXTRN LTPA:WORD,ENVIRSEG:WORD\r
+DATARES ENDS\r
+\r
+TRANDATA SEGMENT PUBLIC\r
+ EXTRN PIPEEMES:BYTE,NULPATH:BYTE,NOSPACE:BYTE\r
+ EXTRN DBACK:BYTE,PROMPT_TABLE:BYTE\r
+TRANDATA ENDS\r
+\r
+TRANSPACE SEGMENT PUBLIC\r
+ EXTRN PATHCNT:WORD,PATHPOS:WORD,PATHSW:WORD\r
+ EXTRN DESTISDIR:BYTE,DESTTAIL:WORD,DESTINFO:BYTE\r
+ EXTRN BATHAND:WORD,RESSEG:WORD,TPA:WORD,SWITCHAR:BYTE\r
+ EXTRN BYTCNT:WORD,COMBUF:BYTE,DIRBUF:BYTE,CHARBUF:BYTE\r
+\r
+\r
+ IF KANJI\r
+ EXTRN KPARSE:BYTE\r
+ ENDIF\r
+\r
+TRANSPACE ENDS\r
+\r
+\r
+TRANCODE SEGMENT PUBLIC BYTE\r
+ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING\r
+\r
+ IF KANJI\r
+ EXTRN TESTKANJ:NEAR\r
+ ENDIF\r
+\r
+ EXTRN CERROR:NEAR,UPCONV:NEAR,PIPEERRSYN:NEAR,SETREST1:NEAR\r
+ EXTRN SWITCH:NEAR,SETREST1:NEAR,BATCLOSE:NEAR,MOVE_NAME:NEAR\r
+ EXTRN FIND_PROMPT:NEAR,FIND_PATH:NEAR,DELETE_PATH:NEAR\r
+ EXTRN STORE_CHAR:NEAR,SCAN_DOUBLE_NULL:NEAR,SCASB2:NEAR\r
+ EXTRN PRINT_DRIVE:NEAR,SAVUDIR:NEAR,CRLF2:NEAR,PAUSE:NEAR\r
+ \r
+ PUBLIC PRINT_B,PRINT_G,DISPSIZE,GETNUM,OUTBYTE\r
+ PUBLIC DELIM,OUT,OUT2,SETPATH,PATHCRUNCH\r
+ PUBLIC CRPRINT,SCANOFF,FCB_TO_ASCZ\r
+ PUBLIC PRINT_L,PATH,PATHCHRCMP,PRINT_ESC,PRINT_BACK\r
+ PUBLIC PRINT_EQ,PRINT,ZPRINT,PRINT_PROMPT\r
+ PUBLIC DISP32BITS,ERROR_PRINT,ERROR_OUTPUT\r
+ PUBLIC FREE_TPA,ALLOC_TPA,PRESCAN,GETBATBYT\r
+\r
+\r
+FREE_TPA:\r
+ASSUME DS:TRANGROUP,ES:NOTHING\r
+ PUSH ES\r
+ MOV ES,[TPA]\r
+ MOV AH,DEALLOC\r
+ INT int_command ; Make lots of free memory\r
+ POP ES\r
+ return\r
+\r
+ALLOC_TPA:\r
+ASSUME DS:TRANGROUP,ES:RESGROUP\r
+ MOV BX,0FFFFH ; Re-allocate the transient\r
+ MOV AH,ALLOC\r
+ INT int_command\r
+ MOV AH,ALLOC\r
+ INT int_command\r
+ MOV [LTPA],AX ; Re-compute evrything\r
+ MOV [TPA],AX\r
+ MOV BX,AX\r
+ MOV AX,CS\r
+ SUB AX,BX\r
+ MOV DX,16\r
+ MUL DX\r
+ OR DX,DX\r
+ JZ SAVSIZ2\r
+ MOV AX,-1\r
+SAVSIZ2:\r
+ MOV [BYTCNT],AX\r
+ return\r
+\r
+\r
+PRESCAN: ; Cook the input buffer\r
+ASSUME DS:TRANGROUP,ES:TRANGROUP\r
+ XOR CX,CX\r
+ MOV ES,[RESSEG]\r
+ASSUME ES:RESGROUP\r
+ MOV SI,OFFSET TRANGROUP:COMBUF+2\r
+ MOV DI,SI\r
+\r
+CountQuotes:\r
+ LODSB ; get a byte\r
+ CMP AL,22h ; is it a quote?\r
+ JNZ CountEnd ; no, try for end of road\r
+ INC CH ; bump count\r
+ JMP CountQuotes ; go get next char\r
+CountEnd:\r
+ CMP AL,13 ; end of road?\r
+ JNZ CountQuotes ; no, go back for next char\r
+\r
+ IF KANJI\r
+ PUSH CX ; save count\r
+ MOV SI,DI ; get back beginning of buffer\r
+KanjiScan:\r
+ LODSB ; get a byte\r
+ CALL TestKanj ; is it a leadin byte\r
+ JZ KanjiQuote ; no, check for quotes\r
+ MOV AH,AL ; save leadin\r
+ LODSB ; get trailing byte\r
+ CMP AX,8140h ; is it Kanji space\r
+ JNZ KanjiScan ; no, go get next\r
+ MOV [SI-2],2020h ; replace with spaces\r
+ JMP KanjiScan ; go get next char\r
+KanjiQuote:\r
+ CMP AL,22h ; beginning of quoted string\r
+ JNZ KanjiEnd ; no, check for end\r
+ DEC CH ; drop count\r
+ JZ KanjiScan ; if count is zero, no quoting\r
+KanjiQuoteLoop:\r
+ LODSB ; get next byte\r
+ CMP AL,22h ; is it another quote\r
+ JNZ KanjiQuoteLoop ; no, get another\r
+ DEC CH ; yes, drop count\r
+ JMP KanjiScan ; go get next char\r
+KanjiEnd:\r
+ CMP AL,13 ; end of line character?\r
+ JNZ KanjiScan ; go back to beginning\r
+ POP CX ; get back original count\r
+ ENDIF\r
+\r
+ MOV SI,DI ; restore pointer to begining\r
+PRESCANLP:\r
+ LODSB\r
+\r
+ IF KANJI\r
+ CALL TESTKANJ\r
+ JZ NOTKANJ6\r
+ MOV [DI],AL\r
+ INC DI ; fake STOSB into DS\r
+ LODSB ; grab second byte\r
+ MOV [DI],AL ; fake stosb into DS\r
+ INC DI\r
+ INC CL\r
+ INC CL\r
+ JMP PRESCANLP\r
+NOTKANJ6:\r
+ ENDIF\r
+\r
+ CMP AL,22H ; " character\r
+ JNZ TRYGREATER\r
+ DEC CH\r
+ JZ TRYGREATER\r
+QLOOP:\r
+ MOV [DI],AL\r
+ INC DI\r
+ INC CL\r
+ LODSB\r
+ CMP AL,22H ; " character\r
+ JNZ QLOOP\r
+ DEC CH\r
+\r
+TRYGREATER:\r
+ CMP AL,'>'\r
+ JNZ NOOUT\r
+ CMP BYTE PTR [SI],'>'\r
+ JNZ NOAPPND\r
+ LODSB\r
+ INC [RE_OUT_APP] ; Flag >>\r
+NOAPPND:\r
+ CALL SCANOFF\r
+ CMP AL,0DH\r
+ JNZ GOTREOFIL\r
+ MOV WORD PTR [RE_OUTSTR],09H ; Cause an error later\r
+ JMP SHORT PRESCANEND\r
+GOTREOFIL:\r
+ PUSH DI\r
+ MOV DI,OFFSET RESGROUP:RE_OUTSTR\r
+SETREOUTSTR: ; Get the output redirection name\r
+ LODSB\r
+ CMP AL,0DH\r
+ JZ GOTRESTR\r
+ CALL DELIM\r
+ JZ GOTRESTR\r
+ CMP AL,[SWITCHAR]\r
+ JZ GOTRESTR\r
+ STOSB ; store it into resgroup\r
+ JMP SHORT SETREOUTSTR\r
+\r
+NOOUT:\r
+ CMP AL,'<'\r
+ JNZ CHKPIPE\r
+ CALL SCANOFF\r
+ CMP AL,0DH\r
+ JNZ GOTREIFIL\r
+ MOV WORD PTR [RE_INSTR],09H ; Cause an error later\r
+ JMP SHORT PRESCANEND\r
+GOTREIFIL:\r
+ PUSH DI\r
+ MOV DI,OFFSET RESGROUP:RE_INSTR\r
+ JMP SHORT SETREOUTSTR ; Get the input redirection name\r
+\r
+CHKPIPE:\r
+ MOV AH,AL\r
+ CMP AH,'|'\r
+ JNZ CONTPRESCAN\r
+ INC [PIPEFLAG]\r
+ CALL SCANOFF\r
+ CMP AL,0DH\r
+ JZ PIPEERRSYNJ5\r
+ CMP AL,'|' ; Double '|'?\r
+ JNZ CONTPRESCAN\r
+PIPEERRSYNJ5:\r
+ PUSH ES\r
+ POP DS ; DS->RESGROUP\r
+ JMP PIPEERRSYN\r
+\r
+GOTRESTR:\r
+ XCHG AH,AL\r
+ CMP BYTE PTR ES:[DI-1],':' ; Trailing ':' OK on devices\r
+ JNZ NOTTRAILCOL\r
+ DEC DI ; Back up over trailing ':'\r
+NOTTRAILCOL:\r
+ XOR AL,AL\r
+ STOSB ; NUL terminate the string\r
+ POP DI ; Remember the start\r
+CONTPRESCAN:\r
+ MOV [DI],AH ; "delete" the redirection string\r
+ INC DI\r
+ CMP AH,0DH\r
+ JZ PRESCANEND\r
+ INC CL\r
+ JMP PRESCANLP\r
+PRESCANEND:\r
+ CMP [PIPEFLAG],0\r
+ JZ ISNOPIPE\r
+ MOV DI,OFFSET RESGROUP:PIPESTR\r
+ MOV [PIPEPTR],DI\r
+ MOV SI,OFFSET TRANGROUP:COMBUF+2\r
+ CALL SCANOFF\r
+PIPESETLP: ; Transfer the pipe into the resident pipe buffer\r
+ LODSB\r
+ STOSB\r
+ CMP AL,0DH\r
+ JNZ PIPESETLP\r
+ISNOPIPE:\r
+ MOV [COMBUF+1],CL\r
+ CMP [PIPEFLAG],0\r
+ PUSH CS\r
+ POP ES\r
+ return\r
+\r
+ASSUME DS:TRANGROUP,ES:TRANGROUP\r
+\r
+PATHCHRCMP:\r
+ CMP [SWITCHAR],'/'\r
+ JZ NOSLASHT\r
+ CMP AL,'/'\r
+ retz\r
+NOSLASHT:\r
+ CMP AL,'\'\r
+ return\r
+\r
+PATHCRUNCH:\r
+; Drive taken from FCB\r
+; DI = Dirsave pointer\r
+;\r
+; Zero set if path dir, CHDIR to this dir, FCB filled with ?\r
+; NZ set if path/file, CHDIR to file, FCB has file (parsed fill ' ')\r
+; [DESTTAIL] points to parse point\r
+; Carry set if no CHDIRs worked, FCB not altered.\r
+; DESTISDIR set non zero if PATHCHRs in path (via SETPATH)\r
+\r
+ MOV DL,DS:[FCB]\r
+ CALL SAVUDIR\r
+ CALL SETPATH\r
+ TEST [DESTINFO],2\r
+ JNZ TRYPEEL ; If ? or * cannot be pure dir\r
+ MOV AH,CHDIR\r
+ INT int_command\r
+ JC TRYPEEL\r
+ CALL SETREST1\r
+ MOV AL,"?" ; *.* is default file spec if pure dir\r
+ MOV DI,5DH\r
+ MOV CX,11\r
+ REP STOSB\r
+ XOR AL,AL ; Set zero\r
+ return\r
+\r
+TRYPEEL:\r
+ MOV SI,[PATHPOS]\r
+ DEC SI ; Point at NUL\r
+ MOV AL,[SI-1]\r
+\r
+ IF KANJI\r
+ CMP [KPARSE],0\r
+ JNZ DELSTRT ; Last char is second KANJI byte, might be '\'\r
+ ENDIF\r
+\r
+ CALL PATHCHRCMP\r
+ JZ PEELFAIL ; Trailing '/'\r
+\r
+ IF KANJI\r
+DELSTRT:\r
+ MOV CX,SI\r
+ MOV SI,DX\r
+ PUSH DX\r
+DELLOOP:\r
+ CMP SI,CX\r
+ JZ GOTDELE\r
+ LODSB\r
+ CALL TESTKANJ\r
+ JZ NOTKANJ8\r
+ INC SI\r
+ JMP DELLOOP\r
+\r
+NOTKANJ8:\r
+ CALL PATHCHRCMP\r
+ JNZ DELLOOP\r
+ MOV DX,SI\r
+ DEC DX\r
+ JMP DELLOOP\r
+\r
+GOTDELE:\r
+ MOV SI,DX\r
+ POP DX\r
+ CMP SI,DX\r
+ JZ BADRET\r
+ MOV CX,SI\r
+ MOV SI,DX\r
+DELLOOP2: ; Set value of KPARSE\r
+ CMP SI,CX\r
+ JZ KSET\r
+ MOV [KPARSE],0\r
+ LODSB\r
+ CALL TESTKANJ\r
+ JZ DELLOOP2\r
+ INC SI\r
+ INC [KPARSE]\r
+ JMP DELLOOP2\r
+\r
+KSET:\r
+ ELSE\r
+DELLOOP:\r
+ CMP SI,DX\r
+ JZ BADRET\r
+ MOV AL,[SI]\r
+ CALL PATHCHRCMP\r
+ JZ TRYCD\r
+ DEC SI\r
+ JMP SHORT DELLOOP\r
+ ENDIF\r
+\r
+TRYCD:\r
+ CMP BYTE PTR [SI+1],'.'\r
+ JZ PEELFAIL ; If . or .., pure cd should have worked\r
+ mov al,[si-1]\r
+ CMP al,DRVCHAR ; Special case dDRVCHAR,DIRCHARfile\r
+ JZ BADRET\r
+\r
+ IF KANJI\r
+ CMP [KPARSE],0\r
+ JNZ NOTDOUBLESL ; Last char is second KANJI byte, might be '\'\r
+ ENDIF\r
+\r
+ CALL PATHCHRCMP\r
+ JNZ NOTDOUBLESL\r
+PEELFAIL:\r
+ STC ; //\r
+ return\r
+NOTDOUBLESL:\r
+ MOV BYTE PTR [SI],0\r
+ MOV AH,CHDIR\r
+ INT int_command\r
+ JNC CDSUCC\r
+ return\r
+\r
+BADRET:\r
+ MOV AL,[SI]\r
+ CALL PATHCHRCMP ; Special case 'DIRCHAR'file\r
+ STC\r
+ retnz\r
+ XOR BL,BL\r
+ XCHG BL,[SI+1]\r
+ MOV AH,CHDIR\r
+ INT int_command\r
+ retc\r
+ MOV [SI+1],BL\r
+CDSUCC:\r
+ CALL SETREST1\r
+ INC SI ; Reset zero\r
+ MOV [DESTTAIL],SI\r
+ MOV DI,FCB\r
+ MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 02H ; Parse with default drive\r
+ INT int_command\r
+ return\r
+\r
+\r
+DISPSIZE:\r
+ MOV SI,WORD PTR[DIRBUF+29+7]\r
+ MOV DI,WORD PTR[DIRBUF+31+7]\r
+\r
+DISP32BITS:\r
+; Prints the 32-bit number DI:SI on the console in decimal. Uses a total\r
+; of 9 digit positions with leading blanks.\r
+ XOR AX,AX\r
+ MOV BX,AX\r
+ MOV BP,AX\r
+ MOV CX,32\r
+CONVLP:\r
+ SHL SI,1\r
+ RCL DI,1\r
+ XCHG AX,BP\r
+ CALL CONVWRD\r
+ XCHG AX,BP\r
+ XCHG AX,BX\r
+ CALL CONVWRD\r
+ XCHG AX,BX\r
+ ADC AL,0\r
+ LOOP CONVLP\r
+\r
+; Conversion complete. Print 9-digit number.\r
+\r
+ MOV DI,OFFSET TRANGROUP:CHARBUF\r
+ MOV CX,1810H ; Allow leading zero blanking for 8 digits\r
+ XCHG DX,AX\r
+ CALL DIGIT\r
+ XCHG AX,BX\r
+ CALL OUTWORD\r
+ XCHG AX,BP\r
+ CALL OUTWORD\r
+ XOR AX,AX\r
+ STOSB\r
+ MOV DX,OFFSET TRANGROUP:CHARBUF\r
+ JMP ZPRINT\r
+\r
+OUTWORD:\r
+ PUSH AX\r
+ MOV DL,AH\r
+ CALL OUTBYTE\r
+ POP DX\r
+OUTBYTE:\r
+ MOV DH,DL\r
+ SHR DL,1\r
+ SHR DL,1\r
+ SHR DL,1\r
+ SHR DL,1\r
+ CALL DIGIT\r
+ MOV DL,DH\r
+DIGIT:\r
+ AND DL,0FH\r
+ JZ BLANKZER\r
+ MOV CL,0\r
+BLANKZER:\r
+ DEC CH\r
+ AND CL,CH\r
+ OR DL,30H\r
+ SUB DL,CL\r
+ MOV AL,DL\r
+ STOSB\r
+ return\r
+\r
+CONVWRD:\r
+ ADC AL,AL\r
+ DAA\r
+ XCHG AL,AH\r
+ ADC AL,AL\r
+ DAA\r
+ XCHG AL,AH\r
+ return\r
+\r
+\r
+GETBATBYT:\r
+; Get one byte from the batch file and return it in AL. End-of-file\r
+; returns <CR> and ends batch mode. DS must be set to resident segment.\r
+; AH, CX, DX destroyed.\r
+ASSUME DS:RESGROUP\r
+ ADD WORD PTR [BATLOC],1 ; Add one to file location\r
+ ADC WORD PTR [BATLOC+2],0\r
+ PUSH BX\r
+ MOV DX,OFFSET RESGROUP:BATBYT\r
+ MOV BX,[BATHAND]\r
+ MOV AH,READ\r
+ MOV CX,1\r
+ INT int_command ; Get one more byte from batch file\r
+ POP BX\r
+ MOV CX,AX\r
+ JC BATEOF\r
+ JCXZ BATEOF\r
+ MOV AL,[BATBYT]\r
+ CMP AL,1AH\r
+ retnz\r
+BATEOF:\r
+ PUSH ES\r
+ MOV ES,[BATCH] ; Turn off batch\r
+ MOV AH,DEALLOC\r
+ INT int_command ; free up the batch piece\r
+ POP ES\r
+ MOV [BATCH],0 ; AFTER DEALLOC in case of ^C\r
+ CALL BATCLOSE\r
+ MOV AL,0DH ; If end-of-file, then end of line\r
+ CMP [SINGLECOM],0FFF0H ; See if we need to set SINGLECOM\r
+ JNZ NOSETSING2\r
+ MOV [SINGLECOM],-1 ; Cause termination\r
+NOSETSING2:\r
+ MOV [ECHOFLAG],1\r
+ return\r
+ASSUME DS:TRANGROUP\r
+\r
+SCANOFF:\r
+ LODSB\r
+ CALL DELIM\r
+ JZ SCANOFF\r
+ DEC SI ; Point to first non-delimiter\r
+ return\r
+\r
+DELIM:\r
+ CMP AL," "\r
+ retz\r
+ CMP AL,"="\r
+ retz\r
+ CMP AL,","\r
+ retz\r
+ CMP AL,";"\r
+ retz\r
+ CMP AL,9 ; Check for TAB character\r
+ return\r
+\r
+\r
+PRINT_PROMPT:\r
+ PUSH DS\r
+ PUSH CS\r
+ POP DS ; MAKE SURE DS IS IN TRANGROUP\r
+\r
+ PUSH ES\r
+ CALL FIND_PROMPT ; LOOK FOR PROMPT STRING\r
+ JC PP0 ; CAN'T FIND ONE\r
+ CMP BYTE PTR ES:[DI],0\r
+ JNZ PP1\r
+PP0:\r
+ CALL PRINT_DRIVE ; USE DEFAULT PROMPT\r
+ MOV AL,SYM\r
+ CALL OUT\r
+ JMP SHORT PP5\r
+\r
+PP1:\r
+ MOV AL,ES:[DI] ; GET A CHAR\r
+ INC DI\r
+ OR AL,AL\r
+ JZ PP5 ; NUL TERMINATED\r
+ CMP AL,"$" ; META CHARACTER?\r
+ JZ PP2 ; NOPE\r
+PPP1:\r
+ CALL OUT\r
+ JMP PP1\r
+\r
+PP2:\r
+ MOV AL,ES:[DI]\r
+ INC DI\r
+ MOV BX,OFFSET TRANGROUP:PROMPT_TABLE-3\r
+ OR AL,AL\r
+ JZ PP5\r
+\r
+PP3:\r
+ ADD BX,3\r
+ CALL UPCONV\r
+ CMP AL,[BX]\r
+ JZ PP4\r
+ CMP BYTE PTR [BX],0\r
+ JNZ PP3\r
+ JMP PP1\r
+\r
+PP4:\r
+ PUSH ES\r
+ PUSH DI\r
+ PUSH CS\r
+ POP ES\r
+ CALL [BX+1]\r
+ POP DI\r
+ POP ES\r
+ JMP PP1\r
+\r
+PP5:\r
+ POP ES ; RESTORE SEGMENTS\r
+ POP DS\r
+ return\r
+\r
+PRINT_BACK:\r
+ MOV DX,OFFSET TRANGROUP:DBACK\r
+ JMP ZPRINT\r
+\r
+PRINT_EQ:\r
+ MOV AL,"="\r
+ JMP SHORT OUTV\r
+PRINT_ESC:\r
+ MOV AL,1BH\r
+ JMP SHORT OUTV\r
+PRINT_G:\r
+ MOV AL,">"\r
+ JMP SHORT OUTV\r
+PRINT_L:\r
+ MOV AL,"<"\r
+ JMP SHORT OUTV\r
+PRINT_B:\r
+ MOV AL,"|"\r
+OUTV:\r
+ JMP OUT\r
+\r
+SETPATH:\r
+; Get an ASCIZ argument from the unformatted parms\r
+; DESTISDIR set if pathchars in string\r
+; DESTINFO set if ? or * in string\r
+ MOV SI,80H\r
+ LODSB\r
+ XOR AH,AH\r
+ MOV [PATHCNT],AX\r
+ MOV [PATHPOS],SI\r
+GETPATH:\r
+ MOV [DESTINFO],0\r
+ MOV [DESTISDIR],0\r
+ MOV SI,[PATHPOS]\r
+ MOV CX,[PATHCNT]\r
+ MOV DX,SI\r
+ JCXZ PATHDONE\r
+ PUSH CX\r
+ PUSH SI\r
+ CALL SWITCH\r
+ MOV [PATHSW],AX\r
+ POP BX\r
+ SUB BX,SI\r
+ POP CX\r
+ ADD CX,BX\r
+ MOV DX,SI\r
+SKIPPATH:\r
+\r
+ IF KANJI\r
+ MOV [KPARSE],0\r
+SKIPPATH2:\r
+ ENDIF\r
+\r
+ JCXZ PATHDONE\r
+ DEC CX\r
+ LODSB\r
+\r
+ IF KANJI\r
+ CALL TESTKANJ\r
+ JZ TESTPPSEP\r
+ DEC CX\r
+ INC SI\r
+ INC [KPARSE]\r
+ JMP SKIPPATH2\r
+\r
+TESTPPSEP:\r
+ ENDIF\r
+\r
+ CALL PATHCHRCMP\r
+ JNZ TESTPMETA\r
+ INC [DESTISDIR]\r
+TESTPMETA:\r
+ CMP AL,'?'\r
+ JNZ TESTPSTAR\r
+ OR [DESTINFO],2\r
+TESTPSTAR:\r
+ CMP AL,'*'\r
+ JNZ TESTPDELIM\r
+ OR [DESTINFO],2\r
+TESTPDELIM:\r
+ CALL DELIM\r
+ JZ PATHDONEDEC\r
+ CMP AL,[SWITCHAR]\r
+ JNZ SKIPPATH\r
+PATHDONEDEC:\r
+ DEC SI\r
+PATHDONE:\r
+ XOR AL,AL\r
+ XCHG AL,[SI]\r
+ INC SI\r
+ CMP AL,0DH\r
+ JNZ NOPSTORE\r
+ MOV [SI],AL ;Don't loose the CR\r
+NOPSTORE:\r
+ MOV [PATHPOS],SI\r
+ MOV [PATHCNT],CX\r
+ return\r
+\r
+PGETARG:\r
+ MOV SI,80H\r
+ LODSB\r
+ OR AL,AL\r
+ retz\r
+ CALL PSCANOFF\r
+ CMP AL,13\r
+ return\r
+\r
+PSCANOFF:\r
+ LODSB\r
+ CALL DELIM\r
+ JNZ PSCANOFFD\r
+ CMP AL,';'\r
+ JNZ PSCANOFF ; ';' is not a delimiter\r
+PSCANOFFD:\r
+ DEC SI ; Point to first non-delimiter\r
+ return\r
+\r
+PATH:\r
+ CALL FIND_PATH\r
+ CALL PGETARG ; Pre scan for arguments\r
+ JZ DISPPATH ; Print the current path\r
+ CALL DELETE_PATH ; DELETE ANY OFFENDING NAME\r
+ CALL SCAN_DOUBLE_NULL\r
+ CALL MOVE_NAME ; MOVE IN PATH=\r
+ CALL PGETARG\r
+ CMP AL,';' ; NUL path argument?\r
+ JZ GOTPATHS\r
+PATHSLP: ; Get the user specified path\r
+ LODSB\r
+ CMP AL,0DH\r
+ JZ GOTPATHS\r
+\r
+ IF KANJI\r
+ CALL TESTKANJ\r
+ JZ NOTKANJ2\r
+ CALL STORE_CHAR\r
+ LODSB\r
+ CALL STORE_CHAR\r
+ JMP SHORT PATHSLP\r
+\r
+NOTKANJ2:\r
+ ENDIF\r
+\r
+ CALL UPCONV\r
+ CMP AL,';' ; ';' not a delimiter on PATH\r
+ JZ NOTDELIM\r
+ CALL DELIM\r
+ JZ GOTPATHS\r
+NOTDELIM:\r
+ CALL STORE_CHAR\r
+ JMP SHORT PATHSLP\r
+\r
+GOTPATHS:\r
+ XOR AX,AX\r
+ STOSW\r
+ return\r
+\r
+DISPPATH:\r
+ CALL PRINT_PATH\r
+ CALL CRLF2\r
+ return\r
+\r
+PRINT_PATH:\r
+ CMP BYTE PTR ES:[DI],0\r
+ JNZ PATH1\r
+PATH0:\r
+ MOV DX,OFFSET TRANGROUP:NULPATH\r
+ PUSH CS\r
+ POP DS\r
+ JMP PRINT\r
+PATH1:\r
+ PUSH ES\r
+ POP DS\r
+ SUB DI,5\r
+ MOV DX,DI\r
+ASSUME DS:RESGROUP\r
+ CALL SCASB2 ; LOOK FOR NUL\r
+ CMP CX,0FFH\r
+ JZ PATH0\r
+ JMP ZPRINT\r
+\r
+FCB_TO_ASCZ: ; Convert DS:SI to ASCIZ ES:DI\r
+ MOV CX,8\r
+MAINNAME:\r
+ LODSB\r
+ CMP AL,' '\r
+ JZ SKIPSPC\r
+ STOSB\r
+SKIPSPC:\r
+ LOOP MAINNAME\r
+ LODSB\r
+ CMP AL,' '\r
+ JZ GOTNAME\r
+ MOV AH,AL\r
+ MOV AL,'.'\r
+ STOSB\r
+ XCHG AL,AH\r
+ STOSB\r
+ MOV CL,2\r
+EXTNAME:\r
+ LODSB\r
+ CMP AL,' '\r
+ JZ GOTNAME\r
+ STOSB\r
+ LOOP EXTNAME\r
+\r
+GOTNAME:\r
+ XOR AL,AL\r
+ STOSB\r
+ return\r
+\r
+GETNUM:\r
+ CALL INDIG\r
+ retc\r
+ MOV AH,AL ; Save first digit\r
+ CALL INDIG ; Another digit?\r
+ JC OKRET\r
+ AAD ; Convert unpacked BCD to decimal\r
+ MOV AH,AL\r
+OKRET:\r
+ OR AL,1\r
+ return\r
+\r
+INDIG:\r
+ MOV AL,BYTE PTR[SI]\r
+ SUB AL,"0"\r
+ retc\r
+ CMP AL,10\r
+ CMC\r
+ retc\r
+ INC SI\r
+ return\r
+\r
+\r
+OUT2: ; Output binary number as two ASCII digits\r
+ AAM ; Convert binary to unpacked BCD\r
+ XCHG AL,AH\r
+ OR AX,3030H ; Add "0" bias to both digits\r
+ CMP AL,"0" ; Is MSD zero?\r
+ JNZ NOSUP\r
+ SUB AL,BH ; Suppress leading zero if enabled\r
+NOSUP:\r
+ MOV BH,0 ; Disable zero suppression\r
+ STOSW\r
+ return\r
+\r
+OUT:\r
+; Print char in AL without affecting registers\r
+ XCHG AX,DX\r
+ PUSH AX\r
+ CALL OUT_CHAR\r
+ POP AX\r
+ XCHG AX,DX\r
+ return\r
+\r
+OUT_CHAR:\r
+ PUSH DS\r
+ PUSH DX\r
+ PUSH CX\r
+ PUSH BX\r
+ PUSH AX\r
+ PUSH CS\r
+ POP DS\r
+ MOV BX,OFFSET TRANGROUP:CHARBUF\r
+ MOV [BX],DL\r
+ MOV DX,BX\r
+ MOV BX,1\r
+ MOV CX,BX\r
+ MOV AH,WRITE\r
+ INT int_command\r
+ POP AX\r
+ POP BX\r
+ POP CX\r
+ POP DX\r
+ POP DS\r
+ return\r
+\r
+\r
+ERROR_PRINT:\r
+ PUSH AX\r
+ PUSH BX\r
+ MOV AL,"$"\r
+ MOV BX,2 ;STD ERROR\r
+ JMP SHORT STRING_OUT\r
+\r
+CRPRINT:\r
+ PUSH AX\r
+ MOV AL,13\r
+ JMP SHORT Z$PRINT\r
+PRINT: ;$ TERMINATED STRING\r
+ PUSH AX\r
+ MOV AL,"$"\r
+ JMP SHORT Z$PRINT\r
+ZPRINT:\r
+ PUSH AX\r
+ XOR AX,AX ;NUL TERMINATED STRING\r
+Z$PRINT:\r
+ PUSH BX\r
+ MOV BX,1 ;STD CON OUT\r
+;\r
+; output string terminated by AL to handle BX, DS:DX points to string\r
+;\r
+STRING_OUT:\r
+ PUSH CX\r
+ PUSH DI\r
+ MOV DI,DX\r
+ MOV CX,-1\r
+ PUSH ES\r
+ PUSH DS\r
+ POP ES\r
+ REPNZ SCASB ; LOOK FOR TERMINATOR\r
+ POP ES\r
+ NEG CX\r
+ DEC CX\r
+ DEC CX\r
+;\r
+; WRITE CHARS AT DS:DX TO HANDLE IN BX, COUNT IN CX\r
+;\r
+ MOV AH,WRITE\r
+ INT int_command\r
+ JC ERROR_OUTPUT\r
+ CMP AX,CX\r
+ JNZ ERROR_OUTPUT\r
+ POP DI\r
+ POP CX\r
+ POP BX\r
+ POP AX\r
+ return\r
+\r
+ERROR_OUTPUT:\r
+ PUSH CS\r
+ POP DS\r
+ASSUME DS:TRANGROUP\r
+ MOV ES,[RESSEG]\r
+ASSUME ES:RESGROUP\r
+ MOV DX,OFFSET TRANGROUP:NOSPACE\r
+ CMP [PIPEFLAG],0\r
+ JZ GO_TO_ERROR\r
+ MOV [PIPEFLAG],0\r
+ MOV DX,OFFSET TRANGROUP:PIPEEMES\r
+GO_TO_ERROR:\r
+ JMP CERROR\r
+\r
+\r
+TRANCODE ENDS\r
+ END\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+TITLE COMMAND Transient Initialized DATA\r
+\r
+ INCLUDE COMSW.ASM\r
+.xlist\r
+.xcref\r
+ INCLUDE COMSEG.ASM\r
+.list\r
+.cref\r
+\r
+ INCLUDE IFEQU.ASM\r
+\r
+TRANCODE SEGMENT PUBLIC\r
+ EXTRN PRINT_DATE:NEAR,PRINT_TIME:NEAR,PRINT_DEFAULT_DIRECTORY:NEAR\r
+ EXTRN PRINT_DRIVE:NEAR,PRINT_VERSION:NEAR,PRINT_G:NEAR\r
+ EXTRN PRINT_L:NEAR,PRINT_B:NEAR,CRLF2:NEAR,OUT:NEAR,PRINT_ESC:NEAR\r
+ EXTRN PRINT_BACK:NEAR,PRINT_EQ:NEAR\r
+\r
+ EXTRN IFNOT:NEAR,IFERLEV:NEAR,IFEXISTS:NEAR\r
+\r
+ EXTRN CATALOG:NEAR,CRENAME:NEAR,ERASE:NEAR,TYPEFIL:NEAR\r
+ EXTRN TCOMMAND:NEAR,COPY:NEAR,PAUSE:NEAR,DATE:NEAR,CTIME:NEAR\r
+ EXTRN VERSION:NEAR,VOLUME:NEAR,$CHDIR:NEAR,$MKDIR:NEAR,$RMDIR:NEAR\r
+ EXTRN CNTRLC:NEAR,VERIFY:NEAR,ADD_NAME_TO_ENVIRONMENT:NEAR\r
+ EXTRN ADD_PROMPT:NEAR,PATH:NEAR,$EXIT:NEAR,CTTY:NEAR,ECHO:NEAR\r
+ EXTRN GOTO:NEAR,SHIFT:NEAR,$IF:NEAR,$FOR:NEAR,CLS:NEAR\r
+TRANCODE ENDS\r
+\r
+; Data for transient portion\r
+\r
+TRANDATA SEGMENT PUBLIC BYTE\r
+\r
+ PUBLIC BADBAT,NEEDBAT,BADNAM,RENERR,NOTFND,NOSPACE,ENVERR,FULDIR\r
+ PUBLIC OVERWR,LOSTERR,DIRMES_PRE,DIRMES_POST,BADDRV,PAUSEMES,BADSWT\r
+ PUBLIC COPIED_PRE,COPIED_POST,BYTMES_PRE,BYTMES_POST\r
+ PUBLIC WEEKTAB,BADDAT,NEWDAT,BADTIM,NEWTIM,SUREMES,CURDAT_MID\r
+ PUBLIC CURDAT_PRE,CURDAT_POST,CURTIM_PRE,CURTIM_POST,VERMES_POST\r
+ PUBLIC DMES,VERMES_PRE,VOLMES,GOTVOL,NOVOL,BADCD,BADMKD,BADRMD\r
+ PUBLIC BAD_ON_OFF,NULPATH,PATH_TEXT,PROMPT_TEXT,BADPMES\r
+ PUBLIC BADDEV,BADLAB,SYNTMES,FORNESTMES,PIPEEMES,INBDEV,OFFMES\r
+ PUBLIC ONMES,CTRLCMES,VERIMES,ECHOMES,BADCPMES,BADARGS,DEVWMES\r
+ PUBLIC ACRLF,DBACK,CLSSTRING,PROMPT_TABLE,IFTAB,COMTAB\r
+ PUBLIC TRANDATAEND,DIRHEAD_PRE,DIRHEAD_POST\r
+\r
+ ORG 0\r
+ZERO = $\r
+BADBAT DB 13,10,"Batch file missing",13,10,"$"\r
+NEEDBAT DB 13,10,"Insert disk with batch file"\r
+ DB 13,10,"and press any key when ready",13,10,"$"\r
+BADNAM DB "Bad command or file name",13,10,"$"\r
+RENERR DB "Duplicate file name or "\r
+NOTFND DB "File not found",13,10,"$"\r
+NOSPACE DB "Insufficient disk space",13,10,"$"\r
+ENVERR DB "Out of environment space",13,10,"$"\r
+FULDIR DB "File creation error",13,10,"$"\r
+OVERWR DB "File cannot be copied onto itself",13,10,"$"\r
+LOSTERR DB "Content of destination lost before copy",13,10,"$"\r
+\r
+;"COPIED_PRE<# files copied>COPIED_POST"\r
+COPIED_POST DB " File(s) copied",13,10\r\8aCOPIED_PRE DB "$"\r
+\r
+;"DIRMES_PRE<# files in dir>DIRMES_POST"\r
+DIRMES_POST DB " File(s) "\r
+DIRMES_PRE DB "$"\r
+\r
+;"BYTMES_PRE<# free bytes>BYTMES_POST"\r
+BYTMES_POST DB " bytes free",13,10\r
+BYTMES_PRE DB "$"\r
+\r
+BADDRV DB "Invalid drive specification",13,10,"$"\r
+PAUSEMES DB "Strike a key when ready . . . $"\r
+BADSWT DB "Invalid parameter",13,10,"$"\r
+WEEKTAB DB "SunMonTueWedThuFriSat"\r
+BADDAT DB 13,10,"Invalid date$"\r
+\r
+;"CURDAT_PRE<day of week>CURDAT_MID<MO,DAY,YR>CURDAT_POST"\r
+;Note: CURDAT_MID also appears in the date printed via PROMPT command\r
+CURDAT_PRE DB "Current date is "\r
+CURDAT_MID LABEL BYTE\r
+CURDAT_POST DB "$"\r
+\r
+NEWDAT DB 13,10,"Enter new date: $"\r
+BADTIM DB 13,10,"Invalid time$"\r
+\r
+;"CURTIM_PRE<HR,MIN,SEC,HSEC>CURTIM_POST"\r
+CURTIM_PRE DB "Current time is "\r
+CURTIM_POST DB "$"\r
+\r
+NEWTIM DB 13,10,"Enter new time: $"\r
+SUREMES DB "Are you sure (Y/N)? $"\r
+DMES DB " <DIR> $"\r
+\r
+;"VERMES_PRE<version #>VERMES_POST"\r
+ IF IBMVER\r
+VERMES_PRE DB "TeleVideo Personal Computer DOS Version "\r
+ ENDIF\r
+ IF MSVER\r
+VERMES_PRE DB "MS-DOS Version "\r
+ ENDIF\r
+VERMES_POST DB "$"\r
+\r
+VOLMES DB " Volume in drive $"\r
+GOTVOL DB " is $"\r
+NOVOL DB " has no label$"\r
+\r
+BADCD DB "Invalid directory",13,10,"$"\r
+BADMKD DB "Unable to create directory",13,10,"$"\r
+BADRMD DB "Invalid path, not directory,",13,10\r
+ DB "or directory not empty",13,10,"$"\r
+BAD_ON_OFF DB "Must specify ON or OFF" ;Note Run over to next message\r
+\r
+;"DIRHEAD_PRE<path of dir>DIRHEAD_POST"\r
+DIRHEAD_POST DB 13,10,"$"\r
+DIRHEAD_PRE DB " Directory of $"\r\8a\r
+NULPATH DB "No Path $"\r
+PATH_TEXT DB "PATH="\r
+PROMPT_TEXT DB "PROMPT="\r
+BADPMES DB "Invalid drive in search path",13,10,"$"\r
+BADDEV DB "Invalid device",13,10,"$"\r
+BADLAB DB "Label not found",13,10,"$"\r
+SYNTMES DB "Syntax error",13,10,"$"\r
+FORNESTMES DB 13,"FOR cannot be nested",13,10,"$"\r
+PIPEEMES DB "Intermediate file error during pipe",13,10,"$"\r
+INBDEV DB "Cannot do binary reads from a device",13,10,"$"\r
+OFFMES DB "off",13,10,"$"\r
+ONMES DB "on",13,10,"$"\r
+CTRLCMES DB "BREAK is $"\r
+VERIMES DB "VERIFY is $"\r
+ECHOMES DB "ECHO is $"\r
+BADCPMES DB "Invalid path or file name",13,10,"$"\r
+BADARGS DB "Invalid number of parameters",13,10,"$"\r
+DEVWMES DB "Error writing to device"\r
+ACRLF DB 13,10,"$"\r
+DBACK DB 8," ",8,0 ; DESTRUCTIVE BACK SPACE\r
+\r
+CLSSTRING DB 4,01BH,"[2J" ; ANSI Clear screen\r
+\r
+PROMPT_TABLE LABEL BYTE\r
+ DB "D"\r
+ DW OFFSET TRANGROUP:PRINT_DATE\r
+ DB "T"\r
+ DW OFFSET TRANGROUP:PRINT_TIME\r
+ DB "P"\r
+ DW OFFSET TRANGROUP:PRINT_DEFAULT_DIRECTORY\r
+ DB "N"\r
+ DW OFFSET TRANGROUP:PRINT_DRIVE\r
+ DB "V"\r
+ DW OFFSET TRANGROUP:PRINT_VERSION\r
+ DB "G"\r
+ DW OFFSET TRANGROUP:PRINT_G\r
+ DB "L"\r
+ DW OFFSET TRANGROUP:PRINT_L\r
+ DB "B"\r
+ DW OFFSET TRANGROUP:PRINT_B\r
+ DB "_"\r
+ DW OFFSET TRANGROUP:CRLF2\r
+ DB "$"\r
+ DW OFFSET TRANGROUP:OUT\r
+ DB "E"\r
+ DW OFFSET TRANGROUP:PRINT_ESC\r
+ DB "H"\r
+ DW OFFSET TRANGROUP:PRINT_BACK\r
+ DB "Q"\r
+ DW OFFSET TRANGROUP:PRINT_EQ\r
+ DB 0 ; NUL TERMINATED\r
+\r
+IFTAB LABEL BYTE ; Table of IF conditionals\r
+ DB 3,"NOT" ; First byte is count\r\8a DW OFFSET TRANGROUP:IFNOT\r
+ DB 10,"ERRORLEVEL"\r
+ DW OFFSET TRANGROUP:IFERLEV\r
+ DB 5,"EXIST"\r
+ DW OFFSET TRANGROUP:IFEXISTS\r
+ DB 0\r
+\r
+COMTAB DB 4,"DIR",1 ; Table for internal command names\r
+ DW OFFSET TRANGROUP:CATALOG\r
+ DB 7,"RENAME",1\r
+ DW OFFSET TRANGROUP:CRENAME\r
+ DB 4,"REN",1\r
+ DW OFFSET TRANGROUP:CRENAME\r
+ DB 6,"ERASE",1\r
+ DW OFFSET TRANGROUP:ERASE\r
+ DB 4,"DEL",1\r
+ DW OFFSET TRANGROUP:ERASE\r
+ DB 5,"TYPE",1\r
+ DW OFFSET TRANGROUP:TYPEFIL\r
+ DB 4,"REM",0\r
+ DW OFFSET TRANGROUP:TCOMMAND\r
+ DB 5,"COPY",1\r
+ DW OFFSET TRANGROUP:COPY\r
+ DB 6,"PAUSE",0\r
+ DW OFFSET TRANGROUP:PAUSE\r
+ DB 5,"DATE",0\r
+ DW OFFSET TRANGROUP:DATE\r
+ DB 5,"TIME",0\r
+ DW OFFSET TRANGROUP:CTIME\r
+ DB 4,"VER",0\r
+ DW OFFSET TRANGROUP:VERSION\r
+ DB 4,"VOL",1\r
+ DW OFFSET TRANGROUP:VOLUME\r
+ DB 3,"CD",1\r
+ DW OFFSET TRANGROUP:$CHDIR\r
+ DB 6,"CHDIR",1\r
+ DW OFFSET TRANGROUP:$CHDIR\r
+ DB 3,"MD",1\r
+ DW OFFSET TRANGROUP:$MKDIR\r
+ DB 6,"MKDIR",1\r
+ DW OFFSET TRANGROUP:$MKDIR\r
+ DB 3,"RD",1\r
+ DW OFFSET TRANGROUP:$RMDIR\r
+ DB 6,"RMDIR",1\r
+ DW OFFSET TRANGROUP:$RMDIR\r
+ DB 6,"BREAK",0\r
+ DW OFFSET TRANGROUP:CNTRLC\r
+ DB 7,"VERIFY",0\r
+ DW OFFSET TRANGROUP:VERIFY\r
+ DB 4,"SET",0\r
+ DW OFFSET TRANGROUP:ADD_NAME_TO_ENVIRONMENT\r
+ DB 7,"PROMPT",0\r
+ DW OFFSET TRANGROUP:ADD_PROMPT\r
+ DB 5,"PATH",0\r
+ DW OFFSET TRANGROUP:PATH\r\8a DB 5,"EXIT",0\r
+ DW OFFSET TRANGROUP:$EXIT\r
+ DB 5,"CTTY",1\r
+ DW OFFSET TRANGROUP:CTTY\r
+ DB 5,"ECHO",0\r
+ DW OFFSET TRANGROUP:ECHO\r
+ DB 5,"GOTO",0\r
+ DW OFFSET TRANGROUP:GOTO\r
+ DB 6,"SHIFT",0\r
+ DW OFFSET TRANGROUP:SHIFT\r
+ DB 3,"IF",0\r
+ DW OFFSET TRANGROUP:$IF\r
+ DB 4,"FOR",0\r
+ DW OFFSET TRANGROUP:$FOR\r
+ DB 4,"CLS",0\r
+ DW OFFSET TRANGROUP:CLS\r
+ DB 0 ; Terminate command table\r
+\r
+TRANDATAEND LABEL BYTE\r
+\r
+TRANDATA ENDS\r
+ END\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a
\ No newline at end of file
--- /dev/null
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ MS-DOS 2.0\r
+\r
+ Utility Extensions\r
+\f\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ The following notation is used below:\r
+\r
+ [item] item is optional.\r
+ item* item is repeated 0 or more times.\r
+ item+ item is repeated 1 or more times.\r
+ {item1 | item2}\r
+ item1 is present or item 2 is present but\r
+ not both.\r
+ <object> indicates a syntactic variable.\r
+\f\r
+\r
+COMMAND invokation\r
+\r
+COMMAND [[<drive>:]<path>] [<cttydev>] [-D] [-P] [-C <string>]\r
+\r
+ -P If present COMMAND will be permanent, otherwise\r
+ this is a transient command.\r
+\r
+ -D If present COMMAND will not prompt for DATE and\r
+ TIME when it comes up.\r
+\r
+ d: Specifies device where command will look for\r
+ COMMAND.COM current default drive if absent.\r
+\r
+ <Path> Specifies a directory on device d: root\r
+ directory if absent.\r
+\r
+ <cttydev> Name of the CTTY device. /DEV/CON if absent\r
+ and command is permanent. The /DEV/ may be left\r
+ off if AVAILDEV is TRUE (see sysinit doc).\r
+\r
+ -C <string> If present -C must be the last switch.\r
+ This causes COMMAND to try to execute the string\r
+ as if the user had typed it at the standard input.\r
+ COMMAND executes this single command string and\r
+ then exits. If the -P switch is present it is\r
+ ignored (can't have a single command, permanent\r
+ COMMAND). NOTE: ALL of the text on the command\r
+ line after the -C is just passed on. It is not\r
+ processed for more arguments, this is why -C must\r
+ be last.\r
+\r
+COMMAND extensions\r
+\r
+IF <condition> <command>\r
+\r
+ where <condition> is one of the following:\r
+\r
+ ERRORLEVEL <number>\r
+ true if and only if the previous program EXECed by\r
+ COMMAND had an exit code of <number> or higher.\r
+\r
+ <string1> == <string2>\r
+ true if and only if <string1> and <string2> are\r
+ identical after parameter substitution. Strings\r
+ may not have embedded delimiters.\r
+\r
+ EXIST <filename>\r
+ true if and only if <filename> exists.\r
+\r
+ NOT <condition>\r
+ true if and only if <condition> is false.\r
+\r
+ The IF statement allows conditional execution of commands.\r
+ When the <condition> is true, then the <command> is\r
+ executed otherwise, the <command> is skipped.\r
+\r
+ Examples:\r
+\r
+ IF not exist /tmp/foo ECHO Can't find file /tmp/foo\r
+\r
+ IF $1x == x ECHO Need at least one parameter\r
+\r
+ IF NOT ERRORLEVEL 3 LINK $1,,;\r
+\r
+\r
+FOR %%<c> IN <set> DO <command>\r
+\r
+ <c> can be any character but 0,1,2,3,..,9 (so there is no\r
+ confusion with the %0 - %9 batch parameters).\r
+\r
+ <set> is ( <item>* )\r
+\r
+ The %%<c> variable is sequentially set to each member of\r
+ <set> and then <command> is evaluated. If a member of\r
+ <set> is an expression involving * and/or ?, then the\r
+ variable is set to each matching pattern from disk. In\r
+ this case only one such <item> may be in the set, any\r
+ <item>s after the first are ignored.\r
+\r
+ Example:\r
+\r
+ FOR %%f IN ( *.ASM ) DO MASM %%f;\r
+\r
+ for %%f in (FOO BAR BLECH) do REM %%f to you\r
+\r
+ NOTE: The '%%' is needed so that after Batch parameter\r
+ (%0 - %9) processing is done, there is one '%' left.\r
+ If only '%f' were there, the batch parameter processor\r
+ would see the '%' then look at 'f', decide that '%f'\r
+ was an error (bad parameter reference) and throw out\r
+ the '%f' so that FOR would never see it. If the FOR\r
+ is NOT in a batch file, then only ONE '%' should be\r
+ used.\r
+\f\r
+\r
+SHIFT\r
+\r
+ Currently, command files are limited to handling 10\r
+ parameters: %0 through %9. To allow access to more than\r
+ these, the command SHIFT will perform a 'pop' of the\r
+ command line parameters:\r
+\r
+ if %0 = "foo"\r
+ %1 = "bar"\r
+ %2 = "blech"\r
+ %3...%9 are empty\r
+\r
+ then a SHIFT will result in the following:\r
+\r
+ %0 = "bar"\r
+ %1 = "blech"\r
+ %2...%9 are empty\r
+\r
+ If there are more than 10 parameters given on a command\r
+ line, then the those that appear after the 10th (%9) will\r
+ be shifted one at a time into %9 by successive shifts.\r
+\r
+:<label>\r
+\r
+ This is essentially a no-op. It defines a label in the\r
+ batch file for a subsequent GOTO. It may also be used to\r
+ put comment lines in batch files since all lines that\r
+ start with ':' are ignored.\r
+\r
+GOTO <label>\r
+\r
+ Causes commands to be taken from the batch file beginning\r
+ with the line after the <label> definition. If no label\r
+ has been defined, the current batch file will terminate.\r
+\r
+ Example:\r
+\r
+ :foo\r
+ REM looping...\r
+ GOTO foo\r
+\r
+ will produce a infinite sequence of messages:\r
+ 'REM looping...'\r
+\r
+ NOTE: Labels are case insensitive, :FOO == :foo == :Foo\r
+\f\r
+\r
+ECHO [{ON | OFF | <message>}]\r
+\r
+ Normally, commands in a BATCH file are echoed onto the\r
+ standard output as they are seen by COMMAND. ECHO OFF\r
+ turns off this feature. ECHO ON turns echoing back on.\r
+ If ON or OFF is not specified and there is text following\r
+ the command, that text (a message) is echoed to standard\r
+ output. If there are no arguments at all, the current\r
+ setting of echo (on or off) is echoed to the standard\r
+ output in the form:\r
+\r
+ ECHO is xxx\r
+\r
+ Where xxx is "on" or "off".\r
+\r
+Redirection of standard input/standard output.\r
+\r
+ Programs that read from the keyboard and write to the\r
+ screen are said to be doing I/O to the standard input and\r
+ standard output. Using any of the following will result\r
+ in I/O to these standard devices:\r
+\r
+ Writing to default handles 1 / read from default\r
+ handle 0.\r
+\r
+ Doing byte I/O using system calls 1, 2, 6-12.\r
+\r
+ These standard devices may be redirected to/from files by\r
+ the following in command line arguments:\r
+\r
+ > <filename>\r
+ causes <filename> to be created (or truncated to\r
+ zero length) and then assigns standard output to\r
+ that file. All output from the command will be\r
+ placed in the file.\r
+\r
+ < <filename>\r
+ causes standard input to be assigned to\r
+ <filename>. All input to the command will come\r
+ from this file. If end-of-file is reached, then\r
+ system calls 1, 2, 6-12 will return ^Z , while\r
+ reading from handle 0 will return zero characters.\r
+\r
+ >> <filename>\r
+ causes <filename> to be opened (created if\r
+ necessary) and positions the write pointer at the\r
+ end of the file so that all output will be\r
+ appended to the file.\r
+\r
+ Note that the above will not appear in the command line\r
+ that the program being invoked sees.\r
+\r
+ Examples:\r
+\r
+ DIR *.ASM > FOO.LST\r
+ Sends the output of the dir command to the file\r
+ FOO.LST.\r
+\f\r
+\r
+ FOR %0 IN (*.ASM) DO MASM %0; >>ERRS.LST\r
+ Sends all error output from assembling every .ASM file\r
+ into the file ERRS.LST.\r
+\r
+Piping of standard I/O\r
+\r
+ It is often useful for the output of one program to be\r
+ sent as input to another program. A typical case is a\r
+ program that produces columnar output that must later be\r
+ sorted.\r
+\r
+ The pipe feature allows this to occur naturally is the\r
+ programs do all of their I/O to the standard devices.\r
+\r
+ For example, if we had a program SORT that read all of\r
+ it's standard input, sorted it and then wrote it to the\r
+ standard output, then we could get a sorted directory\r
+ listing as follows:\r
+\r
+ DIR | SORT\r
+\r
+ The | would cause all standard output generated by the\r
+ left-hand command to be sent to the standard input of the\r
+ right-hand command.\r
+\r
+ If we wanted the sorted directory to be sent to a file, we\r
+ type:\r
+\r
+ DIR | SORT >FILE\r
+\r
+ and away it goes.\r
+\r
+ The piping feature is implemented as sequential execution\r
+ of the procedures with redirection to and from temporary\r
+ files. In the example above, the following would be an\r
+ exact equivalent:\r
+\r
+ DIR >/tmp/std1\r
+ SORT </tmp/std1 >FILE\r
+\r
+\f\r
+\r
+ The pipe is not a real pipe but rather a quasi-pipe\r
+ that uses temporary files to hold the input and output as\r
+ it sequentially executes the elements of the pipe. These\r
+ files are created in the current directory, of the current\r
+ drive and have the form %PIPEx%.$$$, where x will be 1 or\r
+ 2. This means that any program that runs in the pipe must\r
+ be sure to restore the current directory and drive if it\r
+ has changed them, otherwise the pipe files will be lost.\r
+\r
+\r
+VER\r
+ Prints DOS version number.\r
+\r
+VOL [<drive>:]\r
+ Prints the volume ID of the disk in drive d:. No d: does\r
+ default drive.\r
+\r
+CHDIR [{<drive>: | <path>}]\r
+ Change directory, or print current. directory.If no\r
+ argument is given, the current directory on the default\r
+ drive is printed. If d: alone is given, the durrent\r
+ directory of drive d is printed. Otherwise the current\r
+ directory is set to path.\r
+\r
+ NOTE:"CD" is accepted as an abbreviation.\r
+\r
+MKDIR <path> - Make a directory.\r
+ "MD" is accepted as an abbreviation.\r
+\r
+RMDIR <path> - Remove a directory.\r
+ "RD" is accepted as an abbreviation.\r
+ The directory must be empty except for\r
+ '.' and '..'.\r
+\r
+ <path> - A standard XENIX style path with the optional\r
+ addition of a drive spec:\r
+\r
+ A:/FOO/BAR Full path\r
+ /FOO/BAR Full path, current drive\r
+ FOO/BAR Current dir relative\r
+ A:FOO/BAR " " "\r
+\r
+VERIFY [{ON | OFF}]\r
+ Select/deselect verify after write mode. This supliments\r
+ the V switch to the COPY command. Once turned ON, it\r
+ stays on until some program changes it (via the set verify\r
+ system call) or the VERIFY OFF command is given. If no\r
+ argument is given, the current setting of VERIFY is\r
+ printed to the standard output in the form:\r
+\r
+ VERIFY is xxx\r
+\r
+ Where xxx is "on" or "off".\r
+\r
+PATH [<path>{;<path>}*]\r
+ Set command search paths. This allows users to set\r
+ directories that should be searched for external commands\r
+ after a search of the current directory is made. The\r
+ default value is /bin. In addition there are two special\r
+ cases: PATH all by itself with no arguments will print\r
+ the current path. Path with the single argument ';' (ie.\r
+ "PATH ;") will set the NUL path (no directories other than\r
+ the current one searched). If no argument is given, the\r
+ current value of PATH is printed to the standard output in\r
+ the form:\r
+\r
+ PATH=text of path\r
+ or\r
+ No path\r
+\r
+ NOTE: On IBM systems, the default value of path is No\r
+ path.\r
+\r
+EXIT\r
+ For COMMANDs run without the P switch, this causes COMMAND\r
+ to return. For a normal COMMAND it causes a return to\r
+ itself.\r
+\r
+BREAK [{ON | OFF}]\r
+ Like in CONFIG.SYS, "BREAK ON" turns on the Control C\r
+ check in the DOS function dispatcher. "BREAK OFF" turns\r
+ it off. If no argument is given the setting of BREAK is\r
+ printed to the standard output in the form:\r
+\r
+ BREAK is xxx\r
+\r
+ Where xxx is "on" or "off".\r
+\r
+PROMPT [<prompt-text>]\r
+ Set the system prompt. MS-DOS prompts are now user\r
+ settable, all of the text on the command line is taken to\r
+ be the new prompt. If no text is present the prompt is\r
+ set to the default prompt. There are meta strings for\r
+ various special prompts. These are of the form '$c' where\r
+ c is one of the following:\r
+\r
+ $ - The '$' character.\r
+ t - The time.\r
+ d - The date.\r
+ p - The current directory of the default drive.\r
+ v - The version number.\r
+ n - The default drive.\r
+ g - The '>' character.\r
+ l - The '<' character.\r
+ b - The '|' character.\r
+ s - The ' ' character.\r
+ e - The ESC character.\r
+ _ - A CR LF sequence.\r
+\r
+ EXAMPLE:\r
+ PROMPT $n:\r
+ Would set the normal MS-DOS prompt.\r
+ PROMPT $n>\r
+ Would det the normal PC-DOS prompt.\r
+ PROMPT Time = $t$_Date = $d\r
+ Would set a two line prompt which printed\r
+ Time = (current time)\r
+ Date = (current date)\r
+\r
+ NOTE: For '$c' sequences, lower case = upper case, and\r
+ any character not on the above list is mapped to\r
+ nothing.\r
+\r
+SET (ENVNAME)=(ENVTEXT)\r
+ Set environment strings. This command inserts strings in\r
+ COMMAND's environment. For instance:\r
+\r
+ SET PROMPT=$n>\r
+ Duplicates the function of the PROMPT command.\r
+ SET PATH=p1;p2\r
+ Duplicates the function of the PATH command.\r
+ SET foo=bar\r
+ Puts the string FOO=bar into the environment (note the\r
+ case mapping of (ENVNAME)).\r
+\r
+ NOTE: Environments are very flexible, almost anything can\r
+ be put into the environment with the SET command; the\r
+ only requirement is that a single '=' be present in\r
+ the string.\r
+\r
+CLS\r
+ Clear screen, causes the ANSI escape sequence ESC[2J to be\r
+ sent to standard output.\r
+\r
+CTTY /DEV/dev - Change console TTY. For instance:\r
+\r
+ CTTY /DEV/AUX\r
+\r
+ Would move all command I/O to the AUX port.\r
+\r
+ CTTY /DEV/CON\r
+\r
+ Would move it back to the normal device. The\r
+ /dev/ prefix may be left off if AVAILDEV is\r
+ TRUE (see configuration-file doc).\r
+\r
+COMMAND internal commands take path arguments.\r
+\r
+ DIR <path>\r
+\r
+ COPY <path> <path>\r
+\r
+ DEL(ERASE) <path>\r
+ If the path is a dir, all files in that dir\r
+ are deleted.\r
+ NOTE: The "Are you sure (Y/N)" prompt for DEL and\r
+ ERASE now uses buffered standard input, so\r
+ users must type a return after their answer.\r
+ This gives them the chance to correct if they\r
+ type 'y' by mistake.\r
+\r
+ TYPE <path> (must specify a file)\r
+\r
+\f\r
+\r
+\r
+FILCOM - compare two files\r
+\r
+ The FILCOM program compares two files and produces a log\r
+ of differences between them. The comparison may be made\r
+ in two fashions; either on a line-by-line basis, or on a\r
+ byte-by-byte basis.\r
+\r
+ The line-by-line compare will isolate blocks of lines that\r
+ are different between the two files and will print the\r
+ blocks from each file. The line-by-line compare is the\r
+ default when neither of the two files being compared has\r
+ the extension .EXE, .COM, or .OBJ.\r
+\r
+ The byte-by-byte compare will display exactly which bytes\r
+ are different between the two files. If either file being\r
+ compared has extension .EXE, .COM, or .OBJ then the files\r
+ will be compared in byte-by-byte mode.\r
+\f\r
+\r
+\r
+RECOVER - recover files from a trashed disk.\r
+\r
+ If a sector on a disk goes bad, you can recover either the\r
+ file that contained that sector (without the sector) or\r
+ the entire disk (if the bad sector was in the directory).\r
+\r
+ To recover a particular file:\r
+\r
+ RECOVER <file-to-recover>\r
+\r
+ This will cause the file to be read sector by sector and\r
+ to be have the bad sector skipped. Note that this implies\r
+ that the allocation unit containing the bad sector will be\r
+ read as much as possible. When such a bad sector is\r
+ found, its containing allocation unit is marked as bad,\r
+ thus preventing future allocations of that bad sector.\r
+\r
+ To recover a particular disk:\r
+\r
+ RECOVER <drive-letter>:\r
+\r
+ This will cause a scan to be made of the drive's FAT for\r
+ chains of allocation units (files). A new root directory\r
+ is then written that has entries of the form FILEnnnn.\r
+ Each FILEnnnn will point to the head of one of the\r
+ allocation unit chains.\r
+\r
+ If there are more chains than directory entries in the\r
+ root, RECOVER prints a message and leaves the un-RECOVERED\r
+ chains in the FAT so that RECOVER can be run again once\r
+ some room has been made in the ROOT.\r
+\f\r
+\r
+\r
+DEBUG ON MS-DOS 2.0\r
+\r
+\r
+ When 2.0 DEBUG is invoked it sets up a program header\r
+atoffset 0 in its program work area. On previous versions it\r
+was OK to overwrite this header with impunity: this is true\r
+of the default header set up if no <filespec> is given to\r
+DEBUG. If DEBUGging a .COM or .EXE file, however, you must be\r
+careful not to tamper with the header of the program below\r
+address 5CH, to do this will probably result in a crash. It\r
+is also important that an attempt is not made to "restart" a\r
+program once the "program terminated normally" message is\r
+given. The program must be reloaded with the N and L commands\r
+in order for it to run properly.\r
+\r
+NEW FEATURES\r
+\r
+The A (Assemble) Command\r
+\r
+FORMAT: A [<address>]\r
+\r
+PURPOSE: To assemble 8086/8087/8088 mnemonics directly into\r
+ memory.\r
+\r
+o If a syntax error is encountered, DEBUG responds with\r
+\r
+ ^ Error\r
+\r
+ and redisplays the current assembly address.\r
+\r
+o All numeric values are hexadecimal and may be entered\r
+ as 1-4 characters.\r
+\r
+o Prefix mnemonics must be entered in front of the opcode\r
+ to which they refer. They may also be entered on a\r
+ separate line.\r
+\r
+o The segment override mnemonics are CS:, DS:, ES:, and\r
+ SS:\r
+\r
+o String manipulation mnemonics must explictly state the\r
+ string size. For example, the MOVSW must be used to\r
+ move word strings and MOVSB must be used to move byte\r
+ strings.\r
+\r
+\r
+o The mnemonic for the far return is RETF.\r
+\r
+o The assembler will automatically assemble short, near\r
+ or far jumps and calls depending on byte displacement\r
+ to the destination address. These may be overridden\r
+ with the NEAR or FAR prefix. For example:\r
+\r
+ 0100:0500 JMP 502 ; a 2 byte short jump\r
+ 0100:0502 JMP NEAR 505 ; a 3 byte near jump\r
+ 0100:0505 JMP FAR 50A ; a 5 byte far jump\r
+\r
+ The NEAR prefix may be abbreviated to NE but the FAR\r
+ prefix cannot be abbreviated.\r
+\r
+o DEBUG cannot tell whether some operands refer to a word\r
+ memory location or a byte memroy location. In this case\r
+ the data type must be explicity stated with the prefix\r
+ "WORD PTR" or "BYTE PTR". DEBUG will also except the\r
+ abbreviations "WO" and "BY". For example:\r
+\r
+ NEG BYTE PTR [128]\r
+ DEC WO [SI]\r
+\r
+o DEBUG also cannot tell whether an operand refers to a\r
+ memory location or to an immediate operand. DEBUG uses\r
+ the common convention that operands enclosed in square\r
+ brackets refer to memory. For example:\r
+\r
+ MOV AX,21 ;Load AX with 21H\r
+ MOV AX,[21] ;Load AX with the contents\r
+ ;of memory location 21H\r
+\r
+o Two popular pseudo-instructions have also been included.\r
+ The DB opcode will assemble byte values directly into\r
+ memory. The DW opcode will assemble word values directly\r
+ into memory. For example:\r
+\r
+ DB 1,2,3,4,"THIS IS AN EXAMPLE"\r
+ DB 'THIS IS A QUOTE: "'\r
+ DB "THIS IS A QUOTE: '"\r
+\r
+ DW 1000,2000,3000,"BACH"\r
+\r
+\r
+o All forms of the register indirect commands are supported.\r
+ For example:\r
+\r
+ ADD BX,34[BP+2].[SI-1]\r
+ POP [BP+DI]\r
+ PUSH [SI]\r
+\r
+o All opcode synonyms are supported, For example:\r
+\r
+ LOOPZ 100\r
+ LOOPE 100\r
+\r
+ JA 200\r
+ JNBE 200\r
+\r
+o For 8087 opcodes the WAIT or FWAIT prefix must be\r
+ explictly specified. For example:\r
+\r
+ FWAIT FADD ST,ST(3) ; This lines will assemble\r
+ ; a FWAIT prefix\r
+\r
+ FLD TBYTE PTR [BX] ; This line will not\r
+\f\r
+\r
+\r
+FORMAT enhancements\r
+\r
+ FORMAT will now install volume id's during the format\r
+ process. DIR and CHKDSK will display these volume id's.\r
+\r
+ User programs can read the volume id on a particular drive\r
+ by doing a 'search next' with the volume id attribute. It\r
+ is impossible, using normal DOS calls, to delete a volume\r
+ id or to create another one. The only way to create a\r
+ volume id is to reformat the disk.\r
+\r
+ NOTE: On IBM systems the V switch must be given to FORMAT\r
+ to have it do Volume IDs.\r
+\r
+\f\r
+\r
+\r
+CHKDSK FOR MS-DOS 2.0\r
+\r
+\r
+ MS-DOS 2.0 has a tree structured directory scheme which\r
+did not exist on previous versions of MS-DOS. As a result\r
+CHKDSK is a much more complex program than in previous\r
+versions since it must perform a tree traversal to find all of\r
+the files on a given disk. It employes a depth first\r
+traversal in order to accomplish this.\r
+\r
+ Previous versions of CHKDSK automatically "fixed"\r
+disks (regardless of whether it was appropriate). CHKDSK 2.00\r
+run normally will not alter the disk in any way, it simply\r
+reports on any inconsistencies found. To actually "fix" a\r
+disk CHKDSK must be run with the F switch (Fix). This allows\r
+you to perhaps take some alternate (to CHKDSK repairs) action\r
+before letting CHKDSK loose on your disk.\r
+\r
+ CHKDSK 2.00 will report on non-contiguous allocation units\r
+(extents) for specified files. This is handy for gaging how\r
+"fragmented" a disk volume has become. This is done by simply\r
+giving a filespec:\r
+\r
+ CHKDSK B:*.*\r
+\r
+This would report extents for all files in the current\r
+directory for drive B after doing a normal consistency check\r
+on drive B. Files which have many extents can be copied and\r
+renamed to restore them to a contiguous state, thus improving\r
+I/O performance to the files.\r
+\r
+ Previous versions of CHKDSK would simply free\r
+allocation units which were marked as used, but were not\r
+actually part of any file. CHKDSK 2.00 will recover these\r
+"orphan" allocation units if specified. If orphan allocation\r
+units are found, CHKDSK prompts for free or recover. Free\r
+just frees the orphans as previous versions did, recover will\r
+employ allocation chain analysis to create "orphan files" in\r
+the root directory of the disk. These files will have the\r
+form "%ORPHAN%.l$$" where l will take on some ASCII value\r
+greater than '@'. These files may then be inspected to see if\r
+valuable data was contained in them. If there is not enough\r
+room to make all of the "orphan" files, CHKDSK leaves the\r
+unrecovered chains in the FAT so that CHKDSK can be run again\r
+(once some entries in the ROOT have been deleted). NOTE:\r
+Making ORPHAN files is a SLOW process.\r
+\r
+ Verbose mode. CHKDSK 2.00 may be run with the V switch\r
+which causes a trace of the files and directories being\r
+processed to be printed as CHKDSK runs.\r
+\r
+\f\r
+FILTERS FOR MS-DOS 2.0\r
+\r
+ A filter is a utility that reads from standard input,\r
+modifies the information in some way, then writes the result\r
+to standard output. In this way the data is said to have been\r
+"filtered" by the program. Since different filters can be\r
+piped together in many different ways a few filters can take\r
+the place of a large number of specific purpose programs. The\r
+following describes the filters that are provided with MS-DOS\r
+2.0:\r
+\r
+CIPHER <key word>\r
+\r
+ Cipher reads a program from standard input, encrypts it\r
+using the key word provided by the user, then writes the\r
+result to standard output. To decrypt the file simply run\r
+CIPHER again using the same keyword. For example:\r
+\r
+A>CIPHER MYSTERY <NSA.CIA >SECRET.FIL\r
+\r
+ This command line will read file NSA.CIA, encrypt it using\r
+the key word "MYSTERY", then write the result to file\r
+SECRET.FIL To view the original file the following command\r
+line could be used:\r
+\r
+A>CIPHER MYSTERY <SECRET.FIL\r
+\r
+ This will read file SECRET.FIL, decrypt the file using the\r
+key word "MYSTERY", then write the result to standard output,\r
+which in this case is the console.\r
+\r
+FGREP\r
+\r
+ This filter takes as arguments a string and optionally a\r
+series of file names. It will send to standard output all\r
+lines from the files specified in the command line that\r
+contain the string.\r
+\r
+ If no files are specified FGREP will take the input from\r
+standard in. The format for the command line invocation of\r
+FGREP is:\r
+\r
+FGREP [<option>] <string> <filename>*\r
+\r
+ The options available are:\r
+\r
+ /v Will cause FGREP to output all lines NOT\r
+ containing the specified string.\r
+\r
+ /c Will cause FGREP to only print the count of\r
+ lines matched in each of the files.\r
+\r
+ /n Each line matched is preceded by its relative\r
+ line number in the file.\r
+\r
+ The string argument should be enclosed in double quotes.\r
+Two double quotes in succession are taken as a single double\r
+quote. So,\r
+\r
+A>FGREP "Fool""s Paradise" book1.txt book2.txt bible\r
+\r
+will output all lines from the book1.txt, book2.txt and bible\r
+(in that order that contain the string: Fool"s Paradise .\r
+And,\r
+\r
+A>dir b: | fgrep /v "DAT"\r
+\r
+will output all names of the files in disk b: which do not\r
+contain the string DAT .\r
+\r
+MORE\r
+\r
+ The filter MORE reads from standard input, sends one\r
+screen full of information to standard output and then pauses\r
+with message:\r
+\r
+-- More --\r
+\r
+ Pressing the RETURN key will cause another screen full of\r
+information to be written to standard output. This process\r
+continues until all the input data is read.\r
+\r
+SORT [/R] [/+n]\r
+\r
+ Sort reads from standard input, sorts the data, the writes\r
+the information to standard output. The sort is done using\r
+the ASCII collating sequence. There are switches which allow\r
+the user to select various options:\r
+\r
+ R - Reverse the sort, that is make "Z" come before "A"\r
+\r
+ +n - Sort starting with column "n" where n is some integer.\r
+ The default is start the comparisons with column 1,\r
+ this switch allows the user to start in any column.\r
+\r
+example:\r
+\r
+A>SORT /R <UNSORT.TXT >SORT.TXT\r
+\r
+This command line will read the file UNSORT.TXT, do a reverse\r
+sort, then write the output to file SORT.TXT\r
+\r
+A>DIR | SORT /+14\r
+\r
+ This command line will cause the output of the directory\r
+command to be piped to the sort filter, the sort filter will\r
+sort starting with column 14 (This is the column the file size\r
+starts), then send the output to the console. Thus a\r
+directory sorted by file size will be the result. To get real\r
+fancy:\r
+\r
+A>DIR | SORT /+14 | MORE\r
+\r
+will do the same thing except that MORE will give you a chance\r
+to read the directory before it scrolls off the screen.\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+;\r
+; xenix file calls for MSDOS\r
+;\r
+\r
+INCLUDE DOSSEG.ASM\r
+\r
+IFNDEF KANJI\r
+KANJI EQU 0 ;FALSE\r
+ENDIF\r
+\r
+CODE SEGMENT BYTE PUBLIC 'CODE'\r
+ ASSUME SS:DOSGROUP,CS:DOSGROUP\r
+\r
+.xlist\r
+.xcref\r
+INCLUDE DOSSYM.ASM\r
+INCLUDE DEVSYM.ASM\r
+.cref\r
+.list\r
+\r
+TITLE XENIX - IO system to mimic UNIX\r
+NAME XENIX\r
+\r
+ i_need NoSetDir,BYTE\r
+ i_need CURDRV,BYTE\r
+ i_need IOCALL,BYTE\r
+ i_need IOMED,BYTE\r
+ i_need IOSCNT,WORD\r
+ i_need IOXAD,DWORD\r
+ i_need DIRSTART,WORD\r
+ i_need ATTRIB,BYTE\r
+ i_need THISFCB,DWORD\r
+ i_need AuxStack,BYTE\r
+ i_need Creating,BYTE\r
+ i_need ThisDRV,BYTE\r
+ i_need NAME1,BYTE\r
+ i_need LastEnt,WORD\r
+ i_need ThisDPB,DWORD\r
+ i_need EntLast,WORD\r
+ i_need CurrentPDB,WORD\r
+ i_need sft_addr,DWORD ; pointer to head of table\r
+ i_need CURBUF,DWORD ; pointer to current buffer\r
+ i_need DMAADD,DWORD ; pointer to current dma address\r
+\r
+BREAK <Local data>\r
+\r
+CODE ENDS\r
+DATA SEGMENT BYTE PUBLIC 'DATA'\r
+\r
+open_name DW ?\r
+ DW ?\r
+open_access DB ?\r
+open_jfn DW ? ; accessed as DD\r
+open_jfn_b DW ? ; accessed as DD with above\r
+open_sfn DW ?\r
+open_sfoff DW ? ; accessed as DD\r
+open_sfn_b DW ? ; accessed as DD with above\r
+open_devid DB ?\r
+Cr_read_only DB ?\r
+rename_source DD ?\r
+rename_dest DD ?\r
+\r
+DATA ENDS\r
+CODE SEGMENT BYTE PUBLIC 'CODE'\r
+\r
+BREAK <Validate_path - check to see if there are meta characters in path>\r
+\r
+;\r
+; Input: DS:DX is an ASCIZ path\r
+; Output: Carry set if meta-characters present or path malformed and\r
+; Zero is set if the only problem is that meta-characters\r
+; are present in the last element of the path\r
+procedure Validate_path,near\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ PUSH AX\r
+ PUSH CX\r
+ PUSH SI\r
+ MOV SI,DX\r
+ MOV CX,0FFH ;No path seps yet\r
+ MOV AX,[SI] ; Get first two bytes\r
+ OR AL,AL\r
+ JZ validate_malformed ; NUL path\r
+ CMP AH,':'\r
+ JNZ validate_loop ; OK so far\r
+ CMP BYTE PTR [SI+2],0\r
+ JZ validate_malformed ; NUL path (just d:)\r
+validate_loop:\r
+ LODSB\r
+validate_loop1:\r
+\r
+ IF KANJI\r
+ invoke TESTKANJ\r
+ JZ NOTKANJ6\r
+ INC SI\r
+ JMP validate_loop\r
+\r
+NOTKANJ6:\r
+ ENDIF\r
+\r
+ OR AL,AL\r
+ JZ validate_end\r
+ CMP AL,"?"\r
+ JZ validate_error\r
+ CMP AL,"*"\r
+ JZ validate_error\r
+ invoke PathChrCmp\r
+ JNZ validate_loop\r
+ JCXZ validate_malformed ;If path sep, cannot have meta yet\r
+ LODSB ;Look ahead one char\r
+ OR AL,AL\r
+ JZ validate_checktslsh ;Trailing path sep\r
+ invoke PathChrCmp\r
+ JNZ validate_loop1 ;Double path sep?\r
+validate_malformed:\r
+ INC CX\r
+ OR CX,CX ;Reset zero\r
+ JMP SHORT validate_set_carry\r
+\r
+validate_error:\r
+ XOR CX,CX ;Flag metas found\r
+ JMP validate_loop\r
+\r
+validate_checktslsh:\r
+;A bizarre case, "/" is OK, "d:/" is OK, anything else is an error\r
+ SUB SI,DX\r
+ CMP SI,2\r
+ JZ validate_end ;Two chars, the '/' and the NUL\r
+ CMP SI,4\r
+ JNZ validate_malformed ;Four chars, "D:/<NUL>"\r
+ MOV SI,DX\r
+ CMP BYTE PTR [SI+1],':'\r
+ JNZ validate_malformed ;Second char must be a ':'\r
+\r
+validate_end:\r
+ OR CX,CX ;Clears carry\r
+ JNZ validate_ok ;No metas found, leave carry clear\r
+validate_set_carry:\r
+ STC\r
+validate_ok:\r
+ POP SI\r
+ POP CX\r
+ POP AX\r
+ return\r
+validate_path ENDP\r
+\r
+BREAK <Access_path - determine if file found>\r
+\r
+;\r
+; Input: DS:DX point to a path\r
+; Output: Carry reset - outputs of GetPath\r
+; carry set - AL has error code\r
+;\r
+ procedure Access_path,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ CALL Validate_path\r
+ JC access_no_path\r
+ MOV SI,DX\r
+ invoke GetPath\r
+ retnc\r
+ MOV AL,error_file_not_found\r
+ OR CL,CL\r
+ JNZ access_ret\r
+access_no_path:\r
+ MOV AL,error_path_not_found\r
+access_ret:\r
+ STC\r
+ return\r
+access_path ENDP\r
+\r
+BREAK <Find_free_jfn - return a free jfn in users PDB>\r
+;\r
+; system file table data\r
+;\r
+\r
+;\r
+; The system file table is two linear tables. The first table is the\r
+; DOS initialization table containing a default number of FCBs. The\r
+; first word in the table is a link to the second table, which\r
+; SYSINIT sets up, the second word is the number of FCBs in the table.\r
+;\r
+\r
+;\r
+; find_free_jfn\r
+; input: none\r
+; output: JNC <found>\r
+; ES:DI is pointer to free JFN\r
+; JC <no free jfns>\r
+; ES,DI indeterminate\r
+;\r
+ procedure Find_free_jfn,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ PUSH AX\r
+ PUSH CX\r
+ MOV AL,0FFh\r
+ MOV ES,[CurrentPDB]\r
+ MOV DI,PDB_JFN_Table\r
+ MOV CX,FilPerProc\r
+ REPNE SCASB\r
+ STC\r
+ JNZ Find_jfn_ret\r
+ DEC DI\r
+ CLC\r
+Find_jfn_ret:\r
+ POP CX\r
+ POP AX\r
+ return\r
+Find_free_jfn ENDP\r
+\r
+BREAK <find_free_sfn - return a free sfn and sf pointer>\r
+;\r
+; find_free_sfn\r
+; input: none\r
+; output: JNC <found>\r
+; ES:DI is free sf entry\r
+; SI is sfn\r
+; JC <not found>\r
+; ES,DI,SI indeterminate\r
+;\r
+; sft_addr --> (link) count (fcbs)\r
+; links = -1 means end of list\r
+;\r
+ procedure Find_free_sfn,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ PUSH BX\r
+ PUSH CX\r
+ LES BX,sft_addr ; head of chain of tables\r
+ XOR SI,SI ; count of sfn\r
+\r
+ ; ES:BX points to table... search through table\r
+Find_sfn_in_table:\r
+ CMP BX,-1 ; end of chain\r
+ JZ Find_no_free_sfns\r
+ MOV DI,sft_table ; offset to sf entry\r
+ MOV CX,ES:[BX].sft_count ; count of fcbs in table\r
+\r
+Find_sfn:\r
+ CMP ES:BYTE PTR [BX+DI].sf_ref_count,0h\r
+ JZ Find_got_sfn ; ref count is 0 -> free entry\r
+ ADD DI,SIZE sf_entry ; look to next entry\r
+ INC SI ; bump sfn\r
+ LOOP Find_sfn\r
+ LES BX,ES:[BX].sft_link ; link to next\r
+ JMP SHORT Find_sfn_in_table ; look for more\r
+\r
+Find_no_free_sfns:\r
+ STC\r
+ JMP SHORT find_ret\r
+Find_got_sfn:\r
+ ADD DI,BX\r
+ CLC\r
+Find_ret:\r
+ POP CX\r
+ POP BX\r
+ RET\r
+Find_free_sfn ENDP\r
+\r
+BREAK <$Open - open a file handle>\r
+;\r
+; Assembler usage:\r
+; LDS DX, Name\r
+; MOV AH, Open\r
+; MOV AL, access\r
+; INT int_command\r
+;\r
+; ACCESS Function\r
+; ------ --------\r
+; open_for_read file is opened for reading\r
+; open_for_write file is opened for writing\r
+; open_for_both file is opened for both reading and writing.\r
+;\r
+; Error returns:\r
+; AX = error_invalid_access\r
+; = error_file_not_found\r
+; = error_access_denied\r
+; = error_too_many_open_files\r
+;\r
+\r
+ procedure $Open,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ MOV [Cr_read_only],0\r
+Open_create:\r
+ CMP AL,open_for_both ; validate access\r
+ JBE OPEN_get_jfn\r
+ error error_invalid_access\r
+\r
+OPEN_get_jfn:\r
+ MOV [open_name+2],DS\r
+ context DS\r
+ MOV open_name,DX\r
+ MOV open_access,AL\r
+\r
+ invoke Find_free_jfn ; scan through user's area\r
+ ; ES:DI is the jfn entry\r
+ JNC OPEN_get_sfn\r
+OPEN_too_many:\r
+ error error_too_many_open_files\r
+\r
+OPEN_get_sfn:\r
+ MOV OPEN_jfn_b,ES\r
+ MOV OPEN_jfn,DI\r
+ invoke Find_free_sfn ; get a free sft entry\r
+ ; ES:DI is the SFT entry that's free, SI is the sfn\r
+ JC OPEN_too_many\r
+\r
+OPEN_file:\r
+ MOV OPEN_sfn,SI\r
+ MOV OPEN_sfoff,DI\r
+ MOV OPEN_sfn_b,ES\r
+;\r
+; open the file\r
+;\r
+ PUSH DS\r
+ LDS DX,DWORD PTR [open_name]\r
+ ASSUME DS:NOTHING\r
+ CALL access_path\r
+ POP DS\r
+ ASSUME DS:DOSGROUP\r
+ JNC open_check_access ; carry set -> error\r
+ transfer SYS_RET_ERR\r
+\r
+open_check_access:\r
+ MOV ES,WORD PTR [CURBUF+2] ; get buffer location\r
+ MOV open_devid,AH\r
+ TEST AH,080h\r
+ JNZ open_set_FCB_dev ;is a device\r
+ MOV AL,ES:[BX].dir_attr\r
+ TEST AL,attr_directory ; can't open directories\r
+ JZ open_try_volid\r
+\r
+open_bad_access:\r
+ error error_access_denied\r
+\r
+open_try_volid:\r
+ TEST AL,attr_volume_id ; can't open volume ids\r
+ JNZ open_bad_access\r
+ TEST AL,attr_read_only ; check write on read only\r
+ JZ open_set_FCB\r
+ CMP [Cr_read_only],0\r
+ JNZ open_set_FCB ; ok if creating read only file\r
+ CMP open_access, open_for_read\r
+ JNZ open_bad_access ; writing on a read only file\r
+ JMP SHORT open_set_FCB\r
+\r
+open_set_FCB_dev:\r
+ PUSH SS\r
+ POP ES ;Device opens are DOSGROUP relative\r
+\r
+open_set_FCB:\r
+ MOV CX,11 ; copy name into FCB...\r
+ PUSH SI ; ES:BX is source, must change\r
+ MOV SI,BX ; ES:SI is source\r
+ MOV DI,open_sfoff ; ??:DI is dest\r
+ PUSH DS\r
+ PUSH ES\r
+ MOV ES,open_sfn_b ; ES:DI is dest\r
+ POP DS ; DS:SI is source\r
+ ASSUME DS:NOTHING\r
+;\r
+; need to save attribute for the close operation\r
+;\r
+ MOV AH,DS:[BX.dir_attr] ; save attribute for close\r
+ MOV ES:[DI.sf_attr],AH\r
+\r
+ ADD DI,sf_fcb+1 ; point to name\r
+\r
+ IF KANJI\r
+ MOVSB\r
+ CMP BYTE PTR ES:[DI-1],5\r
+ JNZ NOTKTRAN\r
+ MOV BYTE PTR ES:[DI-1],0E5H\r
+NOTKTRAN:\r
+ DEC CX\r
+ ENDIF\r
+\r
+ REP MOVSB ; move in parsed name\r
+ POP DS\r
+ ASSUME DS:DOSGROUP\r
+ POP SI\r
+ LES DI,DWORD PTR [open_sfoff]\r
+ ADD DI,sf_fcb ; offset on fcb in sf entry\r
+ MOV AH,open_devid\r
+ invoke DOOPEN ; let open code fill in blanks\r
+ context DS\r
+ LES DI,DWORD PTR [open_sfoff]\r
+ INC ES:[DI].sf_ref_count ; reference this FCB\r
+ MOV AL,open_access ; stash the access\r
+ MOV ES:BYTE PTR [DI].sf_mode,AL\r
+ XOR AX,AX\r
+ MOV ES:WORD PTR [DI.sf_FCB.fcb_RR],AX ; beginning of file\r
+ MOV ES:WORD PTR [DI.sf_FCB.fcb_RR+2],AX\r
+ INC AX\r
+ MOV ES:WORD PTR [DI.sf_FCB.fcb_RECSIZ],AX ; byte io only\r
+ LES DI,DWORD PTR [open_jfn]\r
+ MOV AX,open_sfn\r
+ MOV ES:BYTE PTR [DI],AL ; stash sfn in PDB\r
+ SUB DI,PDB_jfn_table ; get jfn for user\r
+ MOV AX,DI\r
+ transfer SYS_RET_OK\r
+$Open ENDP\r
+\r
+\r
+BREAK <$UNLINK - delete a file entry>\r
+;\r
+; Assembler usage:\r
+; LDS DX, name\r
+; MOV AH, Unlink\r
+; INT 21h\r
+;\r
+; Error returns:\r
+; AX = error_file_not_found\r
+; = error_access_denied\r
+;\r
+ procedure $UNLINK,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ CALL access_path\r
+ JNC unlink_check_attr\r
+ transfer SYS_RET_ERR\r
+\r
+unlink_check_attr:\r
+ JZ unlink_dir\r
+ LDS DI,DWORD PTR [CURBUF] ; get directory entry\r
+ TEST DS:[BX.dir_attr],attr_read_only\r
+ JZ unlink_doit\r
+\r
+unlink_dir:\r
+ error error_access_denied\r
+\r
+unlink_doit:\r
+ MOV BYTE PTR DS:[BX.dir_name],0E5h ; delete dir entry\r
+ MOV BYTE PTR DS:[DI.BUFDIRTY],1 ; dirty the buffer\r
+ LODSW\r
+ MOV BX,AX\r
+ AND BX,0FFFh\r
+ context DS\r
+ JZ unlink_flush\r
+ invoke RELEASE\r
+unlink_flush:\r
+ MOV AL,BYTE PTR ES:[BP.DPB_drive]\r
+ invoke FLUSHBUF\r
+ transfer SYS_RET_OK\r
+$UNLINK ENDP\r
+\r
+BREAK <$CREAT - creat a new file and open him for input>\r
+;\r
+; Assembler usage:\r
+; LDS DX, name\r
+; MOV AH, Creat\r
+; MOV CX, access\r
+; INT 21h\r
+; ; AX now has the handle\r
+;\r
+; Error returns:\r
+; AX = error_access_denied\r
+; = error_path_not_found\r
+; = error_too_many_open_files\r
+;\r
+\r
+\r
+ procedure $CREAT,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ CALL Validate_path\r
+ JNC unlink_do_make\r
+ error error_path_not_found\r
+unlink_do_make:\r
+ PUSH DX\r
+ PUSH DS\r
+ context DS\r
+ MOV WORD PTR [CREATING],0E5FFh\r
+ MOV WORD PTR [ThisFCB+2],SS\r
+ MOV WORD PTR [ThisFCB],OFFSET DOSGROUP:AUXSTACK-40\r
+ MOV SI,DX\r
+ MOV AL,CL\r
+ AND CL,attr_read_only\r
+ MOV [Cr_read_only],CL\r
+ POP DS\r
+ PUSH DS\r
+ASSUME DS:NOTHING\r
+ invoke MakeNode\r
+ POP DS\r
+ POP DX\r
+ OR AL,AL\r
+ JZ creat_open\r
+ CMP AL,3\r
+ JZ creat_open\r
+creat_no_access:\r
+ error error_access_denied\r
+creat_open:\r
+ MOV AL,open_for_both\r
+ JMP Open_create\r
+\r
+$CREAT ENDP\r
+\r
+\r
+BREAK <$DUP - duplicate a jfn>\r
+;\r
+; Assembler usage:\r
+; MOV BX, fh\r
+; MOV AH, Dup\r
+; INT int_command\r
+; AX has the returned handle\r
+; Errors:\r
+; AX = dup_invalid_handle\r
+; = dup_too_many_open_files\r
+ procedure $DUP,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ context DS\r
+ invoke Find_free_jfn\r
+ JC dup_no_free_handles\r
+\r
+dup_force:\r
+ PUSH ES\r
+ PUSH DI\r
+ invoke Get_sf_from_jfn\r
+ POP SI\r
+ POP DS\r
+ JC dup_bad_handle\r
+ ; ES:DI is pointer to sf entry\r
+ ; DS:DI is pointer to jfn\r
+ INC ES:[DI].sf_ref_count ; another jfn reference...\r
+ MOV AL,[BX].PDB_JFN_table ; get old sfn\r
+ MOV [SI],AL ; store in new place\r
+ SUB SI,PDB_JFN_table ; get jfn\r
+ MOV AX,SI\r
+ transfer SYS_RET_OK\r
+\r
+dup_no_free_handles:\r
+ error error_too_many_open_files\r
+\r
+dup_bad_handle:\r
+ error error_invalid_handle\r
+$DUP ENDP\r
+\r
+BREAK <$DUP2 - force a dup on a particular jfn>\r
+;\r
+; Assembler usage:\r
+; MOV BX, fh\r
+; MOV CX, newfh\r
+; MOV AH, Dup2\r
+; INT int_command\r
+; Error returns:\r
+; AX = error_invalid_handle\r
+;\r
+ procedure $DUP2,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ XCHG BX,CX ; BX < destination jfn\r
+ PUSH BX\r
+ PUSH CX\r
+ invoke $CLOSE ; close BX\r
+ context DS\r
+ POP CX\r
+ POP BX\r
+ invoke Get_jfn_pointer\r
+ XCHG BX,CX\r
+ JNC dup_force\r
+lseek_bad_handle:\r
+ error error_invalid_handle\r
+$DUP2 ENDP\r
+\r
+\r
+BREAK <$CHMOD - change file attributes>\r
+;\r
+; Assembler usage:\r
+; LDS DX, name\r
+; MOV CX, attributes\r
+; INT 21h\r
+; Error returns:\r
+; AX = error_path_not_found\r
+; AX = error_access_denied\r
+;\r
+ procedure $CHMOD,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ CMP AL,1\r
+ JBE chmod_save\r
+ error error_invalid_function\r
+chmod_save:\r
+ JB chmod_try_file\r
+ MOV BX,CX\r
+ AND BX,NOT attr_changeable\r
+ JZ chmod_try_file\r
+\r
+chmod_bad:\r
+ error error_access_denied\r
+\r
+chmod_bye:\r
+ transfer SYS_RET_ERR\r
+chmod_try_file:\r
+ PUSH CX\r
+ PUSH AX\r
+ CALL access_path\r
+ POP DX\r
+ POP CX\r
+ JC chmod_bye\r
+ LES DI,[CURBUF]\r
+ context DS\r
+ OR DL,DL\r
+ JZ chmod_fetch\r
+ AND BYTE PTR ES:[BX].dir_attr,NOT attr_changeable\r
+ OR BYTE PTR ES:[BX].dir_attr,CL\r
+ MOV ES:[DI.BUFDIRTY],1\r
+ MOV AL,-1\r
+ invoke FlushBuf\r
+ transfer SYS_RET_OK\r
+chmod_fetch:\r
+ XOR CX,CX\r
+ MOV CL,BYTE PTR ES:[BX].dir_attr\r
+ invoke Get_user_stack\r
+ MOV [SI.user_CX],CX\r
+ transfer SYS_RET_OK\r
+$chmod ENDP\r
+\r
+BREAK <$CURRENT_DIR - dump the current directory into user space>\r
+;\r
+; Assembler usage:\r
+; LDS SI,area\r
+; MOV DL,drive\r
+; INT 21h\r
+; ; DS:SI is a pointer to 64 byte area that contains drive\r
+; ; current directory.\r
+; Error returns:\r
+; AX = error_invalid_drive\r
+;\r
+procedure $CURRENT_DIR,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ PUSH DS\r
+ PUSH BX\r
+ PUSH SI\r
+ invoke $get_DPB\r
+;\r
+; ES:BP points to DPB. DS:SI points to user stack, unless error\r
+;\r
+ CMP AL,0FFh\r
+ JNZ current_copy\r
+ POP AX ; Clean Stack\r
+ POP AX\r
+ POP AX\r
+ error error_invalid_drive\r
+\r
+current_copy:\r
+ POP DI ; where to move to\r
+ POP [SI.user_BX] ; restore old BX\r
+ POP BX\r
+ MOV [SI.user_DS],BX ; and restore old DS\r
+;\r
+; ES:BP is pointer to DPB. BX:DI is pointer to destination\r
+;\r
+ CMP ES:[BP.dpb_current_dir],-1\r
+ JNZ current_ok\r
+ PUSH BX\r
+ PUSH DI\r
+ MOV [ATTRIB],attr_all\r
+ invoke GETCURRDIR\r
+ POP DI\r
+ POP BX\r
+current_ok:\r
+ MOV SI,BP ; ES:SI is source\r
+ PUSH ES\r
+ POP DS ; DS:SI is source\r
+ MOV ES,BX ; ES:DI is destination\r
+ CMP [SI.dpb_current_dir],0\r
+ JNZ current_move\r
+ MOV BYTE PTR [SI.dpb_dir_text],0\r
+\r
+current_move:\r
+ ADD SI,dpb_dir_text\r
+ MOV CX,DIRSTRLEN\r
+current_loop:\r
+ LODSB\r
+ STOSB\r
+ OR AL,AL\r
+ LOOPNZ current_loop\r
+ transfer SYS_RET_OK\r
+$CURRENT_DIR ENDP\r
+\r
+\r
+BREAK <$RENAME - move directory entries around>\r
+;\r
+; Assembler usage:\r
+; LDS DX, source\r
+; LES DI, dest\r
+; MOV AH, Rename\r
+; INT 21h\r
+;\r
+; Error returns:\r
+; AX = error_file_not_found\r
+; = error_not_same_device\r
+; = error_access_denied\r
+procedure $RENAME,near\r
+\r
+ MOV WORD PTR [rename_source],DX\r
+ MOV WORD PTR [rename_source+2],DS\r
+ MOV WORD PTR [rename_dest],DI\r
+ MOV WORD PTR [rename_dest+2],ES\r
+ CALL Access_path\r
+ JNC rename_check_dir\r
+ transfer SYS_RET_ERR\r
+\r
+rename_check_dir:\r
+ JZ rename_no_access\r
+ MOV DS,WORD PTR [CurBuf+2]\r
+ PUSH [BX.dir_date]\r
+ PUSH [BX.dir_first]\r
+ PUSH [BX.dir_size_h]\r
+ PUSH [BX.dir_size_l]\r
+ PUSH [BX.dir_time]\r
+ PUSH WORD PTR [BX.dir_attr]\r
+ PUSH WORD PTR [ThisDrv]\r
+ LDS SI,[rename_dest]\r
+ invoke GetPath\r
+ POP AX\r
+ JC rename_check_drives\r
+rename_bad_access:\r
+ ADD SP,12\r
+rename_no_access:\r
+ error error_access_denied\r
+rename_check_drives:\r
+ CMP AL,[ThisDrv]\r
+ JZ rename_create\r
+ ADD SP,12\r
+ error error_not_same_device\r
+rename_create:\r
+ LDS SI,[rename_dest]\r
+ POP AX\r
+ PUSH AX\r
+ MOV WORD PTR [Creating],0E5FFh\r
+ MOV WORD PTR [ThisFCB+2],SS\r
+ MOV WORD PTR [ThisFCB],OFFSET DOSGROUP:AUXStack-40\r
+ invoke MakeNode\r
+ JC rename_bad_access\r
+ LDS SI,[CurBuf]\r
+ POP AX\r
+ MOV [BX.dir_attr],AL\r
+ POP [BX.dir_time]\r
+ POP [BX.dir_size_l]\r
+ POP [BX.dir_size_h]\r
+ POP [BX.dir_first]\r
+ POP [BX.dir_date]\r
+ MOV [SI.BUFDIRTY],1\r
+ LDS SI,[rename_source]\r
+ invoke GetPath\r
+ LDS SI,[CurBuf]\r
+ MOV BYTE PTR [BX],0E5h\r
+ MOV [SI.BUFDIRTY],1\r
+ context DS\r
+ MOV AL,0FFh\r
+ invoke FlushBuf\r
+ transfer SYS_RET_OK\r
+\r
+$RENAME ENDP\r
+\r
+BREAK <$FIND_FIRST - find first matching xenix filename>\r
+;\r
+; Assembler usage:\r
+; MOV AH, FindFirst\r
+; LDS DX, name\r
+; MOV CX, attr\r
+; INT 21h\r
+; ; DMA address has datablock\r
+;\r
+; Error Returns:\r
+; AX = error_file_not_found\r
+; = error_no_more_files\r
+;\r
+procedure $FIND_FIRST,near\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ CALL Validate_path\r
+ JNC find_get\r
+ JZ find_get\r
+ error error_file_not_found\r
+find_get:\r
+ MOV SI,DX\r
+ PUSH CX\r
+ INC BYTE PTR [NoSetDir] ; if we find a dir, don't change to it\r
+ MOV WORD PTR [Creating],0E500h\r
+ CALL GetPath\r
+ POP CX\r
+ MOV [Attrib],CL\r
+find_check:\r
+ JNC find_check_attr\r
+find_no_more:\r
+ error error_no_more_files\r
+find_check_attr:\r
+ MOV DS,WORD PTR [CURBUF+2]\r
+ MOV CH,[BX.dir_attr]\r
+ invoke MatchAttributes\r
+ JZ found_it\r
+ PUSH [LastEnt]\r
+ MOV BX,[DirStart]\r
+ JMP find_it_next\r
+found_it:\r
+ LES DI,[DMAADD]\r
+ MOV AL,[Attrib]\r
+ STOSB ; find_buf 0 = attribute in search\r
+ MOV AL,[ThisDrv]\r
+ STOSB ; find_buf 1 = drive\r
+ MOV CX,11\r
+ PUSH BX\r
+ MOV SI,OFFSET DOSGROUP:NAME1; find_buf 2 = formatted name\r
+ PUSH DS\r
+ PUSH SS\r
+ POP DS\r
+\r
+ IF KANJI\r
+ MOVSB\r
+ CMP BYTE PTR ES:[DI-1],5\r
+ JNZ NOTKANJB\r
+ MOV BYTE PTR ES:[DI-1],0E5H\r
+NOTKANJB:\r
+ DEC CX\r
+ ENDIF\r
+\r
+ REP MOVSB\r
+ POP DS\r
+ MOV AX,[LastEnt]\r
+ STOSW ; find_buf 13 = LastEnt\r
+ MOV AX,WORD PTR [ThisDPB]\r
+ STOSW ; find_buf 15 = ThisDPB\r
+ MOV AX,WORD PTR [ThisDPB+2]\r
+ STOSW\r
+ MOV AX,[DirStart]\r
+ STOSW ; find_buf 19 = DirStart\r
+ MOV AL,[BX].dir_attr\r
+ STOSB ; find_buf 21 = attribute found\r
+ MOV AX,[BX].dir_time\r
+ STOSW ; find_buf 22 = time\r
+ MOV AX,[BX].dir_date\r
+ STOSW ; find_buf 24 = date\r
+ MOV AX,[BX].dir_size_l\r
+ STOSW ; find_buf 26 = low(size)\r
+ MOV AX,[BX].dir_size_h\r
+ STOSW ; find_buf 28 = high(size)\r
+ POP SI\r
+ MOV CX,8 ; find_buf 30 = packed name\r
+find_loop_name:\r
+ LODSB\r
+ STOSB\r
+ CMP AL," "\r
+ LOOPNZ find_loop_name\r
+ JNZ find_check_dot\r
+ DEC DI\r
+find_check_dot:\r
+ ADD SI,CX\r
+ CMP BYTE PTR [SI]," "\r
+ JZ find_done\r
+ MOV AL,"."\r
+ STOSB\r
+ MOV CX,3\r
+find_loop_ext:\r
+ LODSB\r
+ STOSB\r
+ CMP AL," "\r
+ LOOPNZ find_loop_ext\r
+ JNZ find_done\r
+ DEC DI\r
+find_done:\r
+ XOR AL,AL\r
+ STOSB\r
+ transfer SYS_RET_OK\r
+$FIND_FIRST ENDP\r
+\r
+BREAK <$FIND_NEXT - scan for match in directory>\r
+;\r
+; Assembler usage:\r
+; ; dma points at area returned by find_first\r
+; MOV AH, findnext\r
+; INT 21h\r
+; ; next entry is at dma\r
+;\r
+; Error Returns:\r
+; AX = error_no_more_files\r
+;\r
+procedure $FIND_NEXT,near\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ LDS SI,[DMAADD]\r
+ MOV DX,SI\r
+ INC DX\r
+ PUSH SI\r
+ invoke MOVNAMENOSET\r
+ POP SI\r
+ JNC find_load\r
+findnext_no_more:\r
+ error error_no_more_files\r
+find_load:\r
+ MOV AX,[SI.find_buf_LastEnt]\r
+ LES BP,[SI.find_buf_ThisDPB]\r
+ OR AX,AX\r
+ JS findnext_no_more\r
+ MOV BX,[SI.find_buf_DirStart]\r
+ MOV DL,[SI.find_buf_sattr]\r
+ MOV [Attrib],DL\r
+ PUSH AX\r
+ MOV WORD PTR [ThisDPB],BP\r
+ MOV WORD PTR [ThisDPB+2],ES\r
+find_it_next:\r
+ invoke SetDirSrch\r
+ ASSUME DS:DOSGROUP\r
+ POP AX\r
+ MOV [ENTLAST],-1\r
+ invoke GetEnt\r
+ invoke NextEnt\r
+ JMP find_check\r
+$find_next ENDP\r
+\r
+do_ext\r
+\r
+CODE ENDS\r
+ END\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
--- /dev/null
+;\r
+; xenix file calls for MSDOS\r
+;\r
+\r
+INCLUDE DOSSEG.ASM\r
+\r
+IFNDEF KANJI\r
+KANJI EQU 0 ;FALSE\r
+ENDIF\r
+\r
+CODE SEGMENT BYTE PUBLIC 'CODE'\r
+ ASSUME SS:DOSGROUP,CS:DOSGROUP\r
+\r
+.xlist\r
+.xcref\r
+INCLUDE DOSSYM.ASM\r
+INCLUDE DEVSYM.ASM\r
+.cref\r
+.list\r
+\r
+TITLE XENIX - IO system to mimic UNIX\r
+NAME XENIX\r
+\r
+ i_need NoSetDir,BYTE\r
+ i_need CURDRV,BYTE\r
+ i_need IOCALL,BYTE\r
+ i_need IOMED,BYTE\r
+ i_need IOSCNT,WORD\r
+ i_need IOXAD,DWORD\r
+ i_need DIRSTART,WORD\r
+ i_need ATTRIB,BYTE\r
+ i_need THISFCB,DWORD\r
+ i_need AuxStack,BYTE\r
+ i_need Creating,BYTE\r
+ i_need ThisDRV,BYTE\r
+ i_need NAME1,BYTE\r
+ i_need LastEnt,WORD\r
+ i_need ThisDPB,DWORD\r
+ i_need EntLast,WORD\r
+ i_need CurrentPDB,WORD\r
+ i_need sft_addr,DWORD ; pointer to head of table\r
+ i_need CURBUF,DWORD ; pointer to current buffer\r
+ i_need DMAADD,DWORD ; pointer to current dma address\r
+\r
+BREAK <Local data>\r
+\r
+CODE ENDS\r
+DATA SEGMENT BYTE PUBLIC 'DATA'\r
+\r
+\r
+PushSave DW ?\r
+PushES DW ?\r
+PushBX DW ?\r
+\r
+xenix_count DW ?\r
+\r
+DATA ENDS\r
+CODE SEGMENT BYTE PUBLIC 'CODE'\r
+\r
+\r
+BREAK <get_sf_from_sfn - translate a sfn into sf pointer>\r
+;\r
+; get_sf_from_sfn\r
+; input: AX has sfn (0 based)\r
+; DS is DOSGROUP\r
+; output: JNC <found>\r
+; ES:DI is sf entry\r
+; JC <error>\r
+; ES,DI indeterminate\r
+;\r
+ procedure get_sf_from_sfn,NEAR\r
+ ASSUME DS:DOSGROUP,ES:NOTHING\r
+ PUSH AX ; we trash AX in process\r
+ LES DI,[sft_addr]\r
+\r
+get_sfn_loop:\r
+ CMP DI,-1 ; end of chain of tables?\r
+ JZ get_sf_invalid ; I guess so...\r
+ SUB AX,ES:[DI].sft_count ; chop number of entries in this table\r
+ JL get_sf_gotten ; sfn is in this table\r
+ LES DI,ES:[DI].sft_link ; step to next table\r
+ JMP get_sfn_loop\r
+\r
+get_sf_gotten:\r
+ ADD AX,ES:[DI].sft_count ; reset to index in this table\r
+ PUSH BX\r
+ MOV BX,SIZE sf_entry\r
+ MUL BL ; number of bytes offset into table\r
+ POP BX\r
+ ADD AX,sft_table ; offset into sf table structure\r
+ ADD DI,AX ; offset into memory\r
+ CLC\r
+ JMP SHORT get_sf_ret\r
+\r
+get_sf_jfn_invalid:\r
+get_sf_invalid:\r
+ STC\r
+\r
+get_sf_jfn_ret:\r
+get_sf_ret:\r
+ POP AX ; remember him?\r
+ RET\r
+get_sf_from_sfn ENDP\r
+\r
+BREAK <get_sf_from_jfn - translate a jfn into sf pointer>\r
+;\r
+; get_sf_from_jfn\r
+; input: BX is jfn 0 based\r
+; DS is DOSGROUP\r
+; output: JNC <found>\r
+; ES:DI is sf entry\r
+; JC <error>\r
+; ES,DI is indeterminate\r
+;\r
+ procedure get_sf_from_jfn,NEAR\r
+ ASSUME DS:DOSGROUP,ES:NOTHING\r
+ PUSH AX ; save him\r
+ invoke get_jfn_pointer\r
+ JC get_sf_jfn_invalid\r
+ MOV AL,ES:[DI] ; get sfn\r
+ CMP AL,0FFh ; is it free?\r
+ JZ get_sf_jfn_invalid ; yep... error\r
+ XOR AH,AH\r
+ invoke get_sf_from_sfn ; check this sfn out...\r
+ JMP SHORT get_sf_jfn_ret ; condition codes are properly set\r
+\r
+get_sf_from_jfn ENDP\r
+\r
+BREAK <get_jfn_pointer - map a jfn into a pointer to jfn>\r
+;\r
+; get_jfn_pointer\r
+; input: BX is jfn\r
+; DS is DOSGROUP\r
+; output: JNC <found>\r
+; ES:DI is pointer to jfn\r
+; JC <bad jfn>\r
+;\r
+ procedure Get_jfn_pointer,NEAR\r
+ ASSUME DS:DOSGROUP,ES:NOTHING\r
+ CMP BX,FilPerProc\r
+ JAE get_jfn_bad\r
+ MOV ES,[CurrentPDB]\r
+ MOV DI,BX\r
+ ADD DI,PDB_JFN_Table\r
+ CLC\r
+ RET\r
+\r
+get_jfn_bad:\r
+ STC\r
+ RET\r
+get_jfn_pointer ENDP\r
+\r
+\r
+BREAK <$Close - release a handle>\r
+;\r
+; Assembler usage:\r
+; MOV BX, handle\r
+; MOV AH, Close\r
+; INT int_command\r
+;\r
+; Error return:\r
+; AX = error_invalid_handle\r
+;\r
+ procedure $Close,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+ context DS\r
+\r
+ invoke get_jfn_pointer ; get jfn loc\r
+ JNC close_jfn\r
+close_bad_handle:\r
+ error error_invalid_handle\r
+\r
+close_jfn:\r
+ MOV AL,BYTE PTR ES:[DI]\r
+ CMP AL,0FFh\r
+ JE close_bad_handle\r
+ MOV BYTE PTR ES:[DI],0FFh;\r
+ XOR AH,AH\r
+ invoke get_sf_from_sfn\r
+ JC close_bad_handle\r
+ PUSH ES\r
+ POP DS\r
+ ASSUME DS:NOTHING\r
+ DEC [DI].sf_ref_count ; no more reference\r
+ LEA DX,[DI].sf_fcb\r
+;\r
+; need to restuff Attrib if we are closing a protected file\r
+;\r
+ TEST [DI.sf_fcb.fcb_DevID],devid_file_clean+devid_device\r
+ JNZ close_ok\r
+ PUSH WORD PTR [DI].sf_attr\r
+ invoke MOVNAMENOSET\r
+ POP BX\r
+ MOV [Attrib],BL\r
+ invoke FCB_CLOSE_INNER\r
+ CMP AL,0FFh ; file not found error?\r
+ JNZ close_ok\r
+ error error_file_not_found\r
+close_ok:\r
+ transfer SYS_RET_OK\r
+\r
+$Close ENDP\r
+\r
+\r
+BREAK <PushDMA, PopDMA, ptr_normalize - set up local dma and save old>\r
+; PushDMA\r
+; input: DS:DX is DMA\r
+; output: DS:DX is normalized , ES:BX destroyed\r
+; [DMAADD] is now set up to DS:DX\r
+; old DMA is pushed\r
+\r
+ procedure PushDMA,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+ MOV PushES,ES\r
+ MOV PushBX,BX\r
+ POP PushSave\r
+ LES BX,DWORD PTR [DMAADD] ; get old dma\r
+ PUSH ES\r
+ PUSH BX\r
+ PUSH PushSave\r
+ invoke ptr_normalize ; get new dma\r
+ MOV WORD PTR [DMAADD],DX ; save IT!\r
+ MOV WORD PTR [DMAADD+2],DS\r
+ MOV ES,PushES\r
+ MOV BX,PushBX\r
+ RET\r
+PushDMA ENDP\r
+\r
+; PopDMA\r
+; input: old DMA under ret address on stack\r
+; output: [DMAADD] set to old version and stack popped\r
+ procedure PopDMA,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+ POP PushSave\r
+ POP WORD PTR [DMAADD]\r
+ POP WORD PTR [DMAADD+2]\r
+ PUSH PushSave\r
+ RET\r
+PopDMA ENDP\r
+\r
+; ptr_normalize\r
+; input: DS:DX is a pointer\r
+; output: DS:DX is normalized (DX < 10h)\r
+ procedure ptr_normalize,NEAR\r
+ PUSH CX ; T1 = CX\r
+ PUSH DX ; T2 = DX\r
+ MOV CL,4\r
+ SHR DX,CL ; DX = (DX >> 4) (using CX)\r
+ MOV CX,DS\r
+ ADD CX,DX\r
+ MOV DS,CX ; DS = DS + DX (using CX)\r
+ POP DX\r
+ AND DX,0Fh ; DX = T2 & 0Fh\r
+ POP CX ; CX = T1\r
+\r
+; PUSH AX\r
+; PUSH DX\r
+; MOV AX,DS\r
+; PUSH CX\r
+; MOV CL,4\r
+; SHR DX,CL ; get upper part of dx\r
+; POP CX\r
+; ADD AX,DX ; add into seg address\r
+; MOV DS,AX\r
+; POP DX\r
+; AND DX,0Fh ; save low part\r
+; POP AX\r
+\r
+ RET\r
+ptr_normalize ENDP\r
+\r
+BREAK <$Read - Do file/device I/O>\r
+;\r
+; Assembler usage:\r
+; LDS DX, buf\r
+; MOV CX, count\r
+; MOV BX, handle\r
+; MOV AH, Read\r
+; INT int_command\r
+; AX has number of bytes read\r
+; Errors:\r
+; AX = read_invalid_handle\r
+; = read_access_denied\r
+;\r
+\r
+ procedure $Read,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+ invoke PushDMA\r
+ CALL IO_setup\r
+ JC IO_err\r
+ CMP ES:[DI].sf_mode,open_for_write\r
+ JNE read_setup\r
+IO_bad_mode:\r
+ MOV AL,read_access_denied\r
+IO_err:\r
+ invoke PopDMA\r
+ transfer SYS_RET_ERR\r
+\r
+read_setup:\r
+ invoke $FCB_RANDOM_READ_BLOCK ; do read\r
+IO_done:\r
+ invoke get_user_stack ; get old frame\r
+ MOV AX,[SI].user_CX ; get returned CX\r
+ MOV CX,xenix_count\r
+ MOV [SI].user_CX,CX ; stash our CX\r
+ invoke PopDMA ; get old DMA\r
+ transfer SYS_RET_OK\r
+$Read ENDP\r
+\r
+BREAK <$Write - Do file/device I/O>\r
+;\r
+; Assembler usage:\r
+; LDS DX, buf\r
+; MOV CX, count\r
+; MOV BX, handle\r
+; MOV AH, Write\r
+; INT int_command\r
+; AX has number of bytes written\r
+; Errors:\r
+; AX = write_invalid_handle\r
+; = write_access_denied\r
+;\r
+\r
+ procedure $Write,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+\r
+ invoke PushDMA\r
+ CALL IO_setup\r
+ JC IO_err\r
+ CMP ES:[DI].sf_mode,open_for_read\r
+ JE IO_bad_mode\r
+ invoke $FCB_RANDOM_WRITE_BLOCK ; do write\r
+ JMP IO_done\r
+\r
+$write ENDP\r
+\r
+IO_setup:\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ context DS\r
+ MOV xenix_count,CX\r
+ invoke Get_sf_from_jfn\r
+ ; ES:DI is sf pointer\r
+ MOV AL,read_invalid_handle ;Assume an error\r
+ MOV CX,xenix_count\r
+ LEA DX,[DI].sf_fcb\r
+ PUSH ES\r
+ POP DS\r
+ ASSUME DS:NOTHING\r
+ RET\r
+\r
+BREAK <$LSEEK - set random record field>\r
+;\r
+; Assembler usage:\r
+; MOV DX, offsetlow\r
+; MOV CX, offsethigh\r
+; MOV BX, handle\r
+; MOV AL, method\r
+; MOV AH, LSeek\r
+; INT int_command\r
+; DX:AX has the new location of the pointer\r
+; Error returns:\r
+; AX = error_invalid_handle\r
+; = error_invalid_function\r
+ procedure $LSEEK,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ CMP AL,3\r
+ JB lseek_get_sf\r
+ error error_invalid_function\r
+\r
+lseek_get_sf:\r
+ context DS\r
+ invoke get_sf_from_jfn\r
+ PUSH ES\r
+ POP DS\r
+ ASSUME DS:NOTHING\r
+ JC lseek_bad\r
+;\r
+; don't seek device\r
+;\r
+ TEST [DI.sf_fcb+fcb_devid],devid_device\r
+ JZ lseek_dispatch\r
+ XOR AX,AX\r
+ XOR DX,DX\r
+ JMP SHORT lseek_ret\r
+lseek_dispatch:\r
+ DEC AL\r
+ JL lseek_beginning\r
+ DEC AL\r
+ JL lseek_current\r
+; move from end of file\r
+; first, get end of file\r
+ XCHG AX,DX ; AX <- low\r
+ XCHG DX,CX ; DX <- high\r
+ ASSUME DS:NOTHING\r
+ ADD AX,[DI+sf_fcb+fcb_FILSIZ]\r
+ ADC DX,[DI+sf_fcb+fcb_FILSIZ+2]\r
+ JMP SHORT lseek_ret\r
+\r
+lseek_beginning:\r
+ XCHG AX,DX ; AX <- low\r
+ XCHG DX,CX ; DX <- high\r
+\r
+lseek_ret:\r
+ MOV WORD PTR [DI+sf_fcb+fcb_RR],AX\r
+ MOV WORD PTR [DI+sf_fcb+fcb_RR+2],DX\r
+ invoke get_user_stack\r
+ MOV [SI.user_DX],DX\r
+ MOV [SI.user_AX],AX\r
+ transfer SYS_RET_OK\r
+\r
+lseek_current:\r
+; ES:DI is pointer to sf... need to invoke set random record for place\r
+ XCHG AX,DX ; AX <- low\r
+ XCHG DX,CX ; DX <- high\r
+ ADD AX,WORD PTR [DI+sf_fcb+fcb_RR]\r
+ ADC DX,WORD PTR [DI+sf_fcb+fcb_RR+2]\r
+ JMP lseek_ret\r
+\r
+lseek_bad:\r
+ error error_invalid_handle\r
+$lseek ENDP\r
+\r
+\r
+BREAK <$IOCTL - return/set device dependent stuff>\r
+;\r
+; Assembler usage:\r
+; MOV BX, Handle\r
+; MOV DX, Data\r
+;\r
+; (or LDS DX,BUF\r
+; MOV CX,COUNT)\r
+;\r
+; MOV AH, Ioctl\r
+; MOV AL, Request\r
+; INT 21h\r
+;\r
+; Error returns:\r
+; AX = error_invalid_handle\r
+; = error_invalid_function\r
+; = error_invalid_data\r
+\r
+ procedure $IOCTL,NEAR\r
+ ASSUME DS:NOTHING,ES:NOTHING\r
+ MOV SI,DS ;Stash DS for calls 2,3,4 and 5\r
+ context DS\r
+ CMP AL,3\r
+ JA ioctl_check_block ;Block device\r
+ PUSH DX\r
+ invoke get_sf_from_jfn\r
+ POP DX ;Restore DATA\r
+ JNC ioctl_check_permissions ; have valid handle\r
+ error error_invalid_handle\r
+\r
+ioctl_check_permissions:\r
+ CMP AL,2\r
+ JAE ioctl_control_string\r
+ CMP AL,0\r
+ MOV AL,BYTE PTR ES:[DI+sf_fcb+fcb_devid]\r
+ JZ ioctl_read ; read the byte\r
+ OR DH,DH\r
+ JZ ioctl_check_device ; can I set with this data?\r
+ error error_invalid_data ; no DH <> 0\r
+\r
+ioctl_check_device:\r
+ TEST AL,devid_ISDEV ; can I set this handle?\r
+ JZ ioctl_bad_fun ; no, it is a file.\r
+ MOV BYTE PTR ES:[DI+sf_fcb+fcb_devid],DL\r
+ transfer SYS_RET_OK\r
+\r
+ioctl_read:\r
+ XOR AH,AH\r
+ TEST AL,devid_ISDEV ; Should I set high byte\r
+ JZ ioctl_no_high ; no\r
+ LES DI,DWORD PTR ES:[DI+sf_fcb+fcb_FIRCLUS] ;Get device pointer\r
+ MOV AH,BYTE PTR ES:[DI.SDEVATT+1] ;Get high byte\r
+ioctl_no_high:\r
+ invoke get_user_stack\r
+ MOV DX,AX\r
+ MOV [SI.user_DX],DX\r
+ transfer SYS_RET_OK\r
+\r
+ioctl_control_string:\r
+ TEST BYTE PTR ES:[DI+sf_fcb+fcb_devid],devid_ISDEV ; can I?\r
+ JZ ioctl_bad_fun ; no, it is a file.\r
+ LES DI,DWORD PTR ES:[DI+sf_fcb+fcb_FIRCLUS] ;Get device pointer\r
+ XOR BL,BL ; Unit number of char dev = 0\r
+ JMP SHORT ioctl_do_string\r
+\r
+ioctl_check_block:\r
+ DEC AL\r
+ DEC AL ;4=2,5=3,6=4,7=5\r
+ CMP AL,3\r
+ JBE ioctl_get_dev\r
+\r
+ MOV AH,1\r
+ SUB AL,4 ;6=0,7=1\r
+ JZ ioctl_get_status\r
+ MOV AH,3\r
+ DEC AL\r
+ JNZ ioctl_bad_fun\r
+\r
+ioctl_get_status:\r
+ PUSH AX\r
+ invoke GET_IO_FCB\r
+ POP AX\r
+ JC ioctl_acc_err\r
+ invoke IOFUNC\r
+ MOV AH,AL\r
+ MOV AL,0FFH\r
+ JNZ ioctl_status_ret\r
+ INC AL\r
+ioctl_status_ret:\r
+ transfer SYS_RET_OK\r
+\r
+ioctl_bad_fun:\r
+ error error_invalid_function\r
+\r
+ioctl_acc_err:\r
+ error error_access_denied\r
+\r
+ioctl_get_dev:\r
+ PUSH CX\r
+ PUSH DX\r
+ PUSH AX\r
+ PUSH SI ;DS in disguise\r
+ MOV AL,BL ;Drive\r
+ invoke GETTHISDRV\r
+ JC ioctl_bad_drv\r
+ invoke FATREAD ;"get" the drive\r
+ MOV BL,ES:[BP.dpb_UNIT] ; Unit number\r
+ LES DI,ES:[BP.dpb_driver_addr]\r
+ CLC ;Make sure error jump not taken\r
+ioctl_bad_drv:\r
+ POP SI\r
+ POP AX\r
+ POP DX\r
+ POP CX\r
+ JC ioctl_acc_err\r
+ioctl_do_string:\r
+ TEST ES:[DI.SDEVATT],DEVIOCTL ;See if device accepts control\r
+ JZ ioctl_bad_fun ;NO\r
+ DEC AL\r
+ DEC AL\r
+ JZ ioctl_control_read\r
+ MOV [IOCALL.REQFUNC],DEVWRIOCTL\r
+ JMP SHORT ioctl_control_call\r
+ioctl_control_read:\r
+ MOV [IOCALL.REQFUNC],DEVRDIOCTL\r
+ioctl_control_call:\r
+ MOV AL,DRDWRHL\r
+ MOV AH,BL ;Unit number\r
+ MOV WORD PTR [IOCALL.REQLEN],AX\r
+ XOR AX,AX\r
+ MOV [IOCALL.REQSTAT],AX\r
+ MOV [IOMED],AL\r
+ MOV [IOSCNT],CX\r
+ MOV WORD PTR [IOXAD],DX\r
+ MOV WORD PTR [IOXAD+2],SI\r
+ PUSH ES\r
+ POP DS\r
+ASSUME DS:NOTHING\r
+ MOV SI,DI ;DS:SI -> driver\r
+ PUSH SS\r
+ POP ES\r
+ MOV BX,OFFSET DOSGROUP:IOCALL ;ES:BX -> Call header\r
+ invoke DEVIOCALL2\r
+ MOV AX,[IOSCNT] ;Get actual bytes transferred\r
+ transfer SYS_RET_OK\r
+\r
+$IOCTL ENDP\r
+\r
+BREAK <File_Times - modify write times on a handle>\r
+;\r
+; Assembler usage:\r
+; MOV AH, FileTimes\r
+; MOV AL, func\r
+; MOV BX, handle\r
+; ; if AL = 1 then then next two are mandatory\r
+; MOV CX, time\r
+; MOV DX, date\r
+; INT 21h\r
+; ; if AL = 0 then CX/DX has the last write time/date\r
+; ; for the handle.\r
+;\r
+; Error returns:\r
+; AX = error_invalid_function\r
+; = error_invalid_handle\r
+;\r
+procedure $File_times,near\r
+ CMP AL,2\r
+ JB filetimes_ok\r
+ error error_invalid_function\r
+\r
+filetimes_ok:\r
+ PUSH SS\r
+ POP DS\r
+ CALL Get_sf_from_jfn\r
+ JNC filetimes_disp\r
+ error error_invalid_handle\r
+\r
+filetimes_disp:\r
+ OR AL,AL\r
+ JNZ filetimes_set\r
+ MOV CX,ES:[DI.sf_fcb.fcb_FTIME]\r
+ MOV DX,ES:[DI.sf_fcb.fcb_FDATE]\r
+ invoke Get_user_stack\r
+ MOV [SI.user_CX],CX\r
+ MOV [SI.user_DX],DX\r
+ transfer SYS_RET_OK\r
+\r
+filetimes_set:\r
+ MOV ES:[DI.sf_fcb.fcb_FTIME],CX\r
+ MOV ES:[DI.sf_fcb.fcb_FDATE],DX\r
+ AND ES:[DI.sf_fcb.fcb_DEVID],NOT devid_file_clean\r
+ transfer SYS_RET_OK\r
+$file_times ENDP\r
+\r
+do_ext\r
+\r
+CODE ENDS\r
+ END\r
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file