]> wirehaze git hosting - MS-DOS.git/commitdiff

wirehaze git hosting

MS-DOS v2.0 Release
authorRich Turner <richturn@microsoft.com>
Sat, 13 Aug 1983 00:53:34 +0000 (17:53 -0700)
committerRich Turner <richturn@microsoft.com>
Sat, 22 Sep 2018 00:53:34 +0000 (17:53 -0700)
156 files changed:
v2.0/bin/ANSI.DOC [new file with mode: 0644]
v2.0/bin/CHKDSK.COM [new file with mode: 0644]
v2.0/bin/COMMAND.COM [new file with mode: 0644]
v2.0/bin/CONFIG.DOC [new file with mode: 0644]
v2.0/bin/CREF.EXE [new file with mode: 0644]
v2.0/bin/DEBUG.COM [new file with mode: 0644]
v2.0/bin/DEVDRIV.DOC [new file with mode: 0644]
v2.0/bin/DISKCOPY.COM [new file with mode: 0644]
v2.0/bin/DOSPATCH.TXT [new file with mode: 0644]
v2.0/bin/EDLIN.COM [new file with mode: 0644]
v2.0/bin/EXE2BIN.EXE [new file with mode: 0644]
v2.0/bin/FC.EXE [new file with mode: 0644]
v2.0/bin/FILBP.PAS [new file with mode: 0644]
v2.0/bin/FIND.EXE [new file with mode: 0644]
v2.0/bin/FORMAT.DOC [new file with mode: 0644]
v2.0/bin/FORMAT.OBJ [new file with mode: 0644]
v2.0/bin/FORMES.OBJ [new file with mode: 0644]
v2.0/bin/INCOMP.DOC [new file with mode: 0644]
v2.0/bin/INT24.DOC [new file with mode: 0644]
v2.0/bin/LINK.EXE [new file with mode: 0644]
v2.0/bin/MASM.EXE [new file with mode: 0644]
v2.0/bin/MORE.COM [new file with mode: 0644]
v2.0/bin/MSDOS.SYS [new file with mode: 0644]
v2.0/bin/PRINT.COM [new file with mode: 0644]
v2.0/bin/PROFIL.OBJ [new file with mode: 0644]
v2.0/bin/PROFILE.DOC [new file with mode: 0644]
v2.0/bin/PROHST.EXE [new file with mode: 0644]
v2.0/bin/PROHST.PAS [new file with mode: 0644]
v2.0/bin/QUICK.DOC [new file with mode: 0644]
v2.0/bin/README.DOC [new file with mode: 0644]
v2.0/bin/RECOVER.COM [new file with mode: 0644]
v2.0/bin/SORT.EXE [new file with mode: 0644]
v2.0/bin/SYS.COM [new file with mode: 0644]
v2.0/bin/SYSCALL.DOC [new file with mode: 0644]
v2.0/bin/SYSIMES.OBJ [new file with mode: 0644]
v2.0/bin/SYSINIT.DOC [new file with mode: 0644]
v2.0/bin/SYSINIT.OBJ [new file with mode: 0644]
v2.0/bin/UTILITY.DOC [new file with mode: 0644]
v2.0/source/ALLOC.ASM [new file with mode: 0644]
v2.0/source/ANSI.txt [new file with mode: 0644]
v2.0/source/BUF.ASM [new file with mode: 0644]
v2.0/source/CHKDSK.ASM [new file with mode: 0644]
v2.0/source/CHKMES.ASM [new file with mode: 0644]
v2.0/source/CHKPROC.ASM [new file with mode: 0644]
v2.0/source/COMEQU.ASM [new file with mode: 0644]
v2.0/source/COMLINK [new file with mode: 0644]
v2.0/source/COMMAND.ASM [new file with mode: 0644]
v2.0/source/COMSEG.ASM [new file with mode: 0644]
v2.0/source/COMSW.ASM [new file with mode: 0644]
v2.0/source/CONFIG.txt [new file with mode: 0644]
v2.0/source/COPY.ASM [new file with mode: 0644]
v2.0/source/COPYPROC.ASM [new file with mode: 0644]
v2.0/source/CPARSE.ASM [new file with mode: 0644]
v2.0/source/CTRLC.ASM [new file with mode: 0644]
v2.0/source/DEBASM.ASM [new file with mode: 0644]
v2.0/source/DEBCOM1.ASM [new file with mode: 0644]
v2.0/source/DEBCOM2.ASM [new file with mode: 0644]
v2.0/source/DEBCONST.ASM [new file with mode: 0644]
v2.0/source/DEBDATA.ASM [new file with mode: 0644]
v2.0/source/DEBEQU.ASM [new file with mode: 0644]
v2.0/source/DEBMES.ASM [new file with mode: 0644]
v2.0/source/DEBUASM.ASM [new file with mode: 0644]
v2.0/source/DEBUG.ASM [new file with mode: 0644]
v2.0/source/DEV.ASM [new file with mode: 0644]
v2.0/source/DEVDRIV.txt [new file with mode: 0644]
v2.0/source/DEVSYM.ASM [new file with mode: 0644]
v2.0/source/DIR.ASM [new file with mode: 0644]
v2.0/source/DIRCALL.ASM [new file with mode: 0644]
v2.0/source/DISK.ASM [new file with mode: 0644]
v2.0/source/DISKCOPY.ASM [new file with mode: 0644]
v2.0/source/DISKMES.ASM [new file with mode: 0644]
v2.0/source/DOSLINK [new file with mode: 0644]
v2.0/source/DOSMAC.ASM [new file with mode: 0644]
v2.0/source/DOSMAC_v211.ASM [new file with mode: 0644]
v2.0/source/DOSMES.ASM [new file with mode: 0644]
v2.0/source/DOSSEG.ASM [new file with mode: 0644]
v2.0/source/DOSSYM.ASM [new file with mode: 0644]
v2.0/source/DOSSYM_v211.ASM [new file with mode: 0644]
v2.0/source/EDLIN.ASM [new file with mode: 0644]
v2.0/source/EDLMES.ASM [new file with mode: 0644]
v2.0/source/EDLPROC.ASM [new file with mode: 0644]
v2.0/source/EXE2BIN.ASM [new file with mode: 0644]
v2.0/source/EXEC.ASM [new file with mode: 0644]
v2.0/source/EXEMES.ASM [new file with mode: 0644]
v2.0/source/FAT.ASM [new file with mode: 0644]
v2.0/source/FC.ASM [new file with mode: 0644]
v2.0/source/FCB.ASM [new file with mode: 0644]
v2.0/source/FCMES.ASM [new file with mode: 0644]
v2.0/source/FIND.ASM [new file with mode: 0644]
v2.0/source/FINDMES.ASM [new file with mode: 0644]
v2.0/source/FORMAT.ASM [new file with mode: 0644]
v2.0/source/FORMAT.txt [new file with mode: 0644]
v2.0/source/FORMES.ASM [new file with mode: 0644]
v2.0/source/GENFOR.ASM [new file with mode: 0644]
v2.0/source/GETSET.ASM [new file with mode: 0644]
v2.0/source/HRDDRV.ASM [new file with mode: 0644]
v2.0/source/IFEQU.ASM [new file with mode: 0644]
v2.0/source/INCOMP.txt [new file with mode: 0644]
v2.0/source/INIT.ASM [new file with mode: 0644]
v2.0/source/INT24.txt [new file with mode: 0644]
v2.0/source/MISC.ASM [new file with mode: 0644]
v2.0/source/MORE.ASM [new file with mode: 0644]
v2.0/source/MOREMES.ASM [new file with mode: 0644]
v2.0/source/MSCODE.ASM [new file with mode: 0644]
v2.0/source/MSDATA.ASM [new file with mode: 0644]
v2.0/source/MSDOS.ASM [new file with mode: 0644]
v2.0/source/MSHEAD.ASM [new file with mode: 0644]
v2.0/source/MSINIT.ASM [new file with mode: 0644]
v2.0/source/PCLOCK.ASM [new file with mode: 0644]
v2.0/source/PRINT.ASM [new file with mode: 0644]
v2.0/source/PRINT_v211.ASM [new file with mode: 0644]
v2.0/source/PROC.ASM [new file with mode: 0644]
v2.0/source/PROFIL.ASM [new file with mode: 0644]
v2.0/source/PROFILE.txt [new file with mode: 0644]
v2.0/source/PROHST.HLP [new file with mode: 0644]
v2.0/source/QUICK.txt [new file with mode: 0644]
v2.0/source/RDATA.ASM [new file with mode: 0644]
v2.0/source/README.txt [new file with mode: 0644]
v2.0/source/RECMES.ASM [new file with mode: 0644]
v2.0/source/RECOVER.ASM [new file with mode: 0644]
v2.0/source/ROM.ASM [new file with mode: 0644]
v2.0/source/RUCODE.ASM [new file with mode: 0644]
v2.0/source/SKELIO.ASM [new file with mode: 0644]
v2.0/source/SORT.ASM [new file with mode: 0644]
v2.0/source/SORTMES.ASM [new file with mode: 0644]
v2.0/source/STDBUF.ASM [new file with mode: 0644]
v2.0/source/STDCALL.ASM [new file with mode: 0644]
v2.0/source/STDCTRLC.ASM [new file with mode: 0644]
v2.0/source/STDFCB.ASM [new file with mode: 0644]
v2.0/source/STDIO.ASM [new file with mode: 0644]
v2.0/source/STDPROC.ASM [new file with mode: 0644]
v2.0/source/STDSW.ASM [new file with mode: 0644]
v2.0/source/STRIN.ASM [new file with mode: 0644]
v2.0/source/SYS.ASM [new file with mode: 0644]
v2.0/source/SYSCALL.ASM [new file with mode: 0644]
v2.0/source/SYSCALL.txt [new file with mode: 0644]
v2.0/source/SYSIMES.ASM [new file with mode: 0644]
v2.0/source/SYSINIT.ASM [new file with mode: 0644]
v2.0/source/SYSINIT.txt [new file with mode: 0644]
v2.0/source/SYSMES.ASM [new file with mode: 0644]
v2.0/source/TCODE.ASM [new file with mode: 0644]
v2.0/source/TCODE2.ASM [new file with mode: 0644]
v2.0/source/TCODE3.ASM [new file with mode: 0644]
v2.0/source/TCODE4.ASM [new file with mode: 0644]
v2.0/source/TCODE5.ASM [new file with mode: 0644]
v2.0/source/TDATA.ASM [new file with mode: 0644]
v2.0/source/TIME.ASM [new file with mode: 0644]
v2.0/source/TSPC.ASM [new file with mode: 0644]
v2.0/source/TUCODE.ASM [new file with mode: 0644]
v2.0/source/UINIT.ASM [new file with mode: 0644]
v2.0/source/UTILITY.txt [new file with mode: 0644]
v2.0/source/WSBAUD.BAS [new file with mode: 0644]
v2.0/source/WSMSGS.OVR [new file with mode: 0644]
v2.0/source/WSOVLY1.OVR [new file with mode: 0644]
v2.0/source/XENIX.ASM [new file with mode: 0644]
v2.0/source/XENIX2.ASM [new file with mode: 0644]

