PCDOS.TIP  ·  TIP  ·  61.4 KB  ·  1984-08-27  ·  from IBM-PC-User-Group-Software-Library_Disk-44_Feb-1980
   [This text file was downloaded from an electronic bulletin board.  
    There may be occasional errors or spurious characters in the text]


                            Notes and Observations 
                                       - 
                                      on 
                                       - 
                        IBM PC-DOS and Microsoft MS-DOS 
                                       - 
                             Releases 2.0 and 2.1 
                                       - 
                                  April, 1984 
 
 
             This  document  is a collection of data from  various  sources,  
        including  bulletin  boards,   magazines,   seminar  handouts,   and  
        independent research. 
 
        WARNING: This information is provided without warranty of any kind. 
        Each individual must determine the applicability and accuracy ofthis  
        information to their specific environment. 
 
        If you have corrections,  additions,  or comments,  please send them  
        to: 
                                 John Chapman 
                              844 S. Madison St. 
                          Hinsdale, Illinois   60521 
        Or, send  EMAIL  to  userid   [70205,1217]  on  CompuServ, 
        or         MAIL  to  userid    $AC          on  PCSHARE 
 
   BATCH PROCESSING 
 
   To modify the DOS 2.0 command interpreter so that the default is echo off 
   when a batch file is run, 
 
   C>debug \command.com 
   -e1721 28 1f 
   -e364a 24 26 c6 06 6e 09 00 e9 19 e8 
   -w 
   Writing 4500 bytes 
   -q 
 
   The DOS Environment is accessible for use in BATs. 
 
   The standard keywords COMSPEC, PATH, PROMPT et al can all be read and set. 
   New keywords can be set and checked within BATs.  The keywords are saved 
   across BAT executions. 
 
   For instance BATs can check which screen is active using SET conventions 
   as follows: 
 
           . NOTE leading and trailing Percent signs 
           IF %SCREEN% == MONO GOTO COLOR 
           IF %SCREEN% == COLOR GOTO MONO 
           :COLOR 
           SET SCREEN=COLOR 
           . NOTE no spaces around '=' in SET 
           MODE CO80 
           EXIT 
           :MONO 
           SET SCREEN=MONO 
           MODE MONO 
           EXIT 
           . SCREEN is set and saved across BAT executions 
 
   Another example using a link convention allows BATs to call BATs: 
 
   *****CALL.BAT***** 
 
           IF NOT %BATLABEL% == . GOTO %BATLABEL% 
           . note BATLABEL is assumed to be set to '.' as a null value 
           ECHO DO SOME STUFF HERE 
           SET BATCALR=%0 
           . give the called BAT my name to get back 
           . then leave word where to come back to 
           SET BATLABEL=RETURN 
           . set further parms to save %1 thru %9 if necessary 
           CALLED 
           :RETURN 
           ECHO FINISH UP HERE AFTER RETURN 
 
   PC/MS-DOS Tips (2.0/2.1)                                             2 
 
   The DOS Environment is accessible for use in BATs. (Cont'd) 
 
   *****CALLED.BAT***** 
 
           ECHO DO STUFF WE WERE CALLED TO DO 
           . return to caller 
           %BATCALR% 
           . separate keywords will be necessary if further calls 
           . will be made 
 
 
   A note of caution (this is documented), the environment at boot time, 
   is limited (I believe to only 128 bytes). If any resident modules are 
   installed (i.e. PRINT, MODE, or GRAPHICS) the area cannot be expanded. 
   You can SET enough variables from within AUTOEXEC.BAT to get enough 
   space to get by. 
 
   I would also recommend setting up a set of conventions and preinitializing 
   the parms you'll use to '.'; Null parameters are removed from the 
   environment. 
 
   In summary - 
   The rules are simple 
           SET a parm without percent signs 
           refer to them by enclosing them in percent signs 
 
   I hope this discovery will generate a lot of re-thinking some BAT 
   techniques. 
 
   PC/MS-DOS Tips (2.0/2.1)                                             3 
                    Current MSDOS 1.xx - 2.xx Disk formats  
 
                            (T. Jennings 19 Aug 83) 
         
             Disk Type                     Type Code 
        ....................................................... 
        Single Density Single Sided 8"     (SD128) 
   **** Double Density Single Sided 8"     (DD1024) 
   **** FIDO's 8" Double Density           (DD1K) 
        Double Density Double Sided 8"     (DD1024-2) 
        IBM Displaywriter System disk      (SD256) 
        IBM Displaywriter System disk      (DD256-2) 
        IBM PC 8 Sector Single Sided       (IBM8) 
        IBM PC 9 Sector Single Sided       (IBM9) 
        IBM PC 8 Sector Double Sided       (IBM8-2) 
        IBM PC 9 Sector Double Sided       (IBM9-2) 
        Single Density Double Sided 8"     (SD128-2) 
 
   **** Never did get Microsoft to figure out which one these 
        is the "correct" 8 inch format. Who knows. 
        Type      Dir  Disk      Fats Blk  Res  Sec       FAT 
        Code      Size Size           size secs size      ID 
        ..................................................... 
        SD128      68   251K     2     512  1    128      FE 
        DD1K      192   660K     2    1024  1   1024      FE 
        DD1024     96   612K     2    1024  1   1024      FE 
        DD1024-2  192  1232K     2    1024  1   1024      FF 
        SD256      80   287K     2     512  2    256      FA  Note 1 
        DD256-2   172  1001K     2    1024  2    256      FB  Note 2 
        IBM8       64   162K     2     512  1    512      FE 
        IBM9       64   180K     2     512  1    512      FC 
        IBM8-2    112   320K     2    1024  1    512      FF 
        IBM9-2    112   360K     2    1024  1    512      FD 
        SD128-2    68            2     512  4    128      FC 
         
        Type      trks secs res  sec  FAT  dir  1st  2nd  1st  1st  totl num. 
        Code           trk  secs size size size FAT  FAT  dir  data secs heads 
        ...................................................................... 
        SD128     77   26    1    128   6  17    1    7   13   30   2002  1 
        DD1024    77    8    1   1024   1   3    1    2    3    6    616  1 
        DD1024-2  77    8    1   1024   2   6    1    3    5   11   1232  2 
        SD256     77   15   17    256   4  10    2    6   10   20   1155  1 Note 1 
        DD256-2   77   26   54    256   6  20    2    8   14   34   4004  2 Note 2 
        IBM8      40    8    1    512   1   4    1    2    3    7    320  1 
        IBM9      40    9    1    512   2   4    1    3    5    9    360  1 
        IBM8-2    40    8    1    512   1   7    1    3    5   10    640  2 
        IBM9-2    40    9    1    512   2   7    1    3    5   12    720  2 
        SD128-2   77    26   4    128  12  17    4   16   28   45   4004  2 
 
   Note 1: 
        15 sector bias in BIOS 
   Note 2: 
        52 sector bias in BIOS 
 
   PC/MS-DOS Tips (2.0/2.1)                                             4 
                      Additional feature in DEBUG command 
 
   There is a compare feature in DEBUG that is not in the documentation. Two  
   blocks  of  memory  can  be compared,  byte by byte  with  the  following  
   command:  
 
          -C AD1 AD2 AD3 
       
   DEBUG will compare the memory block from AD1 to AD2 with the memory block  
   starting at AD3.  The results appear in a table showing both blocks  side  
   by side with the addresses and the corresponding contents. 
 
                     (from IBM.PC Users Group of Winnipeg) 
 
   PC/MS-DOS Tips (2.0/2.1)                                             5 
 
                             Program File Formats 
 
       The order of the segments in memory is determined by the linker;  and  
   all the segments are contiguous, unless you do some really determined and  
   tricky  hacking.  Supposedly,  the  linker  determines the order  of  the  
   segments by putting them in "alphabetical order by segment name",  or  at  
   least  that's what the documentation says it's supposed to do;  but  I've  
   found  that it puts them in the order in which they're encountered in the  
   program  source  code,   unless  you  create  a  dummy  file  (see   LINK  
   instructions)  with  a different sequence and make it first in  the  LINK  
   list  of  OBJ modules.  (I generally put them in source in  the  sequence  
   code,  data,  stack;  they  always come out in that order,  regardless of  
   segment names,  unless I use the dummy file.  Let's assume that  sequence  
   for the remainder of this discussion.) 
 
      With an .EXE file, just before execution, the registers are as follows: 
 
   AX        - ostensibly per doc, zero; seems to contain the number 
                of characters in the command tail, though 
 
   BX:CX     - 32-bit number showing load module memory size in bytes 
                (good for dynamically allocating memory) 
 
   DX        - zero 
 
   SS:SP     - if you defined a stack segment, these are loaded 
                accordingly; if not, SS=CS, SP=0FFFFH or end of 
                memory 
 
   DS and ES - SEGMENT address of "program header" (see below) 
 
   CS:IP     - far address of label in "END" statement of program 
 
      The  program  header  is  the standard 256-byte  .COM  file  "header",  
   similar  to what you would expect to see at 00-FFH in CP/M 2.x  (but  see  
   doc for important differences!).  Therefore, DS = CS - 10H (which is 100H  
   divided by 10H) if the code seg is the first (owest) in memory,  because  
   it points to a location 100H before the start of the code seg. 
 
   PC/MS-DOS Tips (2.0/2.1)                                             6 
                             Program File Formats   (Cont'd) 
 
      Now, if CS is, say, 9E3H when you come up, then DS and ES will contain  
   9D3H.  (Remember,  though, that your code thinks it starts at 9E3:0, zero  
   being  the  address  you  specified  in  your  END  directive,   and  the  
   instruction  pointer  will  actually  contain zero.)  These  values  have  
   nothing  at all to do with the place at which your data seg  is  located;  
   they  point at that "program header".  At location 9D3:80 (DS:80) is  the  
   command  tail,  if  you're gonna reference that;  its length is in AX  (I  
   believe) and is also pointed to by the expression DS:80 (just like  CP/M;  
   data  starts  at 81H),  or to say it another way,  in this case  absolute  
   memory location 09DB0 (09D30+80).  But your code segment  is,  say,  400H  
   long,  and  the  linker knew that 'cause the assembler told it so in  the  
   seg, the instructions 
 
           MOV     AX,DATASEG 
           MOV     DS,AX 
           MOV     ES,AX 
 
   (where DATASEG is the name of your data segment) will have been  resolved  
   by  the  linker  in this way;  the first instruction of those  three  was  
   interpreted by the assembler as an immediate move,  but the "data" to  be  
   moved  into AX was marked as relocatable.  The linker leaves instructions  
   for the loader to add 9E3H (or whatever address the loader decided was  a  
   good  place  to put the program) to the value of the "constant"  DATASEG,  
   which  is  equal  to 40H (400H/10H) because it's being  "loaded"  into  a  
   segment  register,  and when you look at that instruction under DEBUG  it  
   would  say  MOV AX,0A23H.  (Obviously,  this is the  process  of  address  
   resolution.) In absolute addresses, the codeseg starts at 09E30H, and the  
   dataseg  400H later at 0A230H;  in 8086 shorthand that's 9E3:0 and  A23:0  
   respet2vely.  (This  assumes the stackseg is last,  say at  A98:0;  that  
   would  imply  that  your data seg  was  (0A98H-0A23H)*10H,  or  750H,  in  
   length.)  
 
      Almost  all  instructions  accessing data use DS as  "base"  register,  
   unless  you  override that with a prefix (as in  MOV  AX,ES:BLKCTR).  All  
   instructions  accessing  storage  require one of the  segregs  as  "base"  
   register.  (String primitives ALWAYS work with DS and/or ES and can't  be  
   overridden by a prefix;  instructions using BP as an "index" are relative  
   to  SS,  unless  overridden  by a prefix;  otherwise,  it's DS  when  not  
   overridden. Be careful!) 
 
   PC/MS-DOS Tips (2.0/2.1)                                             7 
 
                             Program File Formats   (Cont'd) 
 
      In BAL,  you give the assembler a USING statement;  that tells it that  
   offsets  will  be  computed relative to the first operand  of  the  USING  
   statement,  and tells it to use the second operand as "base" register  in  
   base+offset instructions. The code won't work properly until you load the  
   address  of  the  first  operand into the register named  by  the  second  
   operand.  In  8086,  you  give the assembler  an  ASSUME  statement;  for  
   instructions  using CS as "base" (segment) register (all of  them),  such  
   offsets  will be calculated from the point named as xyz in the  statement  
   "ASSUME  CS:xyz,  DS:abc,ES:def";  for instructions which use DS (such as  
   MOV AX,BLKCTR), the value of the offset of BLKCTR is computed relative to  
   label abc;  for ES instructions (when you use a segment override  prefix,  
   as in MOV AX,ES:BLKCTR),  offset is computed relative to "def".  Then, if  
   you  haven't  pointed to "abc" with your segment register in such  a  way  
   that  (for example) DS:offset points to the absolute location of  BLKCTR,  
   you'll be moving something random into your AX register. With .COM files,  
   CS=DS=ES at startup; note that a typical .COM file ASSUME statement looks  
   like  ASSUME  CS:CODESEG,DS:CODESEG,ES:CODESEG,SS:CODESEG  (whoops,   one  
   more) 
 
   But  as you can see from the preceding stuff,  with .EXE files DS and  ES  
   start out with values which don't point at your data at all.  You have to  
   do  something like MOV AX,abc!MOV DS,AX!MOV ES,AX to put coherent  values  
   into  the  segregs,  just as you have to do something like BALR  4,0!BCTR  
   4,0!BCTR 4,0 to put a coherent value into the base reg in BAL.  That  is,  
   with an .EXE file, you tell the assembler to use DATASEG as the reference  
   point to compute an offset from (with the ASSUME statement); and then you  
   must  make sure you load DS with a value that will,  in combination  with  
   the computed offset, point at the right data. 
 
      One more example, then I'll stop. Let's take a BAL program and specify  
   a code "segment" 4096 bytes long, a data "segment" 4096 bytes long, and a  
   "stack  segment"  after that.  In order to be able to access all of  that  
   data in that way,  you'd need three base registers; let's use 3, 4 and 5.  
   With BAL,  you have to figure the addresses yourself, so we get something  
   like: 
     
   PGM     START   0 BEGIN   STM     14,12,12(13) 
           BALR    3,0 
   DTSEG   EQU     START+4096 
   STSEG   EQU     START+8192 
           USING   *,3 
           USING   DTSEG,4 
           USING   STSEG,5 
   START   ST      13,SAVEAREA+4 
           LA      13,SAVEAREA 
           LA      4,4096(3) 
           LA      5,8192(3) 
   That is, if I remember my BAL. You get the idea. 
 
   PC/MS-DOS Tips (2.0/2.1)                                             8 
 
                       The CTTY Command and Basic Feature 
 
                               (from Tom Jennings) 
 
            The DOS manual explains that the command is simply CTTY 
            device-name. This will transfer control from the keyboard and 
            screen to that device.  It suggests that LPT1: is not a ood 
            idea since the printer communicates (mostly) one way. What 
            this really leaves is COM1:, COM2: and AUX:  
            I very cleverly tried typing CTTY COM1: It does do something, 
            it kills the keyboard and a cold BOOT is necessary to 
            restart. Well, that wasn't it. Something must occur prior to 
            the CTTY command. Being strickly a seat-of-the-pants type, I 
            set the HAYES to ANSWER and called in. Nice, I had a 
            connection (CARRIER/carrier). I rushed over to the PC 
            keyboard and typed CTTY COM1: and the screen went dead. So, 
            what else is new....But, on my other SYSTEM, (other end of 
            the office), the prompt A> appeared. I sat and typed on the 
            terminal just as though I was sitting in front of the IBM. 
            Well, what do you know? 
            1) Commands are limited to what the terminal keyboard can 
            reproduce i.e. ^C for CTRL-BREAK but not CTRL-ALT-DEL (as if 
            you would want that one anyway). 
            2) Going to BASIC cuts you off. SYSTEM control returns to the 
            keyboard. 
            3) Most commands work except COPY as it relates to CON: or 
            COM1: COPY from disk to disk worked O.K. 
            4) This means is total control from outside while in DOS 
            only on a line-by-line basis. Anything which relies on screen 
            mapping will not work. (Run Norton's DISKMAP from the 
            terminal and the map appears on the PC screen.) 
 
            You may be wondering why all this verbage.  Well....  the result  
   of  my  efforts is a BASIC program called RING.BAS which will set up  the  
   HAYES  to  patiently look for an incoming ring,  and very  politely  turn  
   SYSTEM  control over to the caller.  Oh,  I forgot to mention  the  BASIC  
   program  must be called from a BATCH file called OUTSIDER.BAT.  When RING  
   goes back to the SYSTEM,  the next command is CTTY COM1: Slick, huh? RING  
   will even write the BATCH file for you.  Just take a look at the internal  
   documentation for additional information.  
 
   Note:  Tom Jenning's 'FIDO' board is at (415) 864-1418  
 
   PC/MS-DOS Tips (2.0/2.1)                                             9 
               DOS 2.0 HAS PROBLEMS WITH REDIRECTION OF I/O 
 
        There   are  problems  in  DOS  2.0 with the redirection of I/O  and  
   piping  for programs that use the original  DOS  1.1  INT   21   function  
   calls   for  input.    This  problem  is  readily apparent to users of C  
   language packages such as Computer  Innovation  C-86,   Lattice  C,   or  
   Microsoft  C  (you'd  think  they  would  get it right!).  One problem is  
   that all output to the screen is redirected,   even     keyboard   echo.  
   Correct   operation   would  redirect  all program output for the  screen  
   (stdout)  to the specified >file,  but the echo of keyboard input   would  
   still   be  sent  to  the  screen.   Instead,  both the keyboard echo and  
   the program output are sent to the redirected   >file.   Thus,  if  you  
   run   programs  such as the CAT.C (K&R,page 154) example that  Microsoft  
   distributes  with their C;  or COPYIO.C (K&R,page 15)  with  the   output  
   redirected to a file, you will get the following results: 
 
         1.   Under  DOS  1.1, keyboard input is echoed to the screen 
         as you type and each line  appears  in  the  >file  once  as 
         expected. 
         2.   Under  DOS  2.0,  keyboard  input  is not echoed to the 
         screen, but each line appears in the >file twice! 
 
        This  situation is handled correctly in DOS  2.0  if  the  new   INT  
   21  function call 3F is used.   This can be demonstrated by  redirecting  
   output for the DOS 2.0 function MORE - it works as desired. 
 
        The  redirecting of input to these programs doesn't  work   properly  
   either.    If   the  file  has  not been edited with debug to end with  a  
   control-Z,  the  program will hang up at the end  of  the  <input   file.  
   You  must reboot the system to continue!  Also, if you pipe the output of  
   the  first  program  into a second  program,   the  final   output   will  
   contain  each   line  four times,  doubled spaced after the second  lie!  
   These  problems do not occur for programs that  use  the  new  DOS   2.0  
   calls for I/O, such as SORT and MORE. 
 
        The   question  now  is  how  do  you fixup C programs to run  under  
   DOS  2.0 and not redirect keyboard echo to the stdout file?   The easiest  
   way  for C compilers that include their  own  redirection  code   is   to  
   change  their redirection symbols from <,  >,  and >> to something  else.  
   Then DOS  2.0  won't  do  the redirection,  so the C code will be able to  
   do  it correctly.       With the Microsoft C compiler,  this is  easily  
   accomplished  by modifying three lines of code inMAIN.C.      A  good   
   choice  is  to modify MAIN.C  so  that  it    redirects  on the symbols  
   {,  
,  and 

.  The only restriction is that these symbols then   should   
   not  be  used in  filenames.   With these changes, the user can choose to  
   let either DOS  <,  >,  >>      or C  {, 
,  

   do  the  redirecting.    
   The   modified  version   of MAIN.C   is  compiled  to  obtain  a  new  
  MAIN.OBJ,  which  can  either be put into the library MC.LIB to  replace   
   the     original MAIN by  using  the  LIB.EXE  utility,   i.e.      LIB    
   MC.LIB   MAINMAIN  or it can be kept separate.   If  kept   separate,   
   remember   to   include it  in  the  list  of   .OBJ   files   specified         
   in  the LINK call, i.e. LINK cmain myprogram. 
 
        The three lines to change in Microsoft C's MAIN are: 
             case '{': 
             case '
': 
             if (*line == '
') 
 
   PC/MS-DOS Tips (2.0/2.1)                                             10 
 
 
        The following is a summary of some undocumented DOS 2.0 functions 
   which can be invoked through interrupt 21H. The information provided 
   herein have inaccuracies, so use it at our own risk! It is correct to 
   the best of my knowledge. See the section in your DOS 2.0 manual entitled 
   "Invoking DOS Functions" for further information. The function number 
   provided below for each operation is to be placed in the AH register as 
   described in the DOS manual. All numbers shown are in hex. 
 
   FUNCTION                DESCRIPTION 
 
      37           This interrupt is used to change incompatible 
                   configuration parameters to allow for switch 
                   indicators and whether hardware devices are 
                   available at every level of the tree directory. 
 
                   Usage:  MOV     AH, 37 
                           MOV     AL, func                ; function code 
                           MOV     DL, data 
                           INT     21H 
                   ; read function data is returned in DL 
 
                   Function code for AL: 
                   0 - Return the DOS switch character in DL. 
                       Many systems might return "-". 
                   1 - Make the character in DL the switch character. 
                   2 - Read the device availability byte into DL. A 
                       0 means devices that devices must be accessed 
                       in file I/O calls by /DEV/device. A non-zero 
                       value means that devices are accessible at 
                       every level of the directory tree (e.g., PRN 
                       is the printer and not a file PRN). 
                   3 - Set the device availability byte to the 
                       contents of DL. 
 
                   Possible errors returned in AL: 
                   FF - Illegal function code specified in AL. 
 
      1F (?)       Retrieve the pointer to the default drive parameter block. 
 
                   Usage:  MOV     AH, 1F 
                           INT     21H 
                   ; address of drive parameter block is returned in DS:BX 
 
   PC/MS-DOS Tips (2.0/2.1)                                             11 
      32 (?)       Retrieve the pointer to the drive parameter block 
                   for the drive number in DL, where 0 = default drive, 
                   1 = drive A:, 2 = drive B:, etc.). 
 
                   Usage:  MOV     AH, 32h 
                           MOV     DL, drivenum 
                           INT     21H 
                   ; address of drive parameter block is returned in DS:BX 
                   ; AL contains FF if the drive # in DL is invalid. 
 
      F8 (?)       Set OEM handler for INT 21H calls from F9 through FF 
                   to DS:DX. To reset these calls, pass DS and DX with FFFF. 
                   DOS is set up to allow ONE handler for all 7 of these 
                   calls. Any call to these handlers will result in the 
                   carry bit being set and AX will contain 1 if they are 
                   not initialized. The handling routine is passed all 
                   registers just as the user set them. The OEM handler 
                   routine should be exited through an IRET. 
 
                   Usage:  LDS     DX, handleaddr 
                           MOV     AH, F8h 
                           INT     21H 
      4B           Load and possibly execute a program (EXEC). This call 
                   is PARTIALLY documented in the IBM DOS 2.0 manual, but 
                   several function call values (for register AL) are 
                   omitted. They are: 
 
                           1 - Create the program segment prefix and 
                               load the program, but do not begin 
                               execution. The CS:IP and SS:SP of the 
                               program are placed in the area provided 
                               by the user. 
 
                                   +-------------------------------+ 
                                   | Word segment addr of environ. | 
                                   +-------------------------------+ 
                                   | Dword ptr to cmd line at 80h  | 
                                   +-------------------------------+ 
                                   | Dword ptr to default FCB to   | 
                                   | be passed at 5Ch.             | 
                                   +-------------------------------+ 
                                   | Dword ptr to default FCD to   | 
                                   | be passed at 6Ch.             | 
                                   +-------------------------------+ 
                                   | Dword value of SS:SP returned | 
                                   +-------------------------------+ 
                                   | Dword value of CS:IP returned | 
                                   +-------------------------------+ 
 
                           2 - This function still remains a mystery. 
   PC/MS-DOS Tips (2.0/2.1)                                             12 
 
      4E           Find first matching file (FIND FIRST). This function 
                   is PARTIALLY documented in the IBM DOS 2.0 manual. 
                   The description of what is returned in the DTA where 
                   the first 21 bytes are "reserved for DOS use on 
                   subsequent find next calls" contain the following 
                   in this order: 
 
                           1 byte  - attribute byte of search 
                           1 byte  - drive used in search 
                           11 bytes- The search name used 
                           2 bytes - Word value of last entry 
                           4 bytes - Dword pointer to this DTA 
                           2 bytes - Word directory start 
                           ----------------------------------- 
                           { The documented bytes follow here 
         h (                 such as attribute found, file's 
                             time, date, size, and name found. 
 
 
      50           Define the current DTA (?) - this is all I know... 
      51           Retrieve current DTA (?) 
      52           Retrieve "IVARS" (?) 
      53           Define something about a DTA (?) 
      55           Duplicate a DTA (?) 
 
       The DOS critical section flag may be interrogated from 
       within an interrupt handler before requesting DOS 
       services: 
 
             MOV AH,34h 
             INT 21h 
       returns in ES:BX the address of a byte indicating (when 
       set) that DOS is in an uninterruptible state, and no DOS 
       calls should be made. 
 
   PC/MS-DOS Tips (2.0/2.1)                                             13 
 
   To access DOS' PRINT capabilities: 
             MOV AH,func 
             INT 2Fh 
     Where: 
 
             AH = 0    adds the file specified by DS:DX to the 
                       print queue.  DS:DX must point to valid 
                       opened FCB. 
 
             AH = 1    cancels the file indicated by DS:DX. 
                       DS:DX must point to an FCB, opened or 
                       unopened.  The drive byte must not be 0. 
                       Wildcards are restricted: ? is okay, * 
                       isn't. 
 
             AH > 1    do nothing. 
        Return with registers set as follows: 
                       DS,SI,DI,CX preserved, all others destroyed. 
                       AH = number of files currently in queue. 
                       AL = for AH=0, return 1 if queue was 
                            full.  For all other cases, return 0. 
                       ES:BX = pointer to list of 10 FCBs in 
                            queue, 38 bytes/FCB.  If the first 
                            byte of an FCB is -1, that FCB is 
                            unused. 
 
                       ES:DX = pointer to currently printing 
                            FCB.  If the queue is empty, DX = -1. 
 
   PC/MS-DOS Tips (2.0/2.1)                                             14 
    An Operating System Dialog - PC/MS-DOS  
 
           This  is a list of PCDOS and MSDOS peculiarities,  etc.  You will  
   have to guess from the text what the particular questions were,  but  you  
   systems  programmers will find it worth your while to rummage through  it  
   all. 
   There  is a problem of compatibility between MS-DOS and IBM PC-DOS having  
   to do with FCB Open and Create which has finally been tracked. 
   The IBM 1.0,  1.1,  and 2.0 documentation of OPEN (call 0FH) contains the  
   following statement. 
           "The current block field (FCB bytes C-D) is 
            set to zero [when an FB is opened]." 
   This statement is NOT true of MS-DOS 1.25 or MS-DOS 2.00.  The difference  
   is intentional,  and the reason is CP/M 1.4 compatibility.  Zeroing  that  
   field  is  not  CP/M compatible.  Some CP/M programs will  not  run  when  
   machine  translated if that field is zero ed.  The reason it is zeroed in  
   the IBM versions is that IBM specifically requested that it be zeroed.  
   This  is the reason for the complaints from some vendors about  the  fact  
   that  IBM MultiPlan will not run under MS-DOS.  It is probably the reason  
   that some other IBM programs don't run under MS-DOS. 
 
   PROGRAMMERS NOTE: 
           Do what all MS/PC-DOS  Systems programs do: Set 
   every single FCB field you want to use regardless of what         
   the documentation says is initialized. 
 
       a)   It seems there is a maximum of 19 handles,  no matter  what  the  
   files parameter is set to.   Is this really the case?  What does one gain  
   by  setting  files  to  less than 19?  Is memory  for  handles  allocated  
   dynamically? 
 
           There  is a maximum of 20 handles per process no matter what  the  
   files parameter is set to. There has to be a table in your process header  
   for your handles, there is a limited amount of space down there. 40 bytes  
   or  so  are taken up by each system FCB,  setting files to less  than  20  
   saves  a  little  bit of memory.  Memory for  handles  is  not  allocated  
   dynamically,  in  general an attempt to do so would fail  anyway.  Recall  
   that .COM files and most .EXE files are given the biggest piece of memory  
   possible  w  hen they are EXECed because the DOS cannot make  assumptions  
   about  how  much  memory  these programs  really  use.  This  means  they  
   typically get ALL of the free memory,  that means there is no free memory  
   to allocate dynamically. You will find that almost a ll operating systems  
   (CP/M  is  about the only exception) have a limit on the number  of  open  
   files.  MS-DOS  has  a limit of 20.  CP/M has no such limits  because  it  
   requires the user to keep FCBs in his own address space, managing FCBs is  
   a  pain.  You get si mplicity and you give up very little.  What  program  
   needs more than 20 open files?  If you can think of one, it is probably a  
   poorly written program in that it probably only needs a few open files at  
   a time and doesn't bother to close files after it's d one with them. 
 
   PC/MS-DOS Tips (2.0/2.1)                                             15 
 
       b)  Execing a program eats 5 (I think) handles per try.  Is this  the  
   passing  of parent's environment that is mentioned (very briefly) in  the  
   documentatio n?  What are these handles?  They don't seem to be allocated  
   with system calls,   either.   Is that true?   std-in,  std-out, std-err,  
   std-aux, std-prn. I suppose you would like your program to be able to use  
   the 1-12 system calls? That means there have to be 5, the first three are  
   standard UNIX style fair and are required for the software tools approach  
   to  programming.  Std-aux and Std-prn are required for system calls  3,4,  
   and 5. Just because you are handed these default handles doesn't mean you  
   can't close them. 
 
       "...   1)  what exactly is meant by the dos being in  an     unstable  
   state.  (This is what the documentation says    happens if one returns to  
   a user program directly from    an int 24 handler.)..."  
 
   It  means  that the DOS has the notion of an error being in  effect.  All  
   printer echoing is turned off,  and some other stuff doesn't work.  Also,  
   there  are dirty buffers that are not correctly flushed  out.   Thus  the  
   disks may not be consistent. 
 
       "...   2) my experimentation shows that an abort from    a hard error  
   handler causes an int 22 without the value    for int 22 being sucked out  
   of  the  program header.   every    other way out of a program  uses  he  
   terminate address in the header. 
     is this difference intentional?   Why? DOes one expect the value at int  
   22 to be different from the value in the header ever?..." 
 
   False.   No INT 22h is ever issued.   The header is only used to save the  
   previous process' vectors.  The address contained in INT 22 is saved in a  
   temp spot,  the contents of INTs 22-24 are restored from the header,  and  
   then  an  indirect  jump is taken th rough the  temp  location.   Certain  
   programs  (such  as  COMMAND)  may  want  to  intercept  themselves  from  
   terminating. 
 
   Consider this case:   You create a file on a write-protected drive.   The  
   system  will  read in a directory sector and modify  it.   It  will  then  
   attempt to write it out, causing a write-protect error.  If you catch the  
   INT  24 and do not return,  the dirty b uffer still exists.  To clear out  
   the  dirty buffer,  you MUST return from the INT 24 saying to  abort  the  
   process.   You  can then catch the terminate and restore your stack  (you  
   will be running on your parent's stack).  
 
       "...   1)  Why does PCDOS exec function 3 (overlay) demand that there  
   be some free memory that it can allocate...." 
 
   It doesn't.  IBM specifically requested that the Exec code be overlayable  
   in  the  MSDOS.   As  a  result,  it lives  in  the  transient  piece  of  
   COMMAND.COM and gets loaded when needed:  thus the requidement for enough  
   free space to laod the Exec loader (about 1.5K). 
 
   Under  other  MSDOS's  there is no such problem as the Exec  system  call  
   lives in system space.   A general rule of thumb is: if you are not going  
   to use some space,  free it.   You can do this either via SetBlock system  
   call,  or by twiddling the EXE file he ader. You should avoid .COM format  
   files. 
 
   PC/MS-DOS Tips (2.0/2.1)                                             16 
       "...  what happens if I try to overlay an .EXE file with the high/low  
   switch set to load the thing for high memory..."  
 
   Nothing.   The  HIGH/LOW  switch is only for process  creation,  not  for  
   overlays. 
 
       "...  Are all these answeres the same for MSDOS?..." [Yes.]  
 
       "... zeroing of the current record field ..." 
 
   That  incompatability  existed between 1.1 PC-DOS and  1.25  MSDOS.   2.0  
   versions of both function identically (like 1.1 PC-DOS). 
 
   The Shell command on PC-DOS 2.0 works just fine. 
 
           CONFIG.SYS 
                   shell = b:\command.com b:\ /P 
 
   Putting a disk with command.com in drive B:  when the system boots causes  
   COMMAND to be read from drive B:  and the COMSPEC in  the environment  is  
   "B:\COMMAND.COM".  If  you are having trouble it's because you are  doing  
   something wrong.  Recall that your g iven COMSPEC is checked, if you give  
   it  a  bad  one it will try to go back to the default which is  the  root  
   directory on the default drive.  Recall also that this is an undocumented  
   2.0 feature so even if it doesn't work nobody is going to be all that  ho  
   t to do something about it. 
 
    My  error on the shell stuff,  IBM hid it real well.  The "b:\" is  also  
   documented  on page 10-9 (the [d:][path] part).  They did an equally poor  
   job here. 
 
   The  /P  and the path spec have absolutely nothing to do with  the  SHELL  
   command,  they  are arguments to command.  Expecting SHELL to know  stuff  
   particular to command is not reasonable because you are not restricted to  
   running command as your top level she ll.  You can run DEBUG as your  top  
   level shell by saying 
 
           SHELL = debug.com 
 
   But watch out!! debug is not designed to run as a top level shell. if you  
   ever  say "q" to this debug the system will crash.  Command on the  other  
   hand  is  smart enough to run as a top level shell.  If you give  the  /P  
   switch to it Command does some specia l things to insure that typing EXIT  
   to  it  will  not  cause the system to crash  as  with  debug.  There  is  
   absolutely no way for command to assume the /P switch because he must run  
   as  a top level shell,  and as a utility.  The smart user has to tell him  
   what to do.  Similarly the "b:\" tells command where to look for himself.  
   For instance: 
 
           SHELL = A:\BIN\COMMAND.COM D:\COMMAND\BIN /P 
 
   The  "A:\BIN\COMMAND.COM"  tells  SYSINIT  where  to  load  the   initial  
   command.com, the "D:\COMMAND\BIN" tells command where to look for himself  
   when  he  needs  to locate his transient.  As you can see  they  are  not  
   restricted  to  being  the  same  things.  I  suggest  you  foreward  any  
   complaints about the manual to  [no address given] 
 
   PC/MS-DOS Tips (2.0/2.1)                                             17 
 
    The volume ID attribute is very special, and is treated differently from  
   all the other attributes.  It is very "sticky",  in order to find one you  
   must look for it and it alone. And when you do look for it, you find only  
   it and nothing else. 
 
   The  volume ID is constrained to be in the ROOT directory,  and there can  
   be  only one file in the ROOT with the attribute.  The FCB  flavor  calls  
   have special code to enforce these rules. 
 
   The  new calls were supposed to enforce the same rules,  but they are not  
   working correctly,  and unexpected results are possible.  You should  use  
   the old FCB calls to diddle with volume ID for the moment. 
 
   Thanks for the info.  The causes of your problems are: 
 
   (a) ^Z on output to a device in cooked mode will terminate    the output.   
   This is for CPM-compatability:   you don't want stuff after the ^Z output  
   to your printer for example.  
 
       As  a result COMMAND.COM issues a write to stdout and    then  checks  
   to  see  if the number written is equal to the    number  requested.   If  
   they are not the same,  then a redirection error is assumed.   ECHO ^Z is  
   supposed to    output a single cha racter.   It outputs NO characters and     
   thus the strange message. 
 
       Programs  that use old function calls,  get redirected,     and  then  
   read more than is expected will behave    bizarrely:  how do you indicate  
   EOF  on  a read-byte-from-    console system call?   I  believe  that  it  
   returns  ^Z.  Most  of  these  programs  we re  never  expecting  to  get  
   redirected  and  thus,  the  failure to handle  the  boundary  conditions  
   properly.  
 
   (b)  The  main crock about CP/M is that the extention on a     file  name  
   determined  the type of the file.   This is    bogus:  a file  should  be  
   distinguished by its contents,     not by its name.  When you are loading  
   a  file  with the    name *.EXE,  it d oes NOT assume that it is  an  EXE  
   format     file.   It  looks  at  the first two  bytes  for  a  signature     
   telling  it that it is an EXE file.   If it has the proper     signature,  
   then the loa proceeds.  otherwise,  it    presumes the file to be a COM- 
   form at file. 
 
       If  the file has the EXE signature,  then the internal    consistency  
   IS checked. 
 
       Pre-2.0 versions of MSDOS did not check the signature    byte for EXE  
   files. 
 
   PC/MS-DOS Tips (2.0/2.1)                                             18 
   ; 
   ;This routine implements the UN*X system call (in spite of the fact that I 
   ;called it exec, the name in the DOS manual) under Lattice C although it 
   ;should be easy to adopt it to other languages.  One caution, it uses the 
   ;undocumented 037h DOS call to retrieve the switch character.  This is 
   ;clearly marked in the code and I will change it after DOS 2.0 so I'd rather 
   ;the DOS purists don't jump down my throat about this.  If you don't like it 
   ;the way it is, change it. 
   ; 
   ; 
   ;                                                    Darrell Plank 
   ;                                                    BTL-IH 
                PAGE 55,132 
   ; 
   ; This function is modified from the macro by Brad Davis (b-davis@utah-cs) 
   ; The prolog and epilog are modified from Jim Holtman's macros for Pascal. 
   ; 
   ; exec( cmd) 
   ; char *md; 
   ; 
   ; This function accepts a string with the pathname of a command to be 
   ; executed and executes it.  The returned value is one of the following: 
   ;        0:     Successful 
   ;       -1:     Insufficient Memory 
   ;       -2:     Access Denied 
   ;       -3:     No such command 
   ;       -4:     Invalid command format 
   ; 
 
   PROLOG  MACRO 
           PUSH    BP 
           MOV     BP,SP 
           ENDM 
 
   EPILOG  MACRO   NUM 
           POP     BP 
           RET 
           ENDM 
 
   PC/MS-DOS Tips (2.0/2.1)                                             19 
 
   EXECVAL EQU     0 
   OVLVAL  EQU     3 
   FNCINT  EQU     21H 
   SETBLK  EQU     4AH 
   EXECF   EQU     4BH 
   CR      EQU     0DH 
 
   PSP     STRUC 
   INTVECT DW      ? 
   TOM     DW      ? 
   RES1    DB      ? 
   DOSLONG DB      5 DUP (?) 
   TERMINA DD      ? 
   CTRLBRK DD      ? 
   CRITERR DD      ? 
   DOS1    DB      22 DUP (?) 
   ENVIRO  DW      ? 
   DOS2    DB      46 DUP (?) 
   FPA1    DB      16 DUP (?) 
   FPA2    DB      20 DUP (?) 
   UPA     DB      128 DUP (?) 
   PSP     ENDS 
 
   EXECDEF STRUC 
   NENVIRO DW 
   COMMND  DW      2 DUP (0) 
   FCB5CH  DW      2 DUP (0) 
   FCB6CH  DW      2 DUP (0) 
   EXECDEF ENDS 
 
   PC/MS-DOS Tips (2.0/2.1)                                             20 
 
   PGROUP  GROUP PROG 
   PROG    SEGMENT BYTE PUBLIC 'prog' 
           ASSUME CS:PGROUP 
 
   PUBLIC  EXEC 
   EXEC    PROC NEAR 
           PROLOG 
           PUSH    DS 
           PUSH    ES 
   ; 
   ; free up as much memory as we can 
   ; 
           MOV     AX,CS 
           PUSH    ES              ; Save ES for later 
           MOV     ES,AX 
           MOV     BX,SS 
           SUB     BX,AX 
           ADD     BX,1000H        ; 64K for stack segment 
           MOV     AH,SETBLK 
           INT     FNCINT 
           JNC     NEAR PTR LBL1 
           MOV     AX,-1           ; Insufficient memory 
           JMP     NEAR PTR FINE 
   LBL1:   POP     ES              ; Get ES's original value 
   ; 
   ; Save SS and SP registers 
   ; 
           MOV     CS:SPSAVE,SP 
           MOV     CS:SSSAVE,SS 
   ; 
   ; set up the parameter block 
   ; 
           MOV     CS:EXECBLK.NENVIRO,0    ; Inherit envir. from parent 
           MOV     AX,3700H                ; Undocumented call for SWITCHAR 
 
   PC/MS-DOS Tips (2.0/2.1)                                             21 
 
   ; W A R N I N G:  The following function call is undocumented and is 
   ; liable to disappear or change in future versions of DOS. 
           INT     FNCINT 
           MOV     CS:COMMAND[1],DL        ; Switchar 
           MOV     DX,4[BP]                ; Address of the command  
           MOV     SI,DX 
           MOV     DI,DX 
           CLD 
           XOR     AL,AL 
           MOV     CX,100H                 ; Longest string can be 100h 
           REPNE SCASB                     ; Find Null termination 
           SUB     DX,DI 
           NEG     DX 
           MOV     CX,DX 
           DEC     CX 
           ADD     DX,2 
           MOV     CS:COMMAND[0],DL        ; Save command length 
           LEA     DI,CS:COMMAND[4] 
           MOV     AX,CS 
           MOV     ES,AX 
           REP MOVSB                       ; Copy command into our buffer 
           ASSUME  DS:PGROUP 
           MOV     AX,CS 
           MOV     DS,AX                   ; DS points at code segment 
           MOV     BYTE PTR [DI],CR        ; Put in Carriage Return 
           LEA     DX,COMMAND 
           MOV     EXECBLK.COMMND[0],DX 
           MOV     EXECBLK.COMMND[2],DS 
           MOV     BX,OFFSET EXECBLK 
           XOR     SI,SI 
           MOV     DS,[SI].ENVIRO          ; Get environment address 
   ASSUME  DS:NOTHING 
           LEA     SI,CS:COMSPEC           ; Point SI at env. variable name 
           PUSH    DS                      ; Swap 
           PUSH    ES                      ; ES 
           POP     DS                      ; and 
           POP     ES                      ; DS 
           CALL    GETENV 
           PUSH    DS                      ; Swap 
           PUSH    ES                      ; them 
           POP     DS                      ; back 
           POP     ES                      ; again 
           MOV     AH,EXECF 
           MOV     AL,EXECVAL              ; OVLVAL here for overlay 
           INT     FNCINT 
           JC      NEAR PTR LBL2 
           MOV     AX,0                    ; Successful exec 
           JMP     NEAR PTR FINE 
   LBL2:   MOV     SI,AX 
           MOV     AL,CS:ERRORS[SI]        ; Get error code 
           MOV     AH,0FFH                 ; Sign extension - Assume Negative 
   FINE:   MOV     SS,CS:SSSAVE 
           MOV     SP,CS:SPSAVE 
           POP     ES 
           POP     DS 
           EPILOG  1 
 
   PC/MS-DOS Tips (2.0/2.1)                                             22 
 
   EXECBLK EXECDEF <> 
   ; 
   ; first byte of command s length excluding the length byte and the 
   ; trailing \r.  Second byte is switchar. 
   ; 
   COMMAND DB      2 DUP(?),"C ",254 DUP(?) 
   COMSPEC DB      "COMSPEC",0 
   SPSAVE  DW 
   SSSAVE  DW 
   ERRORS  DB      ? 
           DB      ? 
           DB      -3      ; No such command 
           DB      ? 
           DB      ? 
           DB      -2      ; Access denied 
           DB      ? 
           DB      ? 
           DB      -1      ; Insufficient memory 
           DB      ? 
           DB      ? 
           DB      -4      ; Invalid command format 
 
   EXEC    ENDP 
 
   ; 
   ; Getenv expects ES to have the environment paragraph and DS:SI to point 
   ; to an ASCIIZ string with the desired environment variable in it. 
   ; It returns the address of the proper string in ds:dx. 
   ; 
 
           PUBLIC GETENV 
   GETENV  PROC NEAR 
 
           PROLOG 
           PUSH    AX 
           PUSH    CX 
           PUSH    SI 
           PUSH    DI 
           MOV     CS:VARNAME,SI           ; Save offset of env. name 
           XOR     DI,DI 
 
   PC/MS-DOS Tips (2.0/2.1)                                             23 
 
   ; 
   ; At this point ds:si points to dummy variable environment name and 
   ; es:di points to environment. 
   ; 
           CLD                             ;Forward string operations 
   TOP: 
           LODSB                           ;Get a char. of env. name 
           CMP     AL,0                    ;If we're at the end 
           JNE     NEAR PTR LBL3 
           CMP     BYTE PTR ES:[DI],'='    ;Check for match 
           JNE     NEAR PTR LBL4 
   ; 
   ; We matched 
   ; 
           INC     DI                      ;Move beyond '=' 
           MOV     DX,DI 
           POP     DI 
           POP     SI 
           POP     CX 
           POP     AX 
           EPILOG  2 
   LBL4: 
   ; 
   ; At this point we found the end of the Env. variable name but it didn't 
   ; match because the env. string was too long 
   ; 
           MOV     CX,-1 
           REPNE SCASB                     ;Find the end of the env. string 
           CMP     BYTE PTR ES:[DI],0 
           JNE     LBL3 
           MOV     AX,-1                   ;End of evironment area 
           POP     DI 
           POP     SI 
           POP     CX 
           POP     AX 
           EPILOG  2 
   PC/MS-DOS Tips (2.0/2.1)                                             24 
 
   LBL3: 
   ; 
   ; Check if the next character matches 
   ; 
           AND     AX,11011111b            ;Capitalize the character in ax 
           SCASB 
           JE      TOP 
   ; 
   ; If we get here we don't have a match so move on 
   ; 
           MOV     SI,CS:VARNAME           ;Go back to start of env. string 
           XOR     AX,AX 
           MOV     CX,-1 
           REPNE SCASB                     ;Go to next env. variable 
           CMP     BYTE PTR ES:[DI],0 
           JNE     TOP 
           MOV     AX,-1                   ;End of environment area 
           POP     DI 
           POP     SI 
           POP     CX 
           POP     AX 
           EPILOG  2 
     
   VARNAME DW      ? 
 
   GETENV  ENDP 
 
   PROG    ENDS 
           END 
   PC/MS-DOS Tips (2.0/2.1)                                             25 
+------------------------------------------------------------------------------------+ 
|    D O S   2 . 1        I N T E R R U P T    2 1       F U N C T I O N   C O D E S | 
+------------------------------------------------------------------------------------+ 
+----+--------------------------+-----------------------+----------------------------+ 
| AH |    F U N C T I O N       | Entry / Register Use  |        N O T E S           | 
+----+--------------------------+-----------------------+----------------------------+ 
| 00 | Program terminate        | CS=PSP seg. addr.     | Exit vectors are restored  | 
| 01 | Keyboard input           | N/A: returns AL       | waits for a char;echoes it | 
| 02 | Display output           | puts DL               | break checked for          | 
| 03 | AUX (Asynch) input       | N/A: returns AL       | Unbuffered, non-interrupt  | 
| 04 | AUX (Asynch) output      | puts DL               |     "        "     "       | 
| 05 | Printer output           | puts DL               |                            | 
| 06 | Direct CON: I/O          | DL=FF input           | ZF set for no input        | 
| 07 | Direct CON: input Noecho | N/A: returns AL       |                            | 
| 08 | Console input     Noecho | N/A: returns AL       | Same as Fctn 1 except echo | 
| 09 | Print string             | DS:DX ==>string       | string terminated w. $     | 
| 0A | Buffered keyboard input  | DS:DX ==>buffer       | first byte is length       | 
| 0B | Check std. input status  | AL=FF if input        | AL=00 if no input          | 
| 0C | Clear kybd buf. + other  | AL = function no.     | fctns 1,6,7,8,A allowed    | 
+----+--------------------------+-----------------------+----------------------------+ 
| 0D | Disk reset               | N/A                   | Flushes all file buffers   | 
| 0E | Select disk              | DL=drive no.          | AL=no drives on system     | 
| 0F | Open file                | DS:DX ==> FCB         | AL=FF for error            | 
| 10 | Close file               | DS:DX ==> FCB         | AL=FF for error            | 
| 11 | Search for first entry   | DS:DX ==> FCB         | AL=FF for no match         | 
| 12 | Search for next entry    | DS:DX ==> FCB         | must follow fctn 11        | 
| 13 | Delete file              | DS:DX ==> FCB         | AL=FF for error            | 
| 14 | Sequential read          | DS:DX ==> FCB         | EOF = 01 or 03 (data)      | 
| 15 | Sequential write         | DS:DX ==> FCB         | AL=01(full) 02(bad buffer) | 
| 16 | Create file              | DS:DX ==> FCB         | AL=FF for full directory   | 
| 17 | Rename file              | DS:DX ==> FCB         | AL=FF for error            | 
| 18 | Used internally by DOS:  |                       |                            | 
| 19 | Current disk             | N/A: returns AL       |                            | 
| 1A | Set DTA                  | DS:DX ==> new DTA     |                            | 
| 1B | Get FAT (default drive)  | N/A: returns DS:BX    | FAT id byte for dflt drive | 
| 1C | Get FAT (select drive)   | N/A: returns DS:BX    | FAT id byte for DL         | 
| 1D | Used internally by DOS:  |                       |                            | 
| 1E | Used internally by DOS:  |                       |                            | 
| 1F | Used internally by DOS:  |                       |                            | 
| 20 | Used internally by DOS:  |                       |                            | 
| 21 | Random read              | DS:DX ==> FCB         | AL=00 good read            | 
| 22 | Random write             | DS:DX ==> FCB         | AL=00 good write           | 
| 23 | File size                | DS:DX ==> FCB         | AL=00 rrf=no.records       | 
| 24 | Set random record field  | DS:DX ==> FCB         |                            | 
+----+--------------------------+-----------------------+----------------------------+ 
| 25 | Set interrupt vector     | DS:DX = vector        | Int specified in AL        | 
| 26 | Create new PSP           | DX = segment no.      | Use 4B instead             | 
+----+--------------------------+-----------------------+----------------------------+ 
| 27 | Random block read        | DS:DX ==> FCB         | CX = record count          | 
| 28 | Random block write       | DS:DX ==> FCB         | CX = record count          | 
| 29 | Parse filename           | DS:SI ==> command     | AL = parse service         | 
+----+--------------------------+-----------------------+----------------------------+ 
| 2A | Get date                 | N/A: returns CX:DX    | CX=yr DH=mo DL=day         | 
| 2B | Set date                 | CX:DX = new date      |                            | 
| 2C | Get time                 | N/A: returns CX:DX    | CH=hrs CL=min DH=secs      | 
| 2D | Set time                 | CX:DX = new time      |                            | 
| 2E | Set / reset VERIFY       | DL=0, AL=1/0 (on/off  | See 54                     | 
+----+--------------------------+-----------------------+----------------------------+ 
| AH |    F U N C T 	P N       | Entry / Register Use  |        N O T E S          {_ | 
+----+--------------------------+-----------------------+----------------------------+ 
 
 
+------------------------------------------------------------------------------------+ 
|    D O S   2 . 1        I N T E R R U P T    2 1       F U N C T I O N   C O D E S | 
+------------------------------------------------------------------------------------+ 
+----+--------------------------+-----------------------+----------------------------+ 
| AH |    F U N C T I O N       | Entry / Register Use  |        N O T E S           | 
+----+--------------------------+-----------------------+----------------------------+ 
| 2F | Get DTA                  | N/A: ES:BX ==>DTA     |                            | 
| 30 | Get DOS version number   | N/A: returns AX       | BX=0 CX=0 AL=maj AH=minor  | 
| 31 | Stay res. terminate      | AL=retcode DX=size    |                            | 
| 32 | Used internally by DOS:  |                       |                            | 
| 33 | Ctrl-Break check         | AL=00/01 (get/set)    |                            | 
|    |                          | DL=00/01 (off/on)     |                            | 
| 34 | Used internally by DOS:  |                       |                            | 
| 35 | Get interrupt vector     | N/A: returns ES:BX    | See 25                     | 
| 36 | Get disk free space      | DL=drive; returns BX  | DX=tot CX=bytes AX=sectors | 
| 37 | Used internally by DOS:  | Get/set SWITCHAR      | AL=0/1 DL=char             | 
| 38 | Get natl dependent info  | DS:DX ==> memory      | country dependent block    | 
+----+--------------------------+-----------------------+----------------------------+ 
| 39 | MKDIR - Create subdir.   | DS:DX ==> ASCIIZ      | Errors 3,5                 | 
| 3A | RMDIR - Remove subdir.   | DS:DX ==> ASCIIZ      | Errors 3,5                 | 
| 3B | CHDIR - Change subdir.   | DS:DX ==> ASCIIZ      | Error  3                   | 
+----+--------------------------+-----------------------+----------------------------+ 
| 3C | Create a file  (handle)  | DS:DX ==> ASCIIZ      | CX=attr BX returns handle  | 
| 3D | Open a file    (handle)  | DS:DX ==> ASCIIZ      | AL=access code             | 
| 3E | Close a file   (handle)  | BX = handle no.       | Error 6 only               | 
| 3F | Read           (handle)  | BX = handle no.       | CX=read length             | 
| 40 | Write          (handle)  | BX = handle no.       | CX=write length            | 
| 41 | Unlink - Dir. delete     | DS:DX ==> ASCIIZ      | Errors 2,5ength            | 
| 42 | LSEEK - Move r/w pointer | BX = handle no.       | AX=method CX:DX=offset     | 
| 43 | CHMOD - Change file mode | DS:DX ==> ASCIIZ      | AL=function                | 
| 44 | IOCTL - I/O control      | BX = handle no.       | AL=function value          | 
| 45 | DUP - Dup file handle    | BX = handle no.       | AX returns new handle      | 
| 46 | FDUP - Force dup handle  | BX = handle no.       | CX contains second handle  | 
+----+--------------------------+-----------------------+----------------------------+ 
| 47 | Get current directory    | DL = drive            | DS:SI==> 64byte area       | 
+----+--------------------------+-----------------------+----------------------------+ 
| 48 | Allocate memory          | BX = no. para.        | AX returns block start     | 
| 49 | Free memory              | ES ==> block          | Errors 7,9                 | 
| 4A | Modify allocated memory  | ES = block BX = size  | Errors 7,8,9               | 
| 4B | EXEC - load a program    | DS:DX ==>ASCIIZ       | AL=function; 0 or 3        | 
+----+--------------------------+-----------------------+----------------------------+ 
| 4C | EXIT - Terminate         | AL = retcode          | See FC 0                   | 
| 4D | WAIT - return code       | N/A: returns AX       |                            | 
| 4E | Find first match (ASCIIZ)| DS:DX ==> ASCIIZ      | CX = attrib                | 
| 4F | Find next match  (ASCIIZ)| DTA ==> 4E call       | same as 4E                 | 
| 50 | Used internally by DOS:  |                       |                            | 
| 51 | Used internally by DOS:  |                       |                            | 
| 52 | Used internally by DOS:  |                       |                            | 
| 53 | Used internally by DOS:  |                       |                            | 
| 54 | Get VERIFY state         | N/A: AL=0/1 (on/off)  | See FC 2E                  | 
| 55 | Used internally by DOS:  |                       |                            | 
| 56 | Rename a file    (ASCIIZ)| DS:DX ==> ASCIIZ      | same drive only            | 
| 57 | Get/Set file date stamp  | BX = handle no.       | DX=date CX=time AL=0/1      
+----+--------------------------+-----------------------+----------------------------+ 
| AH |    F U N C T I O N       | Entry / Register Use  |        N O T E S           | 
+----+--------------------------+-----------------------+----------------------------+