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&n