diff --git a/v2.0/bin/ANSI.DOC b/v2.0/bin/ANSI.DOC
new file mode 100644 (file)
index 0000000..040d9d2
Binary files /dev/null and b/v2.0/bin/ANSI.DOC differ
diff --git a/v2.0/bin/CHKDSK.COM b/v2.0/bin/CHKDSK.COM
new file mode 100644 (file)
index 0000000..152bc38
Binary files /dev/null and b/v2.0/bin/CHKDSK.COM differ
diff --git a/v2.0/bin/COMMAND.COM b/v2.0/bin/COMMAND.COM
new file mode 100644 (file)
index 0000000..820f393
Binary files /dev/null and b/v2.0/bin/COMMAND.COM differ
diff --git a/v2.0/bin/CONFIG.DOC b/v2.0/bin/CONFIG.DOC
new file mode 100644 (file)
index 0000000..bfb1985
Binary files /dev/null and b/v2.0/bin/CONFIG.DOC differ
diff --git a/v2.0/bin/CREF.EXE b/v2.0/bin/CREF.EXE
new file mode 100644 (file)
index 0000000..a88c2fa
Binary files /dev/null and b/v2.0/bin/CREF.EXE differ
diff --git a/v2.0/bin/DEBUG.COM b/v2.0/bin/DEBUG.COM
new file mode 100644 (file)
index 0000000..41d127b
Binary files /dev/null and b/v2.0/bin/DEBUG.COM differ
diff --git a/v2.0/bin/DEVDRIV.DOC b/v2.0/bin/DEVDRIV.DOC
new file mode 100644 (file)
index 0000000..3c82793
--- /dev/null
@@ -0,0 +1,802 @@
+                  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
diff --git a/v2.0/bin/DISKCOPY.COM b/v2.0/bin/DISKCOPY.COM
new file mode 100644 (file)
index 0000000..ea4e0d2
Binary files /dev/null and b/v2.0/bin/DISKCOPY.COM differ
diff --git a/v2.0/bin/DOSPATCH.TXT b/v2.0/bin/DOSPATCH.TXT
new file mode 100644 (file)
index 0000000..20ebd95
--- /dev/null
@@ -0,0 +1,62 @@
+There are three locations in the DOS where OEMs may want to
+patch in information specific to their installation.
+
+
+The first is the location of the default switch character.
+This character is one byte at DEBUG location 1E5, and is
+set to '/'. To change it to '-' (XENIX compatible)
+do:
+
+        DEBUG MSDOS.SYS
+
+        >e1e5
+        XXXX:01E5   2F.         <at this point give the desired
+                                 new switch character in HEX and
+                                 hit return>
+        >w
+        Writing YYYY Bytes
+        >q
+
+If the byte at 1E5 is not 2F, look around in the immediate
+vacinity (do d1e0) for it. It is the only 2F in that area.
+
+
+The second is the location of the 24 bit user number and the
+8 bit OEM number. These values are returned by the GET_VERSION
+system call.
+The user number is 3 bytes starting at
+debug location 683, The OEM number is one byte at debug location
+686. The user number is initialized to 0, the OEM number to -1
+and they immediatly follow the Microsoft Copyright message. If these
+bytes are not zero, look for the four bytes following the
+Copyright message which should be in the vacinity of 683.
+OEMs should request an OEM number from Microsoft if they
+want one of their very own, this prevents selecting one someone
+else already has.
+
+
+The third is the location of the editing template definitions.
+This is a table which defines the two byte edit function keys
+for system call 10 and for EDLIN. This table is at debug location
+33EA, and should start with a 1B. If the byte at 33EA is not
+1B, look around in the immediate vacinity. Here is what the
+default table looks like. It is a definition for the Zenith
+Z-19 terminal:
+
+ESCCHAR DB      1BH     ;The Escape character, Nul (0) on IBM
+ESCTAB:
+       DB      "Z"     ;5AH Put a ^Z in the template, F6 on IBM
+        DB      "S"     ;53H Copy one char, --> on IBM
+        DB      "V"     ;56H Skip one char, DEL on IBM
+        DB      "T"     ;54H Copy to char, F2 on IBM
+        DB      "W"     ;57H Skip to char, F4 on IBM
+        DB      "U"     ;55H Copy line, F3 on IBM
+        DB      "E"     ;45H Kill line, Not used on IBM
+        DB      "J"     ;4AH Reedit line, F5 on IBM
+        DB      "D"     ;44H Backspace, <-- on IBM
+        DB      "P"     ;50H Toggle insert mode, INS on IBM 
+        DB      "Q"     ;51H Toggle insert mode, INS on IBM 
+        DB      "R"     ;52H Escape char, F7 on IBM
+        DB      "R"     ;52H End of table, must be same as previos character
+
+\1a
\ No newline at end of file
diff --git a/v2.0/bin/EDLIN.COM b/v2.0/bin/EDLIN.COM
new file mode 100644 (file)
index 0000000..81e097b
Binary files /dev/null and b/v2.0/bin/EDLIN.COM differ
diff --git a/v2.0/bin/EXE2BIN.EXE b/v2.0/bin/EXE2BIN.EXE
new file mode 100644 (file)
index 0000000..f4b0dd7
Binary files /dev/null and b/v2.0/bin/EXE2BIN.EXE differ
diff --git a/v2.0/bin/FC.EXE b/v2.0/bin/FC.EXE
new file mode 100644 (file)
index 0000000..aa06624
Binary files /dev/null and b/v2.0/bin/FC.EXE differ
diff --git a/v2.0/bin/FILBP.PAS b/v2.0/bin/FILBP.PAS
new file mode 100644 (file)
index 0000000..71decc8
Binary files /dev/null and b/v2.0/bin/FILBP.PAS differ
diff --git a/v2.0/bin/FIND.EXE b/v2.0/bin/FIND.EXE
new file mode 100644 (file)
index 0000000..b5d07d0
Binary files /dev/null and b/v2.0/bin/FIND.EXE differ
diff --git a/v2.0/bin/FORMAT.DOC b/v2.0/bin/FORMAT.DOC
new file mode 100644 (file)
index 0000000..ab47f54
--- /dev/null
@@ -0,0 +1,393 @@
+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
diff --git a/v2.0/bin/FORMAT.OBJ b/v2.0/bin/FORMAT.OBJ
new file mode 100644 (file)
index 0000000..61fe107
Binary files /dev/null and b/v2.0/bin/FORMAT.OBJ differ
diff --git a/v2.0/bin/FORMES.OBJ b/v2.0/bin/FORMES.OBJ
new file mode 100644 (file)
index 0000000..247f39e
Binary files /dev/null and b/v2.0/bin/FORMES.OBJ differ
diff --git a/v2.0/bin/INCOMP.DOC b/v2.0/bin/INCOMP.DOC
new file mode 100644 (file)
index 0000000..6c187b6
Binary files /dev/null and b/v2.0/bin/INCOMP.DOC differ
diff --git a/v2.0/bin/INT24.DOC b/v2.0/bin/INT24.DOC
new file mode 100644 (file)
index 0000000..d38d6fa
Binary files /dev/null and b/v2.0/bin/INT24.DOC differ
diff --git a/v2.0/bin/LINK.EXE b/v2.0/bin/LINK.EXE
new file mode 100644 (file)
index 0000000..aa58151
Binary files /dev/null and b/v2.0/bin/LINK.EXE differ
diff --git a/v2.0/bin/MASM.EXE b/v2.0/bin/MASM.EXE
new file mode 100644 (file)
index 0000000..d43bfb7
Binary files /dev/null and b/v2.0/bin/MASM.EXE differ
diff --git a/v2.0/bin/MORE.COM b/v2.0/bin/MORE.COM
new file mode 100644 (file)
index 0000000..b28f807
Binary files /dev/null and b/v2.0/bin/MORE.COM differ
diff --git a/v2.0/bin/MSDOS.SYS b/v2.0/bin/MSDOS.SYS
new file mode 100644 (file)
index 0000000..803eb70
Binary files /dev/null and b/v2.0/bin/MSDOS.SYS differ
diff --git a/v2.0/bin/PRINT.COM b/v2.0/bin/PRINT.COM
new file mode 100644 (file)
index 0000000..b2788d3
Binary files /dev/null and b/v2.0/bin/PRINT.COM differ
diff --git a/v2.0/bin/PROFIL.OBJ b/v2.0/bin/PROFIL.OBJ
new file mode 100644 (file)
index 0000000..66946b3
Binary files /dev/null and b/v2.0/bin/PROFIL.OBJ differ
diff --git a/v2.0/bin/PROFILE.DOC b/v2.0/bin/PROFILE.DOC
new file mode 100644 (file)
index 0000000..2d50631
Binary files /dev/null and b/v2.0/bin/PROFILE.DOC differ
diff --git a/v2.0/bin/PROHST.EXE b/v2.0/bin/PROHST.EXE
new file mode 100644 (file)
index 0000000..dfa8983
Binary files /dev/null and b/v2.0/bin/PROHST.EXE differ
diff --git a/v2.0/bin/PROHST.PAS b/v2.0/bin/PROHST.PAS
new file mode 100644 (file)
index 0000000..4ee13fc
--- /dev/null
@@ -0,0 +1,403 @@
+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
diff --git a/v2.0/bin/QUICK.DOC b/v2.0/bin/QUICK.DOC
new file mode 100644 (file)
index 0000000..d443b8e
Binary files /dev/null and b/v2.0/bin/QUICK.DOC differ
diff --git a/v2.0/bin/README.DOC b/v2.0/bin/README.DOC
new file mode 100644 (file)
index 0000000..c5bbf25
--- /dev/null
@@ -0,0 +1,177 @@
+                         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
diff --git a/v2.0/bin/RECOVER.COM b/v2.0/bin/RECOVER.COM
new file mode 100644 (file)
index 0000000..fa51fae
Binary files /dev/null and b/v2.0/bin/RECOVER.COM differ
diff --git a/v2.0/bin/SORT.EXE b/v2.0/bin/SORT.EXE
new file mode 100644 (file)
index 0000000..9e2c19a
Binary files /dev/null and b/v2.0/bin/SORT.EXE differ
diff --git a/v2.0/bin/SYS.COM b/v2.0/bin/SYS.COM
new file mode 100644 (file)
index 0000000..2d315d7
Binary files /dev/null and b/v2.0/bin/SYS.COM differ
diff --git a/v2.0/bin/SYSCALL.DOC b/v2.0/bin/SYSCALL.DOC
new file mode 100644 (file)
index 0000000..26d4729
--- /dev/null
@@ -0,0 +1,1657 @@
+\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
diff --git a/v2.0/bin/SYSIMES.OBJ b/v2.0/bin/SYSIMES.OBJ
new file mode 100644 (file)
index 0000000..3172652
Binary files /dev/null and b/v2.0/bin/SYSIMES.OBJ differ
diff --git a/v2.0/bin/SYSINIT.DOC b/v2.0/bin/SYSINIT.DOC
new file mode 100644 (file)
index 0000000..fa20d08
Binary files /dev/null and b/v2.0/bin/SYSINIT.DOC differ
diff --git a/v2.0/bin/SYSINIT.OBJ b/v2.0/bin/SYSINIT.OBJ
new file mode 100644 (file)
index 0000000..3dc2c13
Binary files /dev/null and b/v2.0/bin/SYSINIT.OBJ differ
diff --git a/v2.0/bin/UTILITY.DOC b/v2.0/bin/UTILITY.DOC
new file mode 100644 (file)
index 0000000..a63793c
--- /dev/null
@@ -0,0 +1,813 @@
+\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
diff --git a/v2.0/source/ALLOC.ASM b/v2.0/source/ALLOC.ASM
new file mode 100644 (file)
index 0000000..7b69826
--- /dev/null
@@ -0,0 +1,371 @@
+;\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
diff --git a/v2.0/source/ANSI.txt b/v2.0/source/ANSI.txt
new file mode 100644 (file)
index 0000000..040d9d2
Binary files /dev/null and b/v2.0/source/ANSI.txt differ
diff --git a/v2.0/source/BUF.ASM b/v2.0/source/BUF.ASM
new file mode 100644 (file)
index 0000000..f1ad800
--- /dev/null
@@ -0,0 +1,508 @@
+;
+; buffer management for MSDOS
+;
+
+INCLUDE DOSSEG.ASM
+
+CODE    SEGMENT BYTE PUBLIC  'CODE'
+        ASSUME  SS:DOSGROUP,CS:DOSGROUP
+
+.xlist
+.xcref
+INCLUDE DOSSYM.ASM
+INCLUDE DEVSYM.ASM
+.cref
+.list
+
+        i_need  BuffHead,DWORD
+        i_need  PreRead,WORD
+        i_need  LastBuffer,DWORD
+        i_need  CurBuf,DWORD
+        i_need  WPErr,BYTE
+
+SUBTTL SETVISIT,SKIPVISIT -- MANAGE BUFFER SCANS
+PAGE
+        procedure   SETVISIT,near
+ASSUME  DS:NOTHING,ES:NOTHING
+
+; Inputs:
+;       None
+; Function:
+;       Set up a scan of I/O buffers
+; Outputs:
+;       All visit flags = 0
+;               NOTE: This pre-scan is needed because a hard disk error
+;                     may cause a scan to stop in the middle leaving some
+;                     visit flags set, and some not set.
+;       DS:DI Points to [BUFFHEAD]
+; No other registers altered
+
+        LDS     DI,[BUFFHEAD]
+        PUSH    AX
+        XOR     AX,AX
+SETLOOP:
+        MOV     [DI.VISIT],AL
+        LDS     DI,[DI.NEXTBUF]
+        CMP     DI,-1
+        JNZ     SETLOOP
+        LDS     DI,[BUFFHEAD]
+        POP     AX
+        return
+
+        entry   SKIPVISIT
+ASSUME  DS:NOTHING,ES:NOTHING
+
+; Inputs:
+;       DS:DI Points to a buffer
+; Function:
+;       Skip visited buffers
+; Outputs:
+;       DS:DI Points to next unvisited buffer
+;       Zero is set if skip to LAST buffer
+; No other registers altered
+
+        CMP     DI,-1
+        retz
+        CMP     [DI.VISIT],1
+        retnz
+        LDS     DI,[DI.NEXTBUF]
+        JMP     SHORT SKIPVISIT
+        return
+SetVisit    ENDP
+
+
+SUBTTL SCANPLACE, PLACEBUF -- PUT A BUFFER BACK IN THE POOL
+PAGE
+        procedure   ScanPlace,near
+ASSUME  DS:NOTHING,ES:NOTHING
+
+; Inputs:
+;       Same as PLACEBUF
+; Function:
+;       Save scan location and call PLACEBUF
+; Outputs:
+;       DS:DI Points to saved scan location
+; SI destroyed, other registers unchanged
+
+        PUSH    ES
+        LES     SI,[DI.NEXTBUF]         ; Save scan location
+        CALL    PLACEBUF
+        PUSH    ES
+        POP     DS                      ; Restore scan location
+        MOV     DI,SI
+        POP     ES
+        return
+ScanPlace   ENDP
+
+NRETJ:  JMP     SHORT NRET
+
+        procedure   PLACEBUF,NEAR
+ASSUME  DS:NOTHING,ES:NOTHING
+
+; Input:
+;       DS:DI points to buffer
+; Function:
+;       Remove buffer from queue and re-insert it in proper place.
+;       If buffer doesn't go at end, and isn't free, decrement
+;       priorities.
+; NO registers altered
+;
+; DS:SI -- Curbuf, current buffer in list
+; ES:DI -- Buf, buffer passed as argument
+; BP:CX -- Pointsave, saved Buf.nextbuf
+; DX:BX -- Lastbuf, previous buffer in list
+; AL    -- Inserted, Buf has been inserted
+; AH    -- Removed, Buf has been removed
+
+        IF      IBM
+        IF      NOT IBM
+        invoke  save_world
+        XOR     AX,AX           ; Inserted = Removed = FALSE
+        LES     CX,[DI.NEXTBUF]
+        MOV     BP,ES           ; Pointsave = Buf.nextbuf
+        MOV     SI,DS
+        MOV     ES,SI           ; Buf is ES:DI
+        LDS     SI,[BUFFHEAD]   ; Curbuf = HEAD
+        CALL    POINTCOMP       ; Buf == HEAD?
+        JNZ     TNEWHEAD
+        CMP     CX,-1           ; Buf is LAST?
+        JZ      NRETJ           ; Only one buffer, nothing to do
+        MOV     WORD PTR [BUFFHEAD],CX
+        MOV     WORD PTR [BUFFHEAD+2],BP        ; HEAD = Pointsave
+        INC     AH              ; Removed = TRUE
+        MOV     DS,BP
+        MOV     SI,CX           ; Curbuf = HEAD
+TNEWHEAD:
+        MOV     BL,ES:[DI.BUFPRI]
+        CMP     BL,[SI.BUFPRI]
+        JGE     BUFLOOP
+NEWHEAD:                        ; If Buf.pri < HEAD.pri
+        MOV     WORD PTR ES:[DI.NEXTBUF],SI
+        MOV     WORD PTR ES:[DI.NEXTBUF+2],DS   ; Buf.nextbuf = HEAD
+        MOV     WORD PTR [BUFFHEAD],DI
+        MOV     WORD PTR [BUFFHEAD+2],ES        ; HEAD = Buf
+        INC     AL                              ; Inserted = TRUE
+        OR      AH,AH
+        JNZ     NRET            ; If Removed == TRUE
+BUFLOOP:
+        PUSH    DS
+        PUSH    SI
+        LDS     SI,[SI.NEXTBUF]
+        CALL    POINTCOMP
+        POP     SI
+        POP     DS
+        JNZ     TESTINS
+        MOV     WORD PTR [SI.NEXTBUF],CX        ; If Curbuf.nextbuf == buf
+        MOV     WORD PTR [SI.NEXTBUF+2],BP      ; Curbuf.nextbuf = Pointsave
+        INC     AH              ; Removed = TRUE
+        OR      AL,AL
+        JNZ     SHUFFLE         ; If Inserted == TRUE
+TESTINS:
+        OR      AL,AL
+        JNZ     LOOKBUF
+        PUSH    CX              ; If NOT Inserted
+        MOV     CL,ES:[DI.BUFPRI]
+        CMP     CL,[SI.BUFPRI]
+        POP     CX
+        JGE     LOOKBUF
+        PUSH    DS              ; If Buf.pri < Curbuf.pri
+        MOV     DS,DX
+        MOV     WORD PTR [BX.NEXTBUF],DI
+        MOV     WORD PTR [BX.NEXTBUF+2],ES      ; Lastbuf.nextbuf = Buf
+        POP     DS
+        MOV     WORD PTR ES:[DI.NEXTBUF],SI
+        MOV     WORD PTR ES:[DI.NEXTBUF+2],DS   ; Buf.nextbuf = Curbuf
+        INC     AL              ; Inserted = TRUE
+        OR      AH,AH
+        JNZ     SHUFFLE         ; If Removed == TRUE
+LOOKBUF:
+        MOV     BX,SI
+        MOV     DX,DS           ; Lastbuf = Curbuf
+        CMP     WORD PTR [SI.NEXTBUF],-1
+        JZ      ISLAST
+        LDS     SI,[SI.NEXTBUF] ; Curbuf = Curbuf.nextbuf
+        JMP     SHORT BUFLOOP
+ISLAST:                 ; If Curbuf is LAST
+        MOV     WORD PTR [SI.NEXTBUF],DI
+        MOV     WORD PTR [SI.NEXTBUF+2],ES      ; Curbuf.nextbuf = Buf
+        MOV     WORD PTR ES:[DI.NEXTBUF],-1
+        MOV     WORD PTR ES:[DI.NEXTBUF+2],-1      ; Buf is LAST
+NRET:
+        invoke  restore_world
+        return
+
+SHUFFLE:
+        LDS     DI,[BUFFHEAD]
+DECLOOP:
+        CMP     [DI.BUFPRI],FREEPRI
+        JZ      NODEC
+        DEC     [DI.BUFPRI]
+NODEC:
+        LDS     DI,[DI.NEXTBUF]
+        CMP     DI,-1
+        JNZ     DECLOOP
+        JMP     SHORT NRET
+        ENDIF
+        ENDIF
+
+        invoke  save_world
+        LES     CX,[DI.NEXTBUF]
+        CMP     CX,-1           ; Buf is LAST?
+        JZ      NRET            ; Buffer already last
+        MOV     BP,ES           ; Pointsave = Buf.nextbuf
+        PUSH    DS
+        POP     ES              ; Buf is ES:DI
+        LDS     SI,[BUFFHEAD]   ; Curbuf = HEAD
+        CALL    POINTCOMP       ; Buf == HEAD?
+        JNZ     BUFLOOP
+        MOV     WORD PTR [BUFFHEAD],CX
+        MOV     WORD PTR [BUFFHEAD+2],BP        ; HEAD = Pointsave
+        JMP     SHORT LOOKEND
+
+BUFLOOP:
+        PUSH    DS
+        PUSH    SI
+        LDS     SI,[SI.NEXTBUF]
+        CALL    POINTCOMP
+        JZ      GOTTHEBUF
+        POP     AX
+        POP     AX
+        JMP     SHORT BUFLOOP
+
+GOTTHEBUF:
+        POP     SI
+        POP     DS
+        MOV     WORD PTR [SI.NEXTBUF],CX        ; If Curbuf.nextbuf == buf
+        MOV     WORD PTR [SI.NEXTBUF+2],BP      ; Curbuf.nextbuf = Pointsave
+LOOKEND:
+        PUSH    DS
+        PUSH    SI
+        LDS     SI,[SI.NEXTBUF]
+        CMP     SI,-1
+        JZ      GOTHEEND
+        POP     AX
+        POP     AX
+        JMP     SHORT LOOKEND
+
+GOTHEEND:
+        POP     SI
+        POP     DS
+        MOV     WORD PTR [SI.NEXTBUF],DI
+        MOV     WORD PTR [SI.NEXTBUF+2],ES      ; Curbuf.nextbuf = Buf
+        MOV     WORD PTR ES:[DI.NEXTBUF],-1
+        MOV     WORD PTR ES:[DI.NEXTBUF+2],-1      ; Buf is LAST
+NRET:
+        invoke  restore_world
+        return
+
+PLACEBUF    ENDP
+
+        procedure   PLACEHEAD,NEAR
+ASSUME  DS:NOTHING,ES:NOTHING
+
+; SAME AS PLACEBUF except places buffer at head
+
+        invoke  save_world
+        PUSH    DS
+        POP     ES
+        LDS     SI,[BUFFHEAD]
+        MOV     WORD PTR [BUFFHEAD],DI
+        MOV     WORD PTR [BUFFHEAD+2],ES
+        MOV     WORD PTR ES:[DI.NEXTBUF],SI
+        MOV     WORD PTR ES:[DI.NEXTBUF+2],DS
+LOOKEND2:
+        PUSH    DS
+        PUSH    SI
+        LDS     SI,[SI.NEXTBUF]
+        CALL    POINTCOMP
+        JZ      GOTHEEND2
+        POP     AX
+        POP     AX
+        JMP     SHORT LOOKEND2
+
+GOTHEEND2:
+        POP     SI
+        POP     DS
+        MOV     WORD PTR [SI.NEXTBUF],-1
+        MOV     WORD PTR [SI.NEXTBUF+2],-1      ; Buf is LAST
+        JMP     SHORT NRET
+
+PLACEHEAD   ENDP
+
+SUBTTL POINTCOMP -- 20 BIT POINTER COMPARE
+PAGE
+        procedure   PointComp,NEAR
+ASSUME  DS:NOTHING,ES:NOTHING
+
+; Compare DS:SI to ES:DI (or DS:DI to ES:SI) for equality
+; DO NOT USE FOR < or >
+; No Registers altered
+
+        CMP     SI,DI
+        retnz
+        PUSH    CX
+        PUSH    DX
+        MOV     CX,DS
+        MOV     DX,ES
+        CMP     CX,DX
+        POP     DX
+        POP     CX
+        return
+PointComp   ENDP
+
+SUBTTL GETBUFFR -- GET A SECTOR INTO A BUFFER
+PAGE
+        procedure   GETBUFFR,NEAR
+ASSUME  DS:DOSGROUP,ES:NOTHING
+
+; Input:
+;       AH = Priority buffer is to have
+;       AL = 0 means sector must be pre-read
+;          ELSE no pre-read
+;       DX = Desired physical sector number
+;       ES:BP = Pointer to drive parameters
+; Function:
+;       Get the specified sector into one of the I/O buffers
+;       And shuffle the queue
+; Output:
+;       [CURBUF] Points to the Buffer for the sector
+; DX,ES:BP unchanged, all other registers destroyed
+
+        XOR     SI,SI
+        entry   GETBUFFRB
+        MOV     [PREREAD],AX
+        MOV     AL,ES:[BP.dpb_drive]
+        LDS     DI,[LASTBUFFER]
+ASSUME  DS:NOTHING
+        CMP     DI,-1                           ; Recency pointer valid?
+        JZ      SKBUF                           ; No
+        CMP     DX,[DI.BUFSECNO]
+        JNZ     SKBUF                           ; Wrong sector
+        CMP     AL,[DI.BUFDRV]
+        JNZ     SKBUF                           ; Wrong Drive
+        JMP     SHORT JUSTBUF                   ; Just asked for same buffer
+SKBUF:
+        LDS     DI,[BUFFHEAD]
+NXTBFF:
+        CMP     DX,[DI.BUFSECNO]
+        JNZ     BUMP
+        CMP     AL,[DI.BUFDRV]
+        JNZ     BUMP
+        JMP     SHORT SETINF
+BUMP:
+        LDS     DI,[DI.NEXTBUF]
+        CMP     DI,-1
+        JNZ     NXTBFF
+        LDS     DI,[BUFFHEAD]
+        PUSH    SI
+        PUSH    DX
+        PUSH    BP
+        PUSH    ES
+        CALL    BUFWRITE        ; Write out the dirty buffer
+        POP     ES
+        POP     BP
+        POP     DX
+        POP     SI
+RDSEC:                          ; Read in the new sector
+        TEST    BYTE PTR [PREREAD],-1
+        JNZ     SETBUF
+        LEA     BX,[DI.BufInSiz]        ; Point at buffer
+        MOV     CX,1
+        PUSH    SI
+        PUSH    DI
+        PUSH    DX
+        OR      SI,SI
+        JZ      NORMSEC
+        invoke  FATSECRD
+        JMP     SHORT GOTTHESEC         ; Buffer is marked free if read barfs
+NORMSEC:
+        invoke  DREAD                   ; Buffer is marked free if read barfs
+GOTTHESEC:
+        POP     DX
+        POP     DI
+        POP     SI
+SETBUF:
+        MOV     [DI.BUFSECNO],DX
+        MOV     WORD PTR [DI.BUFDRVDP],BP
+        MOV     WORD PTR [DI.BUFDRVDP+2],ES
+        XOR     AH,AH
+        MOV     AL,ES:[BP.dpb_drive]
+        MOV     WORD PTR [DI.BUFDRV],AX
+SETINF:
+        MOV     AX,1                            ; Default to not a FAT sector
+        OR      SI,SI
+        JZ      SETSTUFFOK
+        MOV     AL,ES:[BP.dpb_FAT_count]
+        MOV     AH,ES:[BP.dpb_FAT_size]
+SETSTUFFOK:
+        MOV     WORD PTR [DI.BUFWRTCNT],AX
+        CALL    PLACEBUF
+JUSTBUF:
+        MOV     WORD PTR [CURBUF+2],DS
+        MOV     WORD PTR [LASTBUFFER+2],DS
+        PUSH    SS
+        POP     DS
+ASSUME  DS:DOSGROUP
+        MOV     WORD PTR [CURBUF],DI
+        MOV     WORD PTR [LASTBUFFER],DI
+        return
+GETBUFFR    ENDP
+
+
+SUBTTL FLUSHBUF -- WRITE OUT DIRTY BUFFERS
+PAGE
+        procedure   FlushBuf,NEAR
+ASSUME  DS:DOSGROUP,ES:NOTHING
+
+; Input:
+;       DS = DOSGROUP
+;       AL = Physical unit number
+;          = -1 for all units
+; Function:
+;       Write out all dirty buffers for unit, and flag them as clean
+; DS Preserved, all others destroyed (ES too)
+
+        LDS     DI,[BUFFHEAD]
+ASSUME  DS:NOTHING
+        MOV     AH,-1
+NXTBUFF:
+        CMP     [DI.BUFDRV],AH
+        JZ      SKIPBFF                 ; Skip free buffers
+        CMP     AH,AL
+        JZ      DOBUFFER                ; Do all dirty buffers
+        CMP     AL,[DI.BUFDRV]
+        JNZ     SKIPBFF                 ; Buffer not for this unit
+DOBUFFER:
+        CMP     BYTE PTR [DI.BUFDIRTY],0
+        JZ      SKIPBFF                 ; Buffer not dirty
+        PUSH    AX
+        PUSH    WORD PTR [DI.BUFDRV]
+        CALL    BUFWRITE
+        POP     AX
+        XOR     AH,AH                   ; Buffer is clean
+        CMP     AL,BYTE PTR [WPERR]
+        JNZ     NOZAP
+        MOV     AL,0FFH                 ; Invalidate buffer, it is inconsistent
+NOZAP:
+        MOV     WORD PTR [DI.BUFDRV],AX
+        POP     AX                      ; Search info
+SKIPBFF:
+        LDS     DI,[DI.NEXTBUF]
+        CMP     DI,-1
+        JNZ     NXTBUFF
+        PUSH    SS
+        POP     DS
+        return
+FlushBuf    ENDP
+
+
+SUBTTL BUFWRITE -- WRITE OUT A BUFFER IF DIRTY
+PAGE
+        procedure   BufWrite,NEAR
+ASSUME  DS:NOTHING,ES:NOTHING
+
+; Input:
+;       DS:DI Points to the buffer
+; Function:
+;       Write out all the buffer if dirty.
+; Output:
+;       Buffer marked free
+; DS:DI Preserved, ALL others destroyed (ES too)
+
+        MOV     AX,00FFH
+        XCHG    AX,WORD PTR [DI.BUFDRV] ; Free, in case write barfs
+        CMP     AL,0FFH
+        retz                            ; Buffer is free.
+        OR      AH,AH
+        retz                            ; Buffer is clean.
+        CMP     AL,BYTE PTR [WPERR]
+        retz                            ; If in WP error zap buffer
+        LES     BP,[DI.BUFDRVDP]
+        LEA     BX,[DI.BufInSiz]        ; Point at buffer
+        MOV     DX,[DI.BUFSECNO]
+        MOV     CX,WORD PTR [DI.BUFWRTCNT]
+        MOV     AL,CH                   ; [DI.BUFWRTINC]
+        XOR     CH,CH
+        MOV     AH,CH
+        PUSH    DI
+WRTAGAIN:
+        PUSH    CX
+        PUSH    AX
+        MOV     CX,1
+        PUSH    BX
+        PUSH    DX
+        invoke  DWRITE          ; Write out the dirty buffer
+        POP     DX
+        POP     BX
+        POP     AX
+        POP     CX
+        ADD     DX,AX
+        LOOP    WRTAGAIN
+        POP     DI
+        return
+BufWrite    ENDP
+
+do_ext
+
+CODE    ENDS
+    END
diff --git a/v2.0/source/CHKDSK.ASM b/v2.0/source/CHKDSK.ASM
new file mode 100644 (file)
index 0000000..c305a1d
--- /dev/null
@@ -0,0 +1,901 @@
+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
diff --git a/v2.0/source/CHKMES.ASM b/v2.0/source/CHKMES.ASM
new file mode 100644 (file)
index 0000000..83af5ba
--- /dev/null
@@ -0,0 +1,477 @@
+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
diff --git a/v2.0/source/CHKPROC.ASM b/v2.0/source/CHKPROC.ASM
new file mode 100644 (file)
index 0000000..b003f83
--- /dev/null
@@ -0,0 +1,1408 @@
+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
diff --git a/v2.0/source/COMEQU.ASM b/v2.0/source/COMEQU.ASM
new file mode 100644 (file)
index 0000000..81763fb
--- /dev/null
@@ -0,0 +1,33 @@
+;*************************************
+; COMMAND EQUs which are not switch dependant
+
+IFDEF   IBM
+        INCLUDE IFEQU.ASM
+ENDIF
+
+
+SYM     EQU     ">"
+
+LINPERPAG       EQU     23
+NORMPERLIN      EQU     1
+WIDEPERLIN      EQU     5
+COMBUFLEN       EQU     128     ; Length of commmand buffer
+
+DRVCHAR         EQU     ":"
+
+FCB     EQU     5CH
+
+VARSTRUC        STRUC
+ISDIR   DB      ?
+SIZ     DB      ?
+TTAIL   DW      ?
+INFO    DB      ?
+BUF     DB      DIRSTRLEN + 20 DUP (?)
+VARSTRUC        ENDS
+
+WSWITCH EQU     1               ; Wide display during DIR
+PSWITCH EQU     2               ; Pause (or Page) mode during DIR
+ASWITCH EQU     4               ; ASCII mode during COPY
+BSWITCH EQU     8               ; Binary mode during COPY
+VSWITCH EQU     10H             ; Verify switch
+GOTSWITCH EQU   8000H           ; Meta switch set if switch character encountered
diff --git a/v2.0/source/COMLINK b/v2.0/source/COMLINK
new file mode 100644 (file)
index 0000000..f7dd961
Binary files /dev/null and b/v2.0/source/COMLINK differ
diff --git a/v2.0/source/COMMAND.ASM b/v2.0/source/COMMAND.ASM
new file mode 100644 (file)
index 0000000..db2783a
--- /dev/null
@@ -0,0 +1,788 @@
+;\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
diff --git a/v2.0/source/COMSEG.ASM b/v2.0/source/COMSEG.ASM
new file mode 100644 (file)
index 0000000..81ab3c8
--- /dev/null
@@ -0,0 +1,38 @@
+; The following are all of the segments used in the load order
+
+CODERES SEGMENT PUBLIC
+CODERES ENDS
+
+DATARES SEGMENT PUBLIC
+DATARES ENDS
+
+ENVIRONMENT SEGMENT PUBLIC
+ENVIRONMENT ENDS
+
+INIT    SEGMENT PUBLIC
+INIT    ENDS
+
+TAIL    SEGMENT PUBLIC
+TAIL    ENDS
+
+TRANCODE        SEGMENT PUBLIC
+TRANCODE        ENDS
+
+TRANDATA        SEGMENT PUBLIC
+TRANDATA        ENDS
+
+TRANSPACE       SEGMENT PUBLIC
+TRANSPACE       ENDS
+
+TRANTAIL        SEGMENT PUBLIC
+TRANTAIL        ENDS
+
+ZEXEC_CODE      SEGMENT PUBLIC
+ZEXEC_CODE      ENDS
+
+ZEXEC_DATA      SEGMENT PUBLIC
+ZEXEC_DATA      ENDS
+
+RESGROUP        GROUP   CODERES,DATARES,ENVIRONMENT,INIT,TAIL
+TRANGROUP       GROUP   TRANCODE,TRANDATA,TRANSPACE,TRANTAIL
+EGROUP          GROUP   ZEXEC_CODE,ZEXEC_DATA
diff --git a/v2.0/source/COMSW.ASM b/v2.0/source/COMSW.ASM
new file mode 100644 (file)
index 0000000..830585f
--- /dev/null
@@ -0,0 +1,13 @@
+; 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
diff --git a/v2.0/source/CONFIG.txt b/v2.0/source/CONFIG.txt
new file mode 100644 (file)
index 0000000..bfb1985
Binary files /dev/null and b/v2.0/source/CONFIG.txt differ
diff --git a/v2.0/source/COPY.ASM b/v2.0/source/COPY.ASM
new file mode 100644 (file)
index 0000000..0456a4f
--- /dev/null
@@ -0,0 +1,579 @@
+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
diff --git a/v2.0/source/COPYPROC.ASM b/v2.0/source/COPYPROC.ASM
new file mode 100644 (file)
index 0000000..f6e3bb1
--- /dev/null
@@ -0,0 +1,526 @@
+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
diff --git a/v2.0/source/CPARSE.ASM b/v2.0/source/CPARSE.ASM
new file mode 100644 (file)
index 0000000..967efaa
--- /dev/null
@@ -0,0 +1,291 @@
+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
diff --git a/v2.0/source/CTRLC.ASM b/v2.0/source/CTRLC.ASM
new file mode 100644 (file)
index 0000000..054903d
--- /dev/null
@@ -0,0 +1,468 @@
+;
+; ^C status routines for MSDOS
+;
+
+INCLUDE DOSSEG.ASM
+
+CODE    SEGMENT BYTE PUBLIC  'CODE'
+        ASSUME  SS:DOSGROUP,CS:DOSGROUP
+
+.xlist
+.xcref
+INCLUDE DOSSYM.ASM
+INCLUDE DEVSYM.ASM
+.cref
+.list
+
+        i_need  DevIOBuf,BYTE
+        i_need  DidCTRLC,BYTE
+        i_need  INDOS,BYTE
+        i_need  DSKSTCOM,BYTE
+        i_need  DSKSTCALL,BYTE
+        i_need  DSKSTST,WORD
+        i_need  BCON,DWORD
+        i_need  DSKCHRET,BYTE
+        i_need  DSKSTCNT,WORD
+        i_need  IDLEINT,BYTE
+        i_need  CONSWAP,BYTE
+        i_need  user_SS,WORD
+        i_need  user_SP,WORD
+        i_need  ERRORMODE,BYTE
+        i_need  ConC_spSave,WORD
+        i_need  Exit_type,BYTE
+        i_need  PFLAG,BYTE
+        i_need  ExitHold,DWORD
+        i_need  WPErr,BYTE
+        i_need  ReadOp,BYTE
+        i_need  CONTSTK,WORD
+        i_need  Exit_Code,WORD
+        i_need  CurrentPDB,WORD
+        i_need  DIVMES,BYTE
+        i_need  DivMesLen,BYTE
+
+SUBTTL Checks for ^C in CON I/O
+PAGE
+ASSUME  DS:NOTHING,ES:NOTHING
+
+        procedure   DSKSTATCHK,NEAR ; Check for ^C if only one level in
+        CMP     BYTE PTR [INDOS],1
+        retnz                   ; Do NOTHING
+        PUSH    CX
+        PUSH    ES
+        PUSH    BX
+        PUSH    DS
+        PUSH    SI
+        PUSH    CS
+        POP     ES
+        PUSH    CS
+        POP     DS
+ASSUME  DS:DOSGROUP
+        XOR     CX,CX
+        MOV     BYTE PTR [DSKSTCOM],DEVRDND
+        MOV     BYTE PTR [DSKSTCALL],DRDNDHL
+        MOV     [DSKSTST],CX
+        MOV     BX,OFFSET DOSGROUP:DSKSTCALL
+        LDS     SI,[BCON]
+ASSUME  DS:NOTHING
+        invoke  DEVIOCALL2
+        TEST    [DSKSTST],STBUI
+        JNZ     ZRET                    ; No characters available
+        MOV     AL,BYTE PTR [DSKCHRET]
+DSK1:
+        CMP     AL,"C"-"@"
+        JNZ     RET36
+        MOV     BYTE PTR [DSKSTCOM],DEVRD
+        MOV     BYTE PTR [DSKSTCALL],DRDWRHL
+        MOV     BYTE PTR [DSKCHRET],CL
+        MOV     [DSKSTST],CX
+        INC     CX
+        MOV     [DSKSTCNT],CX
+        invoke  DEVIOCALL2              ; Eat the ^C
+        POP     SI
+        POP     DS
+        POP     BX                      ; Clean stack
+        POP     ES
+        POP     CX
+        JMP     SHORT CNTCHAND
+
+ZRET:
+        XOR     AL,AL                   ; Set zero
+RET36:
+        POP     SI
+        POP     DS
+        POP     BX
+        POP     ES
+        POP     CX
+        return
+
+NOSTOP:
+        CMP     AL,"P"-"@"
+        JZ      INCHK
+
+        IF      NOT TOGLPRN
+        CMP     AL,"N"-"@"
+        JZ      INCHK
+        ENDIF
+
+        CMP     AL,"C"-"@"
+        JZ      INCHK
+        return
+DSKSTATCHK  ENDP
+
+        procedure   SPOOLINT,NEAR
+        PUSHF
+        CMP     BYTE PTR [IDLEINT],0
+        JZ      POPFRET
+        CMP     BYTE PTR [ERRORMODE],0
+        JNZ     POPFRET                 ;No spool ints in error mode
+        INT     int_spooler
+POPFRET:
+        POPF
+RET18:  return
+SPOOLINT    ENDP
+
+        procedure   STATCHK,NEAR
+
+        invoke  DSKSTATCHK              ; Allows ^C to be detected under
+                                        ; input redirection
+        PUSH    BX
+        XOR     BX,BX
+        invoke  GET_IO_FCB
+        POP     BX
+        JC      RET18
+        MOV     AH,1
+        invoke  IOFUNC
+        JZ      SPOOLINT
+        CMP     AL,'S'-'@'
+        JNZ     NOSTOP
+        XOR     AH,AH
+        invoke  IOFUNC                  ; Eat Cntrl-S
+        JMP     SHORT PAUSOSTRT
+PRINTOFF:
+PRINTON:
+        NOT     BYTE PTR [PFLAG]
+        return
+
+PAUSOLP:
+        CALL    SPOOLINT
+PAUSOSTRT:
+        MOV     AH,1
+        invoke  IOFUNC
+        JZ      PAUSOLP
+INCHK:
+        PUSH    BX
+        XOR     BX,BX
+        invoke  GET_IO_FCB
+        POP     BX
+        JC      RET18
+        XOR     AH,AH
+        invoke  IOFUNC
+        CMP     AL,'P'-'@'
+        JZ      PRINTON
+        IF      NOT TOGLPRN
+        CMP     AL,'N'-'@'
+        JZ      PRINTOFF
+        ENDIF
+        CMP     AL,'C'-'@'
+        retnz
+STATCHK ENDP
+
+        procedure   CNTCHAND,NEAR
+; Ctrl-C handler.
+; "^C" and CR/LF is printed.  Then the user registers are restored and
+; the user CTRL-C handler is executed.  At this point the top of the stack
+; has 1) the interrupt return address should the user CTRL-C handler wish
+; to allow processing to continue; 2) the original interrupt return address
+; to the code that performed the function call in the first place.  If
+; the user CTRL-C handler wishes to continue, it must leave all registers
+; unchanged and RET (not IRET) with carry CLEAR.  If carry is SET then
+; an terminate system call is simulated.
+        MOV     AL,3                ; Display "^C"
+        invoke  BUFOUT
+        invoke  CRLF
+        PUSH    SS
+        POP     DS
+ASSUME  DS:DOSGROUP
+        CMP     BYTE PTR [CONSWAP],0
+        JZ      NOSWAP
+        invoke  SWAPBACK
+NOSWAP:
+        CLI                         ; Prepare to play with stack
+        MOV     SP,[user_SP]
+        MOV     SS,[user_SS]        ; User stack now restored
+ASSUME  SS:NOTHING
+        invoke  restore_world       ; User registers now restored
+ASSUME  DS:NOTHING
+        MOV     BYTE PTR [INDOS],0  ; Go to known state
+        MOV     BYTE PTR [ERRORMODE],0
+        MOV     [ConC_spsave],SP    ; save his SP
+        INT     int_ctrl_c          ; Execute user Ctrl-C handler
+        MOV     [user_SS],AX        ; save the AX
+        PUSHF                       ; and the flags (maybe new call)
+        POP     AX
+        CMP     SP,[ConC_spsave]
+        JNZ     ctrlc_try_new       ; new syscall maybe?
+ctrlc_repeat:
+        MOV     AX,[user_SS]        ; no...
+        transfer    COMMAND         ; Repeat command otherwise
+
+ctrlc_try_new:
+        SUB     [ConC_spsave],2     ; Are there flags on the stack?
+        CMP     SP,[ConC_spsave]
+        JZ      ctrlc_new           ; yes, new system call
+
+ctrlc_abort:
+        MOV     AX,(EXIT SHL 8) + 0
+        MOV     BYTE PTR [DidCTRLC],0FFh
+
+        transfer    COMMAND         ; give up by faking $EXIT
+
+ctrlc_new:
+        PUSH    AX
+        POPF
+        POP     [user_SS]
+        JNC     ctrlc_repeat        ; repeat operation
+        JMP     ctrlc_abort         ; indicate ^ced
+
+CNTCHAND ENDP
+
+SUBTTL DIVISION OVERFLOW INTERRUPT
+PAGE
+; Default handler for division overflow trap
+        procedure   DIVOV,NEAR
+ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING
+        MOV     SI,OFFSET DOSGROUP:DIVMES
+        CALL    RealDivOv
+        JMP     ctrlc_abort     ; Use Ctrl-C abort on divide overflow
+DIVOV   ENDP
+
+;
+; RealDivOv: perform actual divide overflow stuff.
+; Inputs:   none
+; Outputs:  message to BCON
+;
+        procedure   RealDivOv,NEAR  ; Do divide overflow and clock process
+
+        PUSH    CS                  ; get ES addressability
+        POP     ES
+
+        PUSH    CS                  ; get DS addressability
+        POP     DS
+ASSUME  DS:DOSGROUP
+
+        MOV     BYTE PTR [DskStCom],DevWrt
+        MOV     BYTE PTR [DskStCall],DRdWrHL
+        MOV     [DskSTST],0
+        MOV     BL,[DivMesLen]
+        XOR     BH,BH
+        MOV     [DskStCnt],BX
+        MOV     BX,OFFSET DOSGROUP:DskStCall
+        MOV     WORD PTR [DskChRet+1],SI    ; transfer address (need an EQU)
+        LDS     SI,[BCON]
+ASSUME  DS:NOTHING
+        invoke  DEVIOCALL2
+        MOV     WORD PTR [DskChRet+1],OFFSET DOSGROUP:DevIOBuf
+        MOV     [DskStCnt],1
+        return
+RealDivOv   ENDP
+
+SUBTTL CHARHRD,HARDERR,ERROR -- HANDLE DISK ERRORS AND RETURN TO USER
+PAGE
+        procedure   CHARHARD,NEAR
+ASSUME  DS:NOTHING,ES:NOTHING,SS:DOSGROUP
+
+; Character device error handler
+; Same function as HARDERR
+
+        MOV     WORD PTR [EXITHOLD+2],ES
+        MOV     WORD PTR [EXITHOLD],BP
+        PUSH    SI
+        AND     DI,STECODE
+        MOV     BP,DS                   ;Device pointer is BP:SI
+        CALL    FATALC
+        POP     SI
+        return
+CHARHARD    ENDP
+
+        procedure   HardErr,NEAR
+ASSUME  DS:NOTHING,ES:NOTHING
+
+; Hard disk error handler. Entry conditions:
+;       DS:BX = Original disk transfer address
+;       DX = Original logical sector number
+;       CX = Number of sectors to go (first one gave the error)
+;       AX = Hardware error code
+;       DI = Original sector transfer count
+;       ES:BP = Base of drive parameters
+;       [READOP] = 0 for read, 1 for write
+                                        ;
+        XCHG    AX,DI                   ; Error code in DI, count in AX
+        AND     DI,STECODE              ; And off status bits
+        CMP     DI,WRECODE              ; Write Protect Error?
+        JNZ     NOSETWRPERR
+        PUSH    AX
+        MOV     AL,ES:[BP.dpb_drive]
+        MOV     BYTE PTR [WPERR],AL              ; Flag drive with WP error
+        POP     AX
+NOSETWRPERR:
+        SUB     AX,CX                   ; Number of sectors successfully transferred
+        ADD     DX,AX                   ; First sector number to retry
+        PUSH    DX
+        MUL     ES:[BP.dpb_sector_size]          ; Number of bytes transferred
+        POP     DX
+        ADD     BX,AX                   ; First address for retry
+        XOR     AH,AH                   ; Flag disk section in error
+        CMP     DX,ES:[BP.dpb_first_FAT]    ; In reserved area?
+        JB      ERRINT
+        INC     AH                      ; Flag for FAT
+        CMP     DX,ES:[BP.dpb_dir_sector]   ; In FAT?
+        JB      ERRINT
+        INC     AH
+        CMP     DX,ES:[BP.dpb_first_sector]       ; In directory?
+        JB      ERRINT
+        INC     AH                      ; Must be in data area
+ERRINT:
+        SHL     AH,1                    ; Make room for read/write bit
+        OR      AH,BYTE PTR [READOP]
+        entry   FATAL
+        MOV     AL,ES:[BP.dpb_drive]      ; Get drive number
+        entry   FATAL1
+        MOV     WORD PTR [EXITHOLD+2],ES
+        MOV     WORD PTR [EXITHOLD],BP  ; The only things we preserve
+        LES     SI,ES:[BP.dpb_driver_addr]
+        MOV     BP,ES                   ; BP:SI points to the device involved
+FATALC:
+        CMP     BYTE PTR [ERRORMODE],0
+        JNZ     SETIGN                  ; No INT 24s if already INT 24
+        MOV     [CONTSTK],SP
+        PUSH    SS
+        POP     ES
+ASSUME  ES:DOSGROUP
+        CLI                             ; Prepare to play with stack
+        INC     BYTE PTR [ERRORMODE]    ; Flag INT 24 in progress
+        DEC     BYTE PTR [INDOS]        ; INT 24 handler might not return
+        MOV     SS,[user_SS]
+ASSUME  SS:NOTHING
+        MOV     SP,ES:[user_SP]         ; User stack pointer restored
+        INT     int_fatal_abort         ; Fatal error interrupt vector, must preserve ES
+        MOV     ES:[user_SP],SP         ; restore our stack
+        MOV     ES:[user_SS],SS
+        MOV     SP,ES
+        MOV     SS,SP
+ASSUME  SS:DOSGROUP
+        MOV     SP,[CONTSTK]
+        INC     BYTE PTR [INDOS]        ; Back in the DOS
+        MOV     BYTE PTR [ERRORMODE],0  ; Back from INT 24
+        STI
+IGNRET:
+        LES     BP,[EXITHOLD]
+ASSUME  ES:NOTHING
+        CMP     AL,2
+        JZ      error_abort
+        MOV     BYTE PTR [WPERR],-1              ;Forget about WP error
+        return
+
+SETIGN:
+        XOR     AL,AL                   ;Flag ignore
+        JMP     SHORT IGNRET
+
+error_abort:
+        PUSH    SS
+        POP     DS
+ASSUME  DS:DOSGROUP
+        CMP     BYTE PTR [CONSWAP],0
+        JZ      NOSWAP2
+        invoke  SWAPBACK
+NOSWAP2:
+        MOV     BYTE PTR [exit_Type],Exit_hard_error
+        MOV     DS,[CurrentPDB]
+ASSUME  DS:NOTHING
+
+;
+; reset_environment checks the DS value against the CurrentPDB.  If they
+; are different, then an old-style return is performed.  If they are
+; the same, then we release jfns and restore to parent.  We still use
+; the PDB at DS:0 as the source of the terminate addresses.
+;
+; output:   none.
+;
+        entry   reset_environment
+        ASSUME  DS:NOTHING,ES:NOTHING
+        PUSH    DS                      ; save PDB of process
+
+        MOV     AL,int_Terminate
+        invoke  $Get_interrupt_vector   ; and who to go to
+        MOV     WORD PTR [EXITHOLD+2],ES ; save return address
+        MOV     WORD PTR [EXITHOLD],BX
+
+        MOV     BX,[CurrentPDB]         ; get current process
+        MOV     DS,BX                   ;
+        MOV     AX,DS:[PDB_Parent_PID]  ; get parent to return to
+        POP     CX
+;
+; AX = parentPDB, BX = CurrentPDB, CX = ThisPDB
+; Only free handles if AX <> BX and BX = CX and [exit_code].upper is not
+; Exit_keep_process
+;
+        CMP     AX,BX
+        JZ      reset_return            ; parentPDB = CurrentPDB
+        CMP     BX,CX
+        JNZ     reset_return            ; CurrentPDB <> ThisPDB
+        PUSH    AX                      ; save parent
+        CMP     BYTE PTR [exit_type],Exit_keep_process
+        JZ      reset_to_parent         ; keeping this process
+
+        invoke  arena_free_process
+
+        ; reset environment at [CurrentPDB]; close those handles
+        MOV     CX,FilPerProc
+
+reset_free_jfn:
+        MOV     BX,CX
+        PUSH    CX
+        DEC     BX                      ; get jfn
+        invoke  $CLOSE                  ; close it, ignore return
+        POP     CX
+        LOOP    reset_free_jfn          ; and do 'em all
+
+reset_to_parent:
+        POP     [CurrentPDB]            ; set up process as parent
+
+reset_return:                           ; come here for normal return
+        PUSH    CS
+        POP     DS
+        ASSUME  DS:DOSGROUP
+        MOV     AL,-1
+        invoke  FLUSHBUF                ; make sure that everything is clean
+
+        CLI
+        MOV     BYTE PTR [INDOS],0               ;Go to known state
+        MOV     BYTE PTR [WPERR],-1              ;Forget about WP error
+;
+; Snake into multitasking... Get stack from CurrentPDB person
+;
+        MOV     DS,[CurrentPDB]
+        ASSUME  DS:NOTHING
+        MOV     SS,WORD PTR DS:[PDB_user_stack+2]
+        MOV     SP,WORD PTR DS:[PDB_user_stack]
+
+        ASSUME  SS:NOTHING
+        invoke  restore_world
+        ASSUME  ES:NOTHING
+        POP     AX                      ; suck off CS:IP of interrupt...
+        POP     AX
+        POP     AX
+        MOV     AX,0F202h               ; STI
+        PUSH    AX
+        PUSH    WORD PTR [EXITHOLD+2]
+        PUSH    WORD PTR [EXITHOLD]
+        STI
+        IRET            ; Long return back to user terminate address
+HardErr ENDP
+
+        ASSUME  SS:DOSGROUP
+
+do_ext
+
+CODE    ENDS
+    END
diff --git a/v2.0/source/DEBASM.ASM b/v2.0/source/DEBASM.ASM
new file mode 100644 (file)
index 0000000..a0fb0db
--- /dev/null
@@ -0,0 +1,1264 @@
+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
diff --git a/v2.0/source/DEBCOM1.ASM b/v2.0/source/DEBCOM1.ASM
new file mode 100644 (file)
index 0000000..8e992d9
--- /dev/null
@@ -0,0 +1,694 @@
+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
diff --git a/v2.0/source/DEBCOM2.ASM b/v2.0/source/DEBCOM2.ASM
new file mode 100644 (file)
index 0000000..a800d4b
--- /dev/null
@@ -0,0 +1,1269 @@
+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
diff --git a/v2.0/source/DEBCONST.ASM b/v2.0/source/DEBCONST.ASM
new file mode 100644 (file)
index 0000000..e8f8c35
--- /dev/null
@@ -0,0 +1,1103 @@
+.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
diff --git a/v2.0/source/DEBDATA.ASM b/v2.0/source/DEBDATA.ASM
new file mode 100644 (file)
index 0000000..fbe4a3f
Binary files /dev/null and b/v2.0/source/DEBDATA.ASM differ
diff --git a/v2.0/source/DEBEQU.ASM b/v2.0/source/DEBEQU.ASM
new file mode 100644 (file)
index 0000000..5a20f01
--- /dev/null
@@ -0,0 +1,32 @@
+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
diff --git a/v2.0/source/DEBMES.ASM b/v2.0/source/DEBMES.ASM
new file mode 100644 (file)
index 0000000..791b2e5
Binary files /dev/null and b/v2.0/source/DEBMES.ASM differ
diff --git a/v2.0/source/DEBUASM.ASM b/v2.0/source/DEBUASM.ASM
new file mode 100644 (file)
index 0000000..6a53124
--- /dev/null
@@ -0,0 +1,868 @@
+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
diff --git a/v2.0/source/DEBUG.ASM b/v2.0/source/DEBUG.ASM
new file mode 100644 (file)
index 0000000..91db1ca
--- /dev/null
@@ -0,0 +1,838 @@
+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
diff --git a/v2.0/source/DEV.ASM b/v2.0/source/DEV.ASM
new file mode 100644 (file)
index 0000000..b640d55
--- /dev/null
@@ -0,0 +1,439 @@
+;\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
diff --git a/v2.0/source/DEVDRIV.txt b/v2.0/source/DEVDRIV.txt
new file mode 100644 (file)
index 0000000..3c82793
--- /dev/null
@@ -0,0 +1,802 @@
+                  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
diff --git a/v2.0/source/DEVSYM.ASM b/v2.0/source/DEVSYM.ASM
new file mode 100644 (file)
index 0000000..b648f04
Binary files /dev/null and b/v2.0/source/DEVSYM.ASM differ
diff --git a/v2.0/source/DIR.ASM b/v2.0/source/DIR.ASM
new file mode 100644 (file)
index 0000000..d0bb84f
--- /dev/null
@@ -0,0 +1,1084 @@
+;\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
diff --git a/v2.0/source/DIRCALL.ASM b/v2.0/source/DIRCALL.ASM
new file mode 100644 (file)
index 0000000..db55ab8
--- /dev/null
@@ -0,0 +1,507 @@
+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
diff --git a/v2.0/source/DISK.ASM b/v2.0/source/DISK.ASM
new file mode 100644 (file)
index 0000000..b1acd82
--- /dev/null
@@ -0,0 +1,1302 @@
+;\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
diff --git a/v2.0/source/DISKCOPY.ASM b/v2.0/source/DISKCOPY.ASM
new file mode 100644 (file)
index 0000000..56e39cb
Binary files /dev/null and b/v2.0/source/DISKCOPY.ASM differ
diff --git a/v2.0/source/DISKMES.ASM b/v2.0/source/DISKMES.ASM
new file mode 100644 (file)
index 0000000..d5f0226
Binary files /dev/null and b/v2.0/source/DISKMES.ASM differ
diff --git a/v2.0/source/DOSLINK b/v2.0/source/DOSLINK
new file mode 100644 (file)
index 0000000..9d56841
--- /dev/null
@@ -0,0 +1,5 @@
+msdos mscode dosmes misc getset dircall alloc dev dir +
+disk fat rom stdbuf stdcall stdctrlc stdfcb stdproc +
+stdio time xenix xenix2;
+
+\1a
\ No newline at end of file
diff --git a/v2.0/source/DOSMAC.ASM b/v2.0/source/DOSMAC.ASM
new file mode 100644 (file)
index 0000000..35c16f1
Binary files /dev/null and b/v2.0/source/DOSMAC.ASM differ
diff --git a/v2.0/source/DOSMAC_v211.ASM b/v2.0/source/DOSMAC_v211.ASM
new file mode 100644 (file)
index 0000000..3340505
--- /dev/null
@@ -0,0 +1,274 @@
+;
+; Macro file for MSDOS.
+;
+
+SUBTTL BREAK a listing into pages and give new subtitles
+PAGE
+BREAK MACRO subtitle
+ SUBTTL subtitle
+ PAGE
+ENDM
+
+BREAK <I_NEED: declare a variable external, if necessary, and allocate a size>
+
+;
+; declare a variable external and allocate a size
+;
+I_NEED MACRO sym,len
+ DATA SEGMENT BYTE PUBLIC 'DATA'
+ IFIDN <len>,<WORD>
+ EXTRN &sym:WORD
+ ELSE
+ IFIDN <len>,<DWORD>
+ EXTRN &sym:DWORD
+ ELSE
+ EXTRN &sym:BYTE
+ ENDIF
+ ENDIF
+ DATA ENDS
+ENDM
+
+;
+; call a procedure that may be external. The call will be short.
+;
+invoke MACRO name
+.xcref
+ IF2
+ IFNDEF name
+ EXTRN name:NEAR
+ ENDIF
+ ENDIF
+.cref
+ CALL name
+ENDM
+
+PAGE
+;
+; jump to a label that may be external. The jump will be near.
+;
+transfer MACRO name
+.xcref
+ IF2
+ IFNDEF name
+ EXTRN name:NEAR
+ ENDIF
+ ENDIF
+.cref
+ JUMP name
+ENDM
+
+;
+; get a short address in a word
+;
+short_addr MACRO name
+ IFDIF <name>,<?>
+.xcref
+ IF2
+ IFNDEF name
+ EXTRN name:NEAR
+ ENDIF
+ ENDIF
+.cref
+ DW OFFSET DOSGROUP:name
+ ELSE
+ DW ?
+ ENDIF
+ENDM
+
+;
+; get a long address in a dword
+;
+long_addr MACRO name
+.xcref
+ IF2
+ IFNDEF name
+ EXTRN name:NEAR
+ ENDIF
+.cref
+ DD name
+ENDM
+
+;
+; declare a PROC near or far but PUBLIC nonetheless
+;
+procedure MACRO name,distance
+ PUBLIC name
+name PROC distance
+ENDM
+
+PAGE
+;
+; define a data item to be public and of an appropriate size/type
+;
+I_AM MACRO name,size
+ PUBLIC name
+
+ IFIDN <size>,<WORD>
+name DW ?
+ ELSE
+ IFIDN <size>,<DWORD>
+name DD ?
+ ELSE
+ IFIDN <size>,<BYTE>
+name DB ?
+ ELSE
+name DB size DUP (?)
+ ENDIF
+ ENDIF
+ ENDIF
+ENDM
+
+PAGE
+;
+; call the macro chain
+;
+do_ext macro
+endm
+
+PAGE
+
+;
+; define an entry in a procedure
+;
+entry macro name
+ PUBLIC name
+name:
+endm
+
+BREAK <ERROR - print a message and then jump to a label>
+
+error macro code
+ local a
+.xcref
+ MOV AL,code
+ transfer SYS_RET_ERR
+.cref
+ENDM
+
+BREAK <JUMP - real jump that links up shortwise>
+;
+; given a label <lbl> either 2 byte jump to another label <lbl>_J
+; if it is near enough or 3 byte jump to <lbl>
+;
+
+jump macro lbl
+ local a
+.xcref
+ a:
+ ifndef lbl&_J ;; is this the first invocation
+ JMP lbl
+ ELSE
+ IF lbl&_J GE $
+ JMP lbl
+ ELSE
+ IF ($-lbl&_J) GT 126 ;; is the jump too far away?
+ JMP lbl
+ ELSE ;; do the short one...
+ JMP lbl&_J
+ ENDIF
+ ENDIF
+ ENDIF
+ lbl&_j = a
+.cref
+endm
+
+BREAK <RETURN - return from a function>
+
+return macro
+ local a
+.xcref
+a:
+ RET
+ret_l = a
+.cref
+endm
+
+BREAK <CONDRET - conditional return>
+
+makelab macro l,cc,ncc
+ local a
+ j&ncc a ;; j<NCC> a:
+ return ;; return
+ a: ;; a:
+ ret_&cc = ret_l ;; define ret_<CC> to be ret_l
+endm
+
+condret macro cc,ncc
+ local a,b
+ ifdef ret_l ;; if ret_l is defined
+ if (($ - ret_l) le 126) and ($ gt ret_l)
+ ;; if ret_l is near enough then
+ a: j&cc ret_l ;; a: j<CC> to ret_l
+ ret_&cc = a ;; define ret_<CC> to be a:
+ else
+ makelab a,cc,ncc
+ endif
+ else
+ ifdef ret_&cc ;; if ret_<CC> defined
+ if (($ - ret_&cc) le 126) and ($ gt ret_&cc)
+ ;; if ret_<CC> is near enough
+ a: j&cc ret_&cc ;; a: j<CC> to ret_<CC>
+ ret_&cc = a ;; define ret_<CC> to be a:
+ else
+ makelab a,cc,ncc
+ endif
+ else
+ makelab a,cc,ncc
+ endif
+ endif
+endm
+;condret macro cc,ncc
+; local a,b
+; ifdef ret_l ; if ret_l is defined
+; if (($ - ret_l) le 126) and ($ gt ret_l)
+; ; if ret_l is near enough then
+; a: j&cc ret_l ; a: j<CC> to ret_l
+; ret_&cc = a ; define ret_<CC> to be a:
+; exitm
+; endif
+; endif
+; ifdef ret_&cc ; if ret_<CC> defined
+; if (($ - ret_&cc) le 126) and ($ gt ret_&cc)
+; ; if ret_<CC> is near enough
+; a: j&cc ret_&cc ; a: j<CC> to ret_<CC>
+; ret_&cc = a ; define ret_<CC> to be a:
+; exitm
+; endif
+; endif
+; j&ncc a ; j<NCC> a:
+; return ; return
+; a: ; a:
+; ret_&cc = ret_l ; define ret_<CC> to be ret_l
+;endm
+;
+BREAK <RETZ - return if zero, links up shortwise if necessary>
+
+retz macro
+ condret z,nz
+endm
+
+BREAK <RETNZ - return if not zero, links up shortwise if necessary>
+
+retnz macro
+ condret nz,z
+endm
+
+BREAK <RETC - return if carry set, links up shortwise if necessary>
+
+retc macro
+ condret c,nc
+endm
+
+BREAK <RETNC - return if not carry, links up shortwise if necessary>
+
+retnc macro
+ condret nc,c
+endm
+
+BREAK <CONTEXT - set the DOS context to a particular register>
+
+context macro r
+ PUSH SS
+ POP r
+ ASSUME r:DOSGROUP
+endm
diff --git a/v2.0/source/DOSMES.ASM b/v2.0/source/DOSMES.ASM
new file mode 100644 (file)
index 0000000..fb3f17a
--- /dev/null
@@ -0,0 +1,355 @@
+       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
diff --git a/v2.0/source/DOSSEG.ASM b/v2.0/source/DOSSEG.ASM
new file mode 100644 (file)
index 0000000..5d7e8c2
--- /dev/null
@@ -0,0 +1,17 @@
+;
+; segment ordering for MSDOS
+;
+
+CONSTANTS       SEGMENT BYTE PUBLIC 'CONST'
+CONSTANTS       ENDS
+
+DATA            SEGMENT BYTE PUBLIC 'DATA'
+DATA            ENDS
+
+CODE            SEGMENT BYTE PUBLIC 'CODE'
+CODE            ENDS
+
+LAST            SEGMENT BYTE PUBLIC 'LAST'
+LAST            ENDS
+
+DOSGROUP    GROUP   CODE,CONSTANTS,DATA,LAST
diff --git a/v2.0/source/DOSSYM.ASM b/v2.0/source/DOSSYM.ASM
new file mode 100644 (file)
index 0000000..918ed5d
--- /dev/null
@@ -0,0 +1,904 @@
+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
diff --git a/v2.0/source/DOSSYM_v211.ASM b/v2.0/source/DOSSYM_v211.ASM
new file mode 100644 (file)
index 0000000..106e115
--- /dev/null
@@ -0,0 +1,963 @@
+include DOSMAC.ASM
+IF2
+    %OUT    DOSSYM in Pass 2
+ENDIF
+
+IFNDEF  ALTVECT
+ALTVECT EQU     0       ;FALSE
+ENDIF
+
+DOS_MAJOR_VERSION   EQU      2
+DOS_MINOR_VERSION   EQU     11
+
+BREAK <Control character definitions>
+
+c_DEL       EQU     7Fh         ;    ASCII rubout or delete previous char
+c_BS        EQU     08h         ; ^H ASCII backspace
+c_CR        EQU     0Dh         ; ^M ASCII carriage return
+c_LF        EQU     0Ah         ; ^J ASCII linefeed
+c_ETB       EQU     17h         ; ^W ASCII end of transmission
+c_NAK       EQU     15h         ; ^U ASCII negative acknowledge
+c_ETX       EQU     03h         ; ^C ASCII end of text
+c_HT        EQU     09h         ; ^I ASCII tab
+
+BREAK <BPB Definition>
+
+
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+;                                                                          ;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;                                                                          ;
+; Certain structures, constants and system  calls  below  are  private  to ;
+; the DOS  and  are  extremely  version-dependent.  They may change at any ;
+; time at  the  implementors'  whim.   As  a  result,  they  must  not  be ;
+; documented to  the  general  public.   If  an  extreme case arises, they ;
+; must be documented with this warning.                                    ;
+;                                                                          ;
+; Those structures and constants that are subject to  the  above  will  be ;
+; marked and bracketed with the flag:                                      ;
+;                                                                          ;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;                                                                          ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+
+BREAK  <Bios Parameter Block>
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;                                                                          ;
+
+; Bios Parameter Block definition
+; This structure is used to build a full DPB
+
+BPBLOCK STRUC
+BPSECSZ DW      ?       ; Size in bytes of physical sector
+BPCLUS  DB      ?       ; Sectors/Alloc unit
+BPRES   DW      ?       ; Number of reserved sectors
+BPFTCNT DB      ?       ; Number of FATs
+BPDRCNT DW      ?       ; Number of directory entries
+BPSCCNT DW      ?       ; Total number of sectors
+BPMEDIA DB      ?       ; Media descriptor byte
+BPFTSEC DW      ?       ; Number of sectors taken up by one FAT
+BPBLOCK ENDS
+;                                                                          ;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+
+BREAK <Disk I/O Buffer Header>
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;                                                                          ;
+
+; Field definition for I/O buffer information
+
+BUFFINFO        STRUC
+NEXTBUF         DD      ?       ; Pointer to next buffer in list
+; The next two items are often refed as a word
+BUFDRV          DB      ?       ; Logical drive # assoc with buffer FF = free
+BUFDIRTY        DB      ?       ; Dirty flag
+BUFPRI          DB      ?       ; Buffer selection priority (see EQUs below)
+VISIT           DB      ?       ; Visit flag for buffer pool scans
+BUFSECNO        DW      ?       ; Sector number of buffer
+; The next two items are often refed as a word
+BUFWRTCNT       DB      ?       ; For FAT sectors, # times sector written out
+BUFWRTINC       DB      ?       ; "   "     "   , # sectors between each write
+BUFDRVDP        DD      ?       ; Pointer to drive parameters
+BUFFINFO        ENDS
+
+BUFINSIZ        EQU     SIZE BUFFINFO
+                                ; Size of structure in bytes
+
+FREEPRI EQU     0
+LBRPRI  EQU     2               ; Last byte of buffer read
+LBWPRI  EQU     4               ; Last byte written
+RPRI    EQU     6               ; Read but not last byte
+WPRI    EQU     8               ; Written but not last byte
+DIRPRI  EQU     15              ; Directory Sector
+FATPRI  EQU     30              ; FAT sector
+;                                                                          ;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+
+BREAK <User stack inside of system call>
+; Location of user registers relative user stack pointer
+
+user_environ    STRUC
+user_AX     DW      ?
+user_BX     DW      ?
+user_CX     DW      ?
+user_DX     DW      ?
+user_SI     DW      ?
+user_DI     DW      ?
+user_BP     DW      ?
+user_DS     DW      ?
+user_ES     DW      ?
+user_IP     DW      ?
+user_CS     DW      ?
+user_F      DW      ?
+user_environ    ENDS
+
+BREAK <interrupt definitions>
+
+INTTAB          EQU     20H
+INTBASE         EQU     4 * inttab
+ENTRYPOINT      EQU     INTBASE+40H
+
+        IF      ALTVECT
+ALTTAB  EQU     0F0H
+ALTBASE EQU     4 * ALTTAB
+        ENDIF
+
+;
+; interrupt assignments
+;
+        IF      NOT ALTVECT
+int_abort           EQU     INTTAB          ; abort process
+int_command         EQU     int_abort+1     ; call MSDOS
+int_terminate       EQU     int_abort+2     ; int to terminate address
+int_ctrl_c          EQU     int_abort+3     ; ^c trapper
+int_fatal_abort     EQU     int_abort+4     ; hard disk error
+int_disk_read       EQU     int_abort+5     ; logical sector disk read
+int_disk_write      EQU     int_abort+6     ; logical sector disk write
+int_keep_process    EQU     int_abort+7     ; terminate program and stay
+                                            ; resident
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;                                                                          ;
+int_spooler         EQU     int_abort+8     ; spooler call
+int_fastcon         EQU     int_abort+9     ; fast CON interrupt
+;                                                                          ;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+        ELSE
+int_abort           EQU     INTTAB          ; abort process
+int_command         EQU     int_abort+1     ; call MSDOS
+int_terminate       EQU     ALTTAB          ; int to terminate address
+int_ctrl_c          EQU     int_terminate+1 ; ^c trapper
+int_fatal_abort     EQU     int_terminate+2 ; hard disk error
+int_disk_read       EQU     int_abort+5     ; logical sector disk read
+int_disk_write      EQU     int_abort+6     ; logical sector disk write
+int_keep_process    EQU     int_abort+7     ; terminate program and stay
+                                            ; resident
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;                                                                          ;
+int_spooler         EQU     int_terminate+3 ; spooler call
+int_fastcon         EQU     int_abort+9     ; fast CON interrupt
+;                                                                          ;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+        ENDIF
+
+addr_int_abort          EQU    4 * int_abort
+addr_int_command        EQU    4 * int_command
+addr_int_terminate      EQU    4 * int_terminate
+addr_int_ctrl_c         EQU    4 * int_ctrl_c
+addr_int_fatal_abort    EQU    4 * int_fatal_abort
+addr_int_disk_read      EQU    4 * int_disk_read
+addr_int_disk_write     EQU    4 * int_disk_write
+addr_int_keep_process   EQU    4 * int_keep_process
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;                                                                          ;
+addr_int_spooler        EQU    4 * int_spooler
+addr_int_fastcon        EQU    4 * int_fastcon
+;                                                                          ;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+
+BREAK <Disk map>
+;  MSDOS partitions the disk into 4 sections:
+;
+;  phys sector 0:   +-------------------+
+;       |           | boot/reserved     |
+;       |           +-------------------+
+;       |           |  File allocation  |
+;       v           |      table(s)     |
+;                   |  (multiple copies |
+;                   |     are kept)     |
+;                   +-------------------+
+;                   |     Directory     |
+;                   +-------------------+
+;                   |     File space    |
+;                   +-------------------+
+;                   |   Unaddressable   |
+;                   |  (to end of disk) |
+;                   +-------------------+
+;
+; All partition boundaries are sector boundaries.  The size of the FAT is
+; adjusted to maximize the file space addressable.
+
+BREAK <Directory entry>
+
+;
+;       +---------------------------+
+;       |  (12 BYTE) filename/ext   |       0       0
+;       +---------------------------+
+;       |     (BYTE) attributes     |       11      B
+;       +---------------------------+
+;       |    (10 BYTE) reserved     |       12      C
+;       +---------------------------+
+;       | (WORD) time of last write |       22      16
+;       +---------------------------+
+;       | (WORD) date of last write |       24      18
+;       +---------------------------+
+;       |   (WORD) First cluster    |       26      1A
+;       +---------------------------+
+;       |     (DWORD) file size     |       28      1C
+;       +---------------------------+
+;
+;   First byte of filename  = E5 -> free directory entry
+;                           = 00 -> end of allocated directory
+;   Time:   Bits 0-4=seconds/2, bits 5-10=minute, 11-15=hour
+;   Date:   Bits 0-4=day, bits 5-8=month, bits 9-15=year-1980
+;
+dir_entry   STRUC
+dir_name    DB      11 DUP (?)          ; file name
+dir_attr    DB      ?                   ; attribute bits
+dir_pad     DB      10 DUP (?)          ; reserved for expansion
+dir_time    DW      ?                   ; time of last write
+dir_date    DW      ?                   ; date of last write
+dir_first   DW      ?                   ; first allocation unit of file
+dir_size_l  DW      ?                   ; low 16 bits of file size
+dir_size_h  DW      ?                   ; high 16 bits of file size
+dir_entry   ENDS
+
+attr_read_only      EQU      1h
+attr_hidden         EQU      2h
+attr_system         EQU      4h
+attr_volume_id      EQU      8h
+attr_directory      EQU     10h
+attr_archive        EQU     20h
+
+attr_all            EQU     attr_hidden+attr_system+attr_directory
+                                        ; OR of hard attributes for FINDENTRY
+
+attr_ignore         EQU     attr_read_only+attr_archive
+                                        ; ignore this(ese) attribute(s) during
+                                        ; search first/next
+
+attr_changeable     EQU     attr_read_only+attr_hidden+attr_system+attr_archive
+                                        ; changeable via CHMOD
+
+BREAK <File allocation Table information>
+;
+; The File Allocation Table uses a 12-bit entry for each allocation unit on
+; the disk.  These entries are packed, two for every three bytes.  The contents
+; of entry number N is found by 1) multiplying N by 1.5; 2) adding the result
+; to the base address of the Allocation Table; 3) fetching the 16-bit word
+; at this address; 4) If N was odd (so that N*1.5 was not an integer), shift
+; the word right four bits; 5) mask to 12 bits (AND with 0FFF hex).  Entry
+; number zero is used as an end-of-file trap in the OS and is passed to the
+; BIOS to help determine disk format.  Entry 1 is reserved for future use.
+; The first available allocation unit is assigned entry number two, and even
+; though it is the first, is called cluster 2.  Entries greater than 0FF8H
+; are end of file marks; entries of zero are unallocated.  Otherwise, the
+; contents of a FAT entry is the number of the next cluster in the file.
+;
+; Clusters with bad sectors are tagged with FF7H.  Any non-zero number would
+; do because these clusters show as allocated, but are not part of any
+; allocation chain and thus will never be allocated to a file.  A particular
+; number is selected so that disk checking programs know what to do (ie.  a
+; cluster with entry FF7H which is not in a chain is not an error).
+
+BREAK <DPB structure>
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;                                                                          ;
+
+DIRSTRLEN       EQU     64      ; Max length in bytes of directory strings
+
+dpb     STRUC
+dpb_drive           DB      ?   ; Logical drive # assoc with DPB (A=0,B=1,...)
+dpb_UNIT            DB      ?   ; Driver unit number of DPB
+dpb_sector_size     DW      ?   ; Size of physical sector in bytes
+dpb_cluster_mask    DB      ?   ; Sectors/cluster - 1
+dpb_cluster_shift   DB      ?   ; Log2 of sectors/cluster
+dpb_first_FAT       DW      ?   ; Starting record of FATs
+dpb_FAT_count       DB      ?   ; Number of FATs for this drive
+dpb_root_entries    DW      ?   ; Number of directory entries
+dpb_first_sector    DW      ?   ; First sector of first cluster
+dpb_max_cluster     DW      ?   ; Number of clusters on drive + 1
+dpb_FAT_size        DB      ?   ; Number of records occupied by FAT
+dpb_dir_sector      DW      ?   ; Starting record of directory
+dpb_driver_addr     DD      ?   ; Pointer to driver
+dpb_media           DB      ?   ; Media byte
+dpb_first_access    DB      ?   ; This is initialized to -1 to force a media
+                                ; check the first time this DPB is used
+dpb_next_dpb        DD      ?   ; Pointer to next Drive parameter block
+dpb_current_dir     DW      ?   ; Cluster number of start of current directory
+                                ; 0 indicates root, -1 indicates invalid (disk
+                                ; ?  changed)
+dpb_dir_text        DB      DIRSTRLEN DUP(?)
+                                ; ASCIZ string of current directory
+dpb     ENDS
+
+DPBSIZ  EQU     SIZE dpb        ; Size of the structure in bytes
+
+DSKSIZ  =       dpb_max_cluster ; Size of disk (temp used during init only)
+;                                                                          ;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+
+BREAK <File Control Block definition>
+;
+; Field definition for FCBs
+; The FCB has the following structure:
+;
+;       +---------------------------+
+;       |   Drive indicator(byte)   |
+;       +---------------------------+
+;       |    Filename (8 chars)     |
+;       +---------------------------+
+;       |    Extension (3 chars)    |
+;       +---------------------------+
+;       |   Current Extent(word)    |
+;       +---------------------------+
+;       |    Record size (word)     |
+;       +---------------------------+
+;       |    File Size (2 words)    |
+;       +---------------------------+
+;       |       Date of write       |
+;       +---------------------------+
+;       |       Time of write       |
+;       +---------------------------+
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;                                                                          ;
+;       | Flags:                    |
+;       |  bit 7=0 file/1 device    |
+;       |  bit 6=0 if dirty         |
+;       |  bits 0-5 deviceid        |
+;       +---------------------------+
+;       |   first cluster in file   |
+;       +---------------------------+
+;       | position of last cluster  |
+;       +---------------------------+
+;       |   last cluster accessed   |   12 bit-+--- packed in 3 bytes
+;       +---------------------------+          |
+;       |     parent directory      |   <------+
+;       +---------------------------+
+;                                                                          ;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+;       |    next record number     |
+;       +---------------------------+
+;       |   random record number    |
+;       +---------------------------+
+;
+
+sys_fcb     STRUC
+fcb_drive   DB      ?
+fcb_name    DB      8 DUP (?)
+fcb_ext     DB      3 DUP (?)
+fcb_EXTENT  DW      ?
+fcb_RECSIZ  DW      ?       ; Size of record (user settable)
+fcb_FILSIZ  DW      ?       ; Size of file in bytes; used with the following
+                            ; word
+fcb_DRVBP   DW      ?       ; BP for SEARCH FIRST and SEARCH NEXT
+fcb_FDATE   DW      ?       ; Date of last writing
+fcb_FTIME   DW      ?       ; Time of last writing
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;                                                                          ;
+fcb_DEVID   DB      ?       ; Device ID number, bits 0-5 if file.
+                            ; bit 7=0 for file, bit 7=1 for I/O device
+                            ; If file, bit 6=0 if dirty
+                            ; If I/O device, bit 6=0 if EOF (input)
+                            ;               Bit 5=1 if Raw mode
+                            ;               Bit 0=1 if console input device
+                            ;               Bit 1=1 if console output device
+                            ;               Bit 2=1 if null device
+                            ;               Bit 3=1 if clock device
+fcb_FIRCLUS DW      ?       ; First cluster of file
+fcb_CLUSPOS DW      ?       ; Position of last cluster accessed
+fcb_LSTCLUS DW      ?       ; Last cluster accessed and directory pack 2 12
+            DB      ?       ; bit numbers into 24 bits...
+;                                                                          ;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+fcb_NR      DB      ?       ; Next record
+fcb_RR      DB      4 DUP (?)               ; Random record
+sys_fcb     ENDS
+
+FILDIRENT       = fcb_FILSIZ            ; Used only by SEARCH FIRST and SEARCH
+                                        ; NEXT
+
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;                                                                          ;
+devid_file_clean        EQU     40h     ; true if file and not written
+devid_file_mask_drive   EQU     3Fh     ; mask for drive number
+
+devid_device            EQU     80h     ; true if a device
+devid_device_EOF        EQU     40h     ; true if end of file reached
+devid_device_raw        EQU     20h     ; true if in raw mode
+devid_device_special    EQU     10h     ; true if special device
+devid_device_clock      EQU     08h     ; true if clock device
+devid_device_null       EQU     04h     ; true if null device
+devid_device_con_out    EQU     02h     ; true if console output
+devid_device_con_in     EQU     01h     ; true if consle input
+
+;
+; structure of devid field as returned by IOCTL is:
+;
+;       BIT     7   6   5   4   3   2   1   0
+;             |---|---|---|---|---|---|---|---|
+;             | I | E | R | S | I | I | I | I |
+;             | S | O | A | P | S | S | S | S |
+;             | D | F | W | E | C | N | C | C |
+;             | E |   |   | C | L | U | O | I |
+;             | V |   |   | L | K | L | T | N |
+;             |---|---|---|---|---|---|---|---|
+;       ISDEV = 1 if this channel is a device
+;             = 0 if this channel is a disk file
+;
+;       If ISDEV = 1
+;
+;             EOF = 0 if End Of File on input
+;             RAW = 1 if this device is in Raw mode
+;                 = 0 if this device is cooked
+;             ISCLK = 1 if this device is the clock device
+;             ISNUL = 1 if this device is the null device
+;             ISCOT = 1 if this device is the console output
+;             ISCIN = 1 if this device is the console input
+;
+;       If ISDEV = 0
+;             EOF = 0 if channel has been written
+;             Bits 0-5  are  the  block  device  number  for
+;                 the channel (0 = A, 1 = B, ...)
+;
+devid_ISDEV     EQU     80h
+devid_EOF       EQU     40h
+devid_RAW       EQU     20h
+devid_SPECIAL   EQU     10H
+devid_ISCLK     EQU     08h
+devid_ISNUL     EQU     04h
+devid_ISCOT     EQU     02h
+devid_ISCIN     EQU     01h
+
+devid_block_dev EQU     1Fh             ; mask for block device number
+
+;
+; find first/next buffer
+;
+find_buf    STRUC
+find_buf_sattr      DB  ?           ; attribute of search
+find_buf_drive      DB  ?           ; drive of search
+find_buf_name       DB  11 DUP (?)  ; formatted name
+find_buf_LastEnt    DW  ?           ; LastEnt
+find_buf_ThisDPB    DD  ?           ; This DPB
+find_buf_DirStart   DW  ?           ; DirStart
+;                                                                          ;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+
+find_buf_attr       DB  ?           ; attribute found
+find_buf_time       DW  ?           ; time
+find_buf_date       DW  ?           ; date
+find_buf_size_l     DW  ?           ; low(size)
+find_buf_size_h     DW  ?           ; high(size)
+find_buf_pname      DB  13 DUP (?)  ; packed name
+find_buf    ENDS
+
+BREAK <Process data block>
+;
+; Process data block (otherwise known as program header)
+;
+
+FilPerProc          EQU     20
+
+Process_data_block  STRUC
+PDB_Exit_Call       DW      ?           ; INT int_abort system terminate
+PDB_block_len       DW      ?           ; size of execution block
+                    DB      ?
+PDB_CPM_Call        DB  5 DUP (?)       ; ancient call to system
+PDB_Exit            DD      ?           ; pointer to exit routine
+PDB_Ctrl_C          DD      ?           ; pointer to ^C routine
+PDB_Fatal_abort     DD      ?           ; pointer to fatal error
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;                                                                          ;
+PDB_Parent_PID      DW      ?           ; PID of parent (terminate PID)
+PDB_JFN_Table       DB  FilPerProc DUP (?)
+                                        ; indices into system table
+;                                                                          ;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+PDB_environ         DW      ?           ; seg addr of environment
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;                                                                          ;
+PDB_User_stack      DD      ?           ; stack of self during system calls
+PDB_PAD1            DB      1Eh DUP (?)
+;                                                                          ;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+PDB_Call_system     DB      5 DUP (?)   ; portable method of system call
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;                                                                          ;
+PDB_PAD2            DB      6h DUP (?)  ;
+;                                                                          ;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+Process_data_block  ENDS
+
+BREAK <EXEC and EXE file structures>
+;
+; EXEC arg block - load/go program
+;
+
+;
+; The following get used as arguments to the EXEC system call.  They indicate
+; whether or not the program is executed or whether or not a program header
+; gets created.
+;
+exec_func_no_execute    EQU 1           ; no execute bit
+exec_func_overlay       EQU 2           ; overlay bit
+
+Exec0           STRUC
+Exec0_environ   DW      ?               ; seg addr of environment
+Exec0_com_line  DD      ?               ; pointer to asciz command line
+Exec0_5C_FCB    DD      ?               ; default fcb at 5C
+Exec0_6C_FCB    DD      ?               ; default fcb at 6C
+Exec0           ENDS
+
+Exec1           STRUC
+Exec1_environ   DW      ?               ; seg addr of environment
+Exec1_com_line  DD      ?               ; pointer to asciz command line
+Exec1_5C_FCB    DD      ?               ; default fcb at 5C
+Exec1_6C_FCB    DD      ?               ; default fcb at 6C
+Exec1_SP        DW      ?               ; stack pointer of program
+Exec1_SS        DW      ?               ; stack seg register of program
+Exec1_IP        DW      ?               ; entry point IP
+Exec1_CS        DW      ?               ; entry point CS
+Exec1           ENDS
+
+Exec3           STRUC
+Exec3_load_addr DW      ?               ; seg address of load point
+Exec3_reloc_fac DW      ?               ; relocation factor
+Exec3           ENDS
+
+;
+; Exit codes in upper byte
+;
+Exit_terminate      EQU     0
+Exit_abort          EQU     0
+Exit_Ctrl_C         EQU     1
+Exit_Hard_Error     EQU     2
+Exit_Keep_process   EQU     3
+
+;
+; EXE file header
+;
+
+EXE_file    STRUC
+exe_signature   DW  ?                   ; must contain 4D5A  (yay zibo!)
+exe_len_mod_512 DW  ?                   ; low 9 bits of length
+exe_pages       DW  ?                   ; number of 512b pages in file
+exe_rle_count   DW  ?                   ; count of reloc entries
+exe_par_dir     DW  ?                   ; number of paragraphs before image
+exe_min_BSS     DW  ?                   ; minimum number of para of BSS
+exe_max_BSS     DW  ?                   ; max number of para of BSS
+exe_SS          DW  ?                   ; stack of image
+exe_SP          DW  ?                   ; SP of image
+exe_chksum      DW  ?                   ; checksum  of file (ignored)
+exe_IP          DW  ?                   ; IP of entry
+exe_CS          DW  ?                   ; CS of entry
+exe_rle_table   DW  ?                   ; byte offset of reloc table
+exe_iov         DW  ?                   ; overlay number (0 for root)
+exe_sym_tab     DD  ?                   ; offset of symbol table in file
+EXE_file    ENDS
+
+exe_valid_signature     EQU 5A4Dh
+exe_valid_old_signature EQU 4D5Ah
+
+symbol_entry    STRUC
+sym_value       DD  ?
+sym_type        DW  ?
+sym_len         DB  ?
+sym_name        DB  255 dup (?)
+symbol_entry    ENDS
+
+BREAK <Internal system file table format>
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;                                                                          ;
+;
+; system file table
+;
+
+sft             STRUC
+sft_link        DD      ?
+sft_count       DW      ?               ; number of entries
+sft_table       DW      ?               ; beginning of array of the following
+sft             ENDS
+
+;
+; system file table entry
+;
+
+sf_entry        STRUC
+sf_ref_count    DB      ?               ; number of processes sharing fcb
+sf_mode         DB      ?               ; mode of access
+sf_attr         DB      ?               ; attribute of file
+sf_fcb          DB      (SIZE sys_fcb) DUP (?)
+                                        ; actual FCB
+sf_entry        ENDS
+
+sf_default_number   EQU     5h
+;                                                                          ;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+
+BREAK <Memory arena structure>
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;                                                                          ;
+;
+; arena item
+;
+arena   STRUC
+arena_signature     DB  ?               ; 4D for valid item, 5A for last item
+arena_owner         DW  ?               ; owner of arena item
+arena_size          DW  ?               ; size in paragraphs of item
+arena   ENDS
+
+;
+; Current structure of the data returned by the international call
+;
+
+internat_block STRUC
+Date_tim_format DW      ?           ; 0-USA, 1-EUR, 2-JAP
+Currency_sym    DB      ?           ; Currency Symbol 5 bytes
+                DB      ?
+                DB      ?
+                DB      ?
+                DB      ?
+Thous_sep       DB      ?           ; Thousands separator 2 bytes
+                DB      ?
+Decimal_sep     DB      ?           ; Decimal separator 2 bytes
+                DB      ?
+Date_sep        DB      ?           ; Date separator 2 bytes
+                DB      ?
+Time_sep        DB      ?           ; Decimal separator 2 bytes
+                DB      ?
+Bit_feild       DB      ?           ; Bit values
+                                    ;   Bit 0 = 0 if currency symbol first
+                                    ;         = 1 if currency symbol last
+                                    ;   Bit 1 = 0 if No space after currency symbol
+                                    ;         = 1 if space after currency symbol
+Currency_cents  DB      ?           ; Number of places after currency dec point
+Time_24         DB      ?           ; 1 if 24 hour time, 0 if 12 hour time
+Map_call        DW      ?           ; Address of case mapping call (DWORD)
+                DW      ?           ; THIS IS TWO WORDS SO IT CAN BE INITIALIZED
+                                    ;  in pieces.
+Data_sep        DB      ?           ; Data list separator character
+                DB      ?
+internat_block ENDS
+
+;
+; Max size of the block returned by the INTERNATIONAL call
+;
+internat_block_max      EQU     32
+
+;
+; CAUTION: The routines in ALLOC.ASM rely on the fact that arena_signature
+; and arena_owner_system are all equal to zero and are contained in DI.  Change
+; them and change ALLOC.ASM.
+
+arena_owner_system  EQU 0               ; free block indication
+
+arena_signature_normal  EQU 4Dh         ; valid signature, not end of arena
+arena_signature_end     EQU 5Ah         ; valid signature, last block in arena
+;                                                                          ;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+
+BREAK <Machine instruction definitions>
+
+mi_INT          EQU     0CDh
+mi_Long_JMP     EQU     0EAh
+mi_Long_CALL    EQU     09Ah
+mi_Long_RET     EQU     0CBh
+
+BREAK <Standard I/O assignments>
+
+stdin       EQU     0
+stdout      EQU     1
+stderr      EQU     2
+stdaux      EQU     3
+stdprn      EQU     4
+
+BREAK <Xenix subfunction assignments>
+
+open_for_read   EQU 0
+open_for_write  EQU 1
+open_for_both   EQU 2
+
+BREAK <Xenix error codes>
+
+;
+; XENIX calls all return error codes through AX.  If an error occurred then
+; the carry bit will be set and the error code is in AX.  If no error occurred
+; then the carry bit is reset and AX contains returned info.
+;
+
+no_error_occurred               EQU     0                                                              ?
+
+error_invalid_function          EQU     1
+error_file_not_found            EQU     2
+error_path_not_found            EQU     3
+error_too_many_open_files       EQU     4
+error_access_denied             EQU     5
+error_invalid_handle            EQU     6
+error_arena_trashed             EQU     7
+error_not_enough_memory         EQU     8
+error_invalid_block             EQU     9
+error_bad_environment           EQU     10
+error_bad_format                EQU     11
+error_invalid_access            EQU     12
+error_invalid_data              EQU     13
+;**** unused                    EQU     14
+error_invalid_drive             EQU     15
+error_current_directory         EQU     16
+error_not_same_device           EQU     17
+error_no_more_files             EQU     18
+
+country_not_found               EQU     error_file_not_found
+alloc_not_enough_memory         EQU     error_not_enough_memory
+alloc_arena_trashed             EQU     error_arena_trashed
+
+close_invalid_handle            EQU     error_invalid_handle
+close_invalid_function          EQU     error_invalid_function
+
+chdir_path_not_found            EQU     error_path_not_found
+
+chmod_path_not_found            EQU     error_path_not_found
+chmod_access_denied             EQU     error_access_denied
+chmod_invalid_function          EQU     error_invalid_function
+
+creat_access_denied             EQU     error_access_denied
+creat_path_not_found            EQU     error_path_not_found
+creat_too_many_open_files       EQU     error_too_many_open_files
+
+curdir_invalid_drive            EQU     error_invalid_drive
+
+dealloc_invalid_block           EQU     error_invalid_block
+dealloc_arena_trashed           EQU     error_arena_trashed
+
+dup_invalid_handle              EQU     error_invalid_handle
+dup_too_many_open_files         EQU     error_too_many_open_files
+
+dup2_invalid_handle             EQU     error_invalid_handle
+
+exec_invalid_function           EQU     error_invalid_function
+exec_bad_environment            EQU     error_bad_environment
+exec_bad_format                 EQU     error_bad_format
+exec_not_enough_memory          EQU     error_not_enough_memory
+exec_file_not_found             EQU     error_file_not_found
+
+filetimes_invalid_function      EQU     error_invalid_function
+filetimes_invalid_handle        EQU     error_invalid_handle
+
+findfirst_file_not_found        EQU     error_file_not_found
+findfirst_no_more_files         EQU     error_no_more_files
+findnext_no_more_files          EQU     error_no_more_files
+
+international_invalid_function  EQU     error_invalid_function
+
+ioctl_invalid_handle            EQU     error_invalid_handle
+ioctl_invalid_function          EQU     error_invalid_function
+ioctl_invalid_data              EQU     error_invalid_data
+
+lseek_invalid_handle            EQU     error_invalid_handle
+lseek_invalid_function          EQU     error_invalid_function
+
+mkdir_path_not_found            EQU     error_path_not_found
+mkdir_access_denied             EQU     error_access_denied
+
+open_invalid_access             EQU     error_invalid_access
+open_file_not_found             EQU     error_file_not_found
+open_access_denied              EQU     error_access_denied
+open_too_many_open_files        EQU     error_too_many_open_files
+
+read_invalid_handle             EQU     error_invalid_handle
+read_access_denied              EQU     error_access_denied
+
+rename_file_not_found           EQU     error_file_not_found
+rename_not_same_device          EQU     error_not_same_device
+rename_access_denied            EQU     error_access_denied
+
+rmdir_path_not_found            EQU     error_path_not_found
+rmdir_access_denied             EQU     error_access_denied
+rmdir_current_directory         EQU     error_current_directory
+
+setblock_invalid_block          EQU     error_invalid_block
+setblock_arena_trashed          EQU     error_arena_trashed
+setblock_not_enough_memory      EQU     error_not_enough_memory
+setblock_invalid_function       EQU     error_invalid_function
+
+unlink_file_not_found           EQU     error_file_not_found
+unlink_access_denied            EQU     error_access_denied
+
+write_invalid_handle            EQU     error_invalid_handle
+write_access_denied             EQU     error_access_denied
+
+BREAK <system call definitions>
+
+Abort                           EQU 0   ;  0      0
+Std_Con_Input                   EQU 1   ;  1      1
+Std_Con_Output                  EQU 2   ;  2      2
+Std_Aux_Input                   EQU 3   ;  3      3
+Std_Aux_Output                  EQU 4   ;  4      4
+Std_Printer_Output              EQU 5   ;  5      5
+Raw_Con_IO                      EQU 6   ;  6      6
+Raw_Con_Input                   EQU 7   ;  7      7
+Std_Con_Input_No_Echo           EQU 8   ;  8      8
+Std_Con_String_Output           EQU 9   ;  9      9
+Std_Con_String_Input            EQU 10  ; 10      A
+Std_Con_Input_Status            EQU 11  ; 11      B
+Std_Con_Input_Flush             EQU 12  ; 12      C
+Disk_Reset                      EQU 13  ; 13      D
+Set_Default_Drive               EQU 14  ; 14      E
+FCB_Open                        EQU 15  ; 15      F
+FCB_Close                       EQU 16  ; 16     10
+Dir_Search_First                EQU 17  ; 17     11
+Dir_Search_Next                 EQU 18  ; 18     12
+FCB_Delete                      EQU 19  ; 19     13
+FCB_Seq_Read                    EQU 20  ; 20     14
+FCB_Seq_Write                   EQU 21  ; 21     15
+FCB_Create                      EQU 22  ; 22     16
+FCB_Rename                      EQU 23  ; 23     17
+Get_Default_Drive               EQU 25  ; 25     19
+Set_DMA                         EQU 26  ; 26     1A
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;                                                                          ;
+Get_Default_DPB                 EQU 31  ; 31     1F
+;                                                                          ;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+FCB_Random_Read                 EQU 33  ; 33     21
+FCB_Random_Write                EQU 34  ; 34     22
+Get_FCB_File_Length             EQU 35  ; 35     23
+Get_FCB_Position                EQU 36  ; 36     24
+Set_Interrupt_Vector            EQU 37  ; 37     25
+Create_Process_Data_Block       EQU 38  ; 38     26
+FCB_Random_Read_Block           EQU 39  ; 39     27
+FCB_Random_Write_Block          EQU 40  ; 40     28
+Parse_File_Descriptor           EQU 41  ; 41     29
+Get_Date                        EQU 42  ; 42     2A
+Set_Date                        EQU 43  ; 43     2B
+Get_Time                        EQU 44  ; 44     2C
+Set_Time                        EQU 45  ; 45     2D
+Set_Verify_On_Write             EQU 46  ; 46     2E
+; Extended functionality group
+Get_DMA                         EQU 47  ; 47     2F
+Get_Version                     EQU 48  ; 48     30
+Keep_Process                    EQU 49  ; 49     31
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;                                                                          ;
+Get_DPB                         EQU 50  ; 50     32
+;                                                                          ;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+Set_CTRL_C_Trapping             EQU 51  ; 51     33
+Get_InDOS_Flag                  EQU 52  ; 52     34
+Get_Interrupt_Vector            EQU 53  ; 53     35
+Get_Drive_Freespace             EQU 54  ; 54     36
+Char_Oper                       EQU 55  ; 55     37
+International                   EQU 56  ; 56     38
+;   Directory Group
+MKDir                           EQU 57  ; 57     39
+RMDir                           EQU 58  ; 58     3A
+CHDir                           EQU 59  ; 59     3B
+;   File Group
+Creat                           EQU 60  ; 60     3C
+Open                            EQU 61  ; 61     3D
+Close                           EQU 62  ; 62     3E
+Read                            EQU 63  ; 63     3F
+Write                           EQU 64  ; 64     40
+Unlink                          EQU 65  ; 65     41
+LSeek                           EQU 66  ; 66     42
+CHMod                           EQU 67  ; 67     43
+IOCtl                           EQU 68  ; 68     44
+XDup                            EQU 69  ; 69     45
+XDup2                           EQU 70  ; 70     46
+Current_Dir                     EQU 71  ; 71     47
+;    Memory Group
+Alloc                           EQU 72  ; 72     48
+Dealloc                         EQU 73  ; 73     49
+Setblock                        EQU 74  ; 74     4A
+;    Process Group
+Exec                            EQU 75  ; 75     4B
+Exit                            EQU 76  ; 76     4C
+Wait                            EQU 77  ; 77     4D
+Find_First                      EQU 78  ; 78     4E
+;   Special Group
+Find_Next                       EQU 79  ; 79     4F
+; SPECIAL SYSTEM GROUP
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;                                                                          ;
+Set_Current_PDB                 EQU 80  ; 80     50
+Get_Current_PDB                 EQU 81  ; 81     51
+Get_In_Vars                     EQU 82  ; 82     52
+SetDPB                          EQU 83  ; 83     53
+;                                                                          ;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+Get_Verify_On_Write             EQU 84  ; 84     54
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;                                                                          ;
+Dup_PDB                         EQU 85  ; 85     55
+;                                                                          ;
+;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
+;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
+Rename                          EQU 86  ; 86     56
+File_Times                      EQU 87  ; 87     57
+AllocOper                       EQU 88  ; 88     58
+; Network extention system calls
+GetExtendedError                EQU 89  ; 89     59
+CreateTempFile                  EQU 90  ; 90     5A
+CreateNewFile                   EQU 91  ; 91     5B
+LockOper                        EQU 92  ; 92     5C Lock and Unlock
+ServerCall                      EQU 93  ; 93     5D CommitAll, ServerDOSCall,
+                                        ;           CloseByName, CloseUser,
+                                        ;           CloseUserProcess,
+                                        ;           GetOpenFileList
+UserIDOper                      EQU 94  ; 94     5E Get and Set
+AssignOper                      EQU 95  ; 95     5F On, Off, Get, Set, Cancel
+
+Set_Oem_Handler                 EQU 248 ; 248    F8
+OEM_C1                          EQU 249 ; 249    F9
+OEM_C2                          EQU 250 ; 250    FA
+OEM_C3                          EQU 251 ; 251    FB
+OEM_C4                          EQU 252 ; 252    FC
+OEM_C5                          EQU 253 ; 253    FD
+OEM_C6                          EQU 254 ; 254    FE
+OEM_C7                          EQU 255 ; 255    FF
+SUBTTL
diff --git a/v2.0/source/EDLIN.ASM b/v2.0/source/EDLIN.ASM
new file mode 100644 (file)
index 0000000..f795ac4
--- /dev/null
@@ -0,0 +1,1846 @@
+        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
diff --git a/v2.0/source/EDLMES.ASM b/v2.0/source/EDLMES.ASM
new file mode 100644 (file)
index 0000000..f49ed96
Binary files /dev/null and b/v2.0/source/EDLMES.ASM differ
diff --git a/v2.0/source/EDLPROC.ASM b/v2.0/source/EDLPROC.ASM
new file mode 100644 (file)
index 0000000..0128b1d
--- /dev/null
@@ -0,0 +1,531 @@
+\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
diff --git a/v2.0/source/EXE2BIN.ASM b/v2.0/source/EXE2BIN.ASM
new file mode 100644 (file)
index 0000000..80deb43
--- /dev/null
@@ -0,0 +1,514 @@
+        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
diff --git a/v2.0/source/EXEC.ASM b/v2.0/source/EXEC.ASM
new file mode 100644 (file)
index 0000000..d41aceb
--- /dev/null
@@ -0,0 +1,1035 @@
+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
diff --git a/v2.0/source/EXEMES.ASM b/v2.0/source/EXEMES.ASM
new file mode 100644 (file)
index 0000000..542ec12
Binary files /dev/null and b/v2.0/source/EXEMES.ASM differ
diff --git a/v2.0/source/FAT.ASM b/v2.0/source/FAT.ASM
new file mode 100644 (file)
index 0000000..b1a4863
--- /dev/null
@@ -0,0 +1,362 @@
+;\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
diff --git a/v2.0/source/FC.ASM b/v2.0/source/FC.ASM
new file mode 100644 (file)
index 0000000..21ed991
--- /dev/null
@@ -0,0 +1,1684 @@
+        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
diff --git a/v2.0/source/FCB.ASM b/v2.0/source/FCB.ASM
new file mode 100644 (file)
index 0000000..11528f7
--- /dev/null
@@ -0,0 +1,512 @@
+;
+; FCB management routines for MSDOS
+;
+
+INCLUDE DOSSEG.ASM
+
+IFNDEF  KANJI
+KANJI   EQU     0       ;FALSE
+ENDIF
+
+CODE    SEGMENT BYTE PUBLIC  'CODE'
+        ASSUME  SS:DOSGROUP,CS:DOSGROUP
+
+.xlist
+.xcref
+INCLUDE DOSSYM.ASM
+INCLUDE DEVSYM.ASM
+.cref
+.list
+
+        i_need  Name1,BYTE
+        i_need  NumIO,BYTE
+        i_need  DevFCB,BYTE
+        i_need  Creating,BYTE
+        i_need  ExtFCB,BYTE
+        i_need  Attrib,BYTE
+        i_need  SpaceFlag,BYTE
+        i_need  Current_Country,WORD
+
+        procedure   MakeFcb,NEAR
+DRVBIT  EQU     2
+NAMBIT  EQU     4
+EXTBIT  EQU     8
+        MOV     BYTE PTR [SpaceFlag],0
+        XOR     DL,DL           ; Flag--not ambiguous file name
+        TEST    AL,DRVBIT       ; Use current drive field if default?
+        JNZ     DEFDRV
+        MOV     BYTE PTR ES:[DI],0      ; No - use default drive
+DEFDRV:
+        INC     DI
+        MOV     CX,8
+        TEST    AL,NAMBIT       ; Use current name fields as defualt?
+        XCHG    AX,BX           ; Save bits in BX
+        MOV     AL," "
+        JZ      FILLB           ; If not, go fill with blanks
+        ADD     DI,CX
+        XOR     CX,CX           ; Don't fill any
+FILLB:
+        REP     STOSB
+        MOV     CL,3
+        TEST    BL,EXTBIT       ; Use current extension as default
+        JZ      FILLB2
+        ADD     DI,CX
+        XOR     CX,CX
+FILLB2:
+        REP     STOSB
+        XCHG    AX,CX           ; Put zero in AX
+        STOSW
+        STOSW                   ; Initialize two words after to zero
+        SUB     DI,16           ; Point back at start
+        TEST    BL,1            ; Scan off separators if not zero
+        JZ      SKPSPC
+        CALL    SCANB           ; Peel off blanks and tabs
+        CALL    DELIM           ; Is it a one-time-only delimiter?
+        JNZ     NOSCAN
+        INC     SI              ; Skip over the delimiter
+SKPSPC:
+        CALL    SCANB           ; Always kill preceding blanks and tabs
+NOSCAN:
+        CALL    GETLET
+        JBE     NODRV           ; Quit if termination character
+        CMP     BYTE PTR[SI],":"        ; Check for potential drive specifier
+        JNZ     NODRV
+        INC     SI              ; Skip over colon
+        SUB     AL,"@"          ; Convert drive letter to binary drive number
+        JBE     BADDRV          ; Valid drive numbers are <= NUMIO
+        CMP     AL,BYTE PTR [NUMIO]
+        JBE     HAVDRV
+BADDRV:
+        MOV     DL,-1
+HAVDRV:
+        STOSB           ; Put drive specifier in first byte
+        INC     SI
+        DEC     DI      ; Counteract next two instructions
+NODRV:
+        DEC     SI      ; Back up
+        INC     DI      ; Skip drive byte
+NORMSCAN:
+        MOV     CX,8
+        CALL    GETWORD         ; Get 8-letter file name
+        CMP     BYTE PTR [SI],"."
+        JNZ     NODOT
+        INC     SI              ; Skip over dot if present
+        MOV     CX,3            ; Get 3-letter extension
+        CALL    MUSTGETWORD
+NODOT:
+        MOV     AL,DL
+        return
+
+NONAM:
+        ADD     DI,CX
+        DEC     SI
+        return
+
+GETWORD:
+        CALL    GETLET
+        JBE     NONAM           ; Exit if invalid character
+        DEC     SI
+;
+; UGH!!! Horrible bug here that should be fixed at some point:
+; If the name we are scanning is longer than CX, we keep on reading!
+;
+MUSTGETWORD:
+        CALL    GETLET
+;
+; If spaceFlag is set then we allow spaces in a pathname
+;
+        JB      FILLNAM
+        JNZ     MustCheckCX
+        TEST    BYTE PTR [SpaceFlag],0FFh
+        JZ      FILLNAM
+        CMP     AL," "
+        JNZ     FILLNAM
+
+MustCheckCX:
+        JCXZ    MUSTGETWORD
+        DEC     CX
+        CMP     AL,"*"                  ; Check for ambiguous file specifier
+        JNZ     NOSTAR
+        MOV     AL,"?"
+        REP     STOSB
+NOSTAR:
+        STOSB
+
+        IF      KANJI
+        CALL    TESTKANJ
+        JZ      NOTDUAL3
+        JCXZ    BNDERR                  ; Attempt to straddle boundry
+        MOVSB                           ; Transfer second byte
+        DEC     CX
+        JMP     SHORT NOTDUAL3
+BNDERR:
+        MOV     BYTE PTR ES:[DI-1]," "  ; patch up that space
+        JMP     MustGetWord             ; go back and scan until delim
+
+NOTDUAL3:
+        ENDIF
+
+        CMP     AL,"?"
+        JNZ     MUSTGETWORD
+        OR      DL,1                    ; Flag ambiguous file name
+        JMP     MUSTGETWORD
+FILLNAM:
+        MOV     AL," "
+        REP     STOSB
+        DEC     SI
+        return
+
+SCANB:
+        LODSB
+        CALL    SPCHK
+        JZ      SCANB
+        DEC     SI
+        return
+MakeFCB ENDP
+
+;
+; NameTrans is used by FindPath to scan off an element
+; of a path.  We must allow spaces in pathnames
+; Inputs:   SS - DOSGROUP
+;           DS:SI name
+; Outputs:  DS:SI advanced over spot
+;           ES:DI point to after Name1
+; registers modified: AX, BX, CX, DX
+procedure   NameTrans,near
+        MOV     BYTE PTR [SpaceFlag],1
+        PUSH    SS
+        POP     ES
+        MOV     DI,OFFSET DOSGROUP:NAME1
+        PUSH    DI
+        MOV     AL,' '
+        MOV     CX,11
+        REP     STOSB
+        XOR     AL,AL
+        MOV     DL,AL
+        STOSB
+        POP     DI
+        CMP     BYTE PTR [SI],'.'
+
+        IF      KANJI
+        JZ      FOOBAR
+        CALL    NORMSCAN
+        CMP     [NAME1],0E5H
+        retnz
+        MOV     [NAME1],5
+        return
+FOOBAR:
+        ELSE
+        JNZ     NORMSCAN
+        ENDIF
+
+        MOVSB
+        LODSB
+        CALL    PATHCHRCMP
+        JZ      GOTDOTNAME
+        OR      AL,AL
+        JZ      GOTDOTNAME
+        CMP     AL,'.'
+        JNZ     BADDOTS
+        STOSB
+        LODSB
+        CALL    PATHCHRCMP
+        JZ      GOTDOTNAME
+        OR      AL,AL
+        JZ      GOTDOTNAME
+        DEC     SI
+BADDOTS:
+        DEC     SI
+GOTDOTNAME:
+        DEC     SI
+        XOR     AL,AL
+        return
+nametrans   ENDP
+
+SUBTTL BUILDFCB -- MAKE A BLANK FCB FOR A DEVICE
+PAGE
+        procedure BuildFCB,near
+ASSUME  DS:DOSGROUP,ES:DOSGROUP
+
+; Function:
+;       Build a blank FCB for I/O to a device
+; Outputs:
+;       Same as GETNAME
+
+        MOV     AX,"  "
+        MOV     DI,OFFSET DOSGROUP:DEVFCB+8     ; Point to extent field
+        STOSW
+        STOSB                   ; Blank out extent field
+        XOR     AX,AX
+        MOV     CX,10
+        REP     STOSW           ; Fill FCB with zeros
+        STOSB
+        invoke  DATE16
+        MOV     DI,OFFSET DOSGROUP:DEVFCB+22
+        XCHG    AX,DX
+        STOSW
+        XCHG    AX,DX
+        STOSW
+        XCHG    AX,BX           ; But device number in AH
+        MOV     BX,OFFSET DOSGROUP:DEVFCB
+        MOV     SI,DI
+        XOR     AL,AL           ; Set zero, clear carry
+        return
+BuildFCB    ENDP
+
+SUBTTL MOVENAME, LODNAME -- EXAMINE FCB AND SETUP
+PAGE
+        procedure   FCB_move,NEAR
+
+        entry   MOVNAMENOSET
+        MOV     DI,1
+        JMP     SHORT MOVSTART
+
+        entry   MOVNAME
+ASSUME  DS:NOTHING,ES:NOTHING
+
+; Inputs:
+;       DS, DX point to FCB or extended FCB
+; Outputs:
+;       DS:DX point to normal FCB
+;       DS:SI point after end of NAME/EXT in FCB
+;       ES = DOSGROUP
+;       If file name OK:
+;       [NAME1] has name in upper case
+; All registers destroyed
+; Carry set if bad file name or drive
+
+        XOR     DI,DI
+MOVSTART:
+        MOV     WORD PTR [CREATING],0E500H   ; Not creating, not DEL *.*
+        MOV     SI,DX
+        LODSB
+        MOV     [EXTFCB],AL     ; Set flag if extended FCB in use
+        XOR     AH,AH           ; Set default attributes
+        CMP     AL,-1           ; Is it an extended FCB?
+        JNZ     HAVATTRB
+        ADD     DX,7            ; Adjust to point to normal FCB
+        ADD     SI,6
+        MOV     AH,[SI-1]       ; Attribute byte
+        LODSB                   ; Get drive select byte
+HAVATTRB:
+        invoke  GETTHISDRV
+        retc
+        PUSH    DS
+        PUSH    DX
+        PUSH    SI
+        PUSH    AX
+;
+; DS:DX is pointer to good FCB
+; DS:SI is same
+;
+; Move the file into Name1 and UCASE it
+;
+        PUSH    DI
+        context ES
+        MOV     DI,OFFSET DOSGROUP:NAME1
+        CALL    LodName
+        POP     DI
+        JC      DrvNoSet
+
+;
+; are we setting current dir info?
+;
+        OR      DI,DI
+        JNZ     DrvNoSet        ; do not set dir info
+
+;
+; check for device name first, eliminating drive hits on devices
+;
+        context DS
+        invoke  DEVNAME
+        JNC     DrvNoSet            ; we have a device
+
+;
+; make sure that everything is current
+;
+        invoke  FATREAD
+        ASSUME  DS:NOTHING,ES:NOTHING
+        MOV     BYTE PTR [ATTRIB],attr_directory+attr_hidden+attr_system
+        invoke  GETCURRDIR
+DrvNoSet:
+        POP     AX
+        MOV     BYTE PTR [ATTRIB],AH
+
+        POP     SI
+        POP     DX
+        POP     DS
+        context ES
+        MOV     DI,OFFSET DOSGROUP:NAME1
+
+        entry   LODNAME
+; Inputs:   DS:SI point to an FCB
+;           ES:DI point to an FCB
+; Outputs:  DS:SI point to after FCB
+;           ES:DI point to after FCB
+;                 FCB from DS:SI copied and ucased to ES:DI
+; Carry set if there was an error.
+; Destroys AX,CX
+        CMP     BYTE PTR [SI]," "       ; Don't allow blank as first letter
+        STC                     ; In case of error
+        retz
+
+        IF      KANJI
+        MOV     CX,8
+        CMP     BYTE PTR [SI],0E5H
+        JNZ     MOVCHK
+        INC     SI
+        MOV     AL,5
+        STOSB
+        MOVSB
+        MOV     CX,6
+MOVCHK:
+        CALL    GETLET
+        JB      RET6
+        JNZ     STOLET          ; Is it a delimiter?
+        CMP     AL," "          ; This is the only delimiter allowed
+        STC                     ; In case of error
+        JNZ     RET6
+STOLET:
+        STOSB
+        CALL    TESTKANJ
+        JZ      MOVLP           ;No
+        LODSB                   ;Get second byte
+        DEC     CX
+        JZ      BOUNDERR        ;Attempt to cross boundry
+        STOSB
+MOVLP:
+        LOOP    MOVCHK
+        MOV     CX,3
+MOVCHK2:
+        CALL    GETLET
+        JB      RET6
+        JNZ     STOLET2         ; Is it a delimiter?
+        CMP     AL," "          ; This is the only delimiter allowed
+        STC                     ; In case of error
+        retnz
+STOLET2:
+        STOSB
+        CALL    TESTKANJ
+        JZ      MOVLP2          ;No
+        LODSB                   ;Get second byte
+        DEC     CX
+        JNZ     DOSTORE
+BOUNDERR:                       ;Attempt to cross boundry
+        STC
+        return
+
+DOSTORE:
+        STOSB
+MOVLP2:
+        LOOP    MOVCHK2
+        ELSE
+        MOV     CX,11
+MOVCHK:
+        CALL    GETLET
+        JB      RET6
+        JNZ     STOLET          ; Is it a delimiter?
+        CMP     AL," "          ; This is the only delimiter allowed
+        STC                     ; In case of error
+        retnz
+STOLET:
+        STOSB
+        LOOP    MOVCHK
+        ENDIF
+
+        CLC                     ; Got through whole name - no error
+RET6:   return
+FCB_Move    ENDP
+
+SUBTTL GETLET, DELIM -- CHECK CHARACTERS AND CONVERT
+PAGE
+        procedure   GetLet,NEAR
+; Get a byte from [SI], convert it to upper case, and compare for delimiter.
+; ZF set if a delimiter, CY set if a control character (other than TAB).
+        LODSB
+
+        CMP     AL,"a"
+        JB      CHK1
+        CMP     AL,"z"
+        JA      CHK1
+        SUB     AL,20H          ; Convert to upper case
+CHK1:
+        PUSH    SI
+        MOV     SI,[Current_Country]
+        ADD     SI,Map_call
+        PUSH    CS              ; CS for long return
+        CALL    WORD PTR CS:[SI]
+        POP     SI
+        entry   CHK
+        CMP     AL,"."
+        retz
+        CMP     AL,'"'
+        retz
+        CALL    PATHCHRCMP
+        retz
+        CMP     AL,"["
+        retz
+        CMP     AL,"]"
+        retz
+
+DELIM:
+        CMP     AL,":"          ; Allow ":" as separator in IBM version
+        retz
+
+        CMP     AL,"<"
+        retz
+        CMP     AL,"|"
+        retz
+        CMP     AL,">"
+        retz
+
+        CMP     AL,"+"
+        retz
+        CMP     AL,"="
+        retz
+        CMP     AL,";"
+        retz
+        CMP     AL,","
+        retz
+SPCHK:
+        CMP     AL,9            ; Filter out tabs too
+        retz
+; WARNING! " " MUST be the last compare
+        CMP     AL," "
+        return
+GetLet  ENDP
+
+        procedure   PATHCHRCMP,NEAR
+        CMP     AL,'/'
+        retz
+        CMP     AL,'\'
+        return
+PathChrCMP  ENDP
+
+        IF      KANJI
+        procedure   TESTKANJ,NEAR
+        CMP     AL,81H
+        JB      NOTLEAD
+        CMP     AL,9FH
+        JBE     ISLEAD
+        CMP     AL,0E0H
+        JB      NOTLEAD
+        CMP     AL,0FCH
+        JBE     ISLEAD
+NOTLEAD:
+        PUSH    AX
+        XOR     AX,AX           ;Set zero
+        POP     AX
+        return
+
+ISLEAD:
+        PUSH    AX
+        XOR     AX,AX           ;Set zero
+        INC     AX              ;Reset zero
+        POP     AX
+        return
+TESTKANJ  ENDP
+        ENDIF
+do_ext
+
+CODE    ENDS
+    END
diff --git a/v2.0/source/FCMES.ASM b/v2.0/source/FCMES.ASM
new file mode 100644 (file)
index 0000000..1fc52cb
Binary files /dev/null and b/v2.0/source/FCMES.ASM differ
diff --git a/v2.0/source/FIND.ASM b/v2.0/source/FIND.ASM
new file mode 100644 (file)
index 0000000..7c82768
--- /dev/null
@@ -0,0 +1,932 @@
+      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
diff --git a/v2.0/source/FINDMES.ASM b/v2.0/source/FINDMES.ASM
new file mode 100644 (file)
index 0000000..cb120db
Binary files /dev/null and b/v2.0/source/FINDMES.ASM differ
diff --git a/v2.0/source/FORMAT.ASM b/v2.0/source/FORMAT.ASM
new file mode 100644 (file)
index 0000000..694857b
--- /dev/null
@@ -0,0 +1,1627 @@
+;***************************************************************
+;
+;       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
diff --git a/v2.0/source/FORMAT.txt b/v2.0/source/FORMAT.txt
new file mode 100644 (file)
index 0000000..ab47f54
--- /dev/null
@@ -0,0 +1,393 @@
+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
diff --git a/v2.0/source/FORMES.ASM b/v2.0/source/FORMES.ASM
new file mode 100644 (file)
index 0000000..eedae27
Binary files /dev/null and b/v2.0/source/FORMES.ASM differ
diff --git a/v2.0/source/GENFOR.ASM b/v2.0/source/GENFOR.ASM
new file mode 100644 (file)
index 0000000..a108593
Binary files /dev/null and b/v2.0/source/GENFOR.ASM differ
diff --git a/v2.0/source/GETSET.ASM b/v2.0/source/GETSET.ASM
new file mode 100644 (file)
index 0000000..289f4c8
--- /dev/null
@@ -0,0 +1,627 @@
+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
diff --git a/v2.0/source/HRDDRV.ASM b/v2.0/source/HRDDRV.ASM
new file mode 100644 (file)
index 0000000..672b99d
--- /dev/null
@@ -0,0 +1,501 @@
+       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
diff --git a/v2.0/source/IFEQU.ASM b/v2.0/source/IFEQU.ASM
new file mode 100644 (file)
index 0000000..ff5f581
--- /dev/null
@@ -0,0 +1,18 @@
+;*************************************
+; COMMAND EQUs which are switch dependant
+
+IF1
+    IF IBM
+        %OUT IBM version
+    ELSE
+        %OUT Normal version
+    ENDIF
+
+    IF   HIGHMEM
+        %OUT Highmem version
+    ENDIF
+
+    IF   KANJI
+        %OUT Kanji version
+    ENDIF
+ENDIF
diff --git a/v2.0/source/INCOMP.txt b/v2.0/source/INCOMP.txt
new file mode 100644 (file)
index 0000000..6c187b6
Binary files /dev/null and b/v2.0/source/INCOMP.txt differ
diff --git a/v2.0/source/INIT.ASM b/v2.0/source/INIT.ASM
new file mode 100644 (file)
index 0000000..0ea86f5
--- /dev/null
@@ -0,0 +1,939 @@
+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
diff --git a/v2.0/source/INT24.txt b/v2.0/source/INT24.txt
new file mode 100644 (file)
index 0000000..d38d6fa
Binary files /dev/null and b/v2.0/source/INT24.txt differ
diff --git a/v2.0/source/MISC.ASM b/v2.0/source/MISC.ASM
new file mode 100644 (file)
index 0000000..e0a5cee
--- /dev/null
@@ -0,0 +1,648 @@
+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
diff --git a/v2.0/source/MORE.ASM b/v2.0/source/MORE.ASM
new file mode 100644 (file)
index 0000000..6c9bf95
Binary files /dev/null and b/v2.0/source/MORE.ASM differ
diff --git a/v2.0/source/MOREMES.ASM b/v2.0/source/MOREMES.ASM
new file mode 100644 (file)
index 0000000..57c28d1
--- /dev/null
@@ -0,0 +1,17 @@
+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
diff --git a/v2.0/source/MSCODE.ASM b/v2.0/source/MSCODE.ASM
new file mode 100644 (file)
index 0000000..c4b58bc
--- /dev/null
@@ -0,0 +1,615 @@
+;
+; 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
diff --git a/v2.0/source/MSDATA.ASM b/v2.0/source/MSDATA.ASM
new file mode 100644 (file)
index 0000000..ed524e8
--- /dev/null
@@ -0,0 +1,342 @@
+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
diff --git a/v2.0/source/MSDOS.ASM b/v2.0/source/MSDOS.ASM
new file mode 100644 (file)
index 0000000..1d43531
--- /dev/null
@@ -0,0 +1,12 @@
+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
diff --git a/v2.0/source/MSHEAD.ASM b/v2.0/source/MSHEAD.ASM
new file mode 100644 (file)
index 0000000..108197d
--- /dev/null
@@ -0,0 +1,198 @@
+; 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
diff --git a/v2.0/source/MSINIT.ASM b/v2.0/source/MSINIT.ASM
new file mode 100644 (file)
index 0000000..36edf9f
--- /dev/null
@@ -0,0 +1,408 @@
+; 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
diff --git a/v2.0/source/PCLOCK.ASM b/v2.0/source/PCLOCK.ASM
new file mode 100644 (file)
index 0000000..6018bfd
Binary files /dev/null and b/v2.0/source/PCLOCK.ASM differ
diff --git a/v2.0/source/PRINT.ASM b/v2.0/source/PRINT.ASM
new file mode 100644 (file)
index 0000000..dd58735
--- /dev/null
@@ -0,0 +1,1645 @@
+;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
diff --git a/v2.0/source/PRINT_v211.ASM b/v2.0/source/PRINT_v211.ASM
new file mode 100644 (file)
index 0000000..4585af7
--- /dev/null
@@ -0,0 +1,1645 @@
+;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
diff --git a/v2.0/source/PROC.ASM b/v2.0/source/PROC.ASM
new file mode 100644 (file)
index 0000000..abc6f9c
--- /dev/null
@@ -0,0 +1,130 @@
+;
+; 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
diff --git a/v2.0/source/PROFIL.ASM b/v2.0/source/PROFIL.ASM
new file mode 100644 (file)
index 0000000..08a5ada
--- /dev/null
@@ -0,0 +1,705 @@
+        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
diff --git a/v2.0/source/PROFILE.txt b/v2.0/source/PROFILE.txt
new file mode 100644 (file)
index 0000000..2d50631
Binary files /dev/null and b/v2.0/source/PROFILE.txt differ
diff --git a/v2.0/source/PROHST.HLP b/v2.0/source/PROHST.HLP
new file mode 100644 (file)
index 0000000..13880e5
--- /dev/null
@@ -0,0 +1,35 @@
+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
diff --git a/v2.0/source/QUICK.txt b/v2.0/source/QUICK.txt
new file mode 100644 (file)
index 0000000..d443b8e
Binary files /dev/null and b/v2.0/source/QUICK.txt differ
diff --git a/v2.0/source/RDATA.ASM b/v2.0/source/RDATA.ASM
new file mode 100644 (file)
index 0000000..7a9b368
Binary files /dev/null and b/v2.0/source/RDATA.ASM differ
diff --git a/v2.0/source/README.txt b/v2.0/source/README.txt
new file mode 100644 (file)
index 0000000..c5bbf25
--- /dev/null
@@ -0,0 +1,177 @@
+                         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
diff --git a/v2.0/source/RECMES.ASM b/v2.0/source/RECMES.ASM
new file mode 100644 (file)
index 0000000..0723208
Binary files /dev/null and b/v2.0/source/RECMES.ASM differ
diff --git a/v2.0/source/RECOVER.ASM b/v2.0/source/RECOVER.ASM
new file mode 100644 (file)
index 0000000..05d27f9
--- /dev/null
@@ -0,0 +1,876 @@
+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
diff --git a/v2.0/source/ROM.ASM b/v2.0/source/ROM.ASM
new file mode 100644 (file)
index 0000000..f668986
--- /dev/null
@@ -0,0 +1,530 @@
+;\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
diff --git a/v2.0/source/RUCODE.ASM b/v2.0/source/RUCODE.ASM
new file mode 100644 (file)
index 0000000..927a559
Binary files /dev/null and b/v2.0/source/RUCODE.ASM differ
diff --git a/v2.0/source/SKELIO.ASM b/v2.0/source/SKELIO.ASM
new file mode 100644 (file)
index 0000000..b2ff8e3
--- /dev/null
@@ -0,0 +1,1377 @@
+       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
diff --git a/v2.0/source/SORT.ASM b/v2.0/source/SORT.ASM
new file mode 100644 (file)
index 0000000..a4f39e8
--- /dev/null
@@ -0,0 +1,420 @@
+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
diff --git a/v2.0/source/SORTMES.ASM b/v2.0/source/SORTMES.ASM
new file mode 100644 (file)
index 0000000..4fb6556
Binary files /dev/null and b/v2.0/source/SORTMES.ASM differ
diff --git a/v2.0/source/STDBUF.ASM b/v2.0/source/STDBUF.ASM
new file mode 100644 (file)
index 0000000..400280a
Binary files /dev/null and b/v2.0/source/STDBUF.ASM differ
diff --git a/v2.0/source/STDCALL.ASM b/v2.0/source/STDCALL.ASM
new file mode 100644 (file)
index 0000000..5d9d926
Binary files /dev/null and b/v2.0/source/STDCALL.ASM differ
diff --git a/v2.0/source/STDCTRLC.ASM b/v2.0/source/STDCTRLC.ASM
new file mode 100644 (file)
index 0000000..a02d90d
Binary files /dev/null and b/v2.0/source/STDCTRLC.ASM differ
diff --git a/v2.0/source/STDFCB.ASM b/v2.0/source/STDFCB.ASM
new file mode 100644 (file)
index 0000000..17cf4e9
--- /dev/null
@@ -0,0 +1,16 @@
+;
+; 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
diff --git a/v2.0/source/STDIO.ASM b/v2.0/source/STDIO.ASM
new file mode 100644 (file)
index 0000000..c14c98a
--- /dev/null
@@ -0,0 +1,17 @@
+;
+; 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
diff --git a/v2.0/source/STDPROC.ASM b/v2.0/source/STDPROC.ASM
new file mode 100644 (file)
index 0000000..3d44849
--- /dev/null
@@ -0,0 +1,16 @@
+;
+; 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
diff --git a/v2.0/source/STDSW.ASM b/v2.0/source/STDSW.ASM
new file mode 100644 (file)
index 0000000..30a8a16
--- /dev/null
@@ -0,0 +1,34 @@
+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
diff --git a/v2.0/source/STRIN.ASM b/v2.0/source/STRIN.ASM
new file mode 100644 (file)
index 0000000..2bc58fb
--- /dev/null
@@ -0,0 +1,292 @@
+        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
diff --git a/v2.0/source/SYS.ASM b/v2.0/source/SYS.ASM
new file mode 100644 (file)
index 0000000..e15758e
--- /dev/null
@@ -0,0 +1,587 @@
+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
diff --git a/v2.0/source/SYSCALL.ASM b/v2.0/source/SYSCALL.ASM
new file mode 100644 (file)
index 0000000..02d38d8
--- /dev/null
@@ -0,0 +1,749 @@
+;
+; 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
diff --git a/v2.0/source/SYSCALL.txt b/v2.0/source/SYSCALL.txt
new file mode 100644 (file)
index 0000000..26d4729
--- /dev/null
@@ -0,0 +1,1657 @@
+\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
diff --git a/v2.0/source/SYSIMES.ASM b/v2.0/source/SYSIMES.ASM
new file mode 100644 (file)
index 0000000..1ff4f0d
Binary files /dev/null and b/v2.0/source/SYSIMES.ASM differ
diff --git a/v2.0/source/SYSINIT.ASM b/v2.0/source/SYSINIT.ASM
new file mode 100644 (file)
index 0000000..0c198b1
--- /dev/null
@@ -0,0 +1,1424 @@
+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
diff --git a/v2.0/source/SYSINIT.txt b/v2.0/source/SYSINIT.txt
new file mode 100644 (file)
index 0000000..fa20d08
Binary files /dev/null and b/v2.0/source/SYSINIT.txt differ
diff --git a/v2.0/source/SYSMES.ASM b/v2.0/source/SYSMES.ASM
new file mode 100644 (file)
index 0000000..c7dea6d
--- /dev/null
@@ -0,0 +1,51 @@
+   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
diff --git a/v2.0/source/TCODE.ASM b/v2.0/source/TCODE.ASM
new file mode 100644 (file)
index 0000000..dfe6ca5
--- /dev/null
@@ -0,0 +1,1088 @@
+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
diff --git a/v2.0/source/TCODE2.ASM b/v2.0/source/TCODE2.ASM
new file mode 100644 (file)
index 0000000..bc2742d
--- /dev/null
@@ -0,0 +1,522 @@
+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
diff --git a/v2.0/source/TCODE3.ASM b/v2.0/source/TCODE3.ASM
new file mode 100644 (file)
index 0000000..547c937
--- /dev/null
@@ -0,0 +1,677 @@
+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
diff --git a/v2.0/source/TCODE4.ASM b/v2.0/source/TCODE4.ASM
new file mode 100644 (file)
index 0000000..a8c44a6
--- /dev/null
@@ -0,0 +1,1002 @@
+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
diff --git a/v2.0/source/TCODE5.ASM b/v2.0/source/TCODE5.ASM
new file mode 100644 (file)
index 0000000..63fb3cf
--- /dev/null
@@ -0,0 +1,953 @@
+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
diff --git a/v2.0/source/TDATA.ASM b/v2.0/source/TDATA.ASM
new file mode 100644 (file)
index 0000000..9a4af2e
--- /dev/null
@@ -0,0 +1,243 @@
+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
diff --git a/v2.0/source/TIME.ASM b/v2.0/source/TIME.ASM
new file mode 100644 (file)
index 0000000..f1e4a1c
Binary files /dev/null and b/v2.0/source/TIME.ASM differ
diff --git a/v2.0/source/TSPC.ASM b/v2.0/source/TSPC.ASM
new file mode 100644 (file)
index 0000000..85f02e7
Binary files /dev/null and b/v2.0/source/TSPC.ASM differ
diff --git a/v2.0/source/TUCODE.ASM b/v2.0/source/TUCODE.ASM
new file mode 100644 (file)
index 0000000..1a69b77
Binary files /dev/null and b/v2.0/source/TUCODE.ASM differ
diff --git a/v2.0/source/UINIT.ASM b/v2.0/source/UINIT.ASM
new file mode 100644 (file)
index 0000000..2e6bc77
Binary files /dev/null and b/v2.0/source/UINIT.ASM differ
diff --git a/v2.0/source/UTILITY.txt b/v2.0/source/UTILITY.txt
new file mode 100644 (file)
index 0000000..a63793c
--- /dev/null
@@ -0,0 +1,813 @@
+\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
diff --git a/v2.0/source/WSBAUD.BAS b/v2.0/source/WSBAUD.BAS
new file mode 100644 (file)
index 0000000..cc5426c
Binary files /dev/null and b/v2.0/source/WSBAUD.BAS differ
diff --git a/v2.0/source/WSMSGS.OVR b/v2.0/source/WSMSGS.OVR
new file mode 100644 (file)
index 0000000..714ecbf
Binary files /dev/null and b/v2.0/source/WSMSGS.OVR differ
diff --git a/v2.0/source/WSOVLY1.OVR b/v2.0/source/WSOVLY1.OVR
new file mode 100644 (file)
index 0000000..123b56e
Binary files /dev/null and b/v2.0/source/WSOVLY1.OVR differ
diff --git a/v2.0/source/XENIX.ASM b/v2.0/source/XENIX.ASM
new file mode 100644 (file)
index 0000000..dd20b50
--- /dev/null
@@ -0,0 +1,907 @@
+;\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
diff --git a/v2.0/source/XENIX2.ASM b/v2.0/source/XENIX2.ASM
new file mode 100644 (file)
index 0000000..1535dbb
--- /dev/null
@@ -0,0 +1,626 @@
+;\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