home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft_Programmers_Library.7z / MPL / msdos / dos40ref.txt < prev    next >
Encoding:
Text File  |  2013-11-08  |  710.1 KB  |  19,304 lines

  1.  Microsoft MS-DOS Programmer's Reference
  2.  
  3.  
  4.  ════════════════════════════════════════════════════════════════════════════
  5.  
  6.  
  7.  Microsoft(R) MS-DOS(R) Programmer's Reference
  8.  
  9.  Version 4.0
  10.  
  11.  
  12.  ════════════════════════════════════════════════════════════════════════════
  13.  
  14.  
  15.    Information in this document is subject to change without notice and does
  16.    not represent a commitment on the part of Microsoft Corporation. The
  17.    software described in this document is furnished under a license agreement
  18.    or non-disclosure agreement. The software may be used or copied only in
  19.    accordance with the terms of the agreement. It is against the law to copy
  20.    the software on any medium except as specifically allowed in the license
  21.    or non-disclosure agreement. No part of this manual may be reproduced or
  22.    transmitted in any form or by any means, electronic or mechanical,
  23.    including photocopying and recording, for any purpose without the express
  24.    written permission of Microsoft.
  25.  
  26.    (C) Copyright Microsoft Corporation, 1988. All rights reserved.
  27.  
  28.    Simultaneously published in the United States and Canada.
  29.  
  30.    Printed in the United States of America.
  31.  
  32.    Microsoft, the Microsoft logo, MS-DOS, and XENIX are registered trademarks
  33.    of Microsoft Corporation.
  34.  
  35.    IBM, IBM Personal Computer, IBM PC, and PC-DOS are registered trademarks
  36.    of International Business Machines Corporation.
  37.  
  38.    INTEL is a registered trademark of Intel Corporation.
  39.  
  40.  ────────────────────────────────────────────────────────────────────────────
  41.  Contents
  42.  
  43.  Chapter 1   System Calls
  44.      1.1   Introduction
  45.            1.1.1   System Calls That Have Been Superseded
  46.            1.1.2   How to Use This Manual
  47.      1.2   Standard Character Device I/O
  48.      1.3   Memory Management
  49.      1.4   Process Management
  50.            1.4.1   Loading and Executing a Program
  51.            1.4.2   Loading an Overlay
  52.      1.5   File and Directory Management
  53.            1.5.1   Handles
  54.            1.5.2   File-Related Function Requests
  55.            1.5.3   Device-Related Function Requests
  56.            1.5.4   Directory-Related Function Requests
  57.            1.5.5   File Attributes
  58.      1.6   Microsoft Networks
  59.      1.7   National Language Support
  60.      1.8   Miscellaneous System-Management Functions
  61.      1.9   Old System Calls
  62.            1.9.1   File Control Block (FCB)
  63.      1.10  Using the System Calls
  64.            1.10.1  Issuing an Interrupt
  65.            1.10.2  Calling a Function Request
  66.            1.10.3  Using the Calls from a High-Level Language
  67.            1.10.4  Treatment of Registers
  68.            1.10.5  Handling Errors
  69.            1.10.6  System Call Descriptions
  70.      1.11  Interrupts
  71.            1.11.1  Conditions upon Entry
  72.            1.11.2  Requirements for an Interrupt 24H Handler
  73.      1.12  Function Requests
  74.  
  75.  Chapter 2   MS-DOS Device Drivers
  76.      2.1   Introduction
  77.      2.2   Format of a Device Driver
  78.      2.3   How to Create a Device Driver
  79.            2.3.1   Device Strategy Routine
  80.            2.3.2   Device Interrupt Routine
  81.      2.4   Installing Device Drivers
  82.      2.5   Device Headers
  83.            2.5.1   Pointer to Next Device Field
  84.            2.5.2   Attribute Field
  85.            2.5.3   Strategy and Interrupt Routines
  86.            2.5.4   Name Field
  87.      2.6   Request Header
  88.            2.6.1   Length of Record
  89.            2.6.2   Unit Code Field
  90.            2.6.3   Command Code Field
  91.            2.6.4   Status Field
  92.      2.7   Device Driver Functions
  93.            2.7.1   The Init Function
  94.            2.7.2   The Media Check Function
  95.            2.7.3   The Build BPB Function
  96.            2.7.4   The Read or Write Function
  97.            2.7.5   The Non-destructive Read, No Wait Function
  98.            2.7.6   The Open or Close Function
  99.            2.7.7   The Removable Media Function
  100.            2.7.8   The Status Function
  101.            2.7.9   The Flush Function
  102.            2.7.10  The Generic IOCtl Function
  103.            2.7.11  The Get/Set Logical Drive Map Function
  104.      2.8   The Media Descriptor Byte
  105.      2.9   Format of a Media Descriptor Table
  106.      2.10  The CLOCK Device
  107.      2.11  Anatomy of a Device Call
  108.      2.12  Two Sample Device Drivers
  109.  
  110.  Chapter 3   MS-DOS Technical Information
  111.      3.1   Introduction
  112.      3.2   MS-DOS Initialization
  113.      3.3   The Command Processor
  114.      3.4   MS-DOS Disk Allocation
  115.      3.5   MS-DOS Disk Directory
  116.      3.6   File Allocation Table (FAT)
  117.            3.6.1   How to Use the FAT (12-Bit FAT Entries)
  118.            3.6.2   How to Use the FAT (16-Bit FAT Entries)
  119.      3.7   MS-DOS Standard Disk Formats
  120.  
  121.  Chapter 4   MS-DOS Control Blocks and Work Areas
  122.      4.1   Introduction
  123.      4.2   Typical Contents of an MS-DOS Memory Map
  124.      4.3   The MS-DOS Program Segment
  125.  
  126.  Chapter 5   National Language Support
  127.      5.1   Introduction
  128.      5.2   National Language Support Calls
  129.      5.3   Font Files
  130.            5.3.1   Font File Structure
  131.  
  132.  Chapter 6   .Exe File Structure and Loading
  133.      6.1   Introduction
  134.      6.2   Format of a File Header
  135.      6.3   The Relocation Table
  136.  
  137.  Chapter 7   Relocatable Object Module Formats
  138.      7.1   Introduction
  139.            7.1.1   Definition of Terms
  140.      7.2   Module Identification and Attributes
  141.            7.2.1   Segment Definition
  142.            7.2.2   Addressing a Segment
  143.            7.2.3   Symbol Definition
  144.            7.2.4   Indices
  145.      7.3   Conceptual Framework for Fixups
  146.            7.3.1   Self-Relative Fixup
  147.            7.3.2   Segment-Relative Fixup
  148.      7.4   Record Sequence
  149.      7.5   Introducing the Record Formats
  150.            7.5.1   Sample Record Format (SAMREC)
  151.            7.5.2   T-Module Header Record (THEADR)
  152.            7.5.3   L-Module Header Record (LHEADR)
  153.            7.5.4   List of Names Record (LNAMES)
  154.            7.5.5   Segment Definition Record (SEGDEF)
  155.            7.5.6   Group Definition Record (GRPDEF)
  156.            7.5.7   Public Names Definition Record (PUBDEF)
  157.            7.5.8   Communal Names Definition Record (COMDEF)
  158.            7.5.9   Local Symbols Record (LOCSYM)
  159.            7.5.10  External Names Definition Record (EXTDEF)
  160.            7.5.11  Line Numbers Record (LINNUM)
  161.            7.5.12  Logical Enumerated Data Record (LEDATA)
  162.            7.5.13  Logical Iterated Data Record (LIDATA)
  163.            7.5.14  Fixup Record (FIXUPP)
  164.            7.5.15  Module End Record (MODEND)
  165.            7.5.16  Comment Record (COMENT)
  166.      7.6   Microsoft Type Representations for Communal Variables
  167.  
  168.  Chapter 8   Programming Hints
  169.      8.1   Introduction
  170.      8.2   Interrupts
  171.      8.3   System Calls
  172.      8.4   Device Management
  173.      8.5   Memory Management
  174.      8.6   Process Management
  175.      8.7   File and Directory Management
  176.            8.7.1   Locking Files
  177.      8.8   Miscellaneous
  178.  
  179.  Figures
  180.  Figure 1.1  Example of the 8088 Registers
  181.  Figure 1.2  Sample Program with Common Skeleton
  182.  Figure 2.1  Sample Device Header
  183.  Figure 2.2  Attribute Word for Character Devices
  184.  Figure 2.3  Attribute Word for Block Devices
  185.  Figure 2.4  Request Header
  186.  Figure 2.5  Status Field
  187.  Figure 2.6  Format of a Boot Sector
  188.  Figure 2.7  Format of a Clock Device
  189.  Figure 4.1  Program Segment Prefix
  190.  Figure 5.1  Font File Structure
  191.  Figure 7.1  Location Types
  192.  
  193.  Tables
  194.  Table 1.1   Standard-Character I/O Function Requests
  195.  Table 1.2   Memory Management Function Requests
  196.  Table 1.3   Process-Management Function Requests
  197.  Table 1.4   Predefined Device Handles
  198.  Table 1.5   File-Related Function Requests
  199.  Table 1.6   File-Sharing Function Requests
  200.  Table 1.7   Device-Related Function Requests
  201.  Table 1.8   Directory-Related Function Requests
  202.  Table 1.9   File Attributes
  203.  Table 1.10  Microsoft Networks Function Requests
  204.  Table 1.11  National-Language-Support Function Requests
  205.  Table 1.12  Miscellaneous System-Management Function Requests
  206.  Table 1.13  Old System Calls and Their Replacements
  207.  Table 1.14  Format of the File Control Block (FCB)
  208.  Table 1.15  Error Codes Returned in AX
  209.  Table 1.16  MS-DOS Interrupts, Numeric Order
  210.  Table 1.17  MS-DOS Interrupts, Alphabetic Order
  211.  Table 1.18  MS-DOS Function Requests, Numeric Order
  212.  Table 1.19  MS-DOS Function Requests, Alphabetic Order
  213.  Table 1.20  Bit Values for Function 29H
  214.  Table 1.21  Sharing Mode Bit Values
  215.  Table 1.22  Access Code Bit Values
  216.  Table 1.23  MS-DOS Data Bit Values
  217.  Table 1.24  Contents of the Parameter Block
  218.  Table 1.25  Contents of the Parameter Block
  219.  Table 1.26  DTA Values After Successful Find First File
  220.  Table 1.27  Allocation Strategy
  221.  Table 2.1   For Character Devices:
  222.  Table 2.2   For Block Devices:
  223.  Table 3.1   MS-DOS Standard Removable-Disk Formats
  224.  Table 3.2   MS-DOS Standard Removable-Disk Formats (High-Density)
  225.  Table 7.1   Object Module Record Formats
  226.  Table 7.2   Combination Attribute Example
  227.  
  228.  
  229.  
  230.  ────────────────────────────────────────────────────────────────────────────
  231.  Chapter 1  System Calls
  232.  
  233.      1.1   Introduction
  234.            1.1.1   System Calls That Have Been Superseded
  235.            1.1.2   How to Use This Manual
  236.      1.2   Standard Character Device I/O
  237.      1.3   Memory Management
  238.      1.4   Process Management
  239.            1.4.1   Loading and Executing a Program
  240.            1.4.2   Loading an Overlay
  241.      1.5   File and Directory Management
  242.            1.5.1   Handles
  243.            1.5.2   File-Related Function Requests
  244.            1.5.3   Device-Related Function Requests
  245.            1.5.4   Directory-Related Function Requests
  246.            1.5.5   File Attributes
  247.      1.6   Microsoft Networks
  248.      1.7   National Language Support
  249.      1.8   Miscellaneous System-Management Functions
  250.      1.9   Old System Calls
  251.            1.9.1   File Control Block (FCB)
  252.      1.10  Using the System Calls
  253.            1.10.1  Issuing an Interrupt
  254.            1.10.2  Calling a Function Request
  255.            1.10.3  Using the Calls from a High-Level Language
  256.            1.10.4  Treatment of Registers
  257.            1.10.5  Handling Errors
  258.            1.10.6  System Call Descriptions
  259.      1.11  Interrupts
  260.            1.11.1  Conditions upon Entry
  261.            1.11.2  Requirements for an Interrupt 24H Handler
  262.      1.12  Function Requests
  263.  
  264.  
  265.  1.1  Introduction
  266.  
  267.    The routines that MS-DOS uses to manage system operation and resources can
  268.    be called by any application program. Using these system calls makes it
  269.    easier to write machine-independent programs and increases the likelihood
  270.    that a program will be compatible with future versions of MS-DOS. MS-DOS
  271.    system calls fall into several categories:
  272.  
  273.    ■  Standard character device I/O
  274.  
  275.    ■  Memory management
  276.  
  277.    ■  Process management
  278.  
  279.    ■  File and directory management
  280.  
  281.    ■  Microsoft Network calls
  282.  
  283.    ■  National Language Support calls
  284.  
  285.    ■  Miscellaneous system functions
  286.  
  287.    Applications invoke MS-DOS services by using software interrupts. The
  288.    current range of interrupts used for MS-DOS is 20H-27H; 28H-40H are
  289.    reserved. Interrupt 21H is the function request service; it provides
  290.    access to a wide variety of MS-DOS services. In some cases, the full AX
  291.    register is used to specify the requested function. Each interrupt or
  292.    function request uses values in various registers to receive or return
  293.    function-specific information.
  294.  
  295.  1.1.1  System Calls That Have Been Superseded
  296.  
  297.    Many system calls introduced in versions of MS-DOS earlier than 2.0 have
  298.    been superseded by function requests that are more efficient and easier to
  299.    use. Although MS-DOS still includes these old system calls, they should
  300.    not be used unless it is imperative that a program maintain
  301.    backward-compatibility with versions of MS-DOS earlier than 2.0.
  302.  
  303.    A table of the pre-2.0 system calls and a description of the File Control
  304.    Block (required by some of the old calls) appear in Section 1.8, "Old
  305.    System Calls."
  306.  
  307.  1.1.2  How to Use This Manual
  308.  
  309.    The first part of this chapter explains how DOS manages its resources──
  310.    such as memory, files, and processes──and briefly describes the purpose of
  311.    most of the system calls. The remainder of the chapter describes each
  312.    interrupt and function request in detail.
  313.  
  314.    The system-call descriptions are in numeric order, interrupts followed by
  315.    function requests. These descriptions include further detail on how MS-DOS
  316.    manages its resources.
  317.  
  318.    Chapter 2 of this manual describes how to write an MS-DOS device driver.
  319.  
  320.    Chapters 3 and 4 contain more detailed information about MS-DOS,
  321.    including how it manages disk space, uses control blocks, and loads and
  322.    executes relocatable programs (files with an extension of .exe).
  323.  
  324.    Chapter 5 describes MS-DOS national language support.
  325.  
  326.    Chapter 6 describes .exe file structure and loading procedures (for
  327.    versions of MS-DOS earlier than 2.0).
  328.  
  329.    Chapter 7 describes the Intel object module format.
  330.  
  331.    Chapter 8 gives some programming hints.
  332.  
  333.  
  334.  1.2  Standard Character Device I/O
  335.  
  336.    The standard-character function requests handle all input and output to
  337.    and from character devices such as consoles, printers, and serial ports.
  338.    If a program uses these function requests, its input and output can be
  339.    redirected.
  340.  
  341.    Table 1.1 lists the MS-DOS function requests for managing
  342.    standard-character input and output.
  343.  
  344.    Table 1.1
  345.    Standard-Character I/O Function Requests
  346. ╓┌─┌─────────┌─────────────────────┌─────────────────────────────────────────╖
  347.    Code       Request              Description
  348.    ──────────────────────────────────────────────────────────────────────────
  349.    01H       Read Keyboard and    Gets a character from standard input and
  350.               Echo                 echoes it to standard output
  351.  
  352.    02H       Display Character    Sends a character to standard output
  353.  
  354.    03H       Auxiliary Input      Gets a character from standard auxiliary
  355.  
  356.    04H       Auxiliary Output     Sends a character to standard auxiliary
  357.  
  358.    05H       Print Character      Sends a character to the standard printer
  359.    Code       Request              Description
  360.    ──────────────────────────────────────────────────────────────────────────
  361.   05H       Print Character      Sends a character to the standard printer
  362.  
  363.    06H       Direct Console I/O   Gets a character from standard input or
  364.                                    sends a character to standard output
  365.  
  366.    07H       Direct Console Input Gets a character from standard input
  367.  
  368.    08H       Read Keyboard        Gets a character from standard input
  369.  
  370.    09H       Display String       Sends a string to standard output
  371.  
  372.    0AH       Buffered Keyboard    Gets a string from standard input
  373.               Input
  374.  
  375.    0BH       Check Keyboard       Reports on the status of the standard
  376.               Status               input buffer
  377.  
  378.    0CH       Flush Buffer, Read   Empties the standard input buffer and
  379.               Keyboard             calls one of the other standard character
  380.    Code       Request              Description
  381.    ──────────────────────────────────────────────────────────────────────────
  382.              Keyboard             calls one of the other standard character
  383.    ──────────────────────────────────────────────────────────────────────────
  384.  
  385.  
  386.    Although several of these standard-character I/O function requests seem to
  387.    do the same thing, they are distinguished by whether they check for
  388.    control characters or echo characters from standard input to standard
  389.    output. The detailed descriptions later in this chapter point out the
  390.    differences.
  391.  
  392.  
  393.  1.3  Memory Management
  394.  
  395.    MS-DOS keeps track of which areas of memory are allocated by writing a
  396.    memory control block at the beginning of each. This control block
  397.    specifies the size of the memory area; the name of the process, if any,
  398.    that owns the memory area; and a pointer to the next area of memory. If
  399.    the memory area is not owned, it is available.
  400.  
  401.    Table 1.2 lists the MS-DOS function requests for managing memory.
  402.  
  403.    Table 1.2
  404.    Memory Management Function Requests
  405.    Code       Request              Description
  406.    ──────────────────────────────────────────────────────────────────────────
  407.    48H       Allocate Memory      Requests a block of memory
  408.  
  409.    49H       Free Allocated       Frees a block of memory previously
  410.               Memory               allocated with 48H
  411.  
  412.    4AH       Set Block            Changes the size of an allocated memory
  413.    ──────────────────────────────────────────────────────────────────────────
  414.  
  415.    When a process requests additional memory with Function 48H (Allocate
  416.    Memory), MS-DOS searches for a block of available memory large enough to
  417.    satisfy the request. If it finds such a block of memory, it changes the
  418.    memory control block to show the owning process. If the block of memory is
  419.    larger than the requested amount, MS-DOS changes the size field of the
  420.    memory control block to the requested amount, writes a new memory control
  421.    block at the beginning of the unneeded portion showing that it is
  422.    available, and updates the pointers to add this memory to the chain of
  423.    memory control blocks. MS-DOS then returns the segment address of the
  424.    first byte of the allocated memory to the requesting process.
  425.  
  426.    When a process releases an allocated block of memory with Function 49H
  427.    (Free Allocated Memory), MS-DOS changes the memory control block to show
  428.    that it is available (not owned by any process).
  429.  
  430.    When a process uses Function 4AH (Set Block) to shrink an allocated block
  431.    of memory, MS-DOS builds a memory control block for the memory being
  432.    released and adds it to the chain of memory control blocks. When a process
  433.    tries to use Function 4AH (Set Block) to expand an allocated block of
  434.    memory, MS-DOS treats it as a request for additional memory rather than
  435.    returning the segment address of the additional memory to the requesting
  436.    process. However, MS-DOS simply chains the additional memory to the
  437.    existing memory block. If MS-DOS can't find a block of available memory
  438.    large enough to satisfy a request for additional memory made with either
  439.    Function 48H (Allocate Memory) or Function 4AH (Set Block), MS-DOS
  440.    returns an error code to the requesting process.
  441.  
  442.    When a program receives control, it should call Function 4AH (Set Block)
  443.    to shrink its initial memory-allocation block (the block that begins with
  444.    its Program Segment Prefix) to the minimum it requires. This frees
  445.    unneeded memory and makes the best application design for portability to
  446.    future multitasking environments.
  447.  
  448.    When a program exits, MS-DOS automatically frees its initial
  449.    memory-allocation block before returning control to the calling program
  450.    (command.com is usually the calling program for application programs). DOS
  451.    frees any memory owned by the exiting process.
  452.  
  453.    Any program that changes memory that is not allocated to it will most
  454.    likely destroy at least one memory-management control block. This causes a
  455.    memory-allocation error the next time MS-DOS tries to use the chain of
  456.    memory-control blocks; the only cure is to restart the system.
  457.  
  458.  
  459.  1.4  Process Management
  460.  
  461.    MS-DOS uses several function requests to load, execute, and terminate
  462.    programs. Application programs can use these same function requests to
  463.    manage other programs.
  464.  
  465.    Table 1.3 lists the MS-DOS function requests for managing processes.
  466.  
  467.    Table 1.3
  468.    Process-Management Function Requests
  469.    Code       Request              Description
  470.    ──────────────────────────────────────────────────────────────────────────
  471.    31H       Keep Process         Terminates a process and returns control
  472.                                    to the invoking process, but keeps the
  473.                                    terminated process in memory
  474.  
  475.    4B00H,    Load and Execute     Loads and executes a program, or loads a
  476.    4B03H     Program or Overlay   program overlay without executing it
  477.  
  478.    4CH       End Process          Returns control to the invoking process
  479.  
  480.    4DH       Get Return Code of   Returns a code passed by an exiting child
  481.               Child Process        process
  482.  
  483.    62H       Get PSP              Returns the segment address of the current
  484.    ──────────────────────────────────────────────────────────────────────────
  485.  
  486.    Function 4BH (Load and Execute Program or Overlay) has two subfunctions,
  487.    4B00H (Load and Execute Program) and 4B03H (Load Overlay). The
  488.    differences between them are described in the following sections.
  489.  
  490.  1.4.1  Loading and Executing a Program
  491.  
  492.    When a program uses Function 4B00H (Load and Execute Program) to load and
  493.    execute another program, MS-DOS allocates memory, writes a Program Segment
  494.    Prefix (PSP) for the new program at offset 0 of the allocated memory,
  495.    loads the new program, and passes control to it. When the invoked program
  496.    exits, control returns to the calling program.
  497.  
  498.    Command.com uses Function 4B00H to load and execute command files.
  499.    Application programs have the same degree of control over process
  500.    management as does command.com.
  501.  
  502.    In addition to these common features, there are some differences in the
  503.    way MS-DOS loads .com and .exe files.
  504.  
  505.    Loading a .Com Program
  506.  
  507.    When command.com loads and executes a .com program, it allocates all
  508.    available memory to the application and sets the stack pointer 100H bytes
  509.    from the end of available memory. A .com program should set up its own
  510.    stack before shrinking its initial memory-allocation block with Function
  511.    4AH (Set Block) because the default stack is in the memory to be
  512.    released.
  513.  
  514.    If a newly loaded program is allocated all of memory──as a .com program
  515.    is──or requests all of available memory by using Function 48H (Allocate
  516.    Memory), MS-DOS allocates to it the memory occupied by the transient part
  517.    of command.com. If the program changes this memory, MS-DOS must reload the
  518.    transient portion of command.com before it can continue. If a program
  519.    exits (via Function 31H, Keep Process) without releasing enough memory,
  520.    the system halts and must be reset. To minimize this possibility, a .com
  521.    program should use Function 4AH (Set Block) to shrink its initial
  522.    allocation block before doing anything else. Also, before exiting, all
  523.    programs must release all memory they allocate by using Function 48H
  524.    (Allocate Memory).
  525.  
  526.    Loading a .Exe Program
  527.  
  528.    When command.com loads and executes a .exe program, it allocates the size
  529.    of the program's memory image plus either the value in the MAX──ALLOC
  530.    field (offset 0CH) of the file header (if that much memory is available)
  531.    or the value in the MIN──ALLOC field (offset 0AH). The linker sets these
  532.    fields. Before passing control to the .exe file, MS-DOS uses the
  533.    relocation information in the file header to calculate the correct
  534.    relocation addresses.
  535.  
  536.    For a more detailed description of how MS-DOS loads .com and .exe files,
  537.    see Chapter 3, "MS-DOS Technical Information," and Chapter 4, "MS-DOS
  538.    Control Blocks and Work Areas."
  539.  
  540.    Executing a Program from Within Another Program
  541.  
  542.    Since command.com builds pathnames, searches directory paths for
  543.    executable files, and relocates .exe files, the simplest way to load and
  544.    execute a program is to load and execute an additional copy of
  545.    command.com, passing it a command line that includes the /C switch, which
  546.    invokes the .com or .exe file. The description of Function 4B00H (Load
  547.    and Execute Program) describes how to do this.
  548.  
  549.  1.4.2  Loading an Overlay
  550.  
  551.    When a program uses Function 4B03H (Load Overlay) to load an overlay, it
  552.    must pass MS-DOS the segment address at which the overlay is to be loaded.
  553.    The program must call the overlay, which then returns directly to the
  554.    calling program. The calling program is in complete control: MS-DOS does
  555.    not write a PSP for the overlay or intervene in any other way.
  556.  
  557.    MS-DOS does not check to see if the calling program owns the memory where
  558.    the overlay is to be loaded. If the calling program does not own the
  559.    memory, loading the overlay will most likely destroy a memory-control
  560.    block, causing an eventual memory-allocation error.
  561.  
  562.    Therefore, a program that loads an overlay must either allow room for the
  563.    overlay when it calls Function 4AH (Set Block) to shrink its initial
  564.    memory-allocation block, or shrink its initial memory-allocation block to
  565.    the minimum and then use Function 48H (Allocate Memory) to allocate
  566.    memory for the overlay.
  567.  
  568.  
  569.  1.5  File and Directory Management
  570.  
  571.    The MS-DOS hierarchical (multilevel) file system is similar to that of the
  572.    XENIX operating system. For a description of the multilevel directory
  573.    system and how to use it, see the MS-DOS User's Reference.
  574.  
  575.  1.5.1  Handles
  576.  
  577.    To create or open a file, a program passes MS-DOS a pathname and the
  578.    attribute to be assigned to the file. MS-DOS returns a 16-bit number,
  579.    called a handle. For most subsequent actions, MS-DOS requires only this
  580.    handle to identify the file.
  581.  
  582.    A handle can refer to either a file or a device. MS-DOS predefines five
  583.    standard handles. These handles are always open, so you needn't open them
  584.    before you use them. Table 1.4 lists these predefined handles.
  585.  
  586.    Table 1.4
  587.    Predefined Device Handles
  588.    Handle     Standard device      Comment
  589.    ──────────────────────────────────────────────────────────────────────────
  590.    0          Input                Can be redirected from command line
  591.    1          Output               Can be redirected from command line
  592.    2          Error
  593.    3          Auxiliary
  594.    4          Printer
  595.    ──────────────────────────────────────────────────────────────────────────
  596.  
  597.    When MS-DOS creates or opens a file, it assigns the first available
  598.    handle. Since a program can have 20 open handles, including the five
  599.    predefined handles, it typically can open 15 extra files. By using
  600.    Function 46H (Force Duplicate File Handle), MS-DOS can temporarily force
  601.    any of the five predefined handles to refer to an alternate file or
  602.    device. For more information about Function 46H, see its description
  603.    later in this chapter.
  604.  
  605.  1.5.2  File-Related Function Requests
  606.  
  607.    MS-DOS treats a file as a string of bytes; it assumes no record structure
  608.    or access technique. An application program imposes whatever record
  609.    structure it needs on this string of bytes. Reading from or writing to a
  610.    file requires only pointing to the data buffer and specifying the number
  611.    of bytes to read or write. Table 1.5 lists the MS-DOS function requests
  612.    for managing files.
  613.  
  614.    Table 1.5
  615.    File-Related Function Requests
  616. ╓┌─┌─────────┌─────────────────────┌─────────────────────────────────────────╖
  617.    Code       Request              Description
  618.    ──────────────────────────────────────────────────────────────────────────
  619.    3CH       Create Handle        Creates a file
  620.  
  621.    3DH       Open Handle          Opens a file
  622.  
  623.    3EH       Close Handle         Closes a file
  624.  
  625.    3FH       Read Handle          Reads from a file
  626.  
  627.    40H       Write Handle         Writes to a file
  628.  
  629.    42H       Move File Pointer    Sets the read/write pointer in a file
  630.  
  631.    45H       Duplicate File       Creates a new handle that refers to the
  632.    Code       Request              Description
  633.    ──────────────────────────────────────────────────────────────────────────
  634.   45H       Duplicate File       Creates a new handle that refers to the
  635.               Handle               same file as an existing handle
  636.  
  637.    46H       Force Duplicate File Makes an existing handle refer to the same
  638.               Handle               file as another existing handle
  639.  
  640.    5AH       Create Temporary     Creates a file with a unique name
  641.               File
  642.  
  643.    5BH       Create New File      Attempts to create a file, but fails if a
  644.                                    file with the same name exists
  645.  
  646.    67H       Set Handle Count     Increases or decreases the number of files
  647.                                    a program can have open at one time
  648.  
  649.    68H       Commit File          Flushes buffered data for a file without
  650.                                    closing it to ensure the disk image of
  651.    ──────────────────────────────────────────────────────────────────────────
  652.  
  653.    Code       Request              Description
  654.    ──────────────────────────────────────────────────────────────────────────
  655. 
  656.  
  657.    File Sharing
  658.  
  659.    Version 3.1 of MS-DOS introduced file sharing, which let more than one
  660.    process share access to a file. File sharing operates only after the share
  661.    command has been executed to load file-sharing support. That is, you must
  662.    use the share command to take advantage of file sharing.
  663.  
  664.    Table 1.6 lists the MS-DOS function requests for sharing files; if file
  665.    sharing is not in effect, these function requests cannot be used. Function
  666.    3DH (Open Handle) can operate in several modes. Here it is referred to in
  667.    the file-sharing modes, which require file sharing to be in effect.
  668.    (Compatibility mode is usable without file sharing being in effect.)
  669.  
  670.    Table 1.6
  671.    File-Sharing Function Requests
  672.    Code       Request              Description
  673.    ──────────────────────────────────────────────────────────────────────────
  674.    3DH       Open Handle          Opens a file by using one of the
  675.                                    file-sharing modes
  676.  
  677.    440BH     IOCtl Retry          (before Interrupt 24H is issued)
  678.                                    Specifies how many times to retry an I/O
  679.                                    operation that fails due to a file-sharing
  680.                                    violation
  681.  
  682.    5C00H     Lock                 Locks a region of a file
  683.  
  684.    5C01H     Unlock               Unlocks a region of a file
  685.    ──────────────────────────────────────────────────────────────────────────
  686.  
  687.  1.5.3  Device-Related Function Requests
  688.  
  689.    I/O Control for devices is implemented with Function 44H (IOCtl), which
  690.    includes several subfunctions necessary to perform device-related tasks.
  691.    Some forms of the IOCtl function request require that the device driver be
  692.    written to support the IOCtl interface. Table 1.7 lists the MS-DOS
  693.    function requests for managing devices.
  694.  
  695.    Table 1.7
  696.    Device-Related Function Requests
  697. ╓┌─┌──────────────┌─────────────────────────┌────────────────────────────────╖
  698.    Code            Request                  Description
  699.    ──────────────────────────────────────────────────────────────────────────
  700.    4400H, 4401H  IOCtl Data               Gets or sets device description
  701.  
  702.    4402H, 4403H  IOCtl Character          Gets or sets character-device
  703.                                             control data
  704.  
  705.    4404H, 4405H  IOCtl Block              Gets or sets block-device control
  706.                                             data
  707.  
  708.    4406H, 4407H  IOCtl Status             Checks device input or output
  709.                                             status
  710.  
  711.    4408H          IOCtl Is Changeable      Checks whether block device
  712.                                             contains removable medium
  713.  
  714.    440CH          Generic IOCtl (for       Sets Generic IOCtl for handles
  715.                    handles)                 and supports code pages for
  716.    Code            Request                  Description
  717.    ──────────────────────────────────────────────────────────────────────────
  718.                   handles)                 and supports code pages for
  719.                                             devices or returns DCBS
  720.                                             information.
  721.  
  722.    440DH          Generic IOCtl (for       Sets Generic IOCtl for devices
  723.                    devices)
  724.  
  725.    440EH, 440FH  Get/Set IOCtl Drive Map  Gets or sets logical drive map
  726.    ──────────────────────────────────────────────────────────────────────────
  727.  
  728.  
  729.    Some forms of the IOCtl function request can be used only with Microsoft
  730.    Networks; these forms are listed in Section 1.6, "Microsoft Networks."
  731.  
  732.  1.5.4  Directory-Related Function Requests
  733.  
  734.    A directory entry is a 32-byte record that includes the file's name,
  735.    extension, date and time of last change, and size. An entry in a
  736.    subdirectory is identical to an entry in the root directory. Directory
  737.    entries are described in detail in Chapter 3.
  738.  
  739.    The root directory on a disk has room for a fixed number of entries: 64 on
  740.    a standard single-sided disk, 112 on a standard double-sided disk. For
  741.    hard disks, the number of directories depends on the DOS partition size. A
  742.    subdirectory is simply a file with a unique attribute; there can be as
  743.    many subdirectories on a disk as space allows. The depth of a directory
  744.    structure, therefore, is limited only by the amount of storage on a disk
  745.    and the maximum pathname length of 64 characters. Pre-2.0 disks appear to
  746.    have only a root directory that contains files but no subdirectories.
  747.  
  748.    Table 1.8 lists the MS-DOS function requests for managing directories.
  749.  
  750.    Table 1.8
  751.    Directory-Related Function Requests
  752. ╓┌─┌─────────┌─────────────────────┌─────────────────────────────────────────╖
  753.    Code       Request              Description
  754.    ──────────────────────────────────────────────────────────────────────────
  755.    39H       Create Directory     Creates a subdirectory
  756.  
  757.    3AH       Remove Directory     Deletes a subdirectory
  758.    Code       Request              Description
  759.    ──────────────────────────────────────────────────────────────────────────
  760.   3AH       Remove Directory     Deletes a subdirectory
  761.  
  762.    3BH       Change Current       Changes the current directory
  763.               Directory
  764.  
  765.    41H       Delete Directory     Deletes a file
  766.               Entry (Unlink)
  767.  
  768.    43H       Get/Set File         Retrieves or changes the attributes of a
  769.               Attributes (Chmod)   file
  770.  
  771.    47H       Get Current          Returns current directory for a given
  772.               Directory            drive
  773.  
  774.    4EH       Find First File      Searches a directory for the first entry
  775.                                    that matches a filename
  776.  
  777.    4FH       Find Next File       Searches a directory for the next entry
  778.                                    that matches a filename
  779.    Code       Request              Description
  780.    ──────────────────────────────────────────────────────────────────────────
  781.                                   that matches a filename
  782.  
  783.    56H       Change Directory     Renames a file
  784.               Entry
  785.  
  786.    57H       Get/Set Date/Time of Changes the time and date of last change
  787.               File                 in a directory entry
  788.    ──────────────────────────────────────────────────────────────────────────
  789.  
  790.  
  791.  1.5.5  File Attributes
  792.  
  793.    Table 1.9 describes the file attributes and how they are represented in
  794.    the attribute byte of the directory entry (offset 0BH). The attributes can
  795.    be inspected or changed with Function 43H (Get/Set File Attributes
  796.    [Chmod]).
  797.  
  798.    Table 1.9
  799.    File Attributes
  800.    Code                     Description
  801.    ──────────────────────────────────────────────────────────────────────────
  802.    00H                      Normal; can be read or written without
  803.                             restriction
  804.  
  805.    01H                      Read-only; cannot be opened for write; a file
  806.                             with the same name cannot be created
  807.  
  808.    02H                      Hidden; not found by directory search
  809.  
  810.    04H                      System; not found by directory search
  811.  
  812.    08H                      VolumeID; only one file can have this attribute;
  813.                             it must be in the root directory
  814.  
  815.    10H                      Subdirectory
  816.  
  817.    20H                      Archive; set whenever the file is changed, or
  818.    ──────────────────────────────────────────────────────────────────────────
  819.  
  820.    The VolumeID (08H) and Subdirectory (10H) attributes cannot be changed
  821.    with Function 43H (Get/Set File Attributes [Chmod]).
  822.  
  823.  
  824.  1.6  Microsoft Networks
  825.  
  826.    Microsoft Networks consists of a server and one or more workstations.
  827.    MS-DOS maintains an assign list that keeps track of which workstation disk
  828.    drives and devices have been redirected to the server. For a description
  829.    of the operation and use of the network, see the Microsoft Networks
  830.    Manager's Guide and Microsoft Networks User's Guide.
  831.  
  832.    Table 1.10 lists the MS-DOS function requests for managing a Microsoft
  833.    Networks workstation.
  834.  
  835.    Table 1.10
  836.    Microsoft Networks Function Requests
  837. ╓┌─┌─────────┌─────────────────────┌─────────────────────────────────────────╖
  838.    Code       Request              Description
  839.    ──────────────────────────────────────────────────────────────────────────
  840.    4409H     IOCtl Is Redirected  Checks whether a drive letter refers to a
  841.               Block                local or redirected drive
  842.    Code       Request              Description
  843.    ──────────────────────────────────────────────────────────────────────────
  844.              Block                local or redirected drive
  845.  
  846.    440AH     IOCtl Is Redirected  Checks whether a device name refers to a
  847.               Handle               local or redirected device
  848.  
  849.    5E00H     Get Machine Name     Gets the network name of the workstation
  850.  
  851.    5E02H     Set Printer Setup    Defines a string of control characters to
  852.                                    be added at the beginning of each file
  853.                                    that is sent to a network printer
  854.  
  855.    5F02H     Get Assign-List      Gets an entry from the assign list, which
  856.               Entry                shows the workstation drive letter or
  857.                                    device name and the network name of the
  858.                                    directory or device on the server to which
  859.                                    the entry is reassigned
  860.  
  861.    5F03H     Make Network         Redirects a workstation drive or device to
  862.               Connection           a server directory or device
  863.    Code       Request              Description
  864.    ──────────────────────────────────────────────────────────────────────────
  865.              Connection           a server directory or device
  866.  
  867.    5F04H     Delete Network       Cancels the redirection of a workstation
  868.               Connection           drive or device to a server directory or
  869.    ──────────────────────────────────────────────────────────────────────────
  870.  
  871.  
  872.  
  873.  1.7  National Language Support
  874.  
  875.    National language support of MS-DOS includes these major features:
  876.  
  877.    ■  Country-dependent information
  878.  
  879.    ■  Support for national keyboard layouts
  880.  
  881.    ■  Programming interfaces for national language support
  882.  
  883.    ■  Utility commands
  884.  
  885.    Country-dependent information is available on a per-country basis and
  886.    includes the following:
  887.  
  888.    ■  Time, date, and currency
  889.  
  890.    ■  Lowercase-to-uppercase character-conversion tables
  891.  
  892.    ■  Collating sequence for character sorting
  893.  
  894.    ■  Valid single-byte characters used in filenames
  895.  
  896.    Keyboard support for different keyboard layouts is provided and
  897.    selectable.
  898.  
  899.    Table 1.11 lists the MS-DOS national-language-support system calls that
  900.    allow applications to use the country-dependent information just
  901.    described.
  902.  
  903.    Table 1.11
  904.    National-Language-Support Function Requests
  905.    Code       Request              Description
  906.    ──────────────────────────────────────────────────────────────────────────
  907.    65H       Get Extended Country Returns standard country information,
  908.               Information          pointer to uppercase table, pointer to
  909.                                    filename uppercasing table, or pointer to
  910.                                    collating table.
  911.  
  912.    66H       Get/Set Global Code  Gets or sets the code page used by the
  913.               Page                 kernel and all devices.
  914.    ──────────────────────────────────────────────────────────────────────────
  915.  
  916.  
  917.  1.8  Miscellaneous System-Management Functions
  918.  
  919.  
  920.  
  921.    The remaining system calls manage other system functions and resources
  922.    such as drives, addresses, and the clock. Table 1.12 lists the MS-DOS
  923.    function requests for managing miscellaneous system resources and
  924.    operations.
  925.  
  926.    Table 1.12
  927.    Miscellaneous System-Management Function Requests
  928. ╓┌─┌─────────┌─────────────────────┌─────────────────────────────────────────╖
  929.    Code       Request              Description
  930.    ──────────────────────────────────────────────────────────────────────────
  931.    0DH       Reset Disk           Empties all file buffers
  932.  
  933.    0EH       Select Disk          Sets the default drive
  934.  
  935.    19H       Get Current Disk     Returns the default drive
  936.  
  937.    1AH       Set Disk Transfer    Establishes the disk I/O buffer
  938.               Address
  939.  
  940.    1BH       Get Default Drive    Returns disk-format data
  941.               Data
  942.    1CH       Get Drive Data       Returns disk-format data
  943.  
  944.    25H       Set Interrupt Vector Sets interrupt-handler address
  945.  
  946.    29H       Parse File Name      Checks string for valid filename
  947.    Code       Request              Description
  948.    ──────────────────────────────────────────────────────────────────────────
  949.   29H       Parse File Name      Checks string for valid filename
  950.  
  951.    2AH       Get Date             Returns system date
  952.  
  953.    2BH       Set Date             Sets system date
  954.  
  955.    2CH       Get Time             Returns system time
  956.  
  957.    2DH       Set Time             Sets system time
  958.  
  959.    2EH       Set/Reset Verify     Turns disk verify on or off
  960.               Flag
  961.  
  962.    2FH       Get Disk Transfer    Returns system-disk-I/O-buffer address
  963.               Address
  964.  
  965.    30H       Get MS-DOS Version   Returns MS-DOS version number
  966.               Number
  967.    33H       CONTROL+C Check      Returns CONTROL+C check status
  968.    Code       Request              Description
  969.    ──────────────────────────────────────────────────────────────────────────
  970.   33H       CONTROL+C Check      Returns CONTROL+C check status
  971.  
  972.    35H       Get Interrupt Vector Returns address of interrupt handler
  973.  
  974.    36H       Get Disk Free Space  Returns disk-space data
  975.  
  976.    38H       Get/Set Country Data Sets current country or retrieves country
  977.                                    information
  978.  
  979.    54H       Get Verify State     Returns status of disk verify
  980.    ──────────────────────────────────────────────────────────────────────────
  981.  
  982.  
  983.  
  984.  1.9  Old System Calls
  985.  
  986.    Most of the superseded system calls deal with files. Table 1.13 lists
  987.    these old calls and the function requests that have superseded them.
  988.  
  989.    Although MS-DOS still includes these old system calls, they should not be
  990.    used unless a program must maintain backward-compatibility with earlier
  991.    versions of MS-DOS.
  992.  
  993.    Table 1.13
  994.    Old System Calls and Their Replacements
  995. ╓┌─┌──────────┌─────────────────────────┌──────────┌─────────────────────────╖
  996.      Old System Call                       Has Been Superseded By
  997.    Code        Function                 Code        Function
  998.    ──────────────────────────────────────────────────────────────────────────
  999.    00H        Terminate Program        4CH        End Process
  1000.    0FH        Open File                3DH        Open Handle
  1001.    10H        Close File               3EH        Close Handle
  1002.    11H        Search for First Entry   4EH        Find First File
  1003.    12H        Search for Next Entry    4FH        Find Next File
  1004.    13H        Delete File              41H        Delete Directory Entry
  1005.    14H        Sequential Read          3FH        Read Handle
  1006.    15H        Sequential Write         40H        Write Handle
  1007.    16H        Create File              3CH        Create Handle
  1008.                                         5AH        Create Temporary File
  1009.                                         5BH        Create New File
  1010.      Old System Call                       Has Been Superseded By
  1011.    Code        Function                 Code        Function
  1012.    ──────────────────────────────────────────────────────────────────────────
  1013.                                        5BH        Create New File
  1014.    17H        Rename File              56H        Change Directory Entry
  1015.    21H        Random Read              3FH        Read Handle
  1016.    22H        Random Write             40H        Write Handle
  1017.    23H        Get File Size            42H        Move File Pointer
  1018.    24H        Set Relative Record      42H        Move File Pointer
  1019.    26H        Create New PSP           4B00H,     Load and Execute Program
  1020.                                         4B03H      or Overlay
  1021.    27H        Random Block Read        42H        Move File Pointer
  1022.                                         3FH        Read Handle
  1023.    28H        Random Block Write       42H        Move File Pointer
  1024.                                         40H        Write Handle
  1025.  
  1026.    Code        Interrupt                Code        Function
  1027.    ──────────────────────────────────────────────────────────────────────────
  1028.    20H        Program Terminate        4CH        End Process
  1029.    27H        Terminate But Stay       31H        Keep Process
  1030.                Resident
  1031.      Old System Call                       Has Been Superseded By
  1032.    Code        Function                 Code        Function
  1033.    ──────────────────────────────────────────────────────────────────────────
  1034.               Resident
  1035.    ──────────────────────────────────────────────────────────────────────────
  1036.  
  1037.  
  1038.  1.9.1  File Control Block (FCB)
  1039.  
  1040.    The old file-related function requests require that a program maintain a
  1041.    File Control Block (FCB) for each file; this control block contains such
  1042.    information as a file's name, size, record length, and pointer to current
  1043.    record. MS-DOS does most of this housekeeping for the newer,
  1044.    handle-oriented function requests.
  1045.  
  1046.    Some descriptions of the old function requests refer to unopened and
  1047.    opened FCBs. An unopened FCB contains only a drive specifier and filename.
  1048.    An opened FCB contains all fields filled by Function 0FH (Open File).
  1049.  
  1050.    The Program Segment Prefix (PSP) includes room for two FCBs at offsets 5CH
  1051.    and 6CH. For a description of how to use the PSP and FCB calls, see
  1052.    Chapter 4, "MS-DOS Control Blocks and Work Areas." Table 1.14 describes
  1053.    the FCB fields.
  1054.  
  1055.    Table 1.14
  1056.    Format of the File Control Block (FCB)
  1057.          Offset
  1058.    Hex            Dec            Bytes                 Field
  1059.    ──────────────────────────────────────────────────────────────────────────
  1060.    00H             0             1                     Drive Number
  1061.    01H             1             8                     Filename
  1062.    09H             9             3                     Extension
  1063.    0CH            12             2                     Current Block
  1064.  
  1065.    0EH            14             2                     Record Size
  1066.    10H            16             4                     File Size
  1067.    14H            20             2                     Date of Last Write
  1068.    16H            22             2                     Time of Last Write
  1069.  
  1070.    18H            24             8                     Reserved
  1071.    20H            32             1                     Current Record
  1072.    21H            33             4                     Relative Record
  1073.    ──────────────────────────────────────────────────────────────────────────
  1074.  
  1075.    Fields of the FCB
  1076.  
  1077.    Drive Number (offset 00H): Specifies the disk drive; 1 means drive A and 2
  1078.    means drive B. If you use the FCB to create or open a file, you can set
  1079.    this field to 0 to specify the default drive; Function 0FH (Open File)
  1080.    sets the field to the number of the default drive.
  1081.  
  1082.    Filename (offset 01H): Eight characters, left-aligned and padded (if
  1083.    necessary) with blanks. If you specify a reserved device name (such as
  1084.    PRN), do not put a colon at the end.
  1085.  
  1086.    Extension (offset 09H): Three characters, left-aligned and padded (if
  1087.    necessary) with blanks. This field can be all blanks (no extension).
  1088.  
  1089.    Current Block (offset 0CH): Points to the block (group of 128 records)
  1090.    that contains the current record. This field and the Current Record field
  1091.    (offset 1FH) make up the record pointer. This field is set to zero by the
  1092.    Open File system call.
  1093.  
  1094.    Record Size (offset 0EH): The size of a logical record, in bytes. Set to
  1095.    128 by the Open File system call. If the record size is not 128 bytes, you
  1096.    must set this field after opening the file.
  1097.  
  1098.    File Size (offset 10H): The size of the file, in bytes. The first word of
  1099.    this 4-byte field is the low-order part of the size.
  1100.  
  1101.    Date of Last Write (offset 14H): The date the file was created or last
  1102.    updated. The year, month, and day are mapped into two bytes as follows:
  1103.  
  1104.    Offset 15H          Offset 14H
  1105.    |Y|Y|Y|Y|Y|Y|Y|M|   |M|M|M|D|D|D|D|D|
  1106.    15              9   8    5 4        0
  1107.  
  1108.    Time of Last Write (offset 16H): The time the file was created or last
  1109.    updated. The hour, minutes, and seconds are mapped into two bytes as
  1110.    follows:
  1111.  
  1112.    Offset 17H          Offset 16H
  1113.    |H|H|H|H|H|M|M|M|   |M|M|M|S|S|S|S|S|
  1114.    15      11 10            5 4        0
  1115.  
  1116.    Reserved (offset 18H): These fields are reserved for use by MS-DOS.
  1117.    Current Record (offset 20H): Points to one of the 128 records in the
  1118.    current block. This field and the Current Block field (offset 0CH) make up
  1119.    the record pointer. The Open File system call does not initialize this
  1120.    field. You must set it before doing a sequential read or write to the
  1121.    file.
  1122.  
  1123.    Relative Record (offset 21H): Points to the currently selected record,
  1124.    counting from the beginning of the file (starting with 0). The Open File
  1125.    system call does not initialize this field. You must set it before doing a
  1126.    random read or write to the file. If the record size is less than 64
  1127.    bytes, both words of this field are used; if the record size is 64 bytes
  1128.    or more, only the first three bytes are used.
  1129.  
  1130.    ──────────────────────────────────────────────────────────────────────────
  1131.    Note
  1132.      If you use the FCB at offset 5CH of the Program Segment Prefix, the last
  1133.      byte of the Relative Record field is the first byte of the unformatted
  1134.      parameter area that starts at offset 80H. This is the default Disk
  1135.      Transfer Area.
  1136.    ──────────────────────────────────────────────────────────────────────────
  1137.  
  1138.    Extended FCB
  1139.  
  1140.    The Extended File Control Block is used to create or search for directory
  1141.    entries of files with special attributes. It adds the following 7-byte
  1142.    prefix to the FCB:
  1143.  
  1144.    Name                 Bytes      Offset
  1145.    ──────────────────────────────────────────────────────────────────────────
  1146.    Flag byte (FFH)      1          07H
  1147.    Reserved             5          06H
  1148.    Attribute byte       1          01H
  1149.    ──────────────────────────────────────────────────────────────────────────
  1150.  
  1151.    File attributes are described earlier in this chapter in Section 1.5.5,
  1152.    "File Attributes."
  1153.  
  1154.    ──────────────────────────────────────────────────────────────────────────
  1155.    Note
  1156.      You must remember to point to the beginning of the extended FCB if you
  1157.      are using Functions 0FH-16H with extended FCBs.
  1158.    ──────────────────────────────────────────────────────────────────────────
  1159.  
  1160.  
  1161.  1.10  Using the System Calls
  1162.  
  1163.    The remainder of this chapter describes how to use the system calls in
  1164.    application programs, and it lists the calls in numeric and alphabetic
  1165.    order, describing each call in detail.
  1166.  
  1167.  1.10.1  Issuing an Interrupt
  1168.  
  1169.    MS-DOS reserves Interrupts 28H through 3FH for its own use, and maintains
  1170.    the table of interrupt-handler addresses (the vector table) in locations
  1171.    80H-FCH. Also, in case you need to write your own routines for three
  1172.    particular MS-DOS interrupt handlers (Program Terminate, CONTROL+C, and
  1173.    Critical Error), this chapter includes descriptions of each. Function
  1174.    requests have superseded most of these interrupts.
  1175.  
  1176.    To issue an interrupt, move any required data into the registers and give
  1177.    the INT instruction with the number of the interrupt you want.
  1178.  
  1179.  1.10.2  Calling a Function Request
  1180.  
  1181.    A function request is an MS-DOS routine for managing system resources. Use
  1182.    the following procedure to call a function request:
  1183.  
  1184.    1. Move any required data into the registers.
  1185.  
  1186.    2. Move the function number into AH.
  1187.  
  1188.    3. Move the action code, if required, into AL.
  1189.  
  1190.    4. Issue Interrupt 21H.
  1191.  
  1192.  1.10.3  Using the Calls from a High-Level Language
  1193.  
  1194.    The system calls can be executed from any high-level language whose
  1195.    modules can be linked with assembly-language modules. In addition to this
  1196.    linking technique, you can:
  1197.  
  1198.    ■  Use the Interrupt 86 function of C to call a function request directly.
  1199.  
  1200.    ■  Use the DOSXQQ function of Pascal to call a function request directly.
  1201.  
  1202.    ■  Use the CALL statement or USER function to execute the required
  1203.       assembly-language code from the BASIC interpreter.
  1204.  
  1205.  1.10.4  Treatment of Registers
  1206.  
  1207.    When MS-DOS takes control after a function request, it switches to an
  1208.    internal stack, and preserves any registers not used to return information
  1209.    (except AX). The calling program's stack must be large enough to
  1210.    accommodate the interrupt system──at least 128 bytes in addition to other
  1211.    needs.
  1212.  
  1213.  1.10.5  Handling Errors
  1214.  
  1215.    Most of the function requests introduced with MD-DOS version 2.0 or later
  1216.    set the Carry flag if there is an error, identifying the specific error by
  1217.    returning a number in the AX register. Table 1.15 lists these error codes
  1218.    and their meanings.
  1219.  
  1220.    Table 1.15
  1221.    Error Codes Returned in AX
  1222. ╓┌─┌──────────────┌──────────────────────────────────────────────────────────╖
  1223.    Code           Meaning
  1224.    ──────────────────────────────────────────────────────────────────────────
  1225.     1             Invalid function code
  1226.     2             File not found
  1227.     3             Path not found
  1228.     4             Too many open files (no open handles left)
  1229.     5             Access denied
  1230.     6             Invalid handle
  1231.     7             Memory control blocks destroyed
  1232.     8             Insufficient memory
  1233.     9             Invalid memory block address
  1234.  
  1235.    10             Invalid environment
  1236.    11             Invalid format
  1237.    12             Invalid access code
  1238.    13             Invalid data
  1239.    14             Reserved
  1240.    15             Invalid drive
  1241.    Code           Meaning
  1242.    ──────────────────────────────────────────────────────────────────────────
  1243.   15             Invalid drive
  1244.    16             Attempt to remove the current directory
  1245.    17             Not same device
  1246.    18             No more files
  1247.    19             Disk is write-protected
  1248.  
  1249.    20             Bad disk unit
  1250.    21             Drive not ready
  1251.    22             Invalid disk command
  1252.    23             CRC error
  1253.    24             Invalid length (disk operation)
  1254.    25             Seek error
  1255.    26             Not an MS-DOS disk
  1256.    27             Sector not found
  1257.    28             Out of paper
  1258.    29             Write fault
  1259.  
  1260.    30             Read Fault
  1261.    31             General failure
  1262.    Code           Meaning
  1263.    ──────────────────────────────────────────────────────────────────────────
  1264.   31             General failure
  1265.    32             Sharing violation
  1266.    33             Lock violation
  1267.    34             Wrong disk
  1268.    35             FCB unavailable
  1269.    36             Sharing buffer exceeded
  1270.    37             Reserved
  1271.    38             Handle end-of-file operation not completed
  1272.    39-49          Reserved
  1273.  
  1274.    50             Network request not supported
  1275.    51             Remote computer not listening
  1276.    52             Duplicate name on network
  1277.    53             Network name not found
  1278.    54             Network busy
  1279.    55             Network device no longer exists
  1280.    56             Net BIOS command limit exceeded
  1281.    57             Network adapter hardware error
  1282.    58             Incorrect response from network
  1283.    Code           Meaning
  1284.    ──────────────────────────────────────────────────────────────────────────
  1285.   58             Incorrect response from network
  1286.    59             Unexpected network error
  1287.  
  1288.    60             Incompatible remote adapter
  1289.    61             Print queue full
  1290.    62             Queue not full
  1291.    63             Not enough space for print file
  1292.    64             Network name was deleted
  1293.    65             Access denied
  1294.    66             Network device type incorrect
  1295.    67             Network name not found
  1296.    68             Network name limit exceeded
  1297.    69             Net BIOS session limit exceeded
  1298.  
  1299.    70             Temporarily paused
  1300.    71             Network request not accepted
  1301.    72             Print or disk redirection is paused
  1302.    73-79          Reserved
  1303.  
  1304.    Code           Meaning
  1305.    ──────────────────────────────────────────────────────────────────────────
  1306. 
  1307.    80             File Exists
  1308.    81             Reserved
  1309.    82             Cannot make
  1310.    83             Interrupt 24 failure
  1311.    84             Out of structures
  1312.    85             Already assigned
  1313.    86             Invalid password
  1314.    87             Invalid parameter
  1315.    88             Net write fault
  1316.    89             Function not supported by network
  1317.  
  1318.    90             Required system component not installed
  1319.    ──────────────────────────────────────────────────────────────────────────
  1320.  
  1321.  
  1322.    To handle error conditions, put the following statement immediately after
  1323.    calls that return errors:
  1324.  
  1325.    JC <error>
  1326.  
  1327.    <Error> represents the label of an error-handling routine that gets the
  1328.    specific error condition by checking the value in AX. This routine then
  1329.    takes appropriate action.
  1330.  
  1331.    Some of the older system calls return a value in a register that specifies
  1332.    whether the operation was successful. To handle such errors, check the
  1333.    error code and take the appropriate action.
  1334.  
  1335.    Extended Error Codes
  1336.  
  1337.    Versions of MS-DOS after 2.0 have added new error messages. Any programs
  1338.    that use the older system calls cannot use these new error messages. To
  1339.    avoid incompatibility, MS-DOS maps these new error codes to the old error
  1340.    code that most closely matches the new one.
  1341.  
  1342.    Function 59H (Get Extended Error) has been added so that these new calls
  1343.    can be used. It provides as much detail as possible about the most recent
  1344.    error code returned by MS-DOS. The description of Function 59H lists the
  1345.    new, more detailed error codes and shows how to use this function request.
  1346.  
  1347.  1.10.6  System Call Descriptions
  1348.  
  1349.    Most system calls require that you move information into one or more
  1350.    registers before issuing the call that returns information in the
  1351.    registers. The description of each system call in this chapter includes
  1352.    the following:
  1353.  
  1354.    ■  A diagram of the 8088 registers that shows their contents before and
  1355.       after the system call
  1356.  
  1357.    ■  A more complete description of the register contents required before
  1358.       the system call
  1359.  
  1360.    ■  A description of the processing performed
  1361.  
  1362.    ■  A more complete description of the register contents after the system
  1363.       call
  1364.  
  1365.    ■  An example of how to use the system call
  1366.  
  1367.    The following figure is a sample illustration of the 8088 registers,
  1368.    showing how the information is presented. Shaded areas indicate that the
  1369.    register receives or returns information used by the call.
  1370.  
  1371.       ┌───────┬───────┐
  1372.    AX:│  AH   │  AL   │
  1373.       ├───────┼───────┤
  1374.    BX:│  BH   │  BL   │
  1375.       ├───────┼───────┤
  1376.    CX:│  CH   │  CL   │
  1377.       ├───────┼───────┤
  1378.    DX:│  DH   │  DL   │
  1379.       └───────┴───────┘
  1380.       ┌───────────────┐
  1381.       │       SP      │
  1382.       ├───────────────┤
  1383.       │       BP      │
  1384.       ├───────────────┤
  1385.       │       SI      │
  1386.       ├───────────────┤
  1387.       │       DI      │
  1388.       └───────────────┘
  1389.       ┌───────────────┐
  1390.       │       SP      │
  1391.       ├───────┬───────┤
  1392.       │FLAGS H│FLAGS L│
  1393.       └───────┴───────┘
  1394.  
  1395.       ┌───────────────┐
  1396.       │       CS      │
  1397.       ├───────────────┤
  1398.       │       DS      │
  1399.       ├───────────────┤
  1400.       │       SS      │
  1401.       ├───────────────┤
  1402.       │       ES      │
  1403.       └───────────────┘
  1404.  
  1405.    Figure 1.1  Example of the 8088 Registers
  1406.  
  1407.    Sample Programs
  1408.  
  1409.    The sample programs show only data declarations and the code that you need
  1410.    to use the system calls. Unless stated otherwise, each example assumes a
  1411.    common program skeleton that defines the segments and returns control to
  1412.    MS-DOS. Each sample program is intended to be executed as a .com file.
  1413.    Figure 1.2 shows a complete sample program. The unshaded portion shows
  1414.    what appears in this chapter; the shaded portions are the common skeleton.
  1415.  
  1416.  
  1417.    ------------------------------------------------------------
  1418.    code       segment
  1419.               assume  cs:code,ds:code,es:nothing,ss:nothing
  1420.               org     100H
  1421.    start:     jmp    begin
  1422.    ;
  1423.    filename   db     "b:\textfile.asc",0
  1424.    buffer     db      129 dup (?)
  1425.    handle     dw      ?
  1426.    ;
  1427.    begin:     open_handle filename,0    ; Open the file
  1428.               jc      error_open        ; Routine not shown
  1429.               mov     handle,ax         ; Save handle
  1430.    read_line: read_handle handle,buffer,128 ; Read 128 bytes
  1431.               jc      error_read        ; Routine not shown
  1432.               cmp     ax,0              ; End of file?
  1433.               je      return            ; Yes, go home
  1434.               mov     bx,ax             ; No, AX bytes read
  1435.               mov     buffer[bx],"$"    ; To terminate string
  1436.               display buffer            ; See Function 09H
  1437.               jmp     read_line         ; Get next 128 bytes
  1438.  
  1439.    return:    end_process 0             ; Return to MS-DOS
  1440.    last_inst:                           ; To mark next byte
  1441.    ;
  1442.    code       ends
  1443.               end     start
  1444.    ------------------------------------------------------------
  1445.  
  1446.    Figure 1.2  Sample Program with Common Skeleton
  1447.  
  1448.    A macro has been defined for each system call to allow the examples to be
  1449.    more complete programs, rather than isolated uses of the system calls.
  1450.    These macros, plus some general-purpose ones, are used in the sample
  1451.    programs. For instance, the sample program in the preceding figure
  1452.    includes four such macros: open_handle, read_handle, display, and
  1453.    end_process. All the macro definitions are listed at the end of this
  1454.    chapter.
  1455.  
  1456.    The macros assume the environment for a .com program as described in
  1457.    Chapter 4; in particular, they assume that all the segment registers
  1458.    contain the same value. To conserve space, the macros generally leave
  1459.    error checking to the main code and do not protect registers. This keeps
  1460.    the macros short, yet useful. You may find that such macros are a
  1461.    convenient way to include system calls in your assembly-language programs.
  1462.  
  1463.    Error Handling in Sample Programs
  1464.  
  1465.    Whenever a system call returns an error code, the sample program shows a
  1466.    test for the error condition and a jump to an error routine. To conserve
  1467.    space, the error routines themselves aren't shown. Some error routines
  1468.    might simply display a message and continue processing. For more serious
  1469.    errors, the routine might display a message and end the program
  1470.    (performing any required housekeeping, such as closing files).
  1471.  
  1472.    Tables 1.16 through 1.19 list the Interrupts and Function Requests in
  1473.    numeric and alphabetic order.
  1474.  
  1475.    Table 1.16
  1476.    MS-DOS Interrupts, Numeric Order
  1477.    Interrupt                            Description
  1478.    ──────────────────────────────────────────────────────────────────────────
  1479.    20H                                 Program Terminate
  1480.    21H                                 Function Request
  1481.    22H                                 Terminate Process Exit Address
  1482.    23H                                 CONTROL+C Handler Address
  1483.    24H                                 Critical-Error-Handler Address
  1484.    25H                                 Absolute Disk Read
  1485.    26H                                 Absolute Disk Write
  1486.    27H                                 Terminate But Stay Resident
  1487.    28H-3FH                              Reserved
  1488.    ──────────────────────────────────────────────────────────────────────────
  1489.  
  1490.    Table 1.17
  1491.    MS-DOS Interrupts, Alphabetic Order
  1492.    Description                          Interrupt
  1493.    ──────────────────────────────────────────────────────────────────────────
  1494.    Absolute Disk Read                   25H
  1495.    Absolute Disk Write                  26H
  1496.    CONTROL+C Handler Address            23H
  1497.    Critical-Error-Handler Address       24H
  1498.    Function Request                     21H
  1499.    Program Terminate                    20H
  1500.    Reserved                             28H-3FH
  1501.    Terminate Process Exit Address       22H
  1502.    Terminate But Stay Resident          27H
  1503.    ──────────────────────────────────────────────────────────────────────────
  1504.  
  1505.    Table 1.18
  1506.    MS-DOS Function Requests, Numeric Order
  1507. ╓┌─┌──────────────────┌──────────────────────────────────────────────────────╖
  1508.    Function           Description
  1509.    ──────────────────────────────────────────────────────────────────────────
  1510.    00H               Terminate Program
  1511.    01H               Read Keyboard And Echo
  1512.    02H               Display Character
  1513.    03H               Auxiliary Input
  1514.    Function           Description
  1515.    ──────────────────────────────────────────────────────────────────────────
  1516.   03H               Auxiliary Input
  1517.    04H               Auxiliary Output
  1518.    05H               Print Character
  1519.    06H               Direct Console I/O
  1520.    07H               Direct Console Input
  1521.    08H               Read Keyboard
  1522.    09H               Display String
  1523.    0AH               Buffered Keyboard Input
  1524.    0BH               Check Keyboard Status
  1525.    0CH               Flush Buffer, Read Keyboard
  1526.    0DH               Reset Disk
  1527.    0EH               Select Disk
  1528.    0FH               Open File
  1529.    10H               Close File
  1530.    11H               Search For First Entry
  1531.    12H               Search For Next Entry
  1532.    13H               Delete File
  1533.    14H               Sequential Read
  1534.    15H               Sequential Write
  1535.    Function           Description
  1536.    ──────────────────────────────────────────────────────────────────────────
  1537.   15H               Sequential Write
  1538.    16H               Create File
  1539.    17H               Rename File
  1540.    18H                Reserved
  1541.    19H               Get Current Disk
  1542.    1AH               Set Disk Transfer Address
  1543.    1BH               Get Default Drive Data
  1544.    1CH               Get Drive Data
  1545.    1DH-20H            Reserved
  1546.    21H               Random Read
  1547.    22H               Random Write
  1548.    23H               Get File Size
  1549.    24H               Set Relative Record
  1550.    25H               Set Interrupt Vector
  1551.    26H               Create New PSP
  1552.    27H               Random Block Read
  1553.    28H               Random Block Write
  1554.    29H               Parse File Name
  1555.    2AH               Get Date
  1556.    Function           Description
  1557.    ──────────────────────────────────────────────────────────────────────────
  1558.   2AH               Get Date
  1559.    2BH               Set Date
  1560.    2CH               Get Time
  1561.    2DH               Set Time
  1562.    2EH               Set/Reset Verify Flag
  1563.    2FH               Get Disk Transfer Address
  1564.    30H               Get MS-DOS Version Number
  1565.    31H               Keep Process
  1566.    32H                Reserved
  1567.    33H               CONTROL+C Check
  1568.    34H                Reserved
  1569.    35H               Get Interrupt Vector
  1570.    36H               Get Disk Free Space
  1571.    37H                Reserved
  1572.    38H               Get/Set Country Data
  1573.    39H               Create Directory
  1574.    3AH               Remove Directory
  1575.    3BH               Change Current Directory
  1576.    3CH               Create Handle
  1577.    Function           Description
  1578.    ──────────────────────────────────────────────────────────────────────────
  1579.   3CH               Create Handle
  1580.    3DH               Open Handle
  1581.    3EH               Close Handle
  1582.    3FH               Read Handle
  1583.    40H               Write Handle
  1584.    41H               Delete Directory Entry (Unlink)
  1585.    42H               Move File Pointer
  1586.    43H               Get/Set File Attributes (Chmod)
  1587.    4400H, 4401H     IOCtl Data
  1588.    4402H, 4403H     IOCtl Character
  1589.    4404H, 4405H     IOCtl Block
  1590.    4406H, 4407H     IOCtl Status
  1591.    4408H             IOCtl Is Changeable
  1592.    4409H             IOCtl Is Redirected Block
  1593.    440AH             IOCtl Is Redirected Handle
  1594.    440BH             IOCtl Retry
  1595.    440CH             Generic IOCtl (for code page functions)
  1596.    440DH             Generic IOCtl (for devices)
  1597.    440EH             Get IOCtl Drive Map
  1598.    Function           Description
  1599.    ──────────────────────────────────────────────────────────────────────────
  1600.   440EH             Get IOCtl Drive Map
  1601.    440FH             Set IOCtl Drive Map
  1602.    45H               Duplicate File Handle
  1603.    46H               Force Duplicate File Handle
  1604.    47H               Get Current Directory
  1605.    48H               Allocate Memory
  1606.    49H               Free Allocated Memory
  1607.    4AH               Set Block
  1608.    4B00H, 4B03H     Load and Execute Program or Overlay
  1609.    4CH               End Process
  1610.    4DH               Get Return Code of Child Process
  1611.    4EH               Find First File
  1612.    4FH               Find Next File
  1613.    50H-53H            Reserved
  1614.    54H               Get Verify State
  1615.    55H                Reserved
  1616.    56H               Change Directory Entry
  1617.    57H               Get/Set Date/Time of File
  1618.    58H               Get/Set Allocation Strategy
  1619.    Function           Description
  1620.    ──────────────────────────────────────────────────────────────────────────
  1621.   58H               Get/Set Allocation Strategy
  1622.    59H               Get Extended Error
  1623.    5AH               Create Temporary File
  1624.    5BH               Create New File
  1625.    5C00H, 5C01H     Lock/Unlock Files
  1626.    5DH                Reserved
  1627.    5E00H             Get Machine Name
  1628.    5E02H             Set Printer Setup
  1629.    5E03H             Get Printer Setup
  1630.    5F02H             Get Assign-List Entry
  1631.    5F03H             Make Network Connection
  1632.    5F04H             Delete Network Connection
  1633.    60H-61H            Reserved
  1634.    62H               Get PSP
  1635.    63H,64H            Reserved
  1636.    65H               Get Extended Country Information
  1637.    66H               Get/Set Global Code Page
  1638.    67H               Set Handle Count
  1639.    68H               Commit File
  1640.    Function           Description
  1641.    ──────────────────────────────────────────────────────────────────────────
  1642.   68H               Commit File
  1643.    69H-6BH            Reserved
  1644.    6CH               Extended Open/Create
  1645.    6DH-7FH            Reserved
  1646.    ──────────────────────────────────────────────────────────────────────────
  1647.  
  1648.  
  1649.    Table 1.19
  1650.    MS-DOS Function Requests, Alphabetic Order
  1651. ╓┌─┌───────────────────────────────────────────────────────┌─────────────────╖
  1652.    Description                                             Function
  1653.    ──────────────────────────────────────────────────────────────────────────
  1654.    Allocate Memory                                         48H
  1655.    Auxiliary Input                                         03H
  1656.    Auxiliary Output                                        04H
  1657.    Buffered Keyboard Input                                 0AH
  1658.    Change Current Directory                                3BH
  1659.    Change Directory Entry                                  56H
  1660.    Check Keyboard Status                                   0BH
  1661.    Description                                             Function
  1662.    ──────────────────────────────────────────────────────────────────────────
  1663.   Check Keyboard Status                                   0BH
  1664.    Close File                                              10H
  1665.    Close Handle                                            3EH
  1666.    Commit FIle                                             68H
  1667.    CONTROL+C Check                                         33H
  1668.    Create Directory                                        39H
  1669.    Create File                                             16H
  1670.    Create Handle                                           3CH
  1671.    Create New File                                         5BH
  1672.    Create New PSP                                          26H
  1673.    Create Temporary File                                   5AH
  1674.    Delete Directory Entry (Unlink)                         41H
  1675.    Delete File                                             13H
  1676.    Delete Network Connection                               5F04H
  1677.    Direct Console I/O                                      06H
  1678.    Direct Console Input                                    07H
  1679.    Display Character                                       02H
  1680.    Display String                                          09H
  1681.    Duplicate File Handle                                   45H
  1682.    Description                                             Function
  1683.    ──────────────────────────────────────────────────────────────────────────
  1684.   Duplicate File Handle                                   45H
  1685.    End Process                                             4CH
  1686.    Extended Open/Create                                    6CH
  1687.    Find First File                                         4EH
  1688.    Find Next File                                          4FH
  1689.    Flush Buffer, Read Keyboard                             0CH
  1690.    Force Duplicate File Handle                             46H
  1691.    Free Allocated Memory                                   49H
  1692.    Generic IOCtl (for devices)                             440DH
  1693.    Generic IOCtl (for code page functions)                 440CH
  1694.    Get Assign-List Entry                                   5F02H
  1695.    Get Current Directory                                   47H
  1696.    Get Current Disk                                        19H
  1697.    Get Date                                                2AH
  1698.    Get Default Drive Data                                  1BH
  1699.    Get Disk Free Space                                     36H
  1700.    Get Disk Transfer Address                               2FH
  1701.    Get Drive Data                                          1CH
  1702.    Get Extended Country Information                        65H
  1703.    Description                                             Function
  1704.    ──────────────────────────────────────────────────────────────────────────
  1705.   Get Extended Country Information                        65H
  1706.    Get Extended Error                                      59H
  1707.    Get File Size                                           23H
  1708.    Get Interrupt Vector                                    35H
  1709.    Get IOCtl Drive Map                                     440EH
  1710.    Get Machine Name                                        5E00H
  1711.    Get MS-DOS Version Number                               30H
  1712.    Get PSP                                                 62H
  1713.    Get Printer Setup                                       5E03H
  1714.    Get Return Code of Child Process                        4DH
  1715.    Get Time                                                2CH
  1716.    Get Verify State                                        54H
  1717.    Get/Set Allocation Strategy                             58H
  1718.    Get/Set Country Data                                    38H
  1719.    Get/Set Date/Time Of File                               57H
  1720.    Get/Set File Attributes (Chmod)                         43H
  1721.    Get/Set Global Code Page                                66H
  1722.    IOCtl Block                                             4404H, 4405H
  1723.    IOCtl Character                                         4402H, 4403H
  1724.    Description                                             Function
  1725.    ──────────────────────────────────────────────────────────────────────────
  1726.   IOCtl Character                                         4402H, 4403H
  1727.    IOCtl Data                                              4400H, 4401H
  1728.    IOCtl Is Changeable                                     4408H
  1729.    IOCtl Is Redirected Block                               4409H
  1730.    IOCtl Is Redirected Handle                              440AH
  1731.    IOCtl Retry                                             440BH
  1732.    IOCtl Status                                            4406H, 4407H
  1733.    Keep Process                                            31H
  1734.    Load and Execute Program                                4B00H
  1735.    Load Overlay                                            4B03H
  1736.    Lock/Unlock Files                                       5C00H, 5C01H
  1737.    Make Network Connection                                 5F03H
  1738.    Move File Pointer                                       42H
  1739.    Open File                                               0FH
  1740.    Open Handle                                             3DH
  1741.    Parse File Name                                         29H
  1742.    Print Character                                         05H
  1743.    Random Block Read                                       27H
  1744.    Random Block Write                                      28H
  1745.    Description                                             Function
  1746.    ──────────────────────────────────────────────────────────────────────────
  1747.   Random Block Write                                      28H
  1748.    Random Read                                             21H
  1749.    Random Write                                            22H
  1750.    Read Handle                                             3FH
  1751.    Read Keyboard                                           08H
  1752.    Read Keyboard And Echo                                  01H
  1753.    Remove Directory                                        3AH
  1754.    Rename File                                             17H
  1755.    Reserved                                                18H
  1756.    Reserved                                                1DH-20H
  1757.    Reserved                                                32H
  1758.    Reserved                                                34H
  1759.    Reserved                                                37H
  1760.    Reserved                                                50H-53H
  1761.    Reserved                                                55H
  1762.    Reserved                                                5DH
  1763.    Reserved                                                60H-61H
  1764.    Reserved                                                63H, 64H
  1765.    Reserved                                                69H-6BH
  1766.    Description                                             Function
  1767.    ──────────────────────────────────────────────────────────────────────────
  1768.   Reserved                                                69H-6BH
  1769.    Reserved                                                6DH-7FH
  1770.    Reset Disk                                              0DH
  1771.    Search for First Entry                                  11H
  1772.    Search for Next Entry                                   12H
  1773.    Select Disk                                             0EH
  1774.    Sequential Read                                         14H
  1775.    Sequential Write                                        15H
  1776.    Set Block                                               4AH
  1777.    Set Date                                                2BH
  1778.    Set Disk Transfer Address                               1AH
  1779.    Set Handle Count                                        67H
  1780.    Set Interrupt Vector                                    25H
  1781.    Set IOCtl Drive Map                                     440FH
  1782.    Set Printer Setup                                       5E02H
  1783.    Set Relative Record                                     24H
  1784.    Set Time                                                2DH
  1785.    Set/Reset Verify Flag                                   2EH
  1786.    Terminate Program                                       00H
  1787.    Description                                             Function
  1788.    ──────────────────────────────────────────────────────────────────────────
  1789.   Terminate Program                                       00H
  1790.    Write Handle                                            40H
  1791.    ──────────────────────────────────────────────────────────────────────────
  1792.  
  1793.  
  1794.    A detailed description of each system call follows. These calls are listed
  1795.    in numeric order, interrupts first, followed by function requests.
  1796.  
  1797.    ──────────────────────────────────────────────────────────────────────────
  1798.    Note
  1799.      Unless stated otherwise, in the system call descriptions──both text and
  1800.      code──all numbers are in hexadecimal.
  1801.    ──────────────────────────────────────────────────────────────────────────
  1802.  
  1803.  
  1804.  1.11  Interrupts
  1805.  
  1806.    The following pages describe Interrupts 20H-27H.
  1807.  
  1808.  
  1809.  ────────────────────────────────────────────────────────────────────────────
  1810.  Program Terminate (Interrupt 20H)
  1811.  ────────────────────────────────────────────────────────────────────────────
  1812.  
  1813.    Call:
  1814.  
  1815.    CS
  1816.      Segment address of Program Segment Prefix
  1817.  
  1818.    Return:
  1819.  
  1820.    None
  1821.  
  1822.  
  1823.    Comments:
  1824.  
  1825.    Interrupt 20H terminates the current process and returns control to its
  1826.    parent process. It also closes all open file handles and clears the disk
  1827.    cache. When this interrupt is issued, CS must contain the segment address
  1828.    of the Program Segment Prefix.
  1829.  
  1830.    Interrupt 20H is provided only for compatibility with MS-DOS versions
  1831.    prior to 2.0. New programs should use Function 4CH (End Process), which
  1832.    permits returning a completion code to the parent process and does not
  1833.    require CS to contain the segment address of the Program Segment Prefix.
  1834.  
  1835.    The following exit addresses are restored from the Program Segment Prefix:
  1836.  
  1837.    Offset             Exit Address
  1838.    ──────────────────────────────────────────────────────────────────────────
  1839.    0AH                Program terminate
  1840.    0EH                CONTROL+C
  1841.    12H                Critical error
  1842.    ──────────────────────────────────────────────────────────────────────────
  1843.  
  1844.    All file buffers are flushed to disk.
  1845.  
  1846.    ──────────────────────────────────────────────────────────────────────────
  1847.    Note
  1848.      You should close all files that have changed in length before issuing
  1849.      this interrupt. If you do not close a changed file, its length may not
  1850.      be recorded correctly in the directory. See Functions 10H and 3EH for
  1851.      a description of the Close File system calls. If sharing is loaded, you
  1852.      should remove all locks before using Interrupt 20H. See Function 5C00H
  1853.      (Lock) for more information.
  1854.    ──────────────────────────────────────────────────────────────────────────
  1855.  
  1856.    Macro Definition:
  1857.  
  1858.    terminate  macro
  1859.               int 20H
  1860.               endm
  1861.  
  1862.    Example:
  1863.  
  1864.    The following program displays a message and returns to MS-DOS.
  1865.  
  1866.    message db "displayed by INT20H example". 0DH, 0AH, "$"
  1867.    ;
  1868.    begin:  display message  ; see Function 09H
  1869.            terminate        ; THIS INTERRUPT
  1870.    code    ends
  1871.            end     start
  1872.  
  1873.  
  1874.  ────────────────────────────────────────────────────────────────────────────
  1875.  Function Request (Interrupt 21H)
  1876.  ────────────────────────────────────────────────────────────────────────────
  1877.  
  1878.    Call:
  1879.  
  1880.    AH
  1881.      Function number
  1882.  
  1883.    Other registers
  1884.      As specified in individual function
  1885.  
  1886.    Return:
  1887.  
  1888.    None
  1889.  
  1890.  
  1891.    Comments:
  1892.  
  1893.    As specified in individual function. Interrupt 21H causes MS-DOS to carry
  1894.    out the function request whose number is in AH. See Section 1.12,
  1895.    "Function Requests," for a description of the MS-DOS functions.
  1896.  
  1897.    Example:
  1898.  
  1899.    To call the Get Time function:
  1900.  
  1901.    mov   ah,2CH           ; Get Time is Function 2CH
  1902.    int   21H              ; MS-DOS function request
  1903.  
  1904.  
  1905.  ────────────────────────────────────────────────────────────────────────────
  1906.  Terminate Process Exit Address (Interrupt 22H)
  1907.  ────────────────────────────────────────────────────────────────────────────
  1908.  
  1909.    This interrupt may be issued only by MS-DOS; user programs must never
  1910.    issue it. If you must write your own terminate interrupt handler, use
  1911.    Function 35H (Get Interrupt Vector) to get the address of the standard
  1912.    routine, save the address, then use Function 25H (Set Interrupt Vector)
  1913.    to change the Interrupt 22H entry in the vector table so that it points to
  1914.    your routine.
  1915.  
  1916.    When a program terminates, MS-DOS transfers control to the routine that
  1917.    starts at the address in the Interrupt 22H entry in the vector table. When
  1918.    MS-DOS creates a program segment, it copies this address into the Program
  1919.    Segment Prefix, starting at offset 0AH.
  1920.  
  1921.  
  1922.  ────────────────────────────────────────────────────────────────────────────
  1923.  CONTROL+C Handler Address (Interrupt 23H)
  1924.  ────────────────────────────────────────────────────────────────────────────
  1925.  
  1926.    When you type CONTROL+C or CONTROL+BREAK (on IBM-compatibles), MS-DOS
  1927.    transfers control as soon as possible to the routine that starts at the
  1928.    address in the Interrupt 23H entry in the vector table. When MS-DOS
  1929.    creates a program segment, it copies the address currently in the
  1930.    interrupt table into the Program Segment Prefix, starting at offset 0EH.
  1931.  
  1932.    This interrupt may be issued only by MS-DOS; user programs must never
  1933.    issue it. If you must write your own CONTROL+C interrupt handler, use
  1934.    Function 35H (Get Interrupt Vector) to get the address of the standard
  1935.    routine, save the address, then use Function 25H (Set Interrupt Vector)
  1936.    to change the Interrupt 23H entry in the vector table to point to your
  1937.    routine.
  1938.  
  1939.    If the CONTROL+C routine preserves all registers, it can end with an IRET
  1940.    instruction (return from interrupt) to continue program execution. If a
  1941.    user-written interrupt program returns with a long return, the program
  1942.    uses the carry flag to determine whether or not the program will abort. If
  1943.    the carry flag is set, it will abort; otherwise, execution will continue
  1944.    as with a return by IRET.
  1945.  
  1946.    If a user-written CONTROL+BREAK routine interrupts function calls 09H,
  1947.    0AH, or buffered I/O, and if it continues execution with an IRET, then I/O
  1948.    continues from the start of the line. MS-DOS always outputs a CONTROL+C to
  1949.    the screen when it issues an Interrupt 23H. There is no way to turn this
  1950.    off.
  1951.  
  1952.    When the interrupt occurs, all registers are set to the value they had
  1953.    when the original call to MS-DOS was made. There are no restrictions on
  1954.    what a CONTROL+C handler can do──including calling MS-DOS functions──as
  1955.    long as the program restores the registers.
  1956.  
  1957.    If a CONTROL+C interrupts Function 09H or 0AH (Display String or Buffered
  1958.    Keyboard Input), the three-byte sequence 03H-0DH-0AH (usually displayed as
  1959.    C followed by a carriage-return) is sent to the display and the function
  1960.    resumes at the beginning of the next line.
  1961.  
  1962.    Suppose a program uses Function 4BH (Load and Execute Program or Overlay)
  1963.    to create a second Program Segment Prefix and execute a second program,
  1964.    which then changes the CONTROL+C address in the vector table. MS-DOS
  1965.    restores this CONTROL+C vector to its original value before returning
  1966.    control to the calling program.
  1967.  
  1968.  
  1969.  ────────────────────────────────────────────────────────────────────────────
  1970.  critical-error-handler address (Interrupt 24H)
  1971.  ────────────────────────────────────────────────────────────────────────────
  1972.  
  1973.    If a critical error occurs during execution of an I/O function
  1974.    request (this often means a fatal disk error), MS-DOS transfers control to
  1975.    the routine at the address in the Interrupt 24H entry in the vector table.
  1976.    When MS-DOS creates a program segment, it copies this address into the
  1977.    Program Segment Prefix, starting at offset 12H.
  1978.  
  1979.    This interrupt may be issued only by MS-DOS; user programs must never
  1980.    issue it. If you must write your own critical-error interrupt handler, use
  1981.    Function 35H (Get Interrupt Vector) to get the address of the standard
  1982.    routine, save the address, then use Function 25H (Set Interrupt Vector)
  1983.    to change the Interrupt 24H entry in the vector table to point to your
  1984.    routine.
  1985.  
  1986.    MS-DOS does not issue Interrupt 24H if a failure occurs during execution
  1987.    of Interrupt 25H (Absolute Disk Read) or Interrupt 26H (Absolute Disk
  1988.    Write). A command.com error routine handles these errors. This routine
  1989.    retries the disk operation, then gives you the choice of aborting the
  1990.    operation, retrying it, allowing the system call to fail and the
  1991.    application process to continue, or ignoring the error.
  1992.  
  1993.    The following topics describe the requirements of an Interrupt 24H
  1994.    routine, including the error codes, registers, and stack.
  1995.  
  1996.  1.11.1  Conditions upon Entry
  1997.  
  1998.    After retrying an I/O error five times, MS-DOS issues Interrupt 24H,
  1999.    unless a File Allocation Table (FAT) or directory sector is involved. In
  2000.    those cases, DOS performs three retries. The interrupt handler receives
  2001.    control with interrupts disabled. AX and DI contain error codes, and BP
  2002.    contains the offset (to the segment address in SI) of a Device Header
  2003.    control block that describes the device on which the error occurred.
  2004.  
  2005.  1.11.2  Requirements for an Interrupt 24H Handler
  2006.  
  2007.    To issue the "Abort, Retry, Fail or Ignore" prompt to a user, a
  2008.    user-written critical-error handler should first push the flags and
  2009.    execute a FAR call to the address of the standard Interrupt 24H handler
  2010.    (the user program that changed the Interrupt 24H vector also should have
  2011.    saved this address). After a user responds to the prompt, MS-DOS returns
  2012.    control to the user-written routine.
  2013.  
  2014.    ──────────────────────────────────────────────────────────────────────────
  2015.    Note
  2016.      There are source applications which will have trouble handling critical
  2017.      errors, since this changes the stack frame.
  2018.    ──────────────────────────────────────────────────────────────────────────
  2019.  
  2020.    The error handler can then do its processing. However, before it does
  2021.    anything else, it must preserve BX, CX, DX, DS, ES, SS, and SP. Also, the
  2022.    error handler may use only function calls 01H-0CH (inclusive) and 59H (if
  2023.    it uses any others, the error handler destroys the MS-DOS stack and leaves
  2024.    MS-DOS in an unstable state). The contents of the Device Header should not
  2025.    be changed.
  2026.  
  2027.    It is recommended that the Interrupt 24H routine fail critical errors and
  2028.    let the application test for an extended error code when the Interrupt
  2029.    21H routine returns.
  2030.  
  2031.    User Stack
  2032.  
  2033.    This call uses the user stack that contains the following (starting with
  2034.    the top of the stack):
  2035.  
  2036.    IP     MS-DOS registers from issuing Interrupt 24H
  2037.    CS
  2038.    FLAGS
  2039.  
  2040.    AX     User registers at time of original
  2041.    BX     INT 21H
  2042.    CX
  2043.    DX
  2044.    SI
  2045.    DI
  2046.    BP
  2047.    DS
  2048.    ES
  2049.  
  2050.    IP     From the original INT 21H
  2051.    CS     from the user to MS-DOS
  2052.    FLAGS
  2053.  
  2054.    The registers are set such that if the user-written error handler issues
  2055.    an IRET, MS-DOS responds according to the value in AL:
  2056.  
  2057.    AL                 Action
  2058.    ──────────────────────────────────────────────────────────────────────────
  2059.    0                  Ignore the error.
  2060.    1                  Retry the operation.
  2061.    2                  Abort the program by issuing Interrupt 23H.
  2062.    3                  Fail the system call that is in progress.
  2063.    ──────────────────────────────────────────────────────────────────────────
  2064.  
  2065.    Notice that the ignore option may cause unexpected results, such as
  2066.    causing MS-DOS to behave as if an operation had completed successfully.
  2067.  
  2068.    Disk Error Code in AX
  2069.  
  2070.    If bit 7 of AH is 0, the error occurred on a disk drive. AL contains the
  2071.    failing drive (0=A, 1=B, etc.). Bit 0 of AH specifies whether the error
  2072.    occurred during a read or write operation (0=read, 1=write), and bits 1
  2073.    and 2 of AH identify the area of the disk where the error occurred:
  2074.  
  2075.    Bits 1-2                             Location of error
  2076.    ──────────────────────────────────────────────────────────────────────────
  2077.    00                                   MS-DOS area
  2078.    01                                   File Allocation Table
  2079.    10                                   Directory
  2080.    11                                   Data area
  2081.    ──────────────────────────────────────────────────────────────────────────
  2082.  
  2083.    Bits 3-5 of AH specify valid responses to the error prompt:
  2084.  
  2085.    Bit        Value                Response
  2086.    ──────────────────────────────────────────────────────────────────────────
  2087.    3          0                    Fail not allowed
  2088.               1                    Fail allowed
  2089.    4          0                    Retry not allowed
  2090.               1                    Retry allowed
  2091.    5          0                    Ignore not allowed
  2092.               1                    Ignore allowed
  2093.    ──────────────────────────────────────────────────────────────────────────
  2094.  
  2095.    If you specify Retry but it isn't allowed, MS-DOS changes it to Fail. If
  2096.    you specify Ignore but it isn't allowed, MS-DOS changes it to Fail. If you
  2097.    specify Fail but it isn't allowed, MS-DOS changes it to Abort. The Abort
  2098.    response is always allowed.
  2099.  
  2100.    Other Device Error Code in AX
  2101.  
  2102.    If bit 7 of AH is 1, either the memory image of the File Allocation Table
  2103.    (FAT) is bad or an error occurred on a character device. The device header
  2104.    pointed to by BP:SI contains a WORD of attribute bits that identify the
  2105.    type of device and, therefore, the type of error.
  2106.  
  2107.    The word of attribute bits is at offset 04H of the Device Header. Bit 15
  2108.    specifies the type of device (0=block, 1=character).
  2109.  
  2110.    If bit 15 is 0 (block device), the error was a bad memory image of the
  2111.    FAT.
  2112.  
  2113.    If bit 15 is 1 (character device), the error was on a character device. DI
  2114.    contains the error code, the contents of AL are undefined, and bits 0-3 of
  2115.    the attribute word have the following meaning:
  2116.  
  2117.    Bit                Meaning if Set
  2118.    ──────────────────────────────────────────────────────────────────────────
  2119.    0                  Current standard input
  2120.    1                  Current standard output
  2121.    2                  Current null device
  2122.    3                  Current clock device
  2123.    ──────────────────────────────────────────────────────────────────────────
  2124.  
  2125.    See Chapter 2, "MS-DOS Device Drivers," for a complete description of the
  2126.    Device Header control block.
  2127.  
  2128.    Error Code in DI
  2129.  
  2130.    The high byte of DI is undefined. The low byte contains the following
  2131.    error codes:
  2132.  
  2133.    Error code         Description
  2134.    ──────────────────────────────────────────────────────────────────────────
  2135.    0                  Attempt to write on write-protected disk
  2136.    1                  Unknown unit
  2137.    2                  Drive not ready
  2138.    3                  Unknown command
  2139.    4                  CRC error in data
  2140.    5                  Bad drive request structure length
  2141.    6                  Seek error
  2142.    7                  Unknown media type
  2143.    8                  Sector not found
  2144.    9                  Printer out of paper
  2145.    A                  Write fault
  2146.    B                  Read fault
  2147.    C                  General failure
  2148.    ──────────────────────────────────────────────────────────────────────────
  2149.  
  2150.    A user-written Interrupt 24H handler can use Function 59H (Get Extended
  2151.    Error) to get detailed information about the error that caused the
  2152.    interrupt to be issued.
  2153.  
  2154.  
  2155.  ────────────────────────────────────────────────────────────────────────────
  2156.  Absolute Disk Read (Interrupt 25H)
  2157.  ────────────────────────────────────────────────────────────────────────────
  2158.  
  2159.    Call:
  2160.  
  2161.    AL
  2162.      Drive number
  2163.    DS:BX
  2164.      Disk Transfer Address or
  2165.      Far pointer to parameter packet if CX = -1
  2166.    CX
  2167.      Number of sectors or -1
  2168.    DX
  2169.      Beginning relative sector
  2170.  
  2171.    Return:
  2172.  
  2173.    AL
  2174.      Error code if CF=1
  2175.    FLAGS
  2176.      CF        = 0 if successful
  2177.            = 1 if not successful
  2178.      AX
  2179.       0207 if attempt made to access partition larger
  2180.       than 32 megabytes with MS-DOS 3.3 or earlier.
  2181.  
  2182.  
  2183.    Comments:
  2184.  
  2185.    The registers must contain the following:
  2186.  
  2187.    Register           Contents
  2188.    ──────────────────────────────────────────────────────────────────────────
  2189.    AL                 Drive number (0=A, 1=B, etc.)
  2190.  
  2191.    DS:BX              Offset of Disk Transfer Address or far pointer to
  2192.                       parameter packet if CX = -1
  2193.  
  2194.    CX                 Number of sectors to read or -1
  2195.  
  2196.    DX                 Beginning relative sector
  2197.    ──────────────────────────────────────────────────────────────────────────
  2198.  
  2199.    ──────────────────────────────────────────────────────────────────────────
  2200.    Warning
  2201.      Avoid using this function unless absolutely necessary. Instead, you
  2202.      should access files through normal MS-DOS function requests. There is no
  2203.      guarantee of upward compatibility for the Absolute Disk I/O in future
  2204.      releases of MS-DOS.
  2205.    ──────────────────────────────────────────────────────────────────────────
  2206.  
  2207.    If CX = -1, DS:BX is the far pointer to the parameter packet. The
  2208.    parameter packet API provides access to partitions larger than 32
  2209.    megabytes. The parameter packet contains:
  2210.  
  2211.            Starting sector number  dd        ?
  2212.            Number of sectors       dw        ?
  2213.            Transfer address        dd        ?
  2214.  
  2215.  
  2216.    Interrupt 25H transfers control to the device driver and reads from the
  2217.    disk to the Disk-Transfer Address the number of sectors specified in CX.
  2218.    The interrupt has the same requirements as and processes identically to
  2219.    Interrupt 26H (Absolute Disk Write), except that it reads data rather
  2220.    than writes it. Also, since this interrupt does not check your input
  2221.    parameters too closely, make sure they are reasonable. If you use
  2222.    unreasonable parameters, you may get strange results or cause your system
  2223.    to crash.
  2224.  
  2225.    ──────────────────────────────────────────────────────────────────────────
  2226.    Note
  2227.      This call destroys all registers except the segment registers. So before
  2228.      issuing the interrupt, save any registers that your program uses.
  2229.    ──────────────────────────────────────────────────────────────────────────
  2230.  
  2231.    The system pushes the flags at the time of the call; they are still there
  2232.    upon return. To prevent uncontrolled growth, be sure to pop the stack upon
  2233.    return.
  2234.  
  2235.    If the disk operation is successful, the Carry Flag (CF) is 0. If the disk
  2236.    operation is not successful, CF is 1 and AL contains the MS-DOS error code
  2237.    (see Interrupt 24H earlier in this section for the codes and their
  2238.    meanings).
  2239.  
  2240.    Macro Definition:
  2241.  
  2242.    abs_disk_read  macro  disk,buffer,num_sectors,first_sector
  2243.                   mov    al,disk
  2244.                   mov    bx,offset buffer
  2245.                   mov    cx,num_sectors
  2246.                   mov    dx,first_sector
  2247.                   int    25H
  2248.                   popf
  2249.                   endm
  2250.  
  2251.    Example:
  2252.  
  2253.    The following program copies the contents of a single-sided disk in drive
  2254.    A to the disk in drive B.
  2255.  
  2256.    prompt     db   "Source in A, target in B",0DH,0AH
  2257.               db   "Any key to start. $"
  2258.    first      dw    0
  2259.    buffer     db    60 dup (512 dup (?))  ; 60 sectors
  2260.    ;
  2261.    begin:     display prompt         ; see Function 09H
  2262.               read_kbd               ; see Function 08H
  2263.               mov     cx,6           ; copy 6 groups of
  2264.                                        ; 60 sectors
  2265.    copy:      push    cx             ; save the loop counter
  2266.               abs_disk_read  0,buffer,60,first  ; THIS INTERRUPT
  2267.               abs_disk_write 1,buffer,60,first  ; see INT 26H
  2268.               add  first,60          ; do the next 60 sectors
  2269.               pop  cx                ; restore the loop counter
  2270.               loop copy
  2271.  
  2272.    The following code is an example of reading the absolute sector with
  2273.    Interrupt 25H.
  2274.  
  2275.              mov  al, 'C'-'A'       ; select drive C:
  2276.              mov  cx,-1             ; request new absolute format
  2277.              mov  bx,code            ; set ds:bx up to point to parameter
  2278.              mov  ds,bx              ; packet with sector number, length
  2279.              mov  bx,offset par_pck  ; and transfer address information
  2280.              int  25H                ; do operation
  2281.              jc   error_on_read      ; check for errors
  2282.  
  2283.    par_pck:
  2284.              dd   12345H             ; absolute sector number to read=12345H
  2285.              dw   2                  ; number of sectors to read
  2286.              dd   buffer             ; transfer address
  2287.  
  2288.    buffer    db   1024 dup (0)       ; target buffer for read
  2289.  
  2290.  
  2291.  ────────────────────────────────────────────────────────────────────────────
  2292.  Absolute Disk Write (Interrupt 26H)
  2293.  ────────────────────────────────────────────────────────────────────────────
  2294.  
  2295.    Call:
  2296.  
  2297.    AL
  2298.      Drive number
  2299.    DS:BX
  2300.      Disk Transfer Address or
  2301.      Far pointer to parameter packet if CX = -1
  2302.    CX
  2303.      Number of sectors or -1
  2304.    DX
  2305.      Beginning relative sector
  2306.  
  2307.    Return:
  2308.  
  2309.    AL
  2310.      Error code if CF = 1
  2311.    FLAGS
  2312.      CF        = 0 if successful
  2313.            = 1 if not successful
  2314.  
  2315.  
  2316.    Comments:
  2317.  
  2318.    ──────────────────────────────────────────────────────────────────────────
  2319.    Warning
  2320.      Avoid using this function unless absolutely necessary. Instead, you
  2321.      should access files through normal MS-DOS function requests. There is no
  2322.      guarantee of upward compatibility for the Absolute Disk I/O in future
  2323.      releases of MS-DOS.
  2324.    ──────────────────────────────────────────────────────────────────────────
  2325.  
  2326.    The registers must contain the following:
  2327.  
  2328.    Register           Contents
  2329.    ──────────────────────────────────────────────────────────────────────────
  2330.    AL                 Drive number (0=A, 1=B, etc.)
  2331.  
  2332.    DS:BX              Offset of Disk Transfer Address or far pointer to
  2333.                       parameter packet if CX = -1
  2334.  
  2335.    CX                 Number of sectors to write or -1
  2336.  
  2337.    DX                 Beginning relative sector
  2338.    ──────────────────────────────────────────────────────────────────────────
  2339.  
  2340.    This interrupt transfers control to MS-DOS. The number of sectors
  2341.    specified in CX is written from the Disk Transfer Address to the disk. Its
  2342.    requirements and processing are identical to Interrupt 25H (Absolute Disk
  2343.    Read), except data is written to the disk rather than read from it. Also,
  2344.    since Interrupt 26H does not check your input parameters too closely, make
  2345.    sure they are reasonable. If you use unreasonable parameters, you may get
  2346.    strange results or cause your system to crash.
  2347.  
  2348.    If CX = -1, DS:BX is the far pointer to the parameter packet. The
  2349.    parameter packet contains:
  2350.  
  2351.            Starting sector number        dd        ?
  2352.            Number of sectors        dw        ?
  2353.            Transfer address        dd        ?
  2354.  
  2355.  
  2356.    ──────────────────────────────────────────────────────────────────────────
  2357.    Note
  2358.      This call destroys all registers except the segment registers. So before
  2359.      issuing the interrupt, be sure to save any registers your program uses.
  2360.    ──────────────────────────────────────────────────────────────────────────
  2361.  
  2362.    The system pushes the flags at the time of the call; they are still there
  2363.    upon return. To prevent uncontrolled growth, be sure to pop the stack upon
  2364.    return.
  2365.  
  2366.    If the disk operation is successful, the Carry Flag (CF) is 0. If the disk
  2367.    operation is not successful, CF is 1 and AL contains the MS-DOS error code
  2368.    (see Interrupt 24H for the codes and their meanings).
  2369.  
  2370.    Macro Definition:
  2371.  
  2372.    abs_disk_write  macro  disk,buffer,num_sectors,first_sector
  2373.                    mov    al,disk
  2374.                    mov    bx,offset buffer
  2375.                    mov    cx,num_sectors
  2376.                    mov    dx,first_sector
  2377.                    int    26H
  2378.                    popf
  2379.                    endm
  2380.  
  2381.    Example:
  2382.  
  2383.    The following program copies the contents of a single-sided disk in drive
  2384.    A to the disk in drive B, verifying each write. It uses a buffer of 32
  2385.    kilobytes.
  2386.  
  2387.    off        equ   0
  2388.    on         equ   1
  2389.    ;
  2390.    prompt     db   "Source in A, target in B",0DH,0AH
  2391.               db   "Any key to start. $"
  2392.    first      dw    0
  2393.    buffer     db    60 dup (512 dup (?))  ; 60 sectors
  2394.    ;
  2395.    begin:     display prompt       ; see Function 09H
  2396.               read_kbd             ; see Function 08H
  2397.               verify  on           ; see Function 2EH
  2398.               mov     cx,6         ; copy 6 groups of 60 sectors
  2399.    copy:      push    cx           ; save the loop counter
  2400.               abs_disk_read  0,buffer,60,first  ; see INT 25H
  2401.               abs_disk_write 1,buffer,60,first  ; THIS INTERRUPT
  2402.               add  first,60        ; do the next 60 sectors
  2403.               pop  cx              ; restore the loop counter
  2404.               loop copy
  2405.               verify  off          ; see Function 2EH
  2406.  
  2407.    The following code is an example of writing the absolute sector with
  2408.    Interrupt 26H.
  2409.  
  2410.             mov   al,'C'-'A'        ; select drive C:
  2411.             mov   cx,-1             ; request new absolute format
  2412.             mov   bx,code            ; set ds:bx up to point to parameter
  2413.             mov   ds,bx              ; packet with sector number, length
  2414.             mov   bx,offset par_pck  ; and transfer address information
  2415.             int   26H                ; do operation
  2416.             jc    error_on_write     ; check for errors
  2417.  
  2418.    par_pck:
  2419.            dd     12345H             ; absolute sector number to write=12345H
  2420.            dw     2                  ; number of sectors to write
  2421.            dd     buffer             ; transfer address
  2422.  
  2423.    buffer  db     1024 dup (0)       ; target buffer for write
  2424.  
  2425.  
  2426.  ────────────────────────────────────────────────────────────────────────────
  2427.  Terminate But Stay Resident (Interrupt 27H)
  2428.  ────────────────────────────────────────────────────────────────────────────
  2429.  
  2430.    Call:
  2431.  
  2432.    CS:DX
  2433.      Pointer to first byte following
  2434.      last byte of code.
  2435.  
  2436.    Return:
  2437.  
  2438.    None
  2439.  
  2440.  
  2441.    Comments:
  2442.  
  2443.    This interrupt is provided only for compatibility with MS-DOS versions
  2444.    prior to 2.0. Unless your resident program must be compatible with MS-DOS
  2445.    versions before 2.0, you should use Function 31H (Keep Process) to
  2446.    install it. Function 31H lets programs larger than 64K remain resident
  2447.    and allows return information to be passed.
  2448.  
  2449.    However, Interrupt 27H, which is often used to install device-specific
  2450.    interrupt handlers, forces programs that are up to 64K to remain resident
  2451.    after they terminate.
  2452.  
  2453.    DX must contain the offset (from the segment address in CS) of the first
  2454.    byte that follows the last byte of code in the program. When Interrupt 27H
  2455.    is executed, the program terminates and control returns to MS-DOS, but the
  2456.    program is not overlaid by other programs. Files left open are not closed.
  2457.    When the interrupt is called, CS must contain the segment address of the
  2458.    Program Segment Prefix (the value of DS and ES when execution started).
  2459.    .Exe programs that are loaded into high memory must not use this
  2460.    interrupt. Similarly, since it restores the Interrupt 22H, 23H, and
  2461.    24H vectors, you should not use Interrupt 27H to install new CONTROL+C or
  2462.    critical-error handlers.
  2463.  
  2464.    Macro Definition:
  2465.  
  2466.    stay_resident  macro last_instruc
  2467.                   mov   dx,offset last_instruc
  2468.                   inc   dx
  2469.                   int   27H
  2470.                   endm
  2471.  
  2472.    Example:
  2473.  
  2474.    Since the most common use of Interrupt 27H is to install a
  2475.    machine-specific routine, there is no general example that applies. The
  2476.    macro definition, however, shows the calling syntax.
  2477.  
  2478.  
  2479.  1.12  Function Requests
  2480.  
  2481.    The following pages describe function calls 00H-68H.
  2482.  
  2483.  
  2484.  ────────────────────────────────────────────────────────────────────────────
  2485.  Terminate Program (Function 00H)
  2486.  ────────────────────────────────────────────────────────────────────────────
  2487.  
  2488.    Call:
  2489.  
  2490.    AH = 00H
  2491.    CS
  2492.      Segment address of
  2493.      Program Segment Prefix
  2494.  
  2495.    Return:
  2496.  
  2497.    None
  2498.  
  2499.  
  2500.    Comments:
  2501.  
  2502.    Function 00H performs the same function as Interrupt 20H. It terminates
  2503.    the current process and returns control to its parent process. It also
  2504.    closes all open file handles and clears the disk cache. When this
  2505.    interrupt is issued, CS must contain the segment address of the Program
  2506.    Segment Prefix.
  2507.  
  2508.    The CS register must contain the segment address of the Program Segment
  2509.    Prefix before you call this interrupt.
  2510.  
  2511.    The following exit addresses are restored from the specified offsets in
  2512.    the Program Segment Prefix:
  2513.  
  2514.    Offset             Exit Address
  2515.    ──────────────────────────────────────────────────────────────────────────
  2516.    0AH                Program terminate
  2517.    0EH                CONTROL+C
  2518.    12H                Critical error
  2519.    ──────────────────────────────────────────────────────────────────────────
  2520.  
  2521.    All file buffers are flushed to disk.
  2522.  
  2523.    ──────────────────────────────────────────────────────────────────────────
  2524.    Warning
  2525.      Close all files that have changed in length before calling this
  2526.      function. If you do not close a changed file, its length is not
  2527.      correctly recorded in the directory. See Function 10H for a description
  2528.      of the Close File system call.
  2529.    ──────────────────────────────────────────────────────────────────────────
  2530.  
  2531.    Macro Definition:
  2532.  
  2533.    terminate_program  macro
  2534.                       xor    ah,ah
  2535.                       int    21H
  2536.                       endm
  2537.  
  2538.    Example:
  2539.  
  2540.    The following program displays a message and returns to MS-DOS. It uses
  2541.    only the opening portion of the sample program skeleton shown in Figure
  2542.    1.2.
  2543.  
  2544.    message db "Displayed by FUNC00H example", 0DH,0AH,"$"
  2545.    ;
  2546.    begin:  display message    ; see Function 09H
  2547.            terminate_program  ; THIS FUNCTION
  2548.    code    ends
  2549.            end    start
  2550.  
  2551.  
  2552.  ────────────────────────────────────────────────────────────────────────────
  2553.  Read Keyboard and Echo (Function 01H)
  2554.  ────────────────────────────────────────────────────────────────────────────
  2555.  
  2556.    Call:
  2557.  
  2558.    AH = 01H
  2559.  
  2560.    Return:
  2561.  
  2562.    AL
  2563.      Character typed
  2564.  
  2565.  
  2566.    Comments:
  2567.  
  2568.    Function 01H waits for a character to be read from standard input, then
  2569.    echoes the character to standard output and returns it in AL. If the
  2570.    character is CONTROL+C, it executes Interrupt 23H.
  2571.  
  2572.    Macro Definition:
  2573.  
  2574.    read_kbd_and_echo  macro
  2575.                       mov  ah, 01H
  2576.                       int  21H
  2577.                       endm
  2578.  
  2579.    Example:
  2580.  
  2581.    The following program displays and prints characters as you type them. If
  2582.    you press the ENTER key, the program sends a linefeed/carriage-return
  2583.    sequence to both the display and the printer.
  2584.  
  2585.    begin:     read_kbd_and_echo         ; THIS FUNCTION
  2586.               print_char   al           ; see Function 05H
  2587.               cmp          al,0DH       ; is it a CR?
  2588.               jne          begin        ; no, print it
  2589.               print_char   0AH          ; see Function 05H
  2590.               display_char 0AH          ; see Function 02H
  2591.               jmp          begin        ; get another character
  2592.  
  2593.  
  2594.  ────────────────────────────────────────────────────────────────────────────
  2595.  Display Character (Function 02H)
  2596.  ────────────────────────────────────────────────────────────────────────────
  2597.  
  2598.    Call:
  2599.  
  2600.    AH = 02H
  2601.    DL
  2602.      Character to be displayed
  2603.  
  2604.    Return:
  2605.  
  2606.    None
  2607.  
  2608.  
  2609.    Comments:
  2610.  
  2611.    Function 02H sends the character in DL to standard output. If you press
  2612.    CONTROL+C, it issues Interrupt 23H.
  2613.  
  2614.    Macro Definition:
  2615.  
  2616.    display_char macro   character
  2617.                 mov     dl,character
  2618.                 mov     ah,02H
  2619.                 int     21H
  2620.                 endm
  2621.  
  2622.    Example:
  2623.  
  2624.    The following program converts lowercase characters to uppercase before
  2625.    displaying them.
  2626.  
  2627.    begin:     read_kbd                 ; see Function 08H
  2628.               cmp     al,"a"
  2629.               jl      uppercase        ; don't convert
  2630.               cmp     al,"z"
  2631.               jg      uppercase        ; don't convert
  2632.               sub     al,20H           ; convert to ASCII code
  2633.                                        ; for uppercase
  2634.    uppercase: display_char al          ; THIS FUNCTION
  2635.               jmp     begin:           ; get another character
  2636.  
  2637.  
  2638.  ────────────────────────────────────────────────────────────────────────────
  2639.  Auxiliary Input (Function 03H)
  2640.  ────────────────────────────────────────────────────────────────────────────
  2641.  
  2642.    Call:
  2643.  
  2644.    AH = 03H
  2645.  
  2646.    Return:
  2647.  
  2648.    AL
  2649.      Character from auxiliary device
  2650.  
  2651.  
  2652.    Comments:
  2653.  
  2654.    Function 03H waits for a character from standard auxiliary devices (AUX,
  2655.    COM1, COM2, COM3, COM4), then returns the character in AL. This system
  2656.    call does not return a status or error code.
  2657.  
  2658.    If you press CONTROL+C, it issues Interrupt 23H.
  2659.  
  2660.    Macro Definition:
  2661.  
  2662.    aux_input  macro
  2663.               mov  ah,03H
  2664.               int  21H
  2665.               endm
  2666.  
  2667.    Example:
  2668.  
  2669.    The following program prints characters as soon as it receives them from
  2670.    the auxiliary device. It stops printing when it receives an end-of-file
  2671.    character (ASCII 26, or CONTROL+Z).
  2672.  
  2673.    begin:     aux_input        ; THIS FUNCTION
  2674.               cmp   al,1AH     ; end of file?
  2675.               je    return     ; yes, all done
  2676.               print_char  al   ; see Function 05H
  2677.               jmp   begin      ; get another character
  2678.  
  2679.  
  2680.  ────────────────────────────────────────────────────────────────────────────
  2681.  Auxiliary Output (Function 04H)
  2682.  ────────────────────────────────────────────────────────────────────────────
  2683.  
  2684.    Call:
  2685.  
  2686.    AH = 04H
  2687.    DL
  2688.      Character for auxiliary device
  2689.  
  2690.    Return:
  2691.  
  2692.    None
  2693.  
  2694.  
  2695.    Comments:
  2696.  
  2697.    Function 04H sends the character in DL to standard auxiliary. This system
  2698.    call does not return a status or error code.
  2699.  
  2700.    If you press CONTROL+C, it issues Interrupt 23H.
  2701.  
  2702.    Macro Definition:
  2703.  
  2704.    aux_output  macro  character
  2705.                mov  dl,character
  2706.                mov  ah,04H
  2707.                int  21H
  2708.                endm
  2709.  
  2710.    Example:
  2711.  
  2712.    The following program gets a series of strings of up to 80 bytes from the
  2713.    keyboard and sends each string to the auxiliary device. It stops when you
  2714.    type a null string (carriage-return only).
  2715.  
  2716.    string   db    81 dup(?) ; see Function 0AH
  2717.    ;
  2718.    begin:   get_string  80,string       ; see Function 0AH
  2719.             cmp  string[1],0            ; null string?
  2720.             je   return                 ; yes, all done
  2721.             mov  cx, word ptr string[1] ; get string length
  2722.             mov  bx,0                   ; set index to 0
  2723.    send_it: aux_output string[bx+2]     ; THIS FUNCTION
  2724.             inc  bx                     ; bump index
  2725.             loop  send_it               ; send another character
  2726.             jmp  begin                  ; get another string
  2727.  
  2728.  
  2729.  ────────────────────────────────────────────────────────────────────────────
  2730.  Print Character (Function 05H)
  2731.  ────────────────────────────────────────────────────────────────────────────
  2732.  
  2733.    Call:
  2734.  
  2735.    AH = 05H
  2736.    DL
  2737.      Character for printer
  2738.  
  2739.    Return:
  2740.  
  2741.    None
  2742.  
  2743.  
  2744.    Comments:
  2745.  
  2746.    Function 05H sends the character in DL to the standard printer. If you
  2747.    press CONTROL+C, it issues Interrupt 23H. This function does not return a
  2748.    status or error code.
  2749.  
  2750.    Macro Definition:
  2751.  
  2752.    print_char macro character
  2753.               mov   dl,character
  2754.               mov   ah,05H
  2755.               int   21H
  2756.               endm
  2757.  
  2758.    Example:
  2759.  
  2760.    The following program prints a walking test pattern on the printer. It
  2761.    stops if you press CONTROL+C.
  2762.  
  2763.    line_num    db    0
  2764.    ;
  2765.    begin:      mov   cx,60        ; print 60 lines
  2766.    start_line: mov   bl,33        ; first printable ASCII
  2767.                                   ; character (!)
  2768.                add   bl,line_num  ; to offset one character
  2769.                push  cx           ; save number-of-lines counter
  2770.                mov   cx,80        ; loop counter for line
  2771.    print_it:   print_char bl      ; THIS FUNCTION
  2772.                inc   bl           ; move to next ASCII character
  2773.                cmp   bl,126       ; last printable ASCII
  2774.                                   ; character (~)
  2775.                jl    no_reset     ; not there yet
  2776.                mov   bl,33        ; start over with (!)
  2777.    no_reset:   loop  print_it     ; print another character
  2778.                print_char 0DH     ; carriage return
  2779.                print_char 0AH     ; linefeed
  2780.                inc   line_num     ; to offset 1st char. of line
  2781.                pop   cx           ; restore #-of-lines counter
  2782.                loop  start_line   ; print another line
  2783.  
  2784.  
  2785.  ────────────────────────────────────────────────────────────────────────────
  2786.  Direct Console I/O (Function 06H)
  2787.  ────────────────────────────────────────────────────────────────────────────
  2788.  
  2789.    Call:
  2790.  
  2791.    AH = 06H
  2792.    DL
  2793.      See text
  2794.  
  2795.    Return:
  2796.  
  2797.    AL
  2798.      If DL = FFH  before call,
  2799.      then zero flag not set means AL
  2800.      has character from standard input.
  2801.      Zero flag set means there was not
  2802.      a character to get, and AL = 0.
  2803.  
  2804.  
  2805.    Comments:
  2806.  
  2807.    The action of Function 06H depends on the value in DL when the function is
  2808.    called:
  2809.  
  2810.    Value in DL        Action
  2811.    ──────────────────────────────────────────────────────────────────────────
  2812.    FFH                If a character has been read from standard input, it is
  2813.                       returned in AL and the zero flag is cleared (0); if a
  2814.                       character has not been read, the zero flag is set (1).
  2815.  
  2816.    Not FFH            The character in DL is sent to standard output.
  2817.    ──────────────────────────────────────────────────────────────────────────
  2818.  
  2819.    This function does not check for CONTROL+C.
  2820.  
  2821.    Macro Definition:
  2822.  
  2823.    dir_console_io  macro switch
  2824.                    mov  dl,switch
  2825.                    mov  ah,06H
  2826.                    int  21H
  2827.                    endm
  2828.  
  2829.    Example:
  2830.  
  2831.    The following program sets the system clock to 0 and displays the time
  2832.    continuously. When you type any character, the display freezes; when you
  2833.    type any character again, the clock is reset to 0 and the display starts
  2834.    again.
  2835.  
  2836.    time      db  "00:00:00.00",0DH,0AH,"$"  ; see Function 09H
  2837.    ;                                      ; for explanation of $
  2838.    ;
  2839.    begin:        set_time  0,0,0,0       ; see Function 2DH
  2840.    read_clock:   get_time                ; see Function 2CH
  2841.                  CONVERT  ch,time        ; see end of chapter
  2842.                  CONVERT  cl,time[3]     ; see end of chapter
  2843.                  CONVERT  dh,time[6]     ; see end of chapter
  2844.                  CONVERT  dl,time[9]     ; see end of chapter
  2845.                  display  time           ; see Function 09H
  2846.                  dir_console_io  FFH     ; THIS FUNCTION
  2847.                  cmp      al,0           ; character typed?
  2848.                  jne      stop           ; yes, stop timer
  2849.                  jmp      read_clock     ; no, keep timer
  2850.                                          ; running
  2851.    stop:         read_kbd                ; see Function 08H
  2852.                  jmp      begin          ; start over
  2853.  
  2854.  
  2855.  ────────────────────────────────────────────────────────────────────────────
  2856.  Direct Console Input (Function 07H)
  2857.  ────────────────────────────────────────────────────────────────────────────
  2858.  
  2859.    Call:
  2860.  
  2861.    AH = 07H
  2862.  
  2863.    Return:
  2864.  
  2865.    AL
  2866.      Character from keyboard
  2867.  
  2868.  
  2869.    Comments:
  2870.  
  2871.    Function 07H waits for a character to be read from standard input, then
  2872.    returns it in AL. This function does not echo the character or check for
  2873.    CONTROL+C. (For a keyboard input function that echoes or checks for
  2874.    CONTROL+C, see Function 01H or 08H.)
  2875.  
  2876.    Macro Definition:
  2877.  
  2878.    dir_console_input  macro
  2879.                       mov  ah,07H
  2880.                       int  21H
  2881.                       endm
  2882.  
  2883.    Example:
  2884.  
  2885.    The following program prompts for a password (eight characters maximum)
  2886.    and places the characters into a string without echoing them.
  2887.  
  2888.    password  db  8 dup(?)
  2889.    prompt    db "Password: $"       ; see Function 09H for
  2890.                                     ; explanation of $
  2891.    begin:    display prompt         ; see Function 09H
  2892.              mov  cx,8              ; maximum length of password
  2893.              xor  bx,bx             ; so BL can be used as index
  2894.    get_pass: dir_console_input      ; THIS FUNCTION
  2895.              cmp  al,0DH            ; was it a carriage return?
  2896.              je   return            ; yes, all done
  2897.              mov  password[bx],al   ; no, put character in string
  2898.              inc  bx                ; bump index
  2899.              loop get_pass          ; get another character
  2900.  
  2901.  
  2902.  ────────────────────────────────────────────────────────────────────────────
  2903.  Read Keyboard (Function 08H)
  2904.  ────────────────────────────────────────────────────────────────────────────
  2905.  
  2906.    Call:
  2907.  
  2908.    AH = 08H
  2909.  
  2910.    Return:
  2911.  
  2912.    AL
  2913.      Character from keyboard
  2914.  
  2915.  
  2916.    Comments:
  2917.  
  2918.    Function 08H waits for a character to be read from standard input, then
  2919.    returns it in AL. If you press CONTROL+C, it issues Interrupt 23H. This
  2920.    function does not echo the character. (For a keyboard input function that
  2921.    echoes the character or checks for CONTROL+C, see Function 01H.)
  2922.  
  2923.    Macro Definition:
  2924.  
  2925.    read_kbd  macro
  2926.              mov   ah,08H
  2927.              int   21H
  2928.              endm
  2929.  
  2930.    Example:
  2931.  
  2932.    The following program prompts for a password (eight characters maximum)
  2933.    and places the characters into a string without echoing them.
  2934.  
  2935.    password  db  8 dup(?)
  2936.    prompt    db "Password: $"      ; see Function 09H
  2937.                                    ; for explanation of $
  2938.    begin:    display prompt        ; see Function 09H
  2939.              mov  cx,8             ; maximum length of password
  2940.              xor  bx,bx            ; BL can be an index
  2941.    get_pass: read_kbd              ; THIS FUNCTION
  2942.              cmp  al,0DH           ; was it a carriage return?
  2943.              je   return           ; yes, all done
  2944.              mov  password[bx],al  ; no, put char. in string
  2945.              inc  bx               ; bump index
  2946.              loop get_pass         ; get another character
  2947.  
  2948.  
  2949.  ────────────────────────────────────────────────────────────────────────────
  2950.  Display String (Function 09H)
  2951.  ────────────────────────────────────────────────────────────────────────────
  2952.  
  2953.    Call:
  2954.  
  2955.    AH = 09H
  2956.    DS:DX
  2957.      Pointer to string to be displayed
  2958.  
  2959.    Return:
  2960.  
  2961.    None
  2962.  
  2963.  
  2964.    Comments:
  2965.  
  2966.    Function 09H sends to standard output a string that ends with "$" (the $
  2967.    is not displayed).
  2968.  
  2969.    The DX register must contain the offset (from the segment address in DS)
  2970.    of the string.
  2971.  
  2972.    Macro Definition:
  2973.  
  2974.    display  macro string
  2975.             mov   dx,offset string
  2976.             mov   ah,09H
  2977.             int   21H
  2978.             endm
  2979.  
  2980.    Example:
  2981.  
  2982.    The following program displays the hexadecimal code of the key that is
  2983.    typed.
  2984.  
  2985.    table    db     "0123456789ABCDEF"
  2986.    result   db     " - 00H",0DH,0AH,"$"  ; see text for
  2987.                                          ; explanation of $
  2988.    begin:   read_kbd_and_echo            ; see Function 01H
  2989.             xor     ah,ah                ; clear upper byte
  2990.             convert ax,16,result[3] ; see end of chapter
  2991.             display result               ; THIS FUNCTION
  2992.             jmp     begin                ; do it again
  2993.  
  2994.  
  2995.  ────────────────────────────────────────────────────────────────────────────
  2996.  Buffered Keyboard Input (Function 0AH)
  2997.  ────────────────────────────────────────────────────────────────────────────
  2998.  
  2999.    Call:
  3000.  
  3001.    AH = 0AH
  3002.    DS:DX
  3003.      Pointer to input buffer
  3004.  
  3005.    Return:
  3006.  
  3007.    None
  3008.  
  3009.  
  3010.    Comments:
  3011.  
  3012.    Function 0AH gets a string from standard input. DX must contain the offset
  3013.    (from the segment address in DS) of an input buffer of the following form:
  3014.  
  3015.    Byte               Contents
  3016.    ──────────────────────────────────────────────────────────────────────────
  3017.    1                  Maximum number of characters in buffer, including the
  3018.                       carriage return (you must set this value).
  3019.  
  3020.    2                  Actual number of characters typed, not counting the
  3021.                       carriage return (the function sets this value).
  3022.  
  3023.    3-n                Buffer; must be at least as long as the number in byte
  3024.    ──────────────────────────────────────────────────────────────────────────
  3025.  
  3026.    Characters are read from standard input and placed in the buffer beginning
  3027.    at the third byte until an ENTER character (ASCII 0DH) is read. If the
  3028.    buffer fills to one less than the maximum, additional characters read are
  3029.    ignored and ASCII 07H (Bel) is sent to standard output until an ENTER
  3030.    character is read. If you type the string at the console, it can be edited
  3031.    as it is being entered. If you press CONTROL+C, it issues Interrupt 23H.
  3032.  
  3033.    MS-DOS sets the second byte of the buffer to the number of characters read
  3034.    (not counting the carriage return).
  3035.  
  3036.    Macro Definition:
  3037.  
  3038.    get_string  macro  limit,string
  3039.                mov    dx,offset string
  3040.                mov    string,limit
  3041.                mov    ah,0AH
  3042.                int    21H
  3043.                endm
  3044.  
  3045.    Example:
  3046.  
  3047.    The following program gets a 16-byte (maximum) string from the keyboard
  3048.    and fills a 24-line by 80-character screen with it.
  3049.  
  3050.    buffer           label byte
  3051.    max_length       db    ?                ; maximum length
  3052.    chars_entered    db    ?                ; number of chars.
  3053.    string           db    17 dup (?)       ; 16 chars + CR
  3054.    strings_per_line dw    0                ; how many strings
  3055.                                            ; fit on line
  3056.    crlf             db    0DH,0AH
  3057.    ;
  3058.    begin:           get_string 17,buffer   ; THIS FUNCTION
  3059.                     xor  bx,bx             ; so byte can be
  3060.                                            ; used as index
  3061.                     mov  bl,chars_entered  ; get string length
  3062.                     mov  buffer[bx+2],"$"  ; see Function 09H
  3063.                     mov  al,50H            ; columns per line
  3064.                     cbw
  3065.                     div  chars_entered     ; times string fits
  3066.                                            ; on line
  3067.                     xor  ah,ah             ; clear remainder
  3068.                     mov  strings_per_line,ax ; save col. counter
  3069.                     mov  cx,24             ; row counter
  3070.    display_screen:  push cx                ; save it
  3071.                     mov  cx,strings_per_line ; get col. counter
  3072.    display_line:    display  string        ; see Function 09H
  3073.                     loop display_line
  3074.                     display crlf           ; see Function 09H
  3075.                     pop  cx                ; get line counter
  3076.                     loop display_screen    ; display 1 more line
  3077.  
  3078.  
  3079.  ────────────────────────────────────────────────────────────────────────────
  3080.  Check Keyboard Status (Function 0BH)
  3081.  ────────────────────────────────────────────────────────────────────────────
  3082.  
  3083.    Call:
  3084.  
  3085.    AH = 0BH
  3086.  
  3087.    Return:
  3088.  
  3089.    AL
  3090.      00H        = no characters in type-ahead buffer
  3091.      FFH        = characters in type-ahead buffer
  3092.  
  3093.  
  3094.    Comments:
  3095.  
  3096.    Function 0BH checks whether characters are available from standard input
  3097.    (if standard input has not been redirected, it checks the type-ahead
  3098.    buffer). If characters are available, AL returns FFH; if not, AL returns
  3099.    0. If CONTROL+C is in the buffer, it issues Interrupt 23H.
  3100.  
  3101.    Macro Definition:
  3102.  
  3103.    check_kbd_status  macro
  3104.                      mov   ah,0BH
  3105.                      int   21H
  3106.                      endm
  3107.  
  3108.    Example:
  3109.  
  3110.    The following program displays the time continuously until you press any
  3111.    key:
  3112.  
  3113.    time        db       "00:00:00.00",0DH,0AH,"$"
  3114.               .
  3115.               .
  3116.    begin:      get_time                  ; see Function 2CH
  3117.                byte_to_dec ch,time       ; see end of chapter
  3118.                byte_to_dec cl,time[3]    ; see end of chapter
  3119.                byte_to_dec dh,time[6]    ; see end of chapter
  3120.                byte_to_dec dl,time[9]    ; see end of chapter
  3121.                display time              ; see Function 09H
  3122.                check_kbd_status          ; THIS FUNCTION
  3123.                cmp     al,0FFH           ; has a key been typed?
  3124.                je      return            ; yes, go home
  3125.                jmp     begin             ; no, keep displaying
  3126.                                          ; time
  3127.  
  3128.  
  3129.  ────────────────────────────────────────────────────────────────────────────
  3130.  Flush Buffer, Read Keyboard (Function 0CH)
  3131.  ────────────────────────────────────────────────────────────────────────────
  3132.  
  3133.    Call:
  3134.  
  3135.    AH = 0CH
  3136.    AL
  3137.      1, 6, 7, 8, or 0AH = the
  3138.      corresponding function
  3139.      is called.
  3140.      Any other value = no
  3141.      further processing.
  3142.  
  3143.    Return:
  3144.  
  3145.    AL
  3146.      00H = Type-ahead buffer
  3147.      was flushed; no other
  3148.      processing performed.
  3149.  
  3150.  
  3151.    Comments:
  3152.  
  3153.    Function 0CH empties the standard input buffer (if standard input has not
  3154.    been redirected, Function 0CH empties the type-ahead buffer). Further
  3155.    processing depends on the value in AL when the function is called.
  3156.  
  3157.    AL                 Action
  3158.    ──────────────────────────────────────────────────────────────────────────
  3159.    1,6,7,8, or 0AH    The corresponding MS-DOS function is executed.
  3160.    Any other value    No further processing; AL returns 0.
  3161.    ──────────────────────────────────────────────────────────────────────────
  3162.  
  3163.    Macro Definition:
  3164.  
  3165.    flush_and_read_kbd  macro switch
  3166.                        mov   al,switch
  3167.                        mov   ah,0CH
  3168.                        int   21H
  3169.                        endm
  3170.  
  3171.    Example:
  3172.  
  3173.    The following program both displays and prints characters as you type
  3174.    them. If you press the ENTER key, the program sends a
  3175.    carriage-return/linefeed sequence to both the display and the printer.
  3176.  
  3177.    begin:     flush_and_read_kbd 1      ; THIS FUNCTION
  3178.               print_char   al           ; see Function 05H
  3179.               cmp          al,0DH       ; is it a carriage return?
  3180.               jne          begin        ; no, print it
  3181.               print_char   0AH          ; see Function 05H
  3182.               display_char 0AH          ; see Function 02H
  3183.               jmp          begin        ; get another character
  3184.  
  3185.  
  3186.  ────────────────────────────────────────────────────────────────────────────
  3187.  Reset Disk (Function 0DH)
  3188.  ────────────────────────────────────────────────────────────────────────────
  3189.  
  3190.    Call:
  3191.  
  3192.    AH = 0DH
  3193.  
  3194.    Return:
  3195.  
  3196.    None
  3197.  
  3198.  
  3199.    Comments:
  3200.  
  3201.    Function 0DH flushes all file buffers to ensure that the internal buffer
  3202.    cache matches the disks in the drives. It writes out buffers that have
  3203.    been modified and marks all buffers in the internal cache as free. This
  3204.    function request is normally used to force a known state of the system;
  3205.    CONTROL+C interrupt handlers should call this function.
  3206.  
  3207.    This function does not update directory entries; you must close changed
  3208.    files to update their directory entries (see Function 10H, Close File).
  3209.  
  3210.    Macro Definition:
  3211.  
  3212.    reset_disk macro
  3213.               mov   ah,0DH
  3214.               int   21H
  3215.               endm
  3216.  
  3217.    Example:
  3218.  
  3219.    The following program flushes all file buffers and selects disk A.
  3220.  
  3221.    begin:  reset_disk
  3222.            select_disk "A"
  3223.  
  3224.  
  3225.  ────────────────────────────────────────────────────────────────────────────
  3226.  Select Disk (Function 0EH)
  3227.  ────────────────────────────────────────────────────────────────────────────
  3228.  
  3229.    Call:
  3230.  
  3231.    AH = 0EH
  3232.    DL
  3233.      Logical drive number
  3234.      (0 = A, 1 = B, etc.)
  3235.  
  3236.    Return:
  3237.  
  3238.    AL
  3239.      Number of logical drives
  3240.  
  3241.  
  3242.    Comments:
  3243.  
  3244.    Function 0EH selects the drive specified in DL (0=A, 1=B, etc.) as the
  3245.    current logical drive. AL returns the number of logical drives.
  3246.  
  3247.    ──────────────────────────────────────────────────────────────────────────
  3248.    Note
  3249.      For future compatibility, treat the value returned in AL with care. For
  3250.      example, if AL returns 5, it is not safe to assume that drives A, B, C,
  3251.      D, and E are all valid drive designators.
  3252.    ──────────────────────────────────────────────────────────────────────────
  3253.  
  3254.    Macro Definition:
  3255.  
  3256.    select_disk macro disk
  3257.                mov   dl,disk[-64]
  3258.                mov   ah,0EH
  3259.                int   21H
  3260.                endm
  3261.  
  3262.    Example:
  3263.  
  3264.    The following program toggles between drive A and drive B to select the
  3265.    current drive (in a two-drive system).
  3266.  
  3267.    begin:    current_disk       ; see Function 19H
  3268.              cmp    al,00H      ; drive A: selected?
  3269.              je     select_b    ; yes, select B
  3270.              select_disk "A"    ; THIS FUNCTION
  3271.              jmp    return
  3272.    select_b: select_disk "B"    ; THIS FUNCTION
  3273.  
  3274.  
  3275.  ────────────────────────────────────────────────────────────────────────────
  3276.  Open File (Function 0FH)
  3277.  ────────────────────────────────────────────────────────────────────────────
  3278.  
  3279.    Call:
  3280.  
  3281.    AH = 0FH
  3282.    DS:DX
  3283.      Pointer to unopened FCB
  3284.  
  3285.    Return:
  3286.  
  3287.    AL
  3288.      00H        = Directory entry found
  3289.      FFH        = No directory entry found
  3290.  
  3291.  
  3292.    Comments:
  3293.  
  3294.    Function 0FH opens a file. DX must contain the offset (from the segment
  3295.    address in DS) of an unopened File Control Block (FCB). This call searches
  3296.    the disk directory for the named file.
  3297.  
  3298.    If the call finds a directory entry for the file, AL returns 0 and the FCB
  3299.    is filled as follows:
  3300.  
  3301.    ■  If the drive code was 0 (current drive), it is changed to the actual
  3302.       drive used (1=A, 2=B, etc.). This lets you change the current drive
  3303.       without interfering with subsequent operations on this file.
  3304.  
  3305.    ■  Current Block (offset 0CH) is set to 0.
  3306.  
  3307.    ■  Record Size (offset 0EH) is set to the system default of 128.
  3308.  
  3309.    ■  File Size (offset 10FH), Date of Last Write (offset 14H), and Time of
  3310.       Last Write (offset 16H) are set from the directory entry.
  3311.  
  3312.    Before performing a sequential disk operation on the file, you must set
  3313.    the Current Record field (offset 20H). Before performing a random disk
  3314.    operation on the file, you must set the Relative Record field (offset
  3315.    21H). If the default record size (128 bytes) is not correct, set it to the
  3316.    correct length.
  3317.  
  3318.    If the call doesn't find a directory entry for the file, or if the file
  3319.    has the hidden or system attribute, AL returns FFH.
  3320.  
  3321.    Macro Definition:
  3322.  
  3323.    open  macro fcb
  3324.          mov   dx,offset fcb
  3325.          mov   ah,0FH
  3326.          int   21H
  3327.          endm
  3328.  
  3329.    Example:
  3330.  
  3331.    The following program prints a file named textfile.asc that is on the disk
  3332.    in drive B. If a partial record is in the buffer at end-of-file, the
  3333.    routine that prints the partial record prints characters until it
  3334.    encounters an end-of-file mark (ASCII 26, or CONTROL+Z).
  3335.  
  3336.    fcb            db    2,"TEXTFILEASC"
  3337.                   db    26 dup (?)
  3338.    buffer         db    128 dup (?)
  3339.    ;
  3340.    begin:         set_dta  buffer       ; see Function 1AH
  3341.                   open  fcb             ; THIS FUNCTION
  3342.    read_line:     read_seq  fcb         ; see Function 14H
  3343.                   cmp   al,02H          ; end of file?
  3344.                   je    all_done        ; yes, go home
  3345.                   cmp   al,00H          ; more to come?
  3346.                   jg    check_more      ; no, check for partial
  3347.                                         ; record
  3348.                   mov   cx,80H          ; yes, print the buffer
  3349.                   xor   si,si           ; set index to 0
  3350.    print_it:      print_char buffer[si] ; see Function 05H
  3351.                   inc   si              ; bump index
  3352.                   loop  print_it        ; print next character
  3353.                   jmp   read_line       ; read another record
  3354.    check_more:    cmp   al,03H          ; part. record to print?
  3355.                   jne   all_done        ; no
  3356.                   mov   cx,80H          ; yes, print it
  3357.                   xor   si,si           ; set index to 0
  3358.    find_eof:      cmp   buffer[si],26   ; end-of-file mark?
  3359.                   je    all_done        ; yes
  3360.                   print_char buffer[si] ; see Function 05H
  3361.                   inc   si              ; bump index to next
  3362.                                         ; character
  3363.                   loop  find_eof
  3364.    all_done:      close fcb             ; see Function 10H
  3365.  
  3366.  
  3367.  ────────────────────────────────────────────────────────────────────────────
  3368.  Close File (Function 10H)
  3369.  ────────────────────────────────────────────────────────────────────────────
  3370.  
  3371.    Call:
  3372.  
  3373.    AH = 10H
  3374.    DS:DX
  3375.      Pointer to opened FCB
  3376.  
  3377.    Return:
  3378.  
  3379.    AL
  3380.      00H        = Directory entry found
  3381.      FFH        = No directory entry found
  3382.  
  3383.  
  3384.    Comments:
  3385.  
  3386.    Function 10H closes a file. DX must contain the offset (to the segment
  3387.    address in DS) of an opened FCB. This call searches the disk directory for
  3388.    the file named in the FCB. If it finds a directory entry for the file, it
  3389.    compares the location of the file with the corresponding entries in the
  3390.    FCB. The call then updates the directory entry, if necessary, to match the
  3391.    FCB, and AL returns 0.
  3392.  
  3393.    After you change a file, you must call this function to update the
  3394.    directory entry. You should close any FCB (even one for a file that has
  3395.    not been changed) when you no longer need access to a file.
  3396.  
  3397.    If this call doesn't find a directory entry for the file, AL returns FFH.
  3398.  
  3399.    Macro Definition:
  3400.  
  3401.    close  macro fcb
  3402.           mov   dx,offset fcb
  3403.           mov   ah,10H
  3404.           int   21H
  3405.           endm
  3406.  
  3407.    Example:
  3408.  
  3409.    The following program checks the first byte of the file named mod1.bas in
  3410.    drive B to see if it is FFH and, if it is, prints a message.
  3411.  
  3412.    message        db   "Not saved in ASCII format",0DH,0AH,"$"
  3413.    fcb            db    2,"MOD1    BAS"
  3414.                   db    26  dup (?)
  3415.    buffer         db    128 dup (?)
  3416.    ;
  3417.    begin:         set_dta  buffer       ; see Function 1AH
  3418.                   open  fcb             ; see Function 0FH
  3419.                   read_seq  fcb         ; see Function 14H
  3420.  
  3421.                   cmp   buffer,0FFH     ; is first byte FFH?
  3422.                   jne   all_done        ; no
  3423.                   display  message      ; see Function 09H
  3424.    all_done:      close fcb             ; THIS FUNCTION
  3425.  
  3426.  
  3427.  ────────────────────────────────────────────────────────────────────────────
  3428.  Search for First Entry (Function 11H)
  3429.  ────────────────────────────────────────────────────────────────────────────
  3430.  
  3431.    Call:
  3432.  
  3433.    AH = 11H
  3434.    DS:DX
  3435.      Pointer to unopened FCB
  3436.  
  3437.    Return:
  3438.  
  3439.    AL
  3440.      00H        = Directory entry found
  3441.      FFH        = No directory entry found
  3442.  
  3443.  
  3444.    Comments:
  3445.  
  3446.    Function 11H searches the disk directory for the first matching filename.
  3447.    DX must contain the offset (from the segment address in DS) of an unopened
  3448.    FCB. The filename in the FCB can include wildcard characters. To search
  3449.    for hidden or system files, DX must point to the first byte of an extended
  3450.    FCB prefix.
  3451.  
  3452.    If this call does not find a directory entry for the filename in the FCB,
  3453.    AL returns FFH.
  3454.  
  3455.    But if the call does find a directory entry for the filename in the FCB,
  3456.    AL returns 0 and the call creates an unopened FCB of the same type (normal
  3457.    or extended) at the Disk Transfer Address as follows:
  3458.  
  3459.    1. If the search FCB was normal, the first byte at the Disk Transfer
  3460.       Address is set to the drive number used in the search (1=A, 2=B, etc.)
  3461.       and the next 32 bytes contain the directory entry.
  3462.  
  3463.    2. If the search FCB was extended, the first byte at the Disk Transfer
  3464.       Address is set to FFH, the next 5 bytes are set to 00H, and the
  3465.       following byte is set to the value of the attribute byte in the search
  3466.       FCB. The remaining 33 bytes are the same as the result of the normal
  3467.       FCB (drive number and 32 bytes of directory entry).
  3468.  
  3469.    If you use Function 12H (Search for Next Entry) to continue searching for
  3470.    matching filenames, you must not alter or open the original FCB at DS:DX.
  3471.  
  3472.    The attribute field is the last byte of the extended FCB fields that
  3473.    precede the FCB (see Extended FCB in Section 1.9.1). If the attribute
  3474.    field is zero, Function 11H searches only normal file entries. It does not
  3475.    search directory entries for hidden files, system files, volume label, and
  3476.    subdirectories.
  3477.  
  3478.    If the attribute field is hidden file, system file, or subdirectory entry
  3479.    (02H, 04H, or 10H), or any combination of those values, this call also
  3480.    searches all normal file entries. To search all directory entries except
  3481.    the volume label, set the attribute byte to 16H (hidden file and system
  3482.    file and subdirectory entry).
  3483.  
  3484.    If the attribute field is Volume ID (08H), the call searches only the
  3485.    volume label entry.
  3486.  
  3487.    Macro Definition:
  3488.  
  3489.    search_first  macro fcb
  3490.                  mov   dx,offset fcb
  3491.                  mov   ah,11H
  3492.                  int   21H
  3493.                  endm
  3494.  
  3495.    Example:
  3496.  
  3497.    The following program verifies the existence of a file named report.asm on
  3498.    the disk in drive B.
  3499.  
  3500.    yes        db   "FILE EXISTS.$"
  3501.    no         db   "FILE DOES NOT EXIST.$"
  3502.    crlf       db    0DH,0AH,"$"
  3503.    fcb        db    2,"REPORT  *ASM"
  3504.               db    26 dup (?)
  3505.    buffer     db    128 dup (?)
  3506.    ;
  3507.    begin:     set_dta  buffer           ; see Function 1AH
  3508.               search_first fcb          ; THIS FUNCTION
  3509.               cmp      al,0FFH          ; directory entry found?
  3510.               je       not_there        ; no
  3511.               display  yes              ; see Function 09H
  3512.               jmp      continue
  3513.    not_there: display  no               ; see Function 09H
  3514.    continue:  display  crlf             ; see Function 09H
  3515.  
  3516.  
  3517.  ────────────────────────────────────────────────────────────────────────────
  3518.  Search for Next Entry (Function 12H)
  3519.  ────────────────────────────────────────────────────────────────────────────
  3520.  
  3521.    Call:
  3522.  
  3523.    AH = 12H
  3524.    DS:DX
  3525.      Pointer to unopened FCB
  3526.  
  3527.    Return:
  3528.  
  3529.    AL
  3530.      00H        = Directory entry found
  3531.      FFH        = No directory entry found
  3532.  
  3533.  
  3534.    Comments:
  3535.  
  3536.    After you use Function 11H (Search for First Entry), you can use Function
  3537.    12H to find any additional directory entries that match a filename
  3538.    (containing wildcard characters). Function 12H searches the disk directory
  3539.    for the next matching name. DX must contain the offset (from the segment
  3540.    address in DS) of an FCB specified in a previous call to Function 11H. To
  3541.    search for hidden or system files, DX must point to the first byte of an
  3542.    extended FCB prefix──one that includes the appropriate attribute value.
  3543.  
  3544.    If the call does not find a directory entry for the filename in the FCB,
  3545.    AL returns FFH.
  3546.  
  3547.    But if the call does find a directory entry for the filename in the FCB,
  3548.    AL returns 0 and the call creates an unopened FCB of the same type (normal
  3549.    or extended) at the Disk Transfer Address (see Function 11H for a
  3550.    description of how the unopened FCB is formed).
  3551.  
  3552.    Macro Definition:
  3553.  
  3554.    search_next  macro fcb
  3555.                 mov   dx,offset fcb
  3556.                 mov   ah,12H
  3557.                 int   21H
  3558.                 endm
  3559.  
  3560.    Example:
  3561.  
  3562.    The following program displays the number of files on the disk in drive B.
  3563.  
  3564.  
  3565.    message     db   "No files",0DH,0AH,"$"
  3566.    files       db    0
  3567.    fcb         db    2,"???????????"
  3568.                db    26  dup (?)
  3569.    buffer      db    128 dup (?)
  3570.    ;
  3571.    begin:      set_dta  buffer         ; see Function 1AH
  3572.                search_first  fcb       ; see Function 11H
  3573.                cmp  al,0FFH            ; directory entry found?
  3574.                je   all_done           ; no, no files on disk
  3575.                inc  files              ; yes, increment file
  3576.                                        ; counter
  3577.    search_dir: search_next  fcb        ; THIS FUNCTION
  3578.                cmp  al,0FFH            ; directory entry found?
  3579.                je   done               ; no
  3580.                inc  files              ; yes, increment file
  3581.                                        ; counter
  3582.                jmp  search_dir         ; check again
  3583.    done:       convert files,10,message ; see end of chapter
  3584.    all_done:   display  message        ; see Function 09H
  3585.  
  3586.  
  3587.  ────────────────────────────────────────────────────────────────────────────
  3588.  Delete File (Function 13H)
  3589.  ────────────────────────────────────────────────────────────────────────────
  3590.  
  3591.    Call:
  3592.  
  3593.    AH = 13H
  3594.    DS:DX
  3595.      Pointer to unopened FCB
  3596.  
  3597.    Return:
  3598.  
  3599.    AL
  3600.     00H        = Directory entry found
  3601.     FFH        = No directory entry found
  3602.  
  3603.  
  3604.    Comments:
  3605.  
  3606.    Function 13H deletes a file. DX must contain the offset (from the segment
  3607.    address in DS) of an unopened FCB. This call searches the directory for a
  3608.    matching filename. The filename in the FCB can contain wildcard
  3609.    characters.
  3610.  
  3611.    If the call does not find a matching directory entry, AL returns FFH.
  3612.  
  3613.    But if the call does find a matching directory entry, AL returns 0 and the
  3614.    call deletes the entry from the directory. If the filename contains a
  3615.    wildcard character, the call will delete all files that match.
  3616.  
  3617.    Do not delete open files.
  3618.  
  3619.    Macro Definition:
  3620.  
  3621.    delete  macro  fcb
  3622.            mov    dx,offset fcb
  3623.            mov    ah,13H
  3624.            int    21H
  3625.            endm
  3626.  
  3627.    Example:
  3628.  
  3629.    The following program deletes each file on the disk in drive B that was
  3630.    last written before December 31, 1982.
  3631.  
  3632.    year           dw    1982
  3633.    month          db    12
  3634.    day            db    31
  3635.    files          db    0
  3636.    message        db   "No files deleted.",0DH,0AH,"$"
  3637.    fcb            db    2,"???????????"
  3638.                   db    26 dup  (?)
  3639.    buffer         db    128 dup (?)
  3640.    ;
  3641.    begin:         set_dta  buffer      ; see Function 1AH
  3642.                   search_first fcb     ; see Function 11H
  3643.                   cmp   al,0FFH        ; directory entry found?
  3644.                   jne   compare        ; yes
  3645.                   jmp   all_done       ; no, no files on disk
  3646.    compare:       convert_date buffer  ; see end of chapter
  3647.                   cmp  cx,year         ; next several lines
  3648.                   jg   next            ; check date in directory
  3649.                   cmp  dl,month        ; entry against date
  3650.                   jg   next            ; above & check next file
  3651.                   cmp  dh,day          ; if date in directory
  3652.                   jge  next            ; entry isn't earlier.
  3653.                   delete  buffer       ; THIS FUNCTION
  3654.                   inc  files           ; bump deleted-files
  3655.                                        ; counter
  3656.    next:          search_next fcb      ; see Function 12H
  3657.                   cmp  al,00H          ; directory entry found?
  3658.                   je   compare         ; yes, check date
  3659.                   cmp  files,0         ; any files deleted?
  3660.                   je   all_done        ; no, display No files
  3661.                                        ; message.
  3662.                   convert files,10,message ; see end of chapter
  3663.    all_done:      display message      ; see Function 09H
  3664.  
  3665.  
  3666.  ────────────────────────────────────────────────────────────────────────────
  3667.  Sequential Read (Function 14H)
  3668.  ────────────────────────────────────────────────────────────────────────────
  3669.  
  3670.    Call:
  3671.  
  3672.    AH = 14H
  3673.    DS:DX
  3674.      Pointer to opened FCB
  3675.  
  3676.    Return:
  3677.  
  3678.    AL
  3679.      00H = Read completed successfully
  3680.      01H = EOF
  3681.      02H = DTA too small
  3682.      03H = EOF, partial record
  3683.  
  3684.  
  3685.    Comments:
  3686.  
  3687.    Function 14H reads a record from a specified file. DX must contain the
  3688.    offset (from the segment address in DS) of an opened FCB. This call loads
  3689.    the record pointed to by the Current Block field (offset 0CH) and Current
  3690.    Record (offset 20H) field at the Disk Transfer Address, then increments
  3691.    the Current Block and Current Record fields.
  3692.  
  3693.    The length of the record is taken from the Record Size field (offset 0EH)
  3694.    of the FCB.
  3695.  
  3696.    AL returns a code that describes the processing:
  3697.  
  3698.    Code               Meaning
  3699.    ──────────────────────────────────────────────────────────────────────────
  3700.    0                  Read completed successfully
  3701.  
  3702.    1                  End-of-file; no data in the record
  3703.  
  3704.    2                  Not enough room at the Disk Transfer Address to read
  3705.                       one record; read canceled
  3706.  
  3707.    3                  End-of-file; a partial record was read and padded to
  3708.    ──────────────────────────────────────────────────────────────────────────
  3709.  
  3710.    Macro Definition:
  3711.  
  3712.    read_seq  macro fcb
  3713.              mov   dx,offset fcb
  3714.              mov   ah,14H
  3715.              int   21H
  3716.              endm
  3717.  
  3718.    Example:
  3719.  
  3720.    The following program displays a file named textfile.asc that is on the
  3721.    disk in drive B; its function is similar to the MS-DOS type command. If a
  3722.    partial record is in the buffer at end-of-file, the routine that displays
  3723.    the partial record displays characters until it encounters an end-of-file
  3724.    mark (ASCII 26, or CONTROL+Z).
  3725.  
  3726.    fcb            db    2,"TEXTFILEASC"
  3727.                   db    26  dup (?)
  3728.    buffer         db    128 dup (?),"$"
  3729.    ;
  3730.    begin:         set_dta  buffer    ; see Function 1AH
  3731.                   open  fcb          ; see Function 0FH
  3732.    read_line:     read_seq  fcb      ; THIS FUNCTION
  3733.                   cmp   al,02H       ; DTA too small?
  3734.                   je    all_done     ; yes
  3735.                   cmp   al,00H       ; end-of-file?
  3736.                   jg    check_more   ; yes
  3737.                   display  buffer    ; see Function 09H
  3738.                   jmp   read_line    ; get another record
  3739.    check_more:    cmp   al,03H       ; partial record in buffer?
  3740.                   jne   all_done     ; no, go home
  3741.                   xor   si,si        ; set index to 0
  3742.    find_eof:      cmp   buffer[si],26 ; is character EOF?
  3743.                   je    all_done     ; yes, no more to display
  3744.                   display_char buffer[si]  ; see Function 02H
  3745.                   inc   si           ; bump index
  3746.                   jmp   find_eof     ; check next character
  3747.    all_done:      close fcb          ; see Function 10H
  3748.  
  3749.  
  3750.  ────────────────────────────────────────────────────────────────────────────
  3751.  Sequential Write (Function 15H)
  3752.  ────────────────────────────────────────────────────────────────────────────
  3753.  
  3754.    Call:
  3755.  
  3756.    AH = 15H
  3757.    DS:DX
  3758.      Pointer to opened FCB
  3759.  
  3760.    Return:
  3761.  
  3762.    AL
  3763.      00H = Write completed successfully
  3764.      01H = Disk full
  3765.      02H = DTA too small
  3766.  
  3767.  
  3768.    Comments:
  3769.  
  3770.    Function 15H writes a record to a specified file. DX must contain the
  3771.    offset (from the segment address in DS) of an opened FCB. This call writes
  3772.    the record pointed to by the Current Block field (offset 0CH) and Current
  3773.    Record field (offset 20H) at the Disk Transfer Address, then increments
  3774.    the Current Block and Current Record fields.
  3775.  
  3776.    The record size is taken from the value of the Record Size field (offset
  3777.    0EH) of the FCB. If the record size is less than a sector, the call writes
  3778.    the data at the Disk Transfer Address to an MS-DOS buffer; MS-DOS writes
  3779.    the buffer to disk when it contains a full sector of data, when the file
  3780.    is closed, or when Function 0DH (Reset Disk) is issued.
  3781.  
  3782.    AL returns a code that describes the processing:
  3783.  
  3784.    Code               Meaning
  3785.    ──────────────────────────────────────────────────────────────────────────
  3786.    0                  Write completed successfully
  3787.  
  3788.    1                  Disk full; write canceled
  3789.  
  3790.    2                  Not enough room at the Disk Transfer Address to write
  3791.    ──────────────────────────────────────────────────────────────────────────
  3792.  
  3793.    Macro Definition:
  3794.  
  3795.    write_seq  macro fcb
  3796.               mov   dx,offset fcb
  3797.               mov   ah,15H
  3798.               int   21H
  3799.               endm
  3800.  
  3801.  
  3802.    Example:
  3803.  
  3804.    The following program creates a file named dir.tmp on the disk in drive B
  3805.    containing the disk number (0=A, 1=B, etc.) and filename from each
  3806.    directory entry on the disk.
  3807.  
  3808.    record_size    equ   0EH           ; offset of Record Size
  3809.    ;                                   field in FCB
  3810.    fcb1           db    2,"DIR     TMP"
  3811.                   db    26 dup (?)
  3812.    fcb2           db    2,"???????????"
  3813.                   db    26 dup (?)
  3814.    buffer         db    128 dup (?)
  3815.    ;
  3816.    begin:      set_dta      buffer     ; see Function 1AH
  3817.                search_first fcb2       ; see Function 11H
  3818.                cmp          al,0FFH    ; directory entry found?
  3819.                je           all_done   ; no, no files on disk
  3820.                create       fcb1       ; see Function 16H
  3821.                mov          fcb1[record_size],12
  3822.                                        ; set record size to 12
  3823.    write_it:   write_seq    fcb1       ; THIS FUNCTION
  3824.                cmp          al,0       ; write successful?
  3825.                jne          all_done   ; no, go home
  3826.                search_next  fcb2       ; see Function 12H
  3827.                cmp          al,FFH     ; directory entry found?
  3828.                je           all_done   ; no, go home
  3829.                jmp          write_it   ; yes, write the record
  3830.    all_done:   close        fcb1       ; see Function 10H
  3831.  
  3832.  
  3833.  ────────────────────────────────────────────────────────────────────────────
  3834.  Create File (Function 16H)
  3835.  ────────────────────────────────────────────────────────────────────────────
  3836.  
  3837.    Call:
  3838.  
  3839.    AH = 16H
  3840.    DS:DX
  3841.      Pointer to unopened FCB
  3842.  
  3843.    Return:
  3844.  
  3845.    AL
  3846.      00H        = Empty directory found
  3847.      FFH        = No empty directory available
  3848.  
  3849.  
  3850.    Comments:
  3851.  
  3852.    Function 16H creates a file. DX must contain the offset (from the segment
  3853.    address in DS) of an unopened FCB. MS-DOS searches the directory for an
  3854.    entry that matches the specified filename or, if there is no matching
  3855.    entry, an empty entry.
  3856.  
  3857.    If MS-DOS finds a matching entry, it opens the file and sets the length to
  3858.    zero (in other words, if you try to create a file that already exists,
  3859.    MS-DOS erases it and creates a new, empty file). If MS-DOS doesn't find a
  3860.    matching entry but does find an empty directory entry, it opens the file
  3861.    and sets its length to zero. In either case, the call creates the file,
  3862.    and AL returns 0. If MS-DOS doesn't find a matching entry and there is no
  3863.    empty entry, the call doesn't create the file, and AL returns FFH.
  3864.  
  3865.    You can assign an attribute to the file by using an extended FCB with the
  3866.    attribute byte set to the appropriate value (see "Extended FCB" in Section
  3867.    1.9.1).
  3868.  
  3869.    Macro Definition:
  3870.  
  3871.    create  macro fcb
  3872.            mov   dx,offset fcb
  3873.            mov   ah,16H
  3874.            int   21H
  3875.            endm
  3876.  
  3877.    Example:
  3878.  
  3879.    The following program creates a file named dir.tmp on the disk in drive B
  3880.    containing the disk number (0 = A, 1 = B, etc.) and filename from each
  3881.    directory entry on the disk.
  3882.  
  3883.    record_size    equ   0EH           ; offset of Record Size
  3884.    ;                                   field of FCB
  3885.    fcb1           db    2,"DIR     TMP"
  3886.                   db    26  dup (?)
  3887.    fcb2           db    2,"???????????"
  3888.                   db    26  dup (?)
  3889.    buffer         db    128 dup (?)
  3890.    ;
  3891.    begin:         set_dta   buffer     ; see Function 1AH
  3892.                   search_first  fcb2   ; see Function 11H
  3893.                   cmp       al,0FFH    ; directory entry found?
  3894.                   je        all_done   ; no, no files on disk
  3895.                   create    fcb1       ; THIS FUNCTION
  3896.                   mov       fcb1[record_size],12
  3897.                                        ; set record size to 12
  3898.    write_it:      write_seq fcb1       ; see Function 15H
  3899.                   cmp       al,0       ; write successful
  3900.                   jne       all_done   ; no, go home
  3901.                   search_next  fcb2    ; see Function 12H
  3902.                   cmp       al,FFH     ; directory entry found?
  3903.                   je        all_done   ; no, go home
  3904.                   jmp       write_it   ; yes, write the record
  3905.    all_done:      close     fcb1       ; see Function 10H
  3906.  
  3907.  
  3908.  ────────────────────────────────────────────────────────────────────────────
  3909.  Rename File (Function 17H)
  3910.  ────────────────────────────────────────────────────────────────────────────
  3911.  
  3912.    Call:
  3913.  
  3914.    AH = 17H
  3915.    DS:DX
  3916.      Pointer to modified FCB in the following
  3917.      nonstandard format:
  3918.  
  3919.  
  3920.       Byte(s)           Contents
  3921.       ───────────────────────────────────────────────────────────────────────
  3922.       00H               Drive number
  3923.       01H-08H           Old filename (padded with blanks, if necessary)
  3924.       09H-0BH           Old file extension (padded with blanks, if necessary)
  3925.       0CH-10H           Zeroed out
  3926.       11H-18H           New filename (padded with blanks, if necessary)
  3927.       19H-1BH           New file extension (padded with blanks, if necessary)
  3928.       11CH-24H          Zeroed out
  3929.       ───────────────────────────────────────────────────────────────────────
  3930.  
  3931.    Return:
  3932.  
  3933.    AL
  3934.      00H        =        Directory entry found
  3935.      FFH        =        No directory entry found
  3936.                    or destination already exists
  3937.  
  3938.  
  3939.    Comments:
  3940.  
  3941.    Function 17H changes the name of an existing file. DX must contain the
  3942.    offset (from the segment address in DS) of an FCB with the drive number
  3943.    and filename filled in, followed by a second filename at offset 11H. DOS
  3944.    searches the disk directory for an entry that matches the first filename.
  3945.    This filename can contain wildcard characters.
  3946.  
  3947.    If MS-DOS finds a matching directory entry and there is no directory entry
  3948.    that matches the second filename, it changes the filename in the directory
  3949.    entry to match the second filename in the modified FCB. AL then returns
  3950.    zero. If the second filename does contain a wildcard character, this call
  3951.    does not change the corresponding characters in the filename of the
  3952.    directory entry. You cannot use this function request to rename a hidden
  3953.    file, a system file, or a subdirectory. If MS-DOS does not find a matching
  3954.    directory entry or if it finds an entry for the second filename, AL
  3955.    returns FFH.
  3956.  
  3957.    Macro Definition:
  3958.  
  3959.    rename macro fcb,newname
  3960.           mov   dx,offset fcb
  3961.           mov   ah,17H
  3962.           int   21H
  3963.           endm
  3964.  
  3965.    Example:
  3966.  
  3967.    The following program prompts for the name of a file and a new name; it
  3968.    then renames the file.
  3969.  
  3970.    fcb               db    37 dup (?)
  3971.    prompt1           db   "Filename: $"
  3972.    prompt2           db   "New name: $"
  3973.    reply             db    15 dup(?)
  3974.    crlf              db    0DH,0AH,"$"
  3975.    ;
  3976.    begin:            display  prompt1       ; see Function 09H
  3977.                      get_string  15,reply   ; see Function 0AH
  3978.                      display  crlf          ; see Function 09H
  3979.                      parse    reply[2],fcb  ; see Function 29H
  3980.                      display  prompt2       ; see Function 09H
  3981.                      get_string  15,reply   ; see Function 0AH
  3982.                      display  crlf          ; see Function 09H
  3983.                      parse    reply[2],fcb[16]
  3984.                                             ; see Function 29H
  3985.                      rename   fcb           ; THIS FUNCTION
  3986.  
  3987.  
  3988.  ────────────────────────────────────────────────────────────────────────────
  3989.  Get Current Disk (Function 19H)
  3990.  ────────────────────────────────────────────────────────────────────────────
  3991.  
  3992.    Call:
  3993.  
  3994.    AH = 19H
  3995.  
  3996.    Return:
  3997.  
  3998.    AL
  3999.      Currently selected drive
  4000.      (0 = A, 1 = B, etc.)
  4001.  
  4002.  
  4003.    Comments:
  4004.  
  4005.    Function 19H returns the current drive in AL (0=A, 1=B, etc.).
  4006.  
  4007.    Macro Definition:
  4008.  
  4009.    current_disk  macro
  4010.                  mov   ah,19H
  4011.                  int   21H
  4012.                  endm
  4013.  
  4014.    Example:
  4015.  
  4016.    The following program displays the default drive in a two-drive system.
  4017.  
  4018.    message    db  "Current disk is $"
  4019.    crlf       db   0DH,OAH,"$"
  4020.    ;
  4021.    begin:     display  message         ; see Function 09H
  4022.               current_disk             ; THIS FUNCTION
  4023.               cmp      al,00H          ; is it disk A?
  4024.               jne      disk_b          ; no, it's disk B:
  4025.               display_char "A"         ; see Function 02H
  4026.               jmp      all_done
  4027.    disk_b:    display_char "B"         ; see Function 02H
  4028.    all_done:  display  crlf            ; see Function 09H
  4029.  
  4030.  
  4031.  ────────────────────────────────────────────────────────────────────────────
  4032.  Set Disk Transfer Address (Function 1AH)
  4033.  ────────────────────────────────────────────────────────────────────────────
  4034.  
  4035.    Call:
  4036.  
  4037.    AH = 1AH
  4038.    DS:DX
  4039.     Disk Transfer Address
  4040.  
  4041.    Return:
  4042.  
  4043.    None
  4044.  
  4045.  
  4046.    Comments:
  4047.  
  4048.    Function 1AH sets the Disk Transfer Address. DX must contain the offset
  4049.    (from the segment address in DS) of the Disk Transfer Address. Disk
  4050.    transfers cannot wrap around from the end of the segment to the beginning,
  4051.    nor can they overflow into another segment.
  4052.  
  4053.    If you do not set the Disk Transfer Address, MS-DOS defaults to offset 80H
  4054.    in the Program Segment Prefix. You can check the current Disk Transfer
  4055.    Address with Function 2FH (Get Disk Transfer Address).
  4056.  
  4057.    Macro Definition:
  4058.  
  4059.    set_dta  macro  buffer
  4060.             mov    dx,offset buffer
  4061.             mov    ah,1AH
  4062.             int    21H
  4063.             endm
  4064.  
  4065.    Example:
  4066.  
  4067.    The following program prompts for a letter, converts it to its alphabetic
  4068.    sequence (A=1, B=2, etc.), then reads and displays the corresponding
  4069.    record from a file named alphabet.dat that is on the disk in drive B. The
  4070.    file contains 26 records, each 28 bytes long.
  4071.  
  4072.    record_size     equ   0EH      ; offset of Record Size
  4073.                                   ; field of FCB
  4074.    relative_record equ   21H      ; offset of Relative Record
  4075.    ;                               field of FCB
  4076.    fcb           db    2,"ALPHABETDAT"
  4077.                  db    26  dup (?)
  4078.    buffer        db    28 dup(?),"$"
  4079.    prompt        db   "Enter letter: $"
  4080.    crlf          db    0DH,0AH,"$"
  4081.    ;
  4082.    begin:        set_dta  buffer       ; THIS FUNCTION
  4083.                  open     fcb          ; see Function 0FH
  4084.                  mov      fcb[record_size],28 ; set record size
  4085.    get_char:     display  prompt       ; see Function 09H
  4086.                  read_kbd_and_echo     ; see Function 01H
  4087.                  cmp      al,0DH       ; just a CR?
  4088.                  je       all_done     ; yes, go home
  4089.                  sub      al,41H       ; convert ASCII
  4090.                                        ; code to record #
  4091.                  mov      fcb[relative_record],al
  4092.                                        ; set relative record
  4093.                  display  crlf         ; see Function 09H
  4094.                  read_ran fcb          ; see Function 21H
  4095.                  display  buffer       ; see Function 09H
  4096.                  display  crlf         ; see Function 09H
  4097.                  jmp      get_char     ; get another character
  4098.    all_done:     close    fcb          ; see Function 10H
  4099.  
  4100.  
  4101.  ────────────────────────────────────────────────────────────────────────────
  4102.  Get Default Drive Data (Function 1BH)
  4103.  ────────────────────────────────────────────────────────────────────────────
  4104.  
  4105.    Call:
  4106.  
  4107.    AH = 1BH
  4108.  
  4109.    Return:
  4110.  
  4111.    AL
  4112.       Sectors per cluster
  4113.    CX
  4114.       Bytes per sector
  4115.    DX
  4116.       Clusters per drive
  4117.    DS:BX
  4118.       Pointer to FAT ID byte
  4119.  
  4120.  
  4121.    Comments:
  4122.  
  4123.    Function 1BH retrieves data about the disk in the default drive. The data
  4124.    returns in the following registers:
  4125.  
  4126.    Register           Contents
  4127.    ──────────────────────────────────────────────────────────────────────────
  4128.    AL                 Number of sectors in a cluster (allocation unit)
  4129.    CX                 Number of bytes in a sector
  4130.    DX                 Number of clusters on the disk
  4131.    ──────────────────────────────────────────────────────────────────────────
  4132.  
  4133.    BX returns the offset (to the segment address in DS) of the first byte of
  4134.    the File Allocation Table (FAT), which identifies the type of disk in the
  4135.    drive:
  4136.  
  4137.    Value       Type of Drive
  4138.    ──────────────────────────────────────────────────────────────────────────
  4139.    FF          Double-sided disk, 8 sectors per track, 40 tracks per side
  4140.    FE          Single-sided disk, 8 sectors per track, 40 tracks per side
  4141.    FD          Double-sided disk, 9 sectors per track, 40 tracks per side
  4142.    FC          Single-sided disk, 9 sectors per track, 40 tracks per side
  4143.    F9          Double-sided disk, 15 sectors per track, 40 tracks per side
  4144.    F9          Double-sided disk, 9 sectors per track, 80 tracks per side
  4145.    F8          Fixed disk
  4146.    ──────────────────────────────────────────────────────────────────────────
  4147.  
  4148.    This call is similar to Function 36H (Get Disk Free Space), except that
  4149.    it returns the address of the FAT ID byte in BX instead of the number of
  4150.    available clusters. It is also similar to Function 1CH (Get Drive Data),
  4151.    except that it returns data on the disk in the default drive instead of on
  4152.    the disk in a specified drive. For a description of how MS-DOS stores data
  4153.    on a disk, including a description of the File Allocation Table, see
  4154.    Chapter 3, "MS-DOS Technical Information."
  4155.  
  4156.    ──────────────────────────────────────────────────────────────────────────
  4157.    Warning
  4158.      The FAT ID byte is no longer adequate to identify the type of drive
  4159.      being used. See Chapter 2, "MS-DOS Device Drivers," for more details.
  4160.    ──────────────────────────────────────────────────────────────────────────
  4161.  
  4162.    Macro Definition:
  4163.  
  4164.    def_drive_data  macro
  4165.                    push   ds
  4166.                    mov    ah,1BH
  4167.                    int    21H
  4168.                    mov    al,byte ptr[bx]
  4169.                    pop    ds
  4170.                    endm
  4171.  
  4172.    Example:
  4173.  
  4174.    The following program displays a message that tells whether the default
  4175.    drive is a floppy disk or a hard disk drive.
  4176.  
  4177.    stdout      equ         1
  4178.    ;
  4179.    msg         db          "Default drive is "
  4180.    dskt        db          "disk."
  4181.    fixed       db          "fixed."
  4182.    crlf        db          ODH,OAH
  4183.    ;
  4184.    begin:      write_handle stdout,msg,17      ; display message
  4185.                jc           write_error        ; routine not shown
  4186.                def_drive_data                  ; THIS FUNCTION
  4187.                cmp          byte ptr [bx],0F8H ; check FAT ID byte
  4188.                jne          disk           ; it's a disk
  4189.                write_handle stdout,fixed,6     ; see Function 40H
  4190.                jc           write_error        ; see Function 40H
  4191.                jmp short    all_done           ; clean up & go home
  4192.    disk:   write_handle stdout,dskt,9      ; see Function 40H
  4193.    all_done:   write_handle stdout,crlf,2      ; see Function 40H
  4194.                jc           write_error        ; routine not shown
  4195.  
  4196.  
  4197.  ────────────────────────────────────────────────────────────────────────────
  4198.  Get Drive Data (Function 1CH)
  4199.  ────────────────────────────────────────────────────────────────────────────
  4200.  
  4201.    Call:
  4202.  
  4203.    AH = 1CH
  4204.    DL
  4205.       Drive (0=default, 1=A, etc.)
  4206.  
  4207.  
  4208.    Return:
  4209.  
  4210.    AL
  4211.       0FFH if drive number is invalid;
  4212.       otherwise, sectors per cluster
  4213.    CX
  4214.       Bytes per sector
  4215.    DX
  4216.       Clusters per drive
  4217.    DS:BX
  4218.       Pointer to FAT ID byte
  4219.  
  4220.  
  4221.  
  4222.  
  4223.    Comments:
  4224.  
  4225.    Function 1CH retrieves data about the disk in the specified drive. DL must
  4226.    contain the drive number (0=default, 1=A, etc.). The data returns in the
  4227.    following registers:
  4228.  
  4229.    Register           Contents
  4230.    ──────────────────────────────────────────────────────────────────────────
  4231.    AL                 Number of sectors in a cluster (allocation unit)
  4232.    CX                 Number of bytes in a sector
  4233.    DX                 Number of clusters on the disk
  4234.    ──────────────────────────────────────────────────────────────────────────
  4235.  
  4236.    BX returns the offset (to the segment address in DS) of the first byte of
  4237.    the File Allocation Table (FAT), which identifies the type of disk in the
  4238.    drive:
  4239.  
  4240.    Value       Type of Drive
  4241.    ──────────────────────────────────────────────────────────────────────────
  4242.    FF          Double-sided disk, 8 sectors per track, 40 tracks per side
  4243.    FE          Single-sided disk, 8 sectors per track, 40 tracks per side
  4244.    FD          Double-sided disk, 9 sectors per track, 40 tracks per side
  4245.    FC          Single-sided disk, 9 sectors per track, 40 tracks per side
  4246.    F9          Double-sided disk, 15 sectors per track, 40 tracks per side
  4247.    F9          Double-sided disk, 9 sectors per track, 80 tracks per side
  4248.    F8          Fixed disk
  4249.    ──────────────────────────────────────────────────────────────────────────
  4250.  
  4251.    If the drive number in DL is invalid, AL returns 0FFH.
  4252.  
  4253.    ──────────────────────────────────────────────────────────────────────────
  4254.    Warning
  4255.      The FAT ID byte is no longer adequate to identify the type of drive
  4256.      being used. See Chapter 2, "MS-DOS Device Drivers," for more details.
  4257.    ──────────────────────────────────────────────────────────────────────────
  4258.  
  4259.    This call is similar to Function 36H (Get Disk Free Space), except that
  4260.    it returns the address of the FAT ID byte in BX instead of the number of
  4261.    available clusters. It is also similar to Function 1BH (Get Default Drive
  4262.    Data), except that it returns data on the disk in the drive specified in
  4263.    DL instead of the disk in the default drive. For a description of how
  4264.    MS-DOS stores data on a disk, including a description of the File
  4265.    Allocation Table, see Chapter 3, "MS-DOS Technical Information."
  4266.  
  4267.    Macro Definition:
  4268.  
  4269.    drive_data  macro  drive
  4270.                push   ds
  4271.                mov    dl,drive
  4272.                mov    ah,1BH
  4273.                int    21H
  4274.                mov    al, byte ptr[bx]
  4275.                pop    ds
  4276.                endm
  4277.  
  4278.    Example:
  4279.  
  4280.    The following program displays a message that tells whether drive B is a
  4281.    floppy disk or a hard disk drive.
  4282.  
  4283.    stdout      equ          1
  4284.    :
  4285.    msg         db           "Drive B is "
  4286.    dskt        db           "disk."
  4287.    fixed       db           "fixed."
  4288.    crlf        db           ODH,OAH
  4289.    ;
  4290.    begin:      write_handle stdout,msg,11      ; display message
  4291.                jc           write_error        ; routine not shown
  4292.                drive_data   2                  ; THIS FUNCTION
  4293.                cmp          byte ptr [bx],0F8H ; check FAT ID byte
  4294.                jne          disk           ; it's a disk
  4295.                write_handle stdout,fixed,6     ; see Function 40H
  4296.                jc           write_error        ; routine not shown
  4297.                jmp          all_done           ; clean up & go home
  4298.    disk:   write_handle stdout,dskt,9      ; see Function 40H
  4299.    all_done:   write_handle stdout,crlf,2      ; see Function 40H
  4300.                jc           write_error        ; routine not shown
  4301.  
  4302.  
  4303.  ────────────────────────────────────────────────────────────────────────────
  4304.  Random Read (Function 21H)
  4305.  ────────────────────────────────────────────────────────────────────────────
  4306.  
  4307.    Call:
  4308.  
  4309.    AH = 21H
  4310.    DS:DX
  4311.      Pointer to opened FCB
  4312.  
  4313.    Return:
  4314.  
  4315.    AL
  4316.      0 = Read completed successfully
  4317.      1 = End of file, record empty
  4318.      2 = DTA too small
  4319.      3 = End of file, partial record
  4320.  
  4321.  
  4322.    Comments:
  4323.  
  4324.    Function 21H reads (into the Disk Transfer Address) the record pointed to
  4325.    by the Relative Record field (offset 21H) of the FCB. DX must contain the
  4326.    offset (from the segment address in DS) of an opened FCB. The Current
  4327.    Block field (offset 0CH) and Current Record field (offset 20H) are set to
  4328.    agree with the Relative Record field (offset 21H). The record is then
  4329.    loaded at the Disk Transfer Address. The record length is taken from the
  4330.    Record Size field (offset 0EH) of the FCB.
  4331.  
  4332.    AL returns a code that describes the processing:
  4333.  
  4334.    Code               Meaning
  4335.    ──────────────────────────────────────────────────────────────────────────
  4336.    0                  Read completed successfully
  4337.  
  4338.    1                  End-of-file; no data in the record
  4339.  
  4340.    2                  Not enough room at the Disk Transfer Address to read
  4341.                       one record; read canceled
  4342.  
  4343.    3                  End-of-file; a partial record was read and padded to
  4344.    ──────────────────────────────────────────────────────────────────────────
  4345.  
  4346.    Macro Definition:
  4347.  
  4348.    read_ran  macro  fcb
  4349.              mov    dx,offset fcb
  4350.              mov    ah,21H
  4351.              int    21H
  4352.              endm
  4353.  
  4354.    Example:
  4355.  
  4356.    The following program prompts for a letter, converts it to its alphabetic
  4357.    sequence (A = 1, B = 2, etc.), then reads and displays the corresponding
  4358.    record from a file named alphabet.dat that is on the disk in drive B. The
  4359.    file contains 26 records, each 28 bytes long.
  4360.  
  4361.    record_size     equ   0EH      ; offset of Record Size
  4362.                                   ; field of FCB
  4363.    relative_record equ   21H      ; offset of Relative Record
  4364.    ;                               field of FCB
  4365.    fcb           db    2,"ALPHABETDAT"
  4366.                  db    26  dup (?)
  4367.    buffer        db    28 dup(?),"$"
  4368.    prompt        db   "Enter letter: $"
  4369.    crlf          db    0DH,0AH,"$"
  4370.    ;
  4371.    begin:        set_dta  buffer            ; see Function 1AH
  4372.                  open     fcb               ; see Function 0FH
  4373.                  mov      fcb[record_size],28 ; set record size
  4374.    get_char:     display  prompt            ; see Function 09H
  4375.                  read_kbd_and_echo          ; see Function 01H
  4376.                  cmp      al,0DH            ; just a CR?
  4377.                  je       all_done          ; yes, go home
  4378.                  sub      al,41H            ; convert ASCII code
  4379.                                             ; to record #
  4380.                  mov      fcb[relative_record],al ; set relative
  4381.                                             ; record
  4382.                  display  crlf              ; see Function 09H
  4383.                  read_ran fcb               ; THIS FUNCTION
  4384.                  display  buffer            ; see Function 09H
  4385.                  display  crlf              ; see Function 09H
  4386.                  jmp      get_char          ; get another char.
  4387.    all_done:     close    fcb               ; see Function 10H
  4388.  
  4389.  
  4390.  ────────────────────────────────────────────────────────────────────────────
  4391.  Random Write (Function 22H)
  4392.  ────────────────────────────────────────────────────────────────────────────
  4393.  
  4394.    Call:
  4395.  
  4396.    AH = 22H
  4397.    DS:DX
  4398.      Pointer to opened FCB
  4399.  
  4400.    Return:
  4401.  
  4402.    AL
  4403.      00H = Write completed successfully
  4404.      01H = Disk full
  4405.      02H = DTA too small
  4406.  
  4407.  
  4408.    Comments:
  4409.  
  4410.    Function 22H writes (from the Disk Transfer Address) the record pointed to
  4411.    by the Relative Record field (offset 21H) of the FCB. DX must contain the
  4412.    offset from the segment address in DS of an opened FCB. The Current Block
  4413.    (offset 0CH) and Current Record (offset 20H) fields are set to agree with
  4414.    the Relative Record field (offset 21H). This record is then written from
  4415.    the Disk Transfer Address.
  4416.  
  4417.    The record length is taken from the Record Size field (offset 0EH) of the
  4418.    FCB. If the record size is less than a sector, the data at the Disk
  4419.    Transfer Address is written to a buffer. The buffer is written to a disk
  4420.    when it contains a full sector of data, or when a program closes the file,
  4421.    or when it issues Function 0DH (Reset Disk).
  4422.  
  4423.    AL returns a code that describes the processing:
  4424.  
  4425.    Code               Meaning
  4426.    ──────────────────────────────────────────────────────────────────────────
  4427.    0                  Write completed successfully
  4428.  
  4429.    1                  Disk is full
  4430.  
  4431.    2                  Not enough room at the Disk Transfer Address to write
  4432.    ──────────────────────────────────────────────────────────────────────────
  4433.  
  4434.    Macro Definition:
  4435.  
  4436.    write_ran  macro  fcb
  4437.               mov    dx,offset fcb
  4438.               mov    ah,22H
  4439.               int    21H
  4440.               endm
  4441.  
  4442.    Example:
  4443.  
  4444.    The following program prompts for a letter, converts it to its alphabetic
  4445.    sequence (A = 1, B = 2, etc.), then reads and displays the corresponding
  4446.    record from a file named alphabet.dat that is on the disk in drive B.
  4447.    After displaying the record, it prompts you to enter a changed record. If
  4448.    you type a new record, it is written to the file, but if you just press
  4449.    the ENTER key, the record is not replaced. The file contains 26 records,
  4450.    each 28 bytes long.
  4451.  
  4452.    record_size     equ   0EH      ; offset of Record Size
  4453.                                   ; field of FCB
  4454.    relative_record equ   21H      ; offset of Relative Record
  4455.    ;                               field of FCB
  4456.    fcb        db    2,"ALPHABETDAT"
  4457.               db    26  dup (?)
  4458.    buffer     db    28 dup(?),0DH,0AH,"$"
  4459.    prompt1    db   "Enter letter: $"
  4460.    prompt2    db   "New record (ENTER for no change): $"
  4461.    crlf       db    0DH,0AH,"$"
  4462.    reply      db    28 dup (32)
  4463.    blanks     db    26 dup (32)
  4464.    ;
  4465.  
  4466.    begin:     set_dta  buffer            ; see Function 1AH
  4467.               open     fcb               ; see Function 0FH
  4468.               mov      fcb[record_size],28 ; set record size
  4469.    get_char:  display  prompt1           ; see Function 09H
  4470.               read_kbd_and_echo          ; see Function 01H
  4471.               cmp      al,0DH            ; just a carriage return?
  4472.               je       all_done          ; yes, go home
  4473.               sub      al,41H            ; convert ASCII
  4474.                                          ; code to record #
  4475.               mov      fcb[relative_record],al
  4476.                                          ; set relative record
  4477.               display  crlf              ; see Function 09H
  4478.               read_ran fcb               ; THIS FUNCTION
  4479.               display  buffer            ; see Function 09H
  4480.               display  crlf              ; see Function 09H
  4481.               display  prompt2           ; see Function 09H
  4482.               get_string 27,reply        ; see Function 0AH
  4483.               display  crlf              ; see Function 09H
  4484.               cmp      reply[1],0        ; was anything typed
  4485.                                          ; besides CR?
  4486.               je       get_char          ; no
  4487.                                          ; get another char.
  4488.               xor      bx,bx             ; to load a byte
  4489.               mov      bl,reply[1]       ; use reply length as
  4490.                                          ; counter
  4491.               move_string blanks,buffer,26 ; see chapter end
  4492.               move_string reply[2],buffer,bx ; see chapter end
  4493.               write_ran fcb              ; THIS FUNCTION
  4494.               jmp      get_char          ; get another character
  4495.    all_done:  close    fcb               ; see Function 10H
  4496.  
  4497.  
  4498.  ────────────────────────────────────────────────────────────────────────────
  4499.  Get File Size (Function 23H)
  4500.  ────────────────────────────────────────────────────────────────────────────
  4501.  
  4502.    Call:
  4503.  
  4504.    AH = 23H
  4505.    DS:DX
  4506.      Pointer to unopened FCB
  4507.  
  4508.    Return:
  4509.  
  4510.    AL
  4511.      00H = Directory entry found
  4512.      FFH = No directory entry found
  4513.  
  4514.  
  4515.    Comments:
  4516.  
  4517.    Function 23H returns the size of a specified file. DX must contain the
  4518.    offset (from the segment address in DS) of an unopened FCB.
  4519.  
  4520.    If there is a directory entry that matches the specified file, MS-DOS
  4521.    divides the File Size field (offset 10H) of the directory entry by the
  4522.    Record Size field (offset 0EH) of the FCB, puts the result in the Relative
  4523.    Record field (offset 21H) of the FCB, and returns 0 in AL.
  4524.  
  4525.    You must set the Record Size field of the FCB to the correct value before
  4526.    calling this function. If the Record Size field is not an even divisor of
  4527.    the File Size field, the value set in the Relative Record field is rounded
  4528.    up, yielding a value larger than the actual number of records.
  4529.  
  4530.    If this call does not find a matching directory, AL returns FFH.
  4531.  
  4532.    Macro Definition:
  4533.  
  4534.    file_size  macro  fcb
  4535.               mov    dx,offset fcb
  4536.               mov    ah,23H
  4537.               int    21H
  4538.               endm
  4539.  
  4540.    Example:
  4541.  
  4542.    The following program prompts for the name of a file, opens the file to
  4543.    fill in the Record Size field of the FCB, issues a File Size system call,
  4544.    and displays the record length and number of records.
  4545.  
  4546.    fcb           db      37 dup  (?)
  4547.    prompt        db     "File name: $"
  4548.    msg1          db     "Record length:     ",0DH,0AH,"$"
  4549.    msg2          db     "Records:      ",0DH,0AH,"$"
  4550.    crlf          db      0DH,0AH,"$"
  4551.    reply         db      17 dup(?)
  4552.    ;
  4553.    begin:        display prompt            ; see Function 09H
  4554.                  get_string 17,reply       ; see Function 0AH
  4555.                  cmp     reply[1],0        ; just a CR?
  4556.                  jne     get_length        ; no, keep going
  4557.                  jmp     all_done          ; yes, go home
  4558.    get_length:   display crlf              ; see Function 09H
  4559.                  parse   reply[2],fcb      ; see Function 29H
  4560.                  open    fcb               ; see Function 0FH
  4561.                  file_size fcb             ; THIS FUNCTION
  4562.                  mov     ax,word ptr fcb[33] ; get record length
  4563.                  convert ax,10,msg2[9]     ; see end of chapter
  4564.                  mov     ax,word ptr fcb[14] ;  get record number
  4565.                  convert ax,10,msg1[15]    ; see end of chapter
  4566.                  display msg1              ; see Function 09H
  4567.                  display msg2              ; see Function 09H
  4568.    all_done:     close   fcb               ; see Function 10H
  4569.  
  4570.  
  4571.  ────────────────────────────────────────────────────────────────────────────
  4572.  Set Relative Record (Function 24H)
  4573.  ────────────────────────────────────────────────────────────────────────────
  4574.  
  4575.    Call:
  4576.  
  4577.    AH = 24H
  4578.    DS:DX
  4579.      Pointer to opened FCB
  4580.  
  4581.    Return:
  4582.  
  4583.    None
  4584.    AL=00H
  4585.     Relative Record field is modified in FCB.
  4586.  
  4587.  
  4588.    Comments:
  4589.  
  4590.    Function 24H sets the Relative Record field (offset 21H) to the file
  4591.    address specified by the Current Block field (offset 0CH) and Current
  4592.    Record field (offset 20H). DX must contain the offset (from the segment
  4593.    address in DS) of an opened FCB. You use this call to set the file pointer
  4594.    before a Random Read or Write (Functions 21H, 22H, 27H, or 28H).
  4595.  
  4596.    Macro Definition:
  4597.  
  4598.    set_relative_record  macro  fcb
  4599.                         mov    dx,offset fcb
  4600.                         mov    ah,24H
  4601.                         int    21H
  4602.                         endm
  4603.  
  4604.    Example:
  4605.  
  4606.    The following program copies a file using the Random Block Read and Random
  4607.    Block Write system calls. It speeds the copy by setting the record length
  4608.    equal to the file size and the record count to 1, and by using a buffer of
  4609.    32 kilobytes. It positions the file pointer by setting the Current Record
  4610.    field (offset 20H) to 1 and using Function 24H (Set Relative Record) to
  4611.    make the Relative Record field (offset 21H) point to the same record that
  4612.    the combination of the Current Block field (offset 0CH) and Current Record
  4613.    field (offset 20H) points to.
  4614.  
  4615.    current_record  equ   20H        ; offset of Current Record
  4616.                                     ; field of FCB
  4617.    fil_size        equ   10H        ; offset of File Size
  4618.    ;                                 field of FCB
  4619.    fcb       db      37 dup (?)
  4620.    filename  db      17 dup(?)
  4621.    prompt1   db     "File to copy: $"  ; see Function 09H for
  4622.    prompt2   db     "Name of copy: $"  ; explanation of $
  4623.    crlf      db      0DH,0AH,"$"
  4624.    file_length  dw   ?
  4625.    buffer    db      32767 dup(?)
  4626.    ;
  4627.    begin:    set_dta  buffer              ; see Function 1AH
  4628.              display  prompt1             ; see Function 09H
  4629.              get_string  15,filename      ; see Function 0AH
  4630.              display  crlf                ; see Function 09H
  4631.              parse    filename[2],fcb     ; see Function 29H
  4632.              open     fcb                 ; see Function 0FH
  4633.              mov      fcb[current_record],0 ; set Current Record
  4634.                                           ; field
  4635.              set_relative_record  fcb     ; THIS FUNCTION
  4636.              mov      ax,word ptr fcb[fil_size] ; get file size
  4637.              mov      file_length,ax      ; save it for
  4638.                                           ; ran_block_write
  4639.              ran_block_read  fcb,1,ax     ; see Function 27H
  4640.              display  prompt2             ; see Function 09H
  4641.              get_string  15,filename      ; see Function 0AH
  4642.              display  crlf                ; see Function 09H
  4643.              parse    filename[2],fcb     ; see Function 29H
  4644.              create   fcb                 ; see Function 16H
  4645.              mov      fcb[current_record],0 ; set Current Record
  4646.                                           ; field
  4647.              set_relative_record  fcb     ; THIS FUNCTION
  4648.              mov      ax,file_length      ; get original file
  4649.              ran_block_write  fcb,1,ax    ; see Function 28H
  4650.              close    fcb                 ; see Function 10H
  4651.  
  4652.  
  4653.  ────────────────────────────────────────────────────────────────────────────
  4654.  Set Interrupt Vector (Function 25H)
  4655.  ────────────────────────────────────────────────────────────────────────────
  4656.  
  4657.    Call:
  4658.  
  4659.    AH = 25H
  4660.    AL
  4661.      Interrupt number
  4662.    DS:DX
  4663.      Pointer to interrupt-handling
  4664.      routine
  4665.  
  4666.    Return:
  4667.  
  4668.    None
  4669.  
  4670.  
  4671.    Comments:
  4672.  
  4673.    Function 25H sets the address in the interrupt vector table for the
  4674.    specified interrupt.
  4675.  
  4676.    AL must contain the number of the interrupt. DX must contain the offset
  4677.    (to the segment address in DS) of the interrupt-handling routine.
  4678.  
  4679.    To avoid compatibility problems, programs should never set an interrupt
  4680.    vector directly and should never use Interrupt 25H to read directly from
  4681.    memory. To get a vector, use Function 35H (Get Interrupt Vector), and to
  4682.    set a vector, use Function 25H, unless your program must be compatible
  4683.    with MS-DOS versions earlier than 2.0.
  4684.  
  4685.    Macro Definition:
  4686.  
  4687.    set_vector  macro  interrupt,handler_start
  4688.                mov    al,interrupt
  4689.                mov    dx,offset handler_start
  4690.                mov    ah,25H
  4691.                endm
  4692.  
  4693.    Example:
  4694.  
  4695.    Because interrupts tend to be machine-specific, no example is shown.
  4696.  
  4697.  
  4698.  ────────────────────────────────────────────────────────────────────────────
  4699.  Create New PSP (Function 26H)
  4700.  ────────────────────────────────────────────────────────────────────────────
  4701.  
  4702.    Call:
  4703.  
  4704.    AH = 26H
  4705.    DX
  4706.      Segment address of new PSP
  4707.  
  4708.    Return:
  4709.  
  4710.    None
  4711.  
  4712.  
  4713.    Comments:
  4714.  
  4715.    This function request has been superseded. Use Function 4B00H or 4B03H
  4716.    (Load and Execute Program or Overlay) to run a child process, unless your
  4717.    program must be compatible with MS-DOS versions earlier than 2.0.
  4718.  
  4719.    Function 26H creates a new Program Segment Prefix. DX must contain the
  4720.    segment address where the new PSP is to be created.
  4721.  
  4722.    Macro Definition:
  4723.  
  4724.    create_psp  macro  seg_addr
  4725.                mov    dx,seg_addr
  4726.                mov    ah,26H
  4727.                endm
  4728.  
  4729.    Example:
  4730.  
  4731.    Because Functions 4B00H (Load and Execute Program) and 4B03H (Load
  4732.    Overlay) have superseded this function request, no example is shown.
  4733.  
  4734.  
  4735.  ────────────────────────────────────────────────────────────────────────────
  4736.  Random Block Read (Function 27H)
  4737.  ────────────────────────────────────────────────────────────────────────────
  4738.  
  4739.    Call:
  4740.  
  4741.    AH = 27H
  4742.    DS:DX
  4743.      Pointer to opened FCB
  4744.    CX
  4745.      Number of blocks to read
  4746.  
  4747.    Return:
  4748.  
  4749.    AL
  4750.      0 = Read completed successfully
  4751.      1 = End of file, empty record
  4752.      2 = DTA too small
  4753.      3 = End of file, partial record
  4754.    CX
  4755.      Number of blocks read
  4756.  
  4757.  
  4758.    Comments:
  4759.  
  4760.    Function 27H reads one or more records from a specified file to the Disk
  4761.    Transfer Address. DX must contain the offset (to the segment address in
  4762.    DS) of an opened FCB. CX must contain the number of records to read.
  4763.    Reading starts at the record specified by the Relative Record field
  4764.    (offset 21H); you must set this field with Function 24H (Set Relative
  4765.    Record) before calling this function.
  4766.  
  4767.    DOS calculates the number of bytes to read by multiplying the value in CX
  4768.    by the Record Size field (offset 0EH) of the FCB.
  4769.  
  4770.    CX returns the number of records read. The Current Block field (offset
  4771.    0CH), Current Record field (offset 20H), and Relative Record field (offset
  4772.    21H) are set to address the next record.
  4773.  
  4774.    If you call this function with CX=0, no records are read. AL returns a
  4775.    code that describes the processing:
  4776.  
  4777.    Code               Meaning
  4778.    ──────────────────────────────────────────────────────────────────────────
  4779.    0                  Read completed successfully
  4780.  
  4781.    1                  End-of-file; no data in the record
  4782.  
  4783.    2                  Not enough room at the Disk Transfer Address to read
  4784.                       one record; read canceled
  4785.  
  4786.    3                  End-of-file; a partial record was read and padded to
  4787.    ──────────────────────────────────────────────────────────────────────────
  4788.  
  4789.    Macro Definition:
  4790.  
  4791.    ran_block_read  macro  fcb,count,rec_size
  4792.                    mov    dx,offset fcb
  4793.                    mov    cx,count
  4794.                    mov    word ptr fcb[14],rec_size
  4795.                    mov    ah,27H
  4796.                    int    21H
  4797.                    endm
  4798.  
  4799.    Example:
  4800.  
  4801.    The following program copies a file by using Function 27H (Random Block
  4802.    Read). This program speeds the copy process by specifying a record count
  4803.    of 1 and a record length equal to the file size, and by using a buffer of
  4804.    32 kilobytes; the file is read as a single record (compare to the sample
  4805.    program for Function 28H that specifies a record length of 1 and a record
  4806.    count equal to the file size).
  4807.  
  4808.    current_record  equ  20H  ; offset of Current Record field
  4809.    fil_size        equ  10H  ; offset of File Size field
  4810.    ;
  4811.    fcb       db      37 dup (?)
  4812.    filename  db      17 dup(?)
  4813.    prompt1   db     "File to copy: $"   ; see Function 09H for
  4814.    prompt2   db     "Name of copy: $"   ; explanation of $
  4815.    crlf      db      0DH,0AH,"$"
  4816.    file_length  dw   ?
  4817.    buffer    db      32767 dup(?)
  4818.    ;
  4819.  
  4820.  
  4821.  
  4822.    begin:    set_dta    buffer           ; see Function 1AH
  4823.              display    prompt1          ; see Function 09H
  4824.              get_string 15,filename      ; see Function 0AH
  4825.              display    crlf             ; see Function 09H
  4826.              parse      filename[2],fcb  ; see Function 29H
  4827.              open       fcb              ; see Function 0FH
  4828.              mov        fcb[current_record],0  ; set Current
  4829.                                          ; Record field
  4830.              set_relative_record fcb     ; see Function 24H
  4831.              mov        ax, word ptr fcb[fil_size]
  4832.                                          ; get file size
  4833.              mov        file_length,ax   ; save it
  4834.              ran_block_read  fcb,1,ax    ; THIS FUNCTION
  4835.              display    prompt2          ; see Function 09H
  4836.              get_string 15,filename      ; see Function 0AH
  4837.              display    crlf             ; see Function 09H
  4838.              parse      filename[2],fcb  ; see Function 29H
  4839.              create     fcb              ; see Function 16H
  4840.              mov        fcb[current_record],0; set current
  4841.                                          ; Record field
  4842.              set_relative_record fcb     ; see Function 24H
  4843.              ran_block_write  fcb,1,ax   ; see Function 28H
  4844.              close      fcb              ; see Function 10H
  4845.  
  4846.  
  4847.  ────────────────────────────────────────────────────────────────────────────
  4848.  Random Block Write (Function 28H)
  4849.  ────────────────────────────────────────────────────────────────────────────
  4850.  
  4851.    Call:
  4852.  
  4853.    AH = 28H
  4854.    DS:DX
  4855.      Pointer to opened FCB
  4856.    CX
  4857.      Number of blocks to write
  4858.      (0 = set File Size field)
  4859.  
  4860.    Return:
  4861.  
  4862.    AL
  4863.      00H = Write completed successfully
  4864.      01H = Disk full
  4865.      02H = End of segment
  4866.    CX
  4867.      Number of blocks written
  4868.  
  4869.  
  4870.    Comments:
  4871.  
  4872.    Function 28H writes one or more records to a specified file from the Disk
  4873.    Transfer Address. DX must contain the offset (to the segment address in
  4874.    DS) of an opened FCB; CX must contain either the number of records to
  4875.    write or 0.
  4876.  
  4877.    If CX is not 0, the specified number of records is written to the file,
  4878.    starting at the record specified in the Relative Record field (offset 21H)
  4879.    of the FCB. If CX is 0, no records are written, but MS-DOS sets the File
  4880.    Size field (offset 10H) of the directory entry to the value in the
  4881.    Relative Record field (offset 21H) of the FCB. To satisfy this new file
  4882.    size, disk allocation units are allocated or released, as required.
  4883.  
  4884.    MS-DOS calculates the number of bytes to write by multiplying the value in
  4885.    CX by the Record Size field (offset 0EH) of the FCB. CX returns the number
  4886.    of records written; the Current Block field (offset 0CH), Current Record
  4887.    field (offset 20H), and Relative Record (offset 21H) field are set to
  4888.    address the next record. AL returns a code that describes the processing:
  4889.  
  4890.    Code               Meaning
  4891.    ──────────────────────────────────────────────────────────────────────────
  4892.    0                  Write completed successfully
  4893.  
  4894.    1                  Disk full. No records written
  4895.  
  4896.    2                  Not enough room at the Disk Transfer Address to write
  4897.    ──────────────────────────────────────────────────────────────────────────
  4898.  
  4899.    Macro Definition:
  4900.  
  4901.    ran_block_write  macro  fcb,count,rec_size
  4902.                     mov    dx,offset fcb
  4903.                     mov    cx,count
  4904.                     mov    word ptr fcb[14],rec_size
  4905.                     mov    ah,28H
  4906.                     int    21H
  4907.                     endm
  4908.  
  4909.    Example:
  4910.  
  4911.    The following program copies a file using Function 27H (Random Block
  4912.    Read) and Function 28H (Random Block Write). This program speeds the copy
  4913.    process by specifying a record count equal to the file size and a record
  4914.    length of 1, and by using a buffer of 32 kilobytes. The file is copied
  4915.    quickly with one disk access each to read and write (compare to the sample
  4916.    program of Function 27H, which specifies a record count of 1 and a record
  4917.    length equal to file size).
  4918.  
  4919.    current_record  equ  20H   ; offset of Current Record field
  4920.    fil_size        equ  10H   ; offset of File Size field
  4921.    ;
  4922.    fcb       db      37 dup (?)
  4923.    filename  db      17 dup(?)
  4924.    prompt1   db     "File to copy: $"   ; see Function 09H for
  4925.    prompt2   db     "Name of copy: $"   ; explanation of $
  4926.    crlf      db      0DH,0AH,"$"
  4927.    num_recs  dw      ?
  4928.    buffer    db      32767 dup(?)
  4929.    ;
  4930.  
  4931.  
  4932.  
  4933.    begin:    set_dta    buffer      ; see Function 1AH
  4934.              display    prompt1     ; see Function 09H
  4935.              get_string 15,filename ; see Function 0AH
  4936.              display    crlf        ; see Function 09H
  4937.              parse      filename[2],fcb  ; see Function 29H
  4938.              open       fcb              ; see Function 0FH
  4939.              mov        fcb[current_record],0; set Current
  4940.                                          Record field
  4941.              set_relative_record fcb     ; see Function 24H
  4942.              mov        ax, word ptr fcb[fil_size]
  4943.                                          ; get file size
  4944.              mov        num_recs,ax      ; save it
  4945.              ran_block_read  fcb,num_recs,1  ; THIS FUNCTION
  4946.              display    prompt2          ; see Function 09H
  4947.              get_string 15,filename      ; see Function 0AH
  4948.              display    crlf             ; see Function 09H
  4949.              parse      filename[2],fcb  ; see Function 29H
  4950.              create     fcb              ; see Function 16H
  4951.              mov        fcb[current_record],0  ; set Current
  4952.                                          ; Record field
  4953.              set_relative_record fcb     ; see Function 24H
  4954.              ran_block_write fcb,num_recs,1 ; see Function 28H
  4955.              close      fcb              ; see Function 10H
  4956.  
  4957.  
  4958.  ────────────────────────────────────────────────────────────────────────────
  4959.  Parse File Name (Function 29H)
  4960.  ────────────────────────────────────────────────────────────────────────────
  4961.  
  4962.    Call:
  4963.  
  4964.    AH = 29H
  4965.    AL
  4966.      Controls parsing (see text)
  4967.    DS:SI
  4968.      Pointer to string to parse
  4969.    ES:DI
  4970.      Pointer to buffer for unopened FCB
  4971.  
  4972.    Return:
  4973.  
  4974.    AL
  4975.      00H        = No wildcard characters
  4976.      01H        = Wildcard characters used
  4977.      FFH        = Drive letter invalid
  4978.    DS:SI
  4979.      Pointer to first byte past
  4980.      string that was parsed
  4981.    ES:DI
  4982.      Pointer to unopened FCB
  4983.  
  4984.  
  4985.    Comments:
  4986.  
  4987.    Function 29H parses a string for a filename of the form
  4988.    drive:filename.extension. SI must contain the offset (to the segment
  4989.    address in DS) of the string to parse; DI must contain the offset (to the
  4990.    segment address in ES) of an area of memory large enough to hold an
  4991.    unopened FCB. If the string contains a valid filename, this call creates a
  4992.    corresponding unopened FCB at ES:DI.
  4993.  
  4994.    AL controls the parsing. Bits 4-7 must be 0; bits 0-3 have the following
  4995.    meaning:
  4996.  
  4997.    Table 1.20
  4998.    Bit Values for Function 29H
  4999. ╓┌─┌───────────┌────────────┌────────────────────────────────────────────────╖
  5000.    Bit         Value        Meaning
  5001.    ──────────────────────────────────────────────────────────────────────────
  5002.    0           0            Stops parsing if a file separator is encountered
  5003.  
  5004.                1            Ignores leading separators
  5005.  
  5006.    1           0            Sets the drive number in the FCB to 0 (current
  5007.                             drive) if the string does not contain a drive
  5008.                             number
  5009.  
  5010.                1            Leaves the drive number in the FCB unchanged if
  5011.                             the string does not contain a drive number
  5012.  
  5013.    2           0            Sets the filename in the FCB to eight blanks if
  5014.                             the string does not contain a filename
  5015.  
  5016.                1            Leaves the filename in the FCB unchanged if the
  5017.                             string does not contain a filename
  5018.  
  5019.    3           0            Sets the extension in the FCB to three blanks if
  5020.                             the string does not contain an extension
  5021.    Bit         Value        Meaning
  5022.    ──────────────────────────────────────────────────────────────────────────
  5023.                            the string does not contain an extension
  5024.  
  5025.                1            Leaves the extension in the FCB unchanged if the
  5026.    ──────────────────────────────────────────────────────────────────────────
  5027.  
  5028.  
  5029.    If the string contains a filename or extension that includes an asterisk
  5030.    (*), all remaining characters in the name or extension are set to question
  5031.    marks (?).
  5032.  
  5033.    Filename Separators:
  5034.  
  5035.  
  5036.  
  5037.     :  ;  .  ,  =  +  /  "  [  ]  \  <  >  |  space  tab
  5038.  
  5039.    Filename terminators include all the filename separators, plus any control
  5040.    character. A filename cannot contain a filename terminator, since, if the
  5041.    call encounters one, parsing stops.
  5042.  
  5043.    If the string contains a valid filename:
  5044.  
  5045.    ■  AL returns 1 if the filename or extension contains a wildcard character
  5046.       (* or ?); AL returns 0 if neither the filename nor extension contains a
  5047.       wildcard character.
  5048.  
  5049.    ■  DS:SI points to the first character following the parsed string.
  5050.  
  5051.    ■  ES:DI points to the first byte of the unopened FCB.
  5052.  
  5053.    If the drive letter is invalid, AL returns FFH. If the string does not
  5054.    contain a valid filename, ES:DI+1 points to a blank.
  5055.  
  5056.    Macro Definition:
  5057.  
  5058.    parse macro string,fcb
  5059.          mov   si,offset string
  5060.          mov   di,offset fcb
  5061.          push  es
  5062.          push  ds
  5063.          pop   es
  5064.          mov   al,0FH        ; bits 0-3 on
  5065.          mov   ah,29H
  5066.          int   21H
  5067.          pop   es
  5068.          endm
  5069.  
  5070.    Example:
  5071.  
  5072.    The following program verifies the existence of the file named in reply to
  5073.    the prompt.
  5074.  
  5075.    fcb           db      37 dup (?)
  5076.    prompt        db     "Filename: $"
  5077.    reply         db      17 dup(?)
  5078.    yes           db     "File exists",0DH,0AH,"$"
  5079.    no            db     "File does not exist",0DH,0AH,"$"
  5080.                  crlf    db 0DH,0AH,"$"
  5081.    ;
  5082.    begin:        display    prompt        ; see Function 09H
  5083.                  get_string 15,reply      ; see Function 0AH
  5084.                  parse      reply[2],fcb  ; THIS FUNCTION
  5085.                  display    crlf          ; see Function 09H
  5086.                  search_first  fcb        ; see Function 11H
  5087.                  cmp        al,0FFH       ; dir. entry found?
  5088.                  je         not_there     ; no
  5089.                  display    yes           ; see Function 09H
  5090.                  jmp        return
  5091.    not_there:    display    no
  5092.  
  5093.  
  5094.  ────────────────────────────────────────────────────────────────────────────
  5095.  Get Date (Function 2AH)
  5096.  ────────────────────────────────────────────────────────────────────────────
  5097.  
  5098.    Call:
  5099.  
  5100.    AH = 2AH
  5101.  
  5102.    Return:
  5103.  
  5104.    CX
  5105.      Year (1980-2099)
  5106.    DH
  5107.      Month (1-12)
  5108.    DL
  5109.      Day (1-31)
  5110.    AL
  5111.      Day of week (0=Sun., 6=Sat.)
  5112.  
  5113.  
  5114.    Comments:
  5115.  
  5116.    Function 2AH returns the current date set in the operating system as
  5117.    binary numbers in CX and DX:
  5118.  
  5119.    Register           Contents
  5120.    ──────────────────────────────────────────────────────────────────────────
  5121.    CX                 Year (1980-2099)
  5122.    DH                 Month (1=January, 2=February, etc.)
  5123.    DL                 Day of month (1-31)
  5124.    AL                 Day of week (0=Sunday, 1=Monday, etc.)
  5125.    ──────────────────────────────────────────────────────────────────────────
  5126.  
  5127.    Macro Definition:
  5128.  
  5129.    get_date  macro
  5130.              mov   ah,2AH
  5131.              int   21H
  5132.              endm
  5133.  
  5134.    Example:
  5135.  
  5136.    The following program gets the date, increments the day, increments the
  5137.    month or year, if necessary, and sets the new date.
  5138.  
  5139.    month      db      31,28,31,30,31,30,31,31,30,31,30,31
  5140.    ;
  5141.    begin:     get_date            ; THIS FUNCTION
  5142.               inc    dl           ; increment day
  5143.               xor    bx,bx        ; so BL can be used as index
  5144.               mov    bl,dh        ; move month to index register
  5145.               dec    bx           ; month table starts with 0
  5146.               cmp    dl,month[bx] ; past end of month?
  5147.               jle    month_ok     ; no, set new date
  5148.               mov    dl,1         ; yes, set day to 1
  5149.               inc    dh           ; and increment month
  5150.               cmp    dh,12        ; past end of year?
  5151.               jle    month_ok     ; no, set new date
  5152.               mov    dh,1         ; yes, set month to 1
  5153.               inc    cx           ; increment year
  5154.    month_ok:  set_date cx,dh,dl   ; see Function 2AH
  5155.  
  5156.  
  5157.  ────────────────────────────────────────────────────────────────────────────
  5158.  Set Date (Function 2BH)
  5159.  ────────────────────────────────────────────────────────────────────────────
  5160.  
  5161.    Call:
  5162.  
  5163.    AH = 2BH
  5164.    CX
  5165.      Year (1980-2099)
  5166.    DH
  5167.      Month (1-12)
  5168.    DL
  5169.      Day (1-31)
  5170.  
  5171.    Return:
  5172.  
  5173.    AL
  5174.      00H        = Date was valid
  5175.      FFH        = Date was invalid
  5176.  
  5177.  
  5178.    Comments:
  5179.  
  5180.    Function 2BH sets the date in the operating system (and in the CMOS clock,
  5181.    if one exists). Registers CX and DX must contain a valid date in binary:
  5182.  
  5183.    Register           Contents
  5184.    ──────────────────────────────────────────────────────────────────────────
  5185.    CX                 Year (1980-2099)
  5186.    DH                 Month (1=January, 2=February, etc.)
  5187.    DL                 Day of month (1-31)
  5188.    ──────────────────────────────────────────────────────────────────────────
  5189.  
  5190.    If the date is valid, the call sets it and AL returns 0. If the date is
  5191.    not valid, the function aborts and AL returns FFH.
  5192.  
  5193.    Macro Definition:
  5194.  
  5195.    set_date  macro  year,month,day
  5196.              mov    cx,year
  5197.              mov    dh,month
  5198.              mov    dl,day
  5199.              mov    ah,2BH
  5200.              int    21H
  5201.              endm
  5202.  
  5203.    Example:
  5204.  
  5205.    The following program gets the date, increments the day, increments the
  5206.    month or year, if necessary, and sets the new date.
  5207.  
  5208.    month      db      31,28,31,30,31,30,31,31,30,31,30,31
  5209.    ;
  5210.    begin:     get_date            ; see Function 2AH
  5211.               inc    dl           ; increment day
  5212.               xor    bx,bx        ; so BL can be used as index
  5213.               mov    bl,dh        ; move month to index register
  5214.               dec    bx           ; month table starts with 0
  5215.               cmp    dl,month[bx] ; past end of month?
  5216.               jle    month_ok     ; no, set the new date
  5217.               mov    dl,1         ; yes, set day to 1
  5218.               inc    dh           ; and increment month
  5219.               cmp    dh,12        ; past end of year?
  5220.               jle    month_ok     ; no, set the new date
  5221.               mov    dh,1         ; yes, set the month to 1
  5222.               inc    cx           ; increment year
  5223.    month_ok:  set_date cx,dh,dl   ; THIS FUNCTION
  5224.  
  5225.  
  5226.  ────────────────────────────────────────────────────────────────────────────
  5227.  Get Time (Function 2CH)
  5228.  ────────────────────────────────────────────────────────────────────────────
  5229.  
  5230.    Call:
  5231.  
  5232.    AH = 2CH
  5233.  
  5234.    Return:
  5235.  
  5236.    CH
  5237.      Hour (0-23)
  5238.    CL
  5239.      Minutes (0-59)
  5240.    DH
  5241.      Seconds (0-59)
  5242.    DL
  5243.      Hundredths (0-99)
  5244.  
  5245.  
  5246.    Comments:
  5247.  
  5248.    Function 2CH returns the current time set in the operating system (and
  5249.    sets the CMOS clock, if one exists) as binary numbers in CX and DX:
  5250.  
  5251.    Register           Contents
  5252.    ──────────────────────────────────────────────────────────────────────────
  5253.    CH                 Hour (0-23)
  5254.    CL                 Minutes (0-59)
  5255.    DH                 Seconds (0-59)
  5256.    DL                 Hundredths of a second (0-99)
  5257.    ──────────────────────────────────────────────────────────────────────────
  5258.  
  5259.    Depending on how your hardware keeps time, some of these fields may be
  5260.    irrelevant. As an example, many CMOS clock chips do not resolve more than
  5261.    seconds. In such a case, the value in DL will probably always be 0.
  5262.  
  5263.    Macro Definition:
  5264.  
  5265.    get_time  macro
  5266.              mov   ah,2CH
  5267.              int   21H
  5268.              endm
  5269.  
  5270.    Example:
  5271.  
  5272.    The following program displays the time continuously until you press any
  5273.    key.
  5274.  
  5275.    time         db    "00:00:00.00",0DH,"$"
  5276.    ;
  5277.    begin:       get_time               ; THIS FUNCTION
  5278.                 byte_to_dec ch,time    ; see end of chapter
  5279.                 byte_to_dec cl,time[3] ; see end of chapter
  5280.                 byte_to_dec dh,time[6] ; see end of chapter
  5281.                 byte_to_dec dl,time[9] ; see end of chapter
  5282.                 display time           ; see Function 09H
  5283.                 check_kbd_status       ; see Function 0BH
  5284.                 cmp     al,0FFH        ; has a key been pressed?
  5285.                 je      return         ; yes, terminate
  5286.                 jmp     begin          ; no, display time
  5287.  
  5288.  
  5289.  ────────────────────────────────────────────────────────────────────────────
  5290.  Set Time (Function 2DH)
  5291.  ────────────────────────────────────────────────────────────────────────────
  5292.  
  5293.    Call:
  5294.  
  5295.    AH = 2DH
  5296.    CH
  5297.      Hour (0-23)
  5298.    CL
  5299.      Minutes (0-59)
  5300.    DH
  5301.      Seconds (0-59)
  5302.    DL
  5303.      Hundredths (0-99)
  5304.  
  5305.    Return:
  5306.  
  5307.    AL
  5308.      00H        = Time was valid
  5309.      FFH        = Time was invalid
  5310.  
  5311.  
  5312.    Comments:
  5313.  
  5314.    Function 2DH sets the time in the operating system. Registers CX and DX
  5315.    must contain a valid time in binary:
  5316.  
  5317.    Register           Contents
  5318.    ──────────────────────────────────────────────────────────────────────────
  5319.    CH                 Hour (0-23)
  5320.    CL                 Minutes (0-59)
  5321.    DH                 Seconds (0-59)
  5322.    DL                 Hundredths of a second (0-99)
  5323.    ──────────────────────────────────────────────────────────────────────────
  5324.  
  5325.    Depending on how your hardware keeps time, some of these fields may be
  5326.    irrelevant. As an example, many CMOS clock chips do not resolve more than
  5327.    seconds. In such a case, the value in DL will not be relevant.
  5328.  
  5329.    If the time is valid, the call sets it and AL returns 0. If the time is
  5330.    not valid, the function aborts and AL returns FFH.
  5331.  
  5332.    Macro Definition:
  5333.  
  5334.    set_time  macro  hour,minutes,seconds,hundredths
  5335.              mov    ch,hour
  5336.              mov    cl,minutes
  5337.              mov    dh,seconds
  5338.              mov    dl,hundredths
  5339.              mov    ah,2DH
  5340.              int    21H
  5341.              endm
  5342.  
  5343.    Example:
  5344.  
  5345.    The following program sets the system clock to 0 and displays the time
  5346.    continuously. When you type a character, the display freezes; when you
  5347.    type another character, the clock is reset to 0 and the display starts
  5348.    again.
  5349.  
  5350.    time          db  "00:00:00.00",0DH,0AH,"$"
  5351.    ;
  5352.    begin:        set_time  0,0,0,0       ; THIS FUNCTION
  5353.    read_clock:   get_time                ; see Function 2CH
  5354.                  byte_to_dec  ch,time    ; see end of chapter
  5355.                  byte_to_dec  cl,time[3] ; see end of chapter
  5356.                  byte_to_dec  dh,time[6] ; see end of chapter
  5357.                  byte_to_dec  dl,time[9] ; see end of chapter
  5358.                  display  time           ; see Function 09H
  5359.                  dir_console_io 0FFH     ; see Function 06H
  5360.                  cmp      al,00H         ; was a char. typed?
  5361.                  jne      stop           ; yes, stop the timer
  5362.                  jmp      read_clock     ; no keep timer on
  5363.    stop:         read_kbd                ; see Function 08H
  5364.                  jmp      begin          ; keep displaying time
  5365.  
  5366.  
  5367.  ────────────────────────────────────────────────────────────────────────────
  5368.  Set/Reset Verify Flag (Function 2EH)
  5369.  ────────────────────────────────────────────────────────────────────────────
  5370.  
  5371.    Call:
  5372.  
  5373.    AH = 2EH
  5374.    AL
  5375.      0 = Do not verify
  5376.      1 = Verify
  5377.  
  5378.    Return:
  5379.  
  5380.    None
  5381.  
  5382.  
  5383.    Comments:
  5384.  
  5385.    Function 2EH tells MS-DOS whether or not to verify each disk write. If AL
  5386.    is 1, verify is on; if AL is 0, verify is off. MS-DOS checks this flag
  5387.    each time it writes to a disk.
  5388.  
  5389.    The flag is normally off; you may wish to turn it on when writing critical
  5390.    data to disk. Because disk errors are rare and verification slows writing,
  5391.    you will probably want to leave it off at other times. You can check the
  5392.    setting with Function 54H (Get Verify State).
  5393.  
  5394.    Macro Definition:
  5395.  
  5396.    verify  macro  switch
  5397.            mov    al,switch
  5398.            mov    ah,2EH
  5399.            int    21H
  5400.            endm
  5401.  
  5402.    Example:
  5403.  
  5404.    The following program copies the contents of a single-sided disk in drive
  5405.    A to the disk in drive B, verifying each write. It uses a buffer of 32
  5406.    kilobytes.
  5407.  
  5408.    on           equ   1
  5409.    off          equ   0
  5410.    ;
  5411.    prompt       db   "Source in A, target in B",0DH,0AH
  5412.                 db   "Any key to start. $"
  5413.    first        dw    0
  5414.    buffer       db    60 dup (512 dup(?))   ; 60 sectors
  5415.    ;
  5416.    begin:       display prompt              ; see Function 09H
  5417.                 read_kbd                    ; see Function 08H
  5418.                 verify on                   ; THIS FUNCTION
  5419.                 mov    cx,6                 ; copy 60 sectors
  5420.                                             ; 6 times
  5421.    copy:        push   cx                   ; save counter
  5422.                 abs_disk_read  0,buffer,60,first ; see Int 25H
  5423.                 abs_disk_write  1,buffer,64,first ; see Int 26H
  5424.                 add    first,60             ; do next 60 sectors
  5425.                 pop    cx                   ; restore counter
  5426.                 loop   copy                 ; do it again
  5427.                 verify off                  ; THIS FUNCTION
  5428.  
  5429.  
  5430.  ────────────────────────────────────────────────────────────────────────────
  5431.  Get Disk Transfer Address (Function 2FH)
  5432.  ────────────────────────────────────────────────────────────────────────────
  5433.  
  5434.    Call:
  5435.  
  5436.    AH = 2FH
  5437.  
  5438.    Return:
  5439.  
  5440.    ES:BX
  5441.      Pointer to Disk Transfer Address
  5442.  
  5443.  
  5444.    Comments:
  5445.  
  5446.    Function 2FH returns the segment address of the current Disk Transfer
  5447.    Address in ES and the offset in BX.
  5448.  
  5449.    Macro Definition:
  5450.  
  5451.    get_dta  macro
  5452.             mov    ah,2fH
  5453.             int    21H
  5454.             endm
  5455.  
  5456.    Example:
  5457.  
  5458.    The following program displays the current Disk Transfer Address in the
  5459.    form: segment:offset.
  5460.  
  5461.    message   db      "DTA --        :    ",0DH,0AH,"$"
  5462.    sixteen   db       10H
  5463.    temp      db       2 dup (?)
  5464.    ;
  5465.    begin:    get_dta                      ; THIS FUNCTION
  5466.              mov    word ptr temp,ex      ; To access each byte
  5467.              convert temp[1],sixteen,message[07H]  ; See end of
  5468.              convert temp,sixteen,message[09H]    ; chapter for
  5469.              convert bh,sixteen,message[0CH]      ; description
  5470.              convert bl,sixteen,message[0EH]      ; of CONVERT
  5471.              display message              ; See Function 09H
  5472.  
  5473.  
  5474.  ────────────────────────────────────────────────────────────────────────────
  5475.  Get MS-DOS Version Number (Function 30H)
  5476.  ────────────────────────────────────────────────────────────────────────────
  5477.  
  5478.    Call:
  5479.  
  5480.    AH = 30H
  5481.  
  5482.    Return:
  5483.  
  5484.    AL
  5485.      Major version number
  5486.    AH
  5487.      Minor version number
  5488.    BH
  5489.      OEM serial number
  5490.    BL:CX
  5491.      24-bit user (serial) number
  5492.  
  5493.  
  5494.    Comments:
  5495.  
  5496.    Function 30H returns the MS-DOS version number. AL returns the major
  5497.    version number; AH returns the minor version number. (For example, MS-DOS
  5498.    3.0 returns 3 in AL and 0 in AH.)
  5499.  
  5500.    If AL returns 0, the MS-DOS version is earlier than 2.0.
  5501.  
  5502.    Macro Definition:
  5503.  
  5504.    get_version  macro
  5505.                 mov    ah,30H
  5506.                 int    21H
  5507.                 endm
  5508.  
  5509.    Example:
  5510.  
  5511.    The following program displays the MS-DOS version if it is 1.28 or
  5512.    greater.
  5513.  
  5514.    message   db      "MS-DOS Version  . ",0DH,0AH,"$"
  5515.    ten       db       0AH                 ; For CONVERT
  5516.    ;
  5517.    begin:    get_version                  ; THIS FUNCTION
  5518.              cmp     al,0                 ; 1.28 or later?
  5519.              jng     return               ; No, go home
  5520.              convert al,ten,message[0FH]  ; See end of chapter
  5521.              convert ah,ten,message[12H]  ; for description
  5522.              display message              ; See Function 9
  5523.  
  5524.  
  5525.  ────────────────────────────────────────────────────────────────────────────
  5526.  Keep Process (Function 31H)
  5527.  ────────────────────────────────────────────────────────────────────────────
  5528.  
  5529.    Call:
  5530.  
  5531.    AH = 31H
  5532.    AL
  5533.      Return code
  5534.    DX
  5535.      Memory size, in paragraphs
  5536.  
  5537.    Return:
  5538.  
  5539.    None
  5540.  
  5541.  
  5542.    Comments:
  5543.  
  5544.    Function 31H makes a program remain resident after it terminates. You can
  5545.    use it to install device-specific interrupt handlers. But unlike Interrupt
  5546.    27H (Terminate But Stay Resident), this function request allows more than
  5547.    64K bytes to remain resident and does not require CS to contain the
  5548.    segment address of the Program Segment Prefix. You should use Function 31H
  5549.    to install a resident program unless your program must be compatible with
  5550.    MS-DOS versions earlier than 2.0.
  5551.  
  5552.    DX must contain the number of paragraphs of memory required by the program
  5553.    (one paragraph = 16 bytes). AL contains an exit code.
  5554.  
  5555.    Be careful when using this function with .exe programs. The value in DX
  5556.    must be the total size to remain resident, not just the size of the code
  5557.    segment which is to remain resident. A typical error is to forget about
  5558.    the 100H-byte program-header-prefix and give a value in DX that doesn't
  5559.    account for the size of this prefix. MS-DOS terminates the current process
  5560.    and tries to set the memory allocation to the number of paragraphs in DX.
  5561.    No other allocation blocks belonging to the process are released.
  5562.  
  5563.    By using Function 4DH (Get Return Code of Child Process), the parent
  5564.    process can retrieve the process's exit code from AL. (You can test this
  5565.    exit code by using the if command with errorlevel.)
  5566.  
  5567.    Macro Definition:
  5568.  
  5569.    keep_process  macro return_code,last_byte
  5570.                  mov   al,return_code
  5571.                  mov   dx,offset last_byte
  5572.                  mov   cl,4
  5573.                  shr   dx,cl
  5574.                  inc   dx
  5575.                  mov   ah,31H
  5576.                  int   21H
  5577.                  endm
  5578.  
  5579.    Example:
  5580.  
  5581.    Because the most common use of this call is to install a machine-specific
  5582.    routine, an example is not shown. The macro definition, however, shows the
  5583.    calling syntax.
  5584.  
  5585.  
  5586.  ────────────────────────────────────────────────────────────────────────────
  5587.  CONTROL+C Check (Function 33H)
  5588.  ────────────────────────────────────────────────────────────────────────────
  5589.  
  5590.    Call:
  5591.  
  5592.    AH = 33H
  5593.    AL
  5594.       0 = Get state of CONTROL+C
  5595.       1 = Set state of CONTROL+C
  5596.       5 = Query DOS boot drive
  5597.    DL (if AL=1)
  5598.       0 = Off
  5599.       1 = On
  5600.  
  5601.    Return:
  5602.  
  5603.    DL (if AL=0)
  5604.       0 = Off
  5605.       1 = On
  5606.    DL (if AL=5)
  5607.       1 = A, 2 = B, etc.
  5608.    AL
  5609.       FFH = error (AL was neither 0, 1, nor 5
  5610.                   when call was made)
  5611.  
  5612.  
  5613.    Comments:
  5614.  
  5615.    Function 33H gets or sets the state of CONTROL+C (or CONTROL+BREAK for IBM
  5616.    compatibles) checking in MS-DOS and can query the DOS boot drive. AL must
  5617.    contain a code that specifies the requested action:
  5618.  
  5619.    Code               Meaning
  5620.    ──────────────────────────────────────────────────────────────────────────
  5621.    0                  Current state of CONTROL+C checking in DL
  5622.    1                  Set state of CONTROL+C checking to the value in DL
  5623.    5                  Query DOS boot drive in DL
  5624.    ──────────────────────────────────────────────────────────────────────────
  5625.  
  5626.    If AL is 0, DL returns the current state (0=off, 1=on). If AL is 1, the
  5627.    value in DL specifies the state to be set (0=off, 1=on). If AL is neither
  5628.    0, 1, nor 5, AL returns FFH and the state of CONTROL+C checking is
  5629.    unaffected.
  5630.  
  5631.    MS-DOS normally checks for CONTROL+C only when carrying out certain
  5632.    function requests in the 01H through 0CH group (see the description of
  5633.    specific calls for details). When CONTROL+C checking is on, MS-DOS checks
  5634.    for CONTROL+C when carrying out any function request. For example, if
  5635.    CONTROL+C checking is off, all disk I/O proceeds without interruption, but
  5636.    if it is on, the CONTROL+C interrupt is issued at the function request
  5637.    that initiates the disk operation.
  5638.  
  5639.    ──────────────────────────────────────────────────────────────────────────
  5640.    Note
  5641.      Programs that use Function 06H (Direct Console I/O) or 07H (Direct
  5642.      Console Input) to read CONTROL+C as data must ensure that the CONTROL+C
  5643.      checking is off.
  5644.    ──────────────────────────────────────────────────────────────────────────
  5645.  
  5646.    Macro Definition:
  5647.  
  5648.    ctrl_c_ck  macro  action,state
  5649.               mov    al,action
  5650.               mov    dl,state
  5651.               mov    ah,33H
  5652.               int    21H
  5653.               endm
  5654.  
  5655.    Example:
  5656.  
  5657.    The following program displays a message that tells whether CONTROL+C
  5658.    checking is on or off:
  5659.  
  5660.    message   db       "CONTROL+C checking ","$"
  5661.    on        db       "on","$",0DH,0AH,"$"
  5662.    off       db       "off","$",0DH,0AH,"$"
  5663.    ;
  5664.    begin:    display   message          ; See Function 09H
  5665.              ctrl_c_ck 0                ; THIS FUNCTION
  5666.              cmp       dl,0             ; Is checking off?
  5667.              jg        ck_on            ; No
  5668.              display   off              ; See Function 09H
  5669.              jmp       return           ; Go home
  5670.    ck_on:    display   on               ; See Function 09H
  5671.  
  5672.    To query the DOS boot drive value, add the following programs segment:
  5673.  
  5674.              mov       AH,33H           ; Query DOS value
  5675.              mov       AL,05H           ; DOS boot drive
  5676.              int       21H
  5677.              jc        ERROR            ; DL=Boot drive (A=1)
  5678.  
  5679.  
  5680.  ────────────────────────────────────────────────────────────────────────────
  5681.  Get Interrupt Vector (Function 35H)
  5682.  ────────────────────────────────────────────────────────────────────────────
  5683.  
  5684.    Call:
  5685.  
  5686.    AH = 35H
  5687.    AL
  5688.       Interrupt number
  5689.  
  5690.    Return:
  5691.  
  5692.    ES:BX
  5693.       Pointer to interrupt routine
  5694.  
  5695.  
  5696.    Comments:
  5697.  
  5698.    Function 35H gets the address from the interrupt-vector table for the
  5699.    specified interrupt. AL must contain the number of an interrupt.
  5700.  
  5701.    ES returns the segment address of the interrupt handler; BX returns the
  5702.    offset.
  5703.  
  5704.    To avoid compatibility problems, programs should never read an interrupt
  5705.    vector directly from memory, nor set an interrupt vector by writing it
  5706.    into memory. Use this function request to get a vector and Function 25H
  5707.    (Set Interrupt Vector) to set a vector, unless your program must be
  5708.    compatible with MS-DOS versions earlier than 2.0.
  5709.  
  5710.    Macro Definition:
  5711.  
  5712.    get_vector  macro  interrupt
  5713.                mov    al,interrupt
  5714.                mov    ah,35H
  5715.                int    21H
  5716.                endm
  5717.  
  5718.    Example:
  5719.  
  5720.    The following program displays the segment and offset (CS:IP) for the
  5721.    handler for Interrupt 25H (Absolute Disk Read).
  5722.  
  5723.    message   db     "Interrupt 25H -- CS:0000 IP:0000"
  5724.              db      0DH,0AH,"$"
  5725.    vec_seg   db      2 dup (?)
  5726.    vec_off   db      2 dup (?)
  5727.    ;
  5728.    begin:    push    es                    ; save ES
  5729.              get_vector 25H                ; THIS FUNCTION
  5730.              mov     ax,es                 ; INT25H segment in AX
  5731.              pop     es                    ; save ES
  5732.              convert ax,16,message[20]     ; see end of chapter
  5733.              convert bx,16,message[28]     ; see end of chapter
  5734.              display message               ; See Function 9
  5735.  
  5736.  
  5737.  ────────────────────────────────────────────────────────────────────────────
  5738.  Get Disk Free Space (Function 36H)
  5739.  ────────────────────────────────────────────────────────────────────────────
  5740.  
  5741.    Call:
  5742.  
  5743.    AH = 36H
  5744.    DL
  5745.       Drive (0=default, 1=A, etc.)
  5746.  
  5747.    Return:
  5748.  
  5749.    AX
  5750.       0FFFFH if drive number is invalid;
  5751.       otherwise, sectors per cluster
  5752.    BX
  5753.       Available clusters
  5754.    CX
  5755.       Bytes per sector
  5756.    DX
  5757.       Clusters per drive
  5758.  
  5759.  
  5760.    Comments:
  5761.  
  5762.    Function 36H returns the number of clusters available on the disk in the
  5763.    specified drive and the information necessary to calculate the number of
  5764.    bytes available on the disk. DL must contain a drive number (0=default,
  5765.    1=A, etc.). If the drive number is valid, MS-DOS returns the information
  5766.    in the following registers:
  5767.  
  5768.    Register           Contents
  5769.    ──────────────────────────────────────────────────────────────────────────
  5770.    AX                 Sectors per cluster
  5771.    BX                 Available clusters
  5772.    CX                 Bytes per sector
  5773.    DX                 Total clusters
  5774.    ──────────────────────────────────────────────────────────────────────────
  5775.  
  5776.    If the drive number is invalid, AX returns 0FFFFH.
  5777.  
  5778.    This call supersedes Functions 1BH and 1CH in earlier MS-DOS versions.
  5779.  
  5780.    Macro Definition:
  5781.  
  5782.    get_disk_space  macro  drive
  5783.                    mov    dl,drive
  5784.                    mov    ah,36H
  5785.                    int    21H
  5786.                    endm
  5787.  
  5788.    Example:
  5789.  
  5790.    The following program displays space information for the disk in drive B.
  5791.  
  5792.    message   db "      clusters on drive B.",0DH,0AH   ; DX
  5793.              db "      clusters available.",0DH,0AH    ; BX
  5794.              db "      sectors per cluster.",0DH,0AH   ; AX
  5795.              db "      bytes per sector,",0DH,0AH,"$"  ; CX
  5796.    ;
  5797.    begin:    get_disk_space 2                 ; THIS FUNCTION
  5798.              convert    ax,10,message[55]     ; see end of chapter
  5799.              convert    bx,10,message[28]     ; see end of chapter
  5800.              convert    cx,10,message[83]     ; see end of chapter
  5801.              convert    dx,10,message         ; see end of chapter
  5802.              display message                  ; See Function 09H
  5803.  
  5804.  
  5805.  ────────────────────────────────────────────────────────────────────────────
  5806.  Get Country Data (Function 38H)
  5807.  ────────────────────────────────────────────────────────────────────────────
  5808.  
  5809.    Call:
  5810.  
  5811.    AH = 38H
  5812.    AL
  5813.       00H = Current country
  5814.       1-0FEH = Country code
  5815.       0FFH = BX contains country code
  5816.    BX (if AL = 0FFH)
  5817.       Country code 255 or higher
  5818.    DS:DX
  5819.       Pointer to 32-byte memory area
  5820.  
  5821.    Return:
  5822.  
  5823.    Carry set:
  5824.    AX
  5825.       2 = Invalid country code
  5826.    DS:DX
  5827.       Segment:offset pointer to 32-byte memory area
  5828.    Carry not set:
  5829.    BX
  5830.       Country code
  5831.  
  5832.  
  5833.    Comments:
  5834.  
  5835.    Function 38H gets the country-dependent information that MS-DOS uses to
  5836.    control the keyboard and display, or it sets the currently defined country
  5837.    (to set the country code, see the next function request description, Set
  5838.    Country Data). To get the information, DX must contain the offset (from
  5839.    the segment address in DS) of a 32-byte memory area to which the country
  5840.    data returns. AL specifies the country code:
  5841.  
  5842.    Value in AL        Meaning
  5843.    ──────────────────────────────────────────────────────────────────────────
  5844.    00H                Retrieves information about the country currently set
  5845.    1 to 0FEH          Retrieves information about the country identified by
  5846.                       this code
  5847.    0FFH               Retrieves information about the country identified by
  5848.                       the code in BX
  5849.    ──────────────────────────────────────────────────────────────────────────
  5850.  
  5851.    BX must contain the country code if the code is 255 or greater. The
  5852.    country code is usually the international telephone-prefix code. The
  5853.    country-dependent information returns in the following form:
  5854.  
  5855.      Offset
  5856.    Hex        Decimal   Field Name                      Length in bytes
  5857.    ──────────────────────────────────────────────────────────────────────────
  5858.    00H        0         Date format                     2 (word)
  5859.    02H        2         Currency symbol                 5 (ASCIZ string)
  5860.    07H        7         Thousands separator             2 (ASCIZ string)
  5861.    09H        9         Decimal separator               2 (ASCIZ string)
  5862.    0BH        11        Date separator                  2 (ASCIZ string)
  5863.    0DH        13        Time separator                  2 (ASCIZ string)
  5864.    0FH        15        Bit field                       1
  5865.    10H        16        Currency places                 1
  5866.    11H        17        Time format                     1
  5867.    12H        18        Case-map call address           4 (DWORD)
  5868.    16H        22        Data-list separator             2 (ASCIZ string)
  5869.    18H        24        Reserved                        10
  5870.    ──────────────────────────────────────────────────────────────────────────
  5871.  
  5872.    Date Format:
  5873.  
  5874.    0 = USA        (month/day/year)
  5875.    1 = Europe        (day/month/year)
  5876.    2 = Japan        (year/month/day)
  5877.  
  5878.  
  5879.    Bit Field:
  5880.  
  5881.    Bit         Value        Meaning
  5882.    ──────────────────────────────────────────────────────────────────────────
  5883.    0           0            Currency symbol precedes amount
  5884.                1            Currency symbol follows amount
  5885.    1           0            No space between symbol and amount
  5886.                1            One space between symbol and amount
  5887.    ──────────────────────────────────────────────────────────────────────────
  5888.  
  5889.    All other bits are undefined.
  5890.  
  5891.    Time Format:
  5892.  
  5893.    0 = 12-hour clock
  5894.    1 = 24-hour clock
  5895.  
  5896.    Currency Places:
  5897.  
  5898.    Specifies the number of places that appear after the decimal point on
  5899.    currency amounts.
  5900.  
  5901.    Case-Mapping Call Address:
  5902.  
  5903.    Specifies the segment and offset of a FAR procedure that performs
  5904.    country-specific lowercase-to-uppercase mapping on character values from
  5905.    80H to 0FFH. You call it with the character to be mapped in AL. If there
  5906.    is an uppercase code for the character, it is returned in AL; if there is
  5907.    not, or if you call it with a value less than 80H in AL, AL returns
  5908.    unchanged. AL and the FLAGS are the only altered registers.
  5909.  
  5910.    If there is an error, the carry flag (CF) is set and the error code
  5911.    returns in AX:
  5912.  
  5913.    Code               Meaning
  5914.    ──────────────────────────────────────────────────────────────────────────
  5915.    2                  Invalid country code (no table for it).
  5916.    ──────────────────────────────────────────────────────────────────────────
  5917.  
  5918.    Macro Definition:
  5919.  
  5920.    get_country macro  country,buffer
  5921.                local     gc_01
  5922.                mov       dx,offset buffer
  5923.                mov       ax,country
  5924.                cmp       ax,OFFH
  5925.                jl        gc_01
  5926.                mov       al,OFFh
  5927.                mov       bx,country
  5928.    gc_01:      mov       ah,38h
  5929.                int       21H
  5930.                endm
  5931.  
  5932.    Example:
  5933.  
  5934.    The following program displays the time and date in the format appropriate
  5935.    to the current country code, and the number 999,999 and 99/100 as a
  5936.    currency amount with the proper currency symbol and separators.
  5937.  
  5938.    time       db     "  :  :  ",5 dup (20H),"$"
  5939.    date       db     "  /  /  ",5 dup (20H),"$"
  5940.    number     db     "999?999?99",0DH,0AH,"$"
  5941.    data_area  db      32 dup (?)
  5942.    ;
  5943.    begin:    get_country  0,data_area       ; THIS FUNCTION
  5944.              get_time                       ; See Function 2CH
  5945.              byte_to_dec  ch,time           ; See end of chapter
  5946.              byte_to_dec  cl,time[03H]      ; for description of
  5947.              byte_to_dec  dh,time[06H]      ; CONVERT macro
  5948.              get_date                       ; See Function 2AH
  5949.              sub      cx,1900               ; Want last 2 digits
  5950.              byte_to_dec  cl,date[06H]      ; See end of chapter
  5951.              cmp      word ptr data_area,0  ; Check country code
  5952.              jne      not_usa               ; It's not USA
  5953.              byte_to_dec  dh,date           ; See end of chapter
  5954.              byte_to_dec  dl,date[03H]      ; See end of chapter
  5955.              jmp      all_done              ; Display data
  5956.    not_usa:  byte_to_dec  dl,date           ; See end of chapter
  5957.              byte_to_dec  dh,date[03H]      ; See end of chapter
  5958.    all_done: mov      al,data_area[07H]     ; Thousand separator
  5959.              mov      number[03H],al        ; Put in NUMBER
  5960.              mov      al,data_area[09H]     ; Decimal separator
  5961.              mov      number[07H],al        ; Put in AMOUNT
  5962.              display  time                  ; See Function 09H
  5963.              display  date                  ; See Function 09H
  5964.              display_char  data_area[02H]   ; See Function 02H
  5965.              display  number                ; See Function 09H
  5966.  
  5967.  
  5968.  ────────────────────────────────────────────────────────────────────────────
  5969.  Set Country Data (Function 38H)
  5970.  ────────────────────────────────────────────────────────────────────────────
  5971.  
  5972.    Call:
  5973.  
  5974.    AH = 38H
  5975.    DX = -1 (0FFFFH)
  5976.    AL
  5977.       Country code less than 255, or
  5978.       0FFH if the country code is in BX
  5979.    BX (if AL=0FFH)
  5980.       Country code 255 or higher
  5981.  
  5982.    Return:
  5983.  
  5984.    Carry set:
  5985.    AX
  5986.       2 = Invalid country code
  5987.    Carry not set:
  5988.       No error
  5989.  
  5990.  
  5991.    Comments:
  5992.  
  5993.    Function 38H sets the country code that MS-DOS uses to control the
  5994.    keyboard and the display, or it retrieves the country-dependent
  5995.    information (to get the country data, see the previous function request
  5996.    description, Get Country Data). To set the information, DX must contain
  5997.    0FFFFH. AL must contain either the country code, if it is less than 255,
  5998.    or 255 to indicate that the country code is in BX. If AL contains 0FFH, BX
  5999.    must contain the country code.
  6000.  
  6001.    The country code is usually the international telephone prefix-code. See
  6002.    "Get Country Data" for a description of the country data and how it is
  6003.    used.
  6004.  
  6005.    If there is an error, the carry flag (CF) is set and the error code
  6006.    returns in AX:
  6007.  
  6008.    Code               Meaning
  6009.    ──────────────────────────────────────────────────────────────────────────
  6010.    2                  Invalid country code (no table for it).
  6011.    ──────────────────────────────────────────────────────────────────────────
  6012.  
  6013.    Macro Definition:
  6014.  
  6015.    set_country macro  country
  6016.                local  sc_01
  6017.                mov    dx,0FFFFH
  6018.                mov    ax,country
  6019.                cmp    ax,0FFH
  6020.                jl     sc_01
  6021.                mov    bx,country
  6022.                mov    al,0ffh
  6023.    sc_01:      mov    ah,38H
  6024.                int    21H
  6025.                endm
  6026.  
  6027.    Example:
  6028.  
  6029.    The following program sets the country code to the United Kingdom (44).
  6030.  
  6031.    uk        equ         44
  6032.    ;
  6033.    begin:    set_country uk     ; THIS FUNCTION
  6034.              jc          error  ; routine not shown
  6035.  
  6036.  
  6037.  ────────────────────────────────────────────────────────────────────────────
  6038.  Create Directory (Function 39H)
  6039.  ────────────────────────────────────────────────────────────────────────────
  6040.  
  6041.    Call:
  6042.  
  6043.    AH = 39H
  6044.    DS:DX
  6045.       Pointer to pathname
  6046.  
  6047.    Return:
  6048.  
  6049.    Carry set:
  6050.    AX
  6051.       2 = File not found
  6052.       3 = Path not found
  6053.       5 = Access denied
  6054.    Carry not set:
  6055.       No error
  6056.  
  6057.  
  6058.    Comments:
  6059.  
  6060.    Function 39H creates a new subdirectory. DX must contain the offset (from
  6061.    the segment address in DS) of an ASCIZ string that specifies the pathname
  6062.    of the new subdirectory.
  6063.  
  6064.    If there is an error, the carry flag (CF) is set and the error code
  6065.    returns in AX:
  6066.  
  6067.    Code               Meaning
  6068.    ──────────────────────────────────────────────────────────────────────────
  6069.    2                  File not found
  6070.  
  6071.    3                  Path not found
  6072.  
  6073.    5                  No room in the parent directory, a file with the same
  6074.                       name exists in the current directory, or the path
  6075.    ──────────────────────────────────────────────────────────────────────────
  6076.  
  6077.    Macro Definition:
  6078.  
  6079.    make_dir  macro path
  6080.              mov    dx,offset path
  6081.              mov    ah,39H
  6082.              int    21H
  6083.              endm
  6084.  
  6085.    Example:
  6086.  
  6087.    The following program adds a subdirectory named new_dir to the root
  6088.    directory on the disk in drive B and changes the current directory to
  6089.    new_dir. The program then changes the current directory back to the
  6090.    original directory and then deletes new_dir. It displays the current
  6091.    directory after each step to confirm the changes.
  6092.  
  6093.    old_path  db        "b:",0,63 dup (?)
  6094.    new_path  db        "b:\new_dir",0
  6095.    buffer    db        "b:",0,63 dup (?)
  6096.    ;
  6097.    begin:    get_dir    2,old_path[03H]  ; See Function 47H
  6098.              jc         error_get        ; Routine not shown
  6099.              display_asciz  old_path     ; See end of chapter
  6100.              make_dir   new_path         ; THIS FUNCTION
  6101.              jc         error_make       ; Routine not shown
  6102.              change_dir new_path         ; See Function 3BH
  6103.              jc         error_change     ; Routine not shown
  6104.              get_dir    2,buffer[03H]    ; See Function 47H
  6105.              jc         error_get        ; Routine not shown
  6106.              display_asciz  buffer       ; See end of chapter
  6107.              change_dir old_path         ; See Function 3BH
  6108.              jc         error_change     ; Routine not shown
  6109.              rem_dir    new_path         ; See Function 3AH
  6110.              jc         error_rem        ; Routine not shown
  6111.              get_dir    2,buffer[03H]    ; See Function 47H
  6112.              jc         error_get        ; Routine not shown
  6113.              display_asciz  buffer      ; See end of chapter
  6114.  
  6115.  
  6116.  ────────────────────────────────────────────────────────────────────────────
  6117.  Remove Directory (Function 3AH)
  6118.  ────────────────────────────────────────────────────────────────────────────
  6119.  
  6120.    Call:
  6121.  
  6122.    AH = 3AH
  6123.    DS:DX
  6124.       Pointer to pathname
  6125.  
  6126.    Return:
  6127.  
  6128.    Carry set:
  6129.    AX
  6130.       2        = File not found
  6131.       3        = Path not found
  6132.       5        = Access denied
  6133.      16        = Current directory
  6134.    Carry not set:
  6135.       No error
  6136.  
  6137.  
  6138.    Comments:
  6139.  
  6140.    Function 3AH deletes a subdirectory. DX must contain the offset (from the
  6141.    segment address in DS) of an ASCIZ string that specifies the pathname of
  6142.    the subdirectory you want to delete.
  6143.  
  6144.    The subdirectory must not contain any files. You cannot erase the current
  6145.    directory. If there is an error, the carry flag (CF) is set and the error
  6146.    code returns in AX:
  6147.  
  6148.    Code               Meaning
  6149.    ──────────────────────────────────────────────────────────────────────────
  6150.    2                  File not found
  6151.  
  6152.    3                  Path not found
  6153.  
  6154.    5                  Directory not empty, or path doesn't specify a
  6155.                       directory, or it specifies the root directory, or it is
  6156.                       invalid
  6157.  
  6158.    16                 Path specifies current directory
  6159.    ──────────────────────────────────────────────────────────────────────────
  6160.  
  6161.    Macro Definition:
  6162.  
  6163.    rem_dir  macro  path
  6164.             mov    dx,offset path
  6165.             mov    ah,3AH
  6166.             int    21H
  6167.             endm
  6168.  
  6169.    Example:
  6170.  
  6171.    The following program adds a subdirectory named new_dir to the root
  6172.    directory on the disk in drive B and changes the current directory to
  6173.    new_dir. The program then changes the current directory back to the
  6174.    original directory and deletes new_dir. It displays the current directory
  6175.    after each step to confirm the changes.
  6176.  
  6177.    old_path  db        "b:",0,63 dup (?)
  6178.    new_path  db        "b:\new_dir",0
  6179.    buffer    db        "b:",0,63 dup (?)
  6180.    ;
  6181.    begin:    get_dir    2,old_path[03H]  ; See Function 47H
  6182.              jc         error_get        ; Routine not shown
  6183.              display_asciz  old_path    ; See end of chapter
  6184.              make_dir   new_path         ; See Function 39H
  6185.              jc         error_make       ; Routine not shown
  6186.              change_dir new_path         ; See Function 3BH
  6187.              jc         error_change     ; Routine not shown
  6188.              get_dir    2,buffer[03H]    ; See Function 47H
  6189.              jc         error_get        ; Routine not shown
  6190.              display_asciz  buffer      ; See end of chapter
  6191.              change_dir old_path         ; See Function 3BH
  6192.              jc         error_change     ; Routine not shown
  6193.              rem_dir    new_path         ; THIS FUNCTION
  6194.              jc         error_rem        ; Routine not shown
  6195.              get_dir    2,buffer[03H]    ; See Function 47H
  6196.              jc         error_get        ; Routine not shown
  6197.              display_asciz  buffer      ; See end of chapter
  6198.  
  6199.  
  6200.  ────────────────────────────────────────────────────────────────────────────
  6201.  Change Current Directory (Function 3BH)
  6202.  ────────────────────────────────────────────────────────────────────────────
  6203.  
  6204.    Call:
  6205.  
  6206.    AH = 3BH
  6207.    DS:DX
  6208.       Pointer to pathname
  6209.  
  6210.    Return:
  6211.  
  6212.    Carry set:
  6213.    AX
  6214.       2 = File not found
  6215.       3 = Path not found
  6216.    Carry not set:
  6217.       No error
  6218.  
  6219.  
  6220.    Comments:
  6221.  
  6222.    Function 3BH changes the current directory. DX must contain the offset
  6223.    (from the segment address in DS) of an ASCIZ string that specifies the
  6224.    pathname of the new current directory.
  6225.  
  6226.    The directory string is limited to 64 characters.
  6227.  
  6228.    If any member of the path doesn't exist, the path is unchanged. If there
  6229.    is an error, the carry flag (CF) is set and the error code returns in AX:
  6230.  
  6231.    Code               Meaning
  6232.    ──────────────────────────────────────────────────────────────────────────
  6233.    2                  File not found
  6234.  
  6235.    3                  Path either doesn't exist or it specifies a file
  6236.    ──────────────────────────────────────────────────────────────────────────
  6237.  
  6238.    Macro Definition:
  6239.  
  6240.    change_dir  macro  path
  6241.                mov    dx,offset path
  6242.                mov    ah,3BH
  6243.                int    21H
  6244.                endm
  6245.  
  6246.    Example:
  6247.  
  6248.    The following program adds a subdirectory named new_dir to the root
  6249.    directory that is on the disk in drive B and changes the current directory
  6250.    to new_dir. The program then changes the current directory back to the
  6251.    original directory and deletes new_dir. It displays the current directory
  6252.    after each step to confirm the changes.
  6253.  
  6254.    old_path  db        "b:",0,63 dup (?)
  6255.    new_path  db        "b:\new_dir",0
  6256.    buffer    db        "b:",0,63 dup (?)
  6257.    ;
  6258.    begin:    get_dir    2,old_path[03H]  ; See Function 47H
  6259.              jc         error_get        ; Routine not shown
  6260.              display_asciz  old_path    ; See end of chapter
  6261.              make_dir   new_path         ; See Function 39H
  6262.              jc         error_make       ; Routine not shown
  6263.              change_dir new_path         ; THIS FUNCTION
  6264.              jc         error_change     ; Routine not shown
  6265.              get_dir    2,buffer[03H]    ; See Function 47H
  6266.              jc         error_get        ; Routine not shown
  6267.              display_asciz  buffer      ; See end of chapter
  6268.              change_dir old_path         ; See Function 3BH
  6269.              jc         error_change     ; Routine not shown
  6270.              rem_dir    new_path         ; See Function 3AH
  6271.              jc         error_rem        ; Routine not shown
  6272.              get_dir    2,buffer[03H]    ; See Function 47H
  6273.              jc         error_get        ; Routine not shown
  6274.              display_asciz  buffer      ; See end of chapter
  6275.  
  6276.  
  6277.  ────────────────────────────────────────────────────────────────────────────
  6278.  Create Handle (Function 3CH)
  6279.  ────────────────────────────────────────────────────────────────────────────
  6280.  
  6281.    Call:
  6282.  
  6283.    AH = 3CH
  6284.    DS:DX
  6285.       Pointer to pathname
  6286.    CX
  6287.       File attribute
  6288.  
  6289.    Return:
  6290.  
  6291.    Carry set:
  6292.    AX
  6293.       2        = File not found
  6294.       3        = Path not found
  6295.       4        = Too many open files
  6296.       5        = Access denied
  6297.    Carry not set:
  6298.    AX
  6299.       Handle
  6300.  
  6301.  
  6302.    Comments:
  6303.  
  6304.    Function 3CH creates a file and assigns it the first available handle. DX
  6305.    must contain the offset (from the segment address in DS) of an ASCIZ
  6306.    string that specifies the pathname of the file to be created. CX must
  6307.    contain the attribute to be assigned to the file, as described under "File
  6308.    Attributes" earlier in this chapter.
  6309.  
  6310.    If the specified file does not exist, this function creates it. But if the
  6311.    file already exists, it is truncated to a length of 0. Function 3CH then
  6312.    assigns the attribute in CX to the file and opens it for read/write. AX
  6313.    returns the file handle. If there is an error, the carry flag (CF) is set
  6314.    and the error code returns in AX:
  6315.  
  6316.    Code               Meaning
  6317.    ──────────────────────────────────────────────────────────────────────────
  6318.    2                  File not found
  6319.  
  6320.    3                  Path is invalid
  6321.  
  6322.    4                  Too many open files (no handle available)
  6323.  
  6324.    5                  Directory is full, a directory with the same name
  6325.                       exists, or a file with the same name exists with more
  6326.    ──────────────────────────────────────────────────────────────────────────
  6327.  
  6328.    Macro Definition:
  6329.  
  6330.    create_handle  macro  path,attrib
  6331.                   mov    dx,offset path
  6332.                   mov    cx,attrib
  6333.                   mov    ah,3CH
  6334.                   int    21H
  6335.                   endm
  6336.  
  6337.    Example:
  6338.  
  6339.    The following program creates a file named dir.tmp, containing the name
  6340.    and extension of each file in the current directory, on the disk in drive
  6341.    B.
  6342.  
  6343.    srch_file db      "b:*.*",0
  6344.    tmp_file  db      "b:dir.tmp",0
  6345.    buffer    db       43 dup (?)
  6346.    handle    dw       ?
  6347.    ;
  6348.    begin:    set_dta buffer                ; See Function 1AH
  6349.              find_first_file  srch_file,16H  ; See Function 4EH
  6350.              cmp     ax,12H                ; Directory empty?
  6351.              je      all_done              ; Yes, go home
  6352.              create_handle  tmp_file,0     ; THIS FUNCTION
  6353.              jc      error                 ; Routine not shown
  6354.              mov     handle,ax             ; Save handle
  6355.    write_it: write_handle handle,buffer[1EH],12 ; Function 40H
  6356.              find_next_file                ; See Function 4FH
  6357.              cmp     ax,12H                ; Another entry?
  6358.              je      all_done              ; No, go home
  6359.              jmp     write_it              ; Yes, write record
  6360.    all_done: close_handle  handle          ; See Function 3EH
  6361.  
  6362.  
  6363.  ────────────────────────────────────────────────────────────────────────────
  6364.  Open Handle (Function 3DH)
  6365.  ────────────────────────────────────────────────────────────────────────────
  6366.  
  6367.    Call:
  6368.  
  6369.    AH = 3DH
  6370.    AL
  6371.       Access code (see text)
  6372.    DS:DX
  6373.       Pointer to pathname
  6374.  
  6375.    Return:
  6376.  
  6377.    Carry set:
  6378.    AX
  6379.       2        = File not found
  6380.       3        = Path not found
  6381.       4        = Too many open files
  6382.       5        = Access denied
  6383.      12        = Invalid access
  6384.    Carry not set:
  6385.       No error
  6386.  
  6387.  
  6388.    Comments:
  6389.  
  6390.    Function 3DH opens any file, including hidden and system files, for input
  6391.    or output. DX contains the offset (from the segment address in DS) of an
  6392.    ASCIZ string that specifies the pathname of the file to be opened. AL
  6393.    contains a code that specifies how the file is to be opened. This code is
  6394.    described later under "Controlling Access to the File."
  6395.  
  6396.    If there is no error, AX returns the file handle. MS-DOS sets the
  6397.    read/write pointer to the first byte of the file.
  6398.  
  6399.    Controlling Access to the File
  6400.  
  6401.    The value in AL is made up of three parts that specify whether the file is
  6402.    to be opened for read, write, or both (access code); what access other
  6403.    processes have to the file (sharing mode); and whether a child process
  6404.    inherits the file (inherit bit).
  6405.  
  6406.         ┌───┬───────────┬───────────────┐
  6407.    Bit  │ 7 │ 6   5   4 │ 3   2   1   0 │
  6408.         └───┴───────────┴───────────────┘
  6409.  
  6410.          \_/ \_________/ \______________/
  6411.           │       │             │
  6412.           │       │             └────────>  Access code
  6413.           │       │
  6414.           │       └──────────────────────>  Sharing mode
  6415.           │
  6416.           └──────────────────────────────>  Inherit bit
  6417.  
  6418.    Inherit Bit
  6419.  
  6420.    The high-order bit (bit 7) specifies whether the file is inherited by a
  6421.    child process created with Function 4B00H or 4B03H (Load and Execute
  6422.    Program or Overlay). If the bit is 0, the child process inherits the file;
  6423.    if the bit is 1, it doesn't.
  6424.  
  6425.    Sharing Mode
  6426.  
  6427.    The sharing mode bits (bits 4-6) specify what access, if any, other
  6428.    processes have to the open file. It can have the following values:
  6429.  
  6430.    Table 1.21
  6431.    Sharing Mode Bit Values
  6432.    Bits 4-6   Sharing Mode         Description
  6433.    ──────────────────────────────────────────────────────────────────────────
  6434.    000        Compatibility        On a given machine, any process can open
  6435.                                    the file any number of times with this
  6436.                                    mode. Fails if the file has been opened
  6437.                                    with any of the other sharing modes.
  6438.  
  6439.    001        Deny both            Fails if the file has been opened in
  6440.                                    compatibility mode or for read or write
  6441.                                    access, even if by the current process.
  6442.  
  6443.    010        Deny write           Fails if the file has been opened in
  6444.                                    compatibility mode or for write access by
  6445.                                    any other process.
  6446.  
  6447.    011        Deny read            Fails if the file has been opened in
  6448.                                    compatibility mode or for read access by
  6449.                                    any other process.
  6450.  
  6451.    100        Deny none            Fails if the file has been opened in
  6452.    ──────────────────────────────────────────────────────────────────────────
  6453.  
  6454.    Access Code
  6455.  
  6456.    The access code (bits 0-3) specifies how the file is to be used. It can
  6457.    have the following values:
  6458.  
  6459.    Table 1.22
  6460.    Access Code Bit Values
  6461.                  Access
  6462.    Bits 0-3     Allowed       Description
  6463.    ──────────────────────────────────────────────────────────────────────────
  6464.    0000         Read          Fails if the file has been opened in deny read
  6465.                               or deny both sharing mode.
  6466.  
  6467.    0001         Write         Fails if the file has been opened in deny write
  6468.                               or deny both sharing mode.
  6469.  
  6470.    0010         Both          Fails if the file has been opened in deny read,
  6471.    ──────────────────────────────────────────────────────────────────────────
  6472.  
  6473.    If there is an error, the carry flag (CF) is set and the error code is
  6474.    returned in AX:
  6475.  
  6476.    Code               Meaning
  6477.    ──────────────────────────────────────────────────────────────────────────
  6478.    2                  Specified file is invalid or doesn't exist
  6479.  
  6480.    3                  Specified path is invalid or doesn't exist
  6481.  
  6482.    4                  No handles are available in the current process or the
  6483.                       internal system tables are full
  6484.  
  6485.    5                  Program attempted to open a directory or VolumeID, or
  6486.                       tried to open a read-only file for writing
  6487.  
  6488.    12                 Access code (bits 0-3 of AL) not 0, 1, or 2
  6489.    ──────────────────────────────────────────────────────────────────────────
  6490.  
  6491.    If this system call fails because of a file-sharing error, MS-DOS issues
  6492.    Interrupt 24H with error code 2 (Drive Not Ready). A subsequent Function
  6493.    59H (Get Extended Error) returns the extended error code that specifies a
  6494.    sharing violation.
  6495.  
  6496.    When opening a file, it is important to inform MS-DOS of any operations
  6497.    that other processes may perform on this file (sharing mode). The default
  6498.    (compatibility mode) denies all other processes access to the file, unless
  6499.    they also attempt to open the file in compatibility mode. The following
  6500.    table shows the effect of opening a file with compatibility mode set:
  6501.  
  6502.    Type of File Opening            Read-Only File       Not Read-Only
  6503.    ──────────────────────────────────────────────────────────────────────────
  6504.    First open for read, write, or  Succeeds             Succeeds
  6505.    both by machine/process "N"
  6506.  
  6507.    Subsequent opens by machine or  Succeeds             Succeeds
  6508.    process "N"
  6509.  
  6510.    An open by another machine or   Succeeds             Fails
  6511.    process
  6512.    ──────────────────────────────────────────────────────────────────────────
  6513.  
  6514.    Files may be read-only with the MS-DOS attrib command or by a read-only
  6515.    share over the network.
  6516.  
  6517.    It may be all right for other processes to continue to read the file while
  6518.    your process is operating on it. In this case, you should specify "Deny
  6519.    Write," which inhibits other processes from writing to your files but
  6520.    allows them to read from these files.
  6521.  
  6522.    Similarly, it is important for you to specify what operations your process
  6523.    will perform ("Access" mode). If another process has the file open with
  6524.    any sharing mode other than "Deny" mode, then the default mode
  6525.    ("Read/Write") causes the open request to fail. If you only want to read
  6526.    the file, your open request succeeds unless all other processes have
  6527.    specified "Deny" mode or "Deny write."
  6528.  
  6529.    Macro Definition:
  6530.  
  6531.    open_handle  macro  path,access
  6532.                 mov    dx, offset path
  6533.                 mov    al, access
  6534.                 mov    ah, 3DH
  6535.                 int    21H
  6536.                 endm
  6537.  
  6538.    Example:
  6539.  
  6540.    The following program prints a file named textfile.asc that is on the disk
  6541.    in drive B.
  6542.  
  6543.    file       db  "b:textfile.asc",0
  6544.    buffer     db   ?
  6545.    handle     dw   ?
  6546.    ;
  6547.    begin:     open_handle  file,0          ; THIS FUNCTION
  6548.               mov  handle,ax               ; Save handle
  6549.    read_char: read_handle handle,buffer,1  ; Read 1 character
  6550.               jc   error_read              ; Routine not shown
  6551.               cmp  ax,0                    ; End of file?
  6552.               je   return                  ; Yes, go home
  6553.               print_char  buffer           ; See Function 05H
  6554.               jmp  read_char               ; Read another
  6555.  
  6556.  
  6557.  ────────────────────────────────────────────────────────────────────────────
  6558.  Close Handle (Function 3EH)
  6559.  ────────────────────────────────────────────────────────────────────────────
  6560.  
  6561.    Call:
  6562.  
  6563.    AH = 3EH
  6564.    BX
  6565.       Handle
  6566.  
  6567.    Return:
  6568.  
  6569.    Carry set:
  6570.    AX
  6571.       6 = Invalid handle
  6572.    Carry not set:
  6573.       No error
  6574.  
  6575.  
  6576.    Comments:
  6577.  
  6578.    Function 3EH closes a file opened with Function 3DH (Open Handle) or
  6579.    3CH (Create Handle). BX must contain the handle of the open file that you
  6580.    want to close.
  6581.  
  6582.    If there is no error, MS-DOS closes the file and flushes all internal
  6583.    buffers. If there is an error, the carry flag (CF) is set and the error
  6584.    code returns in AX:
  6585.  
  6586.    Code               Meaning
  6587.    ──────────────────────────────────────────────────────────────────────────
  6588.    6                  Handle not open or invalid
  6589.    ──────────────────────────────────────────────────────────────────────────
  6590.  
  6591.    Macro Definition:
  6592.  
  6593.    close_handle  macro  handle
  6594.                  mov    bx,handle
  6595.                  mov    ah,3EH
  6596.                  int    21H
  6597.                  endm
  6598.  
  6599.    Example:
  6600.  
  6601.    The following program creates a file named dir.tmp, containing the
  6602.    filename and extension of each file in the current directory, in the
  6603.    current directory on the disk in drive B.
  6604.  
  6605.    srch_file  db  "b:*.*",0
  6606.    tmp_file   db  "b:dir.tmp",0
  6607.    buffer     db   43 dup (?)
  6608.    handle     dw   ?
  6609.    ;
  6610.    begin:     set_dta  buffer              ; See Function 1AH
  6611.               find_first_file  srch_file,16H  ; See Function 4EH
  6612.               cmp      ax,12H              ; Directory empty?
  6613.               je       all_done            ; Yes, go home
  6614.               create_handle  tmp_file,0    ; See Function 3CH
  6615.               jc       error_create        ; Routine not shown
  6616.               mov      handle,ax           ; Save handle
  6617.    write_it:  write_handle  handle,buffer[1EH],12 ; See Function
  6618.               jc       error_write                ; 40H
  6619.               find_next_file               ; See Function 4FH
  6620.               cmp      ax,12H              ; Another entry?
  6621.               je       all_done            ; No, go home
  6622.               jmp      write_it            ; Yes, write record
  6623.    all_done:  close_handle  handle         ; See Function 3EH
  6624.               jc       error_close         ; Routine not shown
  6625.  
  6626.  
  6627.  ────────────────────────────────────────────────────────────────────────────
  6628.  Read Handle (Function 3FH)
  6629.  ────────────────────────────────────────────────────────────────────────────
  6630.  
  6631.    Call:
  6632.  
  6633.    AH = 3FH
  6634.    BX
  6635.       Handle
  6636.    CX
  6637.       Bytes to read
  6638.    DS:DX
  6639.       Pointer to buffer
  6640.  
  6641.    Return:
  6642.  
  6643.    Carry set:
  6644.    AX
  6645.       5 = Access denied
  6646.       6 = Invalid handle
  6647.    Carry not set:
  6648.    AX
  6649.       Bytes read
  6650.  
  6651.  
  6652.    Comments:
  6653.  
  6654.    Function 3FH reads from the file or device associated with the specified
  6655.    handle. BX must contain the handle. CX must contain the number of bytes to
  6656.    be read. DX must contain the offset (to the segment address in DS) of the
  6657.    buffer.
  6658.  
  6659.    If there is no error, AX returns the number of bytes read; if you attempt
  6660.    to read starting at end of file, AX returns 0. The number of bytes
  6661.    specified in CX is not necessarily transferred to the buffer; if you use
  6662.    this call to read from the keyboard, for example, it reads only up to the
  6663.    first carriage-return.
  6664.  
  6665.    If you use this function request to read from standard input, you can
  6666.    redirect the input.
  6667.  
  6668.    If there is an error, the carry flag (CF) is set and the error code
  6669.    returns in AX:
  6670.  
  6671.    Code               Meaning
  6672.    ──────────────────────────────────────────────────────────────────────────
  6673.    5                  Handle not open for reading
  6674.    6                  Handle not open or invalid
  6675.    ──────────────────────────────────────────────────────────────────────────
  6676.  
  6677.    Macro Definition:
  6678.  
  6679.    read_handle  macro  handle,buffer,bytes
  6680.                 mov    bx,handle
  6681.                 mov    dx,offset buffer
  6682.                 mov    cx,bytes
  6683.                 mov    ah,3FH
  6684.                 int    21H
  6685.                 endm
  6686.  
  6687.    Example:
  6688.  
  6689.    The following program displays a file named textfile.asc that is on the
  6690.    disk in drive B.
  6691.  
  6692.    filename   db     "b:\textfile.asc",0
  6693.    buffer     db      129 dup (?)
  6694.    handle     dw      ?
  6695.    ;
  6696.    begin:     open_handle  filename,0        ; See Function 3DH
  6697.               jc           error_open        ; Routine not shown
  6698.               mov          handle,ax         ; Save handle
  6699.    read_file: read_handle  buffer,file_handle,128
  6700.               jc           error_open        ; Routine not shown
  6701.               cmp          ax,0              ; End of file?
  6702.               je           return            ; Yes, go home
  6703.               mov          bx,ax             ; # of bytes read
  6704.               mov          buffer[bx],"$"    ; Make a string
  6705.               display      buffer            ; See Function 09H
  6706.               jmp          read_file         ; Read more
  6707.  
  6708.  
  6709.  ────────────────────────────────────────────────────────────────────────────
  6710.  Write Handle (Function 40H)
  6711.  ────────────────────────────────────────────────────────────────────────────
  6712.  
  6713.    Call:
  6714.  
  6715.    AH = 40H
  6716.    BX
  6717.       Handle
  6718.    CX
  6719.       Bytes to write
  6720.    DS:DX
  6721.       Pointer to buffer
  6722.  
  6723.    Return:
  6724.  
  6725.    Carry set:
  6726.    AX
  6727.       5 = Access denied
  6728.       6 = Invalid handle
  6729.    Carry not set:
  6730.    AX
  6731.       Bytes written
  6732.  
  6733.  
  6734.    Comments:
  6735.  
  6736.    Function 40H writes to the file or device associated with the specified
  6737.    handle. BX must contain the handle. CX must contain the number of bytes to
  6738.    be written. DX must contain the offset (to the segment address in DS) of
  6739.    the data to be written.
  6740.  
  6741.    If you set CX to zero, the file will be truncated at the current position
  6742.    of the file pointer. MS-DOS will not perform the write if the handle is
  6743.    read-only.
  6744.  
  6745.    If there is no error, AX returns the number of bytes written. Be sure to
  6746.    check AX after performing a write. If its value is less than the number in
  6747.    CX when the call was made, it indicates an error, even though the carry
  6748.    flag isn't set. If AX contains 0, and if the target is a disk file, the
  6749.    disk is full.
  6750.  
  6751.    If you use this function request to write to standard output, you can
  6752.    redirect the output. If you call this request with CX=0, the file size is
  6753.    set to the value of the read/write pointer. To satisfy the new file size,
  6754.    allocation units are allocated or released, as required. If there is an
  6755.    error, the carry flag (CF) is set and the error code returns in AX:
  6756.  
  6757.    Code               Meaning
  6758.    ──────────────────────────────────────────────────────────────────────────
  6759.    5                  Handle not open for writing
  6760.    6                  Handle not open or invalid
  6761.    ──────────────────────────────────────────────────────────────────────────
  6762.  
  6763.    Macro Definition:
  6764.  
  6765.    write_handle  macro  handle,buffer,bytes
  6766.                  mov    bx,handle
  6767.                  mov    dx,offset buffer
  6768.                  mov    cx,bytes
  6769.                  mov    ah,40H
  6770.                  int    21H
  6771.                  endm
  6772.  
  6773.    Example:
  6774.  
  6775.    The following program creates a file named dir.tmp, containing the
  6776.    filename and extension of each file in the current directory, in the
  6777.    current directory on the disk in drive B.
  6778.  
  6779.    srch_file db     "b:*.*",0
  6780.    tmp_file  db     "b:dir.tmp",0
  6781.    buffer    db      43 dup (?)
  6782.    handle    dw      ?
  6783.    ;
  6784.    begin:    set_dta buffer                ; See Function 1AH
  6785.              find_first_file  srch_file,16H ; Check directory
  6786.              cmp     ax,12H                ; Directory empty?
  6787.              je      return                ; Yes, go home
  6788.              create_handle  tmp_file,0     ; See Function 3CH
  6789.              jc      error_create          ; Routine not shown
  6790.              mov     handle,ax             ; Save handle
  6791.    write_it: write_handle handle,buffer[1EH],12 ; THIS FUNCTION
  6792.              jc      error_write           ; Routine not shown
  6793.              find_next_file                ; Check directory
  6794.              cmp     ax,12H                ; Another entry?
  6795.              je      all_done              ; No, go home
  6796.              jmp     write_it              ; Yes, write record
  6797.    all_done: close_handle  handle          ; See Function 3EH
  6798.              jc      error_close           ; Routine not shown
  6799.  
  6800.  
  6801.  ────────────────────────────────────────────────────────────────────────────
  6802.  Delete Directory Entry [Unlink] (Function 41H)
  6803.  ────────────────────────────────────────────────────────────────────────────
  6804.  
  6805.    Call:
  6806.  
  6807.    AH = 41H
  6808.    DS:DX
  6809.       Pointer to pathname
  6810.  
  6811.    Return:
  6812.  
  6813.    Carry set:
  6814.    AX
  6815.       2 = File not found
  6816.       3 = Path not found
  6817.       5 = Access denied
  6818.    Carry not set:
  6819.       No error
  6820.  
  6821.  
  6822.    Comments:
  6823.  
  6824.    Function 41H erases a file by deleting its directory entry. DX must
  6825.    contain the offset (from the segment address in DS) of an ASCIZ string
  6826.    that specifies the pathname of the file that you want to delete. You
  6827.    cannot use wildcard characters.
  6828.  
  6829.    If the file exists and is not read-only, the call deletes it. If there is
  6830.    an error, the call sets the carry flag (CF) and the error code returns in
  6831.    AX:
  6832.  
  6833.    Code               Meaning
  6834.    ──────────────────────────────────────────────────────────────────────────
  6835.    2                  File doesn't exist, or specifies a directory
  6836.    3                  Path is invalid
  6837.    5                  File is read-only
  6838.    ──────────────────────────────────────────────────────────────────────────
  6839.  
  6840.    To delete a file with the read-only attribute, first change its attribute
  6841.    to 0 with Function 43H (Get/Set File Attributes).
  6842.  
  6843.    Macro Definition:
  6844.  
  6845.    delete_entry  macro  path
  6846.                  mov    dx,offset path
  6847.                  mov    ah,41H
  6848.                  int    21H
  6849.                  endm
  6850.  
  6851.    Example:
  6852.  
  6853.    The following program deletes all files, dated before December 31, 1986,
  6854.    from the disk in drive B.
  6855.  
  6856.    year      db       1986
  6857.    month     db       12
  6858.    day       db       31
  6859.    files     db       ?
  6860.    message   db      "NO FILES DELETED.",0DH,0AH,"$"
  6861.    path      db      "b:*.*", 0
  6862.    buffer    db       43 dup (?)
  6863.    ;
  6864.    begin:    set_dta  buffer          ; See Function 1AH
  6865.              select_disk "B"          ; See Function 0EH
  6866.              find_first_file  path,0  ; See Function 4EH
  6867.              jnc      compare         ; got one
  6868.              jmp      all_done        ; no match, go home
  6869.    compare:  convert_date  buffer[-1] ; See end of chapter
  6870.              cmp      cx,year         ; After 1986?
  6871.              jg       next            ; Yes, don't delete
  6872.              cmp      dl,month        ; After December?
  6873.              jg       next            ; Yes, don't delete
  6874.              cmp      dh,day          ; 31st or after?
  6875.              jge      next            ; Yes, don't delete
  6876.              delete_entry  buffer[1EH] ; THIS FUNCTION
  6877.              jc       error_delete    ; Routine not shown
  6878.              inc      files           ; Bump file counter
  6879.    next:     find_next_file           ; Check directory
  6880.              jnc      compare         ; Go home if done
  6881.    how_many: cmp      files,0         ; Was directory empty?
  6882.              je       all_done        ; Yes, go home
  6883.              convert  files,10,message ; See end of chapter
  6884.    all_done: display  message         ; See Function 09H
  6885.              select_disk "A"          ; See Function 0EH
  6886.  
  6887.  
  6888.  ────────────────────────────────────────────────────────────────────────────
  6889.  Move File Pointer (Function 42H)
  6890.  ────────────────────────────────────────────────────────────────────────────
  6891.  
  6892.    Call:
  6893.  
  6894.    AH = 42H
  6895.    AL
  6896.       Method of moving
  6897.    BX
  6898.       Handle
  6899.    CX:DX
  6900.       Distance in bytes (offset)
  6901.  
  6902.    Return:
  6903.  
  6904.    Carry set:
  6905.    AX
  6906.       1 = Invalid function
  6907.       6 = Invalid handle
  6908.    Carry not set:
  6909.    DX:AX
  6910.       New read/write pointer location
  6911.  
  6912.  
  6913.    Comments:
  6914.  
  6915.    Function 42H moves the read/write pointer of the file associated with the
  6916.    specified handle. BX must contain the handle. CX and DX must contain a
  6917.    32-bit offset (CX contains the most significant byte). AL must contain a
  6918.    code that specifies how to move the pointer:
  6919.  
  6920.    Code               Cursor Moved to
  6921.    ──────────────────────────────────────────────────────────────────────────
  6922.    0                  Beginning of file plus the offset
  6923.    1                  Current pointer location plus the offset
  6924.    2                  End of file plus the offset
  6925.    ──────────────────────────────────────────────────────────────────────────
  6926.  
  6927.    DX and AX return the new location of the read/write pointer (a 32-bit
  6928.    integer; DX contains the most significant byte). You can determine the
  6929.    length of a file by setting CX:DX to 0, AL to 2, and calling this
  6930.    function. DX:AX returns the offset of the byte following the last byte in
  6931.    the file (size of the file in bytes). If there is an error, the carry flag
  6932.    (CF) is set and the error code returns in AX:
  6933.  
  6934.    Code               Meaning
  6935.    ──────────────────────────────────────────────────────────────────────────
  6936.    1                  AL not 0, 1, or 2
  6937.    6                  Handle not open
  6938.    ──────────────────────────────────────────────────────────────────────────
  6939.  
  6940.    Macro Definition:
  6941.  
  6942.    move_ptr  macro  handle,high,low,method
  6943.              mov    bx,handle
  6944.              mov    cx,high
  6945.              mov    dx,low
  6946.              mov    al,method
  6947.              mov    ah,42H
  6948.              int    21H
  6949.              endm
  6950.  
  6951.    Example:
  6952.  
  6953.    The following program prompts for a letter, converts it to its alphabetic
  6954.    sequence (A=1, B=2, etc.), then reads and displays the corresponding
  6955.    record from the file named alphabet.dat that is in the current directory
  6956.    on the disk in drive B. The file contains 26 records, each 28 bytes long.
  6957.  
  6958.    file      db      "b:alphabet.dat",0
  6959.    buffer    db       28 dup (?),"$"
  6960.    prompt    db      "Enter letter: $"
  6961.    crlf      db       0DH,0AH,"$"
  6962.    handle    db       ?
  6963.    record_length  dw  28
  6964.    ;
  6965.    begin:    open_handle  file,0    ; See Function 3DH
  6966.              jc       error_open    ; Routine not shown
  6967.              mov      handle,ax     ; Save handle
  6968.    get_char: display  prompt        ; See Function 09H
  6969.              read_kbd_and_echo      ; See Function 01H
  6970.              sub      al,41h        ; Convert to sequence
  6971.              mul      byte ptr record_length  ; Calculate offset
  6972.              move_ptr handle,0,ax,0 ; THIS FUNCTION
  6973.              jc       error_move    ; Routine not shown
  6974.              read_handle handle,buffer,record_length
  6975.              jc       error_read    ; Routine not shown
  6976.              cmp      ax,0          ; End of file?
  6977.              je       return        ; Yes, go home
  6978.              display  crlf          ; See Function 09H
  6979.              display  buffer        ; See Function 09H
  6980.              display  crlf          ; See Function 09H
  6981.              jmp      get_char      ; Get another character
  6982.  
  6983.  
  6984.  ────────────────────────────────────────────────────────────────────────────
  6985.  Get/Set File Attributes (Function 43H)
  6986.  ────────────────────────────────────────────────────────────────────────────
  6987.  
  6988.    Call:
  6989.  
  6990.    AH = 43H
  6991.    AL
  6992.       0 = Get attributes
  6993.       1 = Set attributes
  6994.    CX (if AL=1)
  6995.       Attributes to be set
  6996.    DS:DX
  6997.       Pointer to pathname
  6998.  
  6999.    Return:
  7000.  
  7001.    Carry set:
  7002.    AX
  7003.       1 = Invalid function
  7004.       2 = File not found
  7005.       3 = Path not found
  7006.       5 = Access denied
  7007.    Carry not set:
  7008.    CX
  7009.       Attribute byte (if AL=0)
  7010.  
  7011.  
  7012.    Comments:
  7013.  
  7014.    Function 43H gets or sets the attributes of a file. DX must contain the
  7015.    offset (from the segment address in DS) of an ASCIZ string that specifies
  7016.    the pathname of a file. AL must specify whether to get or set the
  7017.    attribute (0=get, 1=set).
  7018.  
  7019.    If AL is 0 (get the attribute), the attribute byte returns in CX. If AL is
  7020.    1 (set the attribute), CX must contain the attributes to be set. See
  7021.    Section 1.5.5, "File Attributes," for a description of the attributes.
  7022.  
  7023.    You cannot change the VolumeID bit (08H) or the Subdirectory bit (10H) of
  7024.    the attribute byte with this function.
  7025.  
  7026.    If there is an error, the carry flag (CF) is set and the error code
  7027.    returns in AX:
  7028.  
  7029.    Code               Meaning
  7030.    ──────────────────────────────────────────────────────────────────────────
  7031.    1                  AL not 0 or 1
  7032.  
  7033.    2                  File doesn't exist
  7034.  
  7035.    3                  Path invalid
  7036.  
  7037.    5                  Attribute in CX cannot be changed (Subdirectory or
  7038.    ──────────────────────────────────────────────────────────────────────────
  7039.  
  7040.    Macro Definition:
  7041.  
  7042.    change_attr  macro  path,action,attrib
  7043.                 mov    dx,offset path
  7044.                 mov    al,action
  7045.                 mov    cx,attrib
  7046.                 mov    ah,43H
  7047.                 int    21H
  7048.                 endm
  7049.  
  7050.    Example:
  7051.  
  7052.    The following program displays the attributes assigned to the file named
  7053.    report.asm that is in the current directory on the disk in drive B.
  7054.  
  7055.    header    db      15 dup (20h),"Read-",0DH,0AH
  7056.              db     "Filename       Only      Hidden    "
  7057.              db     "System    Volume    Sub-Dir   Archive"
  7058.              db      0DH,0AH,0DH,0AH,"$"
  7059.    path      db     "b:report.asm",3 dup (0),"$"
  7060.    attribute dw      ?
  7061.    blanks    db      9 dup (20h),"$"
  7062.    ;
  7063.    begin:    change_attr  path,0,0  ; THIS FUNCTION
  7064.              jc      error_mode   ; Routine not shown
  7065.              mov     attribute,cx ; Save attribute byte
  7066.              display header       ; See Function 09H
  7067.              display path         ; See Function 09H
  7068.              mov     cx,6         ; Check 6 bits (0-5)
  7069.              mov     bx,1         ; Start with bit 0
  7070.    chk_bit:  test    attribute,bx ; Is the bit set?
  7071.              jz      no_attr      ; No
  7072.              display_char "X"     ; See Function 02H
  7073.              jmp short  next_bit  ; Done with this bit
  7074.    no_attr:  display_char  20h    ; See Function 02H
  7075.    next_bit: display blanks       ; See Function 09H
  7076.              shl     bx,1         ; Move to next bit
  7077.              loop    chk_bit      ; Check it
  7078.  
  7079.  
  7080.  ────────────────────────────────────────────────────────────────────────────
  7081.  IOCtl Data (Function 44H, Codes 0 and 1)
  7082.  ────────────────────────────────────────────────────────────────────────────
  7083.  
  7084.    Call:
  7085.  
  7086.    AH = 44H
  7087.    AL
  7088.       0 = Get device data
  7089.       1 = Set device data
  7090.    BX
  7091.       Handle
  7092.    DX
  7093.       Device data (see text)
  7094.  
  7095.    Return:
  7096.  
  7097.    Carry set:
  7098.    AX
  7099.       1 = Invalid function
  7100.       6 = Invalid handle
  7101.    Carry not set:
  7102.    DX
  7103.      Device data
  7104.  
  7105.  
  7106.    Comments:
  7107.  
  7108.    Function 44H, Codes 0 and 1, either gets or sets the data MS-DOS uses to
  7109.    control the device. AL must contain 0 to get the data or 1 to set it. BX
  7110.    must contain the handle. If AL is 1, DH must contain 0.
  7111.  
  7112.    The device-data word is specified or returned in DX. If bit 7 of the data
  7113.    is 1, the handle refers to a device and the other bits have the meanings
  7114.    shown in Table 1.23.
  7115.  
  7116.    Table 1.23
  7117.    MS-DOS Data Bit Values
  7118. ╓┌─┌──────────┌────────────────────┌─────────────────────────────────────────╖
  7119.    Bit        Value                Meaning
  7120.    ──────────────────────────────────────────────────────────────────────────
  7121.    Bit        Value                Meaning
  7122.    ──────────────────────────────────────────────────────────────────────────
  7123.    0          1                    Console input device
  7124.  
  7125.    1          1                    Console output device
  7126.  
  7127.    2          1                    Null device
  7128.  
  7129.    3          1                    Clock device
  7130.  
  7131.    4          1                    Reserved
  7132.  
  7133.    5          1                    Don't check for control characters
  7134.  
  7135.               0                    Check for control characters
  7136.  
  7137.    6          0                    End of file on input
  7138.  
  7139.    8-10                            Reserved
  7140.  
  7141.    11         1                    Device understands open/close
  7142.    Bit        Value                Meaning
  7143.    ──────────────────────────────────────────────────────────────────────────
  7144.   11         1                    Device understands open/close
  7145.  
  7146.    12                              Reserved
  7147.  
  7148.    13         1                    Device supports output until busy
  7149.  
  7150.    14         1                    Device can process control strings sent
  7151.                                    with Functions 4402H and 4403H (IOCtl
  7152.                                    character); bit can be read only, but not
  7153.                                    set
  7154.  
  7155.    15                              Reserved
  7156.    ──────────────────────────────────────────────────────────────────────────
  7157.  
  7158.  
  7159.    You must set the reserved bits to zero.
  7160.  
  7161.    The control characters referred to in the description of bit 5 are
  7162.    CONTROL+C, CONTROL+P, CONTROL+S, and CONTROL+Z. To read these characters
  7163.    as data, instead of as control characters, you must set bit 5 and use
  7164.    either Function 33H, CONTROL+C Check, or the MS-DOS break command to turn
  7165.    off CONTROL+C checking.
  7166.  
  7167.    If bit 7 of DX is 0, the handle refers to a file and the other bits have
  7168.    the following meanings:
  7169.  
  7170.    Bit        Value                Meaning
  7171.    ──────────────────────────────────────────────────────────────────────────
  7172.    0-5                             Drive number (0=A, 1=B, etc.)
  7173.    6          0                    The file has been written
  7174.    8-15                            Reserved
  7175.    ──────────────────────────────────────────────────────────────────────────
  7176.  
  7177.    If there is an error, the carry flag (CF) is set and the error code
  7178.    returns in AX:
  7179.  
  7180.    Code               Meaning
  7181.    ──────────────────────────────────────────────────────────────────────────
  7182.    1                  AL not 0 or 1, or AL is 1 but DH is not 0
  7183.    6                  Handle in BX not open or is invalid
  7184.    ──────────────────────────────────────────────────────────────────────────
  7185.  
  7186.    Macro Definition:
  7187.  
  7188.    ioctl_data macro  code,handle
  7189.               mov    bx,handle
  7190.               mov    al,code
  7191.               mov    ah,44H
  7192.               int    21H
  7193.               endm
  7194.  
  7195.    Example:
  7196.  
  7197.    The following program gets the device data for standard output, sets the
  7198.    bit that specifies not to check for control characters (bit 5), and then
  7199.    clears the bit.
  7200.  
  7201.    get     equ         0
  7202.    set     equ         1
  7203.    stdout  equ         1
  7204.    ;
  7205.    begin:  ioctl_data  get,stdout          ; THIS FUNCTION
  7206.            jc          error               ; routine not shown
  7207.            mov         dh,0                ; clear DH
  7208.            or          dl,20H              ; set bit 5
  7209.            ioctl_data  set,stdout          ; THIS FUNCTION
  7210.            jc          error               ; routine not shown
  7211.    ;
  7212.    ;   <control characters now treated as data, or "raw mode">
  7213.    ;
  7214.            ioctl_data  get,stdout          ; THIS FUNCTION
  7215.            jc          error               ; routine not shown
  7216.            mov         dh,0                ; clear DH
  7217.            and         dl,0DFH             ; clear bit 5
  7218.            ioctl_data  set,stdout          ; THIS FUNCTION
  7219.    ;
  7220.    ;  <control characters now interpreted, or "cooked mode">
  7221.    ;
  7222.  
  7223.  
  7224.  ────────────────────────────────────────────────────────────────────────────
  7225.  IOCtl Character (Function 44H, Codes 2 and 3)
  7226.  ────────────────────────────────────────────────────────────────────────────
  7227.  
  7228.    Call:
  7229.  
  7230.    AH = 44H
  7231.    AL
  7232.       2 = Send control data
  7233.       3 = Receive control data
  7234.    BX
  7235.       Handle
  7236.    CX
  7237.       Bytes to read or write
  7238.    DS:DX
  7239.       Pointer to buffer
  7240.  
  7241.    Return:
  7242.  
  7243.    Carry set:
  7244.    AX
  7245.       1 = Invalid function
  7246.       6 = Invalid handle
  7247.    Carry not set:
  7248.    AX
  7249.       Bytes transferred
  7250.  
  7251.  
  7252.    Comments:
  7253.  
  7254.    Function 44H, Codes 2 and 3, sends or receives control data to or from a
  7255.    character device. AL must contain 2 to send data or 3 to receive. BX must
  7256.    contain the handle of a character device, such as a printer or serial
  7257.    port. CX must contain the number of bytes to be read or written. DX must
  7258.    contain the offset (to the segment address in DS) of the data buffer.
  7259.  
  7260.    AX returns the number of bytes transferred. The device driver must support
  7261.    the IOCtl interface. If there is an error, the carry flag (CF) is set and
  7262.    the error code returns in AX:
  7263.  
  7264.    Code               Meaning
  7265.    ──────────────────────────────────────────────────────────────────────────
  7266.    1                  AL not 2 or 3, or device cannot perform the specified
  7267.                       function
  7268.  
  7269.    6                  Handle in BX not open or doesn't exist
  7270.    ──────────────────────────────────────────────────────────────────────────
  7271.  
  7272.    Macro Definition:
  7273.  
  7274.    ioctl_char  macro  code,handle,buffer
  7275.                mov    bx,handle
  7276.                mov    dx,offset buffer
  7277.                mov    al,code
  7278.                mov    ah,44H
  7279.                int    21H
  7280.                endm
  7281.  
  7282.  
  7283.    Example:
  7284.  
  7285.    No general example is applicable, since processing of IOCtl control data
  7286.    depends on the device being used, as well as the device driver.
  7287.  
  7288.  
  7289.  ────────────────────────────────────────────────────────────────────────────
  7290.  IOCtl Block (Function 44H, Codes 4 and 5)
  7291.  ────────────────────────────────────────────────────────────────────────────
  7292.  
  7293.    Call:
  7294.  
  7295.    AH = 44H
  7296.    AL
  7297.       4 = Send control data
  7298.       5 = Receive control data
  7299.    BL
  7300.       Drive number (0=default, 1=A, etc.)
  7301.    CX
  7302.       Bytes to read or write
  7303.    DS:DX
  7304.       Pointer to buffer
  7305.  
  7306.    Return:
  7307.  
  7308.    Carry set:
  7309.    AX
  7310.       1 = Invalid function
  7311.       5 = Invalid drive
  7312.    Carry not set:
  7313.    AX
  7314.       Bytes transferred
  7315.  
  7316.  
  7317.    Comments:
  7318.  
  7319.    Function 44H, Codes 4 and 5, sends or receives control data to or from a
  7320.    block device. AL must contain 4 to send data or 5 to receive. BL must
  7321.    contain the drive number (0=default, 1=A, etc.). CX must contain the
  7322.    number of bytes to be read or written. DX must contain the offset (to the
  7323.    segment address in DS) of the data buffer.
  7324.  
  7325.    AX returns the number of bytes transferred. The device driver must support
  7326.    the IOCtl interface. To determine whether or not it does, use Function
  7327.    4400H to get the device data, and test bit 14; if the bit is set, the
  7328.    driver supports IOCtl. If there is an error, the carry flag (CF) is set
  7329.    and the error code returns in AX:
  7330.  
  7331.    Code               Meaning
  7332.    ──────────────────────────────────────────────────────────────────────────
  7333.    1                  AL not 4 or 5, or device cannot perform the specified
  7334.                       function
  7335.  
  7336.    5                  Number in BL not a valid drive number
  7337.    ──────────────────────────────────────────────────────────────────────────
  7338.  
  7339.    Macro Definition:
  7340.  
  7341.    ioctl_status macro  code,drive,buffer
  7342.                 mov    bl,drive
  7343.                 mov    dx,offset buffer
  7344.                 mov    al,code
  7345.                 mov    ah,44H
  7346.                 int    21H
  7347.                 endm
  7348.  
  7349.    Example:
  7350.  
  7351.    No general example is applicable, since processing of IOCtl control data
  7352.    depends on the device being used, as well as the device driver.
  7353.  
  7354.  
  7355.  ────────────────────────────────────────────────────────────────────────────
  7356.  IOCtl Status (Function 44H, Codes 6 and 7)
  7357.  ────────────────────────────────────────────────────────────────────────────
  7358.  
  7359.    Call:
  7360.  
  7361.    AH = 44H
  7362.    AL
  7363.       6 = Check input status
  7364.       7 = Check output status
  7365.    BX
  7366.       Handle
  7367.  
  7368.    Return:
  7369.  
  7370.    Carry set:
  7371.    AX
  7372.       1        = Invalid function
  7373.       5        = Access denied
  7374.       6        = Invalid handle
  7375.      13        = Invalid data
  7376.    Carry not set:
  7377.    AL
  7378.       00H = Not ready
  7379.       0FFH = Ready
  7380.  
  7381.  
  7382.    Comments:
  7383.  
  7384.    Function 44H, Codes 6 and 7, checks whether or not the file or device
  7385.    associated with a handle is ready. AL must contain 6 to check whether the
  7386.    handle is ready for input or 7 to check whether the handle is ready for
  7387.    output. BX must contain the handle.
  7388.  
  7389.    AL returns the status:
  7390.  
  7391.                   Meaning for    Meaning for            Meaning for
  7392.    Value          Device         Input File            Output File
  7393.    ──────────────────────────────────────────────────────────────────────────
  7394.    00H            Not ready      Pointer is at EOF     Ready
  7395.    0FFH           Ready          Ready                 Ready
  7396.    ──────────────────────────────────────────────────────────────────────────
  7397.  
  7398.    An output file always returns ready, even if the disk is full. bp If there
  7399.    is an error, the carry flag (CF) is set and the error code returns in AX:
  7400.  
  7401.    Code               Meaning
  7402.    ──────────────────────────────────────────────────────────────────────────
  7403.    1                  AL not 6 or 7
  7404.    5                  Access denied
  7405.    6                  Number in BX not a valid, open handle
  7406.    13                 Invalid data
  7407.    ──────────────────────────────────────────────────────────────────────────
  7408.  
  7409.    Macro Definition:
  7410.  
  7411.    ioctl_status  macro  code,handle
  7412.                  mov    bx,handle
  7413.                  mov    al,code
  7414.                  mov    ah,44H
  7415.                  int    21H
  7416.                  endm
  7417.  
  7418.    Example:
  7419.  
  7420.    The following program displays a message that tells whether the file
  7421.    associated with handle 6 is ready for input or whether it is at
  7422.    end-of-file.
  7423.  
  7424.    stdout      equ          1
  7425.    ;
  7426.    message     db           "File is "
  7427.    ready       db           "ready."
  7428.    at_eof      db           "at EOF."
  7429.    crlf        db           ODH,OAH
  7430.    ;
  7431.    begin:      write_handle stdout,message,8   ; display message
  7432.                jc           write_error        ; routine not shown
  7433.                ioctl_status 6                  ; THIS FUNCTION
  7434.                jc           ioctl_error        ; routine not shown
  7435.                cmp          al,0               ; check status code
  7436.                jne          not_eof            ; file is ready
  7437.                write_handle stdout,at_eof,7    ; see Function 40H
  7438.                jc           write_error        ; routine not shown
  7439.                jmp          all_done           ; clean up & go home
  7440.    not_eof:    write_handle stdout,ready,6     ; see Function 40H
  7441.    all_done:   write_handle stdout,crlf,2      ; see Function 40H
  7442.                jc           write_error        ; routine not shown
  7443.  
  7444.  
  7445.  ────────────────────────────────────────────────────────────────────────────
  7446.  IOCtl Is Changeable (Function 44H, Code 08H)
  7447.  ────────────────────────────────────────────────────────────────────────────
  7448.  
  7449.    Call:
  7450.  
  7451.    AH = 44H
  7452.    AL = 08H
  7453.    BL
  7454.       Drive number (0=default, 1=A, etc.)
  7455.  
  7456.    Return:
  7457.  
  7458.    Carry set:
  7459.    AX
  7460.        1        = Invalid function
  7461.       15        = Invalid drive
  7462.    Carry not set:
  7463.    AX
  7464.       0 = Changeable
  7465.       1 = Not changeable
  7466.  
  7467.  
  7468.    Comments:
  7469.  
  7470.    Function 44H, Code 08H, checks whether a drive contains a removable or
  7471.    nonremovable disk. BL must contain the drive number (0=default, 1=A,
  7472.    etc.). AX returns 0 if the disk can be changed, 1 if it cannot.
  7473.  
  7474.    This call lets a program determine whether or not to issue a message to
  7475.    change disks.
  7476.  
  7477.    If there is an error, the carry flag (CF) is set and the error code
  7478.    returns in AX:
  7479.  
  7480.    Code               Meaning
  7481.    ──────────────────────────────────────────────────────────────────────────
  7482.    1                  Device does not support this call
  7483.    15                 Number in BL not a valid drive number
  7484.    ──────────────────────────────────────────────────────────────────────────
  7485.  
  7486.    When the call returns error 1 (because the driver doesn't support it), the
  7487.    caller assumes that the driver cannot be changed.
  7488.  
  7489.    Macro Definition:
  7490.  
  7491.    ioctl_change  macro  drive
  7492.                  mov    bl, drive
  7493.                  mov    al, 08H
  7494.                  mov    ah, 44H
  7495.                  int    21H
  7496.                  endm
  7497.  
  7498.    Example:
  7499.  
  7500.    The following program checks whether or not the current drive contains a
  7501.    removable disk. If not, processing continues; if so, the program prompts
  7502.    the user to replace the disk in the current drive.
  7503.  
  7504.    stdout    equ        1
  7505.    ;
  7506.    message   db        "Please replace disk in drive "
  7507.    drives    db        "ABCD"
  7508.    crlf      db         0DH,0AH
  7509.    ;
  7510.    begin:    ioctl_change 0          ; THIS FUNCTION
  7511.              jc           ioctl_error ; routine not shown
  7512.              cmp          ax,0       ; current drive changeable?
  7513.              jne          continue   ; no, continue processing
  7514.              write_handle stdout,message,29 ; see Function 40H
  7515.              jc           write_error ; routine not shown
  7516.              current_disk            ; see Function 19H
  7517.              xor          bx,bx      ; clear index
  7518.              mov          bl,al      ; get current drive
  7519.              display_char drives[bx] ; see Function 02H
  7520.              write_handle stdout,crlf,2 ; see Function 40H
  7521.              jc           write_error ; routine not shown
  7522.    continue:
  7523.    ;          (Further processing here)
  7524.  
  7525.  
  7526.  ────────────────────────────────────────────────────────────────────────────
  7527.  IOCtl Is Redirected Block (Function 44H, Code 09H)
  7528.  ────────────────────────────────────────────────────────────────────────────
  7529.  
  7530.    Call:
  7531.  
  7532.    AH = 44H
  7533.    AL = 09H
  7534.    BL
  7535.       Drive number (0=default, 1=A, etc.)
  7536.  
  7537.    Return:
  7538.  
  7539.    Carry set:
  7540.    AX
  7541.       1        = Invalid function code
  7542.      15        = Invalid drive number
  7543.    Carry not set:
  7544.    DX
  7545.       Device-attribute bits
  7546.  
  7547.  
  7548.    Comments:
  7549.  
  7550.    Function 44H, Code 09H, checks whether a drive letter refers to a drive on
  7551.    a Microsoft Networks workstation (local) or is redirected to a server
  7552.    (remote). BL must contain the drive number (0=default, 1=A, etc.).
  7553.  
  7554.    If the block device is local, DX returns the attribute word from the
  7555.    device header. If the block device is remote, only bit 12 (1000H) is set;
  7556.    the other bits are 0 (reserved).
  7557.  
  7558.    An application program should not test bit 12, because applications should
  7559.    not make distinctions between local and remote files (or devices).
  7560.    Programs should be written so that they will be independent of the
  7561.    location of a device that has been removed.
  7562.  
  7563.    If there is an error, the carry flag (CF) is set and the error code
  7564.    returns in AX:
  7565.  
  7566.    Code               Meaning
  7567.    ──────────────────────────────────────────────────────────────────────────
  7568.    1                  File sharing must be loaded to use this system call
  7569.    15                 Number in BL not a valid drive number
  7570.    ──────────────────────────────────────────────────────────────────────────
  7571.  
  7572.    Macro Definition:
  7573.  
  7574.    ioctl_rblock  macro  drive
  7575.                  mov    bl, drive
  7576.                  mov    al, 09H
  7577.                  mov    ah, 44H
  7578.                  int    21H
  7579.                  endm
  7580.  
  7581.    Example:
  7582.  
  7583.    The following program checks whether or not drive B is local or remote and
  7584.    displays the appropriate message.
  7585.  
  7586.    stdout    equ        1
  7587.    ;
  7588.    message   db        "Drive B: is "
  7589.    loc       db        "local."
  7590.    rem       db        "remote."
  7591.    crlf      db         0DH,0AH
  7592.    ;
  7593.    begin:    write_handle stdout,message,12  ; display message
  7594.              jc           write_error      ; routine not shown
  7595.              ioctl_rblock 2                ; THIS FUNCTION
  7596.              jc           ioctl_error      ; routine not shown
  7597.              test         dx,1000h         ; bit 12 set?
  7598.              jnz          not_loc          ; yes, it's remote
  7599.              write_handle stdout,loc,6     ; see Function 40H
  7600.              jc           write_error      ; routine not shown
  7601.              jmp          done
  7602.    not_loc:  write_handle stdout,rem,7     ; see Function 40H
  7603.              jc           write_error      ; routine not shown
  7604.    done:     write_handle stdout,crlf,2    ; see Function 40H
  7605.              jc           write_error      ; routine not shown
  7606.  
  7607.  
  7608.  ────────────────────────────────────────────────────────────────────────────
  7609.  IOCtl Is Redirected Handle (Function 44H, Code 0AH)
  7610.  ────────────────────────────────────────────────────────────────────────────
  7611.  
  7612.    Call:
  7613.  
  7614.    AH = 44H
  7615.    AL = 0AH
  7616.    BX
  7617.       Handle
  7618.  
  7619.    Return:
  7620.  
  7621.    Carry set:
  7622.    AX
  7623.       1 = Invalid function code
  7624.       6 = Invalid handle
  7625.    Carry not set:
  7626.    DX
  7627.       IOCtl bit field
  7628.  
  7629.  
  7630.    Comments:
  7631.  
  7632.    Function 44H, Code 0AH, checks whether a handle refers to a file or a
  7633.    device on a Microsoft Networks workstation (local) or is redirected to a
  7634.    server (remote). BX must contain the file handle. DX returns the IOCtl bit
  7635.    field; bit 15 is set if the handle refers to a remote file or device.
  7636.  
  7637.    An application program should not test bit 15, because applications should
  7638.    not make distinctions between local and remote files (or devices).
  7639.    Programs should be written so that they will be independent of the
  7640.    location of a device that has been removed.
  7641.  
  7642.    If there is an error, the carry flag (CF) is set and the error code
  7643.    returns in AX:
  7644.  
  7645.    Code               Meaning
  7646.    ──────────────────────────────────────────────────────────────────────────
  7647.    1                  Network must be loaded to use this system call
  7648.    6                  Handle in BX not a valid, open handle
  7649.    ──────────────────────────────────────────────────────────────────────────
  7650.  
  7651.    Macro Definition:
  7652.  
  7653.    ioctl_rhandle macro  handle
  7654.                  mov    bx, handle
  7655.                  mov    al, 0AH
  7656.                  mov    ah, 44H
  7657.                  int    21H
  7658.                  endm
  7659.  
  7660.    Example:
  7661.  
  7662.    The following program checks whether handle 5 refers to a local or remote
  7663.    file or a device and displays the appropriate message.
  7664.  
  7665.    stdout    equ        1
  7666.    ;
  7667.    message   db        "Handle 5 is "
  7668.    loc       db        "local."
  7669.    rem       db        "remote."
  7670.    crlf      db         0DH,0AH
  7671.    ;
  7672.    begin:    write_handle stdout,message,12; display message
  7673.              jc           write_error      ; routine not shown
  7674.              ioctl_rhandle 5               ; THIS FUNCTION
  7675.              jc           ioctl_error      ; routine not shown
  7676.              test         dx,8000h         ; bit 15 set?
  7677.              jnz          not_loc          ; yes, it's remote
  7678.              write_handle stdout,loc,6     ; see Function 40H
  7679.              jc           write_error      ; routine not shown
  7680.              jmp          done
  7681.    not_loc:  write_handle stdout,rem,7     ; see Function 40H
  7682.              jc           write_error      ; routine not shown
  7683.    done:     write_handle stdout,crlf,2    ; see Function 40H
  7684.              jc           write_error      ; routine not shown
  7685.  
  7686.  
  7687.  ────────────────────────────────────────────────────────────────────────────
  7688.  IOCtl Retry (Function 44H, Code 0BH)
  7689.  ────────────────────────────────────────────────────────────────────────────
  7690.  
  7691.    Call:
  7692.  
  7693.    AH = 44H
  7694.    AL = 0BH
  7695.    DX
  7696.       Number of retries
  7697.    CX
  7698.       Wait time
  7699.  
  7700.    Return:
  7701.  
  7702.    Carry set:
  7703.    AX
  7704.       1 = Invalid function code
  7705.    Carry not set:
  7706.       No error
  7707.  
  7708.  
  7709.    Comments:
  7710.  
  7711.    Function 44H, Code 0BH, specifies how many times MS-DOS should retry a
  7712.    disk operation that fails because of a file-sharing violation. DX must
  7713.    contain the number of retries. CX controls the pause between retries.
  7714.  
  7715.    MS-DOS retries this type of disk operation three times, unless you use
  7716.    this system call to specify a different number. After the specified number
  7717.    of retries, MS-DOS issues Interrupt 24H (Critical-Error-Handler Address)
  7718.    for the requesting process.
  7719.  
  7720.    The effect of the delay parameter in CX is machine-dependent because it
  7721.    specifies how many times MS-DOS should execute an empty loop. The actual
  7722.    time varies, depending on the processor and clock speed. You can determine
  7723.    the effect on your machine by using debug. Set the number of retries to 1
  7724.    and then time several values of CX. If there is an error, the carry flag
  7725.    (CF) is set and the error code returns in AX:
  7726.  
  7727.    Code               Meaning
  7728.    ──────────────────────────────────────────────────────────────────────────
  7729.    1                  File sharing must be loaded to use this system call
  7730.    ──────────────────────────────────────────────────────────────────────────
  7731.  
  7732.    Macro Definition:
  7733.  
  7734.    ioctl_retry  macro  retries, wait
  7735.                 mov    dx, retries
  7736.                 mov    cx, wait
  7737.                 mov    al, 0BH
  7738.                 mov    ah, 44H
  7739.                 int    21H
  7740.                 endm
  7741.  
  7742.    Example:
  7743.  
  7744.    The following program sets the number of sharing retries to 10 and
  7745.    specifies a delay of 1000 between retries.
  7746.  
  7747.    begin:    ioctl_retry  10,1000          ; THIS FUNCTION
  7748.              jc           error            ; routine not shown
  7749.  
  7750.  
  7751.  ────────────────────────────────────────────────────────────────────────────
  7752.  Generic IOCtl (for Handles) (Function 44H, Code 0CH)
  7753.  ────────────────────────────────────────────────────────────────────────────
  7754.  
  7755.    Call:
  7756.  
  7757.    AH = 44H
  7758.    AL = 0CH
  7759.    BX
  7760.        Handle
  7761.    CH = 05H
  7762.        Category code (printer device)
  7763.    CL
  7764.        Function (minor) code
  7765.    DS:DX
  7766.        Pointer to data buffer
  7767.  
  7768.    Return:
  7769.  
  7770.    Carry set:
  7771.    AX
  7772.        1        = Invalid function code
  7773.       --        = Any device error
  7774.    Carry not set:
  7775.        No error
  7776.  
  7777.  
  7778.    Comments:
  7779.  
  7780.    This call loads and selects code pages for devices on a per-device basis.
  7781.    It also sets or gets the output iteration count for a printer that
  7782.    supports "PRINT 'TIL BUSY."
  7783.  
  7784.    The video functions (type=display) are supported only if ansi.sys has been
  7785.    installed. If ansi.sys is not installed, mode sets the video state
  7786.    directly. This information reflects the latest mode command or any changes
  7787.    made by use of BIOS. This call uses BIO to get and set the states.
  7788.  
  7789.    The MS-DOS 4.0 mode command sets the values through this interface and the
  7790.    DOS utilities access the information through this interface.
  7791.  
  7792.    The category code may be one of the following:
  7793.  
  7794.    Code               Meaning
  7795.    ──────────────────────────────────────────────────────────────────────────
  7796.    00                 Unknown device
  7797.    01                 Serial printer
  7798.    03                 Console (display) device
  7799.    05                 Parallel printer
  7800.    ──────────────────────────────────────────────────────────────────────────
  7801.  
  7802.    The function code may be one of the following:
  7803.  
  7804.    Code               Meaning
  7805.    ──────────────────────────────────────────────────────────────────────────
  7806.    45H                Sets iteration count for printer
  7807.    4AH                Selects code page
  7808.    4CH                Starts prepare list
  7809.    4DH                Ends prepare list
  7810.    5FH                Sets display device
  7811.    65H                Gets iteration count for printer
  7812.    6AH                Query code page selected
  7813.    6BH                Query code page prepare list
  7814.    7FH                Gets display character (screen width, length, and
  7815.                       color)
  7816.    ──────────────────────────────────────────────────────────────────────────
  7817.  
  7818.    ──────────────────────────────────────────────────────────────────────────
  7819.    Note
  7820.      DS:DX points to a word that contains the new value for the total number
  7821.      of output iterations performed before proceeding. Thus, DS:DX points to
  7822.      a word that contains the character iteration count for the "PRINT 'TIL
  7823.      BUSY" loop. This is the number of times the device driver will wait for
  7824.      the device to signal "ready" before acknowledging "Device busy."
  7825.    ──────────────────────────────────────────────────────────────────────────
  7826.  
  7827.    Macro Definition:
  7828.  
  7829.    ioctl_handles        macro handle,function,category,buffer
  7830.                    mov ch,05H
  7831.                    mov cl,function
  7832.                    mov dx,offset buffer
  7833.                    mov bx,handle
  7834.                    mov ah,44H
  7835.                    mov al,0CH
  7836.                    int 21H
  7837.                    endm
  7838.  
  7839.    Example:
  7840.  
  7841.    The following program obtains device characteristics.
  7842.  
  7843.            mov    ax,440CH    ; Handle based generic IOCTL
  7844.            mov    bx,handle   ; Handle of open device
  7845.            mov    ch,03H      ; Type = display
  7846.            mov    cl,7FH      ; Subfunction for get
  7847.            lds    dx,buffer   ; Info buffer
  7848.            int    21H
  7849.            jc     error
  7850.         buffer  label  byte   ; Return buffer
  7851.            db     0           ; Info level (set to 0
  7852.                               ; before call)
  7853.            db     0           ; reserved    (")
  7854.                               ; for type display
  7855.            dw     7*2         ; length of data
  7856.            dw     flags       ; control flags
  7857.                               ; 0001H=intense (vs blink)
  7858.                               ; display mode
  7859.                               ; 1=text
  7860.                               ; 2=APA
  7861.            db     0           ; reserved
  7862.            dw     colors      ; # of colors (monochrome=0)
  7863.            dw     width       ; width of display (pixels)
  7864.            dw     length      ; length of display (pixels)
  7865.            dw     cols        ; width of display (chars)
  7866.            dw     rows        ; length of display (lines)
  7867.  
  7868.    To fetch code-page information, return the DBCS range vector and add the
  7869.    following:
  7870.  
  7871.            mov    ax=440Ch    ; Handle generic IOCTL
  7872.            mov    cx,036AH    ; Query display
  7873.            mov    bx,handle
  7874.            lds    dx,buffer   ; change buffer content
  7875.            int    21H
  7876.            jc     error
  7877.  
  7878.        Buffer   Label   Word
  7879.            dw   end-start     ; length
  7880.    start:
  7881.            dw   codepage      ; code page
  7882.            db   s1,e1         ; DBCS range
  7883.            db   0,0           ; end of list
  7884.  
  7885.    ──────────────────────────────────────────────────────────────────────────
  7886.    Note
  7887.      Some device drivers may only support the codepage value. As a result,
  7888.      the user of this call must check the returned length before assuming the
  7889.      DBCS information is present. The display.sys and printer.sys device
  7890.      drivers do not need to support the DBCS information. Only the drivers
  7891.      supplied with the Asian MS-DOS 4.0 will provide this support.
  7892.    ──────────────────────────────────────────────────────────────────────────
  7893.  
  7894.  
  7895.  ────────────────────────────────────────────────────────────────────────────
  7896.  Generic IOCtl (for Devices) (Function 44H, Code 0DH)
  7897.  ────────────────────────────────────────────────────────────────────────────
  7898.  
  7899.    Call:
  7900.  
  7901.    AH = 44H
  7902.    AL = 0DH
  7903.    BL
  7904.        Drive number
  7905.            (0 = default, 1 = A, etc.)
  7906.    CH = 08H
  7907.        Category (major) code
  7908.    CL
  7909.        Function (minor) code
  7910.    DS:DX
  7911.        Pointer to parameter block -1
  7912.  
  7913.    Return:
  7914.  
  7915.    Carry set:
  7916.    AX
  7917.        1        = Invalid function code
  7918.        2        = Invalid drive
  7919.        -        = Any device error
  7920.    Carry not set:
  7921.        No error
  7922.  
  7923.  
  7924.    Comments:
  7925.  
  7926.    The function code may be one of the following:
  7927.  
  7928.    Code               Meaning
  7929.    ──────────────────────────────────────────────────────────────────────────
  7930.    40                 Set device parameters
  7931.    41                 Write track on logical device
  7932.    42                 Format track on logical device
  7933.    60                 Get device parameters
  7934.    61                 Read track on logical device
  7935.    62                 Verify track on logical device
  7936.    ──────────────────────────────────────────────────────────────────────────
  7937.  
  7938.    ──────────────────────────────────────────────────────────────────────────
  7939.    Note
  7940.      You must issue "Set Parameters Device" before you can read, write,
  7941.      format, or verify a logical drive.
  7942.    ──────────────────────────────────────────────────────────────────────────
  7943.  
  7944.    You should use the following procedure when you want to read, write,
  7945.    format, or verify a logical drive:
  7946.  
  7947.    1. Save drive parameters using "Get Device Parameters."
  7948.  
  7949.    2. Set desired drive parameters using "Set Device Parameters."
  7950.  
  7951.    3. Perform the I/O operation.
  7952.  
  7953.    4. Restore the original drive parameters using "Set Device Parameters."
  7954.  
  7955.    Set Device Parameters (Function 440DH, CL=40H)
  7956.  
  7957.    When CL=40H, the parameter block has the following field format:
  7958.  
  7959.    ┌────────────────────────────────────┐
  7960.    │ BYTE      Special Functions        │
  7961.    ├────────────────────────────────────┤
  7962.    │ BYTE      Device Type              │
  7963.    ├────────────────────────────────────┤
  7964.    │ WORD      Device Attributes        │
  7965.    ├────────────────────────────────────┤
  7966.    │ WORD      Number of Cylinders      │
  7967.    ├────────────────────────────────────┤
  7968.    │ BYTE      Media Type               │
  7969.    ├────────────────────────────────────┤
  7970.    │           Device BPB               │
  7971.    ├────────────────────────────────────┤
  7972.    │           Track Layout             │
  7973.    └────────────────────────────────────┘
  7974.  
  7975.    These fields have the following meanings:
  7976.  
  7977.    Special Functions
  7978.  
  7979. ╓┌─┌──────────┌─────────┌────────────────────────────────────────────────────╖
  7980.    Bit        Value     Meaning
  7981.    ──────────────────────────────────────────────────────────────────────────
  7982.    Bit        Value     Meaning
  7983.    ──────────────────────────────────────────────────────────────────────────
  7984.    0          0         The Device BPB (BIOS Parameter Block) field contains
  7985.                         the new default BPB for this device. If a previous
  7986.                         Set Device Parameters call set this bit, Build BPB
  7987.                         returns the actual media BPB otherwise, it returns
  7988.                         the default BPB for the device.
  7989.  
  7990.               1         All subsequent Build BPB requests return the device
  7991.                         BPB.
  7992.  
  7993.    1          0         Read all fields of the parameter block.
  7994.  
  7995.               1         Ignore all fields of the parameter block except for
  7996.                         the Track Layout field.
  7997.  
  7998.    2          0         The sectors in the track may not all be the same
  7999.                         size. (You should not use this setting.)
  8000.  
  8001.               1         The sectors in the track are all the same size and
  8002.                         the sector numbers range between 1 and the total
  8003.    Bit        Value     Meaning
  8004.    ──────────────────────────────────────────────────────────────────────────
  8005.                        the sector numbers range between 1 and the total
  8006.                         number of sectors actually in the track. You should
  8007.                         always set this bit.
  8008.  
  8009.    3-7        0         These bits must be zero.
  8010.    ──────────────────────────────────────────────────────────────────────────
  8011.  
  8012.  
  8013.    Device Type
  8014.  
  8015.    This byte describes the physical device and is set by the device. When
  8016.    set, it has the following meanings:
  8017.  
  8018.    Value                                Meaning
  8019.    ──────────────────────────────────────────────────────────────────────────
  8020.    0                                    320/360kilobytes
  8021.    1                                    1.2 megabytes
  8022.    2                                    720 kilobytes
  8023.    3                                    8-inch, single-density
  8024.    4                                    8-inch, double-density
  8025.    5                                    Hard disk
  8026.    6                                    Tape drive
  8027.    7                                    1.44 megabytes
  8028.    ──────────────────────────────────────────────────────────────────────────
  8029.  
  8030.    Device Attributes
  8031.  
  8032.    Bit     Value            Meaning
  8033.    ──────────────────────────────────────────────────────────────────────────
  8034.            0                The media is removable.
  8035.    0       1                The media is not removable.
  8036.    1       0                Disk change-line is not supported (no door lock
  8037.                             support).
  8038.            1                Disk change-line is supported (door lock
  8039.                             support).
  8040.    2-7     0                These bits must be zero.
  8041.    ──────────────────────────────────────────────────────────────────────────
  8042.  
  8043.    Number of Cylinders
  8044.  
  8045.    This field indicates the maximum number of cylinders that the physical
  8046.    device can support. This information is set by the device.
  8047.  
  8048.    Media Type
  8049.  
  8050.    For drives that may contain different media, this field (which is
  8051.    device-dependent) indicates which media the drive expects.
  8052.  
  8053.    For a 1.2-megabyte disk, bit zero has the following meaning:
  8054.  
  8055.    Bit        Value                Meaning
  8056.    ──────────────────────────────────────────────────────────────────────────
  8057.    0          0                    Quad-density, 1.2-megabyte disk
  8058.               1                    Double-density, 320/360-kilobyte disk
  8059.    ──────────────────────────────────────────────────────────────────────────
  8060.  
  8061.    The default media type is a quad-density, 1.2-megabyte disk.
  8062.  
  8063.    Device BPB
  8064.  
  8065.    If bit 0 of the Special Functions field is clear, the BPB in this field is
  8066.    the new default BPB for the device.
  8067.  
  8068.    If bit 0 of the Special Functions field is set, the device driver returns
  8069.    the BPB from this field for subsequent Build BPB requests.
  8070.  
  8071.    Track Layout
  8072.  
  8073.    This field contains a table of variable length for each logical device and
  8074.    indicates the expected layout of the sectors on the media track. The field
  8075.    has the following format:
  8076.  
  8077.    ┌──────────────────────────────────────────────┐
  8078.    │ WORD      Sector Count -- total # of sectors │
  8079.    ├──────────────────────────────────────────────┤
  8080.    │ WORD      Sector Number -- sector #1         │
  8081.    ├──────────────────────────────────────────────┤
  8082.    │ WORD      Sector Size -- sector #1           │
  8083.    ├──────────────────────────────────────────────┤
  8084.    │ WORD      Sector Number -- sector #2         │
  8085.    ├──────────────────────────────────────────────┤
  8086.    │ WORD      Sector Size -- sector #2           │
  8087.    └──────────────────────────────────────────────┘
  8088.                          .
  8089.                          .
  8090.                          .
  8091.    ┌──────────────────────────────────────────────┐
  8092.    │ WORD      Sector Number -- sector #n         │
  8093.    ├──────────────────────────────────────────────│
  8094.    │ WORD      Sector Size -- sector #n           │
  8095.    └──────────────────────────────────────────────┘
  8096.  
  8097.    The Sector Count field indicates the total number of sectors. Each sector
  8098.    number must be unique and in the range of 1 to sector count (n).
  8099.  
  8100.    If bit 2 of the Special Functions field is set, all sector sizes must be
  8101.    the same.
  8102.  
  8103.    Get Device Parameters (Function 440DH, CL=60H)
  8104.  
  8105.    When CL=60H, the parameter block has the same field layout as for CL=40H.
  8106.    However, some of the fields have different meanings. These are described
  8107.    as follows:
  8108.  
  8109.    Special Functions
  8110.  
  8111.    Bit     Value            Meaning
  8112.    ──────────────────────────────────────────────────────────────────────────
  8113.    0       0                Returns the default BPB for the device.
  8114.            1                Returns the BPB that Build BPB would return.
  8115.    1-7     0                These bits must be zero.
  8116.    ──────────────────────────────────────────────────────────────────────────
  8117.  
  8118.    Track Layout
  8119.  
  8120.    The Get Device Parameters call does not use this field.
  8121.  
  8122.    Read/Write Track on Logical Drive (Function 440DH, CL=61H/CL=41H)
  8123.  
  8124.    To write to a track on a logical drive, set CL=41H. To read a track on a
  8125.    logical drive, set CL=61H.
  8126.  
  8127.    When CL=41H or 61H, the parameter block has the following format:
  8128.  
  8129.    ┌──────────────────────────────┐
  8130.    │ BYTE      Special Functions  │
  8131.    ├──────────────────────────────┤
  8132.    │ WORD      Head               │
  8133.    ├──────────────────────────────┤
  8134.    │ WORD      Cylinder           │
  8135.    ├──────────────────────────────┤
  8136.    │ WORD      First Sector       │
  8137.    ├──────────────────────────────┤
  8138.    │ WORD      Number of Sectors  │
  8139.    ├──────────────────────────────│
  8140.    │ DWORD     Transfer Address   │
  8141.    └──────────────────────────────┘
  8142.  
  8143.    These fields are described as follows:
  8144.  
  8145.    Special Functions
  8146.  
  8147.    This byte must be zero.
  8148.  
  8149.    Head
  8150.  
  8151.    This field contains the number of the head on which you perform the write
  8152.    or read.
  8153.  
  8154.    Cylinder
  8155.  
  8156.    This field contains the number of the cylinder on which you perform the
  8157.    write or read.
  8158.  
  8159.    First Sector
  8160.  
  8161.    This field contains the number of the first sector on which you perform
  8162.    the write or read. Sectors are numbered starting with zero, so the fourth
  8163.    sector is numbered 3.
  8164.  
  8165.    Number of Sectors
  8166.  
  8167.    This field contains the total number of sectors.
  8168.  
  8169.    Transfer Address
  8170.  
  8171.    This field contains the address for storing the data to be written or the
  8172.    data just read.
  8173.  
  8174.    Format/Verify Track on Logical Drive (Function 440DH, CL=42H/CL=62H)
  8175.  
  8176.    To format and verify a track on a logical drive, set CL=42H. To verify a
  8177.    track on a logical drive, set CL=62H.
  8178.  
  8179.    When CL=42H or 62H, the parameter block has the following format:
  8180.  
  8181.    ┌──────────────────────────────┐
  8182.    │ BYTE      Special Functions  │
  8183.    ├──────────────────────────────┤
  8184.    │ WORD      Head               │
  8185.    │──────────────────────────────┤
  8186.    │ WORD      Cylinder           │
  8187.    └──────────────────────────────┘
  8188.  
  8189.    These fields are described as follows:
  8190.  
  8191.    Special Functions
  8192.  
  8193.    This byte must be zero.
  8194.  
  8195.    Head
  8196.  
  8197.    This field contains the number of the head on which you perform the format
  8198.    or verify.
  8199.  
  8200.    Cylinder
  8201.  
  8202.    This field contains the number of the cylinder on which you perform the
  8203.    format or verify.
  8204.  
  8205.  
  8206.  ────────────────────────────────────────────────────────────────────────────
  8207.  Get/Set IOCtl Drive Map (Function 44H, Codes 0EH and 0FH)
  8208.  ────────────────────────────────────────────────────────────────────────────
  8209.  
  8210.    Call:
  8211.  
  8212.    AH = 44H
  8213.    AL
  8214.        OEH = Get logical drive map
  8215.        OFH = Set logical drive map
  8216.    BX
  8217.        Drive number
  8218.            (0 = default, 1 = A, etc.)
  8219.  
  8220.    Return:
  8221.  
  8222.    Carry set:
  8223.    AX
  8224.        1 = Invalid function code
  8225.        5 = Invalid drive
  8226.    Carry not set:
  8227.    AL = Logical drive mapped onto physical drive
  8228.         (= 0 if only one drive is
  8229.         assigned to this physical drive)
  8230.  
  8231.  
  8232.    Comments:
  8233.  
  8234.    MS-DOS supports the mapping of multiple logical drives onto a single
  8235.    physical block device. Get IOCtl Drive Map lets you query the DOS about
  8236.    which logical drive is currently mapped onto the corresponding physical
  8237.    device. Set IOCtl Drive Map alters the device that is currently mapped
  8238.    onto the physical device. These functions are only useful if there is more
  8239.    than one logical block device mapped onto a single physical device.
  8240.  
  8241.    A possible use for these functions is with applications that want to
  8242.    disable the DOS prompt in order to place the correct floppy disk in the
  8243.    drive when accessing the other logical drive.
  8244.  
  8245.    To detect whether or not a logical device currently owns the physical
  8246.    device to which it is mapped, a program needs to check the value in AL
  8247.    after calling Function 440EH or 440FH (Get/Set IOCtl Drive Map).
  8248.  
  8249.  
  8250.  ────────────────────────────────────────────────────────────────────────────
  8251.  Duplicate File Handle (Function 45H)
  8252.  ────────────────────────────────────────────────────────────────────────────
  8253.  
  8254.    Call:
  8255.  
  8256.    AH = 45H
  8257.    BX
  8258.       Handle
  8259.  
  8260.    Return:
  8261.  
  8262.    Carry set:
  8263.    AX
  8264.       4 = Too many open files
  8265.       6 = Invalid handle
  8266.    Carry not set:
  8267.    AX
  8268.       New handle
  8269.  
  8270.  
  8271.    Comments:
  8272.  
  8273.    Function 45H creates an additional handle for a file. BX must contain the
  8274.    handle of an open file.
  8275.  
  8276.    MS-DOS returns the new handle in AX. The new handle refers to the same
  8277.    file as the handle in BX, with the file pointer at the same position.
  8278.  
  8279.    After you use this function request, moving the read/write pointer of
  8280.    either handle also moves the pointer for the other handle. You usually use
  8281.    this function request to redirect standard input (handle 0) and standard
  8282.    output (handle 1). For a description of standard input, standard output,
  8283.    and the advantages and techniques of manipulating them, see Software Tools
  8284.    by Brian W. Kernighan and P.J. Plauger (Addison-Wesley Publishing Co.,
  8285.    1976).
  8286.  
  8287.    If there is an error, the carry flag (CF) is set and the error code
  8288.    returns in AX:
  8289.  
  8290.    Code               Meaning
  8291.    ──────────────────────────────────────────────────────────────────────────
  8292.    4                  Too many open files (no handle available)
  8293.    6                  Handle not open or is invalid
  8294.    ──────────────────────────────────────────────────────────────────────────
  8295.  
  8296.    Macro Definition:
  8297.  
  8298.    xdup  macro  handle
  8299.          mov    bx,handle
  8300.          mov    ah,45H
  8301.          int    21H
  8302.          endm
  8303.  
  8304.    Example:
  8305.  
  8306.    The following program redirects standard output (handle 1) to a file named
  8307.    dirfile, invokes a second copy of command.com to list the directory (which
  8308.    writes the directory to dirfile), and then restores standard input to
  8309.    handle 1.
  8310.  
  8311.    pgm_file  db    "command.com",0
  8312.    cmd_line  db    9,"/c dir /w",0dH
  8313.    parm_blk  db    14 dup (0)
  8314.    path            db  "dirfile",0
  8315.    dir_file        dw      ?       ;  For handle
  8316.    sav_stdout dw   ?               ;  For handle
  8317.    ;
  8318.    begin:    set_block  last_inst  ;  See Function 4AH
  8319.              jc      error_setblk  ;  Routine not shown
  8320.              create_handle  path,0 ;  See Function 3CH
  8321.              jc      error_create  ;  Routine not shown
  8322.              mov     dir_file,ax   ;  Save handle
  8323.              xdup    1             ;  THIS FUNCTION
  8324.              jc      error_xdup    ;  Routine not shown
  8325.              mov     sav_stdout,ax ;  Save handle
  8326.              xdup2   dir_file,1    ;  See Function 46H
  8327.              jc      error_xdup2   ;  Routine not shown
  8328.              exec    pgm_file,cmd_line,parm_blk ;  See Function 4BH
  8329.              jc      error_exec    ;  Routine not shown
  8330.              xdup2   sav_stdout,1  ;  See Function 46H
  8331.              jc      error_xdup2   ;  Routine not shown
  8332.              close_handle sav_stdout ;  See Function 3EH
  8333.              jc      error_close   ;  Routine not shown
  8334.              close_handle dir_file ;  See Function 3EH
  8335.              jc      error_close   ;  Routine not shown
  8336.  
  8337.  
  8338.  ────────────────────────────────────────────────────────────────────────────
  8339.  Force Duplicate File Handle (Function 46H)
  8340.  ────────────────────────────────────────────────────────────────────────────
  8341.  
  8342.    Call:
  8343.  
  8344.    AH = 46H
  8345.    BX
  8346.       Handle
  8347.    CX
  8348.       Second handle
  8349.  
  8350.    Return:
  8351.  
  8352.    Carry set:
  8353.    AX
  8354.       4 = Too many open files
  8355.       6 = Invalid handle
  8356.    Carry not set:
  8357.       No error
  8358.  
  8359.  
  8360.    Comments:
  8361.  
  8362.    Function 46H forces a specified handle to refer to the same file as a
  8363.    second handle already associated with an open file. BX must contain the
  8364.    handle of the open file; CX must contain the second handle.
  8365.  
  8366.    On return, the handle in CX now refers to the same file at the same
  8367.    position as the handle in BX. If the file referred to by the handle in CX
  8368.    was open at the time of the call, this function closes it.
  8369.  
  8370.    After you use this call, moving the read/write pointer of either handle
  8371.    also moves the pointer for the other handle. Normally, you would use this
  8372.    function request to redirect standard input (handle 0) and standard output
  8373.    (handle 1). For a description of standard input, standard output, and the
  8374.    advantages and techniques of manipulating them, see Software Tools by
  8375.    Brian W. Kernighan and P.J. Plauger (Addison-Wesley Publishing Co., 1976).
  8376.  
  8377.    If there is an error, the carry flag (CF) is set and the error code
  8378.    returns in AX:
  8379.  
  8380.    Code               Meaning
  8381.    ──────────────────────────────────────────────────────────────────────────
  8382.    4                  Too many open files (no handle available)
  8383.    6                  Handle not open or is invalid
  8384.    ──────────────────────────────────────────────────────────────────────────
  8385.  
  8386.    Macro Definition:
  8387.  
  8388.    xdup2  macro  handle1,handle2
  8389.           mov    bx,handle1
  8390.           mov    cx,handle2
  8391.           mov    ah,46H
  8392.           int    21H
  8393.           endm
  8394.  
  8395.    Example:
  8396.  
  8397.    The following program redirects standard output (handle 1) to a file named
  8398.    dirfile, invokes a second copy of command.com to list the directory (which
  8399.    writes the directory to dirfile), and then restores standard input to
  8400.    handle 1.
  8401.  
  8402.    pgm_file  db    "command.com",0
  8403.    cmd_line  db    9,"/c dir /w",0dH
  8404.    parm_blk  db    14 dup (0)
  8405.    path            db  "dirfile",0
  8406.    dir_file        dw      ?       ;  For handle
  8407.    sav_stdout dw   ?               ;  For handle
  8408.    ;
  8409.    begin:    set_block  last_inst  ;  See Function 4AH
  8410.              jc      error_setblk  ;  Routine not shown
  8411.              create_handle  path,0 ;  See Function 3CH
  8412.              jc      error_create  ;  Routine not shown
  8413.              mov     dir_file,ax   ;  Save handle
  8414.              xdup    1             ;  See Function 45H
  8415.              jc      error_xdup    ;  Routine not shown
  8416.              mov     sav_stdout,ax ;  Save handle
  8417.              xdup2   dir_file,1    ;
  8418.              jc      error_xdup2   ;  Routine not shown
  8419.              exec    pgm_file,cmd_line,parm_blk ;  See Function 4BH
  8420.              jc      error_exec    ;  Routine not shown
  8421.              xdup2   sav_stdout,1  ;  THIS FUNCTION
  8422.              jc      error_xdup2   ;  Routine not shown
  8423.              close_handle sav_stdout ;  See Function 3EH
  8424.              jc      error_close   ;  Routine not shown
  8425.              close_handle dir_file ;  See Function 3EH
  8426.              jc      error_close   ;  Routine not shown
  8427.  
  8428.  
  8429.  ────────────────────────────────────────────────────────────────────────────
  8430.  Get Current Directory (Function 47H)
  8431.  ────────────────────────────────────────────────────────────────────────────
  8432.  
  8433.    Call:
  8434.  
  8435.    AH = 47H
  8436.    DS:SI
  8437.       Pointer to 64-byte memory area
  8438.    DL
  8439.       Drive number
  8440.            (0 = default, 1 = A, etc.)
  8441.  
  8442.    Return:
  8443.  
  8444.    Carry set:
  8445.    AX
  8446.       15 = Invalid drive number
  8447.    Carry not set:
  8448.       No error
  8449.  
  8450.  
  8451.    Comments:
  8452.  
  8453.    Function 47H returns the pathname of the current directory on a specified
  8454.    drive. DL must contain a drive number (0=default, 1=A, etc.). SI must
  8455.    contain the offset (from the segment address in DS) of a 64-byte memory
  8456.    area.
  8457.  
  8458.    MS-DOS places an ASCIZ string in the memory area, consisting of the path
  8459.    (starting from the root directory) of the current directory for the drive
  8460.    specified in DL. The string does not begin with a backslash and does not
  8461.    include the drive letter.
  8462.  
  8463.    If there is an error, the carry flag (CF) is set and the error code
  8464.    returns in AX:
  8465.  
  8466.    Code               Meaning
  8467.    ──────────────────────────────────────────────────────────────────────────
  8468.    15                 Number in DL not a valid drive number
  8469.    ──────────────────────────────────────────────────────────────────────────
  8470.  
  8471.    Macro Definition:
  8472.  
  8473.    get_dir  macro   drive,buffer
  8474.             mov     dl,drive
  8475.             mov     si,offset buffer
  8476.             mov     ah,47H
  8477.             int     21H
  8478.             endm
  8479.  
  8480.    Example:
  8481.  
  8482.    The following program displays the current directory that is on the disk
  8483.    in drive B.
  8484.  
  8485.    disk        db      "b:\#"
  8486.    buffer      db       64 dup (?)
  8487.    ;
  8488.    begin:      get_dir  2,buffer       ; THIS FUNCTION
  8489.                jc       error_dir      ; Routine not shown
  8490.                display  disk           ; See Function 09H
  8491.                display_asciz  buffer  ; See end of chapter
  8492.  
  8493.  
  8494.  ────────────────────────────────────────────────────────────────────────────
  8495.  Allocate Memory (Function 48H)
  8496.  ────────────────────────────────────────────────────────────────────────────
  8497.  
  8498.    Call:
  8499.  
  8500.    AH = 48H
  8501.    BX
  8502.      Paragraphs of memory requested
  8503.  
  8504.    Return:
  8505.  
  8506.    Carry set:
  8507.    AX
  8508.      7 = Memory-control blocks damaged
  8509.      8 = Insufficient memory
  8510.    BX
  8511.      Paragraphs of memory available
  8512.    Carry not set:
  8513.    AX
  8514.      Segment address of allocated memory
  8515.  
  8516.  
  8517.    Comments:
  8518.  
  8519.    Function 48H tries to allocate the specified amount of memory to the
  8520.    current process. BX must contain the number of paragraphs of memory (one
  8521.    paragraph is 16 bytes).
  8522.  
  8523.    If sufficient memory is available to satisfy the request, AX returns the
  8524.    segment address of the allocated memory (the offset is 0). If sufficient
  8525.    memory is not available, BX returns the number of paragraphs of memory in
  8526.    the largest available block.
  8527.  
  8528.    If there is an error, the carry flag (CF) is set and the error code
  8529.    returns in AX:
  8530.  
  8531.    Code               Meaning
  8532.    ──────────────────────────────────────────────────────────────────────────
  8533.    7                  Memory-control blocks damaged (a user program changed
  8534.                       memory that didn't belong to it)
  8535.  
  8536.    8                  Not enough free memory to satisfy the request
  8537.    ──────────────────────────────────────────────────────────────────────────
  8538.  
  8539.    Macro Definition:
  8540.  
  8541.    allocate_memory  macro   bytes
  8542.                     mov     bx,bytes
  8543.                     mov     cl,4
  8544.                     shr     bx,cl
  8545.                     inc     bx
  8546.                     mov     ah,48H
  8547.                     int     21H
  8548.                     endm
  8549.  
  8550.    Example:
  8551.  
  8552.    The following program opens the file named textfile.asc, calculates its
  8553.    size with Function 42H (Move File Pointer), allocates a block of memory
  8554.    the size of the file, reads the file into the allocated memory block, and
  8555.    then frees the allocated memory.
  8556.  
  8557.    path      db      "textfile.asc",0
  8558.    msg1      db      "File loaded into allocated memory block.",
  8559.                       0DH,0AH
  8560.    msg2      db      "Allocated memory now being freed
  8561.                       (deallocated).",0DH,0AH
  8562.    handle    dw       ?
  8563.    mem_seg   dw       ?
  8564.    file_len  dw       ?
  8565.    ;
  8566.    begin:    open_handle  path,0
  8567.              jc       error_open    ; Routine not shown
  8568.              mov      handle,ax     ; Save handle
  8569.              move_ptr handle,0,0,2  ; See Function 42H
  8570.              jc       error_move    ; Routine not shown
  8571.              mov      file_len,ax   ; Save file length
  8572.              set_block  last_inst   ; See Function 4AH
  8573.              jc       error_setblk  ; Routine not shown
  8574.              allocate_memory  file_len ; THIS FUNCTION
  8575.              jc       error_alloc   ; Routine not shown
  8576.              mov      mem_seg,ax    ; Save address of new memory
  8577.              move_ptr handle,0,0,0  ; See Function 42H
  8578.              jc       error_move    ; Routine not shown
  8579.              push     ds            ; Save DS
  8580.              mov      ax,mem_seg    ; Get segment of new memory
  8581.              mov      ds,ax         ; Point DS at new memory
  8582.              read_handle  cs:handle,0,cs:file_len ; Read file into
  8583.    ;                                                new memory
  8584.              pop      ds            ; Restore DS
  8585.              jc       error_read    ; Routine not shown
  8586.    ;          (CODE TO PROCESS FILE GOES HERE)
  8587.              write_handle stdout,msg1,42 ; See Function 40H
  8588.              jc       write_error   ; Routine not shown
  8589.              free_memory  mem_seg   ; See Function 49H
  8590.              jc       error_freemem ; Routine not shown
  8591.              write_handle stdout,msg2,49 ; See Function 40H
  8592.              jc       write_error   ; Routine not shown
  8593.  
  8594.  
  8595.  ────────────────────────────────────────────────────────────────────────────
  8596.  Free Allocated Memory (Function 49H)
  8597.  ────────────────────────────────────────────────────────────────────────────
  8598.  
  8599.    Call:
  8600.  
  8601.    AH = 49H
  8602.    ES
  8603.       Segment address of memory to be
  8604.       freed
  8605.  
  8606.    Return:
  8607.  
  8608.    Carry set:
  8609.    AX
  8610.       7 = Memory-control blocks damaged
  8611.       9 = Incorrect segment
  8612.    Carry not set:
  8613.       No error
  8614.  
  8615.  
  8616.    Comments:
  8617.  
  8618.    Function 49H frees (makes available) a block of memory previously
  8619.    allocated with Function 48H (Allocate Memory). ES must contain the
  8620.    segment address of the memory block to be freed.
  8621.  
  8622.    If there is an error, the carry flag (CF) is set and the error code
  8623.    returns in AX:
  8624.  
  8625.    Code               Meaning
  8626.    ──────────────────────────────────────────────────────────────────────────
  8627.    7                  Memory-control blocks damaged (a user program changed
  8628.                       memory that didn't belong to it)
  8629.  
  8630.    9                  Memory pointed to by ES was not allocated with
  8631.                       Function 48H
  8632.    ──────────────────────────────────────────────────────────────────────────
  8633.  
  8634.    Macro Definition:
  8635.  
  8636.    free_memory  macro   seg_addr
  8637.                 mov     ax,seg_addr
  8638.                 mov     es,ax
  8639.                 mov     ah,49H
  8640.                 int     21H
  8641.                 endm
  8642.  
  8643.    Example:
  8644.  
  8645.    The following program opens a file named textfile.asc, calculates its size
  8646.    with Function 42H (Move File Pointer), allocates a block of memory the
  8647.    size of the file, reads the file into the allocated memory block, and then
  8648.    frees the allocated memory.
  8649.  
  8650.    path      db      "textfile.asc",0
  8651.    msg1      db      "File loaded into allocated memory block.",
  8652.                       0DH,0AH
  8653.    msg2      db      "Allocated memory now being freed
  8654.                       (deallocated).",0DH,0AH
  8655.    handle    dw       ?
  8656.    mem_seg   dw       ?
  8657.    file_len  dw       ?
  8658.    ;
  8659.    begin:    open_handle  path,0
  8660.              jc       error_open    ; Routine not shown
  8661.              mov      handle,ax     ; Save handle
  8662.              move_ptr handle,0,0,2  ; See Function 42H
  8663.              jc       error_move    ; Routine not shown
  8664.              mov      file_len,ax   ; Save file length
  8665.              set_block  last_inst   ; See Function 4AH
  8666.              jc       error_setblk  ; Routine not shown
  8667.              allocate_memory  file_len ; See Function 48H
  8668.              jc       error_alloc   ; Routine not shown
  8669.              mov      mem_seg,ax    ; Save address of new memory
  8670.              mov_ptr  handle,0,0,0  ; See Function 42H
  8671.              jc       error_move    ; Routine not shown
  8672.              push     ds            ; Save DS
  8673.              mov      ax,mem_seg    ; Get segment of new memory
  8674.              mov      ds,ax         ; Point DS at new memory
  8675.              read_handle  handle,code,file_len ; Read file into
  8676.    ;                                             new memory
  8677.              pop      ds            ; Restore DS
  8678.              jc       error_read    ; Routine not shown
  8679.    ;          (CODE TO PROCESS FILE GOES HERE)
  8680.              write_handle stdout,msg1,42 ; See Function 40H
  8681.              jc       write_error   ; Routine not shown
  8682.              free_memory  mem_seg   ; THIS FUNCTION
  8683.              jc       error_freemem ; Routine not shown
  8684.              write_handle stdout,msg2,49 ; See Function 40H
  8685.              jc       write_error   ; Routine not shown
  8686.  
  8687.  
  8688.  ────────────────────────────────────────────────────────────────────────────
  8689.  Set Block (Function 4AH)
  8690.  ────────────────────────────────────────────────────────────────────────────
  8691.  
  8692.    Call:
  8693.  
  8694.    AH = 4AH
  8695.    BX
  8696.       Paragraphs of memory
  8697.    ES
  8698.       Segment address of memory area
  8699.  
  8700.    Return:
  8701.  
  8702.    Carry set:
  8703.    AX
  8704.       7 = Memory-control blocks damaged
  8705.       8 = Insufficient memory
  8706.       9 = Incorrect segment
  8707.    BX
  8708.       Paragraphs of memory available
  8709.    Carry not set:
  8710.       No error
  8711.  
  8712.  
  8713.    Comments:
  8714.  
  8715.    Function 4AH changes the size of a memory-allocation block. ES must
  8716.    contain the segment address of the memory block. BX must contain the new
  8717.    size of the memory block, in paragraphs (one paragraph is 16 bytes).
  8718.  
  8719.    MS-DOS attempts to change the size of the memory block. If the call fails
  8720.    on a request to increase memory, BX returns the maximum size (in
  8721.    paragraphs) to which the block can be increased.
  8722.  
  8723.    Since MS-DOS allocates all available memory to a .com program, you would
  8724.    use this call most often to reduce the size of a program's initial
  8725.    memory-allocation block.
  8726.  
  8727.    If there is an error, the carry flag (CF) is set and the error code
  8728.    returns in AX:
  8729.  
  8730.    Code               Meaning
  8731.    ──────────────────────────────────────────────────────────────────────────
  8732.    7                  Memory-control blocks destroyed (a user program changed
  8733.                       memory that didn't belong to it)
  8734.  
  8735.    8                  Not enough free memory to satisfy the request
  8736.  
  8737.    9                  Wrong address in ES (the memory block it points to
  8738.    ──────────────────────────────────────────────────────────────────────────
  8739.  
  8740.    The following macro shrinks the initial memory-allocation block of a .com
  8741.    program. It takes as a parameter the offset of the first byte following
  8742.    the last instruction of a program (LAST_INST in the sample programs), uses
  8743.    it to calculate the number of paragraphs in the program, and then adds 17
  8744.    to the result: one to round up and 16 to set aside 256 bytes for a stack.
  8745.    It then sets up SP and BP to point to this stack.
  8746.  
  8747.    Macro Definition:
  8748.  
  8749.    set_block  macro   last_byte
  8750.               mov     bx,offset last_byte
  8751.               mov     cl,4
  8752.               shr     bx,cl
  8753.               add     bx,17
  8754.               mov     ah,4AH
  8755.               int     21H
  8756.               mov     ax,bx
  8757.               shl     ax,cl
  8758.               dec     ax
  8759.               mov     sp,ax
  8760.               mov     bp,sp
  8761.               endm
  8762.  
  8763.    Example:
  8764.  
  8765.    The following program invokes a second copy of command.com and executes a
  8766.    dir (directory) command.
  8767.  
  8768.    pgm_file  db      "command.com",0
  8769.    cmd_line  db       9,"/c dir /w",0DH
  8770.    parm_blk  db       14 dup (?)
  8771.    reg_save  db       10 dup (?)
  8772.    ;
  8773.    begin: set_block  last_inst                   ; THIS FUNCTION
  8774.           exec       pgm_file,cmd_line,parm_blk,0 ; See Function 4BH
  8775.  
  8776.  
  8777.  ────────────────────────────────────────────────────────────────────────────
  8778.  Load and Execute Program (Function 4BH, Code 00H)
  8779.  ────────────────────────────────────────────────────────────────────────────
  8780.  
  8781.    Call:
  8782.  
  8783.    AH = 4BH
  8784.    AL = 00H
  8785.    DS:DX
  8786.       Pointer to pathname
  8787.    ES:BX
  8788.       Pointer to parameter block
  8789.  
  8790.    Return:
  8791.  
  8792.    Carry set:
  8793.    AX
  8794.       1        = Invalid function
  8795.       2        = File not found
  8796.       3        = Path not found
  8797.       4        = Too many open files
  8798.       5        = Access denied
  8799.       8        = Insufficient memory
  8800.      10        = Bad environment
  8801.      11        = Bad format
  8802.    Carry not set:
  8803.      No error
  8804.  
  8805.  
  8806.    Comments:
  8807.  
  8808.    Function 4BH, Code 00H, loads and executes a program. DX must contain the
  8809.    offset (from the segment address in DS) of an ASCIZ string that specifies
  8810.    the drive and pathname of an executable program file. BX must contain the
  8811.    offset (from the segment address in ES) of a parameter block. AL must
  8812.    contain 0.
  8813.  
  8814.    There must be enough free memory for MS-DOS to load the program file.
  8815.    MS-DOS allocates all available memory to a program when it loads it, so
  8816.    you must free some memory with Function 4AH (Set Block) before using this
  8817.    function request to load and execute another program. Unless you or MS-DOS
  8818.    needs the memory for some other purpose, you should shrink the memory to
  8819.    the minimum amount required by the current process before issuing this
  8820.    request. MS-DOS creates a Program Segment Prefix for the program being
  8821.    loaded and sets the terminate and CONTROL+C addresses to the instruction
  8822.    that immediately follows the call to Function 4BH in the invoking program.
  8823.  
  8824.    The parameter block consists of four addresses:
  8825.  
  8826.    Table 1.24
  8827.    Contents of the Parameter Block
  8828.    Offset     Length
  8829.    (Hex)      (Bytes)              Description
  8830.    ──────────────────────────────────────────────────────────────────────────
  8831.    00         2 (word)             Segment address of the environment to be
  8832.                                    passed; 00H means copy the parent
  8833.                                    program's environment
  8834.  
  8835.    02         4 (dword)            Segment: Offset of command line to be
  8836.                                    placed at offset 80H of the new Program
  8837.                                    Segment Prefix. Must be a correctly formed
  8838.                                    command line no longer than 128 bytes
  8839.  
  8840.    06         4 (dword)            Segment: Offset of FCB to be placed at
  8841.                                    offset 5CH of the new Program Segment
  8842.                                    Prefix (the Program Segment Prefix is
  8843.                                    described in Chapter 4, "MS-DOS Control
  8844.                                    Blocks and Work Areas")
  8845.  
  8846.    0A         4 (dword)            Segment: Offset of FCB to be placed at
  8847.                                    offset 6CH of the new Program Segment
  8848.    ──────────────────────────────────────────────────────────────────────────
  8849.  
  8850.    All open files of a program are available to the newly loaded program,
  8851.    giving the parent program control over the definition of standard input,
  8852.    output, auxiliary, and printer devices. For example, a program could write
  8853.    a series of records to a file, open the file as standard input, open a
  8854.    second file as standard output, and then use Function 4BH, Code 00H, (Load
  8855.    and Execute Program) to load and execute a program that takes its input
  8856.    from standard input, sorts records, and writes to standard output.
  8857.  
  8858.    The loaded program also receives an environment, a series of ASCIZ strings
  8859.    of the form parameter=value (for example, verify= on). The environment
  8860.    must begin on a paragraph boundary, be less than 32 kilobytes long, and
  8861.    end with a byte of 00H (that is, the final entry consists of an ASCIZ
  8862.    string followed by two bytes of 00H). Following the last byte of zeros is
  8863.    a set of initial arguments passed to a program containing a word count
  8864.    followed by an ASCIZ string. If the call finds the file in the current
  8865.    directory, the ASCIZ string contains the drive and pathname of the
  8866.    executable program as passed to Function 4BH. If the call finds the file
  8867.    in the path, it concatenates the filename with the path information. (A
  8868.    program may use this area to determine from where it was loaded.) If the
  8869.    word-environment address is 0, the loaded program either inherits a copy
  8870.    of the parent program's environment or receives a new environment built
  8871.    for it by the parent. Place the segment address of the environment at
  8872.    offset 2CH of the new Program Segment Prefix. To build an environment for
  8873.    the loaded program, put it on a paragraph boundary and place the segment
  8874.    address of the environment in the first word of the parameter block. To
  8875.    pass a copy of the parent's environment to the loaded program, put 00H in
  8876.    the first word of the parameter block.
  8877.  
  8878.    If there is an error, the carry flag (CF) is set and the error code
  8879.    returns in AX:
  8880.  
  8881.    Code               Meaning
  8882.    ──────────────────────────────────────────────────────────────────────────
  8883.    1                  AL not 0 or 3
  8884.  
  8885.    2                  Program file not found
  8886.  
  8887.    3                  Path invalid or not found
  8888.  
  8889.    4                  Too many open files (no handle available)
  8890.  
  8891.    5                  Directory full, a directory with the same name exists,
  8892.                       or a file with the same name exists
  8893.  
  8894.    8                  Not enough memory to load the program
  8895.  
  8896.    10                 Environment appears longer than 32 kilobytes
  8897.  
  8898.    11                 Program file is a .exe file that contains internally
  8899.    ──────────────────────────────────────────────────────────────────────────
  8900.  
  8901.    Executing Another Copy of Command.com
  8902.  
  8903.    Since command.com builds pathnames, searches command paths for program
  8904.    files, and relocates .exe files, the simplest way to load and execute
  8905.    another program is to load and execute an additional copy of command.com,
  8906.    passing it a command line that includes the /c switch, which invokes the
  8907.    .com or .exe file.
  8908.  
  8909.    This action requires 17 kilobytes of available memory, so a program that
  8910.    does it should be sure to shrink its initial memory-allocation block with
  8911.    Function 4AH (Set Block). The following is the format of a command line
  8912.    that contains the /c switch:
  8913.  
  8914.    length,/c command,0DH
  8915.  
  8916.    where:
  8917.  
  8918.    Length is the length of the command line, counting the length byte but not
  8919.    the ending carriage-return (0DH).
  8920.  
  8921.    Command is any valid MS-DOS command.
  8922.  
  8923.    0DH is a carriage-return character.
  8924.  
  8925.    If a program executes another program directly──naming it as the program
  8926.    file to Function 4BH instead of command.com──it must perform all the
  8927.    processing normally done by command.com.
  8928.  
  8929.    Macro Definition:
  8930.  
  8931.    exec  macro  path,command,parms
  8932.          mov    dx,offset path
  8933.          mov    bx,offset parms
  8934.          mov    word ptr parms[02H],offset command
  8935.          mov    word ptr parms[04H],cs
  8936.          mov    word ptr parms[06H],5CH
  8937.          mov    word ptr parms[08H],es
  8938.          mov    word ptr parms[0AH],6CH
  8939.          mov    word ptr parms[0CH],es
  8940.          mov    al,0
  8941.          mov    ah,4BH
  8942.          int    21H
  8943.          endm
  8944.  
  8945.    Example:
  8946.  
  8947.    The following program invokes a second copy of command.com and executes a
  8948.    dir (directory) command by using the /w (wide) switch:
  8949.  
  8950.    pgm_file  db      "command.com",0
  8951.    cmd_line  db       9,"/c dir /w",0DH
  8952.    parm_blk  db       14 dup (?)
  8953.    reg_save  db       10 dup (?)
  8954.    ;
  8955.    begin:
  8956.       set_block  last_inst                    ; See Function 4AH
  8957.       exec       pgm_file,cmd_line,parm_blk,0 ; THIS FUNCTION
  8958.  
  8959.  
  8960.  ────────────────────────────────────────────────────────────────────────────
  8961.  Load Overlay (Function 4BH, Code 03H)
  8962.  ────────────────────────────────────────────────────────────────────────────
  8963.  
  8964.    Call:
  8965.  
  8966.    AH = 4BH
  8967.    AL = 03H
  8968.    DS:DX
  8969.       Pointer to pathname
  8970.    ES:BX
  8971.       Pointer to parameter block
  8972.  
  8973.    Return:
  8974.  
  8975.    Carry set:
  8976.    AX
  8977.       1        = Invalid function
  8978.       2        = File not found
  8979.       3        = Path not found
  8980.       4        = Too many open files
  8981.       5        = Access denied
  8982.       8        = Insufficient memory
  8983.      10        = Bad environment
  8984.    Carry not set:
  8985.      No error
  8986.  
  8987.  
  8988.    Comments:
  8989.  
  8990.    Function 4BH, Code 03H, loads a program segment (overlay). DX must contain
  8991.    the offset (from the segment address in DS) of an ASCIZ string that
  8992.    specifies the drive and pathname of the program file. BX must contain the
  8993.    offset (from the segment address in ES) of a parameter block. AL must
  8994.    contain 3.
  8995.  
  8996.    MS-DOS assumes that since the invoking program is loading into its own
  8997.    address space, it requires no free memory. This call does not create a
  8998.    Program Segment Prefix. The parameter block is four bytes long:
  8999.  
  9000.    Table 1.25
  9001.    Contents of the Parameter Block
  9002.    Offset     Length
  9003.    (Hex)      (Bytes)              Description
  9004.    ──────────────────────────────────────────────────────────────────────────
  9005.    00         2 (word)             Segment address at which program is to be
  9006.                                    loaded
  9007.  
  9008.    02         2 (word)             Relocation factor; usually the same as the
  9009.                                    first word of the parameter block (for a
  9010.                                    description of a .exe file and of
  9011.                                    relocation, see Chapter 6, ".Exe File
  9012.    ──────────────────────────────────────────────────────────────────────────
  9013.  
  9014.    If there is an error, the carry flag (CF) is set and the error code
  9015.    returns in AX:
  9016.  
  9017.    Code               Meaning
  9018.    ──────────────────────────────────────────────────────────────────────────
  9019.    1                  AL not 00H or 03H
  9020.  
  9021.    2                  Program file not found
  9022.  
  9023.    3                  Path invalid or not found
  9024.  
  9025.    4                  Too many open files (no handle available)
  9026.  
  9027.    5                  Directory is full, a directory with the same name
  9028.                       exists, or a file with the same name exists
  9029.  
  9030.    8                  Not enough memory to load the program
  9031.  
  9032.    10                 Environment appears longer than 32 kilobytes
  9033.    ──────────────────────────────────────────────────────────────────────────
  9034.  
  9035.    Macro Definition:
  9036.  
  9037.    exec_ovl  macro  path,parms,seg_addr
  9038.              mov    dx,offset path
  9039.              mov    bx,offset parms
  9040.              mov    parms,seg_addr
  9041.              mov    parms[02H],seg_addr
  9042.              mov    al,3
  9043.              mov    ah,4BH
  9044.              int    21H
  9045.              endm
  9046.  
  9047.    Example:
  9048.  
  9049.    The following program opens a file named textfile.asc, redirects standard
  9050.    input to that file, loads more.com as an overlay, and calls an overlay
  9051.    named bit.com, which reads textfile.asc as standard input. The overlay
  9052.    must establish its own addressability and end with a FAR return.
  9053.  
  9054.    stdin     equ       0
  9055.    ;
  9056.    file      db    "TEXTFILE.ASC",0
  9057.    cmd_file  db    "\bit.com",0
  9058.    parm_blk  dw     4 dup (?)
  9059.    overlay   label  dword
  9060.              dw     0
  9061.    handle    dw     ?
  9062.    new_mem   dw     ?
  9063.    ;
  9064.    begin:    set_block   last_inst        ; see Function 4AH
  9065.              jc          setblock_error   ; routine not shown
  9066.              allocate_memory  2000        ; see Function 48H
  9067.              jc          allocate_error   ; routine not shown
  9068.              mov         new_mem,ax       ; save seg of memory
  9069.              open_handle file,0           ; see Function 3DH
  9070.              jc          open_error       ; routine not shown
  9071.              mov         handle,ax        ; save handle
  9072.              xdup2       handle,stdin     ; see Function 45H
  9073.              jc          dup2_error       ; routine not shown
  9074.              close_handle handle          ; see Function 3EH
  9075.              jc          close_error      ; routine not shown
  9076.              mov         ax,new_mem       ; addr of new memory
  9077.              exec_ovl cmd_file,parm_blk,ax    ; THIS FUNCTION
  9078.              jc          exec_error       ; routine not shown
  9079.              call        overlay          ; call the overlay
  9080.              free_memory new_mem          ; see Function 49H
  9081.              jc          free_error       ; routine not shown
  9082.    ;
  9083.  
  9084.  
  9085.  ────────────────────────────────────────────────────────────────────────────
  9086.  End Process (Function 4CH)
  9087.  ────────────────────────────────────────────────────────────────────────────
  9088.  
  9089.    Call:
  9090.  
  9091.    AH = 4CH
  9092.    AL
  9093.       Return code
  9094.  
  9095.    Return:
  9096.  
  9097.    None
  9098.  
  9099.  
  9100.    Comments:
  9101.  
  9102.    Function 4CH terminates a process and returns to MS-DOS. AL contains a
  9103.    return code that can be retrieved by the parent process with Function
  9104.    4DH (Get Return Code of Child Process) or the if command, using
  9105.    errorlevel.
  9106.  
  9107.    MS-DOS closes all open handles, ends the current process, and returns
  9108.    control to the invoking process.
  9109.  
  9110.    This function request doesn't require CS to contain the segment address of
  9111.    the Program Segment Prefix. You should use it to end a program (rather
  9112.    than Interrupt 20H or a jump to location 0) unless your program must be
  9113.    compatible with MS-DOS versions earlier than 2.0.
  9114.  
  9115.    ──────────────────────────────────────────────────────────────────────────
  9116.    Note
  9117.      If you use file sharing, you must remove all locks issued by this
  9118.      process or DOS will be in an uncertain state.
  9119.    ──────────────────────────────────────────────────────────────────────────
  9120.  
  9121.    Macro Definition:
  9122.  
  9123.    end_process  macro  return_code
  9124.                 mov    al,return_code
  9125.                 mov    ah,4CH
  9126.                 int    21H
  9127.                 endm
  9128.  
  9129.    Example:
  9130.  
  9131.    The following program displays a message and returns to MS-DOS with a
  9132.    return code of 8. It uses only the opening portion of the sample program
  9133.    skeleton shown at the beginning of this chapter.
  9134.  
  9135.    message   db     "Displayed by FUNC_4CH example",0DH,0AH,"$"
  9136.    ;
  9137.    begin:    display      message   ; See Function 09H
  9138.              end_process  8         ; THIS FUNCTION
  9139.    code      ends
  9140.              end          code
  9141.  
  9142.  
  9143.  ────────────────────────────────────────────────────────────────────────────
  9144.  Get Return Code of Child Process (Function 4DH)
  9145.  ────────────────────────────────────────────────────────────────────────────
  9146.  
  9147.    Call:
  9148.  
  9149.    AH = 4DH
  9150.  
  9151.    Return:
  9152.  
  9153.    AX
  9154.       Return code
  9155.  
  9156.  
  9157.    Comments:
  9158.  
  9159.    Function 4DH retrieves the return code specified when a child process
  9160.    terminates via either Function 31H (Keep Process) or Function 4CH (End
  9161.    Process). The code returns in AL. AH returns a code that specifies why the
  9162.    program ended:
  9163.  
  9164.    Code               Meaning
  9165.    ──────────────────────────────────────────────────────────────────────────
  9166.    0                  Normal termination
  9167.    1                  Terminated by CONTROL+C
  9168.    2                  Critical device error
  9169.    3                  Function 31H (Keep Process)
  9170.    ──────────────────────────────────────────────────────────────────────────
  9171.  
  9172.    This call can retrieve the exit code only once.
  9173.  
  9174.    Macro Definition:
  9175.  
  9176.    ret_code  macro
  9177.              mov    ah,4DH
  9178.              int    21H
  9179.              endm
  9180.  
  9181.    Example:
  9182.  
  9183.    No example is included for this function request because the meaning of a
  9184.    return code varies.
  9185.  
  9186.  
  9187.  ────────────────────────────────────────────────────────────────────────────
  9188.  Find First File (Function 4EH)
  9189.  ────────────────────────────────────────────────────────────────────────────
  9190.  
  9191.    Call:
  9192.  
  9193.    AH = 4EH
  9194.    DS:DX
  9195.       Pointer to pathname
  9196.    CX
  9197.       Attributes to match
  9198.  
  9199.    Return:
  9200.  
  9201.    Carry set:
  9202.    AX
  9203.       2        = File not found
  9204.       3        = Path not found
  9205.      18        = No more files
  9206.    Carry not set:
  9207.       No error
  9208.  
  9209.  
  9210.    Comments:
  9211.  
  9212.    Function 4EH searches the current or specified directory for the first
  9213.    entry that matches the specified pathname. DX must contain the offset
  9214.    (from the segment address in DS) of an ASCIZ string that specifies the
  9215.    pathname, which can contain wildcard characters. CX must contain the
  9216.    attribute to be used in searching for the file, as described in Section
  9217.    1.5.5, "File Attributes."
  9218.  
  9219.    If the attribute field is hidden file, system file, or subdirectory entry
  9220.    (02H, 04H, or 10H), or any combination of these values, all normal file
  9221.    entries are also searched. To search all directory entries except the
  9222.    volume label, set the attribute byte to 16H (hidden file, system file, and
  9223.    directory entry). If this function finds a directory entry that matches
  9224.    the name and attribute, it fills the current DTA as follows:
  9225.  
  9226.    Table 1.26
  9227.    DTA Values After Successful Find First File
  9228.    Offset   Length    Description
  9229.    ──────────────────────────────────────────────────────────────────────────
  9230.    00H      21        Reserved for subsequent Function 4FH (Find Next File)
  9231.  
  9232.    15H      1         Attribute found
  9233.  
  9234.    16H      2         Time file was last written
  9235.  
  9236.    18H      2         Date file was last written
  9237.  
  9238.    1AH      2         Low word of file size
  9239.  
  9240.    1CH      2         High word of file size
  9241.  
  9242.    1EH      13        Name and extension of the file, followed by 00H. All
  9243.                       blanks are removed; if there is an extension, it is
  9244.                       preceded by a period. (Volume labels include a period
  9245.    ──────────────────────────────────────────────────────────────────────────
  9246.  
  9247.    If there is an error, the carry flag (CF) is set and the error code
  9248.    returns in AX:
  9249.  
  9250.    Code               Meaning
  9251.    ──────────────────────────────────────────────────────────────────────────
  9252.    2                  Specified file invalid or doesn't exist
  9253.    3                  Specified path invalid or doesn't exist
  9254.    18                 No matching directory entry found
  9255.    ──────────────────────────────────────────────────────────────────────────
  9256.  
  9257.    Macro Definition:
  9258.  
  9259.    find_first_file  macro  path,attrib
  9260.                     mov    dx,offset path
  9261.                     mov    cx,attrib
  9262.                     mov    ah,4EH
  9263.                     int    21H
  9264.                     endm
  9265.  
  9266.    Example:
  9267.  
  9268.    The following program displays a message that specifies whether a file
  9269.    named report.asm exists in the current directory on the disk in drive B.
  9270.  
  9271.    yes        db      "File exists.",0DH,0AH,"$"
  9272.    no         db      "File does not exist.",0DH,0AH,"$"
  9273.    path       db      "b:report.asm",0
  9274.    buffer     db       43 dup (?)
  9275.    ;
  9276.    begin:     set_dta  buffer           ; See Function 1AH
  9277.               find_first_file  path,0   ; THIS FUNCTION
  9278.               jc       error_findfirst  ; Routine not shown
  9279.               cmp      al,12H           ; File found?
  9280.               je       not_there        ; No
  9281.               display  yes              ; See Function 09H
  9282.               jmp      return           ; All done
  9283.    not_there: display  no               ; See Function 09H
  9284.  
  9285.  
  9286.  ────────────────────────────────────────────────────────────────────────────
  9287.  Find Next File (Function 4FH)
  9288.  ────────────────────────────────────────────────────────────────────────────
  9289.  
  9290.    Call:
  9291.  
  9292.    AH = 4FH
  9293.  
  9294.    Return:
  9295.  
  9296.    Carry set:
  9297.    AX
  9298.      18 = No more files
  9299.    Carry not set:
  9300.       No error
  9301.  
  9302.  
  9303.    Comments:
  9304.  
  9305.    Function 4FH searches for the next directory entry that matches the name
  9306.    and attributes specified in a previous Function 4EH (Find First File).
  9307.    The current DTA must contain the information filled in by Function 4EH
  9308.    (Find First File).
  9309.  
  9310.    If the function finds a matching entry, it fills the current DTA just as
  9311.    it did for Find First File (see Function 4EH (Find First File)).
  9312.  
  9313.    If there is an error, the carry flag (CF) is set and the error code
  9314.    returns in AX:
  9315.  
  9316.    Code               Meaning
  9317.    ──────────────────────────────────────────────────────────────────────────
  9318.    2                  Specified path invalid or doesn't exist
  9319.    18                 No matching directory entry found
  9320.    ──────────────────────────────────────────────────────────────────────────
  9321.  
  9322.    Macro Definition:
  9323.  
  9324.    find_next_file  macro
  9325.                    mov    ah,4FH
  9326.                    int    21H
  9327.                    endm
  9328.  
  9329.    Example:
  9330.  
  9331.    The following program displays the number of files contained in the
  9332.    current directory on the disk in drive B.
  9333.  
  9334.    message     db      "No files",0DH,0AH,"$"
  9335.    files       dw       ?
  9336.    path        db      "b:*.*",0
  9337.    buffer      db       43 dup (?)
  9338.    ;
  9339.    begin:      set_dta  buffer          ; See Function 1AH
  9340.                find_first_file  path,0  ; See Function 4EH
  9341.                jc       error_findfirst ; Routine not shown
  9342.                cmp      al,12H          ; Directory empty?
  9343.                je       all_done        ; Yes, go home
  9344.                inc      files           ; No, bump file counter
  9345.    search_dir: find_next_file           ; THIS FUNCTION
  9346.                jc       error_findnext  ; Routine not shown
  9347.                cmp      al,12H          ; Any more entries?
  9348.                je       done            ; No, go home
  9349.                inc      files           ; Yes, bump file counter
  9350.                jmp      search_dir      ; And check again
  9351.    done:       convert  files,10,message ; See end of chapter
  9352.    all_done:   display  message         ; See Function 09H
  9353.  
  9354.  
  9355.  ────────────────────────────────────────────────────────────────────────────
  9356.  Get Verify State (Function 54H)
  9357.  ────────────────────────────────────────────────────────────────────────────
  9358.  
  9359.    Call:
  9360.  
  9361.    AH = 54H
  9362.  
  9363.    Return:
  9364.  
  9365.    AL
  9366.       0 = No verify after write
  9367.       1 = Verify after write
  9368.  
  9369.  
  9370.    Comments:
  9371.  
  9372.    Function 54H checks whether MS-DOS verifies write operations to disk
  9373.    files. The status returns in AL: 0 if verify is off, 1 if verify is on.
  9374.  
  9375.    You can set the verify status with Function 2EH (Set/Reset Verify Flag).
  9376.  
  9377.    Macro Definition:
  9378.  
  9379.    get_verify  macro
  9380.                mov    ah,54H
  9381.                int    21H
  9382.                endm
  9383.  
  9384.    Example:
  9385.  
  9386.    The following program displays the verify status:
  9387.  
  9388.    message   db     "Verify ","$"
  9389.    on        db     "on.",0DH,0AH,"$"
  9390.    off       db     "off.",0DH,0AH,"$"
  9391.    ;
  9392.    begin:    display message      ; See Function 09H
  9393.              get_verify           ; THIS FUNCTION
  9394.              cmp     al,0         ; Is flag off?
  9395.              jg      ver_on       ; No, it's on
  9396.              display off          ; See Function 09H
  9397.              jmp     return       ; Go home
  9398.    ver_on:   display on           ; See Function 09H
  9399.  
  9400.  
  9401.  ────────────────────────────────────────────────────────────────────────────
  9402.  Change Directory Entry (Function 56H)
  9403.  ────────────────────────────────────────────────────────────────────────────
  9404.  
  9405.    Call:
  9406.  
  9407.    AH = 56H
  9408.    DS:DX
  9409.       Pointer to pathname
  9410.    ES:DI
  9411.       Pointer to second pathname
  9412.  
  9413.    Return:
  9414.  
  9415.    Carry set:
  9416.    AX
  9417.       2        = File not found
  9418.       3        = Path not found
  9419.       5        = Access denied
  9420.      17        = Not same device
  9421.    Carry not set:
  9422.       No error
  9423.  
  9424.  
  9425.    Comments:
  9426.  
  9427.    Function 56H renames a file by changing its directory entry. DX must
  9428.    contain the offset (from the segment address in DS) of an ASCIZ string
  9429.    that contains the pathname of the entry to be changed. DI must contain the
  9430.    offset (from the segment address in ES) of an ASCIZ string that contains a
  9431.    second pathname to which the first is to be changed.
  9432.  
  9433.    If a directory entry for the first pathname exists, it is changed to the
  9434.    second pathname.
  9435.  
  9436.    The directory paths need not be the same; in effect, you can move the file
  9437.    to another directory by renaming it. You cannot use this function request
  9438.    to copy a file to another drive, however; if the second pathname specifies
  9439.    a drive, the first pathname must specify or default to the same drive.
  9440.  
  9441.    You cannot use this function request to rename an open file, a hidden
  9442.    file, a system file, or a subdirectory, because it may corrupt your disk.
  9443.    If there is an error, the carry flag (CF) is set and the error code
  9444.    returns in AX.
  9445.  
  9446.    Code               Meaning
  9447.    ──────────────────────────────────────────────────────────────────────────
  9448.    2                  One of files is invalid or not open
  9449.  
  9450.    3                  One of paths is invalid or not open
  9451.  
  9452.    5                  First pathname specifies a directory, second pathname
  9453.                       specifies an existing file; or second directory entry
  9454.                       could not be opened
  9455.  
  9456.    17                 Both files not on the same drive
  9457.    ──────────────────────────────────────────────────────────────────────────
  9458.  
  9459.    Macro Definition:
  9460.  
  9461.    rename_file  macro  old_path,new_path
  9462.                 mov    dx,offset old_path
  9463.                 push   ds
  9464.                 pop    es
  9465.                 mov    di,offset new_path
  9466.                 mov    ah,56H
  9467.                 int    21H
  9468.                 endm
  9469.  
  9470.    Example:
  9471.  
  9472.    The following program prompts for the name of a file and a new name, then
  9473.    renames the file.
  9474.  
  9475.    prompt1   db     "Filename: $"
  9476.    prompt2   db     "New name: $"
  9477.    old_path  db      15,?,15 dup (?)
  9478.    new_path  db      15,?,15 dup (?)
  9479.    crlf      db      0DH,0AH,"$"
  9480.    ;
  9481.    begin:    display prompt1           ; See Function 09H
  9482.              get_string  15,old_path   ; See Function 0AH
  9483.              xor     bx,bx             ; To use BL as index
  9484.              mov     bl,old_path[1]    ; Get string length
  9485.              mov     old_path[bx+2],0  ; Make an ASCIZ string
  9486.              display crlf              ; See Function 09H
  9487.              display prompt2           ; See Function 09H
  9488.              get_string  15,new_path   ; See Function 0AH
  9489.              xor     bx,bx             ; To use BL as index
  9490.              mov     bl,new_path[1]    ; Get string length
  9491.              mov     new_path[bx+2],0  ; Make an ASCIZ string
  9492.              display crlf              ; See Function 09H
  9493.              rename_file old_path[2],new_path[2]; THIS FUNCTION
  9494.              jc      error_rename      ; Routine not shown
  9495.  
  9496.  
  9497.  
  9498.  
  9499.  ────────────────────────────────────────────────────────────────────────────
  9500.  Get/Set Date/Time of File (Function 57H)
  9501.  ────────────────────────────────────────────────────────────────────────────
  9502.  
  9503.    Call:
  9504.  
  9505.    AH = 57H
  9506.    AL = Function code
  9507.       0 = Get date and time
  9508.       1 = Set date and time
  9509.    BX
  9510.       Handle
  9511.    CX (if AL = 1)
  9512.       Time to be set
  9513.    DX (if AL = 1)
  9514.       Date to be set
  9515.  
  9516.    Return:
  9517.  
  9518.    Carry set:
  9519.    AX
  9520.       1 = Invalid function
  9521.       6 = Invalid handle
  9522.    Carry not set:
  9523.    CX (if AL = 0)
  9524.       Time file last written
  9525.    DX (if AL = 0)
  9526.       Date file last written
  9527.  
  9528.  
  9529.    Comments:
  9530.  
  9531.    Function 57H gets or sets the time and date when a file was last written.
  9532.    To get the time and date, AL must contain 0; the time and date return in
  9533.    CX and DX. To set the time and date, AL must contain 1; CX and DX must
  9534.    contain the time and date. BX must contain the file handle. The time and
  9535.    date are in the form described in "Fields of the FCB" in Section 1.9.1.
  9536.  
  9537.    If there is an error, the carry flag (CF) is set and the error code
  9538.    returns in AX:
  9539.  
  9540.    Code               Meaning
  9541.    ──────────────────────────────────────────────────────────────────────────
  9542.    1                  AL not 0 or 1
  9543.    6                  Handle in BX invalid or not open
  9544.    ──────────────────────────────────────────────────────────────────────────
  9545.  
  9546.    Macro Definition:
  9547.  
  9548.    get_set_date_time macro  handle,action,time,date
  9549.                      mov    bx,handle
  9550.                      mov    al,action
  9551.                      mov    cx,word ptr time
  9552.                      mov    dx,word ptr date
  9553.                      mov    ah,57H
  9554.                      int    21H
  9555.                      endm
  9556.  
  9557.    Example:
  9558.  
  9559.    The following program gets the date of a file named report.asm in the
  9560.    current directory on the disk in drive B, increments the day, increments
  9561.    the month and/or year, if necessary, and sets the new date of the file.
  9562.  
  9563.    month     db      31,28,31,30,31,30,31,31,30,31,30,31
  9564.    path      db     "b:report.asm",0
  9565.    handle    dw      ?
  9566.    time      db      2 dup (?)
  9567.    date      db      2 dup (?)
  9568.    ;
  9569.    begin:    open_handle  path,0         ; See Function 3DH
  9570.              mov     handle,ax           ; Save handle
  9571.              get_set_date_time handle,0,time,date ; THIS FUNCTION
  9572.              jc      error_time          ; Routine not shown
  9573.              mov     word ptr time,cx    ; Save time
  9574.              mov     word ptr date,dx    ; Save date
  9575.              convert_date  date[-24]     ; See end of chapter
  9576.              inc     dh                  ; Increment day
  9577.              xor     bx,bx               ; To use BL as index
  9578.              mov     bl,dl               ; Get month
  9579.              cmp     dh,month[bx-1]      ; Past last day?
  9580.              jle     month_ok            ; No, go home
  9581.              mov     dh,1                ; Yes, set day to 1
  9582.              inc     dl                  ; Increment month
  9583.              cmp     dl,12               ; Is it past December?
  9584.              jle     month_ok            ; No, go home
  9585.              mov     dl,1                ; Yes, set month to 1
  9586.              inc     cx                  ; Increment year
  9587.    month_ok: pack_date  date             ; See end of chapter
  9588.              get_set_date_time handle,1,time,date ; THIS FUNCTION
  9589.              jc      error_time          ; Routine not shown
  9590.              close_handle  handle        ; See Function 3EH
  9591.              jc      error_close         ; Routine not shown
  9592.  
  9593.  
  9594.  ────────────────────────────────────────────────────────────────────────────
  9595.  Get/Set Allocation Strategy (Function 58H)
  9596.  ────────────────────────────────────────────────────────────────────────────
  9597.  
  9598.    Call:
  9599.  
  9600.    AH = 58H
  9601.    AL
  9602.       0 = Get strategy
  9603.       1 = Set strategy
  9604.    BX (AL = 1)
  9605.       0 = First fit
  9606.       1 = Best fit
  9607.       2 = Last fit
  9608.  
  9609.    Return:
  9610.  
  9611.    Carry set:
  9612.    AX
  9613.       1 = Invalid function code
  9614.    Carry not set:
  9615.    AX (AL = 0)
  9616.       0 = First fit
  9617.       1 = Best fit
  9618.       2 = Last fit
  9619.  
  9620.  
  9621.    Comments:
  9622.  
  9623.    Function 58H gets or sets the strategy that MS-DOS uses to allocate memory
  9624.    when a process requests it. If AL contains 0, the strategy is returned in
  9625.    AX. If AL contains 1, BX must contain the strategy. The three possible
  9626.    strategies are shown in the following table.
  9627.  
  9628.    Table 1.27
  9629.    Allocation Strategy
  9630.    Value      Name                 Description
  9631.    ──────────────────────────────────────────────────────────────────────────
  9632.    0          First fit            MS-DOS starts searching at the lowest
  9633.                                    available block and allocates the first
  9634.                                    block it finds (the allocated memory is
  9635.                                    the lowest available block). This is the
  9636.                                    default strategy.
  9637.  
  9638.    1          Best fit             MS-DOS searches each available block and
  9639.                                    allocates the smallest available block
  9640.                                    that satisfies the request.
  9641.  
  9642.    2          Last fit             MS-DOS starts searching at the highest
  9643.                                    available block and allocates the first
  9644.                                    block it finds (the allocated memory is
  9645.    ──────────────────────────────────────────────────────────────────────────
  9646.  
  9647.    You can use this function request to control how MS-DOS uses its memory
  9648.    resources.
  9649.  
  9650.    If there is an error, the carry flag (CF) is set and the error code
  9651.    returns in AX:
  9652.  
  9653.    Code               Meaning
  9654.    ──────────────────────────────────────────────────────────────────────────
  9655.    1                  AL doesn't contain 0 or 1, or BX doesn't contain 0, 1,
  9656.                       or 2.
  9657.    ──────────────────────────────────────────────────────────────────────────
  9658.  
  9659.    Macro Definition:
  9660.  
  9661.    alloc_strat macro  code,strategy
  9662.                mov    bx,strategy
  9663.                mov    al,code
  9664.                mov    ah,58H
  9665.                int    21H
  9666.                endm
  9667.  
  9668.    Example:
  9669.  
  9670.    The following program displays the memory-allocation strategy in effect,
  9671.    then forces subsequent memory allocations to the top of memory by setting
  9672.    the strategy to last fit (code 2).
  9673.  
  9674.    get       equ       0
  9675.    set       equ       1
  9676.    stdout    equ       1
  9677.    last_fit  equ       2
  9678.    ;
  9679.    first     db       "First fit     ",0DH,0AH
  9680.    best      db       "Best fit      ",0DH,0AH
  9681.    last      db       "Last fit      ",0DH,0AH
  9682.    ;
  9683.    begin:    alloc_strat get               ; THIS FUNCTION
  9684.              jc         alloc_error        ; routine not shown
  9685.              mov        cl,4               ; multiply code by 16
  9686.              shl        ax,cl              ; to calculate offset
  9687.              mov        dx,offset first    ; point to first msg
  9688.              add        dx,ax              ; add to base address
  9689.              mov        bx,stdout          ; handle for write
  9690.              mov        cs,16              ; write 16 bytes
  9691.              mov        ah,40h             ; write handle
  9692.              int        21H                ; system call
  9693.    ;          jc         write_error        ; routine not shown
  9694.              alloc_strat set,last_fit      ; THIS FUNCTION
  9695.    ;          jc         alloc_error        ; routine not shown
  9696.  
  9697.  
  9698.  ────────────────────────────────────────────────────────────────────────────
  9699.  Get Extended Error (Function 59H)
  9700.  ────────────────────────────────────────────────────────────────────────────
  9701.  
  9702.    Call:
  9703.  
  9704.    AH = 59H
  9705.    BX = 00H
  9706.  
  9707.    Return:
  9708.  
  9709.    AX
  9710.       Extended-error code
  9711.    BH
  9712.       Error class (see text)
  9713.    BL
  9714.       Suggested action (see text)
  9715.    CH
  9716.       Locus (see text)
  9717.  
  9718.    CL, DX, SI, DI, DS, ES destroyed
  9719.  
  9720.  
  9721.    Comments:
  9722.  
  9723.    Function 59H retrieves an extended-error code for the preceding system
  9724.    call. Each release of MS-DOS extends the error codes to cover new
  9725.    capabilities. These new codes are mapped to a simpler set of error codes
  9726.    based on MS-DOS Version 2.0, so that existing programs can continue to
  9727.    operate correctly. Notice that this call destroys all registers except
  9728.    CS:IP and SS:SP.
  9729.  
  9730.    A user-written Interrupt 24H (Critical-Error Handler Address) can use
  9731.    Function 59H to get detailed information about the error that caused the
  9732.    interrupt to be issued.
  9733.  
  9734.    The input BX is a version indicator that specifies for what level of error
  9735.    handling the application was written. The current level is 00H.
  9736.  
  9737.    The extended-error code consists of four separate codes in AX, BH, BL, and
  9738.    CH that give as much detail as possible about the error and suggest how
  9739.    the issuing program should respond.
  9740.  
  9741.    BH──Error Class
  9742.  
  9743.    BH returns a code that describes the class of error that occurred:
  9744.  
  9745. ╓┌─┌──────────────────┌──────────────────────────────────────────────────────╖
  9746.    Class              Description
  9747.    ──────────────────────────────────────────────────────────────────────────
  9748.    1                  Out of a resource, such as storage or channels
  9749.  
  9750.    2                  Not an error, but a temporary situation (such as a
  9751.                       locked region in a file) that is expected to end
  9752.  
  9753.    3                  Authorization problem
  9754.  
  9755.    4                  Internal error in system software
  9756.  
  9757.    5                  Hardware failure
  9758.  
  9759.    6                  System software failure not the fault of the active
  9760.                       process (could be caused by missing or incorrect
  9761.                       configuration files, for example)
  9762.  
  9763.    7                  Application program error
  9764.  
  9765.    8                  File or item not found
  9766.  
  9767.    Class              Description
  9768.    ──────────────────────────────────────────────────────────────────────────
  9769. 
  9770.    9                  File or item of invalid format or type, or that is
  9771.                       otherwise invalid or unsuitable
  9772.  
  9773.    10                 Interlocked file or item
  9774.  
  9775.    11                 Wrong disk in drive, bad spot on disk, or other problem
  9776.                       with storage medium
  9777.  
  9778.    12                 Other error
  9779.    ──────────────────────────────────────────────────────────────────────────
  9780.  
  9781.  
  9782.    BL──Suggested Action
  9783.  
  9784.    BL returns a code that suggests how the issuing program can respond to the
  9785.    error:
  9786.  
  9787.    Action             Description
  9788.    ──────────────────────────────────────────────────────────────────────────
  9789.    1                  Retry, then prompt user
  9790.  
  9791.    2                  Retry after a Pause
  9792.  
  9793.    3                  If user entered data such as drive letter or filename,
  9794.                       prompt for it again
  9795.  
  9796.    4                  Terminate with cleanup
  9797.  
  9798.    5                  Terminate immediately; system so unhealthy that program
  9799.                       should exit as soon as possible without taking time to
  9800.                       close files and update indexes
  9801.  
  9802.    6                  Error is informational
  9803.  
  9804.    7                  Prompt user to perform some action, such as changing
  9805.    ──────────────────────────────────────────────────────────────────────────
  9806.  
  9807.    CH──Locus
  9808.  
  9809.    CH returns a code that provides additional information to help locate the
  9810.    area involved in the failure. This code is particularly useful for
  9811.    hardware failures (BH=5).
  9812.  
  9813.    Locus          Description
  9814.    ──────────────────────────────────────────────────────────────────────────
  9815.    1              Unknown
  9816.    2              Related to random-access block devices, such as a disk
  9817.                   drive
  9818.    3              Related to Network
  9819.    4              Related to serial-access character devices, such as a
  9820.                   printer
  9821.    5              Related to random-access memory
  9822.    ──────────────────────────────────────────────────────────────────────────
  9823.  
  9824.    Your programs should handle errors by noting the error return from the
  9825.    original system call and then issuing this system call to get the
  9826.    extended-error code. If the program does not recognize the extended-error
  9827.    code, it should respond to the original error code.
  9828.  
  9829.    This system call is available during Interrupt 24H and may be used to
  9830.    return network-related errors.
  9831.  
  9832.    Macro Definition:
  9833.  
  9834.    get_error  macro
  9835.               mov    ah, 59H
  9836.               int    21H
  9837.               endm
  9838.  
  9839.    Example:
  9840.  
  9841.    Since this function request provides such detailed information, a general
  9842.    example is not practical. User programs can interpret the various codes to
  9843.    determine what sort of messages or prompts should be displayed, what
  9844.    action to take, and whether or not to terminate the program if recovery
  9845.    from the errors isn't possible.
  9846.  
  9847.  
  9848.  ────────────────────────────────────────────────────────────────────────────
  9849.  Create Temporary File (Function 5AH)
  9850.  ────────────────────────────────────────────────────────────────────────────
  9851.  
  9852.    Call:
  9853.  
  9854.    AH = 5AH
  9855.    CX
  9856.       Attribute
  9857.    DS:DX
  9858.       Pointer to pathname, followed by a
  9859.       byte of 0, and then by 13 bytes of memory
  9860.  
  9861.    Return:
  9862.  
  9863.    Carry set:
  9864.    AX
  9865.       2 = File not found
  9866.       3 = Path not found
  9867.       4 = Too many open files
  9868.       5 = Access denied
  9869.    Carry not set:
  9870.    AX
  9871.       Handle
  9872.  
  9873.  
  9874.    Comments:
  9875.  
  9876.    Function 5AH creates a file with a unique name. DX must contain the offset
  9877.    (from the segment address in DS) of an ASCIZ string that specifies a
  9878.    pathname and 13 bytes of memory (to hold the filename). CX must contain
  9879.    the attribute to be assigned to the file, as described in Section 1.5.5,
  9880.    "File Attributes."
  9881.  
  9882.    MS-DOS creates a unique filename and appends it to the pathname pointed to
  9883.    by DS:DX, creates the file and opens it in compatibility mode, then
  9884.    returns the file handle in AX. A program that needs a temporary file
  9885.    should use this function request to avoid name conflicts.
  9886.  
  9887.    When the creating process exits, MS-DOS does not automatically delete a
  9888.    file created with Function 5AH. When you no longer need the file, you
  9889.    should delete it. If there is an error, the carry flag (CF) is set and the
  9890.    error code returns in AX:
  9891.  
  9892.    Code               Meaning
  9893.    ──────────────────────────────────────────────────────────────────────────
  9894.    2                  File is invalid or doesn't exist
  9895.  
  9896.    3                  Directory pointed to by DS:DX is invalid or doesn't
  9897.                       exist
  9898.  
  9899.    4                  Too many open files (no handle available)
  9900.  
  9901.    5                  Access denied
  9902.    ──────────────────────────────────────────────────────────────────────────
  9903.  
  9904.    Macro Definition:
  9905.  
  9906.    create_temp macro  pathname,attrib
  9907.                mov    cx,attrib
  9908.                mov    dx,offset pathname
  9909.                mov    ah,5AH
  9910.                int    21H
  9911.                endm
  9912.  
  9913.    Example:
  9914.  
  9915.    The following program creates a temporary file in the directory named
  9916.    \wp\docs, copies a file named textfile.asc that is in the current
  9917.    directory into the temporary file, and then closes both files.
  9918.  
  9919.    stdout   equ       1
  9920.    ;
  9921.    file     db       "TEXTFILE.ASC",0
  9922.    path     db       "\WP\DOCS",0
  9923.    temp     db        13 dup (0)
  9924.    open_msg db       " opened.",0DH,0AH
  9925.    crl_msg  db       " created.",0DH,0AH
  9926.    rd_msg   db       " read into buffer.",0DH,0AH
  9927.    wr_msg   db       "Buffer written to "
  9928.    cl_msg   db       "Files closed.",0DH,0AH
  9929.    crlf     db       0DH,0AH
  9930.    handle1  dw        ?
  9931.    handle2  dw        ?
  9932.    buffer   db        512 dup (?)
  9933.    ;
  9934.  
  9935.  
  9936.  
  9937.    begin:   open_handle file,0            ; see Function 3DH
  9938.             jc         open_error         ; routine not shown
  9939.             mov        handle1,ax         ; save handle
  9940.             write_handle stdout,file,12   ; see Function 40H
  9941.             jc         write_error        ; routine not shown
  9942.             write_handle stdout,open_msg,10 ; see Function 40H
  9943.             jc         write_error        ; routine not shown
  9944.             create_temp path,0            ; THIS FUNCTION
  9945.             jc         create_error       ; routine not shown
  9946.             mov        handle2,ax         ; save handle
  9947.             write_handle stdout,path,8    ; see Function 40H
  9948.             jc         write_error        ; routine not shown
  9949.             display_char ""              ; see Function 02H
  9950.             write_handle stdout,temp,12   ; see Function 40H
  9951.             jc         write_error        ; routine not shown
  9952.             write_handle stdout,crl_msg,11 ; See Function 40H
  9953.             jc         write_error        ; routine not shown
  9954.             read_handle handle1,buffer,512  ; see Function 3FH
  9955.             jc        read_error          ; routine not shown
  9956.             write_handle stdout,file,12   ; see Function 40H
  9957.             jc        write_error         ; routine not shown
  9958.             write_handle stdout,rd_msg,20 ; see Function 40H
  9959.             jc        write_error         ; routine not shown
  9960.             write_handle handle2,buffer,512 ; see Function 40H
  9961.             jc        write_error         ; routine not shown
  9962.             write_handle stdout,wr_msg,18 ; see Function 40H
  9963.             jc         write_error        ; routine not shown
  9964.             write_handle stdout,temp,12   ; see Function 40H
  9965.             jc         write_error        ; routine not shown
  9966.             write_handle stdout,crlf,2    ; see Function 40H
  9967.             jc        write_error         ; routine not shown
  9968.             close_handle handle1          ; see Function 3EH
  9969.             jc        close_error         ; routine not shown
  9970.             close_handle handle2          ; see Function 3EH
  9971.             jc        close_error         ; routine not shown
  9972.             write_handle stdout,cl_msg,15 ; see Function 40H
  9973.             jc        write_error         ; routine not shown
  9974.  
  9975.  
  9976.  ────────────────────────────────────────────────────────────────────────────
  9977.  Create New File (Function 5BH)
  9978.  ────────────────────────────────────────────────────────────────────────────
  9979.  
  9980.    Call:
  9981.  
  9982.    AH = 5BH
  9983.    CX
  9984.       Attribute
  9985.    DS:DX
  9986.       Pointer to pathname
  9987.  
  9988.    Return:
  9989.  
  9990.    Carry set:
  9991.    AX
  9992.        2        = File not found
  9993.        3        = Path not found
  9994.        4        = Too many open files
  9995.        5        = Access denied
  9996.       80        = File already exists
  9997.    Carry not set:
  9998.    AX
  9999.       Handle
  10000.  
  10001.  
  10002.    Comments:
  10003.  
  10004.    Function 5BH creates a new file. DX must contain the offset (from the
  10005.    segment address in DS) of an ASCIZ string that specifies a pathname. CX
  10006.    contains the attribute to be assigned to the file, as described in Section
  10007.    1.5.5, "File Attributes."
  10008.  
  10009.    If there is no existing file with the same filename, MS-DOS creates the
  10010.    file, opens it in compatibility mode, and returns the file handle in AX.
  10011.  
  10012.    This function request fails if the specified file exists, unlike Function
  10013.    3CH (Create Handle), which, under the same circumstances, truncates the
  10014.    file to a length of 0. In a multitasking system, the existence of a file
  10015.    is used as a semaphore; you can use this system call as a test-and-set
  10016.    semaphore. If there is an error, the carry flag (CF) is set and the error
  10017.    code returns in AX:
  10018.  
  10019.    Code               Meaning
  10020.    ──────────────────────────────────────────────────────────────────────────
  10021.    2                  File is invalid or doesn't exist
  10022.  
  10023.    3                  Directory pointed to by DS:DX is invalid or doesn't
  10024.                       exist
  10025.  
  10026.    4                  No free handles are available in the current process,
  10027.                       or internal system tables are full
  10028.  
  10029.    5                  Access denied
  10030.  
  10031.    80                 File with the same specification pointed to by DS:DX
  10032.    ──────────────────────────────────────────────────────────────────────────
  10033.  
  10034.    Macro Definition:
  10035.  
  10036.    create_new macro  pathname,attrib
  10037.               mov    cx, attrib
  10038.               mov    dx, offset pathname
  10039.               mov    ah, 5BH
  10040.               int    21H
  10041.               endm
  10042.  
  10043.    Example:
  10044.  
  10045.    The following program attempts to create a new file named report.asm in
  10046.    the current directory. If the file already exists, the program displays an
  10047.    error message and returns to MS-DOS. If the file doesn't exist and there
  10048.    are no other errors, the program saves the handle and continues
  10049.    processing.
  10050.  
  10051.    err_msg  db       "FILE ALREADY EXISTS",0DH,0AH,"$"
  10052.    path     db       "report.asm",0
  10053.    handle   dw        ?
  10054.    ;
  10055.    begin:    create_new path,0             ; THIS FUNCTION
  10056.              jnc        continue           ; further processing
  10057.              cmp        ax,80              ; file already exist?
  10058.              jne        error              ; routine not shown
  10059.              display    err_msg            ; see Function 09H
  10060.              jmp        return             ; return to MS-DOS
  10061.    continue: mov        handle,ax          ; save handle
  10062.    ;
  10063.    ;          (further processing here)
  10064.  
  10065.  
  10066.  ────────────────────────────────────────────────────────────────────────────
  10067.  Lock (Function 5CH, Code 00H)
  10068.  ────────────────────────────────────────────────────────────────────────────
  10069.  
  10070.    Call:
  10071.  
  10072.    AH = 5CH
  10073.    AL = 00H
  10074.    BX
  10075.       Handle
  10076.    CX:DX
  10077.       Offset of region to be locked
  10078.    SI:DI
  10079.       Length of region to be locked
  10080.  
  10081.    Return:
  10082.  
  10083.    Carry set:
  10084.    AX
  10085.       1        = Invalid function code
  10086.       6        = Invalid handle
  10087.      33        = Lock violation
  10088.      36        = Sharing buffer exceeded
  10089.    Carry not set:
  10090.       No error
  10091.  
  10092.  
  10093.    Comments:
  10094.  
  10095.    Function 5CH, Code 00H, denies all access (read or write) by any other
  10096.    process to the specified region of the file. BX must contain the handle of
  10097.    the file that contains the region to be locked. CX:DX (a four-byte
  10098.    integer) must contain the offset in the file of the beginning of the
  10099.    region. SI:DI (a four-byte integer) must contain the length of the region.
  10100.  
  10101.    If another process attempts to use (read or write) a locked region, MS-DOS
  10102.    retries three times; if the retries fail, MS-DOS issues Interrupt 24H for
  10103.    the requesting process. You can change the number of retries with Function
  10104.    440BH (IOCtl Retry).
  10105.  
  10106.    The locked region can be anywhere in the file. For instance, locking
  10107.    beyond the end of the file is not an error. A region should be locked for
  10108.    only a brief period, so if it is locked for more than ten seconds you
  10109.    should consider it to be an error. Function 45H (Duplicate File Handle)
  10110.    and Function 46H (Force Duplicate File Handle) duplicate access to any
  10111.    locked region. Passing an open file to a child process with Function
  10112.    4B00H (Load and Execute Program) does not duplicate access to locked
  10113.    regions.
  10114.  
  10115.    ──────────────────────────────────────────────────────────────────────────
  10116.    Warning
  10117.      If a program closes a file that contains a locked region or terminates
  10118.      with an open file that contains a locked region, the result is
  10119.      undefined.
  10120.    ──────────────────────────────────────────────────────────────────────────
  10121.  
  10122.    Programs that might be terminated by Interrupt 23H (CONTROL+C Handler
  10123.    Address) or Interrupt 24H (Critical-Error-Handler Address) should trap
  10124.    these interrupts and unlock any locked regions before exiting.
  10125.  
  10126.    Programs should not rely on being denied access to a locked region. A
  10127.    program can determine the status of a region (locked or unlocked) by
  10128.    attempting to lock the region and examining the error code.
  10129.  
  10130.    If there is an error, the carry flag (CF) is set and the error code is
  10131.    returned in AX:
  10132.  
  10133.    Code               Meaning
  10134.    ──────────────────────────────────────────────────────────────────────────
  10135.    1                  File sharing must be loaded to use this function
  10136.                       request.
  10137.  
  10138.    6                  The handle in BX is not a valid, open handle.
  10139.  
  10140.    33                 All or part of the specified region is already locked.
  10141.  
  10142.    36                 There is no more room for lock entries in the buffer.
  10143.                       Refer to the share command in the MS-DOS User's
  10144.                       Reference for information on allocating more lock
  10145.    ──────────────────────────────────────────────────────────────────────────
  10146.  
  10147.    Macro Definition:
  10148.  
  10149.    lock  macro  handle,start,bytes
  10150.          mov    bx, handle
  10151.          mov    cx, word ptr start
  10152.          mov    dx, word ptr start+2
  10153.          mov    si, word ptr bytes
  10154.          mov    di, word ptr bytes+2
  10155.          mov    al, 0
  10156.          mov    ah, 5CH
  10157.          int    21H
  10158.          endm
  10159.  
  10160.    Example:
  10161.  
  10162.    The following program opens a file named finalrpt in "Deny None" mode and
  10163.    locks two portions of it: the first 128 bytes and bytes 1024 through 5119.
  10164.    After some (unspecified) processing, it unlocks the same portions and
  10165.    closes the file.
  10166.  
  10167.    stdout    equ        1
  10168.    ;
  10169.    start1    dd         0
  10170.    lgth1     dd         128
  10171.    start2    dd         1023
  10172.    lgth2     dd         4096
  10173.    file      db        "FINALRPT",0
  10174.    op_msg    db        " opened.",0DH,0AH
  10175.    11_msg    db        "First 128 bytes locked.",0DH,0AH
  10176.    12_msg    db        "Bytes 1024-5119 locked.",0DH,0AH
  10177.    u1_msg    db        "First 128 bytes unlocked.",0DH,0AH
  10178.    u2_msg    db        "Bytes 1024-5119 unlocked.",0DH,0AH
  10179.    cl_msg    db        " closed.:,0DH,0AH
  10180.    handle    dw         ?
  10181.    ;
  10182.    begin:    open_handle file,01000010b     ; see Function 3DH
  10183.              jc         open_error          ; routine not shown
  10184.              write_handle stdout,file,8     ; see Function 40H
  10185.              jc         write_error         ; routine not shown
  10186.              write_handle stdout,op_msg,10  ; see Function 40H
  10187.              jc         write_error         ; routine not shown
  10188.              mov        handle,ax           ; save handle
  10189.              lock       handle,start1,lgth1 ; THIS FUNCTION
  10190.              jc         lock_error          ; routine not shown
  10191.              write_handle stdout,11_msg,25  ; see Function 40H
  10192.              jc         write_error         ; routine not shown
  10193.              lock       handle,start2,lgth2 ; THIS FUNCTION
  10194.              jc         lock_error          ; routine not shown
  10195.              write_handle stdout,12_msg,25  ; see Function 40H
  10196.              jc         write_error         ; routine not shown
  10197.    ;
  10198.    ;  ( Further processing here )
  10199.    ;
  10200.              unlock     handle,start1,lgth1 ; See Function 5C01H
  10201.              jc         unlock_error        ; routine not shown
  10202.              write_handle stdout,ul_msg,27  ; see Function 40H
  10203.              jc         write_error         ; routine not shown
  10204.              unlock     handle,start2,lgth2 ; See Function 5C01H
  10205.              jc         unlock_error        ; routine not shown
  10206.              write_handle stdout,u2_msg,27  ; See Function 40H
  10207.              jc         write_error         ; routine not shown
  10208.              close_handle handle            ; See Function 3EH
  10209.              jc         close_error         ; routine not shown
  10210.              write_handle stdout,file,8     ; see Function 40H
  10211.              jc         write_error         ; routine not shown
  10212.              write_handle stdout,cl_msg,10  ; see Function 40H
  10213.              jc         write_error         ; routine not shown
  10214.  
  10215.  
  10216.  ────────────────────────────────────────────────────────────────────────────
  10217.  Unlock (Function 5CH, Code 01H)
  10218.  ────────────────────────────────────────────────────────────────────────────
  10219.  
  10220.    Call:
  10221.  
  10222.    AH = 5CH
  10223.    AL = 01H
  10224.    BX
  10225.       Handle
  10226.    CX:DX
  10227.       Offset of area to be unlocked
  10228.    SI:DI
  10229.       Length of area to be unlocked
  10230.  
  10231.    Return:
  10232.  
  10233.    Carry set:
  10234.    AX
  10235.       1        = Invalid function code
  10236.       6        = Invalid handle
  10237.      33        = Lock violation
  10238.      36        = Sharing buffer exceeded
  10239.    Carry not set:
  10240.       No error
  10241.  
  10242.  
  10243.    Comments:
  10244.  
  10245.    Function 5CH, Code 01H, unlocks a region previously locked by the same
  10246.    process. BX must contain the handle of the file that contains the region
  10247.    to be unlocked. CX:DX (a four-byte integer) must contain the offset in the
  10248.    file of the beginning of the region. SI:DI (a four-byte integer) must
  10249.    contain the length of the region. The offset and length must be exactly
  10250.    the same as the offset and length specified in the previous Function
  10251.    5C00H (Lock).
  10252.  
  10253.    The description of Function 5C00H (Lock) describes how to use locked
  10254.    regions. If there is an error, the carry flag (CF) is set and the error
  10255.    code returns in AX:
  10256.  
  10257.    Code               Meaning
  10258.    ──────────────────────────────────────────────────────────────────────────
  10259.    1                  File sharing must be loaded to use this function
  10260.                       request.
  10261.  
  10262.    6                  The handle in BX is not a valid, open handle.
  10263.  
  10264.    33                 The region specified is not identical to one that was
  10265.                       previously locked by the same process.
  10266.  
  10267.    36                 There is no more room for lock entries in the buffer.
  10268.                       Refer to the share command in the MS-DOS User's
  10269.                       Reference for information on allocating more lock
  10270.    ──────────────────────────────────────────────────────────────────────────
  10271.  
  10272.    You should issue Function 59H (Get Extended Error) to list the possible
  10273.    errors returned by this function.
  10274.  
  10275.    Macro Definition:
  10276.  
  10277.    unlock  macro  handle,start,bytes
  10278.            mov    bx, handle
  10279.            mov    cx, word ptr start
  10280.            mov    dx, word ptr start+2
  10281.            mov    si, word ptr bytes
  10282.            mov    di, word ptr bytes+2
  10283.            mov    al, 1
  10284.            mov    ah, 5CH
  10285.            int    21H
  10286.            endm
  10287.  
  10288.    Example:
  10289.  
  10290.    The following program opens a file named finalrpt in "Deny None" mode and
  10291.    locks two portions of it: the first 128 bytes and bytes 1024 through 5119.
  10292.    After some (unspecified) processing, it unlocks the same portions and
  10293.    closes the file.
  10294.  
  10295.    stdout    equ        1
  10296.    ;
  10297.    start1    dd         0
  10298.    lgth1     dd         128
  10299.    start2    dd         1023
  10300.    lgth2     dd         4096
  10301.    file      db        "FINALRPT",0
  10302.  
  10303.  
  10304.  
  10305.    op_msg    db        " opened.",0DH,0AH
  10306.    11_msg    db        "First 128 bytes locked.",0DH,0AH
  10307.    12_msg    db        "Bytes 1024-5119 locked.",0DH,0AH
  10308.    u1_msg    db        "First 128 bytes unlocked.",0DH,0AH
  10309.    u2_msg    db        "Bytes 1024-5119 unlocked.",0DH,0AH
  10310.    cl_msg    db        " closed.",0DH,0AH
  10311.    handle    dw         ?
  10312.    ;
  10313.    begin:    open_handle file,01000010b     ; see Function 3DH
  10314.              jc         open_error          ; routine not shown
  10315.              write_handle stdout,file,8     ; see Function 40H
  10316.              jc         write_error         ; routine not shown
  10317.              write_handle stdout,op_msg,10  ; see Function 40H
  10318.              jc         write_error         ; routine not shown
  10319.              mov        handle,ax           ; save handle
  10320.              lock       handle,start1,lgth1 ; See Function 5C00H
  10321.              jc         lock_error          ; routine not shown
  10322.              write_handle stdout,11_msg,25  ; see Function 40H
  10323.              jc         write_error         ; routine not shown
  10324.              lock       handle,start2,lgth2 ; See Function 5C00H
  10325.              jc         lock_error          ; routine not shown
  10326.              write_handle stdout,12_msg,25  ; see Function 40H
  10327.              jc         write_error         ; routine not shown
  10328.    ;
  10329.    ;  ( Further processing here )
  10330.    ;
  10331.              unlock     handle,start1,lgth1 ; THIS FUNCTION
  10332.              jc         unlock_error        ; routine not shown
  10333.              write_handle stdout,u1_msg,27  ; see Function 40H
  10334.              jc         write_error         ; routine not shown
  10335.              unlock     handle,start2,lgth2 ; THIS FUNCTION
  10336.              jc         unlock_error        ; routine not shown
  10337.              write_handle stdout,u2_msg,27  ; see Function 40H
  10338.              jc         write_error         ; routine not shown
  10339.              close_handle handle            ; See Function 3EH
  10340.              jc         close_error         ; routine not shown
  10341.              write_handle stdout,file,8     ; see Function 40H
  10342.              jc         write_error         ; routine not shown
  10343.              write_handle stdout,cl_msg,10  ; see Function 40H
  10344.              jc         write_error         ; routine not shown
  10345.  
  10346.  
  10347.  ────────────────────────────────────────────────────────────────────────────
  10348.  Get Machine Name (Function 5EH, Code 00H)
  10349.  ────────────────────────────────────────────────────────────────────────────
  10350.  
  10351.    Call:
  10352.  
  10353.    AH = 5EH
  10354.    AL = 0
  10355.    DS:DX
  10356.       Pointer to 16-byte buffer
  10357.  
  10358.    Return:
  10359.  
  10360.    Carry set:
  10361.    AX
  10362.       1 = Invalid function code
  10363.    Carry not set:
  10364.    CX
  10365.       Identification number of local
  10366.       computer
  10367.    CH
  10368.       Validity of machine name:
  10369.       00H = invalid
  10370.       nonzero = valid
  10371.    CL
  10372.       NETBIOS number assigned to machine name
  10373.    DS:DX
  10374.       Segment:offset of ASCIZ machine name
  10375.  
  10376.  
  10377.    Comments:
  10378.  
  10379.    Function 5EH, Code 00H, retrieves the net name of the local computer. DX
  10380.    must contain the offset (to the segment address in DS) of a 16-byte
  10381.    buffer. Microsoft Networks must be running.
  10382.  
  10383.    MS-DOS returns the local computer name (a 16-byte ASCIZ string, padded
  10384.    with blanks) in the buffer pointed to by DS:DX. CX returns the
  10385.    identification number of the local computer. If the network was never
  10386.    installed, the CH register returns with zero and the value in the CL
  10387.    register is invalid. If there is an error, the carry flag (CF) is set and
  10388.    the error code returns in AX:
  10389.  
  10390.    Code               Meaning
  10391.    ──────────────────────────────────────────────────────────────────────────
  10392.    1                  Microsoft Networks must be running to use this function
  10393.                       request.
  10394.    ──────────────────────────────────────────────────────────────────────────
  10395.  
  10396.    Macro Definition:
  10397.  
  10398.    get_machine_name  macro  buffer
  10399.                      mov    dx,offset buffer
  10400.                      mov    al,0
  10401.                      mov    ah,5EH
  10402.                      int    21H
  10403.                      endm
  10404.  
  10405.    Example:
  10406.  
  10407.    The following program displays the name of a Microsoft Networks
  10408.    workstation.
  10409.  
  10410.    stdout equ 1
  10411.    ;
  10412.    msg        db   "Netname: "
  10413.    mac_name   db   16 dup (?),0DH,0AH
  10414.    ;
  10415.    begin:    get_machine_name  mac_name        ; THIS FUNCTION
  10416.              jc                name_error      ; routine not shown
  10417.              write_handle      stdout,msg,27   ; see Function 40H
  10418.              jc                write_error     ; routine not shown
  10419.  
  10420.  
  10421.  ────────────────────────────────────────────────────────────────────────────
  10422.  Get/Set Printer Setup (Function 5EH, Codes 02H and 03H)
  10423.  ────────────────────────────────────────────────────────────────────────────
  10424.  
  10425.    Call:
  10426.  
  10427.    AH = 5EH
  10428.    AL
  10429.        02H = Set printer setup string
  10430.        03H = Get printer setup string
  10431.    BX
  10432.        Assign-list index
  10433.    If AL = 02H
  10434.        CX
  10435.            Length of setup string
  10436.  
  10437.        DS:SI
  10438.        Pointer to setup string
  10439.    If AL = 03H
  10440.        ES:DI = Segment: offset of 64-byte buffer
  10441.                      to receive string
  10442.  
  10443.    Return:
  10444.  
  10445.    Carry set:
  10446.    AX
  10447.        1 = Invalid function code
  10448.    Carry not set:
  10449.    CX = Length of printer setup string in bytes
  10450.              (if AL=03H)
  10451.    ES:DI = Segment:offset of ASCII printer setup
  10452.                  string (if AL=03H)
  10453.  
  10454.  
  10455.    Comments:
  10456.  
  10457.    Function 5EH, Code 02H, defines a string of control characters that MS-DOS
  10458.    adds to the beginning of each file sent to the network printer. BX must
  10459.    contain the index into the assign list that identifies the printer (entry
  10460.    0 is the first entry). CX must contain the length of the string. SI must
  10461.    contain the offset (to the segment address in DS) of the string itself.
  10462.    Microsoft Networks must be running.
  10463.  
  10464.    MS-DOS adds the setup string to the beginning of each file sent to the
  10465.    printer, which is specified by the assign-list index in BX. This function
  10466.    request lets each program that shares a printer have its own printer
  10467.    configuration. You can use Function 5F02H (Get Assign-List Entry) to
  10468.    determine which entry in the assign list refers to the printer. If there
  10469.    is an error, the carry flag (CF) is set and the error code returns in AX:
  10470.  
  10471.    Code               Meaning
  10472.    ──────────────────────────────────────────────────────────────────────────
  10473.    1                  Microsoft Networks must be running to use this function
  10474.                       request.
  10475.    ──────────────────────────────────────────────────────────────────────────
  10476.  
  10477.    Macro Definition:
  10478.  
  10479.    printer_setup  macro  index,lgth,string
  10480.                   mov    bx, index
  10481.                   mov    cx, lgth
  10482.                   mov    dx, offset string
  10483.                   mov    al, 2
  10484.                   mov    ah, 5EH
  10485.                   int    21H
  10486.                   endm
  10487.  
  10488.    Example:
  10489.  
  10490.    The following program defines a printer-setup string that consists of the
  10491.    control character to print expanded type on Epson-compatible printers. The
  10492.    printer cancels this mode at the first carriage return, so the effect is
  10493.    to print the first line of each file sent to the network printer as a
  10494.    title in expanded characters. The setup string is one character. This
  10495.    example assumes that the printer is the entry number 3 (the fourth entry)
  10496.    in the assign list. Use Function 5F02H (Get Assign-List Entry) to
  10497.    determine this value.
  10498.  
  10499.    setup     db   0EH
  10500.    ;
  10501.    begin:    printer_setup 3,1,setup       ; THIS FUNCTION
  10502.              jc            error           ; routine not shown
  10503.  
  10504.  
  10505.  ────────────────────────────────────────────────────────────────────────────
  10506.  Get Assign-List Entry (Function 5FH, Code 02H)
  10507.  ────────────────────────────────────────────────────────────────────────────
  10508.  
  10509.    Call:
  10510.  
  10511.    AH = 5FH
  10512.    AL = 02H
  10513.    BX
  10514.       Assign-list index
  10515.    DS:SI
  10516.       Pointer to buffer for local name
  10517.    ES:DI
  10518.       Pointer to buffer for remote name
  10519.  
  10520.    Return:
  10521.  
  10522.    Carry set:
  10523.    AX
  10524.       1        = Invalid function code
  10525.      18        = No more files
  10526.    Carry not set:
  10527.    BL
  10528.       3 = Printer
  10529.       4 = Drive
  10530.    CX
  10531.       Stored user value
  10532.  
  10533.  
  10534.    Comments:
  10535.  
  10536.    Function 5FH, Code 02H, retrieves the specified entry from the network
  10537.    list of assignments. BX must contain the assign-list index (entry 0 is the
  10538.    first entry). SI must contain the offset (to the segment address in DS) of
  10539.    a 16-byte buffer for the local name. DI must contain the offset (to the
  10540.    segment address in ES) of a 128-byte buffer for the remote name. Microsoft
  10541.    Networks must be running.
  10542.  
  10543.    MS-DOS puts the local name in the buffer pointed to by DS:SI and the
  10544.    remote name in the buffer pointed to by ES:DI. The local name can be a
  10545.    null ASCIZ string. BL returns 3 if the local device is a printer or 4 if
  10546.    the local device is a drive. CX returns the stored user value set with
  10547.    Function 5F03H (Make Network Connection). The contents of the assign list
  10548.    can change between calls. You can use this function request to retrieve
  10549.    any entry, or to make a copy of the complete list by stepping through the
  10550.    table. To detect the end of the assign list, check for error code 18 (no
  10551.    more files), as you would when stepping through a directory by using
  10552.    Functions 4EH (Find First File) and 4FH (Find Next File).
  10553.  
  10554.    If there is an error, the carry flag (CF) is set and the error code
  10555.    returns in AX:
  10556.  
  10557.    Code               Meaning
  10558.    ──────────────────────────────────────────────────────────────────────────
  10559.    1                  Microsoft Networks must be running to use this function
  10560.                       request.
  10561.  
  10562.    18                 The index passed in BX is greater than the number of
  10563.    ──────────────────────────────────────────────────────────────────────────
  10564.  
  10565.    Macro Definition:
  10566.  
  10567.    get_list  macro  index,local,remote
  10568.              mov    bx, index
  10569.              mov    si, offset local
  10570.              mov    di, offset remote
  10571.              mov    al,2
  10572.              mov    ah, 5FH
  10573.              int    21H
  10574.              endm
  10575.  
  10576.    Example:
  10577.  
  10578.    The following program displays the assign list on a Microsoft Networks
  10579.    workstation, showing the local name, remote name, and device type (drive
  10580.    or printer) for each entry.
  10581.  
  10582.    stdout    equ        1
  10583.    printer   equ        3
  10584.    ;
  10585.    local_nm  db         16 dup (?),2 dup (20h)
  10586.    remote_nm db         128 dup (?),2 dup (20h)
  10587.    header    db        "Local name",8 dup (20h)
  10588.              db        "Remote name",7 dup (20h)
  10589.              db        "Device Type"
  10590.    crlf      db         0dh,0ah,0dh,0ah
  10591.    drive_msg db        "drive"
  10592.    print_msg db        "printer"
  10593.    index     dw         ?
  10594.    ;
  10595.  
  10596.  
  10597.  
  10598.    begin:    write_handle stdout,header,51   ; see Function 40H
  10599.              jc         write_error          ; routine not shown
  10600.              mov        index,0              ; assign list index
  10601.    ck_list:  get_list   index,local_nm,remote_nm ; THIS FUNCTION
  10602.              jnc        got_one              ; got an entry
  10603.    error:    cmp        ax,18
  10604.  
  10605.              je         last_one             ; yes
  10606.              jmp        error                ; routine not shown
  10607.    got_one:  push       bx                   ; save device type
  10608.              write_handle  stdout,local_nm,148 ; see Function 40H
  10609.              jc         write_error          ; routine not shown
  10610.              pop        bx                   ; get device type
  10611.              cmp        bl,printer           ; is it a printer?
  10612.              je         prntr                ; yes
  10613.              write_handle stdout,drive_msg,5 ; see Function 40H
  10614.              jc         write_error          ; routine not shown
  10615.              jmp        get_next             ; finish message
  10616.    prntr:    write_handle stdout,print_msg,7 ; see Function 40H
  10617.              jc         write_error          ; routine not shown
  10618.    get_next: write_handle stdout,crlf,2      ; see Function 40H
  10619.              jc         write_error          ; routine not shown
  10620.              inc        index                ; bump index
  10621.              jmp        ck_list              ; get next entry
  10622.    last_one: write_handle stdout,crlf,4      ; see Function 40H
  10623.              jc         write_error          ; routine not shown
  10624.    ;
  10625.  
  10626.  
  10627.  ────────────────────────────────────────────────────────────────────────────
  10628.  Make Network Connection (Function 5FH, Code 03H)
  10629.  ────────────────────────────────────────────────────────────────────────────
  10630.  
  10631.    Call:
  10632.  
  10633.    AH = 5FH
  10634.    AL = 03H
  10635.    BL
  10636.       3 = Printer
  10637.       4 = Drive
  10638.    CX
  10639.       User value
  10640.    DS:SI
  10641.       Pointer to name of source device
  10642.    ES:DI
  10643.       Pointer to name of destination
  10644.       device
  10645.  
  10646.    Return:
  10647.  
  10648.    Carry set:
  10649.    AX
  10650.       1 = Invalid function code
  10651.       5 = Access denied
  10652.       3 = Path not found
  10653.       8 = Insufficient memory
  10654.       (Other errors particular to the
  10655.       network may occur.)
  10656.    Carry not set:
  10657.       No error
  10658.  
  10659.  
  10660.    Comments:
  10661.  
  10662.    Function 5FH, Code 03H, redirects a printer or disk drive (source device)
  10663.    to a network directory (destination device). BL must contain 3 if the
  10664.    source device is a printer or 4 if it is a disk drive. SI must contain the
  10665.    offset (to the segment address in DS) of an ASCIZ string that specifies
  10666.    the name of the printer, or a drive letter followed by a colon, or a null
  10667.    string (one byte of 00H). DI must contain the offset (to the segment
  10668.    address in ES) of an ASCIZ string that specifies the name of a network
  10669.    directory. CX contains a user-specified 16-bit value that MS-DOS
  10670.    maintains. Microsoft Networks must be running. The destination string must
  10671.    be an ASCIZ string of the following form:
  10672.  
  10673.    machine-name pathname 00H password 00H
  10674.  
  10675.    where:
  10676.  
  10677.    Machine-name is the net name of the server that contains the network
  10678.    directory.
  10679.  
  10680.    Pathname is the alias of the network directory (not the directory path) to
  10681.    which the source device is to be redirected.
  10682.  
  10683.    00H is a null byte.
  10684.  
  10685.    Password is the password for access to the network directory. If no
  10686.    password is specified, both null bytes must immediately follow the
  10687.    pathname.
  10688.  
  10689.    If BL=3, the source string must be PRN, LPT1, LPT2, or LPT3. This function
  10690.    buffers and sends all output for the named printer to the remote-printer
  10691.    spooler named in the destination string.
  10692.  
  10693.    If BL=4, the source string can be either a drive letter followed by a
  10694.    colon, or a null string. If the source string contains a valid drive
  10695.    letter and colon, this call redirects all subsequent drive-letter
  10696.    references to the network directory named in the destination string. If
  10697.    the source string is a null string, MS-DOS attempts to grant access to the
  10698.    network directory with the specified password.
  10699.  
  10700.    The maximum length of the destination string is 128 bytes. You can
  10701.    retrieve the value in CX by using Function 5F02H (Get Assign-List Entry).
  10702.  
  10703.    If there is an error, the carry flag (CF) is set and the error code
  10704.    returns in AX:
  10705.  
  10706.    Code               Meaning
  10707.    ──────────────────────────────────────────────────────────────────────────
  10708.    1                  Microsoft Networks must be running to use this function
  10709.                       request; the value in BX is not 1 to 4, the source
  10710.                       string is in the wrong format; the destination string
  10711.                       is in the wrong format; or the source device is already
  10712.                       redirected.
  10713.  
  10714.    3                  The network directory path is invalid or doesn't exist.
  10715.  
  10716.    5                  The network directory/password combination is not
  10717.                       valid. This does not mean that the password itself was
  10718.                       invalid; the directory might not exist on the server.
  10719.  
  10720.    8                  There is not enough memory for string substitutions.
  10721.    ──────────────────────────────────────────────────────────────────────────
  10722.  
  10723.    Macro Definition:
  10724.  
  10725.    redir macro  device,value,source,destination
  10726.          mov    bl, device
  10727.          mov    cx, value
  10728.          mov    si, offset source
  10729.          mov    es, seg destination
  10730.          mov    di, offset destination
  10731.          mov    al, 03H
  10732.          mov    ah, 5FH
  10733.          int    21H
  10734.          endm
  10735.  
  10736.    Example:
  10737.  
  10738.    The following program redirects two drives and a printer from a
  10739.    workstation to a server named harold. It assumes the machine name,
  10740.    directory names, and driver letters shown:
  10741.  
  10742.    Local drive     Netname
  10743.    or printer      on server    Password
  10744.  
  10745.    E:              WORD         none
  10746.    F:              COMM         fred
  10747.    PRN:            PRINTER      quick
  10748.  
  10749.    printer   equ  3
  10750.    drive     equ  4
  10751.    ;
  10752.    local_1   db  "e:",0
  10753.    local_2   db  "f:",0
  10754.    local_3   db  "prn",0
  10755.    remote_1  db  "\harold\word",0,0
  10756.    remote_2  db  "\harold\comm",0,"fred",0
  10757.    remote_3  db  "\harold\printer",0,"quick",0
  10758.    ;
  10759.    begin:    redir  local_1,remote_1,drive,0   ; THIS FUNCTION
  10760.              jc     error                      ; routine not shown
  10761.              redir  local_2,remote_2,drive,0   ; THIS FUNCTION
  10762.              jc     error                      ; routine not shown
  10763.              redir  local_3,remote_3,printer,0 ; THIS FUNCTION
  10764.              jc     error                      ; routine not shown
  10765.  
  10766.  
  10767.  ────────────────────────────────────────────────────────────────────────────
  10768.  Delete Network Connection (Function 5FH, Code 04H)
  10769.  ────────────────────────────────────────────────────────────────────────────
  10770.  
  10771.    Call:
  10772.  
  10773.    AH = 5FH
  10774.    AL = 04H
  10775.    DS:SI
  10776.       Pointer to name of source device
  10777.  
  10778.    Return:
  10779.  
  10780.    Carry set:
  10781.    AX
  10782.       1        = Invalid function code
  10783.      15        = Redirection paused on server
  10784.      (Other errors particular to the network
  10785.      may occur.)
  10786.    Carry not set:
  10787.       No error
  10788.  
  10789.  
  10790.    Comments:
  10791.  
  10792.    Function 5FH, Code 04H, cancels the redirection of a printer or disk drive
  10793.    (source device) to a network directory (destination device) made with
  10794.    Function 5F03H (Make Network Connection). SI must contain the offset (to
  10795.    the segment address in DS) of an ASCIZ string that specifies the name of
  10796.    the printer or drive whose redirection is to be canceled. Microsoft
  10797.    Networks must be running.
  10798.  
  10799.    The ASCIZ string pointed to by DS:SI can contain one of three values:
  10800.  
  10801.    ■  The letter of a redirected drive, followed by a colon. Cancels the
  10802.       redirection and restores the drive to its physical meaning.
  10803.  
  10804.    ■  The name of a redirected printer (PRN, LPT1, LPT2, LPT3, or their
  10805.       machine-specific equivalents). Cancels the redirection and restores the
  10806.       printer name to its physical meaning.
  10807.  
  10808.    ■  A string starting with \\ (2 backslashes). Terminates the connection
  10809.       between the local machine and the network directory.
  10810.  
  10811.    If there is an error, the carry flag (CF) is set and the error code
  10812.    returns in AX:
  10813.  
  10814.    Code               Meaning
  10815.    ──────────────────────────────────────────────────────────────────────────
  10816.    1                  Microsoft Networks must be running to use this function
  10817.                       request; or the ASCIZ string names a nonexistent source
  10818.                       device.
  10819.  
  10820.    15                 Disk or printer redirection on the network server is
  10821.    ──────────────────────────────────────────────────────────────────────────
  10822.  
  10823.    Macro Definition:
  10824.  
  10825.    cancel_redir  macro  local
  10826.                  mov    si, offset local
  10827.                  mov    al, 4
  10828.                  mov    ah, 5FH
  10829.                  int    21H
  10830.                  endm
  10831.  
  10832.    Example:
  10833.  
  10834.    The following program cancels the redirection of drives E and F and the
  10835.    printer (PRN) of a Microsoft Networks workstation. It assumes that these
  10836.    local devices were redirected previously.
  10837.  
  10838.    local_1   db        "e:",0
  10839.    local_2   db        "f:",0
  10840.    local_3   db        "prn",0
  10841.    ;
  10842.    begin:    cancel_redir  local_1    ; THIS FUNCTION
  10843.              jc            error      ; routine not shown
  10844.              cancel_redir  local_2    ; THIS FUNCTION
  10845.              jc            error      ; routine not shown
  10846.              cancel_redir  local_3    ; THIS FUNCTION
  10847.              jc            error      ; routine not shown
  10848.  
  10849.  
  10850.  ────────────────────────────────────────────────────────────────────────────
  10851.  Get PSP (Function 62H)
  10852.  ────────────────────────────────────────────────────────────────────────────
  10853.  
  10854.    Call:
  10855.  
  10856.    AH = 62H
  10857.  
  10858.    Return:
  10859.  
  10860.    BX
  10861.       Segment address of the Program
  10862.       Segment Prefix of the current process
  10863.  
  10864.  
  10865.    Comments:
  10866.  
  10867.    Function 62H retrieves the segment address of the currently active process
  10868.    (the start of the Program Segment Prefix). The address returns in BX.
  10869.  
  10870.    Macro Definition:
  10871.  
  10872.    get_psp macro
  10873.            mov    ah, 62H
  10874.            int    21H
  10875.            endm
  10876.  
  10877.    Example:
  10878.  
  10879.    The following program displays the segment address of its Program Segment
  10880.    Prefix (PSP) in hexadecimal.
  10881.  
  10882.    msg       db       "PSP segment address:  H",0DH,0AH,"$"
  10883.    ;
  10884.    begin:    get_psp                       ; THIS FUNCTION
  10885.              convert   bx,16,msg[21]       ; see end of chapter
  10886.              display   msg                 ; see Function 09H
  10887.  
  10888.  
  10889.  ────────────────────────────────────────────────────────────────────────────
  10890.  Get Extended Country Information (Function 65H)
  10891.  ────────────────────────────────────────────────────────────────────────────
  10892.  
  10893.    Call:
  10894.  
  10895.    AH = 65H
  10896.    AL
  10897.      Function (minor) code
  10898.  
  10899.    BX
  10900.      Code page (-1 = active CON device)
  10901.    CX
  10902.      Amount of data to return
  10903.    DX
  10904.      Country ID for which information is to be returned
  10905.      (-1=default country)
  10906.    ES:DI
  10907.      Address of country information buffer
  10908.  
  10909.    Return:
  10910.  
  10911.  
  10912.    Carry set:
  10913.      1 = Buffer has been filled
  10914.      2 = File not found
  10915.    Carry not set:
  10916.      ES:DI = Pointer to country information buffer
  10917.  
  10918.  
  10919.    Comments:
  10920.  
  10921.    Function 65H retrieves standard country information. This information
  10922.    includes country ID, code page, date and time format, currency symbol,
  10923.    separators (for thousands, decimals, data list, date and time) currency
  10924.    format flags, digits in currency, and case-mapping information. The
  10925.    function code passed in AL may be one of the following:
  10926.  
  10927.    Code               Description
  10928.    ──────────────────────────────────────────────────────────────────────────
  10929.    1                  Return standard information
  10930.    2                  Return pointer to uppercase table
  10931.    4                  Return pointer to filename uppercase table
  10932.    6                  Return pointer to collating table
  10933.    7                  Selects the Double Byte Character Set (DBCS)
  10934.    ──────────────────────────────────────────────────────────────────────────
  10935.  
  10936.    Only the information for the default country is kept in the kernel.
  10937.    Country-dependent information for all other countries is contained in the
  10938.    country.sys file. The MS-DOS nlsfunc command is used to access the
  10939.    country-dependent information in country.sys using this call. If the
  10940.    country code and code page number do not match, or if either is invalid,
  10941.    error code 2 is returned to AX. If CX is less than 5, error code 1 is
  10942.    returned. If the amount of information requested is greater than the value
  10943.    of CX, only CX bytes are returned and no error is reported.
  10944.  
  10945.    If AL = 1, the buffer is filled with the following information:
  10946.  
  10947.    db    1    ;   Information ID
  10948.    dw    ?    ;   Size (<=38)
  10949.    dw    ?    ;   Country ID
  10950.    dw    ?    ;   Code page
  10951.  
  10952.    If AL = 2, the buffer is filled with the following information:
  10953.  
  10954.    db    2    ;   Information ID
  10955.    dd    ?    ;   Double-word pointer to uppercase table
  10956.  
  10957.    If AL = 4, the buffer is filled with the following information:
  10958.  
  10959.    db    4    ;   Information ID
  10960.    dd    ?    ;   Double-word pointer to filename uppercase table
  10961.  
  10962.    Both of these tables consist of a length field (two bytes) followed by 128
  10963.    uppercase values for the upper 128 ASCII characters. The following formula
  10964.    is used to compute the address of an uppercase equivalent in the table:
  10965.  
  10966.    Address of outchar = inchar - (256-table──len) = table──start
  10967.  
  10968.    where:
  10969.  
  10970.    Parameter          Meaning
  10971.    ──────────────────────────────────────────────────────────────────────────
  10972.    inchar             Character to be generated
  10973.    table──len         Length of list of uppercase values (two bytes)
  10974.    table──start       Starting address of uppercase table
  10975.    outchar            Uppercase value for inchar
  10976.    ──────────────────────────────────────────────────────────────────────────
  10977.  
  10978.    If inchar is greater than or equal to (256 - table──len), then there is an
  10979.    uppercase equivalent in the table; otherwise, there is not.
  10980.  
  10981.    If AL = 6, the buffer is filled with the following information:
  10982.  
  10983.    db    6    ;   Information ID
  10984.    dd    ?    ;   Double-word pointer to collating sequence
  10985.  
  10986.    The table is 258 bytes long. The first word is the length of the table.
  10987.    The rest of the table is 256 ASCII values in the appropriate order.
  10988.  
  10989.  
  10990.  ────────────────────────────────────────────────────────────────────────────
  10991.  Get/Set Global Code Page (Function 66H)
  10992.  ────────────────────────────────────────────────────────────────────────────
  10993.  
  10994.    Call:
  10995.  
  10996.    AH = 66H
  10997.    AL
  10998.      Function (minor) code
  10999.    BX
  11000.      Code page to set (AL = 2)
  11001.  
  11002.    Return:
  11003.  
  11004.    Carry set:
  11005.    AX
  11006.     02 = File not found
  11007.     65 = Device not selected
  11008.    Carry not set:
  11009.      No error
  11010.  
  11011.  
  11012.    Comments:
  11013.  
  11014.    Function 66H gets or sets the code page used by the kernel and all
  11015.    devices. If no other code page has been set, this function gets the
  11016.    default code page from DX. If another code page is set, this function
  11017.    retrieves the active code page from BX.
  11018.  
  11019.    The MS-DOS nlsfunc command and country.sys must be on the system if this
  11020.    function is to be used to change the global code page. The function code
  11021.    may be one of the following:
  11022.  
  11023.    Code               Description
  11024.    ──────────────────────────────────────────────────────────────────────────
  11025.    1                  Get code page
  11026.    2                  Set code page
  11027.    ──────────────────────────────────────────────────────────────────────────
  11028.  
  11029.    MS-DOS gets the new code page from the country.sys file. Devices must be
  11030.    prepared for code page switching before a code page can be selected. To
  11031.    prepare a device, a device driver that supports code-page switching must
  11032.    be installed by using the device command in the config.sys file. The user
  11033.    must also use the prepare keyword with the MS-DOS mode command to prepare
  11034.    the device for code-page switching.
  11035.  
  11036.    The code page selected must be compatible with the country code specified
  11037.    in the config.sys file. If MS-DOS cannot read country.sys or another
  11038.    specified country information file, error code 02 is returned to AX.
  11039.  
  11040.  
  11041.  ────────────────────────────────────────────────────────────────────────────
  11042.  Set Handle Count (Function 67H)
  11043.  ────────────────────────────────────────────────────────────────────────────
  11044.  
  11045.    Call:
  11046.  
  11047.    AH = 67H
  11048.    BX
  11049.      Number of allowed handles
  11050.  
  11051.    Return:
  11052.  
  11053.    Carry set:
  11054.    AX
  11055.    Carry not set:
  11056.      No error
  11057.  
  11058.  
  11059.    Comments:
  11060.  
  11061.    Function 67H increases or decreases the number of files a program can have
  11062.    open at one time. The maximum number of file handles is 64K. If less than
  11063.    20 are specified, the minimum handle number, 20, is assumed. If this call
  11064.    is used to reduce the number of allowed handles, the new limit does not
  11065.    take affect until any handles above the new limit are closed.
  11066.  
  11067.    The user should use Function 4AH (Set Block) to allocate memory for the
  11068.    extended handle list if BX is greater than 255. The maximum number for the
  11069.    value of the config.sys command files is 255.
  11070.  
  11071.  
  11072.  ────────────────────────────────────────────────────────────────────────────
  11073.  Commit File (Function 68H)
  11074.  ────────────────────────────────────────────────────────────────────────────
  11075.  
  11076.    Call:
  11077.  
  11078.    AH = 68H
  11079.    BX
  11080.      File handle
  11081.  
  11082.    Return:
  11083.  
  11084.    Carry set:
  11085.    AX = error
  11086.    Carry not set
  11087.      No error
  11088.  
  11089.  
  11090.    Comments:
  11091.  
  11092.    Function 68H flushes all buffered data for a file without closing it.
  11093.    Using this call is more efficient than using the traditional close-open
  11094.    sequence, and is more effective for network environments. This call makes
  11095.    sure that the disk image of a file is current.
  11096.  
  11097.    ;  Macro Definitions for MS-DOS System Call Examples
  11098.    ;
  11099.    ; *******************
  11100.    ;  Interrupts
  11101.    ; *******************
  11102.    ;                                 Interrupt 25H
  11103.    ABS_DISK_READ  macro  disk,buffer,num_sectors,first_sector
  11104.         mov    al,disk
  11105.         mov    bx,offset buffer
  11106.         mov    cx,num_sectors
  11107.         mov    dx,first_sector
  11108.         int    25H
  11109.         popf
  11110.         endm
  11111.    ;                                 Interrupt 26H
  11112.    ABS_DISK_WRITE  macro  disk,buffer,num_sectors,first_sector
  11113.         mov    al,disk
  11114.         mov    bx,offset buffer
  11115.         mov    cx,num_sectors
  11116.         mov    dx,first_sector
  11117.         int    26H
  11118.         popf
  11119.         endm
  11120.    ;                                 Interrupt 27H
  11121.    STAY_RESIDENT  macro  last_instruc
  11122.         mov    dx,offset last_instruc
  11123.         inc    dx
  11124.         int    27H
  11125.         endm
  11126.    ;
  11127.    ;
  11128.    ; *******************
  11129.    ;  Function Requests
  11130.    ; *******************
  11131.    ;                                 Function Request 00H
  11132.    TERMINATE_PROGRAM  macro
  11133.         xor    ah,ah
  11134.         int    21H
  11135.         endm
  11136.    ;                                 Function Request 01H
  11137.    READ_KBD_AND_ECHO  macro
  11138.         mov    ah,01H
  11139.         int    21H
  11140.         endm
  11141.    ;                                 Function Request 02H
  11142.    DISPLAY_CHAR  macro  character
  11143.         mov    dl,character
  11144.         mov    ah,02H
  11145.         int    21H
  11146.         endm
  11147.    ;                                 Function Request 03H
  11148.    AUX_INPUT    macro
  11149.         mov     ah,03H
  11150.         int     21H
  11151.         endm
  11152.    ;                                 Function Request 04H
  11153.    AUX_OUTPUT  macro
  11154.         mov    ah,04H
  11155.         int    21H
  11156.         endm
  11157.    ;                                 Function Request 05H
  11158.    PRINT_CHAR  macro  character
  11159.         mov    dl,character
  11160.         mov    ah,05H
  11161.         int    21H
  11162.         endm
  11163.    ;                                 Function Request 06H
  11164.    DIR_CONSOLE_IO  macro  switch
  11165.         mov    dl,switch
  11166.         mov    ah,06H
  11167.         int    21H
  11168.         endm
  11169.    ;                                 Function Request 07H
  11170.    DIR_CONSOLE_INPUT  macro
  11171.         mov    ah,07H
  11172.         int    21H
  11173.         endm
  11174.    ;                                 Function Request 08H
  11175.    READ_KBD  macro
  11176.         mov    ah,08H
  11177.         int    21H
  11178.         endm
  11179.    ;                                 Function Request 09H
  11180.    DISPLAY  macro  string
  11181.         mov    dx,offset string
  11182.         mov    ah,09H
  11183.         int    21H
  11184.         endm
  11185.    ;                                 Function Request 0AH
  11186.    GET_STRING  macro  limit,string
  11187.         mov    dx,offset string
  11188.         mov    string,limit
  11189.         mov    ah,0AH
  11190.         int    21H
  11191.         endm
  11192.    ;                                 Function Request 0BH
  11193.    CHECK_KBD_STATUS  macro
  11194.         mov    ah,0BH
  11195.         int    21H
  11196.         endm
  11197.    ;                                 Function Request 0CH
  11198.    FLUSH_AND_READ_KBD  macro  switch
  11199.         mov    al,switch
  11200.         mov    ah,0CH
  11201.         int    21H
  11202.         endm
  11203.    ;                                 Function Request 0DH
  11204.    RESET_DISK  macro
  11205.         mov    ah,0DH
  11206.         int    21H
  11207.         endm
  11208.    ;                                 Function Request 0EH
  11209.    SELECT_DISK  macro  disk
  11210.         mov    dl,disk[-65]
  11211.         mov    ah,0EH
  11212.         int    21H
  11213.         endm
  11214.    ;                                 Function Request 0FH
  11215.    OPEN  macro  fcb
  11216.         mov    dx,offset fcb
  11217.         mov    ah,0FH
  11218.         int    21H
  11219.         endm
  11220.    ;                                 Function Request 10H
  11221.    CLOSE  macro  fcb
  11222.         mov    dx,offset fcb
  11223.         mov    ah,10H
  11224.         int    21H
  11225.         endm
  11226.    ;                                 Function Request 11H
  11227.    SEARCH_FIRST  macro  fcb
  11228.         mov    dx,offset fcb
  11229.         mov    ah,11H
  11230.         int    21H
  11231.         endm
  11232.    ;                                 Function Request 12H
  11233.    SEARCH_NEXT  macro  fcb
  11234.         mov    dx,offset fcb
  11235.         mov    ah,12H
  11236.         int    21H
  11237.         endm
  11238.    ;                                 Function Request 13H
  11239.    DELETE  macro  fcb
  11240.         mov    dx,offset fcb
  11241.         mov    ah,13H
  11242.         int    21H
  11243.         endm
  11244.    ;                                 Function Request 14H
  11245.    READ_SEQ  macro  fcb
  11246.         mov    dx,offset fcb
  11247.         mov    ah,14H
  11248.         int    21H
  11249.         endm
  11250.    ;                                 Function Request 15H
  11251.    WRITE_SEQ  macro  fcb
  11252.         mov    dx,offset fcb
  11253.         mov    ah,15H
  11254.         int    21H
  11255.         endm
  11256.    ;                                 Function Request 16H
  11257.    CREATE  macro  fcb
  11258.         mov    dx,offset fcb
  11259.         mov    ah,16H
  11260.         int    21H
  11261.         endm
  11262.    ;                                 Function Request 17H
  11263.    RENAME  macro  fcb,newname
  11264.         mov    dx,offset fcb
  11265.         mov    ah,17H
  11266.         int    21H
  11267.         endm
  11268.    ;                                 Function Request 19H
  11269.    CURRENT_DISK  macro
  11270.         mov    ah,19H
  11271.         int    21H
  11272.         endm
  11273.    ;                                 Function Request 1AH
  11274.    SET_DTA  macro  buffer
  11275.         mov    dx,offset buffer
  11276.         mov    ah,1AH
  11277.         endm
  11278.    ;                                 Function Request 1BH
  11279.    DEF_DRIVE_DATA  macro
  11280.         mov    ah,1BH
  11281.         int    21H
  11282.         endm
  11283.    ;                                 Function Request 1CH
  11284.    DRIVE_DATA  macro  drive
  11285.         mov    dl,drive
  11286.         mov    ah,1CH
  11287.         int    21H
  11288.         endm
  11289.    ;                                 Function Request 21H
  11290.    READ_RAN  macro  fcb
  11291.         mov    dx,offset fcb
  11292.         mov    ah,21H
  11293.         int    21H
  11294.         endm
  11295.    ;                                 Function Request 22H
  11296.    WRITE_RAN  macro  fcb
  11297.         mov    dx,offset fcb
  11298.         mov    ah,22H
  11299.         int    21H
  11300.         endm
  11301.    ;                                 Function Request 23H
  11302.    FILE_SIZE  macro  fcb
  11303.         mov    dx,offset fcb
  11304.         mov    ah,23H
  11305.         int    21H
  11306.         endm
  11307.    ;                                 Function Request 24H
  11308.    SET_RELATIVE_RECORD  macro  fcb
  11309.         mov    dx,offset fcb
  11310.         mov    ah,24H
  11311.         int    21H
  11312.         endm
  11313.    ;                                 Function Request 25H
  11314.    SET_VECTOR  macro  interrupt,handler_start
  11315.         mov    al,interrupt
  11316.         mov    dx,offset handler_start
  11317.         mov    ah,25H
  11318.         int    21H
  11319.         endm
  11320.    ;                                 Function Request 26H
  11321.    CREATE_PSP  macro  seg_addr
  11322.         mov    dx,offset seg_addr
  11323.         mov    ah,26H
  11324.         int    21H
  11325.         endm
  11326.    ;                                  Function Request 27H
  11327.    RAN_BLOCK_READ  macro  fcb,count,rec_size
  11328.         mov    dx,offset fcb
  11329.         mov    cx,count
  11330.         mov    word ptr fcb[14],rec_size
  11331.         mov    ah,27H
  11332.         int    21H
  11333.         endm
  11334.    ;                                  Function Request 28H
  11335.    RAN_BLOCK_WRITE  macro  fcb,count,rec_size
  11336.         mov    dx,offset fcb
  11337.         mov    cx,count
  11338.         mov    word ptr fcb[14],rec_size
  11339.         mov    ah,28H
  11340.         int    21H
  11341.         endm
  11342.    ;                                 Function Request 29H
  11343.    PARSE  macro  string,fcb
  11344.         mov    si,offset string
  11345.         mov    di,offset fcb
  11346.         push   es
  11347.         push   ds
  11348.         pop    es
  11349.         mov    al,0FH
  11350.         mov    ah,29H
  11351.         int    21H
  11352.         pop    es
  11353.         endm
  11354.    ;                                  Function Request 2AH
  11355.    GET_DATE  macro
  11356.         mov    ah,2AH
  11357.         int    21H
  11358.         endm
  11359.    ;                                  Function Request 2BH
  11360.    SET_DATE  macro  year,month,day
  11361.         mov    cx,year
  11362.         mov    dh,month
  11363.         mov    dl,day
  11364.         mov    ah,2BH
  11365.         int    21H
  11366.         endm
  11367.    ;                                  Function Request 2CH
  11368.    GET_TIME  macro
  11369.         mov    ah,2CH
  11370.         int    21H
  11371.         endm
  11372.    ;                                  Function Request 2DH
  11373.    SET_TIME  macro  hour,minutes,seconds,hundredths
  11374.         mov    ch,hour
  11375.         mov    cl,minutes
  11376.         mov    dh,seconds
  11377.         mov    dl,hundredths
  11378.         mov    ah,2DH
  11379.         int    21H
  11380.         endm
  11381.    ;                                  Function Request 2EH
  11382.    VERIFY  macro  switch
  11383.         mov    al,switch
  11384.         mov    ah,2EH
  11385.         int    21H
  11386.         endm
  11387.    ;                                  Function Request 2FH
  11388.    GET_DTA  macro
  11389.         mov    ah,2FH
  11390.         int    21H
  11391.         endm
  11392.    ;                                  Function Request 30H
  11393.    GET_VERSION  macro
  11394.         mov    ah,30H
  11395.         int    21H
  11396.         endm
  11397.    ;                                  Function Request 31H
  11398.    KEEP_PROCESS  macro  return_code,last_byte
  11399.         mov    al,return_code
  11400.         mov    dx,offset last_byte
  11401.         mov    cl,4
  11402.         shr    dx,cl
  11403.         inc    dx
  11404.         mov    ah,31H
  11405.         int    21H
  11406.         endm
  11407.    ;                                  Function Request 33H
  11408.    CTRL_C_CK  macro  action,state
  11409.         mov    al,action
  11410.         mov    dl,state
  11411.         mov    ah,33H
  11412.         int    21H
  11413.         endm
  11414.    ;                                  Function Request 35H
  11415.    GET_VECTOR  macro  interrupt
  11416.         mov    al,interrupt
  11417.         mov    ah,35H
  11418.         int    21H
  11419.         endm
  11420.    ;                                  Function Request 36H
  11421.    GET_DISK_SPACE  macro  drive
  11422.         mov    dl,drive
  11423.         mov    ah,36H
  11424.         int    21H
  11425.         endm
  11426.    ;                                  Function Request 38H
  11427.    GET_COUNTRY  macro  country,buffer
  11428.                 local  gc_01
  11429.                 mov    dx,offset buffer
  11430.                 mov    ax,country
  11431.                 cmp    ax,0FFH
  11432.                 jl     gc_01
  11433.                 mov    al,0ffh
  11434.                 mov    bx,country
  11435.    gc_01:       mov    ah,38H
  11436.                 int    21H
  11437.                 endm
  11438.    ;                                  Function Request 38H
  11439.    SET_COUNTRY  macro  country
  11440.                 local  sc_01
  11441.                 mov    dx,0FFFFH
  11442.                 mov    ax,country
  11443.                 cmp    ax,0FFH
  11444.                 jl     sc_01
  11445.                 mov    al,0ffh
  11446.                 mov    bx,country
  11447.    sc_01:       mov    ah,38H
  11448.                 int    21H
  11449.                 endm
  11450.    ;                                  Function Request 39H
  11451.    MAKE_DIR  macro  path
  11452.         mov    dx,offset path
  11453.         mov    ah,39H
  11454.         int    21H
  11455.         endm
  11456.    ;                                  Function Request 3AH
  11457.    REM_DIR  macro  path
  11458.         mov    dx,offset path
  11459.         mov    ah,3AH
  11460.         int    21H
  11461.         endm
  11462.    ;                                  Function Request 3BH
  11463.    CHANGE_DIR  macro  path
  11464.         mov    dx,offset path
  11465.         mov    ah,3BH
  11466.         int    21H
  11467.         endm
  11468.    ;                                  Function Request 3CH
  11469.    CREATE_HANDLE  macro  path,attrib
  11470.         mov    dx,offset path
  11471.         mov    cx,attrib
  11472.         mov    ah,3CH
  11473.         int    21H
  11474.         endm
  11475.    ;                                  Function Request 3DH
  11476.    OPEN_HANDLE  macro  path,access
  11477.         mov    dx,offset path
  11478.         mov    al,access
  11479.         mov     ah,3DH
  11480.         int    21H
  11481.         endm
  11482.    ;                                  Function Request 3EH
  11483.    CLOSE_HANDLE  macro  handle
  11484.         mov    bx,handle
  11485.         mov    ah,3EH
  11486.         int    21H
  11487.         endm
  11488.    ;                                  Function Request 3FH
  11489.    READ_HANDLE  macro  handle,buffer,bytes
  11490.         mov    bx,handle
  11491.         mov    dx,offset buffer
  11492.         mov    cx,bytes
  11493.         mov    ah,3FH
  11494.         int    21H
  11495.         endm
  11496.    ;                                  Function Request 40H
  11497.    WRITE_HANDLE  macro  handle,buffer,bytes
  11498.         mov    bx,handle
  11499.         mov    dx,offset buffer
  11500.         mov    cx,bytes
  11501.         mov    ah,40H
  11502.         int    21H
  11503.         endm
  11504.    ;                                  Function Request 41H
  11505.    DELETE_ENTRY  macro  path
  11506.         mov    dx,offset path
  11507.         mov    ah,41H
  11508.         int    21H
  11509.         endm
  11510.    ;                                  Function Request 42H
  11511.    MOVE_PTR  macro  handle,high,low,method
  11512.         mov    bx,handle
  11513.         mov    cx,high
  11514.         mov    dx,low
  11515.         mov    al,method
  11516.         mov    ah,42H
  11517.         int    21H
  11518.         endm
  11519.    ;                                  Function Request 43H
  11520.    CHANGE_MODE  macro  path,action,attrib
  11521.         mov    dx,offset path
  11522.         mov    al,action
  11523.         mov    cx,attrib
  11524.         mov    ah,43H
  11525.         int    21H
  11526.         endm
  11527.    ;                                  Function Request 4400H,01H
  11528.    IOCTL_DATA  macro  code,handle
  11529.         mov    bx,handle
  11530.         mov    al,code
  11531.         mov    ah,44H
  11532.         int    21H
  11533.         endm
  11534.    ;                                  Function Request 4402H,03H
  11535.    IOCTL_CHAR  macro  code,handle,buffer
  11536.         mov    bx,handle
  11537.         mov    dx,offset buffer
  11538.         mov    al,code
  11539.         mov    ah,44H
  11540.         int    21H
  11541.         endm
  11542.    ;                                  Function Request 4404H,05H
  11543.    IOCTL_STATUS  macro  code,drive,buffer
  11544.         mov    bl,drive
  11545.         mov    dx,offset buffer
  11546.         mov    al,code
  11547.         mov    ah,44H
  11548.         int    21H
  11549.         endm
  11550.    ;                                  Function Request 4406H,07H
  11551.    IOCTL_STATUS macro  code,handle
  11552.         mov    bx,handle
  11553.         mov    al,code
  11554.         mov    ah,44H
  11555.         int    21H
  11556.         endm
  11557.    ;                                  Function Request 4408H
  11558.    IOCTL_CHANGE  macro  drive
  11559.         mov    bl,drive
  11560.         mov    al,08H
  11561.         mov    ah,44H
  11562.         int    21H
  11563.         endm
  11564.    ;                                  Function Request 4409H
  11565.    IOCTL_RBLOCK  macro  drive
  11566.         mov    bl,drive
  11567.         mov    al,09H
  11568.         mov    ah,44H
  11569.         int    21H
  11570.         endm
  11571.    ;                                  Function Request 440AH
  11572.    IOCTL_RHANDLE  macro  handle
  11573.         mov    bx,handle
  11574.         mov    al,0AH
  11575.         mov    ah,44H
  11576.         int    21H
  11577.         endm
  11578.    ;                                  Function Request 440BH
  11579.    IOCTL_RETRY  macro  retries,wait
  11580.         mov    dx,retries
  11581.         mov    cx,wait
  11582.         mov    al,0BH
  11583.         mov    ah,44H
  11584.         int    21H
  11585.         endm
  11586.    ;                                  Function Request 440CH
  11587.    GENERIC_IOCTL_HANDLES macro handle,function,category,buffer
  11588.         mov    ch,05H
  11589.         mov    cl,function
  11590.         mov    dx,offset buffer
  11591.         mov    bx,handle
  11592.         mov    ah,44H
  11593.         mov    al,0CH
  11594.         int    21H
  11595.         endm
  11596.    ;                                  Function Request 440DH
  11597.    GENERIC_IOCTL_BLOCK macro drive_num,function,category,parm_blk
  11598.         mov    ch,08H
  11599.         mov    cl,function
  11600.         mov    dx,offset parm_blk - 1
  11601.         mov    bx,drive_num
  11602.         mov    ah,44H
  11603.         mov    al,0DH
  11604.         int    21H
  11605.         endm
  11606.    ;                                  Function Request 440EH
  11607.    IOCTL_GET_DRIVE_MAP macro   logical_drv
  11608.         mov    bx,logical_drv
  11609.         mov    ah,44H
  11610.         mov    al,0EH
  11611.         int    21H
  11612.         endm
  11613.    ;                                  Function Request 440FH
  11614.    IOCTL_SET_DRIVE_MAP macro   logical_drv
  11615.         mov    bx,logical_drv
  11616.         mov    ah,44H
  11617.         mov    al,0FH
  11618.         int    21H
  11619.         endm
  11620.    ;                                  Function Request 45H
  11621.    XDUP  macro  handle
  11622.         mov    bx,handle
  11623.         mov    ah,45H
  11624.         int    21H
  11625.         endm
  11626.    ;                                  Function Request 46H
  11627.    XDUP2  macro  handle1,handle2
  11628.         mov    bx,handle1
  11629.         mov    cx,handle2
  11630.         mov    ah,46H
  11631.         int    21H
  11632.         endm
  11633.    ;                                  Function Request 47H
  11634.    GET_DIR  macro  drive,buffer
  11635.         mov    dl,drive
  11636.         mov    si,offset buffer
  11637.         mov    ah,47H
  11638.         int    21H
  11639.         endm
  11640.    ;                                  Function Request 48H
  11641.    ALLOCATE_MEMORY  macro  bytes
  11642.         mov    bx,bytes
  11643.         mov    cl,4
  11644.         shr          bx,cl
  11645.         inc    bx
  11646.         mov    ah,48H
  11647.         int    21H
  11648.         endm
  11649.    ;                                  Function Request 49H
  11650.    FREE_MEMORY  macro  seg_addr
  11651.         mov    ax,seg_addr
  11652.         mov    es,ax
  11653.         mov    ah,49H
  11654.         int    21H
  11655.         endm
  11656.    ;                                  Function Request 4AH
  11657.    SET_BLOCK  macro  last_byte
  11658.         mov    bx,offset last_byte
  11659.         mov    cl,4
  11660.         shr    bx,cl
  11661.         add    bx,17
  11662.         mov    ah,4AH
  11663.         int    21H
  11664.         mov     ax,bx
  11665.         shl     ax,cl
  11666.         dec     ax
  11667.         mov     sp,ax
  11668.         mov     bp,sp
  11669.         endm
  11670.    ;                                  Function Request 4B00H
  11671.    EXEC macro  path,command,parms
  11672.         mov    dx,offset path
  11673.         mov    bx,offset parms
  11674.         mov    word ptr parms[02h],offset command
  11675.         mov    word ptr parms[04h],cs
  11676.         mov    word ptr parms[06h],5ch
  11677.         mov    word ptr parms[08h],es
  11678.         mov    word ptr parms[0ah],6ch
  11679.         mov    word ptr parms[0ch],es
  11680.         mov    al,0
  11681.         mov    ah,4BH
  11682.         int    21H
  11683.         endm
  11684.    ;                                  Function Request 4B03H
  11685.    EXEC_OVL  macro  path,parms,seg_addr
  11686.          mov    dx,offset path
  11687.          mov    bx,offset parms
  11688.          mov    parms,seg_addr
  11689.          mov    parms[02H],seg_addr
  11690.          mov    al,3
  11691.          mov    ah,4BH
  11692.          int    21H
  11693.          endm
  11694.    ;                                  Function Request 4CH
  11695.    END_PROCESS  macro  return_code
  11696.                 mov    al,return_code
  11697.                 mov    ah,4CH
  11698.                 int    21H
  11699.                 endm
  11700.    ;                                  Function Request 4DH
  11701.    RET_CODE macro
  11702.          mov    ah,4DH
  11703.          int    21H
  11704.          endm
  11705.    ;                                  Function Request 4EH
  11706.    FIND_FIRST_FILE  macro  path,attrib
  11707.         mov    dx,offset path
  11708.         mov    cx,attrib
  11709.         mov    ah,4EH
  11710.         int    21H
  11711.         endm
  11712.    ;                                  Function Request 4FH
  11713.    FIND_NEXT_FILE  macro
  11714.         mov    ah,4FH
  11715.         int    21H
  11716.         endm
  11717.    ;                                  Function Request 54H
  11718.    GET_VERIFY  macro
  11719.         mov    ah,54H
  11720.         int    21H
  11721.         endm
  11722.    ;                                  Function Request 56H
  11723.    RENAME_FILE  macro  old_path,new_path
  11724.         mov    dx,offset old_path
  11725.         push   ds
  11726.         pop    es
  11727.         mov    di,offset new_path
  11728.         mov    ah,56H
  11729.         int    21H
  11730.         endm
  11731.    ;                                  Function Request 57H
  11732.    GET_SET_DATE_TIME  macro  handle,action,time,date
  11733.         mov     bx,handle
  11734.         mov    al,action
  11735.         mov    cx,word ptr time
  11736.         mov    dx,word ptr date
  11737.         mov    ah,57H
  11738.         int    21H
  11739.         endm
  11740.    ;                                  Function Request 58H
  11741.    ALLOC_STRAT  macro  code,strategy
  11742.         mov    bx,strategy
  11743.         mov    al,code
  11744.         mov    ah,58H
  11745.         int    21H
  11746.         endm
  11747.    ;                                  Function Request 59H
  11748.    GET_ERROR  macro
  11749.         mov    ah,59
  11750.         int    21H
  11751.         endm
  11752.    ;                                  Function Request 5AH
  11753.    CREATE_TEMP  macro  pathname,attrib
  11754.                 mov    cx,attrib
  11755.                 mov    dx,offset pathname
  11756.                 mov    ah,5AH
  11757.                 int    21H
  11758.                 endm
  11759.    ;                                  Function Request 5BH
  11760.    CREATE_NEW  macro  pathname,attrib
  11761.                mov    cx,attrib
  11762.                mov    dx,offset pathname
  11763.                mov    ah,5BH
  11764.                int    21H
  11765.                endm
  11766.    ;                                  Function Request 5C00H
  11767.    LOCK        macro  handle,start,bytes
  11768.                mov    bx,handle
  11769.                mov    cx,word ptr start
  11770.                mov    dx,word ptr start+2
  11771.                mov    si,word ptr bytes
  11772.                mov    di,word ptr bytes+2
  11773.                mov    al,0
  11774.                mov    ah,5CH
  11775.                int    21H
  11776.                endm
  11777.    ;                                  Function Request 5C01H
  11778.    UNLOCK      macro  handle,start,bytes
  11779.                mov    bx,handle
  11780.                mov    cx,word ptr start
  11781.                mov    dx,word ptr start+2
  11782.                mov    si,word ptr bytes
  11783.                mov    di,word ptr bytes+2
  11784.                mov    al,1
  11785.                mov    ah,5CH
  11786.                int    21H
  11787.                endm
  11788.    ;                                  Function Request 5E00H
  11789.    GET_MACHINE_NAME  macro  buffer
  11790.                mov    dx,offset buffer
  11791.                mov    al,0
  11792.                mov    ah,5EH
  11793.                int    21H
  11794.                endm
  11795.    ;                                  Function Request 5E02H
  11796.    PRINTER_SETUP  macro  index,lgth,string
  11797.                mov    bx,index
  11798.                mov    cx,lgth
  11799.                mov    dx,offset string
  11800.                mov    al,2
  11801.                mov    ah,5EH
  11802.                int    21H
  11803.                endm
  11804.    ;                                  Function Request 5F02H
  11805.    GET_LIST    macro  index,local,remote
  11806.                mov    bx,index
  11807.                mov    si,offset local
  11808.                mov    di,offset remote
  11809.                mov    al,2
  11810.                mov    ah,5FH
  11811.                int    21H
  11812.                endm
  11813.    ;                                  Function Request 5F03H
  11814.    REDIR       macro  device,value,source,destination
  11815.                mov    bl,device
  11816.                mov    cx,value
  11817.                mov    si,offset source
  11818.                mov    es,seg destination
  11819.                mov    di,offset destination
  11820.                mov    al,03H
  11821.                mov    ah,5FH
  11822.                int    21H
  11823.                endm
  11824.    ;                                  Function Request 5F04H
  11825.    CANCEL_REDIR  macro  local
  11826.                mov    si,offset local
  11827.                mov    al,4
  11828.                mov    ah,5FH
  11829.                int    21H
  11830.                endm
  11831.    ;                                  Function Request 62H
  11832.    GET_PSP     macro
  11833.                mov    ah,62H
  11834.                int    21H
  11835.                endm
  11836.    ;
  11837.    ;
  11838.    ; *******************
  11839.    ;  General
  11840.    ; *******************
  11841.    ;
  11842.    DISPLAY_ASCIZ  macro  asciz_string
  11843.         local  search,found_it
  11844.         mov    bx,offset asciz_string
  11845.  
  11846.    search:
  11847.         cmp    byte ptr [bx],0
  11848.         je     found_it
  11849.         inc    bx
  11850.         jmp short search
  11851.  
  11852.    found_it:
  11853.         mov    byte ptr [bx],"$"
  11854.         display asciz_string
  11855.         mov    byte ptr [bx],0
  11856.         display_char 0DH
  11857.         display_char 0AH
  11858.         endm
  11859.    ;
  11860.    MOVE_STRING  macro  source,destination,count
  11861.         push   es
  11862.         push   ds
  11863.         pop    es
  11864.         assume es:code
  11865.         mov    si,offset source
  11866.         mov    di,offset destination
  11867.         mov    cx,count
  11868.     rep movs   es:destination,source
  11869.         assume es:nothing
  11870.         pop    es
  11871.         endm
  11872.    ;
  11873.    CONVERT  macro  value,base,destination
  11874.         local  table,start
  11875.         jmp    start
  11876.    table  db   "0123456789ABCDEF"
  11877.  
  11878.    start:
  11879.         push   ax
  11880.         push   bx
  11881.         push   dx
  11882.         mov    al,value
  11883.         xor    ah,ah
  11884.         xor    bx,bx
  11885.         div    base
  11886.         mov    bl,al
  11887.         mov    al,cs:table[bx]
  11888.         mov    destination,al
  11889.         mov    bl,ah
  11890.         mov    al,cs:table[bx]
  11891.         mov    destination[1],al
  11892.         pop    dx
  11893.         pop    bx
  11894.         pop    ax
  11895.         endm
  11896.    ;
  11897.    CONVERT_TO_BINARY  macro  string,number,value
  11898.         local  ten,start,calc,mult,no_mult
  11899.         jmp    start
  11900.    ten  db     10
  11901.  
  11902.    start:
  11903.         mov    value,0
  11904.         xor    cx,cx
  11905.         mov    cl,number
  11906.         xor    si,si
  11907.  
  11908.    calc:
  11909.         xor    ax,ax
  11910.         mov    al,string[si]
  11911.         sub    al,48
  11912.         cmp    cx,2
  11913.         jl     no_mult
  11914.         push   cx
  11915.         dec    cx
  11916.  
  11917.    mult:
  11918.         mul    cs:ten
  11919.         loop   mult
  11920.         pop    cx
  11921.  
  11922.    no_mult:
  11923.         add    value,ax
  11924.         inc    si
  11925.         loop   calc
  11926.         endm
  11927.    ;
  11928.    CONVERT_DATE  macro  dir_entry
  11929.         mov    dx,word ptr dir_entry[24]
  11930.         mov    cl,5
  11931.         shr    dl,cl
  11932.         mov    dh,dir_entry[24]
  11933.         and    dh,1FH
  11934.         xor    cx,cx
  11935.         mov    cl,dir_entry[25]
  11936.         shr    cl,1
  11937.         add    cx,1980
  11938.         endm
  11939.    ;
  11940.    PACK_DATE  macro  date
  11941.         local set_bit
  11942.    ;
  11943.    ;  On entry: DH=day, DL=month, CX=(year-1980)
  11944.    ;
  11945.         sub   cx,1980
  11946.         push  cx
  11947.         mov   date,dh
  11948.         mov   cl,5
  11949.         shl   dl,cl
  11950.         pop   cx
  11951.         jnc   set_bit
  11952.         or    cl,80h
  11953.  
  11954.    set_bit:
  11955.         or    date,dl
  11956.         rol   cl,1
  11957.         mov   date[1],cl
  11958.         endm
  11959.    ;
  11960.  
  11961.  
  11962.  
  11963.  
  11964.  
  11965.  
  11966.  ────────────────────────────────────────────────────────────────────────────
  11967.  Chapter 2  MS-DOS Device Drivers
  11968.  
  11969.      2.1   Introduction
  11970.      2.2   Format of a Device Driver
  11971.      2.3   How to Create a Device Driver
  11972.            2.3.1   Device Strategy Routine
  11973.            2.3.2   Device Interrupt Routine
  11974.      2.4   Installing Device Drivers
  11975.      2.5   Device Headers
  11976.            2.5.1   Pointer to Next Device Field
  11977.            2.5.2   Attribute Field
  11978.            2.5.3   Strategy and Interrupt Routines
  11979.            2.5.4   Name Field
  11980.      2.6   Request Header
  11981.            2.6.1   Length of Record
  11982.            2.6.2   Unit Code Field
  11983.            2.6.3   Command Code Field
  11984.            2.6.4   Status Field
  11985.      2.7   Device Driver Functions
  11986.            2.7.1   The Init Function
  11987.            2.7.2   The Media Check Function
  11988.            2.7.3   The Build BPB Function
  11989.            2.7.4   The Read or Write Function
  11990.            2.7.5   The Non-destructive Read, No Wait Function
  11991.            2.7.6   The Open or Close Function
  11992.            2.7.7   The Removable Media Function
  11993.            2.7.8   The Status Function
  11994.            2.7.9   The Flush Function
  11995.            2.7.10  The Generic IOCtl Function
  11996.            2.7.11  The Get/Set Logical Drive Map Function
  11997.      2.8   The Media Descriptor Byte
  11998.      2.9   Format of a Media Descriptor Table
  11999.      2.10  The CLOCK Device
  12000.      2.11  Anatomy of a Device Call
  12001.      2.12  Two Sample Device Drivers
  12002.  
  12003.  
  12004.  2.1  Introduction
  12005.  
  12006.    The io.sys file comprises the "resident" device drivers, which form the
  12007.    MS-DOS BIOS. These drivers are called upon by MS-DOS to handle
  12008.    input/output (I/O) requests initiated by application programs.
  12009.  
  12010.    One of the most powerful features of MS-DOS is the ability to add new
  12011.    devices such as printers, plotters, and mouse input devices without
  12012.    rewriting the BIOS. The MS-DOS BIOS is configurable; that is, new drivers
  12013.    can be added and existing drivers can be preempted. Nonresident, or
  12014.    installable, device drivers may be easily added at boot time by including
  12015.    a device command line in the config.sys file.
  12016.  
  12017.    At boot time, a minimum of five resident device drivers must be present.
  12018.    These drivers are in a linked list: the header of each one contains a
  12019.    DWORD pointer to the next. The last driver in the chain has an end-of-list
  12020.    marker of -1, -1 (all bits on).
  12021.  
  12022.    Each driver in the chain has two entry points: the strategy entry point
  12023.    and the interrupt entry point. MS-DOS does not take advantage of the two
  12024.    entry points: it calls the strategy routine, then immediately calls the
  12025.    interrupt routine.
  12026.  
  12027.    The dual entry points will accomodate future multitasking versions of
  12028.    MS-DOS. In multitasking environments, I/O must be asynchronous; to
  12029.    accomplish this, the strategy routine will be called to (internally) queue
  12030.    a request and return quickly. It is then the responsibility of the
  12031.    interrupt routine to perform the I/O at interrupt time by getting requests
  12032.    from the internal queue and processing them. When a request is completed,
  12033.    it is flagged as "done" by the interrupt routine. MS-DOS periodically
  12034.    scans the list of requests looking for those that are flagged as done, and
  12035.    "wakes up" the process waiting for the completion of the request.
  12036.  
  12037.    When requests are queued in this manner, it is no longer sufficient to
  12038.    pass I/O information in registers, since many requests may be pending at
  12039.    any time. Therefore, the MS-DOS device interface uses "packets" to pass
  12040.    request information. These request packets vary in size and format, and
  12041.    are composed of two parts:
  12042.  
  12043.    1. The static request header section, which has the same format for all
  12044.       requests
  12045.  
  12046.    2. A section which has information specific to the type of request
  12047.  
  12048.    A driver is called with a pointer to a packet. In multitasking versions,
  12049.    this packet will be linked into a global chain of all pending I/O requests
  12050.    maintained by MS-DOS.
  12051.  
  12052.    MS-DOS does not implement a global or local queue. Only one request is
  12053.    pending at any one time. The strategy routine must store the address of
  12054.    the packet at a fixed location, and the interrupt routine, which is called
  12055.    immediately after the strategy routine, should process the packet by
  12056.    completing the request and returning. It is assumed that the request is
  12057.    completed when the interrupt routine returns.
  12058.  
  12059.    To make a device driver that sysinit can install, a .bin (core image) or
  12060.    .exe format file must be created with the device driver header at the
  12061.    beginning of the file. The link field should be initialized to -1 (sysinit
  12062.    fills it in). Device drivers which are part of the BIOS should have their
  12063.    headers point to the next device in the list and the last header should be
  12064.    initialized to -1,-1. The BIOS must be a .bin (core image) format file.
  12065.  
  12066.    The .exe format installable device drivers may be used in non-IBM versions
  12067.    of MS-DOS. On the IBM Personal Computer, the .exe loader is located in
  12068.    command.com, which is not present at the time that installable devices are
  12069.    being loaded.
  12070.  
  12071.  
  12072.  2.2  Format of a Device Driver
  12073.  
  12074.    A device driver is a program segment responsible for communication between
  12075.    DOS and the system hardware. It has a special header at the beginning
  12076.    identifying it as a device driver, defining entry points, and describing
  12077.    various attributes of the device.
  12078.  
  12079.    ──────────────────────────────────────────────────────────────────────────
  12080.    Note
  12081.      For device drivers, the file must not use the ORG 100H (like .com
  12082.      files). Because it does not use the Program Segment Prefix (PSP), the
  12083.      device driver is simply loaded; therefore, the file must have an origin
  12084.      of zero (ORG 0 or no ORG statement).
  12085.    ──────────────────────────────────────────────────────────────────────────
  12086.  
  12087.    There are two kinds of device drivers:
  12088.  
  12089.    ■  Character device drivers
  12090.  
  12091.    ■  Block device drivers
  12092.  
  12093.    Character devices perform serial character I/O. Examples are the console,
  12094.    communications port, and printer. These devices are named (i.e., CON, AUX,
  12095.    CLOCK, etc.), and programs may open channels (handles or file control
  12096.    blocks) to do I/O to them.
  12097.  
  12098.    Block devices include all the disk drives on the system. They can perform
  12099.    random I/O in structured pieces called blocks (usually the physical sector
  12100.    size). These devices are not named as the character devices are and,
  12101.    therefore, cannot be opened directly. Instead they have unit numbers and
  12102.    are identified by drive letters such as A, B, and C.
  12103.  
  12104.    A single block device driver may be responsible for one or more logically
  12105.    contiguous disk drives. For example, block device driver ALPHA may be
  12106.    responsible for drives A, B, C, and D. This means that it has four units
  12107.    defined (0-3) and, therefore, takes up four drive letters. The position of
  12108.    the driver in the list of all drivers determines which units correspond to
  12109.    which driver letters. If driver ALPHA is the first block driver in the
  12110.    device list, and it defines four units (0-3), then they will be A, B, C,
  12111.    and D. If BETA is the second block driver and defines three units (0-2),
  12112.    then they will be E, F, and G, and so on. The theoretical limit is 63, but
  12113.    it should be noted that the device installation code will not allow the
  12114.    installation of a device if it would result in a drive letter greater than
  12115.    Z (5AH). All block device drivers present in the standard resident BIOS
  12116.    will be placed ahead of installable block device drivers in the list.
  12117.  
  12118.    ──────────────────────────────────────────────────────────────────────────
  12119.    Note
  12120.      Because they have only one name, character devices cannot define
  12121.      multiple units.
  12122.    ──────────────────────────────────────────────────────────────────────────
  12123.  
  12124.  
  12125.  2.3  How to Create a Device Driver
  12126.  
  12127.    To create a device driver that MS-DOS can install, you must create a
  12128.    binary file (.com or .exe format) with a device header at the beginning of
  12129.    the file. Notice that for device drivers, the code should not be
  12130.    originated at 100H, but at 0. The device header contains a link field (a
  12131.    pointer to the next device header) that should be -1, unless there is more
  12132.    than one device driver in the file. The attribute field and entry points
  12133.    must be set correctly.
  12134.  
  12135.    If it is a character device, the name field should be filled in with the
  12136.    name of that character device. The name can be any legal eight-character
  12137.    filename. If the name is less than eight characters, it should be padded
  12138.    out to eight characters with spaces (20H). Notice that device names do not
  12139.    include colons (:). The fact that CON is the same as CON: is a property of
  12140.    the default MS-DOS command interpreter (command.com) and not of the device
  12141.    driver or the MS-DOS interface. All character device names are handled in
  12142.    this way.
  12143.  
  12144.    MS-DOS always processes installable device drivers before handling the
  12145.    default devices; so, to install a new CON device, simply name the device
  12146.    CON. Remember to set the standard input device and standard output device
  12147.    bits in the attribute word on a new CON device. The scan of the device
  12148.    list stops on the first match, so the installable device driver takes
  12149.    precedence.
  12150.  
  12151.    It is not possible to replace the resident disk block device driver with
  12152.    an installable device driver the same way you can replace the other device
  12153.    drivers in the BIOS. Block drivers can be used only for devices not
  12154.    directly supported by the default disk drivers in AE@%
  12155.    database installed. As an example, if your SQL Server is named sql_svr,
  12156.    e
  12157.    Note
  12158.      Because MS-DOS can install the driver anywhere in memory, care must be
  12159.      taken when making far memory references. You should not expect that your
  12160.      driver will always be loaded in the same place every time.
  12161.    ──────────────────────────────────────────────────────────────────────────
  12162.  
  12163.  2.3.1  Device Strategy Routine
  12164.  
  12165.    The device strategy routine, which is called by MS-DOS for each device
  12166.    driver service request, is primarily responsible for queuing these
  12167.    requests in the order in which they are to be processed by the device
  12168.    interrupt routine. Such queuing can be a very important performance
  12169.    feature in a multitasking environment, or where asynchronous I/O is
  12170.    supported. As MS-DOS does not currently support these facilities, only one
  12171.    request can be serviced at a time, and this routine is usually very short.
  12172.    In the coding examples in Section 2.12, "Two Sample Device Drivers," each
  12173.    request is simply stored in a single pointer area.
  12174.  
  12175.  2.3.2  Device Interrupt Routine
  12176.  
  12177.    The device interrupt routine contains the code necessary to process the
  12178.    service request. It may interface to the hardware, or it may use ROM BIOS
  12179.    calls. It usually consists of a series of procedures that handle the
  12180.    specific command codes to be supported as well as some exit and
  12181.    error-handling routines. See the coding examples in Section 2.12, "Two
  12182.    Sample Device Drivers."
  12183.  
  12184.  
  12185.  2.4  Installing Device Drivers
  12186.  
  12187.    MS-DOS allows new device drivers to be installed dynamically at boot time.
  12188.    This is accomplished by initialization code in the io.sys file that reads
  12189.    and processes the config.sys file.
  12190.  
  12191.    MS-DOS calls upon the device drivers to perform their function in the
  12192.    following manner:
  12193.  
  12194.    1. MS-DOS makes a FAR call to the strategy entry.
  12195.  
  12196.    2. MS-DOS passes device driver information in a request header to the
  12197.       strategy routine.
  12198.  
  12199.    3. MS-DOS makes a FAR call to the interrupt entry.
  12200.  
  12201.    This calling structure is designed to be easily upgraded to support any
  12202.    future multitasking environment.
  12203.  
  12204.  
  12205.  2.5  Device Headers
  12206.  
  12207.    A device header is required at the beginning of a device driver. A device
  12208.    header looks like this:
  12209.  
  12210.    ┌──────────────────────────────────────┐
  12211.    │ DWORD Pointer to next device         │
  12212.    │ (Usually set to -1 if this driver    │
  12213.    │ is the last or only driver in the    │
  12214.    │ file)                                │
  12215.    ├──────────────────────────────────────┤
  12216.    │ WORD Attributes                      │
  12217.    ├──────────────────────────────────────┤
  12218.    │ WORD Pointer to device strategy      │
  12219.    │      entry point                     │
  12220.    ├──────────────────────────────────────┤
  12221.    │ WORD Pointer to device interrupt     │
  12222.    │      entry point                     │
  12223.    ├──────────────────────────────────────┤
  12224.    │ 8-BYTE Character device name field   │
  12225.    │ Character devices set a device name. │
  12226.    │ For block devices the first byte is  │
  12227.    │ the number of units.                 │
  12228.    └──────────────────────────────────────┘
  12229.  
  12230.    Figure 2.1  Sample Device Header
  12231.  
  12232.    Notice that the device entry points are words. They must be offsets from
  12233.    the same segment number used to point to this table. For example, if
  12234.    xxx:yyy points to the start of this table, then xxx:strategy and
  12235.    xxx:interrupt are the entry points.
  12236.  
  12237.    The device header fields are described in the following section.
  12238.  
  12239.  2.5.1  Pointer to Next Device Field
  12240.  
  12241.    The pointer to the next device header field is a double-word field (offset
  12242.    followed by segment) that is set by MS-DOS to point at the next driver in
  12243.    the system list at the time the device driver is loaded. It is important
  12244.    that this field be set to -1 prior to load (when it is on the disk as a
  12245.    file) unless there is more than one device driver in the file. If there is
  12246.    more than one driver in the file, the first word of the double-word
  12247.    pointer should be the offset of the next driver's device header.
  12248.  
  12249.    ──────────────────────────────────────────────────────────────────────────
  12250.    Note
  12251.      If there is more than one device driver in the file, the last driver in
  12252.      the file must have the pointer to the next device header field set to
  12253.      -1.
  12254.    ──────────────────────────────────────────────────────────────────────────
  12255.  
  12256.  2.5.2  Attribute Field
  12257.  
  12258.    The attribute field is used to identify the type of device for which this
  12259.    driver is responsible. In addition to distinguishing between block and
  12260.    character devices, these bits are used to give selected character devices
  12261.    special treatment. (Notice that if a bit in the attribute word is defined
  12262.    only for one type of device, a driver for the other type of device must
  12263.    set that bit to 0.)
  12264.  
  12265.    Table 2.1
  12266.    For Character Devices:
  12267.    Bit        Value                Meaning
  12268.    ──────────────────────────────────────────────────────────────────────────
  12269.    0          1                    Device is console input (sti) device
  12270.    1          1                    Device is console output (sto) device
  12271.    2          1                    Device is nul device
  12272.    3          1                    Device is clock device
  12273.    4-5                             Reserved (must be 0)
  12274.    6          1                    Device supports 3.2 functions
  12275.    7-10                            Reserved (must be 0)
  12276.    11         1                    Device understands Open/Close
  12277.    12                              Reserved (must be 0)
  12278.    13         1                    Device supports Output Until Busy (OUB)
  12279.    14         1                    Device supports IOCtl control strings
  12280.    15         1                    Character device
  12281.    ──────────────────────────────────────────────────────────────────────────
  12282.  
  12283.    Table 2.2
  12284.    For Block Devices:
  12285.    Bit        Value                Meaning
  12286.    ──────────────────────────────────────────────────────────────────────────
  12287.    0                               Reserved (must be 0)
  12288.    1          1                    Device supports 32-bit sector addressing
  12289.    2-5                             Reserved (must be 0)
  12290.    6          1                    Device supports 3.2 functions and Generic
  12291.                                    IOCtl function calls
  12292.    7-10                            Reserved (must be 0)
  12293.    11         1                    Device understands Open/Close/Removable
  12294.                                    Media
  12295.    12                              Reserved (must be 0)
  12296.    13         1                    Device determines the media by examining
  12297.                                    the FATID byte
  12298.    14         1                    Device supports IOCtl control strings
  12299.    15         0                    Block device
  12300.    ──────────────────────────────────────────────────────────────────────────
  12301.  
  12302.    For example, assume that you have a new device driver that you want to use
  12303.    as the standard input and output. In addition to installing the driver,
  12304.    you must tell MS-DOS that you want the new driver to override the current
  12305.    standard input and standard output (the CON device). This is accomplished
  12306.    by setting the attributes to the desired characteristics, so you would set
  12307.    bits 0 and 1 to 1 (notice that they are separate). Similarly, a new CLOCK
  12308.    device could be installed by setting that attribute. (Refer to Section
  12309.    2.10, "The CLOCK Device," in this chapter for more information.) Although
  12310.    there is a NUL device attribute, the NUL device cannot be reassigned. This
  12311.    attribute exists so that MS-DOS can determine if the NUL device is being
  12312.    used.
  12313.  
  12314.    Bit 13 for block devices affects the operation of the Build BPB (BIOS
  12315.    Parameter Block) device call. If set, it requires the first sector of the
  12316.    FAT always to reside in the same place. This bit has a different meaning
  12317.    on character devices. It indicates that the device implements the Output
  12318.    Until Busy device call.
  12319.  
  12320.    The IOCtl bit (bit 14) has meaning on character and block devices. The
  12321.    IOCtl functions allow data to be sent and received by the device for its
  12322.    own use (to set baud rate, stop bits, form length, etc.) instead of
  12323.    passing data over the device channel as a normal read or write does. The
  12324.    interpretation of the passed information is up to the device but it must
  12325.    not be treated as normal I/O. This bit tells MS-DOS whether the device can
  12326.    handle control strings by using the IOCtl system call, Function 44H.
  12327.  
  12328.    If a driver cannot process control strings, it should initially set this
  12329.    bit to 0. This tells MS-DOS to return an error if an attempt is made (via
  12330.    Function 44H) to send or receive control strings to this device. A device
  12331.    which can process control strings should initialize the IOCtl bit to 1.
  12332.    For drivers of this type, MS-DOS will make calls to the IOCtl input and
  12333.    output device functions to send and receive IOCtl strings. The IOCtl
  12334.    functions allow data to be sent and received by the device for its own use
  12335.    (for example, to set baud rate, stop bits, and form length), instead of
  12336.    passing data over the device channel as does a normal read or write. The
  12337.    interpretation of the passed information is up to the device, but it must
  12338.    not be treated as a normal I/O request.
  12339.  
  12340.    The Open/Close/Removable Media bit (bit 11) signals to MS-DOS 3.x and
  12341.    later versions whether this driver supports additional MS-DOS 3.x
  12342.    functionality. To support these old drivers, it is necessary to detect
  12343.    them. This bit was reserved in MS-DOS 2.x, and is 0. All new devices
  12344.    should support the Open, Close, and Removable Media calls and set this bit
  12345.    to 1. Since MS-DOS 2.x never makes these calls, the driver will be
  12346.    backward-compatible.
  12347.  
  12348.    The MS-DOS 3.2 bit (bit 6) signals whether the device supports logical
  12349.    drive mapping via Function 440EH (Get Logical Drive Map) and Function
  12350.    440FH (Set Logical Drive Map). This bit also supports generic IOCtl
  12351.    functions via Function 440CH (Generic IOCtl for Handles) and Function
  12352.    440DH (Generic IOCtl for Block Devices).
  12353.  
  12354.    Bit 1 for block devices indicates the driver's ability to manipulate
  12355.    32-bit sector addresses. If bit 1 = 1, 32-bit sector addressing is
  12356.    supported. If bit 1 is set, the sector number field of all requests is a
  12357.    DWORD added to the end of the request header. The old WORD length sector
  12358.    number should be -1.
  12359.  
  12360.    The driver requests affected are:
  12361.  
  12362.    ■  BUILD BPD command 2
  12363.  
  12364.    ■  INPUT/OUTPUT command 3 ,4, 8, 9, and 12
  12365.  
  12366.    ■  GENERIC IOCTL command 19
  12367.  
  12368.    If bit 1 for block devices is 0, only 16-bit sector addressing is
  12369.    available.
  12370.  
  12371.      15  14  13  12  11  10  9   8   7   6   5   4   3   2   1   0
  12372.    ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
  12373.    │ C │ I │   │   │ O │   │   │   │   │ 3 │   │   │ C │ N │ S │ S │
  12374.    │ H │ O │   │   │ P │   │   │   │   │ . │   │   │ L │ U │ T │ T │
  12375.    │ R │ C │   │   │ N │   │   │   │   │ 2 │   │   │ K │ L │ O │ I │
  12376.    └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
  12377.  
  12378.    Figure 2.2  Attribute Word for Character Devices
  12379.  
  12380.  
  12381.  
  12382.      15  14  13  12  11  10  9   8   7   6   5   4   3   2   1   0
  12383.    ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
  12384.    │   │ I │ F │   │ O │   │   │   │   │ 3 │   │   │   │   │ > │   │
  12385.    │   │ O │ A │   │ P │   │   │   │   │ . │   │   │   │   │ 3 │   │
  12386.    │   │ C │ T │   │ N │   │   │   │   │ 2 │   │   │   │   │ 2 │   │
  12387.    └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
  12388.  
  12389.    Figure 2.3  Attribute Word for Block Devices
  12390.  
  12391.  2.5.3  Strategy and Interrupt Routines
  12392.  
  12393.    These two fields are the pointers to the entry points of the strategy and
  12394.    interrupt routines. They are word values, so they must be in the same
  12395.    segment as the device header.
  12396.  
  12397.  2.5.4  Name Field
  12398.  
  12399.    This is an eight-byte field that contains the name of a character device
  12400.    or the number of units of a block device. If the field refers to a block
  12401.    device, the number of units can be put in the first byte. This is
  12402.    optional, because MS-DOS will fill in this location with the value
  12403.    returned by the driver's Init code. For more information, see Section
  12404.    2.4, "Installing Device Drivers."
  12405.  
  12406.  
  12407.  2.6  Request Header
  12408.  
  12409.    When MS-DOS calls a device driver to perform a function, it passes a
  12410.    request header in ES:BX to the strategy entry point. This is a fixed
  12411.    length header, followed by data pertinent to the operation being
  12412.    performed. Notice that it is the device driver's responsibility to
  12413.    preserve the machine state (for example, save all registers, including
  12414.    flags, on entry, and restore them on exit). There is enough room on the
  12415.    stack when the strategy or interrupt routine is called to do about 20
  12416.    pushes. If more room on the stack is needed, the driver should set up its
  12417.    own stack.
  12418.  
  12419.    The following figure illustrates a request header.
  12420.  
  12421.    REQUEST HEADER ->
  12422.    ┌─────────────────────────────┐
  12423.    │ BYTE Length of record       │
  12424.    │  Length in bytes of this    │
  12425.    │  request header             │
  12426.    ├─────────────────────────────┤
  12427.    │ BYTE Unit code              │
  12428.    │  The subunit the operation  │
  12429.    │  is for (minor device)      │
  12430.    │  (no meaning on character   │
  12431.    │   devices)                  │
  12432.    ├─────────────────────────────┤
  12433.    │ BYTE Command code           │
  12434.    ├─────────────────────────────┤
  12435.    │ WORD Status                 │
  12436.    ├─────────────────────────────┤
  12437.    │ 8 BYTES Reserved            │
  12438.    │                             │
  12439.    └─────────────────────────────┘
  12440.  
  12441.    Figure 2.4  Request Header
  12442.  
  12443.    The request header fields are described below.
  12444.  
  12445.  2.6.1  Length of Record
  12446.  
  12447.    This field contains the length (in bytes) of the request header.
  12448.  
  12449.  2.6.2  Unit Code Field
  12450.  
  12451.    The unit code field identifies which unit in your device driver the
  12452.    request is for. For example, if your device driver has three units
  12453.    defined, then the possible values of the unit code field would be 0, 1,
  12454.    and 2.
  12455.  
  12456.  2.6.3  Command Code Field
  12457.  
  12458.    The command code field in the request header can have the following
  12459.    values:
  12460.  
  12461. ╓┌─┌──────────────────┌──────────────────────────────────────────────────────╖
  12462.    Code               Function
  12463.    ──────────────────────────────────────────────────────────────────────────
  12464.    0                  Init
  12465.    1                  Media Check (Block devices only)
  12466.    2                  Build BPB (Block devices only)
  12467.    3                  IOCtl Input (Only called if device has IOCtl)
  12468.    4                  Input (Read)
  12469.    5                  Non-destructive Read, No Wait (Character devices only)
  12470.    6                  Input Status (Character devices only)
  12471.    7                  Input Flush (Character devices only)
  12472.    8                  Output (Write)
  12473.    9                  Output (Write) with Verify
  12474.    10                 Output Status (Character devices only)
  12475.    11                 Output Flush (Character devices only)
  12476.    Code               Function
  12477.    ──────────────────────────────────────────────────────────────────────────
  12478.   11                 Output Flush (Character devices only)
  12479.    12                 IOCtl Output (Only called if device has IOCtl)
  12480.    13                 Device Open (Only called if Open/Close/Removable Media
  12481.                       bit set)
  12482.    14                 Device Close (Only called if Open/Close/Removable Media
  12483.                       bit set)
  12484.    15                 Removable Media (Only called if Open/Close/Removable
  12485.                       Media bit set and device is block)
  12486.    16                 Output Until Busy (Only called if bit 13 is set on
  12487.                       character devices)
  12488.    19                 Generic IOCtl Request
  12489.    23                 Get Logical Device
  12490.    24                 Set Logical Device
  12491.    ──────────────────────────────────────────────────────────────────────────
  12492.  
  12493.  
  12494.  2.6.4  Status Field
  12495.  
  12496.    The following figure illustrates the status field in the request header.
  12497.  
  12498.      15  14 13 12 11 10  9   8   7  6  5  4  3  2  1  0
  12499.    ┌───┬───────────────┬───┬───┬───────────────────────┐
  12500.    │ E │               │ B │ D │                       │
  12501.    │ R │   Reserved    │ U │ O │ Error code (bit 15 on)│
  12502.    │ R │               │ S │ N │                       │
  12503.    │   │               │ Y │ E │                       │
  12504.    └───┴───────────────┴───┴───┴───────────────────────┘
  12505.  
  12506.    Figure 2.5  Status Field
  12507.  
  12508.    The status word is zero on entry and is set by the driver interrupt
  12509.    routine on return.
  12510.  
  12511.    Bit 8 is the done bit. When set, it means the operation has completed. The
  12512.    driver sets it to 1 when it exits.
  12513.  
  12514.    Bit 15 is the error bit. If it is set, then the low eight bits indicate
  12515.    the error. The errors are as follows:
  12516.  
  12517.    Error              Meaning
  12518.    ──────────────────────────────────────────────────────────────────────────
  12519.    0                  Write protect violation
  12520.    1                  Unknown unit
  12521.    2                  Drive not ready
  12522.    3                  Unknown command
  12523.    4                  CRC error
  12524.    5                  Bad drive request structure length
  12525.    6                  Seek error
  12526.    7                  Unknown media
  12527.    8                  Sector not found
  12528.    9                  Printer out of paper
  12529.    ──────────────────────────────────────────────────────────────────────────
  12530.  
  12531.    Error              Meaning
  12532.    ──────────────────────────────────────────────────────────────────────────
  12533.    A                  Write fault
  12534.    B                  Read fault
  12535.    C                  General failure
  12536.    D                  Reserved
  12537.    E                  Reserved
  12538.    F                  Invalid disk change
  12539.    ──────────────────────────────────────────────────────────────────────────
  12540.  
  12541.    Bit 9 is the busy bit, which is set only by Status calls and the Removable
  12542.    Media call.
  12543.  
  12544.  
  12545.  2.7  Device Driver Functions
  12546.  
  12547.    Device drivers may perform all or some of these general functions. In some
  12548.    cases, these functions break down into several command codes, for specific
  12549.    cases. Each of the following general functions is described in this
  12550.    section.
  12551.  
  12552.    ■  Init
  12553.  
  12554.    ■  Media Check
  12555.  
  12556.    ■  Build BPB
  12557.  
  12558.    ■  Read, or Write, or Write Until Busy, or Write with Verify, or Read
  12559.       IOCtl, or Write IOCtl
  12560.  
  12561.    ■  Non-destructive Read, No Wait
  12562.  
  12563.    ■  Open or Close (3.x)
  12564.  
  12565.    ■  Removable Media (3.x)
  12566.  
  12567.    ■  Status
  12568.  
  12569.    ■  Flush
  12570.  
  12571.    ■  Generic IOCtl
  12572.  
  12573.    ■  Get or Set Logical Device
  12574.  
  12575.    All strategy routines are called with ES:BX pointing to the request
  12576.    header. The interrupt routines get the pointers to the request header from
  12577.    the queue that the strategy routines store them in. The command code in
  12578.    the request header tells the driver which function to perform and what
  12579.    data follows the request header.
  12580.  
  12581.    ──────────────────────────────────────────────────────────────────────────
  12582.    Note
  12583.      All DWORD pointers are stored offset first, then segment.
  12584.    ──────────────────────────────────────────────────────────────────────────
  12585.  
  12586.  2.7.1  The Init Function
  12587.  
  12588.    Command code = 0
  12589.  
  12590.    INIT - ES:BX ->
  12591.    ┌────────────────────────────────────┐
  12592.    │ 13-BYTE Request header             │
  12593.    ├────────────────────────────────────┤
  12594.    │ BYTE Number of units               │
  12595.    ├────────────────────────────────────┤
  12596.    │ DWORD End Address                  │
  12597.    ├────────────────────────────────────┤
  12598.    │ DWORD Pointer to BPB array         │
  12599.    │ (Not set by character devices)     │
  12600.    ├────────────────────────────────────┤
  12601.    │ BYTE Block device number           │
  12602.    └────────────────────────────────────┘
  12603.  
  12604.    One of the functions defined for each device driver is Init. This routine
  12605.    is called only once when the device is installed. The Init routine must
  12606.    return the end address, which is a DWORD pointer to the end of the portion
  12607.    of the device driver to remain resident. To save space, you can use this
  12608.    pointer method to delete initialization code that is needed only once.
  12609.  
  12610.    The number of units, end address, and BPB pointer are to be set by the
  12611.    driver. However, on entry for installable device drivers, the DWORD that
  12612.    is to be set by the driver to the BPB array (on block devices) points to
  12613.    the character after the "=" on the line in config.sys that caused this
  12614.    device driver to be loaded. This allows drivers to scan the config.sys
  12615.    invocation line for parameters that might be passed to the driver. This
  12616.    line is terminated by an ENTER or a linefeed character. This data is
  12617.    read-only and allows the device to scan the config.sys command line for
  12618.    arguments.
  12619.  
  12620.         device=\dev\vt52.sys /l
  12621.                │
  12622.                └─────BPB address points here
  12623.  
  12624.    Also, for block devices only, the drive number assigned to the first unit
  12625.    defined by this driver (A=0) is contained in the block device number
  12626.    field. This is also read-only.
  12627.  
  12628.    ──────────────────────────────────────────────────────────────────────────
  12629.    Note
  12630.      The Init routine can issue only Functions 01H-0CH, 25H, 30H, and
  12631.      35H.
  12632.    ──────────────────────────────────────────────────────────────────────────
  12633.  
  12634.    For installable character devices, the end address parameter must be
  12635.    returned. This is a pointer to the first available byte of memory above
  12636.    the driver and may be used to throw away initialization code.
  12637.  
  12638.    Block devices must return the following information:
  12639.  
  12640.    1. The number of units. MS-DOS uses this number to determine logical
  12641.       device names. If the current maximum logical device letter is F at the
  12642.       time of the install call, and the Init routine returns 4 as the number
  12643.       of units, then they will have logical names G, H, I, and J. This
  12644.       mapping is determined by the position of the driver in the device list,
  12645.       and by the number of units on the device (stored in the first byte of
  12646.       the device name field).
  12647.  
  12648.    2. A DWORD pointer to an array of word offsets (pointers) to BPBs (BIOS
  12649.       Parameter Blocks). The BPBs passed by the device driver are used by
  12650.       MS-DOS to create an internal structure. There must be one entry in this
  12651.       array for each unit defined by the device driver. In this way, if all
  12652.       units are the same, all the pointers can point to the same BPB, thereby
  12653.       saving space. If the device driver defines two units, then the DWORD
  12654.       pointer points to the first of two one-word offsets which in turn point
  12655.       to BPBs. The format of the BPB is described in Section 2.7.3, "The
  12656.       Build BPB Function."
  12657.  
  12658.       Notice that this array of word offsets must be protected (below the
  12659.       free pointer set by the return), since an internal DOS structure will
  12660.       be built starting at the byte pointed to by the free pointer. The
  12661.       defined sector size must be less than or equal to the maximum sector
  12662.       size defined by the resident device drivers (BIOS) during
  12663.       initialization. If it isn't, the installation will fail.
  12664.  
  12665.    3. The media descriptor byte. This byte means nothing to MS-DOS, but is
  12666.       passed to devices so that they know what parameters MS-DOS is currently
  12667.       using for a particular drive.
  12668.  
  12669.    ──────────────────────────────────────────────────────────────────────────
  12670.    Note
  12671.      If there are multiple device drivers in a single file, MS-DOS uses the
  12672.      ending address returned by the last Init function called. All device
  12673.      drivers in a single file should return the same ending address. All
  12674.      devices in a single file should be grouped together low in memory with
  12675.      the initialization code for all devices following it in memory.
  12676.    ──────────────────────────────────────────────────────────────────────────
  12677.  
  12678.  2.7.2  The Media Check Function
  12679.  
  12680.    Command Code = 1
  12681.  
  12682.    MEDIA CHECK - ES:BX ->
  12683.    ┌────────────────────────────────────┐
  12684.    │ 13-BYTE Request header             │
  12685.    ├────────────────────────────────────┤
  12686.    │ BYTE Media descriptor from BPB     │
  12687.    ├────────────────────────────────────┤
  12688.    │ BYTE Returned                      │
  12689.    │────────────────────────────────────┤
  12690.    │ Returned DWORD pointer to previous │
  12691.    │ Volume ID if bit 11 set and        │
  12692.    │ Disk Changed is returned           │
  12693.    └────────────────────────────────────┘
  12694.  
  12695.    The Media Check function is used only with block devices. It is called
  12696.    when there is a pending drive-access call other than a file read or write,
  12697.    such as Open, Close, delete, and rename. Its purpose is to determine
  12698.    whether the media in the drive has been changed. If the driver can assure
  12699.    that the media has not been changed (through a door-lock or other
  12700.    interlock mechanism), MS-DOS performance is enhanced, because MS-DOS does
  12701.    not need to reread the FAT and invalidate in-memory buffers for each
  12702.    directory access.
  12703.  
  12704.    When a disk-access call to the DOS occurs (other than a file read or
  12705.    write), the following sequence of events takes place:
  12706.  
  12707.    1. The DOS converts the drive letter into a unit number of a particular
  12708.       block device.
  12709.  
  12710.    2. The device driver is then called to request a media check on that
  12711.       subunit to see if the disk might have been changed. MS-DOS passes the
  12712.       old media descriptor byte. The driver returns one of the following:
  12713.  
  12714.       Return            Meaning
  12715.       ───────────────────────────────────────────────────────────────────────
  12716.       (1)               Media not changed
  12717.       (0)               Don't know if changed
  12718.       (-1)              Media changed
  12719.       value             Error (value is a standard error code value)
  12720.       ───────────────────────────────────────────────────────────────────────
  12721.  
  12722.       If the media has not been changed, MS-DOS proceeds with the disk
  12723.       access.
  12724.  
  12725.       If the value returned is -1, and there are any disk sectors that have
  12726.       been modified and not written back out to the disk for this unit,
  12727.       MS-DOS assumes that the disk has not been changed and proceeds. MS-DOS
  12728.       invalidates any other buffers for the unit and does a Build BPB call
  12729.       (see Step 3, following).
  12730.  
  12731.       If the media has been changed, MS-DOS invalidates all buffers
  12732.       associated with this unit including buffers with modified data that are
  12733.       waiting to be written, and requests a new BIOS Parameter Block via the
  12734.       Build BPB call (see Step 3).
  12735.  
  12736.    3. Once the BPB has been returned, MS-DOS corrects its internal structure
  12737.       for the drive from the new BPB and proceeds with the access after
  12738.       reading the directory and the FAT.
  12739.  
  12740.    Notice that the previous media ID byte is passed to the device driver. If
  12741.    the old media ID byte is the same as the new one, the disk might have been
  12742.    changed and a new disk may be in the drive; therefore, all FAT, directory,
  12743.    and data sectors that are buffered in memory for the drive are considered
  12744.    invalid.
  12745.  
  12746.    If the driver has bit 11 of the device attribute word set to 1, and the
  12747.    driver returns -1 (Media Changed), the driver must set the DWORD pointer
  12748.    to the previous Volume ID field. If the DOS determines that "Media
  12749.    changed" is an error based on the state of the DOS buffer cache, the DOS
  12750.    will generate a 0FH error on behalf of the device. If the driver does not
  12751.    implement volume ID support, but has bit 11 set, it should set a static
  12752.    pointer to the string "NO NAME" ,0. It is not possible for a user to
  12753.    change a disk in less than two seconds. So when Media Check occurs within
  12754.    two seconds of a disk access, the driver reports "Media not changed (1)."
  12755.    This improves performance tremendously.
  12756.  
  12757.    ──────────────────────────────────────────────────────────────────────────
  12758.    Note
  12759.      If the media ID byte in the returned BPB is the same as the previous
  12760.      media ID byte, MS-DOS will assume that the format of the disk is the
  12761.      same (even though the disk may have been changed) and will skip the step
  12762.      of updating its internal structure. Therefore, all BPBs must have unique
  12763.      media bytes regardless of FAT ID bytes.
  12764.    ──────────────────────────────────────────────────────────────────────────
  12765.  
  12766.  2.7.3  The Build BPB Function
  12767.  
  12768.    Command code = 2
  12769.  
  12770.    BUILD BPB - ES:BX ->
  12771.    ┌────────────────────────────────────┐
  12772.    │ 13-BYTE Request header             │
  12773.    ├────────────────────────────────────┤
  12774.    │ BYTE Media descriptor from BPB     │
  12775.    ├────────────────────────────────────┤
  12776.    │ DWORD Transfer address             │
  12777.    │ (Points to one sector worth of     │
  12778.    │  scratch space or first sector     │
  12779.    │  of FAT depending on the value     │
  12780.    │  of Bit 13 in the device attribute │
  12781.    │  word.)                            │
  12782.    ├────────────────────────────────────┤
  12783.    │ DWORD Pointer to BPB               │
  12784.    └────────────────────────────────────┘
  12785.  
  12786.    The Build BPB function is used with block devices only. As described in
  12787.    the Media Check function, the Build BPB function will be called any time
  12788.    that a preceding Media Check call indicates that the disk has been or
  12789.    might have been changed. The device driver must return a pointer to a BPB.
  12790.    This is different from the Init call where the device driver returns a
  12791.    pointer to an array of word offsets to BPBs. The Build BPB call gets a
  12792.    DWORD pointer to a one-sector buffer. The contents of this buffer are
  12793.    determined by the non-FAT ID bit (bit 13) in the attribute field. If the
  12794.    bit is zero, then the buffer contains the first sector of the first FAT.
  12795.    The FAT ID byte is the first byte of this buffer. In this case, the driver
  12796.    must not alter this buffer. Notice that the location of the FAT must be
  12797.    the same for all possible media because this first FAT sector must be read
  12798.    before the actual BPB is returned. If the non-FAT ID bit is set, the
  12799.    pointer points to one sector of scratch space (which may be used for
  12800.    anything). For information on how to construct the BPB, see Section 2.8,
  12801.    "The Media Descriptor Byte," and Section 2.9, "Format of a Media
  12802.    Descriptor Table."
  12803.  
  12804.    MS-DOS 4.0 includes additional support for devices that have door-locks or
  12805.    some other means of telling when a disk has been changed. There is an
  12806.    error that can be returned from the device driver (error 15). The error
  12807.    means "the disk has been changed when it shouldn't have been," and the
  12808.    user is prompted for the correct disk using a volume ID. The driver may
  12809.    generate this error on read or write. The DOS may generate the error on
  12810.    Media Check calls if the driver reports media changed and there are
  12811.    buffers in the DOS buffer cache that need to be flushed to the previous
  12812.    disk.
  12813.  
  12814.    For drivers that support this error, the Build BPB function is a trigger
  12815.    that causes a new volume ID to be read off the disk. This action indicates
  12816.    that the disk has been legally changed. A volume ID is placed on a disk by
  12817.    the format command and is simply an entry in the root directory of the
  12818.    disk that has the Volume ID attribute. It is stored by the driver as an
  12819.    ASCIZ string.
  12820.  
  12821.    The requirement that the driver return a volume ID does not exclude some
  12822.    other volume identifier scheme as long as the scheme uses ASCIZ strings. A
  12823.    NUL (nonexistent or unsupported) volume ID is by convention the following
  12824.    string:
  12825.  
  12826.    DB     "NO NAME     ",0
  12827.  
  12828.  2.7.4  The Read or Write Function
  12829.  
  12830.    Command codes = 3,4,8,9,12, and 16
  12831.  
  12832.    READ OR WRITE (Including IOCtl) or
  12833.       OUTPUT UNTIL BUSY - ES:BX ->
  12834.    ┌────────────────────────────────────┐
  12835.    │ 13-BYTE Request header             │
  12836.    ├────────────────────────────────────┤
  12837.    │ BYTE Media descriptor from BPB     │
  12838.    ├────────────────────────────────────┤
  12839.    │ DWORD Transfer address             │
  12840.    ├────────────────────────────────────┤
  12841.    │ WORD Byte/sector count             │
  12842.    ├────────────────────────────────────┤
  12843.    │ WORD Starting sector number        │
  12844.    │ or -1 if the drive supports        │
  12845.    │ greater than 16-bit sector         │
  12846.    │ addresses                          │
  12847.    │  (Ignored on character devices)    │
  12848.    ├────────────────────────────────────┤
  12849.    │ DWORD pointer to the Volume ID     │
  12850.    ├────────────────────────────────────┤
  12851.    │ Starting sector number             │
  12852.    │ (high-word first) if WORD starting │
  12853.    │ sector number is -1                │
  12854.    │ or                                 │
  12855.    │ Returned DWORD pointer to requested│
  12856.    │ Volume ID if error 0FH             │
  12857.    └────────────────────────────────────┘
  12858.  
  12859.    Code               Request
  12860.    ──────────────────────────────────────────────────────────────────────────
  12861.    3                  IOCtl read
  12862.    4                  Read (block or character device)
  12863.    8                  Write (block or character device)
  12864.    9                  Write with Verify
  12865.    12                 IOCtl Write
  12866.    16                 Output Until Busy (character device only)
  12867.    ──────────────────────────────────────────────────────────────────────────
  12868.  
  12869.    The driver must perform the Read or Write call depending on which command
  12870.    code is set. Block devices read or write sectors; character devices read
  12871.    or write bytes.
  12872.  
  12873.    When I/O completes, the device driver must set the status word and report
  12874.    the number of sectors or bytes successfully transferred. This should be
  12875.    done even if an error prevented the transfer from being completed. Setting
  12876.    the error bit and error code alone is not sufficient. In addition to
  12877.    setting the status word, the driver must set the sector count to the
  12878.    actual number of sectors (or bytes) transferred. No error check is
  12879.    performed on an IOCtl I/O call. The device driver must always set the
  12880.    return byte/sector count to the actual number of bytes/sectors
  12881.    successfully transferred.
  12882.  
  12883.    If the verify switch is on, the device driver will be called with command
  12884.    code 9 (Write with Verify). Your device driver will be responsible for
  12885.    verifying the write.
  12886.  
  12887.    If the driver returns error code 0FH (Invalid disk change), it must return
  12888.    a DWORD pointer to an ASCIZ string (which is the correct volume ID).
  12889.    Returning this error code triggers the DOS to prompt the user to re-insert
  12890.    the disk. The device driver should have read the volume ID as a result of
  12891.    the Build BPB function.
  12892.  
  12893.    Drivers may maintain a reference count of open files on the disk by
  12894.    monitoring the Open and Close functions. This allows the driver to
  12895.    determine when to return error 0FH. If there are no open files (reference
  12896.    count = 0), and the disk has been changed, the I/O is okay. If there are
  12897.    open files, however, an 0FH error may exist.
  12898.  
  12899.    The Output Until Busy call is a speed optimization on character devices
  12900.    only for print spoolers. The device driver is expected to output all the
  12901.    characters possible until the device returns busy. Under no circumstances
  12902.    should the device driver block during this function. Notice that it is not
  12903.    an error for the device driver to return the number of bytes output as
  12904.    being less than the number of bytes requested (or = 0).
  12905.  
  12906.    The Output Until Busy call allows spooler programs to take advantage of
  12907.    the "burst" behavior of most printers. Many printers have on-board RAM
  12908.    buffers that typically hold a line or a fixed amount of characters. These
  12909.    buffers fill up without the printer going busy, or going busy for a short
  12910.    period (less than ten instructions) between characters. A line of
  12911.    characters can be output quickly to the printer, after which the printer
  12912.    is busy for a long time while the characters are being printed. This new
  12913.    device call allows background spooling programs to use this burst behavior
  12914.    efficiently. Rather than take the overhead of a device driver call for
  12915.    each character, or risk getting stuck in the device driver outputting a
  12916.    block of characters, this call allows a burst of characters to be output
  12917.    without the device driver having to wait for the device to be ready.
  12918.  
  12919.    The Following Applies to Block Device Drivers:
  12920.  
  12921.    Under certain circumstances, the BIOS may be asked to perform a write
  12922.    operation of 64 kilobytes, which seems to be a "wrap-around" of the
  12923.    transfer address in the BIOS I/O packet. This request, which arises due to
  12924.    an optimization added to the write code in MS-DOS, will manifest itself
  12925.    only on user writes that are within a sector size of 64 kilobytes on files
  12926.    "growing" past the current end-of-file (EOF) mark. It is allowable for the
  12927.    BIOS to ignore the balance of the write that "wraps around" if it so
  12928.    chooses. For example, a write of 10000H bytes-worth of sectors with a
  12929.    transfer address of xxx:1 could ignore the last two bytes. A user program
  12930.    can never request an I/O of more than FFFFH bytes and cannot wrap around
  12931.    (even to 0) in the transfer segment. Therefore, in this case, the last two
  12932.    bytes can be ignored.
  12933.  
  12934.    MS-DOS maintains two FATs. If the DOS has problems reading the first, it
  12935.    automatically tries the second before reporting the error. The BIOS is
  12936.    responsible for all retries.
  12937.  
  12938.    Although the command.com handler does no automatic retries, there are
  12939.    applications that have their own Interrupt 24H handlers that do automatic
  12940.    retries on certain types of Interrupt 24H errors before reporting them.
  12941.  
  12942.  2.7.5  The Non-destructive Read, No Wait Function
  12943.  
  12944.    Command code = 5
  12945.  
  12946.    NON-DESTRUCTIVE READ NO WAIT - ES:BX ->
  12947.    ┌────────────────────────────────────┐
  12948.    │ 13-BYTE Request header             │
  12949.    ├────────────────────────────────────┤
  12950.    │ BYTE Read from device              │
  12951.    └────────────────────────────────────┘
  12952.  
  12953.    The Non-destructive Read, No Wait function allows MS-DOS to look ahead one
  12954.    input character. The device sets the done bit in the status word.
  12955.  
  12956.    If the character device returns busy bit = 0 (there are characters in the
  12957.    buffer), then the next character that would be read is returned. This
  12958.    character is not removed from the input buffer (hence the term
  12959.    "Non-destructive Read"). If the character device returns busy bit = 1,
  12960.    there are no characters in the buffer.
  12961.  
  12962.  2.7.6  The Open or Close Function
  12963.  
  12964.    Command codes = 13 and 14
  12965.  
  12966.    OPEN or CLOSE  - ES:BX ->
  12967.    ┌────────────────────────────────────┐
  12968.    │ 13-BYTE Static request header      │
  12969.    └────────────────────────────────────┘
  12970.  
  12971.    The Open and Close functions are called by MS-DOS only if the device
  12972.    driver sets the Open/Close/Removable Media attribute bit in the device
  12973.    header. They are designed to inform the device about current file activity
  12974.    on the device. On block devices, they can be used to manage local
  12975.    buffering. The device can keep a reference count. Every Open causes the
  12976.    device to increment the count, every Close to decrement. When the count
  12977.    goes to zero, it means there are no open files on the device. Therefore,
  12978.    the device should flush any buffers that have been written to that may
  12979.    have been used inside the device, because it is now "legal" for the user
  12980.    to change the media on a removable media drive.
  12981.  
  12982.    There are problems with this mechanism on block devices because programs
  12983.    that use FCB calls can open files without closing them. It is, therefore,
  12984.    advisable to reset the count to zero without flushing the buffers when the
  12985.    answer to "Has the media been changed?" is yes, and the Build BPB call is
  12986.    made to the device.
  12987.  
  12988.    These calls are more useful on character devices. The Open call, for
  12989.    instance, can be used to send a device initialization string. On a
  12990.    printer, this could cause a string for setting font and page size
  12991.    characteristics to be sent to the printer so that it would always be in a
  12992.    known state at the start of an I/O stream. Using IOCtl to set these pre-
  12993.    and post- strings provides a flexible mechanism of serial I/O device
  12994.    stream control. The reference count mechanism can also be used to detect a
  12995.    simultaneous access error. It may be desirable to disallow more than one
  12996.    Open on a device at any given time. In this case, a second Open would
  12997.    result in an error.
  12998.  
  12999.    Notice that since all processes have access to stdin, stdout, stderr,
  13000.    stdaux, and stdprn (handles 0,1,2,3,4), the CON, AUX, and PRN devices are
  13001.    always open.
  13002.  
  13003.  2.7.7  The Removable Media Function
  13004.  
  13005.    Command code = 15
  13006.  
  13007.    REMOVABLE MEDIA - ES:BX ->
  13008.    ┌────────────────────────────────────┐
  13009.    │ 13-BYTE Static request header      │
  13010.    └────────────────────────────────────┘
  13011.  
  13012.    The Removable Media function is called by MS-DOS only if the device driver
  13013.    sets the Open/Close/Removable Media attribute bit in the device header.
  13014.    This call is given only to block devices by a subfunction of the IOCtl
  13015.    system call. It is sometimes desirable for a utility to know whether it is
  13016.    dealing with a nonremovable media drive (such as a hard disk), or a
  13017.    removable media drive (like a floppy). An example is the format command,
  13018.    which prints different versions of some of the prompts.
  13019.  
  13020.    The information is returned in the busy bit of the status word. If the
  13021.    busy bit is 1, then the media is nonremovable. If the busy bit is 0, then
  13022.    the media is removable. Notice that the error bit is not checked. It is
  13023.    assumed that this call always succeeds.
  13024.  
  13025.  2.7.8  The Status Function
  13026.  
  13027.    Command codes = 6 and 10
  13028.  
  13029.    STATUS Calls ES:BX ->
  13030.    ┌────────────────────────────────────┐
  13031.    │ 13-BYTE Request header             │
  13032.    └────────────────────────────────────┘
  13033.  
  13034.    The Status function returns information to the DOS as to whether data is
  13035.    waiting for input or output. All the driver must do is set the status word
  13036.    and the busy bit as follows:
  13037.  
  13038.    ■  For output on character devices ── if the driver sets bit 9 to 1 on
  13039.       return, it informs the DOS that a write request (if made) would wait
  13040.       for completion of a current request. If it is 0, there is no current
  13041.       request, and a write request (if made) would start immediately.
  13042.  
  13043.    ■  For input on character devices with a buffer ── A return of 1 implies
  13044.       that no characters are buffered and that a read request (if made) would
  13045.       go to the physical device. If it is 0 on return, then there are
  13046.       characters in the device buffer and a read would not be blocked. A
  13047.       return of 0 implies that the user has typed something. MS-DOS assumes
  13048.       that all character devices have an input type-ahead buffer.
  13049.  
  13050.    Devices that do not have a type-ahead buffer should always return busy = 0
  13051.    so that the DOS will not "hang" waiting for something to get into a
  13052.    non-existent buffer.
  13053.  
  13054.  2.7.9  The Flush Function
  13055.  
  13056.    Command codes = 7 and 11
  13057.  
  13058.    FLUSH Calls - ES:BX ->
  13059.    ┌────────────────────────────────────┐
  13060.    │ 13-BYTE Request header             │
  13061.    └────────────────────────────────────┘
  13062.  
  13063.    The Flush function tells the driver to flush (terminate) all pending
  13064.    requests. This call is used to flush the input queue on character devices.
  13065.  
  13066.    The device driver performs the flush function, sets the status word, and
  13067.    returns.
  13068.  
  13069.  2.7.10  The Generic IOCtl Function
  13070.  
  13071.    Command code = 19
  13072.  
  13073.    ES:BX ->
  13074.    ┌────────────────────────────────────┐
  13075.    │ 13-BYTE Static request header      │
  13076.    ├────────────────────────────────────┤
  13077.    │ BYTE Category (Major) code         │
  13078.    ├────────────────────────────────────┤
  13079.    │ BYTE Function (Minor) code         │
  13080.    ├────────────────────────────────────┤
  13081.    │ WORD (SI) Contents                 │
  13082.    ├────────────────────────────────────┤
  13083.    │ WORD (DI) Contents                 │
  13084.    ├────────────────────────────────────┤
  13085.    │ DWORD Pointer to data buffer       │
  13086.    └────────────────────────────────────┘
  13087.  
  13088.    The Generic IOCtl function provides a generic, expandable IOCtl facility
  13089.    that replaces and makes the Read IOCtl and Write IOCtl device driver
  13090.    functions obsolete. The MS-DOS 2.0 IOCtl functions remain to support
  13091.    existing uses of the IOCtl system call (Subfunctions 2, 3, 4, and 5), but
  13092.    new device drivers should use this generic MS-DOS IOCtl facility. The
  13093.    Generic IOCtl function contains both a category and function code. The DOS
  13094.    examines the category field in order to intercept and obey device commands
  13095.    that are actually serviced by the DOS code; all other command categories
  13096.    are forwarded to the device driver for servicing.
  13097.  
  13098.    For more information on these category and function codes, refer to
  13099.    Function 440CH (Generic IOCtl for Handles) and Function 440DH (Generic
  13100.    IOCtl for Block Devices) in Chapter 1, "System Calls."
  13101.  
  13102.  2.7.11  The Get/Set Logical Drive Map Function
  13103.  
  13104.    Command codes = 23 (Get) or 24 (Set)
  13105.  
  13106.    ┌────────────────────────────────────────┐
  13107.    │ 13-BYTE Static request header          │
  13108.    ├────────────────────────────────────────┤
  13109.    │ BYTE    Input (unit code)              │
  13110.    ├────────────────────────────────────────┤
  13111.    │ BYTE    Output (last device referenced)│
  13112.    ├────────────────────────────────────────┤
  13113.    │ BYTE    Command code                   │
  13114.    ├────────────────────────────────────────┤
  13115.    │ WORD    Status                         │
  13116.    ├────────────────────────────────────────┤
  13117.    │ DWORD   Reserved                       │
  13118.    └────────────────────────────────────────┘
  13119.  
  13120.    The Get/Set Logical Drive Map function is called by MS-DOS only if the
  13121.    device driver sets the DOS 3.2 attribute bit in the device header. The
  13122.    call is issued only to block devices by the subfunction of the IOCtl
  13123.    system call. The logical drive to be mapped is passed in the Unit field of
  13124.    the header to the device driver. The device driver returns the current
  13125.    logical drive owner of the physical device that maps to the requested
  13126.    physical drive. To detect whether or not a logical device currently owns
  13127.    the physical device to which it is mapped, a program needs to verify that,
  13128.    after a call of Function 440EH or 440FH (Get/Set Logical Drive Map), the
  13129.    value of the Unit field is unchanged.
  13130.  
  13131.  
  13132.  2.8  The Media Descriptor Byte
  13133.  
  13134.    In MS-DOS, the media descriptor byte is used to inform the DOS that a
  13135.    different type of media is present. The media descriptor byte can be any
  13136.    value between 0 and FFH. It does not have to be the same as the FAT ID
  13137.    byte. The FAT ID byte, which is the first byte of the FAT, was used in
  13138.    MS-DOS 1.00 to distinguish between different types of disk media, and may
  13139.    be used as well under 2.x and 3.x disk device drivers. However, FAT ID
  13140.    bytes have significance only for block device drivers where the non-FAT ID
  13141.    bit is not set (0).
  13142.  
  13143.    Values of the media descriptor byte or the FAT ID byte have no
  13144.    significance to MS-DOS. They are passed to the device driver so that
  13145.    programs can determine the media type.
  13146.  
  13147.  
  13148.  2.9  Format of a Media Descriptor Table
  13149.  
  13150.    The MS-DOS file system uses a linked list of pointers (one for each
  13151.    cluster or allocation unit) called the File Allocation Table (FAT). Unused
  13152.    clusters are represented by zero and end-of-file by FFFH (or FFFFH on
  13153.    units with 16-bit FAT entries). No valid entry should ever point to a zero
  13154.    entry, but if one does, the first FAT entry (which would be pointed to by
  13155.    a zero entry) was reserved and set to end of chain. Eventually, several
  13156.    end of chain values were defined ([F]FF8H[F]FFFH), and these were used to
  13157.    distinguish different types of media.
  13158.  
  13159.    A preferable technique is to write a complete media descriptor table in
  13160.    the boot sector and use it for media identification. To ensure backward
  13161.    compatibility for systems whose drivers do not set the non-FAT ID bit
  13162.    (including the IBM PC implementation), it is also necessary to write the
  13163.    FAT ID bytes during the format process.
  13164.  
  13165.    To allow more flexibility for supporting many different disk formats in
  13166.    the future, it is recommended that the information relating to the BPB for
  13167.    a particular piece of media be kept in the boot sector. Figure 2.6 shows
  13168.    the format of such a boot sector.
  13169.  
  13170.       ┌────────────────────────────────────┐
  13171.       │ 3 BYTE Near JUMP to boot code      │
  13172.       ├────────────────────────────────────┤
  13173.       │ 8 BYTES OEM name and version       │
  13174.       ├────────────────────────────────────┤
  13175.    B  │ WORD Bytes per sector              │
  13176.    P  ├────────────────────────────────────┤
  13177.    B  │ BYTE Sectors per allocation unit   │
  13178.       ├────────────────────────────────────┤
  13179.      │ WORD Reserved sectors              │
  13180.       ├────────────────────────────────────┤
  13181.       │ BYTE Number of FATs                │
  13182.       ├────────────────────────────────────┤
  13183.       │ WORD Number of root dir entries    │
  13184.       ├────────────────────────────────────┤
  13185.       │ WORD Number of sectors in logical  │
  13186.      │ | image or 0                       │
  13187.       ├────────────────────────────────────┤
  13188.    B  │ BYTE Media descriptor              │
  13189.    P  ├────────────────────────────────────┤
  13190.    B  │ WORD Number of FAT sectors         │
  13191.       ├────────────────────────────────────┤
  13192.       │ WORD Sectors per track             │
  13193.       ├────────────────────────────────────┤
  13194.       │ WORD Number of heads               │
  13195.       ├────────────────────────────────────┤
  13196.       │ WORD Number of hidden sectors      │
  13197.       ├────────────────────────────────────┤
  13198.       │ WORD High order number of hidden   │
  13199.       │ sectors                            │
  13200.       ├────────────────────────────────────┤
  13201.       │ DWORD Number of logical sectors    │
  13202.       └────────────────────────────────────┘
  13203.  
  13204.    Figure 2.6  Format of a Boot Sector
  13205.  
  13206.    Although MS-DOS does not use the five fields that follow the BPB, these
  13207.    fields may be used by a device driver to help it understand the media.
  13208.  
  13209.    The "Sectors per track" and "Number of heads" fields are useful for
  13210.    supporting different media that may have the same logical layout, but a
  13211.    different physical layout (for example, 40-track, double-sided versus
  13212.    80-track, single-sided). "Sectors per track" tells the device driver how
  13213.    the logical disk format is laid out on the physical disk. The "Number of
  13214.    hidden sectors" and "High order number of hidden sectors" fields may be
  13215.    used to support drive-partitioning schemes.
  13216.  
  13217.    The "Number of logical sectors" field tells the device driver how many
  13218.    sectors to reserve if the "Number of sectors in logical image" field is
  13219.    zero. (Notice that this is intended for supporting devices that access
  13220.    more than 32 megabytes.)
  13221.  
  13222.    The following procedure is recommended for media determination by NON FAT
  13223.    ID format drivers:
  13224.  
  13225.    1. Read the boot sector of the drive into the one-sector scratch space
  13226.       pointed to by the DWORD transfer address.
  13227.  
  13228.    2. Determine if the first byte of the boot sector is an E9H or EBIT (the
  13229.       first byte of a 3-byte NEAR or 2-byte SHORT jump) or an EBH (the first
  13230.       byte of a 2-byte jump followed by an NOP). If so, a BPB is located
  13231.       beginning at offset 3. Return a pointer to it.
  13232.  
  13233.    3. If the boot sector does not have a BPB table, it is probably a disk
  13234.       formatted under a 1.x version of MS-DOS and probably uses a FAT ID byte
  13235.       for determining media.
  13236.  
  13237.       The driver may optionally attempt to read the first sector of the FAT
  13238.       into the one-sector scratch area and read the first byte to determine
  13239.       media type based upon whatever FAT ID bytes may have been used on disks
  13240.       that are expected to be read by this system. Return a pointer to a
  13241.       hard-coded BPB.
  13242.  
  13243.  
  13244.  2.10  The CLOCK Device
  13245.  
  13246.    MS-DOS assumes that some sort of clock is available in the system. This
  13247.    may either be a CMOS real-time clock or an interval timer that is
  13248.    initialized at boot time by the user. The CLOCK device defines and
  13249.    performs functions like any other character device, except that it is
  13250.    identified by a bit in the attribute word. The DOS uses this bit to
  13251.    identify it; consequently, the CLOCK device may take any name. The IBM
  13252.    implementation uses the name $CLOCK so as not to conflict with existing
  13253.    files named clock.
  13254.  
  13255.    The CLOCK device is unique in that MS-DOS will read or write a 6-byte
  13256.    sequence that encodes the date and time. A write to this device will set
  13257.    the date and time; a read will get the date and time. Figure 2.7
  13258.    illustrates the binary time format used by the CLOCK device:
  13259.  
  13260.      byte 0   byte 1   byte 2    byte 3   byte 4   byte 5
  13261.    ┌────────┬────────┬─────────┬────────┬────────┬─────────┐
  13262.    │        │        │         │        │        │         │
  13263.    │days since 1-1-80│ minutes │  hours │ sec/100│ seconds │
  13264.    │low byte|hi byte │         │        │        │         │
  13265.    └─────────────────┴─────────┴────────┴────────┴─────────┘
  13266.  
  13267.    Figure 2.7  Format of a Clock Device
  13268.  
  13269.  
  13270.  2.11  Anatomy of a Device Call
  13271.  
  13272.    The following steps illustrate what happens when MS-DOS calls on a block
  13273.    device driver to perform a Write request:
  13274.  
  13275.    1. MS-DOS writes a request packet in a reserved area of memory.
  13276.  
  13277.    2. MS-DOS calls the strategy entry point of the block device driver.
  13278.  
  13279.    3. The device driver saves the ES and BX registers (ES:BX points to the
  13280.       request packet) and does a FAR return.
  13281.  
  13282.    4. MS-DOS calls the interrupt entry point.
  13283.  
  13284.    5. The device driver retrieves the pointer to the request packet and reads
  13285.       the command code (offset 2) to determine that this is a Write request.
  13286.       The device driver converts the command code to an index into a dispatch
  13287.       table and control passes to the Write routine.
  13288.  
  13289.    6. The device driver reads the unit code (offset 1) to determine which
  13290.       disk drive it is supposed to write to.
  13291.  
  13292.    7. Since the command is a disk Write, the device driver must get the
  13293.       transfer address (offset 14), the sector count (offset 18), and the
  13294.       start sector (offset 20) in the request packet.
  13295.  
  13296.    8. The device driver translates the first logical sector number into a
  13297.       track, head, and sector number.
  13298.  
  13299.    9. The device driver writes the specified number of sectors, starting at
  13300.       the beginning sector on the drive defined by the unit code (the subunit
  13301.       defined by this device driver), and transfers data from the transfer
  13302.       address indicated in the request packet. Notice that this may involve
  13303.       multiple Write commands to the disk controller.
  13304.  
  13305.    10.After the transfer is complete, the device driver must report the
  13306.       status of the request to MS-DOS by setting the done bit in the status
  13307.       word (offset 3 in the request packet). It reports the number of sectors
  13308.       actually transferred in the sector count area of the request packet.
  13309.  
  13310.    11.If an error occurs, the driver sets the done bit and the error bit in
  13311.       the status word and fills in the error code in the lower half of the
  13312.       status word. The number of sectors actually transferred must be written
  13313.       in the request header. It is not sufficient just to set the error bit
  13314.       of the status word.
  13315.  
  13316.    12.The device driver does a FAR return to MS-DOS.
  13317.  
  13318.    The device drivers should preserve the state of MS-DOS. This means that
  13319.    all registers (including flags) should be preserved. The direction flag
  13320.    and interrupt enable bits are critical. When the interrupt entry point in
  13321.    the device driver is called, MS-DOS has room for about 40 to 50 bytes on
  13322.    its internal stack. Your device driver should switch to a local stack if
  13323.    it uses extensive stack operations.
  13324.  
  13325.  
  13326.  2.12  Two Sample Device Drivers
  13327.  
  13328.    The following two examples illustrate a block device driver program and a
  13329.    character device driver program. These examples are provided as guides for
  13330.    writing your own device drivers. However, since device drivers are
  13331.    hardware-dependent, your device drivers will differ.
  13332.  
  13333.    Block Device Driver
  13334.  
  13335.  
  13336.  
  13337.    ; ********************* A Block Device *******************
  13338.  
  13339.            Title   5.25-inch Disk Driver
  13340.  
  13341.    ; This driver is intended to drive up to four 5.25-inch
  13342.    ; drives hooked to a single disk controller. All standard
  13343.    ; IBM PC formats are supported.
  13344.  
  13345.  
  13346.    FALSE   EQU     0
  13347.    TRUE    EQU     NOT FALSE
  13348.  
  13349.  
  13350.  
  13351.  
  13352.    ; The I/O port address of the disk controller
  13353.    DISK    EQU     0E0H
  13354.    ; DISK+0
  13355.    ;        1793    Command/Status
  13356.    ; DISK+1
  13357.    ;        1793    Track
  13358.    ; DISK+2
  13359.    ;        1793    Sector
  13360.    ; DISK+3
  13361.    ;        1793    Data
  13362.    ; DISK+4
  13363.    ;        Aux Command/Status
  13364.    ; DISK+5
  13365.    ;        Wait Sync
  13366.  
  13367.    ; Back side select bit
  13368.    BACKBIT EQU     04H
  13369.    ; 5 1/4" select bit
  13370.    SMALBIT EQU     10H
  13371.    ; Double Density bit
  13372.    DDBIT   EQU     08H
  13373.  
  13374.    ; Done bit in status register
  13375.    DONEBIT EQU     01H
  13376.  
  13377.    ; Use table below to select head step speed.
  13378.    ; Step times for 5" drives
  13379.    ; are double that shown in the ; Step value    1771    1793
  13380.    ;
  13381.    ;     0          6ms     3ms
  13382.    ;     1          6ms     6ms
  13383.    ;     2         10ms    10ms
  13384.    ;     3         20ms    15ms
  13385.    ;
  13386.    STPSPD  EQU     1
  13387.  
  13388.    NUMERR  EQU     ERROUT-ERRIN
  13389.  
  13390.    CR      EQU     0DH
  13391.    LF      EQU     0AH
  13392.  
  13393.    CODE    SEGMENT
  13394.    ASSUME  CS:CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING
  13395.    ; -----------------------------------------------------
  13396.    ;
  13397.    ;        Device Header
  13398.    ;
  13399.    DRVDEV  LABEL   WORD
  13400.            DW      -1,-1
  13401.            DW      0000     ; IBM format-compatible, Block
  13402.            DW      STRATEGY
  13403.            DW      DRV$IN
  13404.    DRVMAX  DB      4
  13405.  
  13406.    DRVTBL  LABEL   WORD
  13407.            DW      DRV$INIT
  13408.            DW      MEDIA$CHK
  13409.            DW      GET$BPB
  13410.            DW      CMDERR
  13411.            DW      DRV$READ
  13412.            DW      EXIT
  13413.            DW      EXIT
  13414.            DW      EXIT
  13415.            DW      DRV$WRIT
  13416.            DW      DRV$WRIT
  13417.            DW      EXIT
  13418.            DW      EXIT
  13419.            DW      EXIT
  13420.  
  13421.    ; ------------------------------------
  13422.    ;
  13423.    ;        Strategy
  13424.  
  13425.    PTRSAV  DD      0
  13426.  
  13427.    STRATP  PROC    FAR
  13428.    STRATEGY:
  13429.            MOV     WORD PTR [PTRSAV],BX
  13430.            MOV     WORD PTR [PTRSAV+2],ES
  13431.            RET
  13432.    STRATP  ENDP
  13433.  
  13434.    ; --------------------------------------
  13435.    ;
  13436.    ;        Main Entry
  13437.  
  13438.  
  13439.    CMDLEN  =       0       ; Length of this command
  13440.    UNIT    =       1       ; Subunit specified
  13441.    CMDC    =       2       ; Command Code
  13442.    STATUS  =       3       ; Status
  13443.    MEDIA   =       13      ; Media Descriptor
  13444.    TRANS   =       14      ; Transfer Address
  13445.    COUNT   =       18      ; Count of blocks or characters
  13446.    START   =       20      ; First block to transfer
  13447.  
  13448.    DRV$IN:
  13449.            PUSH    SI
  13450.            PUSH    AX
  13451.            PUSH    CX
  13452.            PUSH    DX
  13453.            PUSH    DI
  13454.            PUSH    BP
  13455.            PUSH    DS
  13456.            PUSH    ES
  13457.            PUSH    BX
  13458.  
  13459.            LDS     BX,[PTRSAV]     ; Get pointer to I/O packet
  13460.  
  13461.            MOV     AL,BYTE PTR [BX].UNIT   ; AL = Unit Code
  13462.            MOV     AH,BYTE PTR [BX].MEDIA  ; AH = Media Descrip
  13463.            MOV     CX,WORD PTR [BX].COUNT  ; CX = Count
  13464.            MOV     DX,WORD PTR [BX].START  ; DX = Start Sector
  13465.            PUSH    AX
  13466.            MOV     AL,BYTE PTR [BX].CMDC   ; Command code
  13467.            CMP     AL,15
  13468.            JA      CMDERRP                 ; Bad command
  13469.            CBW
  13470.            SHL     AX,1                    ; 2 times command =
  13471.                                            ; word table index
  13472.            MOV     SI,OFFSET DRVTBL
  13473.            ADD     SI,AX                   ; Index into table
  13474.            POP     AX                      ; Get back media
  13475.                                            ; and unit
  13476.  
  13477.            LES     DI,DWORD PTR [BX].TRANS ; ES:DI = Transfer
  13478.                                            ; Address
  13479.  
  13480.            PUSH    CS
  13481.            POP     DS
  13482.  
  13483.    ASSUME  DS:CODE
  13484.  
  13485.            JMP     WORD PTR [SI]             ; GO DO COMMAND
  13486.  
  13487.    ; ----------------------------------------------------------
  13488.    ;
  13489.    ;        EXIT - All Routines return through this path
  13490.    ;
  13491.    ASSUME  DS:NOTHING
  13492.    CMDERRP:
  13493.            POP     AX                    ; Clean stack
  13494.    CMDERR:
  13495.            MOV     AL,3                  ; Unknown command error
  13496.            JMP     SHORT ERR$EXIT
  13497.  
  13498.    ERR$CNT:LDS     BX,[PTRSAV]
  13499.            SUB     WORD PTR [BX].COUNT,CX ; # OF SUCCESS. I/Os
  13500.  
  13501.    ERR$EXIT:
  13502.    ; AL has error code
  13503.            MOV     AH,10000001B            ; Mark error return
  13504.            JMP     SHORT ERR1
  13505.  
  13506.    EXITP   PROC    FAR
  13507.  
  13508.    EXIT:   MOV     AH,00000001B
  13509.    ERR1:   LDS     BX,[PTRSAV]
  13510.            MOV     WORD PTR [BX].STATUS,AX
  13511.                                        ; Mark Operation
  13512.    CompleteE
  13513.  
  13514.            POP     BX
  13515.            POP     ES
  13516.            POP     DS
  13517.            POP     BP
  13518.            POP     DI
  13519.            POP     DX
  13520.            POP     CX
  13521.            POP     AX
  13522.            POP     SI
  13523.            RET                         ; Restore REGS and return
  13524.    EXITP   ENDP
  13525.  
  13526.    CURDRV  DB      -1
  13527.  
  13528.    TRKTAB  DB      -1,-1,-1,-1
  13529.  
  13530.    SECCNT  DW      0
  13531.  
  13532.    DRVLIM  =       8       ; Number of sectors on device
  13533.    SECLIM  =       13      ; Maximum Sector
  13534.    HDLIM   =       15      ; Maximum Head
  13535.  
  13536.    ; WARNING - preserve order of drive and curhd!
  13537.  
  13538.    DRIVE   DB      0       ; Physical Drive Code
  13539.    CURHD   DB      0       ; Current Head
  13540.    CURSEC  DB      0       ; Current Sector
  13541.    CURTRK  DW      0       ; Current Track
  13542.  
  13543.  
  13544.    ;
  13545.    MEDIA$CHK:              ; Always indicates Don't know
  13546.    ASSUME  DS:CODE
  13547.            TEST    AH,00000100B       ; Test if Media Removable
  13548.            JZ      MEDIA$EXT
  13549.            XOR     DI,DI              ; Say I Don't know
  13550.    MEDIA$EXT:
  13551.            LDS     BX,[PTRSAV]
  13552.            MOV     WORD PTR [BX].TRANS,DI
  13553.            JMP     EXIT
  13554.  
  13555.    BUILD$BPB:
  13556.    ASSUME  DS:CODE
  13557.            MOV     AH,BYTE PTR ES:[DI]       ; Get FAT ID Byte
  13558.            CALL    BUILDBP                   ; Translate
  13559.    SETBPB: LDS     BX,[PTRSAV]
  13560.            MOV     [BX].MEDIA,AH
  13561.            MOV     [BX].COUNT,DI
  13562.            MOV     [BX].COUNT+2,CS
  13563.            JMP     EXIT
  13564.  
  13565.    BUILDBP:
  13566.    ASSUME  DS:NOTHING
  13567.    ; AH is media byte on entry
  13568.    ; DI points to correct BPB on return
  13569.            PUSH    AX
  13570.            PUSH    CX
  13571.            PUSH    DX
  13572.            PUSH    BX
  13573.            MOV     CL,AH       ; Save Media
  13574.            AND     CL,0F8H     ; Normalize
  13575.            CMP     CL,0F8H     ; Compare with Good Media Byte
  13576.            JZ      GOODID
  13577.            MOV     AH,0FEH     ; Default to 8-sector,
  13578.                                ; Single-sided
  13579.    GOODID:
  13580.            MOV     AL,1        ; Set number of FAT sectors
  13581.            MOV     BX,64*256+8 ; Set Dir Entries and Sector Max
  13582.            MOV     CX,40*8     ; Set Size of Drive
  13583.            MOV     DX,01*256+1 ; Set Head Limit & Sec/All Unit
  13584.            MOV     DI,OFFSET DRVBPB
  13585.            TEST    AH,00000010B ; Test for 8 OR 9 Sectors
  13586.            JNZ     HAS8        ; NZ = has 8 sectors
  13587.            INC     AL          ; Inc Number of FAT sectors
  13588.            INC     BL          ; Inc Sector Max
  13589.            ADD     CX,40       ; Increase Size
  13590.    HAS8:   TEST    AH,00000001B    ; Test for 1 or 2 Heads
  13591.            JZ      HAS1        ; Z = 1 Head
  13592.            ADD     CX,CX       ; Double Size of Disk
  13593.            MOV     BH,112      ; Increase # of Dir Entries
  13594.            INC     DH          ; Inc Sec/All Unit
  13595.            INC     DL          ; Inc Head Limit
  13596.    HAS1:   MOV     BYTE PTR [DI].2,DH
  13597.            MOV     BYTE PTR [DI].6,BH
  13598.            MOV     WORD PTR [DI].8,CX
  13599.            MOV     BYTE PTR [DI].10,AH
  13600.            MOV     BYTE PTR [DI].11,AL
  13601.            MOV     BYTE PTR [DI].13,BL
  13602.            MOV     BYTE PTR [DI].15,DL
  13603.            POP     BX
  13604.            POP     DX
  13605.            POP     CX
  13606.            POP     AX
  13607.            RET
  13608.  
  13609.  
  13610.    ; ----------------------------------------------------------
  13611.    ;
  13612.    ;        Disk I/O Handlers
  13613.    ;
  13614.    ; ENTRY:
  13615.    ;        AL = Drive Number (0-3)
  13616.    ;        AH = Media Descriptor
  13617.    ;        CX = Sector Count
  13618.    ;        DX = First Sector
  13619.    ;        DS = CS
  13620.    ;        ES:DI = Transfer Address
  13621.    ; EXIT:
  13622.    ;        IF Successful Carry Flag = 0
  13623.    ;          ELSE CF=1 AND AL contains (MS-DOS) Error Code,
  13624.              CX # sectors NOT transferred
  13625.  
  13626.    DRV$READ:
  13627.    ASSUME  DS:CODE
  13628.            JCXZ    DSKOK
  13629.            CALL    SETUP
  13630.            JC      DSK$IO
  13631.            CALL    DISKRD
  13632.            JMP     SHORT DSK$IO
  13633.  
  13634.    DRV$WRIT:
  13635.    ASSUME  DS:CODE
  13636.            JCXZ    DSKOK
  13637.            CALL    SETUP
  13638.            JC      DSK$IO
  13639.            CALL    DISKWRT
  13640.    ASSUME  DS:NOTHING
  13641.    DSK$IO: JNC     DSKOK
  13642.            JMP     ERR$CNT
  13643.    DSKOK:  JMP     EXIT
  13644.  
  13645.  
  13646.    SETUP:
  13647.    ASSUME  DS:CODE
  13648.    ; Input same as above
  13649.    ; On output
  13650.    ;  ES:DI = Trans addr
  13651.    ;  DS:BX Points to BPB
  13652.    ;  Carry set if error (AL is error code (MS-DOS))
  13653.    ;  else
  13654.    ;        [DRIVE] = Drive number (0-3)
  13655.    ;        [SECCNT] = Sectors to transfer
  13656.    ;        [CURSEC] = Sector number of start of I/O
  13657.    ;        [CURHD]  = Head number of start of I/O   ; Set
  13658.    ;        [CURTRK] = Track # of start of I/O ; Seek performed
  13659.    ;  All other registers destroyed
  13660.  
  13661.            XCHG   BX,DI              ; ES:BX = Transfer Address
  13662.            CALL   BUILDBP            ; DS:DI = PTR to B.P.B
  13663.            MOV    SI,CX
  13664.            ADD    SI,DX
  13665.            CMP    SI,WORD PTR [DI].DRVLIM
  13666.                                     ; Compare Against Drive Max
  13667.            JBE    INRANGE
  13668.            MOV    AL,8
  13669.            STC
  13670.            RET
  13671.  
  13672.    INRANGE:
  13673.            MOV    [DRIVE],AL
  13674.            MOV    [SECCNT],CX     ; Save Sector Count
  13675.            XCHG   AX,DX           ; Set Up Logical Sector
  13676.                                   ; For Divide
  13677.            XOR    DX,DX
  13678.            DIV    WORD PTR [DI].SECLIM ; Divide by Sec per Track
  13679.            INC    DL
  13680.            MOV    [CURSEC],DL          ; Save Current Sector
  13681.            MOV    CX,WORD PTR [DI].HDLIM ; Get Number of Heads
  13682.            XOR    DX,DX   ; Divide Tracks by Heads per Cylinder
  13683.            DIV    CX
  13684.            MOV    [CURHD],DL      ; Save Current Head
  13685.            MOV    [CURTRK],AX     ; Save Current Track
  13686.    SEEK:
  13687.            PUSH   BX              ; Xaddr
  13688.            PUSH   DI              ; BPB pointer
  13689.            CALL   CHKNEW          ; Unload head if change drives
  13690.            CALL   DRIVESEL
  13691.            MOV    BL,[DRIVE]
  13692.            XOR    BH,BH           ; BX drive index
  13693.            ADD    BX,OFFSET TRKTAB        ; Get current track
  13694.            MOV    AX,[CURTRK]
  13695.            MOV    DL,AL         ; Save desired track
  13696.            XCHG   AL,DS:[BX]    ; Make desired track current
  13697.            OUT    DISK+1,AL     ; Tell Controller current track
  13698.            CMP    AL,DL         ; At correct track?
  13699.            JZ     SEEKRET       ; Done if yes
  13700.            MOV    BH,2          ; Seek retry count
  13701.            CMP    AL,-1         ; Position Known?
  13702.            JNZ    NOHOME        ; If not home head
  13703.    TRYSK:
  13704.            CALL   HOME
  13705.            JC     SEEKERR
  13706.    NOHOME:
  13707.            MOV    AL,DL
  13708.            OUT    DISK+3,AL       ; Desired track
  13709.            MOV    AL,1CH+STPSPD   ; Seek
  13710.            CALL   DCOM
  13711.            AND    AL,98H    ; Accept not rdy, seek, & CRC errors
  13712.            JZ     SEEKRET
  13713.            JS     SEEKERR         ; No retries if not ready
  13714.            DEC    BH
  13715.            JNZ    TRYSK
  13716.    SEEKERR:
  13717.            MOV    BL,[DRIVE]
  13718.            XOR    BH,BH           ; BX drive index
  13719.            ADD    BX,OFFSET TRKTAB        ; Get current track
  13720.            MOV    BYTE PTR DS:[BX],-1     ; Make current track
  13721.                                           ; unknown
  13722.            CALL   GETERRCD
  13723.            MOV    CX,[SECCNT]     ; Nothing transferred
  13724.            POP    BX              ; BPB pointer
  13725.            POP    DI              ; Xaddr
  13726.            RET
  13727.  
  13728.    SEEKRET:
  13729.            POP    BX              ; BPB pointer
  13730.            POP    DI              ; Xaddr
  13731.            CLC
  13732.            RET
  13733.  
  13734.    ; ---------------------------------------------
  13735.    ;
  13736.    ;        Read
  13737.    ;
  13738.  
  13739.    DISKRD:
  13740.    ASSUME  DS:CODE
  13741.            MOV    CX,[SECCNT]
  13742.    RDLP:
  13743.            CALL   PRESET
  13744.            PUSH   BX
  13745.            MOV    BL,10              ; Retry count
  13746.            MOV    DX,DISK+3          ; Data port
  13747.    RDAGN:
  13748.            MOV    AL,80H             ; Read command
  13749.            CLI                       ; Disable for 1793
  13750.            OUT    DISK,AL            ; Output read command
  13751.            MOV    BP,DI              ; Save address for retry
  13752.            JMP    SHORT RLOOPENTRY
  13753.    RLOOP:
  13754.            STOSB
  13755.    RLOOPENTRY:
  13756.            IN     AL,DISK+5          ; Wait for DRQ or INTRQ
  13757.            SHR    AL,1
  13758.            IN     AL,DX              ; Read data
  13759.            JNC    RLOOP
  13760.            STI                       ; Ints OK now
  13761.            CALL   GETSTAT
  13762.            AND    AL,9CH
  13763.            JZ     RDPOP              ; Ok
  13764.            MOV    DI,BP              ; Get back transfer
  13765.            DEC    BL
  13766.            JNZ    RDAGN
  13767.            CMP    AL,10H             ; Record not found?
  13768.            JNZ    GOT_CODE           ; No
  13769.            MOV    AL,1               ; Map it
  13770.    GOT_CODE:
  13771.            CALL   GETERRCD
  13772.            POP    BX
  13773.            RET
  13774.  
  13775.    RDPOP:
  13776.            POP    BX
  13777.            LOOP   RDLP
  13778.            CLC
  13779.            RET
  13780.  
  13781.  
  13782.    ; ---------------------------------------------
  13783.    ;
  13784.    ;        Write
  13785.    ;
  13786.  
  13787.    DISKWRT:
  13788.    ASSUME  DS:CODE
  13789.            MOV     CX,[SECCNT]
  13790.            MOV     SI,DI
  13791.            PUSH    ES
  13792.            POP     DS
  13793.    ASSUME  DS:NOTHING
  13794.    WRLP:
  13795.            CALL    PRESET
  13796.            PUSH    BX
  13797.            MOV     BL,10                   ; Retry count
  13798.            MOV     DX,DISK+3               ; Data port
  13799.    WRAGN:
  13800.            MOV     AL,0A0H            ; Write command
  13801.            CLI                        ; Disable for 1793
  13802.            OUT     DISK,AL            ; Output write command
  13803.            MOV     BP,SI              ; Save address for retry
  13804.    WRLOOP:
  13805.            IN      AL,DISK+5
  13806.            SHR     AL,1
  13807.            LODSB                      ; Get data
  13808.            OUT     DX,AL              ; Write data
  13809.            JNC     WRLOOP
  13810.            STI                        ; Ints OK now
  13811.            DEC     SI
  13812.            CALL    GETSTAT
  13813.            AND     AL,0FCH
  13814.            JZ      WRPOP              ; Ok
  13815.            MOV     SI,BP              ; Get back transfer
  13816.            DEC     BL
  13817.            JNZ     WRAGN
  13818.            CALL    GETERRCD
  13819.            POP     BX
  13820.            RET
  13821.  
  13822.    WRPOP:
  13823.            POP     BX
  13824.            LOOP    WRLP
  13825.            CLC
  13826.            RET
  13827.  
  13828.  
  13829.    PRESET:
  13830.    ASSUME  DS:NOTHING
  13831.            MOV     AL,[CURSEC]
  13832.            CMP     AL,CS:[BX].SECLIM
  13833.            JBE     GOTSEC
  13834.            MOV     DH,[CURHD]
  13835.            INC     DH
  13836.            CMP     DH,CS:[BX].HDLIM
  13837.            JB      SETHEAD            ; Select new head
  13838.            CALL    STEP               ; Go on to next track
  13839.            XOR     DH,DH              ; Select head zero
  13840.    SETHEAD:
  13841.            MOV     [CURHD],DH
  13842.            CALL    DRIVESEL
  13843.            MOV     AL,1               ; First sector
  13844.            MOV     [CURSEC],AL        ; Reset CURSEC
  13845.    GOTSEC:
  13846.            OUT     DISK+2,AL     ; Tell controller which sector
  13847.            INC     [CURSEC]      ; We go on to next sector
  13848.            RET
  13849.  
  13850.    STEP:
  13851.    ASSUME  DS:NOTHING
  13852.            MOV     AL,58H+STPSPD  ; Step in w/ update, no verify
  13853.            CALL    DCOM
  13854.            PUSH    BX
  13855.            MOV     BL,[DRIVE]
  13856.            XOR     BH,BH           ; BX drive index
  13857.            ADD     BX,OFFSET TRKTAB        ; Get current track
  13858.            INC     BYTE PTR CS:[BX]        ; Next track
  13859.            POP     BX
  13860.            RET
  13861.  
  13862.    HOME:
  13863.    ASSUME  DS:NOTHING
  13864.            MOV     BL,3
  13865.    TRYHOM:
  13866.            MOV     AL,0CH+STPSPD   ; Restore with verify
  13867.            CALL    DCOM
  13868.            AND     AL,98H
  13869.            JZ      RET3
  13870.            JS      HOMERR          ; No retries if not ready
  13871.            PUSH    AX              ; Save real error code
  13872.            MOV     AL,58H+STPSPD   ; Step in w/ update no verify
  13873.            CALL    DCOM
  13874.            DEC     BL
  13875.            POP     AX              ; Get back real error code
  13876.            JNZ     TRYHOM
  13877.    HOMERR:
  13878.            STC
  13879.    RET3:   RET
  13880.  
  13881.  
  13882.    CHKNEW:
  13883.    ASSUME  DS:NOTHING
  13884.            MOV     AL,[DRIVE]      ; Get disk drive number
  13885.            MOV     AH,AL
  13886.            XCHG    AL,[CURDRV]     ; Make new drive current.
  13887.            CMP     AL,AH           ; Changing drives?
  13888.            JZ      RET1            ; No
  13889.    ;  If changing drives, unload head so the head load delay
  13890.    ; one-shot will fire again. Do it by seeking to the same
  13891.    ; track with the H bit reset.
  13892.    ;
  13893.            IN      AL,DISK+1       ; Get current track number
  13894.            OUT     DISK+3,AL       ; Make it the track to seek
  13895.            MOV     AL,10H          ; Seek and unload head
  13896.  
  13897.    DCOM:
  13898.    ASSUME  DS:NOTHING
  13899.            OUT     DISK,AL
  13900.            PUSH    AX
  13901.            AAM                     ; Delay 10 microseconds
  13902.            POP     AX
  13903.    GETSTAT:
  13904.            IN      AL,DISK+4
  13905.            TEST    AL,DONEBIT
  13906.            JZ      GETSTAT
  13907.            IN      AL,DISK
  13908.    RET1:   RET
  13909.  
  13910.    DRIVESEL:
  13911.    ASSUME  DS:NOTHING
  13912.    ; Select the drive based on current info
  13913.    ; Only AL altered
  13914.            MOV     AL,[DRIVE]
  13915.            OR      AL,SMALBIT + DDBIT      ; 5 1/4" IBM PC disks
  13916.            CMP     [CURHD],0
  13917.            JZ      GOTHEAD
  13918.            OR      AL,BACKBIT      ; Select side 1
  13919.    GOTHEAD:
  13920.            OUT     DISK+4,AL       ; Select drive and side
  13921.            RET
  13922.  
  13923.    GETERRCD:
  13924.    ASSUME  DS:NOTHING
  13925.            PUSH    CX
  13926.            PUSH    ES
  13927.            PUSH    DI
  13928.            PUSH    CS
  13929.            POP     ES              ; Make ES the local segment
  13930.            MOV     CS:[LSTERR],AL ; Terminate list w/ error code
  13931.            MOV     CX,NUMERR       ; Number of error conditions
  13932.            MOV     DI,OFFSET ERRIN ; Point to error conditions
  13933.            REPNE   SCASB
  13934.            MOV     AL,NUMERR-1[DI] ; Get translation
  13935.            STC                     ; Flag error condition
  13936.            POP     DI
  13937.            POP     ES
  13938.            POP     CX
  13939.            RET                     ; and return
  13940.  
  13941.    ; *********************************************************
  13942.    ;        BPB for an IBM floppy disk, Various parameters are
  13943.    ;        patched by BUILDBP to reflect the type of Media
  13944.    ;        inserted
  13945.    ;        This is a 9-sector, single-side BPB
  13946.    DRVBPB:
  13947.            DW      512          ; Physical sector size in bytes
  13948.            DB      1            ; Sectors/allocation unit
  13949.            DW      1            ; Reserved sectors for DOS
  13950.            DB      2            ; # of allocation tables
  13951.            DW      64           ; Number directory entries
  13952.            DW      9*40         ; Number 512-byte sectors
  13953.            DB      11111100B    ; Media descriptor
  13954.            DW      2            ; Number of FAT sectors
  13955.            DW      9            ; Sector limit
  13956.            DW      1            ; Head limit
  13957.  
  13958.  
  13959.    INITAB  DW      DRVBPB               ; Up to four units
  13960.            DW      DRVBPB
  13961.            DW      DRVBPB
  13962.            DW      DRVBPB
  13963.  
  13964.    ERRIN:  ; DISK ERRORS RETURNED FROM THE CONTROLLER
  13965.            DB      80H             ; No response
  13966.            DB      40H             ; Write protect
  13967.            DB      20H             ; Write Fault
  13968.            DB      10H             ; SEEK error
  13969.            DB      8               ; CRC error
  13970.            DB      1               ; Mapped from 10H
  13971.                                    ; (record not found) on Read
  13972.    LSTERR  DB      0               ; All other errors
  13973.  
  13974.    ERROUT: ; RETURNED ERROR CODES CORRESPONDING TO ABOVE
  13975.            DB      2               ; No response
  13976.            DB      0               ; Write Attempt
  13977.                                    ; On Write-protected disk
  13978.            DB      0AH             ; Write fault
  13979.            DB      6               ; SEEK Failure
  13980.            DB      4               ; Bad CRC
  13981.            DB      8               ; Sector not found
  13982.            DB      12              ; General error
  13983.  
  13984.  
  13985.    DRV$INIT:
  13986.    ;
  13987.    ;  Determine number of physical drives by reading config.sys
  13988.    ;
  13989.    ASSUME  DS:CODE
  13990.            PUSH    DS
  13991.            LDS     SI,[PTRSAV]
  13992.    ASSUME  DS:NOTHING
  13993.            LDS     SI,DWORD PTR [SI.COUNT] ; DS:SI points to
  13994.                                            ; config.sys
  13995.    SCAN_LOOP:
  13996.            CALL    SCAN_SWITCH
  13997.            MOV     AL,CL
  13998.            OR      AL,AL
  13999.            JZ      SCAN4
  14000.            CMP     AL,"s"
  14001.            JZ      SCAN4
  14002.  
  14003.    WERROR: POP     DS
  14004.    ASSUME  DS:CODE
  14005.            MOV     DX,OFFSET ERRMSG2
  14006.    WERROR2: MOV    AH,9
  14007.            INT     21H
  14008.            XOR     AX,AX
  14009.            PUSH    AX                      ; No units
  14010.            JMP     SHORT ABORT
  14011.  
  14012.    BADNDRV:
  14013.            POP     DS
  14014.            MOV     DX,OFFSET ERRMSG1
  14015.            JMP     WERROR2
  14016.  
  14017.    SCAN4:
  14018.    ASSUME  DS:NOTHING
  14019.    ; BX is number of floppies
  14020.            OR      BX,BX
  14021.            JZ      BADNDRV                 ; User error
  14022.            CMP     BX,4
  14023.            JA      BADNDRV                 ; User error
  14024.            POP     DS
  14025.    ASSUME  DS:CODE
  14026.            PUSH    BX                      ; Save unit count
  14027.    ABORT:  LDS     BX,[PTRSAV]
  14028.    ASSUME  DS:NOTHING
  14029.            POP     AX
  14030.            MOV     BYTE PTR [BX].MEDIA,AL           ; Unit count
  14031.            MOV     [DRVMAX],AL
  14032.            MOV     WORD PTR [BX].TRANS,OFFSET DRV$INIT ; SET
  14033.                                                  ; BREAK ADDRESS
  14034.            MOV     [BX].TRANS+2,CS
  14035.            MOV     WORD PTR [BX].COUNT,OFFSET INITAB
  14036.                                     ; SET POINTER TO BPB ARRAY
  14037.            MOV     [BX].ceOUNT+2,CS
  14038.            JMP     EXIT
  14039.    ;
  14040.    ;  Put switch in CL, value in BX
  14041.    ;
  14042.    SCAN_SWITCH:
  14043.            XOR     BX,BX
  14044.            MOV     CX,BX
  14045.            LODSB
  14046.            CMP     AL,10
  14047.            JZ      NUMRET
  14048.            CMP     AL,"-"
  14049.            JZ      GOT_SWITCH
  14050.            CMP     AL,"/"
  14051.            JNZ     SCAN_SWITCH
  14052.    GOT_SWITCH:
  14053.            CMP     BYTE PTR [SI+1],":"
  14054.            JNZ     TERROR
  14055.            LODSB
  14056.            OR      AL,20H          ;  Convert to lowercase
  14057.            MOV     CL,AL           ;  Get switch
  14058.            LODSB                   ;  Skip ":"
  14059.    ;
  14060.    ;   Get number pointed to by [SI]
  14061.    ;
  14062.    ;   Wipes out AX,DX only     BX returns number
  14063.    ;
  14064.    GETNUM1:LODSB
  14065.            SUB     AL,"0"
  14066.            JB      CHKRET
  14067.            CMP     AL,9
  14068.            JA      CHKRET
  14069.            CBW
  14070.            XCHG    AX,BX
  14071.            MOV     DX,10
  14072.            MUL     DX
  14073.            ADD     BX,AX
  14074.            JMP     GETNUM1
  14075.  
  14076.    CHKRET: ADD     AL,"0"
  14077.            CMP     AL," "
  14078.            JBE     NUMRET
  14079.            CMP     AL,"-"
  14080.            JZ      NUMRET
  14081.            CMP     AL,"/"
  14082.            JZ      NUMRET
  14083.    TERROR:
  14084.            POP     DS              ;  Get rid of return address
  14085.            JMP     WERROR
  14086.    NUMRET: DEC     SI
  14087.            RET
  14088.  
  14089.    ERRMSG1 DB      "SMLDRV: Bad number of drives",13,10,"$"
  14090.    ERRMSG2 DB      "SMLDRV: Invalid parameter",13,10,"$"
  14091.    CODE    ENDS
  14092.            END
  14093.  
  14094.    Character Device Driver
  14095.  
  14096.    The following program illustrates a character device driver program.
  14097.  
  14098.  
  14099.    ; ******************** A Character Device *******************
  14100.  
  14101.    Title   VT52 Console for 2.0    (IBM)
  14102.  
  14103.    ; ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  14104.    ;
  14105.    ;        IBM Addresses for I/O
  14106.    ;
  14107.    ; ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  14108.  
  14109.            CR=13              ; Carriage-Return
  14110.            BACKSP=8           ; BACKSPACE
  14111.            ESC=1BH
  14112.            BRKADR=6CH         ; 006C  Break vector address
  14113.            ASNMAX=200         ; Size of key assignment buffer
  14114.  
  14115.    CODE    SEGMENT BYTE
  14116.  
  14117.       ASSUME CS:CODE,DS:NOTHING,ES:NOTHING
  14118.    ; ----------------------------------------------------------
  14119.    ;
  14120.    ;        C O N - Console Device Driver
  14121.    ;
  14122.    CONDEV:                            ; Header for device "CON"
  14123.            DW      -1,-1
  14124.            DW      1000000000010011B  ; CON IN AND CON OUT
  14125.            DW      STRATEGY
  14126.            DW      ENTRY
  14127.            DB      'CON     '
  14128.  
  14129.    ; -----------------------------------------------------------
  14130.    ;
  14131.    ;        Command JUMP Tables
  14132.    CONTBL:
  14133.            DW      CON$INIT
  14134.            DW      EXIT
  14135.            DW      EXIT
  14136.            DW      CMDERR
  14137.            DW      CON$READ
  14138.            DW      CON$RDND
  14139.            DW      EXIT
  14140.            DW      CON$FLSH
  14141.            DW      CON$WRIT
  14142.            DW      CON$WRIT
  14143.            DW      EXIT
  14144.            DW      EXIT
  14145.  
  14146.    CMDTABL DB      'A'
  14147.            DW      CUU             ; cursor up
  14148.            DB      'B'
  14149.            DW      CUD             ; cursor down
  14150.            DB      'C'
  14151.            DW      CUF             ; cursor forward
  14152.            DB      'D'
  14153.            DW      CUB             ; cursor back
  14154.            DB      'H'
  14155.            DW      CUH             ; cursor position
  14156.            DB      'J'
  14157.            DW      ED              ; erase display
  14158.            DB      'K'
  14159.            DW      EL              ; erase line
  14160.            DB      'Y'
  14161.            DW      CUP             ; cursor position
  14162.            DB      'j'
  14163.            DW      PSCP            ; save cursor position
  14164.            DB      'k'
  14165.            DW      PRCP            ; restore cursor position
  14166.            DB      'y'
  14167.            DW      RM              ; reset mode
  14168.            DB      'x'
  14169.            DW      SM              ; set mode
  14170.            DB      00
  14171.  
  14172.    PAGE
  14173.    ; ---------------------------------------------------
  14174.    ;
  14175.    ;        Device entry point
  14176.    ;
  14177.    CMDLEN  =       0       ; Length of this command
  14178.    UNIT    =       1       ; Subunit Specified
  14179.    CMD     =       2       ; Command Code
  14180.    STATUS  =       3       ; Status
  14181.    MEDIA   =       13      ; Media Descriptor
  14182.    TRANS   =       14      ; Transfer Address
  14183.    COUNT   =       18      ; Count of blocks or characters
  14184.    START   =       20      ; First block to transfer
  14185.  
  14186.    PTRSAV  DD      0
  14187.  
  14188.    STRATP  PROC    FAR
  14189.  
  14190.    STRATEGY:
  14191.            MOV     WORD PTR CS:[PTRSAV],BX
  14192.            MOV     WORD PTR CS:[PTRSAV+2],ES
  14193.            RET
  14194.  
  14195.    STRATP  ENDP
  14196.  
  14197.    ENTRY:
  14198.            PUSH    SI
  14199.            PUSH    AX
  14200.            PUSH    CX
  14201.            PUSH    DX
  14202.            PUSH    DI
  14203.            PUSH    BP
  14204.            PUSH    DS
  14205.            PUSH    ES
  14206.            PUSH    BX
  14207.  
  14208.            LDS     BX,CS:[PTRSAV]  ; GET POINTER TO I/O PACKET
  14209.  
  14210.            MOV     CX,WORD PTR DS:[BX].COUNT    ; CX = COUNT
  14211.  
  14212.            MOV     AL,BYTE PTR DS:[BX].CMD
  14213.            CBW
  14214.            MOV     SI,OFFSET CONTBL
  14215.            ADD     SI,AX
  14216.            ADD     SI,AX
  14217.            CMP     AL,11
  14218.            JA      CMDERR
  14219.  
  14220.            LES     DI,DWORD PTR DS:[BX].TRANS
  14221.  
  14222.            PUSH    CS
  14223.            POP     DS
  14224.  
  14225.            ASSUME  DS:CODE
  14226.  
  14227.            JMP     WORD PTR [SI]              ; GO DO COMMAND
  14228.  
  14229.    PAGE
  14230.    ; =====================================================
  14231.    ; =
  14232.    ; =      Subroutines Shared by Multiple Devices
  14233.    ; =
  14234.    ; =====================================================
  14235.    ; -----------------------------------------------------
  14236.    ;
  14237.    ;        EXIT - All routines return through this path
  14238.    ;
  14239.    BUS$EXIT:                               ; Device Busy Exit
  14240.            MOV     AH,00000011B
  14241.            JMP     SHORT ERR1
  14242.  
  14243.    CMDERR:
  14244.            MOV     AL,3                ; Unknown command error
  14245.  
  14246.    ERR$EXIT:
  14247.            MOV     AH,10000001B            ; Mark error Return
  14248.            JMP     SHORT ERR1
  14249.  
  14250.    EXITP   PROC    FAR
  14251.  
  14252.    EXIT:   MOV     AH,00000001B
  14253.    ERR1:   LDS     BX,CS:[PTRSAV]
  14254.            MOV     WORD PTR [BX].STATUS,AX ; Mark
  14255.                                            ; Operation Complete
  14256.  
  14257.            POP     BX
  14258.            POP     ES
  14259.            POP     DS
  14260.            POP     BP
  14261.            POP     DI
  14262.            POP     DX
  14263.            POP     CX
  14264.            POP     AX
  14265.            POP     SI
  14266.            RET                        ; Restore REGS and Return
  14267.    EXITP   ENDP
  14268.    ; -----------------------------------------------
  14269.    ;
  14270.    ;        BREAK Key Handling
  14271.    ;
  14272.    BREAK:
  14273.            MOV     CS:ALTAH,3         ; Indicate BREAK key Set
  14274.    INTRET: IRET
  14275.  
  14276.    PAGE
  14277.    ;
  14278.    ;        WARNING - Variables are very order dependent,
  14279.                      so be careful when adding new ones!
  14280.    ;
  14281.    WRAP    DB      0               ;  0 = WRAP, 1 = NO WRAP
  14282.    STATE   DW      S1
  14283.    MODE    DB      3
  14284.    MAXCOL  DB      79
  14285.    COL     DB      0
  14286.    ROW     DB      0
  14287.    SAVCR   DW      0
  14288.    ALTAH   DB      0               ; Special key handling
  14289.  
  14290.    ; -------------------------------------------------------
  14291.    ;
  14292.    ;     CHROUT - Write out Char in AL using current attribute
  14293.    ;
  14294.    ATTRW   LABEL   WORD
  14295.    ATTR    DB      00000111B       ; Character Attribute
  14296.    BPAGE   DB      0               ; Base Page
  14297.    base    dw      0b800h
  14298.  
  14299.    chrout: cmp     al,13
  14300.            jnz     trylf
  14301.            mov     [col],0
  14302.            jmp     short setit
  14303.  
  14304.    trylf:  cmp     al,10
  14305.            jz      lf
  14306.            cmp     al,7
  14307.            jnz     tryback
  14308.    torom:
  14309.            mov     bx,[attrw]
  14310.            and     bl,7
  14311.            mov     ah,14
  14312.            int     10h
  14313.    ret5:   ret
  14314.  
  14315.    tryback:
  14316.            cmp     al,8
  14317.            jnz     outchr
  14318.            cmp     [col],0
  14319.            jz      ret5
  14320.            dec     [col]
  14321.            jmp     short setit
  14322.  
  14323.    outchr:
  14324.            mov     bx,[attrw]
  14325.            mov     cx,1
  14326.            mov     ah,9
  14327.            int     10h
  14328.            inc     [col]
  14329.            mov     al,[col]
  14330.            cmp     al,[maxcol]
  14331.            jbe     setit
  14332.            cmp     [wrap],0
  14333.            jz      outchr1
  14334.            dec     [col]
  14335.            ret
  14336.    outchr1:
  14337.            mov     [col],0
  14338.    lf:     inc     [row]
  14339.            cmp     [row],24
  14340.            jb      setit
  14341.            mov     [row],23
  14342.            call    scroll
  14343.  
  14344.    setit:  mov     dh,row
  14345.            mov     dl,col
  14346.            xor     bh,bh
  14347.            mov     ah,2
  14348.            int     10h
  14349.            ret
  14350.  
  14351.    scroll: call    getmod
  14352.            cmp     al,2
  14353.            jz      myscroll
  14354.            cmp     al,3
  14355.            jz      myscroll
  14356.            mov     al,10
  14357.            jmp     torom
  14358.    myscroll:
  14359.            mov     bh,[attr]
  14360.            mov     bl,' '
  14361.            mov     bp,80
  14362.            mov     ax,[base]
  14363.            mov     es,ax
  14364.            mov     ds,ax
  14365.            xor     di,di
  14366.            mov     si,160
  14367.            mov     cx,23*80
  14368.            cld
  14369.            cmp     ax,0b800h
  14370.            jz      colorcard
  14371.  
  14372.            rep     movsw
  14373.            mov     ax,bx
  14374.            mov     cx,bp
  14375.            rep     stosw
  14376.    sret:   push    cs
  14377.            pop     ds
  14378.            ret
  14379.  
  14380.    colorcard:
  14381.            mov     dx,3dah
  14382.    wait2:  in      al,dx
  14383.            test    al,8
  14384.            jz      wait2
  14385.            mov     al,25h
  14386.            mov     dx,3d8h
  14387.            out     dx,al           ; turn off video
  14388.            rep     movsw
  14389.            mov     ax,bx
  14390.            mov     cx,bp
  14391.            rep     stosw
  14392.            mov     al,29h
  14393.            mov     dx,3d8h
  14394.            out     dx,al           ; turn on video
  14395.            jmp     sret
  14396.  
  14397.    GETMOD: MOV     AH,15
  14398.            INT     16             ; get column information
  14399.            MOV     BPAGE,BH
  14400.            DEC     AH
  14401.            MOV     WORD PTR MODE,AX
  14402.            RET
  14403.    ; ------------------------------------------------------
  14404.    ;
  14405.    ;        Console Read Routine
  14406.    ;
  14407.    CON$READ:
  14408.            JCXZ    CON$EXIT
  14409.    CON$LOOP:
  14410.            PUSH    CX              ; Save Count
  14411.            CALL    CHRIN           ; Get Char in AL
  14412.            POP     CX
  14413.            STOSB                   ; Store Char at ES:DI
  14414.            LOOP    CON$LOOP
  14415.    CON$EXIT:
  14416.            JMP     EXIT
  14417.    ; ---------------------------------------------------------
  14418.    ;
  14419.    ;        Input Single Char into AL
  14420.    ;
  14421.    CHRIN:  XOR     AX,AX
  14422.            XCHG    AL,ALTAH     ; Get Character & Zero ALTAH
  14423.            OR      AL,AL
  14424.            JNZ     KEYRET
  14425.  
  14426.    INAGN:  XOR     AH,AH
  14427.            INT     22
  14428.    ALT10:
  14429.            OR      AX,AX       ; Check for non-key after BREAK
  14430.            JZ      INAGN
  14431.            OR      AL,AL       ; Special case?
  14432.            JNZ     KEYRET
  14433.            MOV     ALTAH,AH        ; Store special key
  14434.    KEYRET: RET
  14435.    ; ----------------------------------------------------------
  14436.    ;
  14437.    ;        Keyboard Non-destructive Read, No Wait
  14438.    ;
  14439.    CON$RDND:
  14440.            MOV     AL,[ALTAH]
  14441.            OR      AL,AL
  14442.            JNZ     RDEXIT
  14443.  
  14444.    RD1:    MOV     AH,1
  14445.            INT     22
  14446.            JZ      CONBUS
  14447.            OR      AX,AX
  14448.            JNZ     RDEXIT
  14449.            MOV     AH,0
  14450.            INT     22
  14451.            JMP     CON$RDND
  14452.  
  14453.    RDEXIT: LDS     BX,[PTRSAV]
  14454.            MOV     [BX].MEDIA,AL
  14455.    EXVEC:  JMP     EXIT
  14456.    CONBUS: JMP     BUS$EXIT
  14457.    ; ----------------------------------------------------------
  14458.    ;
  14459.    ;        Keyboard Flush Routine
  14460.    ;
  14461.    CON$FLSH:
  14462.            MOV     [ALTAH],0         ; Clear out holding buffer
  14463.  
  14464.            PUSH    DS
  14465.            XOR     BP,BP
  14466.            MOV     DS,BP                   ; Select segment 0
  14467.            MOV     DS:BYTE PTR 41AH,1EH    ; Reset KB queue head
  14468.                                            ; pointer
  14469.            MOV     DS:BYTE PTR 41CH,1EH    ; Reset tail pointer
  14470.            POP     DS
  14471.            JMP     EXVEC
  14472.    ; ----------------------------------------------------------
  14473.    ;
  14474.    ;        Console Write Routine
  14475.    ;
  14476.    CON$WRIT:
  14477.            JCXZ    EXVEC
  14478.            PUSH    CX
  14479.            MOV     AH,3            ; Set current cursor position
  14480.            XOR     BX,BX
  14481.            INT     16
  14482.            MOV     WORD PTR [COL],DX
  14483.            POP     CX
  14484.  
  14485.    CON$LP: MOV     AL,ES:[DI]      ; Get Char
  14486.            INC     DI
  14487.            CALL    OUTC            ; Output Char
  14488.            LOOP    CON$LP          ; Repeat until all through
  14489.            JMP     EXVEC
  14490.  
  14491.    COUT:   STI
  14492.            PUSH    DS
  14493.            PUSH    CS
  14494.            POP     DS
  14495.            CALL    OUTC
  14496.            POP     DS
  14497.            IRET
  14498.  
  14499.    OUTC:   PUSH    AX
  14500.            PUSH    CX
  14501.            PUSH    DX
  14502.            PUSH    SI
  14503.            PUSH    DI
  14504.            PUSH    ES
  14505.            PUSH    BP
  14506.            CALL    VIDEO
  14507.            POP     BP
  14508.            POP     ES
  14509.            POP     DI
  14510.            POP     SI
  14511.            POP     DX
  14512.            POP     CX
  14513.            POP     AX
  14514.            RET
  14515.  
  14516.  
  14517.    ; ----------------------------------------------------------
  14518.    ;
  14519.    ;        Output Single Char in AL to Video Device
  14520.    ;
  14521.    VIDEO:  MOV     SI,OFFSET STATE
  14522.            JMP     [SI]
  14523.  
  14524.    S1:     CMP     AL,ESC                 ; Escape sequence?
  14525.            JNZ     S1B
  14526.            MOV     WORD PTR [SI],OFFSET S2
  14527.            RET
  14528.  
  14529.    S1B:    CALL    CHROUT
  14530.    S1A:    MOV     WORD PTR [STATE],OFFSET S1
  14531.            RET
  14532.  
  14533.  
  14534.    S2:     PUSH    AX
  14535.            CALL    GETMOD
  14536.            POP     AX
  14537.            MOV     BX,OFFSET CMDTABL-3
  14538.    S7A:    ADD     BX,3
  14539.            CMP     BYTE PTR [BX],0
  14540.            JZ      S1A
  14541.            CMP     BYTE PTR [BX],AL
  14542.            JNZ     S7A
  14543.            JMP     WORD PTR [BX+1]
  14544.  
  14545.  
  14546.    MOVCUR: CMP     BYTE PTR [BX],AH
  14547.            JZ      SETCUR
  14548.            ADD     BYTE PTR [BX],AL
  14549.    SETCUR: MOV     DX,WORD PTR COL
  14550.            XOR     BX,BX
  14551.            MOV     AH,2
  14552.            INT     16
  14553.            JMP     S1A
  14554.  
  14555.  
  14556.    CUP:    MOV     WORD PTR [SI],OFFSET CUP1
  14557.            RET
  14558.    CUP1:   SUB     AL,32
  14559.            MOV     BYTE PTR [ROW],AL
  14560.            MOV     WORD PTR [SI],OFFSET CUP2
  14561.            RET
  14562.    CUP2:   SUB     AL,32
  14563.            MOV     BYTE PTR [COL],AL
  14564.            JMP     SETCUR
  14565.  
  14566.    SM:     MOV     WORD PTR [SI],OFFSET S1A
  14567.            RET
  14568.  
  14569.  
  14570.    CUH:    MOV     WORD PTR COL,0
  14571.            JMP     SETCUR
  14572.  
  14573.    CUF:    MOV     AH,MAXCOL
  14574.            MOV     AL,1
  14575.    CUF1:   MOV     BX,OFFSET COL
  14576.            JMP     MOVCUR
  14577.  
  14578.    CUB:    MOV     AX,00FFH
  14579.            JMP     CUF1
  14580.  
  14581.    CUU:    MOV     AX,00FFH
  14582.    CUU1:   MOV     BX,OFFSET ROW
  14583.            JMP     MOVCUR
  14584.  
  14585.    CUD:    MOV     AX,23*256+1
  14586.            JMP     CUU1
  14587.  
  14588.    PSCP:   MOV     AX,WORD PTR COL
  14589.            MOV     SAVCR,AX
  14590.            JMP     SETCUR
  14591.  
  14592.    PRCP:   MOV     AX,SAVCR
  14593.            MOV     WORD PTR COL,AX
  14594.            JMP     SETCUR
  14595.  
  14596.    ED:     CMP     BYTE PTR [ROW],24
  14597.            JAE     EL1
  14598.  
  14599.            MOV     CX,WORD PTR COL
  14600.            MOV     DH,24
  14601.            JMP     ERASE
  14602.  
  14603.    EL1:    MOV     BYTE PTR [COL],0
  14604.    EL:     MOV     CX,WORD PTR [COL]
  14605.    EL2:    MOV     DH,CH
  14606.    ERASE:  MOV     DL,MAXCOL
  14607.            MOV     BH,ATTR
  14608.            MOV     AX,0600H
  14609.            INT     16
  14610.    ED3:    JMP     SETCUR
  14611.  
  14612.  
  14613.    RM:     MOV     WORD PTR [SI],OFFSET RM1
  14614.            RET
  14615.    RM1:    XOR     CX,CX
  14616.            MOV     CH,24
  14617.            JMP     EL2
  14618.  
  14619.    CON$INIT:
  14620.            int     11h
  14621.            and     al,00110000b
  14622.            cmp     al,00110000b
  14623.            jnz     iscolor
  14624.            mov     [base],0b000h          ; look for bw card
  14625.    iscolor:
  14626.            cmp     al,00010000b           ; look for 40 col mode
  14627.            ja      setbrk
  14628.            mov     [mode],0
  14629.            mov     [maxcol],39
  14630.  
  14631.    setbrk:
  14632.            XOR     BX,BX
  14633.            MOV     DS,BX
  14634.            MOV     BX,BRKADR
  14635.            MOV     WORD PTR [BX],OFFSET BREAK
  14636.            MOV     WORD PTR [BX+2],CS
  14637.  
  14638.            MOV     BX,29H*4
  14639.            MOV     WORD PTR [BX],OFFSET COUT
  14640.            MOV     WORD PTR [BX+2],CS
  14641.  
  14642.            LDS     BX,CS:[PTRSAV]
  14643.            MOV     WORD PTR [BX].TRANS,OFFSET CON$INIT
  14644.                                  ; SET BREAK ADDRESS
  14645.            MOV     [BX].TRANS+2,CS
  14646.            JMP     EXIT
  14647.  
  14648.    CODE    ENDS
  14649.            END
  14650.  
  14651.  
  14652.  
  14653.  ────────────────────────────────────────────────────────────────────────────
  14654.  Chapter 3  MS-DOS Technical Information
  14655.  
  14656.      3.1   Introduction
  14657.      3.2   MS-DOS Initialization
  14658.      3.3   The Command Processor
  14659.      3.4   MS-DOS Disk Allocation
  14660.      3.5   MS-DOS Disk Directory
  14661.      3.6   File Allocation Table (FAT)
  14662.            3.6.1   How to Use the FAT (12-Bit FAT Entries)
  14663.            3.6.2   How to Use the FAT (16-Bit FAT Entries)
  14664.      3.7   MS-DOS Standard Disk Formats
  14665.  
  14666.  
  14667.  3.1  Introduction
  14668.  
  14669.    This chapter describes how MS-DOS initializes and how it allocates disk
  14670.    space for the root directory, the File Allocation Tables (FAT), and the
  14671.    data area. For programmers writing installable device drivers, this
  14672.    chapter explains MS-DOS disk directory entries and File Allocation Tables.
  14673.    At the end of the chapter, Tables 3.1 and 3.2 describe MS-DOS standard
  14674.    formats for floppy disks.
  14675.  
  14676.  
  14677.  3.2  MS-DOS Initialization
  14678.  
  14679.    MS-DOS initialization consists of several steps. When you reset your
  14680.    computer or turn on its power, the ROM (Read Only Memory) BIOS is invoked
  14681.    and performs hardware checks and initialization. The ROM BIOS then
  14682.    examines drive A for the boot sector. If it locates a boot sector, the ROM
  14683.    BIOS reads it into low memory and gives it control. If it doesn't find the
  14684.    boot sector, the ROM BIOS then looks in the active partition of the hard
  14685.    disk. If it still doesn't find the boot sector, then the ROM BIOS invokes
  14686.    ROM BASIC.
  14687.  
  14688.    On a removable disk (3.5-inch, 5.25-inch, or 8-inch disk), the boot sector
  14689.    is always located on track 0, sector 1, side 0 of the disk. On a hard
  14690.    disk, the boot sector begins on the first sector of the MS-DOS partition.
  14691.    The hard disk boot sector also includes a partition table. This table
  14692.    identifies the active MS-DOS partition and any other partitions, such as
  14693.    an extended MS-DOS partition, on the hard disk. Notice that extended
  14694.    MS-DOS partitions are not bootable.
  14695.  
  14696.    The boot sector then reads the following files, in the order listed:
  14697.  
  14698.    io.sys
  14699.    msdos.sys
  14700.  
  14701.  
  14702.    ──────────────────────────────────────────────────────────────────────────
  14703.    Note
  14704.      Versions of MS-DOS prior to 3.3 required the io.sys file to be
  14705.      contiguous. This is no longer a requirement.
  14706.    ──────────────────────────────────────────────────────────────────────────
  14707.  
  14708.    Next, the system initialization routine SYSINIT loads all of the resident
  14709.    device drivers. Then, it searches for a config.sys file on the boot disk.
  14710.    SYSINIT allocates memory for buffers and files, based on settings in the
  14711.    config.sys file or system default settings. If the config.sys file
  14712.    specifies any installable device drivers, these are installed next.
  14713.  
  14714.    Finally, SYSINIT executes the MS-DOS command processor, command.com.
  14715.  
  14716.  
  14717.  3.3  The Command Processor
  14718.  
  14719.    The command processor command.com consists of three parts:
  14720.  
  14721.    ■  A resident part resides in memory immediately following msdos.sys and
  14722.       its data area. This part contains routines to process Interrupts 22H
  14723.       (Terminate Process Exit Address), 23H (CONTROL+C Exit Address), and 24H
  14724.       (Critical-Error-Handler Address), as well as a routine to reload the
  14725.       transient part, if needed. All standard MS-DOS error handling is done
  14726.       within this part of command.com. This includes displaying error
  14727.       messages and processing the Abort, Retry, Fail, or Ignore messages.
  14728.  
  14729.    ■  An initialization part follows the resident part. During startup, the
  14730.       initialization part is given control; it contains the processor setup
  14731.       routine in the autoexec.bat file. The initialization part determines
  14732.       the segment address at which programs can be loaded, and because it is
  14733.       no longer needed, is overlaid by the first program that command.com
  14734.       loads.
  14735.  
  14736.    ■  A transient part is loaded at the high end of memory. This part
  14737.       contains all the internal command processors and the batch file
  14738.       processor.
  14739.  
  14740.       The transient part of the command processor produces the system prompt
  14741.       (A>, for example), reads commands from the keyboard (or from batch
  14742.       files), and causes them to be executed. For external commands, the
  14743.       transient part builds a command line and issues Function 4B00H (Load
  14744.       and Execute Program) to load and transfer control to the program.
  14745.  
  14746.  
  14747.  3.4  MS-DOS Disk Allocation
  14748.  
  14749.    The area on a disk partitioned for use by MS-DOS is formatted as follows:
  14750.  
  14751.    1. Reserved area──variable size
  14752.  
  14753.    2. First copy of File Allocation Table──variable size
  14754.  
  14755.    3. Additional copies of File Allocation Table──variable size (optional)
  14756.  
  14757.    4. Root directory──variable size
  14758.  
  14759.    5. File data area
  14760.  
  14761.    Space for a file in the data area is not preallocated. The space is
  14762.    allocated one cluster at a time. A cluster consists of one or more
  14763.    consecutive sectors (the number of sectors in a cluster must be a power of
  14764.    2); the cluster size is determined at format time. All the clusters for a
  14765.    file are "chained" together in the File Allocation Table, discussed in
  14766.    greater detail in Section 3.6, "File Allocation Table (FAT)." MS-DOS
  14767.    normally keeps a second copy of the FAT for consistency, except in the
  14768.    case of reliable storage such as a virtual RAM disk. Should the disk
  14769.    develop a bad sector in the middle of the first FAT, MS-DOS can use the
  14770.    second. This avoids loss of data due to an unreadable FAT.
  14771.  
  14772.  
  14773.  3.5  MS-DOS Disk Directory
  14774.  
  14775.    The format utility builds the root directory for all disks. This
  14776.    directory's location on the disk and the maximum number of entries are
  14777.    dependent on the media. Specifications for standard removable-disk formats
  14778.    are outlined later in this chapter. Notice, however, that MS-DOS regards
  14779.    directories, other than the root directory, as files, so there is no limit
  14780.    to the number of files that the subdirectories under the root directory
  14781.    may contain. All directory entries are 32 bytes in length and are in the
  14782.    following format (notice that byte offsets are in hexadecimal):
  14783.  
  14784.    Byte               Function
  14785.    ──────────────────────────────────────────────────────────────────────────
  14786.    0-7                Filename. Eight characters, left-aligned and padded, if
  14787.                       necessary, with blanks. The first byte of this field
  14788.                       indicates the file status as follows:
  14789.  
  14790. ╓┌─┌──────────────────┌─────────────────┌────────────────────────────────────╖
  14791.                       Byte              Status
  14792.    ──────────────────────────────────────────────────────────────────────────
  14793.                       00H               The directory entry has never been
  14794.                                         used. This is used to limit the
  14795.                                         length of directory searches, for
  14796.                                         performance reasons.
  14797.  
  14798.                       05H               The first character of the filename
  14799.                                         contains an E5H character.
  14800.  
  14801.                       2EH               The entry is for a directory. If the
  14802.                                         second byte is also 2EH, the cluster
  14803.                                         field contains the cluster number of
  14804.                                         this directory's parent directory
  14805.                                         (0000H if the parent directory is the
  14806.                                         root directory). Otherwise, bytes 01H
  14807.                       Byte              Status
  14808.    ──────────────────────────────────────────────────────────────────────────
  14809.                                        root directory). Otherwise, bytes 01H
  14810.                                         through 0AH are all spaces, and the
  14811.                                         cluster field contains the cluster
  14812.                                         number of this directory.
  14813.  
  14814.                       E5H               The file was used, but it has since
  14815.                                         been erased.
  14816.                       Any other character is the first character of a
  14817.                       filename.
  14818.  
  14819.    8-0A               Filename extension.
  14820.  
  14821.    0B                 File attribute. The attribute byte is mapped as follows
  14822.    ──────────────────────────────────────────────────────────────────────────
  14823.  
  14824.  
  14825. ╓┌─┌──────────────────┌─────────────────┌────────────────────────────────────╖
  14826.                       Byte              Contents
  14827.    ──────────────────────────────────────────────────────────────────────────
  14828.                       Byte              Contents
  14829.    ──────────────────────────────────────────────────────────────────────────
  14830.                       01H               File is marked read-only. An attempt
  14831.                                         to open the file for writing using
  14832.                                         Function 3DH (Open Handle) results
  14833.                                         in an error code being returned. This
  14834.                                         value can be used in programs along
  14835.                                         with the other attributes in this
  14836.                                         list. Attempts to delete the file
  14837.                                         with Function 13H (Delete File) or
  14838.                                         Function 41H (Delete Directory
  14839.                                         Entry) will also fail.
  14840.  
  14841.                       02H               Hidden file. The file is excluded
  14842.                                         from normal directory searches.
  14843.  
  14844.                       04H               System file. The file is excluded
  14845.                                         from normal directory searches.
  14846.                       08H               The entry contains the volume label
  14847.                                         in the first 11 bytes. The entry
  14848.                                         contains no other usable information
  14849.                       Byte              Contents
  14850.    ──────────────────────────────────────────────────────────────────────────
  14851.                                        contains no other usable information
  14852.                                         (except date and time of creation)
  14853.                                         and may exist only in the root
  14854.                                         directory.
  14855.  
  14856.                       10H               The entry defines a subdirectory and
  14857.                                         is excluded from normal directory
  14858.                                         searches.
  14859.  
  14860.                       20H               Archive bit. The bit is set to "on"
  14861.                                         whenever the file has been written to
  14862.                                         and closed.
  14863.  
  14864.                                         Note: The system files (io.sys and
  14865.                                         msdos.sys) are marked as read-only,
  14866.                                         hidden, and system files. Files can
  14867.                                         be marked hidden when they are
  14868.                                         created. Also, you may change the
  14869.                                         read-only, hidden, system, and
  14870.                       Byte              Contents
  14871.    ──────────────────────────────────────────────────────────────────────────
  14872.                                        read-only, hidden, system, and
  14873.                                         archive attributes through Function
  14874.                                         43H (Get/Set File Attributes).
  14875.    ──────────────────────────────────────────────────────────────────────────
  14876.  
  14877.  
  14878. ╓┌─┌──────────────────┌──────────────────────────────────────────────────────╖
  14879.    Byte               Function
  14880.    ──────────────────────────────────────────────────────────────────────────
  14881.    0C-15              Reserved.
  14882.  
  14883.    16-17              Time the file was created or last updated. The hour,
  14884.                       minutes, and seconds are mapped into two bytes as
  14885.                       follows (bit 7 on the left, 0 on the right):
  14886.  
  14887.                       Offset 17H
  14888.                       | H | H | H | H | H | M | M | M |
  14889.  
  14890.                       Offset 16H
  14891.    Byte               Function
  14892.    ──────────────────────────────────────────────────────────────────────────
  14893.                      Offset 16H
  14894.                       | M | M | M | S | S | S | S | S |
  14895.  
  14896.                       where:
  14897.  
  14898.  
  14899.                       H is the binary number of hours (0-23).
  14900.                       M is the binary number of minutes (0-59).
  14901.                       S is the binary number of two-second increments.
  14902.  
  14903.  
  14904.    18-19              Date the file was created or last updated. The year,
  14905.                       month, and day are mapped into two bytes as follows:
  14906.  
  14907.                       Offset 19H
  14908.                       | Y | Y | Y | Y | Y | Y | Y | M |
  14909.  
  14910.                       Offset 18H
  14911.                       | M | M | M | D | D | D | D | D |
  14912.    Byte               Function
  14913.    ──────────────────────────────────────────────────────────────────────────
  14914.                      | M | M | M | D | D | D | D | D |
  14915.  
  14916.                       where:
  14917.  
  14918.  
  14919.                       Y is the year, 0-119 (1980-2099).
  14920.                       M is the month (1-12).
  14921.                       D is the day of the month (1-31).
  14922.    ──────────────────────────────────────────────────────────────────────────
  14923.  
  14924.  
  14925.    Byte               Function
  14926.    ──────────────────────────────────────────────────────────────────────────
  14927.    1A-1B              Starting cluster; the number of the first cluster in
  14928.                       the file.
  14929.  
  14930.                       ■ Notice that the first cluster for data space on all
  14931.                       disks is cluster 002.
  14932.  
  14933.                       ■ The cluster number is stored with the least
  14934.                       significant byte first.
  14935.  
  14936.                       ■ For details about converting cluster numbers to
  14937.                       logical sector numbers, see Sections 3.6.1 and 3.6.2.
  14938.  
  14939.    1C-1F              File size in bytes. The first word of this four-byte
  14940.    ──────────────────────────────────────────────────────────────────────────
  14941.  
  14942.  
  14943.  3.6  File Allocation Table (FAT)
  14944.  
  14945.    This section explains how MS-DOS allocates disk space in the data area for
  14946.    a file by using the File Allocation Table to convert the clusters of a
  14947.    file to logical sector numbers. The device driver is then responsible for
  14948.    locating the logical sector on the disk. Programs should use the MS-DOS
  14949.    file management function calls for accessing files. Programs that access
  14950.    the FAT are not guaranteed to be upwardly-compatible with future releases
  14951.    of MS-DOS. The following information is useful to system programmers who
  14952.    wish to write installable device drivers.
  14953.  
  14954.    The File Allocation Table is an array of 12-bit entries (1.5 bytes) for
  14955.    each cluster on the disk. For disks containing more than 4085 clusters, a
  14956.    16-bit FAT entry is used.
  14957.  
  14958.    The first two FAT entries are reserved; however, the device driver may use
  14959.    the first byte as a FAT ID byte for determining media. For hard disks, the
  14960.    value of this byte is F8H. See Tables 3.1 and 3.2 for the media byte
  14961.    descriptors used for 8-inch, 5.25-inch, and 3.5-inch disks.
  14962.  
  14963.    The third FAT entry, which starts at byte offset 4, begins the mapping of
  14964.    the data area (cluster 002). The operating system does not always
  14965.    sequentially write (to the disk) files in the data area. Instead, the
  14966.    system allocates the data area one cluster at a time, skipping over
  14967.    clusters it has already allocated. The first free cluster following the
  14968.    last cluster allocated for that file is the next cluster allocated,
  14969.    regardless of its physical location on the disk. This permits the most
  14970.    efficient use of disk space, since if you erase old files, you can free
  14971.    clusters, which the operating system can then allocate for new files. Each
  14972.    FAT entry contains three or four hexadecimal characters, depending on
  14973.    whether it is a 12-bit or 16-bit entry:
  14974.  
  14975.    Entry              Contents
  14976.    ──────────────────────────────────────────────────────────────────────────
  14977.    (0)000             If the cluster is unused and available.
  14978.  
  14979.    (F)FF7             The cluster has a bad sector in it if it is not part of
  14980.                       any cluster chain. MS-DOS will not allocate such a
  14981.                       cluster. So for its report, the chkdsk command counts
  14982.                       the number of bad clusters, which are not part of any
  14983.                       allocation chain.
  14984.  
  14985.    (F)FF8-FFF         The last cluster of a file.
  14986.  
  14987.    (X)XXX             Any other characters that are the cluster number of the
  14988.                       next cluster in the file. The number of the first
  14989.    ──────────────────────────────────────────────────────────────────────────
  14990.  
  14991.    The File Allocation Table always begins on the first sector after the
  14992.    reserved sectors. If the FAT is larger than one sector, the sectors are
  14993.    contiguous. The operating system usually writes two copies of the FAT to
  14994.    preserve data integrity. MS-DOS reads the FAT into one of its buffers,
  14995.    whenever needed (open, read, write, etc.). The operating system also gives
  14996.    this buffer a high priority to keep it in memory as long as possible.
  14997.  
  14998.  3.6.1  How to Use the FAT (12-Bit FAT Entries)
  14999.  
  15000.    To get the starting cluster of a file, examine its directory entry (in the
  15001.    FAT). Then, to locate each subsequent cluster of the file, follow these
  15002.    steps:
  15003.  
  15004.    1. Multiply the cluster number just used by 1.5 (each FAT entry is 1.5
  15005.       bytes in length).
  15006.  
  15007.    2. The whole part of the product is an offset into the FAT, pointing to
  15008.       the entry that maps the cluster just used. That entry contains the
  15009.       cluster number of the next cluster of the file.
  15010.  
  15011.    3. Use a MOV instruction to move the word at the calculated FAT offset
  15012.       into a register.
  15013.  
  15014.    4. If the last cluster used was an even number, keep the low-order 12 bits
  15015.       of the register by using the AND operator with 0FFFH and the register.
  15016.       If the last cluster used was an odd number, keep the high-order 12 bits
  15017.       by using the SHR instruction to shift the register right four bits.
  15018.  
  15019.    5. If the resultant 12 bits are 0FF8H-0FFFH, the file contains no more
  15020.       clusters. Otherwise, the 12 bits contain the number of the next cluster
  15021.       in the file.
  15022.  
  15023.    To convert the cluster to a logical sector number (relative sector, such
  15024.    as that used by Interrupts 25H and 26H (Absolute Disk Read/Write) and by
  15025.    debug), follow these steps:
  15026.  
  15027.    1. Subtract two from the cluster number.
  15028.  
  15029.    2. Multiply the result by the number of sectors per cluster.
  15030.  
  15031.    3. To this result, add the logical sector number of the beginning of the
  15032.       data area.
  15033.  
  15034.  3.6.2  How to Use the FAT (16-Bit FAT Entries)
  15035.  
  15036.    To get the starting cluster of a file, examine its directory entry (in the
  15037.    FAT). Then, to find the next file cluster, follow these steps:
  15038.  
  15039.    1. Multiply the cluster number last used by 2 (each FAT entry is 2 bytes).
  15040.  
  15041.    2. Use a MOV WORD instruction to move the word at the calculated FAT
  15042.       offset into a register.
  15043.  
  15044.    3. If the resultant 16 bits are 0FFF8-0FFFH, no more clusters are in the
  15045.       file. Otherwise, the 16 bits contain the number of the next cluster in
  15046.       the file.
  15047.  
  15048.  
  15049.  3.7  MS-DOS Standard Disk Formats
  15050.  
  15051.    MS-DOS arranges data clusters on a disk to minimize head movement. MS-DOS
  15052.    then allocates all the space on one track (or cylinder) before moving to
  15053.    the next. It uses the sequential sectors on the lowest-numbered head, then
  15054.    all the sectors on the next head, and so on, until it has used all the
  15055.    sectors on all the heads of the track.
  15056.  
  15057.    The size of the MS-DOS partition on a hard disk determines the size of the
  15058.    FAT and root directory. Likewise, the type of floppy disk (tracks per
  15059.    side, sectors per track, etc.) determines how MS-DOS uses the disk. The
  15060.    removable disk formats listed in Tables 3.1 and 3.2 are standard and
  15061.    should be readable in the appropriate standard drive.
  15062.  
  15063.    Table 3.1
  15064.    MS-DOS Standard Removable-Disk Formats
  15065.    Disk Size in inches               5.25                         8
  15066.    ──────────────────────────────────────────────────────────────────────────
  15067.    WORD no. heads                  1     1     2    2           1    2      1
  15068.    Tracks/side                    40    40    40   40          77   77     77
  15069.    WORD sectors/track              8     9     8    9          26   26      8
  15070.    WORD bytes/sector             512   512   512  512         128  128    024
  15071.    BYTE sectors/ cluster           1     1     2    2           4    4      1
  15072.    WORD reserved sectors           1     1     1    1           1    4      1
  15073.    Byte no. FATs                   2     2     2    2           2    2      2
  15074.    WORD root directory entries    64    64   112  112          68   68    192
  15075.    WORD no. sectors              320   360   640  720        2002 2002    616
  15076.    BYTE media descriptor          FE    FC    FF   FD         FE   FD    FE
  15077.    WORD sectors/FAT                1     2     1    2           6    6      2
  15078.    WORD no. hidden sectors         0     0     0    0           0    0      0
  15079.    ──────────────────────────────────────────────────────────────────────────
  15080.  
  15081.    Table 3.2
  15082.    MS-DOS Standard Removable-Disk Formats (High-Density)
  15083.    Disk Size in inches                  3.5 or 5.25            3.5      5.25
  15084.    ──────────────────────────────────────────────────────────────────────────
  15085.    WORD no. heads                  1     2     2    2           2           2
  15086.    ──────────────────────────────────────────────────────────────────────────
  15087.    Tracks/side                    80    80    80   80          80          80
  15088.    WORD sectors/track              8     9     8    9          18          15
  15089.    WORD bytes/sector             512   512   512  512         512         512
  15090.    BYTE sectors/cluster            2     2     2    2           1           1
  15091.    WORD reserved sectors           1     1     1    1           1           1
  15092.    BYTE no. FATs                   2     2     2    2           2           2
  15093.    WORD root dir entries         112   112   112  112         224         224
  15094.    WORD no. sectors              640   720  1280 1440        2880        2400
  15095.    BYTE media descriptor         FA    FC    FB   F9          F0          F9
  15096.    WORD sectors/FAT                1     2     2    3           9           7
  15097.    WORD no. hidden sectors         0     0     0    0           0           0
  15098.    ──────────────────────────────────────────────────────────────────────────
  15099.  
  15100.  
  15101.  
  15102.  ────────────────────────────────────────────────────────────────────────────
  15103.  Chapter 4  MS-DOS Control Blocks and Work Areas
  15104.  
  15105.      4.1   Introduction
  15106.      4.2   Typical Contents of an MS-DOS Memory Map
  15107.      4.3   The MS-DOS Program Segment
  15108.  
  15109.  
  15110.  4.1  Introduction
  15111.  
  15112.    This chapter describes a typical MS-DOS memory map and explains how a
  15113.    program is loaded into memory. It also describes the structure of an
  15114.    MS-DOS program segment and the contents of segment registers for .exe and
  15115.    .com program files.
  15116.  
  15117.  
  15118.  4.2  Typical Contents of an MS-DOS Memory Map
  15119.  
  15120.    A typical MS-DOS memory map contains the following information:
  15121.  
  15122.      ┌─────────────────────────────────────────────────────┐
  15123.      │             ROM and Video Buffers                   │
  15124.      ├─────────────────────────────────────────────────────┤
  15125.      │          Transient Part of COMMAND.COM              │
  15126.      ├─────────────────────────────────────────────────────┤
  15127.      │                                                     │
  15128.      │                                                     │
  15129.      │                                                     │
  15130.      │                                                     │
  15131.      │              Transient Program Area                 │
  15132.      ├─────────────────────────────────────────────────────┤
  15133.      │                                                     │
  15134.      │                                                     │
  15135.      │                                                     │
  15136.      │                                                     │
  15137.      │          External Commands and Utilities            │
  15138.      │                                                     │
  15139.      ├─────────────────────────────────────────────────────┤
  15140.      │           Resident Part of COMMAND.COM              │
  15141.      ├─────────────────────────────────────────────────────┤
  15142.      │ MS-DOS buffers, control areas, & installed drivers  │
  15143.      ├─────────────────────────────────────────────────────┤
  15144.      │                                                     │
  15145.      │                MSDOS.SYS                            │
  15146.      ├─────────────────────────────────────────────────────┤
  15147.      │        IO.SYS and resident device drivers           │
  15148.      ├─────────────────────────────────────────────────────┤
  15149.      │                 Interrupt Vectors                   │
  15150.    0 └─────────────────────────────────────────────────────┘
  15151.  
  15152.    During system initialization, MS-DOS loads the io.sys and msdos.sys files
  15153.    into low memory (Notice that in MS-DOS 4.0, the msdos.sys file is not
  15154.    required to be written contiguously to the disk). The io.sys system file
  15155.    is the MS-DOS interface to hardware. The msdos.sys system file includes
  15156.    MS-DOS interrupt handlers and service routines (Interrupt 21H functions).
  15157.  
  15158.    Next, the system initialization routine loads the resident and installable
  15159.    device drivers. Above the installable device drivers, MS-DOS writes the
  15160.    resident part of command.com. This part includes interrupt handlers for
  15161.    Interrupts 22H (Terminate Process Exit Address), 23H (CONTROL+C Handler
  15162.    Address), 24H (Critical-Error-Handler Address) and code to reload the
  15163.    transient part. The transient part of command.com is reloaded into high
  15164.    memory. It includes the command interpreter, the internal MS-DOS commands,
  15165.    and the batch processor.
  15166.  
  15167.    External command and utility (.com and .exe) files are loaded into the
  15168.    transient program area. MS-DOS also allocates 256 bytes of user stack used
  15169.    with .com files. User memory is allocated from the lowest end of available
  15170.    memory that fulfills the allocation request.
  15171.  
  15172.  
  15173.  4.3  The MS-DOS Program Segment
  15174.  
  15175.    When you type an external command or execute a program through Function
  15176.    4B00H or 4B03H (Load and Execute Program or Overlay, also called EXEC),
  15177.    MS-DOS determines the lowest available free memory address to use as the
  15178.    start of the program. The memory starting at this address is called the
  15179.    Program Segment.
  15180.  
  15181.    The EXEC system call sets up the first 256 bytes of the Program Segment
  15182.    for the program being loaded into memory. The program is then loaded
  15183.    following this block. A .exe file with minalloc and maxalloc both set to
  15184.    zero is loaded as high as possible.
  15185.  
  15186.    At offset 0 within the Program Segment, MS-DOS builds the Program Segment
  15187.    Prefix control block. The program returns from EXEC by one of five
  15188.    methods:
  15189.  
  15190.    ■  By issuing an Interrupt 21H with AH=4CH (End Process)
  15191.  
  15192.    ■  By issuing an Interrupt 21H with AH=31H (Keep Process)
  15193.  
  15194.    ■  By a long jump to offset 0 in the Program Segment Prefix
  15195.  
  15196.    ■  By issuing an Interrupt 20H (Progam Terminate) with CS:0 pointing at
  15197.       the PSP
  15198.  
  15199.    ■  By issuing an Interrupt 21H with register AH=0 and with CS:0 pointing
  15200.       at the PSP
  15201.  
  15202.    ──────────────────────────────────────────────────────────────────────────
  15203.    Note
  15204.      The first two methods are preferred for functionality, compatibility,
  15205.      and efficiency in future versions of MS-DOS.
  15206.    ──────────────────────────────────────────────────────────────────────────
  15207.  
  15208.    All five methods transfer control to the program that issued the EXEC
  15209.    call. The first two methods return a completion code. They also restore
  15210.    the addresses of Interrupts 22H, 23H, and 24H (Terminate Process Exit
  15211.    Address, CONTROL+C Handler Address, and Critical-Error-Handler Address)
  15212.    from the values saved in the Program Segment Prefix of the terminating
  15213.    program. Control then passes to the terminate address.
  15214.  
  15215.    If a program returns to command.com, control transfers to the resident
  15216.    portion. If the program is a batch file (in process), it continues.
  15217.    Otherwise, command.com performs a checksum on the transient part, reloads
  15218.    it if necessary, issues the system prompt, and waits for you to type
  15219.    another command.
  15220.  
  15221.    When a program receives control, the following conditions are in effect:
  15222.  
  15223.    For All Programs:
  15224.  
  15225.    ■  The segment address of the passed environment is at offset 2CH in the
  15226.       Program Segment Prefix.
  15227.  
  15228.    ■  The environment is a series of ASCII strings (totaling less than 32K)
  15229.       in the form:
  15230.  
  15231.       NAME=parameter
  15232.  
  15233.  
  15234.    ■  A byte of zeros terminates each string, and another byte of zeros
  15235.       terminates the set of strings.
  15236.  
  15237.       Following the last byte of zeros is a set of initial arguments that the
  15238.       operating system passes to a program. This set of arguments contains a
  15239.       word count followed by an ASCII string. If the file is in the current
  15240.       directory, the ASCII string contains the drive and pathname of the
  15241.       executable program as passed to the EXEC function call. If the file is
  15242.       not in the current directory, EXEC concatenates the name of the file
  15243.       with the name of the path. Programs may use this area to determine
  15244.       where the program was loaded.
  15245.  
  15246.    ■  The environment built by the command processor contains at least a
  15247.       comspec=string (the parameters on comspec define the path that MS-DOS
  15248.       uses to locate command.com on the disk). The last path and prompt
  15249.       commands issued are also in the environment, along with any environment
  15250.       strings you have defined with the MS-DOS set command.
  15251.  
  15252.    ■  EXEC passes a copy of the invoking process environment. If your
  15253.       application uses a "keep process" concept, you should be aware that the
  15254.       copy of the environment passed to you is static. That is, it will not
  15255.       change even if you issue subsequent set, path, or prompt commands.
  15256.       Conversely, any modification of the passed environment by the
  15257.       application is not reflected in the parent process environment. For
  15258.       instance, a program cannot change the MS-DOS environment values as the
  15259.       set command does.
  15260.  
  15261.    ■  The Disk Transfer Address (DTA) is set to 80H (default DTA in the
  15262.       Program Segment Prefix). The Program Segment Prefix contains file
  15263.       control blocks at 5CH and 6CH. MS-DOS formats these blocks using the
  15264.       first two parameters that you typed when entering the command. If
  15265.       either parameter contained a pathname, then the corresponding FCB
  15266.       contains only the valid drive number. The filename field is not valid.
  15267.  
  15268.    ■  An unformatted parameter area at 81H contains all the characters typed
  15269.       after the command (including leading and embedded delimiters), with the
  15270.       byte at 80H set to the number of characters. If you type <, >, or
  15271.       parameters on the command line, they do not appear in this area (nor
  15272.       the filenames associated with them). Redirection of standard input and
  15273.       output is transparent to applications.
  15274.  
  15275.    ■  Register AX indicates whether the drive specifiers (entered with the
  15276.       first two parameters) are valid, as follows:
  15277.  
  15278.       AL=FF if the first parameter contained an invalid drive specifier
  15279.       (otherwise AL=00)
  15280.  
  15281.       AH=FF if the second parameter contained an invalid drive specifier
  15282.       (otherwise AH=00)
  15283.  
  15284.    ■  Offset 2 (one word) contains the segment address of the first byte of
  15285.       unavailable memory. Programs must not modify addresses beyond this
  15286.       point unless these addresses were obtained by allocating memory via
  15287.       Function 48H (Allocate Memory).
  15288.  
  15289.    For Executable (.exe) Programs:
  15290.  
  15291.    ■  DS and ES registers point to the Program Segment Prefix.
  15292.  
  15293.    ■  CS,IP,SS, and SP registers contain the values that Microsoft link sets
  15294.       in the .exe image.
  15295.  
  15296.    For Executable (.com) Programs:
  15297.  
  15298.    ■  All four segment registers contain the segment address of the initial
  15299.       allocation block that starts with the Program Segment Prefix control
  15300.       block.
  15301.  
  15302.    ■  .com programs allocate all of user memory. If the program invokes
  15303.       another program through Function 4B00H or 4B03H (EXEC), it must first
  15304.       free some memory through Function 4AH (Set Block) to provide space for
  15305.       the program being executed.
  15306.  
  15307.    ■  The Instruction Pointer (IP) is set to 100H.
  15308.  
  15309.    ■  The Stack Pointer register is set to the end of the program's segment.
  15310.  
  15311.    ■  A .com program places a word of zeros on top of the stack. Then, by
  15312.       doing a RET instruction last, your program can exit to command.com.
  15313.       This method assumes, however, that you have maintained your stack and
  15314.       code segments.
  15315.  
  15316.    Figure 4.1 illustrates the format of the Program Segment Prefix. All
  15317.    offsets are in hexadecimal.
  15318.  
  15319.                          (Offsets in Hex)
  15320.    0 ┌─────────────┬─────────────┬─────────────────────────────┐
  15321.      │             │ End of      │                             │
  15322.      │   INT 20H   │ alloc.      │        Reserved             │
  15323.      │             │ block       │         04H                 │
  15324.    8 ├─────────────┼─────────────┴──────────┬──────────────────┤
  15325.      │             │   Terminate address    │   CONTROL+C exit │
  15326.      │  Reserved   │       (IP, CS)         │   address (IP)   │
  15327.      │             │                        │                  │
  15328.    10├────────────┬┴────────────────────────┼──────────────────┤
  15329.      │CONTROL+C   │ Hard error exit address │                  │
  15330.      │exit        │       (IP, CS)          │                  │
  15331.      │address (CS)│                         │                  │
  15332.      ├────────────┴─────────────────────────┘                  │
  15333.      │                                                         │
  15334.      │                   Used by MS-DOS                        │
  15335.      │                                                         │
  15336.      │                         5CH                             │
  15337.      │                                                         │
  15338.      ├─────────────────────────────────────────────────────────┤
  15339.      │                                                         │
  15340.      │    Formatted Parameter Area 1 formatted as standard     │
  15341.      │                    unopened FCB 6CH                     │
  15342.      ├─────────────────────────────────────────────────────────┤
  15343.      │                                                         │
  15344.      │    Formatted Parameter Area 2 formatted as standard     │
  15345.      │     unopened FCB (overlaid if FCB at 5CH is opened)     │
  15346.    80├─────────────────────────────────────────────────────────┤
  15347.      │             Unformatted Parameter Area                  │
  15348.      │            (default Disk Transfer Area)                 │
  15349.      │       Initially contains command invocation line.       │
  15350.      └─────────────────────────────────────────────────────────┘
  15351.    100
  15352.  
  15353.    Figure 4.1  Program Segment Prefix
  15354.  
  15355.    ──────────────────────────────────────────────────────────────────────────
  15356.    Important
  15357.      Programs must not alter any part of the Program Segment Prefix below
  15358.      offset 5CH.
  15359.    ──────────────────────────────────────────────────────────────────────────
  15360.  
  15361.  
  15362.  
  15363.  ────────────────────────────────────────────────────────────────────────────
  15364.  Chapter 5  National Language Support
  15365.  
  15366.      5.1   Introduction
  15367.      5.2   National Language Support Calls
  15368.      5.3   Font Files
  15369.            5.3.1   Font File Structure
  15370.  
  15371.  
  15372.  5.1  Introduction
  15373.  
  15374.    National language support for this version of MS-DOS 4.0 includes these
  15375.    major features:
  15376.  
  15377.    ■  Country-dependent information
  15378.  
  15379.    ■  Support for national keyboard layouts
  15380.  
  15381.    ■  Programming interfaces for national language support
  15382.  
  15383.    ■  Utility commands
  15384.  
  15385.    Country-dependent information is available on a per-country basis and
  15386.    includes the following:
  15387.  
  15388.    ■  Time, date, and currency
  15389.  
  15390.    ■  Lowercase-to-uppercase character-conversion tables
  15391.  
  15392.    ■  Collating sequence for character sorting
  15393.  
  15394.    ■  Valid single-byte characters used in filenames
  15395.  
  15396.    Selectable keyboard support for different keyboard layouts is provided.
  15397.  
  15398.    The MS-DOS 4.0 programming interfaces for national language support allow
  15399.    applications to use the country-dependent information just described. To
  15400.    access this information, applications do not need to change the current
  15401.    country code of the system.
  15402.  
  15403.    Utility commands allow the user to select the keyboard layout and system
  15404.    country code.
  15405.  
  15406.    This version of MS-DOS does not support right-to-left national languages.
  15407.  
  15408.  
  15409.  5.2  National Language Support Calls
  15410.  
  15411.    The following function calls allow an application to tailor its operation
  15412.    to the current country code and to accept or change the current code page.
  15413.    A country code defines the country in which you live or work. MS-DOS uses
  15414.    this code to prepare and assign default code pages for your system. A code
  15415.    page is a table that defines the character set you are using. A character
  15416.    set is a country-specific or language-specific group of characters that
  15417.    are translated from the code page table and displayed on your screen or
  15418.    printer. Each code page character set contains 256 characters. The
  15419.    following function calls are also used by MS-DOS 4.0 to support the
  15420.    National Language requirements:
  15421.  
  15422.    ■  Function 440CH (Generic IOCtl) ── supports code page switching on a
  15423.       per-device basis.
  15424.  
  15425.    ■  Function 65H (Get Extended Country Information) ── returns standard
  15426.       country information and points to related case-map or collating tables.
  15427.  
  15428.    ■  Function 66H (Get/Set Global Code Page) ── gets or sets the code page
  15429.       used by the kernel and by all devices.
  15430.  
  15431.    These functions support access to country-dependent information, all of
  15432.    which resides in one file named country.sys.
  15433.  
  15434.  
  15435.  5.3  Font Files
  15436.  
  15437.    Font files, also called code page information files, contain the images of
  15438.    code page character sets for use by display or printer devices. These font
  15439.    files are identified by a filename extension of .cpi. Four font files are
  15440.    included with MS-DOS 4.0:
  15441.  
  15442.    Font file          Supported device
  15443.    ──────────────────────────────────────────────────────────────────────────
  15444.    ega.cpi            Color console used with an EGA card
  15445.  
  15446.    lcd.cpi            Liquid crystal display
  15447.  
  15448.    4201.cpi           IBM 4201 Proprinter family and IBM 4202 Proprinter
  15449.                       printers
  15450.  
  15451.    4208.cpi           IBM 4207 Proprinter X24 and IBM 4208 Proprinter XL24
  15452.                       printers
  15453.  
  15454.    5202.cpi           IBM 5202 Quietwriter III printer
  15455.    ──────────────────────────────────────────────────────────────────────────
  15456.  
  15457.  5.3.1  Font File Structure
  15458.  
  15459.    The contents of printer or display font files are structured as follows:
  15460.  
  15461.    ┌──────────────────────────────────────┐
  15462.    │ 23-BYTE File Header                  │
  15463.    ├──────────────────────────────────────┤
  15464.    │ WORD Information Header              │
  15465.    ├──────────────────────────────────────┤
  15466.    │ 28-BYTE Code Page Entry Header(s)    │
  15467.    ├──────────────────────────────────────┤
  15468.    │ Variable size Font Data Block(s)     │
  15469.    ├──────────────────────────────────────┤
  15470.    │ 150-BYTE Copyright Notice            │
  15471.    └──────────────────────────────────────┘
  15472.  
  15473.  
  15474.    Figure 5.1  Font File Structure
  15475.  
  15476.    The first code page entry header immediately follows the information
  15477.    header. The copyright notice is always at the end of the file. Between
  15478.    these, the file consists of arbitrarily intermingled code page entry
  15479.    headers and font data blocks.
  15480.  
  15481.    The font file fields are described in the following sections.
  15482.  
  15483.    File Header
  15484.  
  15485.    Each file must begin with a file header. There is only one of these
  15486.    headers per file. This header identifies the file as a valid font file and
  15487.    has the following format:
  15488.  
  15489.    Length             Parameter
  15490.    ──────────────────────────────────────────────────────────────────────────
  15491.    8 BYTES            File tag
  15492.    8 BYTES            Reserved
  15493.    WORD               Number of pointers
  15494.    BYTE               Type of pointer
  15495.    2 WORDS            Offset
  15496.    ──────────────────────────────────────────────────────────────────────────
  15497.  
  15498.    where:
  15499.  
  15500.    File tag begins with the byte 0FFH and is followed by the seven-byte
  15501.    string "font."
  15502.  
  15503.    Reserved is eight bytes of zeros.
  15504.  
  15505.    Number of pointers is the number of information pointers in the header.
  15506.    For MS-DOS 4.0, the value of this word should be 1.
  15507.  
  15508.    Type of pointer is the type of information pointers in the header. For
  15509.    MS-DOS 4.0, the value of this word should be 1.
  15510.  
  15511.    Offset is the offset, in bytes, from the beginning of the file to the
  15512.    information header.
  15513.  
  15514.    Information Header
  15515.  
  15516.    The information header begins at the offset given in the file header. It
  15517.    describes how many code pages are contained in the font file. The format
  15518.    of this one-word information header is:
  15519.  
  15520.    Length             Parameter
  15521.    ──────────────────────────────────────────────────────────────────────────
  15522.    WORD               Number of code pages
  15523.    ──────────────────────────────────────────────────────────────────────────
  15524.  
  15525.    where:
  15526.  
  15527.    Number of code pages is the number of code page entries in the file.
  15528.  
  15529.    Code Page Entry Header
  15530.  
  15531.    The number of code page entries in a font file is defined in the preceding
  15532.    section, "Information Header." For each code page in the font file, there
  15533.    is a code page entry header that gives general information about that code
  15534.    page entry in the file. The header has the following format:
  15535.  
  15536.    Length             Parameter
  15537.    ──────────────────────────────────────────────────────────────────────────
  15538.    WORD               Length
  15539.    2 WORDS            Pointer
  15540.    WORD               Device type
  15541.    8 BYTES            Device subtype
  15542.    WORD               Code page ID
  15543.    3 WORDS            Reserved
  15544.    2 WORDS            Offset
  15545.    ──────────────────────────────────────────────────────────────────────────
  15546.  
  15547.    where:
  15548.  
  15549.    Length is the size of the code page entry header. Since this header is a
  15550.    fixed size, it can be used for testing if the font file has been read in
  15551.    correctly.
  15552.  
  15553.    Pointer is a two-word pointer to the next code page entry header. The last
  15554.    header will point to nothing and will have a value of 0,0.
  15555.  
  15556.    Device type is 1 if the device is a raster display, or 2 if the device is
  15557.    a printer.
  15558.  
  15559.    Device subtype names the type of display or printer. This field also
  15560.    determines the name of the font file. For example, if the subtype is
  15561.    "EGA," the font file name is ega.cpi
  15562.  
  15563.    Code page ID defines a valid three-digit code page identification number.
  15564.    Valid code page numbers are 437, 850, 860, 863, and 865.
  15565.  
  15566.    Reserved is three words of zeros.
  15567.  
  15568.    Offset is a double-word pointer to the font data block associated with
  15569.    this code page and described in the next section.
  15570.  
  15571.    Font Data Block
  15572.  
  15573.    The Font Data Block consists of the following fields:
  15574.  
  15575.    ┌─────────────────────────────────────────┐
  15576.    │   6-BYTE Font Data Header               │
  15577.    ├─────────────────────────────────────────┤
  15578.    │   Variable length Font Description(s)   │
  15579.    └─────────────────────────────────────────┘
  15580.  
  15581.    The code page of a font data block is specified by the code page entry
  15582.    header whose Offset field points to that font data block. The device type
  15583.    contained in this code page entry header determines whether the font
  15584.    description(s) should be interpreted as raster-style (display) fonts or
  15585.    escape code sequences for particular downloadable device (printer) fonts.
  15586.  
  15587.    The Font Data Header, the Display Font Description, and the Printer Font
  15588.    Description fields are described in the following sections.
  15589.  
  15590.    Font Data Header:
  15591.  
  15592.    The Font Data Header indicates how many font descriptions exist for the
  15593.    current code page. This header has the following fields:
  15594.  
  15595.    Length             Parameter
  15596.    ──────────────────────────────────────────────────────────────────────────
  15597.    WORD               Reserved
  15598.    WORD               Number of fonts
  15599.    WORD               Length of font data
  15600.    ──────────────────────────────────────────────────────────────────────────
  15601.  
  15602.    where:
  15603.  
  15604.    Reserved must be 1.
  15605.  
  15606.    Number of fonts specifies the number of fonts (font descriptions) that
  15607.    immediately follow this font data header. These font descriptions are all
  15608.    associated with the font data block's code page. For printer devices, the
  15609.    number of fonts must be equal to one.
  15610.  
  15611.    Length of font data is equal to the sum of the sizes (in bytes) of the
  15612.    font descriptions, as described in the next two sections.
  15613.  
  15614.    Display Font Description:
  15615.  
  15616.    Each font description for a display device begins with a header that
  15617.    specifies the raster dimensions of each character in the font and the
  15618.    number of characters in the font. This is followed by the raster bitmaps
  15619.    for each character. The actual fields are:
  15620.  
  15621.    Length             Parameter
  15622.    ──────────────────────────────────────────────────────────────────────────
  15623.    BYTE               Height
  15624.    BYTE               Width
  15625.    BYTE               Relative height
  15626.    BYTE               Relative width
  15627.    WORD               Number of characters
  15628.    Variable           Bitmap
  15629.    ──────────────────────────────────────────────────────────────────────────
  15630.  
  15631.    where:
  15632.  
  15633.    Height is the number of rows in pixels that this character occupies on the
  15634.    screen. Width is the number of columns in pixels that this character
  15635.    occupies on the screen.
  15636.  
  15637.    Relative height is part of the aspect ratio. This is currently unused
  15638.    (zero).
  15639.  
  15640.    Relative width is part of the aspect ratio. This is currently unused
  15641.    (zero).
  15642.  
  15643.    Number of characters is the number of characters that are defined in the
  15644.    bitmap immediately following this header. Normally, the entire ASCII
  15645.    character set is defined, so that this value is usually 256.
  15646.  
  15647.    Bitmap is a sequence of bitmaps, one for each character in the font. Each
  15648.    character bitmap is a packed array of bits organized in rows by columns,
  15649.    starting at the upper left corner of the character's image. Since all
  15650.    current display fonts are eight bits wide, the number of bytes needed to
  15651.    encode this packed array is simply equal to the square area of a character
  15652.    in the font divided by 8 (the number of bits per byte).
  15653.  
  15654.    The total length of the display font description is six bytes plus the
  15655.    product of the number of characters in the descriptions and the number of
  15656.    bytes needed to encode a character bitmap.
  15657.  
  15658.    Printer Font Description:
  15659.  
  15660.    There are two formats for printer font descriptions. These vary only in
  15661.    the number of control sequences present in the font description.
  15662.  
  15663.    Unlike the display font description, the number of bytes in the printer
  15664.    font description cannot be directly determined. Instead, the size of the
  15665.    printer font description must be calculated from the font header's length
  15666.    value. As a result, only one printer font description can be contained in
  15667.    a given font data block (otherwise, the point at which the first ended and
  15668.    the second printer font description began could not be determined).
  15669.  
  15670.    The format for the printer font desription is:
  15671.  
  15672.    Length             Parameter
  15673.    ──────────────────────────────────────────────────────────────────────────
  15674.    WORD               Selection type
  15675.    WORD               Control sequence length
  15676.    Variable           Control sequence data
  15677.    Variable           Downloadable font data
  15678.    ──────────────────────────────────────────────────────────────────────────
  15679.  
  15680.    where:
  15681.  
  15682.    Selection type is either 1 or 2. It identifies which of the two formats
  15683.    for the printer font description is being used. These existing printer
  15684.    files use the following selection types:
  15685.  
  15686.       Selection type    Printer font file
  15687.       ───────────────────────────────────────────────────────────────────────
  15688.       1                 4201.cpi
  15689.       2                 4208.cpi
  15690.       2                 5202.cpi
  15691.       ───────────────────────────────────────────────────────────────────────
  15692.  
  15693.    Control sequence length is the number of bytes the control sequence data
  15694.    field takes. This length must always be less than 31 (bytes).
  15695.  
  15696.    Control sequence data is used for initializing the printer with this code
  15697.    page. The size of this field is defined in the control sequence length
  15698.    field.
  15699.  
  15700.    If the selection type field is 2, this control sequence information
  15701.    consists of a single escape sequence that selects the font for this code
  15702.    page (this font may have been downloaded).
  15703.  
  15704.    If the selection type field is 1, this control sequence information is
  15705.    further divided into two escape sequences. In this case, the control
  15706.    sequence data field consists of:
  15707.  
  15708.       Length            Parameter
  15709.       ───────────────────────────────────────────────────────────────────────
  15710.       BYTE              Hardware sequence length
  15711.       Variable          Hardware sequence
  15712.       BYTE              Downloadable sequence length
  15713.       Variable          Downloadable sequence
  15714.       ───────────────────────────────────────────────────────────────────────
  15715.  
  15716.        where:
  15717.  
  15718.        Hardware sequence length is the number of bytes contained in the
  15719.        hardware sequence.
  15720.  
  15721.        Hardware sequence is the escape sequence that selects the hardware
  15722.        (default) font of the printer.
  15723.  
  15724.        Downloadable sequence length is the number of bytes contained in the
  15725.        downloadable sequence.
  15726.  
  15727.        Downloadable sequence is the escape sequence that selects the
  15728.        downloaded font currently resident in the printer.
  15729.  
  15730.        Notice that the total number of bytes in these subfields must be equal
  15731.        to the number of bytes given by the control sequence length field in
  15732.        the printer font description.
  15733.  
  15734.    Downloadable font data consists of the escape sequence required to
  15735.    download the font description. This escape sequence is highly printer
  15736.    specific. The number of bytes in it is determined by subtracting the size
  15737.    of the initial portion of the printer font description from the Length
  15738.    field of the font data block.
  15739.  
  15740.    Since the 4208 and 5202 printers have hardware support for code pages,
  15741.    they do not need any font data to be downloaded. Therefore, this field is
  15742.    nonexistent in those font files.
  15743.  
  15744.  
  15745.  
  15746.  ────────────────────────────────────────────────────────────────────────────
  15747.  Chapter 6  .Exe File Structure and Loading
  15748.  
  15749.      6.1   Introduction
  15750.      6.2   Format of a File Header
  15751.      6.3   The Relocation Table
  15752.  
  15753.  
  15754.  6.1  Introduction
  15755.  
  15756.    ──────────────────────────────────────────────────────────────────────────
  15757.    Note
  15758.      This chapter describes .exe file structure and loading procedures for
  15759.      systems that use a version of MS-DOS earlier than 2.0. For MS-DOS
  15760.      versions 2.0 and later, use Function B00H (Load and Execute Program) to
  15761.      load (or load and execute) a .exe file.
  15762.    ──────────────────────────────────────────────────────────────────────────
  15763.  
  15764.    The .exe files produced by link consist of two parts:
  15765.  
  15766.    ■  Control and relocation information
  15767.  
  15768.    ■  The load module
  15769.  
  15770.    The control and relocation information is at the beginning of the file in
  15771.    an area called the header. Immediately following this header is the load
  15772.    module.
  15773.  
  15774.  
  15775.  6.2  Format of a File Header
  15776.  
  15777.    The header is formatted as follows (notice that offsets are in
  15778.    hexadecimal):
  15779.  
  15780. ╓┌─┌──────────────────┌──────────────────────────────────────────────────────╖
  15781.    Offset             Contents
  15782.    ──────────────────────────────────────────────────────────────────────────
  15783.    0-1                Must contain 4DH, 5AH.
  15784.  
  15785.    2-3                Number of bytes contained in last page; useful for
  15786.                       reading overlays.
  15787.  
  15788.    4-5                Size of the file in 512-byte pages, including the
  15789.                       header.
  15790.  
  15791.    6-7                Number of relocation entries in table.
  15792.  
  15793.    8-9                Size of the header in 16-byte paragraphs. Used to
  15794.    Offset             Contents
  15795.    ──────────────────────────────────────────────────────────────────────────
  15796.   8-9                Size of the header in 16-byte paragraphs. Used to
  15797.                       locate the beginning of the load module in the file.
  15798.  
  15799.    AH-BH              Minimum number of 16-byte paragraphs required above the
  15800.                       end of the loaded program.
  15801.  
  15802.    CH-DH              Maximum number of 16-byte paragraphs required above the
  15803.                       end of the loaded program. If both minalloc and
  15804.                       maxalloc are 0, the program is loaded as high as
  15805.                       possible.
  15806.  
  15807.    EH-FH              Initial value to be loaded into stack segment before
  15808.                       starting program execution. Must be adjusted by
  15809.                       relocation.
  15810.  
  15811.    10-11              Value to be loaded into the SP register before starting
  15812.                       program execution.
  15813.  
  15814.    12-13              Negative sum of all the words in the file.
  15815.    Offset             Contents
  15816.    ──────────────────────────────────────────────────────────────────────────
  15817.   12-13              Negative sum of all the words in the file.
  15818.  
  15819.    14-15              Initial value to be loaded into the IP register before
  15820.                       starting program execution.
  15821.  
  15822.    16-17              Initial value to be loaded into the CS register before
  15823.                       starting program execution. Must be adjusted by
  15824.                       relocation.
  15825.  
  15826.    18-19              Relative byte offset from beginning of run file to
  15827.                       relocation table.
  15828.  
  15829.    1AH-1BH            The number of the overlay as generated by link.
  15830.    ──────────────────────────────────────────────────────────────────────────
  15831.  
  15832.  
  15833.  
  15834.  6.3  The Relocation Table
  15835.  
  15836.    The relocation table that follows the formatted area above consists of a
  15837.    variable number of relocation items. Each relocation item contains two
  15838.    fields: a two-byte offset value, followed by a two-byte segment value.
  15839.    These two fields contain the offset into a word's load module. This item
  15840.    requires modification before the module is given control. The following
  15841.    steps describe this process:
  15842.  
  15843.    1. The formatted part of the header is read into memory. Its size is 1BH.
  15844.  
  15845.    2. MS-DOS allocates a portion of memory depending on the size of the load
  15846.       module and the allocation numbers (AH-BH and CH-DH). MS-DOS then
  15847.       attempts to allocate 0FFFH paragraphs. This attempt always fails and
  15848.       returns the size of the largest free block. If this block is smaller
  15849.       than minalloc and loadsize, there is no memory error. But if this block
  15850.       is larger than maxalloc and loadsize, MS-DOS allocates (maxalloc +
  15851.       loadsize). Otherwise, it allocates the largest free block of memory.
  15852.  
  15853.    3. A Program Segment Prefix is built in the lowest part of the allocated
  15854.       memory.
  15855.  
  15856.    4. MS-DOS calculates the load module size (using offsets 4-5 and 8-9) by
  15857.       subtracting the header size from the file size. The actual size is
  15858.       adjusted down based on the contents of offsets 2-3. The operating
  15859.       system determines (based on the setting of the high/low load switch) an
  15860.       appropriate segment, called the start segment, where it loads the load
  15861.       module.
  15862.  
  15863.    5. The load module is read into memory beginning with the start segment.
  15864.  
  15865.    6. The items in the relocation table are read into a work area.
  15866.  
  15867.    7. MS-DOS adds the segment value of each relocation table item to the
  15868.       start segment value. This calculated segment, plus offset, points to
  15869.       the module to which the start segment value is added. The result is
  15870.       then placed back into the word in the load module.
  15871.  
  15872.    8. Once all relocation items have been processed, the operating system
  15873.       sets the SS and SP registers, using the values in the header. MS-DOS
  15874.       then adds the start segment value to SS and sets the ES and DS
  15875.       registers to the segment address of the Program Segment Prefix. The
  15876.       start segment value is then added to the header CS register value. The
  15877.       result, along with the header IP value, is the initial CS:IP to
  15878.       transfer to before starting execution of the program.
  15879.  
  15880.  
  15881.  
  15882.  ────────────────────────────────────────────────────────────────────────────
  15883.  Chapter 7  Relocatable Object Module Formats
  15884.  
  15885.      7.1   Introduction
  15886.            7.1.1   Definition of Terms
  15887.      7.2   Module Identification and Attributes
  15888.            7.2.1   Segment Definition
  15889.            7.2.2   Addressing a Segment
  15890.            7.2.3   Symbol Definition
  15891.            7.2.4   Indices
  15892.      7.3   Conceptual Framework for Fixups
  15893.            7.3.1   Self-Relative Fixup
  15894.            7.3.2   Segment-Relative Fixup
  15895.      7.4   Record Sequence
  15896.      7.5   Introducing the Record Formats
  15897.            7.5.1   Sample Record Format (SAMREC)
  15898.            7.5.2   T-Module Header Record (THEADR)
  15899.            7.5.3   L-Module Header Record (LHEADR)
  15900.            7.5.4   List of Names Record (LNAMES)
  15901.            7.5.5   Segment Definition Record (SEGDEF)
  15902.            7.5.6   Group Definition Record (GRPDEF)
  15903.            7.5.7   Public Names Definition Record (PUBDEF)
  15904.            7.5.8   Communal Names Definition Record (COMDEF)
  15905.            7.5.9   Local Symbols Record (LOCSYM)
  15906.            7.5.10  External Names Definition Record (EXTDEF)
  15907.            7.5.11  Line Numbers Record (LINNUM)
  15908.            7.5.12  Logical Enumerated Data Record (LEDATA)
  15909.            7.5.13  Logical Iterated Data Record (LIDATA)
  15910.            7.5.14  Fixup Record (FIXUPP)
  15911.            7.5.15  Module End Record (MODEND)
  15912.            7.5.16  Comment Record (COMENT)
  15913.      7.6   Microsoft Type Representations for Communal Variables
  15914.  
  15915.  
  15916.  7.1  Introduction
  15917.  
  15918.    This chapter presents the object record formats that define the
  15919.    relocatable object language for the 8086, 80186, and 80286
  15920.    microprocessors. The 8086 object language is the output of all language
  15921.    translators that have an 8086 processor and that will be linked by the
  15922.    Microsoft linker. The 8086 object language is used for input and output
  15923.    for object language processors such as linkers and librarians, and in the
  15924.    XENIX, PC-DOS, and MS-DOS operating systems.
  15925.  
  15926.    The 8086 object module formats let you specify relocatable memory images
  15927.    that may be linked together. These formats also allow efficient use of the
  15928.    memory mapping facilities of the 8086 family of microprocessors.
  15929.  
  15930.    The following table lists the record formats that Microsoft supports.
  15931.    Their abbreviations appear in parentheses. Each is described in this
  15932.    chapter.
  15933.  
  15934.    Table 7.1
  15935.    Object Module Record Formats
  15936.    Symbol Definition Records
  15937.    ──────────────────────────────────────────────────────────────────────────
  15938.    Public Names Definition Record       (PUBDEF)
  15939.    Communal Names Definition Record     (COMDEF)
  15940.    Local Symbols Record                 (LOCSYM)
  15941.    External Names Definition Record     (EXTDEF)
  15942.    Line Numbers Record                  (LINNUM)
  15943.  
  15944.    Data Records
  15945.    Logical Enumerated Data Record       (LEDATA)
  15946.    Logical Iterated Data Record         (LIDATA)
  15947.    T-Module Header Record               (THEADR)
  15948.    L-Module Header Record               (LHEADR)
  15949.    List of Names Record                 (LNAMES)
  15950.    Segment Definition Record            (SEGDEF)
  15951.    Group Definition Record              (GRPDEF)
  15952.  
  15953.    Fixup Record                         (FIXUPP)
  15954.    Module End Record                    (MODEND)
  15955.    Comment Record                       (COMENT)
  15956.    ──────────────────────────────────────────────────────────────────────────
  15957.  
  15958.    ──────────────────────────────────────────────────────────────────────────
  15959.    Note
  15960.      If an object module contains any undefined values, the behavior of the
  15961.      Microsoft linker is undefined. All undefined values should be considered
  15962.      reserved by Microsoft for future use.
  15963.    ──────────────────────────────────────────────────────────────────────────
  15964.  
  15965.  7.1.1  Definition of Terms
  15966.  
  15967.    The following terms are fundamental to 8086 relocation and linkage:
  15968.  
  15969.    OMF - Object Module Formats
  15970.  
  15971.    MAS - Memory Address Space
  15972.  
  15973.    The 8086 MAS is one megabyte (1,048,576 bytes). Notice that the MAS is
  15974.    distinguished from actual memory, which may occupy only a portion of the
  15975.    MAS.
  15976.  
  15977.    Module
  15978.  
  15979.    A module is an "inseparable" collection of object code and other
  15980.    information produced by a translator.
  15981.  
  15982.    T-Module
  15983.  
  15984.    A T-module is a module created by a translator, such as Pascal or FORTRAN.
  15985.  
  15986.    The following restrictions apply to object modules:
  15987.  
  15988.    ■  Every module should have a name. Translators provide default names
  15989.       (possibly filenames or null names) for T-modules if neither the source
  15990.       code nor the user specifies otherwise.
  15991.  
  15992.    ■  Every T-module in a collection of linked modules should have a
  15993.       different name so that symbolic debugging systems can distinguish the
  15994.       various line numbers and local symbols. The Microsoft linker does not
  15995.       require or enforce this restriction.
  15996.  
  15997.    Frame
  15998.  
  15999.    A frame is a contiguous region of 64K of memory address space (MAS),
  16000.    beginning on a paragraph boundary (i.e., on a multiple of 16 bytes) or on
  16001.    a selector on the 80286 processor. This concept is useful because the
  16002.    contents of the four 8086 segment registers define four (possibly
  16003.    overlapping) frames; no 16-bit address in the 8086 code can access a
  16004.    memory location outside the current four frames.
  16005.  
  16006.    LSEG (Logical Segment)
  16007.  
  16008.    A logical segment (LSEG) is a contiguous region of memory whose contents
  16009.    are determined at translation time (except for address-binding). Neither
  16010.    the size nor the location in MAS are necessarily determined during
  16011.    translation: the size, although partially fixed, may not be final because
  16012.    the linker may combine the LSEG when linking with other LSEGs, forming a
  16013.    single LSEG. So that it can fit in a frame, an LSEG must not be larger
  16014.    than 64K. Thus, a 16-bit offset, from the base of a frame that covers the
  16015.    LSEG, may address any byte in that LSEG.
  16016.  
  16017.    PSEG (Physical Segment)
  16018.  
  16019.    This term is equivalent to frame. Some prefer "PSEG" to "frame" because
  16020.    the terms PSEG and LSEG reflect the "physical" and "logical" nature of the
  16021.    underlying segments.
  16022.  
  16023.    Frame Number
  16024.  
  16025.    Every frame begins on a paragraph boundary. The "paragraphs" in MAS can be
  16026.    numbered from 0 through 65,535. These numbers, each of which defines a
  16027.    frame, are called frame numbers.
  16028.  
  16029.    Group
  16030.  
  16031.    A group is a collection of LSEGs defined at translation time, whose final
  16032.    locations in MAS have been constrained so that at least one frame exists
  16033.    that covers (contains) every LSEG in the collection.
  16034.  
  16035.    The notation "Gr A(X,Y,Z,)" means that LSEGs X, Y, and Z form a group
  16036.    named A. That X, Y, and Z are all LSEGs in the same group does not imply
  16037.    any ordering of X, Y, and Z in MAS, nor does it imply any contiguity
  16038.    between X, Y, and Z.
  16039.  
  16040.    The Microsoft linker does not currently allow an LSEG to be a member of
  16041.    more than one group.
  16042.  
  16043.    Canonic
  16044.  
  16045.    On the 8086 processor, any location in MAS is contained in exactly 4096
  16046.    distinct frames, but one of these frames can be distinguished because it
  16047.    has a higher frame number. This frame is called the canonic frame of the
  16048.    location. In other words, the canonic frame of a given byte is the frame
  16049.    chosen so that the byte's offset from that frame lies in the range 0 to 15
  16050.    (decimal).
  16051.  
  16052.    For example, suppose FOO is a symbol defining a memory location. You would
  16053.    then refer to this frame as the "canonic frame of FOO." Similarly, if S is
  16054.    any set of memory locations, then a unique frame exists that has the
  16055.    lowest frame number in the set of canonic frames of the locations in S.
  16056.    This unique frame is called the canonic frame of the set S. You might
  16057.    refer similarly to the canonic frame of an LSEG or of a group of LSEGs.
  16058.  
  16059.    Segment Name
  16060.  
  16061.    LSEGs are assigned segment names at translation time. These names serve
  16062.    two purposes:
  16063.  
  16064.    ■  During linking, they play a role in determining which LSEGs are
  16065.       combined with other LSEGs.
  16066.  
  16067.    ■  They are used in assembly source code to specify membership in groups.
  16068.  
  16069.    Class Name
  16070.  
  16071.    The translator may optionally assign class names to LSEGs during
  16072.    translation. Classes define a partition on LSEGs: two LSEGs are in the
  16073.    same class if they have the same class name.
  16074.  
  16075.    The Microsoft linker applies the following semantics to class names: the
  16076.    class name "CODE", or any class name whose suffix is "CODE", implies that
  16077.    all segments of that class contain only code and may be considered
  16078.    read-only. Such segments may be overlaid if you specify the module
  16079.    containing the segment as part of an overlay.
  16080.  
  16081.    Overlay Name
  16082.  
  16083.    The linker may optionally assign an overlay name to LSEGs. The overlay
  16084.    name of an LSEG is ignored by Microsoft language linkers for version 3.0
  16085.    and later languages, but the standard MS-DOS linker supports it.
  16086.  
  16087.    Complete Name
  16088.  
  16089.    The complete name of an LSEG consists of the segment name, class name, and
  16090.    overlay name. The linker combines LSEGs from different modules if their
  16091.    complete names are identical.
  16092.  
  16093.  
  16094.  7.2  Module Identification and Attributes
  16095.  
  16096.    A module header record, which provides a module name, is always the first
  16097.    record in a module. In addition to having a name, a module may represent a
  16098.    main program and may have a specified starting address. When linking
  16099.    multiple modules together, you should give only one module which has the
  16100.    main attribute. If more than one main module appears, the first takes
  16101.    precedence.
  16102.  
  16103.    In summary, modules may or may not be main and may or may not have a
  16104.    starting address.
  16105.  
  16106.  7.2.1  Segment Definition
  16107.  
  16108.    A module is a collection of object code defined by a sequence of records
  16109.    that a translator produces. The object code represents contiguous regions
  16110.    of memory whose contents the linker determines during translation. These
  16111.    regions are LSEGs. A module defines the attributes of each LSEG. The
  16112.    segment definition record (SEGDEF) is responsible for maintaining all LSEG
  16113.    information (name, length, memory alignment, etc.). The linker requires
  16114.    the LSEG information when you combine multiple LSEGs and when it
  16115.    establishes segment addressability. The SEGDEF records must follow the
  16116.    first header record.
  16117.  
  16118.  7.2.2  Addressing a Segment
  16119.  
  16120.    The 8086 addressing mechanism provides segment base registers from which
  16121.    you may address a 64-kilobyte region of memory (a frame). There is one
  16122.    code segment base register (CS), two data segment base registers (DS, ES),
  16123.    and one stack segment base register (SS).
  16124.  
  16125.    The possible number of LSEGs that may make up a memory image far exceeds
  16126.    the number of available base registers. Thus, base registers may require
  16127.    frequent loading. This would be the case in a modular program with many
  16128.    small data and/or code LSEGs.
  16129.  
  16130.    Since such frequent loading of base registers is undesirable, it is a good
  16131.    strategy to collect many small LSEGs together into a single unit that will
  16132.    fit in one memory frame. Then all the LSEGs may be addressed using the
  16133.    same base register value. This addressable unit is a group (see the
  16134.    definition of a group in Section 7.1.1, "Definition of Terms").
  16135.  
  16136.    To establish addressability of objects within a group, you must explicitly
  16137.    define each group in the module. The group definition record (GRPDEF)
  16138.    lists constituent segments by their segment names.
  16139.  
  16140.    The GRPDEF records within a module must follow all SEGDEF records because
  16141.    GRPDEF records will reference SEGDEF records in defining a group. The
  16142.    GRPDEF records must also precede all other records except header records,
  16143.    which the linker must process first.
  16144.  
  16145.  7.2.3  Symbol Definition
  16146.  
  16147.    The Microsoft linker supports three different types of records belonging
  16148.    to the class of symbol definition records. The types are public names
  16149.    definition records (PUBDEFs), communal names definition records (COMDEFs),
  16150.    and external names definition records (EXTDEFs). You use these record
  16151.    types to define globally visible procedures and data items and to resolve
  16152.    external references.
  16153.  
  16154.  7.2.4  Indices
  16155.  
  16156.    "Index" fields appear throughout this chapter. An index is an integer that
  16157.    selects a particular item from a collection of items; for example: name
  16158.    index, segment index, group index, external index, type index, etc.
  16159.  
  16160.    ──────────────────────────────────────────────────────────────────────────
  16161.    Note
  16162.      An index is normally a positive number. The index value zero is
  16163.      reserved, and may carry a special meaning depending on the type of index
  16164.      (for example, a segment index of zero specifies the "Unnamed" absolute
  16165.      pseudo-segment; a type index of zero specifies the "Untyped type").
  16166.    ──────────────────────────────────────────────────────────────────────────
  16167.  
  16168.    In general, indices must assume values that are quite large (that is, much
  16169.    larger than 255). Nevertheless, a great number of object files contain no
  16170.    indices with values greater than 50 or 100. Therefore, indices are encoded
  16171.    in one or two bytes, as required.
  16172.  
  16173.    The high-order (left-most) bit of the first (and possibly the only) byte
  16174.    determines whether the index occupies one byte or two. If the bit is 0,
  16175.    the index is a number between 0 and 127, occupying one byte. If the bit is
  16176.    1, the index is a number between 0 and 32K-1, occupying two bytes, and is
  16177.    determined as follows: the low-order eight bits are in the second byte,
  16178.    and the high-order seven bits are in the first byte.
  16179.  
  16180.  
  16181.  7.3  Conceptual Framework for Fixups
  16182.  
  16183.    A fixup is a modification to object code that achieves address binding
  16184.    that a translator requested and a linker performed.
  16185.  
  16186.    ──────────────────────────────────────────────────────────────────────────
  16187.    Note
  16188.      This is the linker's definition of fixup. Nevertheless, the linker can
  16189.      modify object code (make a "fixup") that does not conform to this
  16190.      definition. For example, binding code to either hardware or software
  16191.      floating-point subroutines is a modification to an operation code, which
  16192.      is treated as an address. The previous definition of fixup is not
  16193.      intended to disallow or discourage modifications to the object code.
  16194.    ──────────────────────────────────────────────────────────────────────────
  16195.  
  16196.    8086-family translators need four kinds of data to specify a fixup:
  16197.  
  16198.    ■  The place and type of a location to be fixed up.
  16199.  
  16200.    ■  One of two possible fixup modes.
  16201.  
  16202.    ■  A target, which is the memory address to which the location must refer.
  16203.  
  16204.    ■  A frame that defines a context in which the reference takes place.
  16205.  
  16206.    Location ── There are five types of locations: a pointer, a base, an
  16207.    offset, a hibyte, and a lobyte.
  16208.  
  16209.    The vertical alignment of Figure 7.1 illustrates four points (remember
  16210.    that the high-order byte of a word in 8086 memory is the byte with the
  16211.    higher address):
  16212.  
  16213.    ■  A base is the high-order word of a pointer (the linker doesn't care
  16214.       whether the low-order word of the pointer is present).
  16215.  
  16216.    ■  An offset is the low-order word of a pointer (the linker doesn't care
  16217.       whether the high-order word follows).
  16218.  
  16219.    ■  A hibyte is the high-order half of an offset (the linker doesn't care
  16220.       whether the low-order half precedes).
  16221.  
  16222.    ■  A lobyte is the low-order half of an offset (the linker doesn't care
  16223.       whether the high-order half follows).
  16224.  
  16225.              ┌───────────────────┐
  16226.    Pointer:  │                   │
  16227.              └───────────────────┘
  16228.  
  16229.                        ┌─────────┐
  16230.    Base:               │         │
  16231.                        └─────────┘
  16232.  
  16233.              ┌─────────┐
  16234.    Offset:   │         │
  16235.              └─────────┘
  16236.  
  16237.                   ┌────┐
  16238.    Hibyte:        │    │
  16239.                   └────┘
  16240.  
  16241.              ┌────┐
  16242.    Lobyte:   │    │
  16243.              └────┘
  16244.  
  16245.    Figure 7.1  Location Types
  16246.  
  16247.    A Location is specified by two kinds of data: the location type, and where
  16248.    it is located.
  16249.  
  16250.    The location type is specified by the LOC field in the FIXUPP record's
  16251.    LOCAT field; where it is located is specified by the Data Record Offset
  16252.    field in the same LOCAT field.
  16253.  
  16254.    Mode ── The Microsoft linker supports two kinds of fixups: self-relative
  16255.    and segment-relative.
  16256.  
  16257.    Self-relative fixups support the 8-bit and 16-bit offsets used in CALL,
  16258.    JUMP, and SHORT-JUMP instructions. Segment-relative fixups support all
  16259.    other addressing modes of the 8086.
  16260.  
  16261.    Target ── The target is the location in MAS that the linker references.
  16262.    (More explicitly, the linker considers the target the lowest byte in the
  16263.    object that it is referencing.) The linker specifies a target by one of
  16264.    five methods. There are three "primary" methods and three "secondary"
  16265.    ones. Each primary method of specifying a target uses two kinds of data:
  16266.    an index number X, and a displacement D.
  16267.  
  16268.    Method             Explanation
  16269.    ──────────────────────────────────────────────────────────────────────────
  16270.    (T0)               X is a segment index. The target is the Dth byte in the
  16271.                       LSEG that the segment index identifies.
  16272.  
  16273.    (T1)               X is a group index. The target is the Dth byte in the
  16274.                       LSEG that the group index identifies.
  16275.  
  16276.    (T2)               X is an external index. The external index identifies
  16277.                       the external name that (eventually) gives the address
  16278.                       of a byte. The Dth byte following this byte is the
  16279.    ──────────────────────────────────────────────────────────────────────────
  16280.  
  16281.    Each secondary method of specifying a target uses only one item of data ──
  16282.    the index number X; this assumes an implicit displacement equal to zero.
  16283.  
  16284.    Method             Explanation
  16285.    ──────────────────────────────────────────────────────────────────────────
  16286.    (T4)               X is a segment index. The target is the 0th (first)
  16287.                       byte in the LSEG that the segment index identifies.
  16288.  
  16289.    (T5)               X is a group index. The target is the 0th (first) byte
  16290.                       in the LSEG in the specified group located (eventually)
  16291.                       lowest in MAS.
  16292.  
  16293.    (T6)               X is an external index. The target is the byte whose
  16294.                       address is the external name that the external index
  16295.    ──────────────────────────────────────────────────────────────────────────
  16296.  
  16297.    The following nomenclature describes a target:
  16298.  
  16299.    Nomenclature                                     Method
  16300.    ──────────────────────────────────────────────────────────────────────────
  16301.    Target: SI(segment name), displacement           [T0]
  16302.    Target: GI(group name), displacement             [T1]
  16303.    Target: EI(symbol name), displacement            [T2]
  16304.    Target: SI (segment name)                        [T4]
  16305.    Target: GI (group name)                          [T5]
  16306.    Target: EI (symbol name)                         [T6]
  16307.    ──────────────────────────────────────────────────────────────────────────
  16308.  
  16309.    The following examples illustrate how this notation is used:
  16310.  
  16311.    Sample Nomenclature                  Explanation
  16312.    ──────────────────────────────────────────────────────────────────────────
  16313.    Target: SI(CODE), 1024               The 1025th byte in the segment CODE.
  16314.  
  16315.    Target: GI(DATAAREA)                 The location in MAS of a group called
  16316.                                         DATAAREA.
  16317.  
  16318.    Target: EI(SIN)                      The address of the external
  16319.                                         subroutine SIN.
  16320.  
  16321.    Target: EI(PAYSCHEDULE), 24          The 24th byte following the location
  16322.                                         of an external data structure called
  16323.    ──────────────────────────────────────────────────────────────────────────
  16324.  
  16325.    Frame ── Every 8086 memory reference is to a location contained within a
  16326.    frame. This frame is designated by the contents of a segment register. For
  16327.    the linker to form a correct, usable memory reference, it must know what
  16328.    the target is, and to which frame the reference is being made. Thus, every
  16329.    fixup specifies such a frame, in one of five methods. Some methods use
  16330.    data, X, which is in the index number. Other methods require no data.
  16331.  
  16332.    The five methods of specifying frames are as follows:
  16333.  
  16334.    Method             Explanation
  16335.    ──────────────────────────────────────────────────────────────────────────
  16336.    (F0)               X is a segment index. The frame is the canonic frame of
  16337.                       the LSEG that the segment index defines.
  16338.  
  16339.    (F1)               X is a group index. The frame is the canonic frame
  16340.                       defined by the group (that is, the canonic frame
  16341.                       defined by the LSEG in the group located (eventually)
  16342.                       lowest in MAS).
  16343.  
  16344.    (F2)               X is an external index. The frame is determined when
  16345.                       the linker finds the external name's public definition.
  16346.                       There are two cases:
  16347.  
  16348.                       Case              Explanation
  16349.    ──────────────────────────────────────────────────────────────────────────
  16350.                       (F2a)             The linker defines the symbol
  16351.                                         relative to some LSEG, and there is
  16352.                                         no associated group. The linker also
  16353.                                         specifies the LSEG's canonic frame.
  16354.  
  16355.                       (F2c)             Regardless of how the linker defines
  16356.                                         the symbol, there is an associated
  16357.                                         group. And the linker specifies the
  16358.                                         canonic frame of the group. (The
  16359.                                         Group Index field of the PUBDEF
  16360.    ──────────────────────────────────────────────────────────────────────────
  16361.  
  16362.    Method             Explanation
  16363.    ──────────────────────────────────────────────────────────────────────────
  16364.    (F4)               No X. The frame is the canonic frame of the LSEG that
  16365.                       contains the location.
  16366.  
  16367.    (F5)               No X. The target determines the frame. There are three
  16368.    ──────────────────────────────────────────────────────────────────────────
  16369.  
  16370.                       Case              Explanation
  16371.    ──────────────────────────────────────────────────────────────────────────
  16372.                       (F5a)             The target specifies a segment index:
  16373.                                         in this case, the frame is determined
  16374.                                         as in (F0).
  16375.  
  16376.                       (F5b)             The target specifies a group index:
  16377.                                         in this case, the frame is determined
  16378.                                         as in (F1).
  16379.  
  16380.                       (F5c)             The target specifies an external
  16381.                                         index: in this case, the frame is
  16382.    ──────────────────────────────────────────────────────────────────────────
  16383.  
  16384.    The nomenclature that describes frames is similar to the above
  16385.    nomenclature for targets.
  16386.  
  16387.    Nomenclature                                     Method
  16388.    ──────────────────────────────────────────────────────────────────────────
  16389.    Frame: SI (segment name)                         [F0]
  16390.    Frame: GI (group name)                           [F1]
  16391.    Frame: EI (symbol name)                          [F2]
  16392.    Frame: Location                                  [F4]
  16393.    Frame: target                                    [F5]
  16394.    Frame: None                                      [F6]
  16395.    ──────────────────────────────────────────────────────────────────────────
  16396.  
  16397.    For an 8086 memory reference, the frame specified by a self-relative
  16398.    reference is usually the canonic frame of the LSEG that contains the
  16399.    location. Also, the frame specified by a segment-relative reference is the
  16400.    canonic frame of the LSEG that contains the target.
  16401.  
  16402.  7.3.1  Self-Relative Fixup
  16403.  
  16404.    A self-relative fixup works as follows: the location implicitly defines a
  16405.    memory address──namely, the address of the byte following the location
  16406.    (because at the time of a self-relative reference, the 8086 IP
  16407.    (Instruction Pointer) is pointing to the byte following the reference).
  16408.  
  16409.    For 8086 self-relative references, if either the location or the target is
  16410.    outside the specified frame, the linker gives a warning. Otherwise, there
  16411.    is a unique l6-bit displacement that, when added to the address implicitly
  16412.    defined by the location, yields the relative position of the target in the
  16413.    frame.
  16414.  
  16415.    ■  If the location is an offset, the linker adds the displacement to the
  16416.       location (modulo 65,536) and reports no errors.
  16417.  
  16418.    ■  If the location is a lobyte, the displacement must be within the range
  16419.       {-128:127}; otherwise, the linker gives a warning. The linker adds the
  16420.       displacement to the location (modulo 256).
  16421.  
  16422.    ■  If the location is a base, pointer, or hibyte, it is unclear what the
  16423.       translator intended, so the linker's action is undefined.
  16424.  
  16425.  7.3.2  Segment-Relative Fixup
  16426.  
  16427.    A segment-relative fixup operates as follows: a nonnegative 16-bit number,
  16428.    FBVAL, is defined as the frame number of the frame or selector value that
  16429.    the fixup specifies. A signed 20-bit number, FOVAL, is defined as the
  16430.    distance from the base of the frame to the target. If this signed 20-bit
  16431.    number is less than 0 or greater than 65,535, the linker reports an error.
  16432.    Otherwise, the linker uses FBVAL and FOVAL to fix up the location in the
  16433.    following fashion:
  16434.  
  16435.    ■  If the location is a pointer, the linker adds FBVAL (modulo 65,536) to
  16436.       the high-order word of the pointer, and adds FOVAL (modulo 65,536) to
  16437.       the low-order word of the pointer.
  16438.  
  16439.    ■  If the location is a base, the linker adds FBVAL (modulo 65,536) to the
  16440.       base and ignores FOVAL.
  16441.  
  16442.    ■  If the location is an offset, the linker adds FOVAL (modulo 65,536) to
  16443.       the offset and ignores FBVAL.
  16444.  
  16445.    ■  If the location is a hibyte, the linker adds (FOVAL/256) (modulo 256)
  16446.       to the hibyte and ignores FBVAL. (The division indicated is integer
  16447.       division; that is, the linker discards the remainder.)
  16448.  
  16449.    ■  If the location is a lobyte, the linker adds (FOVAL modulo 256) (modulo
  16450.       256) to the lobyte and ignores FBVAL.
  16451.  
  16452.  
  16453.  7.4  Record Sequence
  16454.  
  16455.    An object code file must contain a sequence of one or more modules, or a
  16456.    library containing zero or more modules. The following syntax shows the
  16457.    valid record ordering necessary to form a module. In addition, the given
  16458.    semantic rules provide information about how to interpret the record
  16459.    sequence.
  16460.  
  16461.    ──────────────────────────────────────────────────────────────────────────
  16462.    Note
  16463.      The description language used in the following syntax is defined in
  16464.      WIRTH: CACM, November 1977, vol. 20, no. 11, pp. 822-823. The character
  16465.      strings represented by capital letters are not literals but identifiers,
  16466.      and are further defined in the record format section.
  16467.    ──────────────────────────────────────────────────────────────────────────
  16468.  
  16469.  
  16470.  
  16471.    object file  = tmodule
  16472.  
  16473.    tmodule      = {THEADR | LHEADR} seg-grp {component} modtail
  16474.  
  16475.    seg_grp      = {LNAMES} {SEGDEF} {EXTDEF | GRPDEF}
  16476.  
  16477.    component    = data | debug_record
  16478.  
  16479.    data         = content_def | thread_def |
  16480.                        PUBDEF | EXTDEF | COMDEF | LOCSYM
  16481.  
  16482.    debug_record = LINNUM
  16483.  
  16484.    content_def  = data_record {FIXUPP}
  16485.  
  16486.    thread_def   = FIXUPP (containing only Thread fields)
  16487.  
  16488.    data_record  = LIDATA | LEDATA
  16489.  
  16490.    modtail      = MODEND
  16491.  
  16492.    The following rules apply:
  16493.  
  16494.    ■  A FIXUPP record always refers to the previous data record.
  16495.  
  16496.    ■  All LNAMES, SEGDEF, GRPDEF, and EXTDEF records must precede all records
  16497.       that refer to them.
  16498.  
  16499.    ■  Comment records may appear anywhere in a file, except as the first or
  16500.       last record in a file or module, or within a content_def.
  16501.  
  16502.  
  16503.  7.5  Introducing the Record Formats
  16504.  
  16505.    The following pages present diagrams of record formats in schematic form.
  16506.    Here is a sample record format that illustrates the various conventions:
  16507.  
  16508.  7.5.1  Sample Record Format (SAMREC)
  16509.  
  16510.    ┌─────┬──────────┬─────///────┬────||||────┬─────┐
  16511.    │     │          │            │            │     │
  16512.    │ REC │  Record  │    Name    │   Number   │ CHK │
  16513.    │ TYP │  Length  │            │            │ SUM │
  16514.    │ xxH │          │            │            │     │
  16515.    │     │          │            │            │     │
  16516.    └─────┴──────────┼────///─────┼────||||────┴─────┘
  16517.                     │            │
  16518.                     └────rpt─────┘
  16519.  
  16520.    The Title and Official Abbreviation
  16521.  
  16522.    At the top of the figure is the name of the record format described, with
  16523.    its official abbreviation. To promote uniformity among various programs,
  16524.    including translators and debuggers, use the abbreviation in both code and
  16525.    documentation. The abbreviation of the record format is always six
  16526.    letters.
  16527.  
  16528.    The Boxes
  16529.  
  16530.    Each format is drawn with boxes of two sizes. A narrow box represents a
  16531.    single byte. A plain wide box represents two bytes. The wide boxes with
  16532.    three slashes in the top and bottom represent a variable number of bytes,
  16533.    one or more, depending upon the content. The wide boxes with four vertical
  16534.    bars in the top and bottom represent four-byte fields.
  16535.  
  16536.    RECTYP
  16537.  
  16538.    The first byte in each record contains a value between 0 and 255,
  16539.    indicating the record type.
  16540.  
  16541.    Record Length
  16542.  
  16543.    The second field in each record contains the number of bytes in the
  16544.    record, exclusive of the first two fields, where a field is a 16-bit
  16545.    number──a low byte followed by a high byte.
  16546.  
  16547.    Name
  16548.  
  16549.    Any field that indicates a name has the following internal structure: the
  16550.    first byte contains a number between 0 and 127, inclusive, indicating the
  16551.    number of remaining bytes in the field. The remaining bytes are
  16552.    interpreted as a byte string.
  16553.  
  16554.    Most translators constrain the character set to a subset of the ASCII
  16555.    character set.
  16556.  
  16557.    Number
  16558.  
  16559.    A four-byte number field represents a 32-bit unsigned integer, where the
  16560.    first eight bits (least-significant) are stored in the first byte (lowest
  16561.    address), the next eight bits are stored in the second byte, and so on.
  16562.  
  16563.    Repeated or Conditional Fields
  16564.  
  16565.    Some portions of a record format contain a field or series of fields that
  16566.    may be repeated one or more times. Such portions are indicated by the
  16567.    "repeated" or "rpt" brackets below the boxes.
  16568.  
  16569.    Similarly, some portions of a record format are present only if some given
  16570.    condition is true; these fields are indicated by similar "conditional" or
  16571.    "cond" brackets below the boxes.
  16572.  
  16573.    CHKSUM
  16574.  
  16575.    The last field in each record is a check sum, which contains the two's
  16576.    complement of the sum (modulo 256) of all other bytes in the record.
  16577.    Therefore, the sum (modulo 256) of all bytes in the record is zero.
  16578.  
  16579.    Bit Fields
  16580.  
  16581.    Sometimes descriptions of the contents of fields are at the bit level.
  16582.    Boxes with vertical lines drawn through them represent bytes or words; the
  16583.    vertical lines indicate bit boundaries. Thus, the following byte
  16584.    representation has three bit fields of three, one, and four bits,
  16585.    respectively.
  16586.  
  16587.    ┌───────────┬───┬───────────────┐
  16588.    │           │   │               │
  16589.    │           │   │               │
  16590.    │           │   │               │
  16591.    └───────────┴───┴───────────────┘
  16592.          3       1         4
  16593.  
  16594.  7.5.2  T-Module Header Record (THEADR)
  16595.  
  16596.    ┌─────┬──────────┬─────///────┬─────┐
  16597.    │     │          │            │     │
  16598.    │ REC │  Record  │    T-      │ CHK │
  16599.    │ TYP │  Length  │    Module  │ SUM │
  16600.    │ 80H │          │    Name    │     │
  16601.    │     │          │            │     │
  16602.    └─────┴──────────┴────///─────┴─────┘
  16603.  
  16604.    T-Module Name
  16605.  
  16606.    The T-Module Name field contains the name for the T-module.
  16607.  
  16608.  7.5.3  L-Module Header Record (LHEADR)
  16609.  
  16610.    ┌─────┬──────────┬─────///────┬─────┐
  16611.    │     │          │            │     │
  16612.    │ REC │  Record  │    L-      │ CHK │
  16613.    │ TYP │  Length  │    Module  │ SUM │
  16614.    │ 82H │          │    Name    │     │
  16615.    │     │          │            │     │
  16616.    └─────┴──────────┴────///─────┴─────┘
  16617.  
  16618.    L-Module Name
  16619.  
  16620.    The L-Module Name field contains the name for the L-module.
  16621.  
  16622.    Every module output from a translator must have a T-module or L-module
  16623.    header record. The linker requires a THEADR or LHEADR record to come first
  16624.    in the module and ignores any others. The LHEADR record is identical to
  16625.    the THEADR record, except it has a record type of 82H.
  16626.  
  16627.  7.5.4  List of Names Record (LNAMES)
  16628.  
  16629.    ┌─────┬──────────┬─────///────┬─────┐
  16630.    │     │          │            │     │
  16631.    │ REC │  Record  │    Name    │ CHK │
  16632.    │ TYP │  Length  │            │ SUM │
  16633.    │ 96H │          │            │     │
  16634.    │     │          │            │     │
  16635.    └─────┴──────────┼────///─────┼─────┘
  16636.                     │            │
  16637.                     └────rpt─────┘
  16638.  
  16639.    The LNAMES record contains a list of names that the following SEGDEF and
  16640.    GRPDEF records may use as the names of segments, classes, and/or groups.
  16641.  
  16642.    The order of LNAMES records in a module and the order of names within each
  16643.    LNAMES record imply a mapping of these names to numbers: 1, 2, 3, etc.
  16644.    These numbers are used as "Name Indices" in the Segment Name Index, Class
  16645.    Name Index, and Group Name Index fields of the SEGDEF and GRPDEF records.
  16646.  
  16647.    Name
  16648.  
  16649.    This repeatable field provides a name, which may have zero length.
  16650.  
  16651.  7.5.5  Segment Definition Record (SEGDEF)
  16652.  
  16653.    ┌───┬────────┬───///───┬─────────┬───///───┬─///─┬─///─┬───┐
  16654.    │   │        │         │         │         │     │     │   │
  16655.    │REC│ Record │ Segment │ Segment │ Segment │Class│Over │CHK│
  16656.    │TYP│ Length │   ATTR  │ Length  │   Name  │Name │Lay  │SUM│
  16657.    │98H│        │         │         │  Index  │Index│Name │   │
  16658.    │   │        │         │         │         │     │Index│   │
  16659.    └───┴────────┴───///───┴─────────┴───///───┴─///─┴─///─┴───┘
  16660.  
  16661.    Segment index values 1 through 32,767, which are used in other record
  16662.    types to refer to specific LSEGs, are defined implicitly by the sequence
  16663.    in which SEGDEF records appear in the object file.
  16664.  
  16665.    Segment ATTR
  16666.  
  16667.    The Segment ATTR field provides information on various attributes of a
  16668.    segment, and has the following format:
  16669.  
  16670.    ┌─────┬────────┬───────┐
  16671.    │     │        │       │
  16672.    │ ACB │ Frame  │  Off- │
  16673.    │  P  │ Number │  Set  │
  16674.    │     │        │       │
  16675.    │     │        │       │
  16676.    └─────┼────────┴───────┤
  16677.          │                │
  16678.          └───conditional──┘
  16679.  
  16680.    The ACBP byte contains four numbers──the A, C, B, and P attribute
  16681.    specifications. This byte has the following format:
  16682.  
  16683.    ┌───────────┬───────────┬───┬───┐
  16684.    │           │           │   │   │
  16685.    │     A     │     C     │ B │ P │
  16686.    │           │           │   │   │
  16687.    └───────────┴───────────┴───┴───┘
  16688.  
  16689.    A (Alignment) is a 3-bit subfield that specifies the alignment attribute
  16690.    of the LSEG. The semantics are defined as follows:
  16691.  
  16692.    Attribute      Explanation
  16693.    ──────────────────────────────────────────────────────────────────────────
  16694.    A=0            SEGDEF describes an absolute LSEG.
  16695.    A=1            SEGDEF describes a relocatable, byte-aligned LSEG.
  16696.    A=2            SEGDEF describes a relocatable, word-aligned LSEG.
  16697.    A=3            SEGDEF describes a relocatable, paragraph-aligned LSEG.
  16698.    A=4            SEGDEF describes a relocatable, page(256-byte)-aligned
  16699.                   LSEG.
  16700.    ──────────────────────────────────────────────────────────────────────────
  16701.  
  16702.    If A=0, the Frame Number and Offset fields are present. With the Microsoft
  16703.    linker, you may use absolute segments for addressing only; for example, to
  16704.    define the starting address of a ROM and to define symbolic names for
  16705.    addresses within the ROM. The linker ignores any data that belongs to an
  16706.    absolute LSEG and issues a warning if absolute segments are defined for a
  16707.    program that runs in protected mode. C (Combination) is a 3-bit subfield
  16708.    that specifies the combination attribute of the LSEG. Absolute segments
  16709.    (A=0) must have combination zero (C=0). For relocatable segments, the C
  16710.    field encodes a number (0,1,2,3,4,5,6, or 7) that indicates how the
  16711.    segment can be combined. One way to interpret this attribute is to
  16712.    consider how two LSEGs are combined.
  16713.  
  16714.    For example, suppose that X and Y are LSEGs, and that Z is the LSEG
  16715.    resulting from the combination of X and Y. Let LX and LY be the lengths of
  16716.    X and Y, and let MXY denote the maximum of LX, LY. Now, to accommodate the
  16717.    alignment attribute of Y, let G be the length of any gap required between
  16718.    the X and Y components of Z. Then, let LZ denote the length of the
  16719.    (combined) LSEG, Z; let dx (0(<=dx<LX) be the offset in X of a byte and,
  16720.    similarly, let dy be the offset (of a byte) in Y.
  16721.  
  16722.    The following table gives the length LZ of the combined LSEG, Z, and the
  16723.    offsets dx' and dy' in Z for the bytes corresponding to dx in X and to dy
  16724.    in Y.
  16725.  
  16726.    Table 7.2
  16727.    Combination Attribute Example
  16728.    C              LZ             dx'           dy'
  16729.    ──────────────────────────────────────────────────────────────────────────
  16730.    2              LX+LY+G        dx            dy+LX+G        "Public"
  16731.    5              LX+LY+G        dx            dy+LX+G        "Stack"
  16732.    6              MXY            dx            dy             "Common"
  16733.    ──────────────────────────────────────────────────────────────────────────
  16734.  
  16735.    Table 7.2 has no lines for C=0, 1, 3, 4, or 7. C=0 indicates that the
  16736.    relocatable LSEG may not be combined. C=1 and C=3 are undefined. C=4 and
  16737.    C=7 are treated the same as C=2.
  16738.  
  16739.    B (Big) is a 1-bit subfield that, if set to 1, indicates that the segment
  16740.    length is exactly 64K (65,536 bytes). In this case, the Segment Length
  16741.    field must contain zero.
  16742.  
  16743.    The P field must always be zero.
  16744.  
  16745.    The Frame Number and Offset fields (present only for absolute segments,
  16746.    A=0) specify the placement in MAS of the absolute segment. Offset is in
  16747.    the range between 0 and 15, inclusive. If you want an offset value larger
  16748.    than 15, you should adjust the frame number.
  16749.  
  16750.    Segment Length
  16751.  
  16752.    The Segment Length field gives a segment's length in bytes. This length
  16753.    may be zero. If it is, the linker does not delete the segment from the
  16754.    module. The Segment Length field is only large enough to hold numbers from
  16755.    0 to 64K-1, inclusive. To give the segment a length of 64K, you must use
  16756.    the B attribute bit in the ACBP field (see Segment ATTR in this section).
  16757.  
  16758.    Segment Name Index
  16759.  
  16760.    The segment name is a name that a programmer or translator assigns to the
  16761.    segment; for example, CODE, DATA, MODULENAME_CODE, TAXDATA, or STACK. The
  16762.    Segment Name Index field provides the segment name by indexing into the
  16763.    list of names provided by the LNAMES record.
  16764.  
  16765.    Class Name Index
  16766.  
  16767.    The class name is a name that a programmer or translator assigns to a
  16768.    segment. If none is assigned, the name is null and has a length of zero.
  16769.    The purpose of a class name is to let the programmer define a "handle" to
  16770.    order the LSEGs in MAS; for example, RED, WHITE, BLUE; or ROM, FASTRAM,
  16771.    DISPLAYRAM. The Class Name Index field provides the class name by indexing
  16772.    into the list of names provided by the LNAMES record.
  16773.  
  16774.    Overlay Name Index
  16775.  
  16776.    The overlay name is a name that the translator and/or the linker, at the
  16777.    programmer's request, applies to a segment. The overlay name, like the
  16778.    class name, may be null. The Overlay Name Index field provides the overlay
  16779.    name by indexing into the list of names provided by the LNAMES record.
  16780.  
  16781.    ──────────────────────────────────────────────────────────────────────────
  16782.    Note
  16783.      Microsoft language linkers (versions 3.00 and later) ignore the Overlay
  16784.      Name Index field, but the standard MS-DOS linker supports it.
  16785.    ──────────────────────────────────────────────────────────────────────────
  16786.  
  16787.  7.5.6  Group Definition Record (GRPDEF)
  16788.  
  16789.    ┌─────┬──────────┬─────///────┬────///─────┬─────┐
  16790.    │     │          │            │            │     │
  16791.    │ REC │  Record  │    Group   │   Group    │ CHK │
  16792.    │ TYP │  Length  │    Name    │  Component │ SUM │
  16793.    │ 9AH │          │    Index   │ Descriptor │     │
  16794.    │     │          │            │            │     │
  16795.    └─────┴──────────┴──///───────┤──///───────┼─────┘
  16796.                                  │            │
  16797.                                  └──repeated──┘
  16798.  
  16799.    Group Name Index
  16800.  
  16801.    The linker may reference a collection of LSEGs with the group name. Most
  16802.    importantly, when the LSEGs are eventually fixed in MAS, a frame must
  16803.    exist that "covers" every LSEG of the group.
  16804.  
  16805.    The Group Name Index field provides the group name by indexing into the
  16806.    list of names provided by the LNAMES record.
  16807.  
  16808.    Group Component Descriptor
  16809.  
  16810.    This repeatable field has the following format:
  16811.  
  16812.    ┌─────┬────///────┐
  16813.    │     │           │
  16814.    │ FFH │  Segment  │
  16815.    │     │   Index   │
  16816.    │     │           │
  16817.    │     │           │
  16818.    └─────┴────///────┘
  16819.  
  16820.    The first byte of the Group Component Descriptor field contains 0FFH; the
  16821.    descriptor contains one field, which is a segment index that selects the
  16822.    LSEG described by a preceding SEGDEF record.
  16823.  
  16824.  7.5.7  Public Names Definition Record (PUBDEF)
  16825.  
  16826.    ┌────┬──────────┬────///──┬───///───┬───────┬──///──┬─────┐
  16827.    │    │          │         │         │       │       │     │
  16828.    │ REC│  Record  │  Public │ Public  │Public │ Type  │ CHK │
  16829.    │ TYP│  Length  │   Base  │  Name   │Offset │ Index │ SUM │
  16830.    │ 90H│          │         │         │       │       │     │
  16831.    │    │          │         │         │       │       │     │
  16832.    └────┴──────────┴────///──┼──///────┴───────┴─///───┼─────┘
  16833.                              │                         │
  16834.                              └─────────repeated────────┘
  16835.  
  16836.    The PUBDEF record provides a list of one or more public names. For each
  16837.    name, three kinds of data are provided: (1) a base value for the name, (2)
  16838.    the offset value of the name, and (3) the type of entity represented by
  16839.    the name.
  16840.  
  16841.    Public Base
  16842.  
  16843.    The Public Base field has the following format:
  16844.  
  16845.    ┌────///────┬────///────┬───────────┐
  16846.    │           │           │           │
  16847.    │   Group   │  Segment  │   Frame   │
  16848.    │   Index   │   Index   │   Number  │
  16849.    │           │           │           │
  16850.    └────///────┴────///────┼───────────┤
  16851.                            │           │
  16852.                            └conditional┘
  16853.  
  16854.    The Group Index field has a format, which was given earlier, and contains
  16855.    a number between 0 and 32,767, inclusive. A nonzero value in the Group
  16856.    Index field associates a group with the public symbol and is used as
  16857.    described in case (F2c) of Section 7.3, "Conceptual Framework for
  16858.    Fixups." A zero value in the Group Index field indicates that there is no
  16859.    associated group.
  16860.  
  16861.    The Segment Index field has a format, which was given earlier, and
  16862.    contains a number between 0 and 32,767, inclusive.
  16863.  
  16864.    A nonzero value in the Segment Index field selects an LSEG. In this case,
  16865.    the location of each public symbol defined in the record is taken as a
  16866.    nonnegative displacement (given by a Public Offset field) from the first
  16867.    byte of the selected LSEG. Also, the Frame Number field must be absent.
  16868.  
  16869.    A zero value in the Segment Index field means that the defined symbols are
  16870.    absolute, and that the absolute addresses of the symbols are the values in
  16871.    the Public Offset field. The Group Index field is ignored. The Frame
  16872.    Number field contains a frame number only if the value of the Segment
  16873.    Index field is zero. The linker ignores this field.
  16874.  
  16875.    A nonzero value in the Group Index field selects some group. This group is
  16876.    taken as the "frame of reference" for references to all public symbols
  16877.    defined in this record. That is, the linker performs the following
  16878.    actions:
  16879.  
  16880.    ■  The linker converts any fixup of the form:
  16881.  
  16882.       Target: EI(P)
  16883.  
  16884.       Frame: Target
  16885.  
  16886.       (where P is a public symbol in this PUBDEF record) to a fixup of the
  16887.       form:
  16888.  
  16889.       Target: SI(L),d
  16890.  
  16891.       Frame: GI(G)
  16892.  
  16893.       where SI(L) and d are provided by the Segment Index and Public Offset
  16894.       fields. (The "normal" action would have the frame specifier in the new
  16895.       fixup be the same as in the old fixup: Frame:Target.)
  16896.  
  16897.    ■  When the linker converts the value of a public symbol, as defined by
  16898.       the Segment Index, Public Offset, and (optionally) Frame Number fields,
  16899.       to a {base,offset} pair, the base part is the base of the indicated
  16900.       group.
  16901.  
  16902.    A zero value in the Group Index field selects no group. The linker does
  16903.    not alter the frame specification of fixups referencing the symbol, and
  16904.    takes, as the base part of the absolute value of the public symbol, the
  16905.    canonic frame of the segment (either LSEG or PSEG) determined by the
  16906.    Segment Index field.
  16907.  
  16908.    Public Name
  16909.  
  16910.    The Public Name field gives the name of the object whose location in MAS
  16911.    is made available to other modules by the linker. The name must contain
  16912.    one or more characters.
  16913.  
  16914.    Public Offset
  16915.  
  16916.    The Public Offset field is a 16-bit value. It is either the offset of the
  16917.    public symbol with respect to an LSEG (if the segment index is greater
  16918.    than zero), or the offset of the public symbol with respect to the
  16919.    specified frame (if the segment index is equal to zero).
  16920.  
  16921.    Type Index
  16922.  
  16923.    The Type Index field identifies a single preceding TYPDEF (Type Definition
  16924.    Record), which contains a descriptor for the type of entity represented by
  16925.    the public symbol. The linker ignores this field.
  16926.  
  16927.  7.5.8  Communal Names Definition Record (COMDEF)
  16928.  
  16929.    ┌─────┬─────┬────///────┬────///────┬──────┬──────────┬─────┐
  16930.    │     │     │           │           │      │          │     │
  16931.    │ REC │ REC │ Communal  │   Type    │ Data │ Communal │ CHK │
  16932.    │ TYP │ LEN │   Name    │   Index   │ Seg  │ Length   │ SUM │
  16933.    │ B0H │     │           │           │ Type │          │     │
  16934.    │     │     │           │           │      │          │     │
  16935.    └─────┴─────┼────///────┴────///────┴──────┴──────────┼─────┴
  16936.                │                                         │
  16937.                └───────repeated──────────────────────────┘
  16938.  
  16939.    The COMDEF record provides a list of one or more Communal Names, which
  16940.    define communal variables. A communal variable is an uninitialized public
  16941.    variable whose final size and location are not fixed during compiling.
  16942.  
  16943.    Communal variables are similar to FORTRAN common blocks in that if you are
  16944.    linking object modules that each declare a communal variable, then the
  16945.    size of that variable is the largest of the declared variables. In the C
  16946.    language, all uninitialized public variables are communal. The following
  16947.    example shows three different declarations of the same C communal
  16948.    variable:
  16949.  
  16950.    char    foo[4];          /* In file a.c */
  16951.    char    foo[1];          /* In file b.c */
  16952.    char    foo[1024];       /* In file c.c */
  16953.  
  16954.    If the objects produced from a.c, b.c, and c.c are linked together, the
  16955.    linker allocates 1024 bytes for the character array "foo."
  16956.  
  16957.    ──────────────────────────────────────────────────────────────────────────
  16958.    Note
  16959.      This record requires that a COMENT record from the Microsoft Extensions
  16960.      class appear before it in the object module.
  16961.    ──────────────────────────────────────────────────────────────────────────
  16962.  
  16963.    Communal Name
  16964.  
  16965.    The Communal Name field gives the communal variable name and must contain
  16966.    one or more characters.
  16967.  
  16968.    Communal names are treated as external names when an external name is
  16969.    requested elsewhere in the module. Communal names are ordered together
  16970.    with external names for the purpose of referring to an external name by
  16971.    its index. (See the description of the EXTDEF record later in this
  16972.    section for more details on external names.)
  16973.  
  16974.    Type Index
  16975.  
  16976.    The Type Index field is ignored by the Microsoft linker.
  16977.  
  16978.    Data Segment Type
  16979.  
  16980.    The Data Segment Type field is a single byte that describes the data
  16981.    segment in which the communal variable resides. It can contain the
  16982.    following values:
  16983.  
  16984.        62H (NEAR) = the communal variable is in the default data segment.
  16985.        61H (FAR) = the communal variable is not in the default data segment.
  16986.  
  16987.  
  16988.    Communal Length
  16989.  
  16990.    The Communal Length field describes the length of the communal variable
  16991.    according to its data segment type.
  16992.  
  16993.    If its value is NEAR (62H), the field represents the length in bytes.
  16994.  
  16995.    If its value is FAR (61H), the field represents:
  16996.  
  16997.    ┌─────//────┬─────///──────┐
  16998.    │ Number of │ Element size │
  16999.    │ elements  │ in bytes     │
  17000.    └────///────┴─────///──────┘
  17001.  
  17002.  
  17003.    The format of all the length fields is as follows:
  17004.  
  17005.    ┌─────┐
  17006.    │     │
  17007.    │  0  │
  17008.    │ to  │
  17009.    │ 127 │
  17010.    │     │
  17011.    └─────┘
  17012.  
  17013.    ┌─────┬───────────┐
  17014.    │     │           │
  17015.    │     │     0     │
  17016.    │ 129 │    to     │
  17017.    │(81H)│   64K-1   │
  17018.    │     │           │
  17019.    └─────┴───────────┘
  17020.  
  17021.    ┌─────┬─────────────────┐
  17022.    │     │                 │
  17023.    │     │        0        │
  17024.    │ 132 │       to        │
  17025.    │(84H)│      16M-1      │
  17026.    │     │                 │
  17027.    └─────┴─────────────────┘
  17028.  
  17029.    ┌─────┬─────────────────┐
  17030.    │     │                 │
  17031.    │     │     -2G-1       │
  17032.    │ 136 │       to        │
  17033.    │(88H)│      2G-1       │
  17034.    │     │                 │
  17035.    └─────┴─────────────────┘
  17036.  
  17037.    The first format (single byte), containing a value between 0 and 127,
  17038.    represents the number given.
  17039.  
  17040.    The second format, with a leading byte containing 129, represents the
  17041.    number contained in the following two bytes.
  17042.  
  17043.    The third format, with a leading byte containing 132, represents the
  17044.    number contained in the following three bytes.
  17045.  
  17046.    The fourth format, with a leading byte containing 136, represents the
  17047.    number contained in the following four bytes with its sign extended if
  17048.    necessary.
  17049.  
  17050.    Link-Time Semantics
  17051.  
  17052.    A PUBDEF matching a communal variable definition overrides the communal
  17053.    variable definition. Two communal variable definitions match if the names
  17054.    in their definitions match. If two matching definitions disagree on
  17055.    whether a communal variable is NEAR or FAR, the linker assumes the
  17056.    variable is NEAR.
  17057.  
  17058.    If the variable is NEAR, then its size is the largest of the sizes
  17059.    specified for it. If the variable is FAR, the linker issues a warning if
  17060.    the array element sizes conflict. If these sizes don't conflict, the
  17061.    variable's size is the element size multiplied by the largest number of
  17062.    elements specified. In addition, the sum of the sizes of all NEAR
  17063.    variables must not exceed 64 kilobytes, and the sum of the sizes of all
  17064.    FAR variables must not exceed the size of the machine's addressable memory
  17065.    space.
  17066.  
  17067.    HUGE Communal Variables:
  17068.  
  17069.    A FAR communal variable that is larger than 64 kilobytes (a HUGE communal
  17070.    variable) resides in segments that are contiguous (on an 8086) or that
  17071.    have consecutive selectors (on an 80286). No other data items reside in
  17072.    the segments occupied by a HUGE communal variable.
  17073.  
  17074.    If the linker finds matching HUGE and NEAR communal variable definitions,
  17075.    it issues a warning message, since it is impossible for a NEAR variable to
  17076.    be larger than 64 kilobytes.
  17077.  
  17078.  7.5.9  Local Symbols Record (LOCSYM)
  17079.  
  17080.    ┌────┬──────────┬────///──┬───///───┬───────┬──///──┬─────┐
  17081.    │    │          │         │         │       │       │     │
  17082.    │ REC│  Record  │  Local  │ Local   │ Local │ Type  │ CHK │
  17083.    │ TYP│  Length  │   Base  │  Name   │Offset │ Index │ SUM │
  17084.    │ 92H│          │         │         │       │       │     │
  17085.    │    │          │         │         │       │       │     │
  17086.    └────┴──────────┴────///──┼──///────┴───────┴─///───┼─────┘
  17087.                              │                         │
  17088.                              └─────────repeated────────┘
  17089.  
  17090.    The LOCSYM record provides information for the definition of a local
  17091.    symbol, one that is visible only within the module in which it is defined.
  17092.  
  17093.    The form and meaning of each of the fields is identical to those in the
  17094.    PUBDEF record.
  17095.  
  17096.    ──────────────────────────────────────────────────────────────────────────
  17097.    Note
  17098.      The LOCSYM record requires that a COMENT record from the Microsoft
  17099.      Extensions class appear before it in the object module. Also, it is only
  17100.      recognized by Microsoft language linkers later than version 3.07.
  17101.    ──────────────────────────────────────────────────────────────────────────
  17102.  
  17103.  7.5.10  External Names Definition Record (EXTDEF)
  17104.  
  17105.    ┌─────┬───────────┬────///────┬────///────┬─────┐
  17106.    │     │           │           │           │     │
  17107.    │ REC │  Record   │ External  │   Type    │ CHK │
  17108.    │ TYP │  Length   │   Name    │   Index   │ SUM │
  17109.    │ 8CH │           │           │           │     │
  17110.    │     │           │           │           │     │
  17111.    └─────┴───────────┼────///────┴────///────┼─────┘
  17112.                      │                       │
  17113.                      └───────repeated────────┘
  17114.  
  17115.    The EXTDEF record provides a list of external names and, for each name,
  17116.    the type of object it represents. The linker assigns to each external name
  17117.    the value provided by an identical public name or local name (if such a
  17118.    name is found).
  17119.  
  17120.    External Name
  17121.  
  17122.    The External Name field provides the external object name, which must have
  17123.    a nonzero length.
  17124.  
  17125.    Including a name in an EXTDEF record is an implicit request to link the
  17126.    object file to a module containing the same name declared as a public
  17127.    symbol, unless the name is defined as a local symbol within the same
  17128.    module as the EXTDEF. This request determines whether or not the external
  17129.    name is referenced within some FIXUPP record in the module.
  17130.  
  17131.    The order of EXTDEF records in a module and the order of external names
  17132.    within each EXTDEF record, together with COMDEF records and communal
  17133.    names, imply a mapping on the set of all external names requested by the
  17134.    module; for example: 1, 2, 3, etc. So to refer to a particular external
  17135.    name, the linker uses these numbers as "external indices" in the Target
  17136.    Datum and/or Frame Datum fields of FIXUPP records.
  17137.  
  17138.    External indices may not reference forward. For example, an EXTDEF
  17139.    defining the kth object must precede any record referring to that object
  17140.    with index k.
  17141.  
  17142.    Type Index
  17143.  
  17144.    The Type Index field is ignored by the Microsoft linker, except for linker
  17145.    versions earlier than 3.05, and for object modules lacking the COMENT
  17146.    record from the Microsoft Extensions class. For that case, refer to
  17147.    Section 7.6, "Microsoft Type Representations for Communal Variables."
  17148.  
  17149.  7.5.11  Line Numbers Record (LINNUM)
  17150.  
  17151.    ┌─────┬──────────┬─────///───┬───────────┬───────────┬─────┐
  17152.    │     │          │           │           │           │     │
  17153.    │ REC │  Record  │   Line    │   Line    │   Line    │ CHK │
  17154.    │ TYP │  Length  │  Number   │  Number   │  Number   │ SUM │
  17155.    │ 94H │          │   Base    │           │  Offset   │     │
  17156.    │     │          │           │           │           │     │
  17157.    └─────┴──────────┴────///────┼───────────┴───────────┼─────┘
  17158.                                 │                       │
  17159.                                 └────────repeated───────┘
  17160.  
  17161.    The LINNUM record allows a translator to relate a line number in source
  17162.    code to the corresponding line in translated code.
  17163.  
  17164.    Line Number Base
  17165.  
  17166.    The Line Number Base field has the following format:
  17167.  
  17168.    ┌────///────┬────///────┐
  17169.    │           │           │
  17170.    │   Group   │  Segment  │
  17171.    │   Index   │   Index   │
  17172.    │           │           │
  17173.    └────///────┴────///────┘
  17174.  
  17175.    The Group Index field is ignored by the Microsoft linker.
  17176.  
  17177.    The Segment Index field determines the location of the first byte of code
  17178.    corresponding to some source line number.
  17179.  
  17180.    Line Number
  17181.  
  17182.    The Line Number field provides a binary line number between 0 and 32,767,
  17183.    inclusive. If the high-order bit is not zero, the number is considered
  17184.    undefined.
  17185.  
  17186.    Line Number Offset
  17187.  
  17188.    The Line Number Offset field is a 16-bit value, which is the offset of the
  17189.    line number with respect to an LSEG (if the segment index is greater than
  17190.    zero).
  17191.  
  17192.  7.5.12  Logical Enumerated Data Record (LEDATA)
  17193.  
  17194.    ┌─────┬───────────┬────///────┬───────────┬─────┬─────┐
  17195.    │     │           │           │           │     │     │
  17196.    │ REC │  Record   │  Segment  │ Enumerated│     │ CHK │
  17197.    │ TYP │  Length   │   Index   │   Data    │ DAT │ SUM │
  17198.    │ A0H │           │           │  offset   │     │     │
  17199.    │     │           │           │           │     │     │
  17200.    └─────┴───────────┴────///────┴───────────┼─────┼─────┘
  17201.                                              │     │
  17202.                                              └─rpt─┘
  17203.  
  17204.    The LEDATA record provides contiguous data from which the linker may
  17205.    construct a portion of an 8086 memory image.
  17206.  
  17207.    Segment Index
  17208.  
  17209.    The Segment Index field, which must be nonzero, specifies an index
  17210.    relative to the SEGDEF records that precede the LEDATA record.
  17211.  
  17212.    Enumerated Data Offset
  17213.  
  17214.    The Enumerated Data Offset field specifies an offset that is relative to
  17215.    the base of the LSEG specified by the segment index. The field also
  17216.    defines the relative location of the first byte of the DAT field.
  17217.    Successive data bytes in the DAT field occupy successively higher
  17218.    locations of memory.
  17219.  
  17220.    DAT
  17221.  
  17222.    The DAT field provides up to 1024 consecutive bytes of relocatable or
  17223.    absolute data.
  17224.  
  17225.  7.5.13  Logical Iterated Data Record (LIDATA)
  17226.  
  17227.    ┌─────┬──────────┬────///────┬───────────┬────///────┬─────┐
  17228.    │     │          │           │           │           │     │
  17229.    │ REC │  Record  │  Segment  │  Iterated │  Iterated │ CHK │
  17230.    │ TYP │  Length  │   Index   │    Data   │   Data    │ SUM │
  17231.    │ A2H │          │           │   Offset  │   Block   │     │
  17232.    │     │          │           │           │           │     │
  17233.    └─────┴──────────┴────///────┴───────────┼────///────┼─────┘
  17234.                                             │           │
  17235.                                             └─repeated──┘
  17236.  
  17237.    The LIDATA record provides contiguous data from which the linker may
  17238.    construct a portion of an 8086 memory image.
  17239.  
  17240.    Segment Index
  17241.  
  17242.    The Segment Index field, which must be nonzero, specifies an index that is
  17243.    relative to the SEGDEF records that precede the LIDATA record.
  17244.  
  17245.    Iterated Data Offset
  17246.  
  17247.    The Iterated Data Offset field specifies an offset that is relative to the
  17248.    base of the LSEG specified by the segment index. It also defines the
  17249.    relative location of the first byte in the iterated data block. Successive
  17250.    data bytes in the iterated data block occupy successively higher locations
  17251.    of memory.
  17252.  
  17253.    Iterated Data Block
  17254.  
  17255.    This repeated field is a structure specifying the repeated data bytes. It
  17256.    has the following format:
  17257.  
  17258.    ┌──────────┬────────────┬────///────┐
  17259.    │          │            │           │
  17260.    │  Repeat  │   Block    │           │
  17261.    │   Count  │   Count    │  Content  │
  17262.    │          │            │           │
  17263.    │          │            │           │
  17264.    └──────────┴────────────┴────///────┘
  17265.  
  17266.    ──────────────────────────────────────────────────────────────────────────
  17267.    Note
  17268.      The linker cannot handle LIDATA records whose iterated data blocks are
  17269.      larger than 512 bytes.
  17270.    ──────────────────────────────────────────────────────────────────────────
  17271.  
  17272.    Repeat Count:
  17273.  
  17274.    The Repeat Count field specifies the number of times to repeat the Content
  17275.    portion of this iterated data block. The value of the Repeat Count field
  17276.    must be nonzero.
  17277.  
  17278.    Block Count:
  17279.  
  17280.    The Block Count field specifies the number of iterated data blocks in the
  17281.    Content portion of this iterated data block. If the Block Count field has
  17282.    a value of zero, the Content portion of the iterated data block is
  17283.    interpreted as data bytes. If the field is nonzero, the Content portion is
  17284.    interpreted as that number of iterated data blocks.
  17285.  
  17286.    Content:
  17287.  
  17288.    The Content field may be interpreted in one of two ways, depending on the
  17289.    value of the previous Block Count field.
  17290.  
  17291.    If the Block Count field is zero, this field is a 1-byte count followed by
  17292.    the indicated number of data bytes. But if the Block Count field is
  17293.    nonzero, the Content field is interpreted as the first byte of another
  17294.    iterated data block.
  17295.  
  17296.  7.5.14  Fixup Record (FIXUPP)
  17297.  
  17298.    ┌─────┬───────────┬────///────┬─────┐
  17299.    │     │           │           │     │
  17300.    │ REC │  Record   │  Thread   │ CHK │
  17301.    │ TYP │  Length   │    or     │ SUM │
  17302.    │ 9CH │           │   Fixup   │     │
  17303.    │     │           │           │     │
  17304.    └─────┴───────────┼────///────┼─────┘
  17305.                      │           │
  17306.                      └────rpt────┘
  17307.  
  17308.    The FIXUPP record specifies zero or more fixups. Each fixup requests a
  17309.    modification (fixup) to a location within the previous data record. A data
  17310.    record may be followed by more than one FIXUPP record that refers to it.
  17311.    Each fixup is specified by a Fixup field that specifies four kinds of
  17312.    data: a location, a mode, a target, and a frame. The frame and target may
  17313.    be specified completely within the Fixup field, or by reference to a
  17314.    preceding Thread field.
  17315.  
  17316.    A Thread field specifies a default target or frame that subsequently may
  17317.    be referred to. Eight threads are provided──four for frame specification
  17318.    and four for target specification. Once a thread has specified a target or
  17319.    frame, any Fixup fields that follow (in the same or following FIXUPP
  17320.    records) may refer to that target or frame until another Thread field with
  17321.    the same type (target or frame) and thread number (0-3) appears (in the
  17322.    same or in another FIXUPP record).
  17323.  
  17324.    Thread
  17325.  
  17326.    The Thread field has the following format:
  17327.  
  17328.    ┌─────┬────///────┐
  17329.    │     │           │
  17330.    │ TRD │   Index   │
  17331.    │ DAT │           │
  17332.    │     │           │
  17333.    └─────┼────///────│
  17334.          │           │
  17335.          └condiional─┘
  17336.  
  17337.    The TRD DAT (Thread Data) field is a byte with the following internal
  17338.    structure:
  17339.  
  17340.    ┌───┬───┬───┬───────────┬───────┐
  17341.    │   │   │   │           │       │
  17342.    │ 0 │ D │ 0 │  Method   │ THRED │
  17343.    │   │   │   │           │       │
  17344.    └───┴───┴───┴───────────┴───────┘
  17345.  
  17346.    The D field is one bit and defines the type of thread being used. If D=0,
  17347.    this bit defines a target thread, and if D=1, it defines a frame thread.
  17348.  
  17349.    Method is a 3-bit field containing a number between 0 and 3 (if D=0) or a
  17350.    number between 0 and 6 (if D=1).
  17351.  
  17352.    If D=0, then Method = (0, 1, 2, 4, 5, 6)mod 4, where 0, 1, 2, 4, 5, 6
  17353.    indicate methods T0, T1, T2, T4, T5, and T6 of specifying a target. Thus,
  17354.    Method indicates the kind of index or frame number required to specify the
  17355.    target, without indicating whether the target is specified by a primary or
  17356.    secondary method.
  17357.  
  17358.    If D=1, then Method = 0, 1, 2, 4, 5, corresponding to methods F0, F1, F2,
  17359.    F4, F5 of specifying a frame. Here, Method indicates the kind (if any) of
  17360.    index required to specify the frame.
  17361.  
  17362.    The THRED field contains a number between 0 and 3, inclusive, and
  17363.    associates a thread number to the frame or target defined by the Thread
  17364.    field.
  17365.  
  17366.    The Index field contains a segment index, group index, or external index
  17367.    depending on the specification in the Method field. If Method specifies F4
  17368.    or F5, this field will not be present.
  17369.  
  17370.    Fixup
  17371.  
  17372.    The Fixup field has the following format:
  17373.  
  17374.    ┌───────────┬─────┬────///────┬────///────┬────///────┐
  17375.    │           │     │           │           │           │
  17376.    │   LOCAT   │ FIX │   Frame   │  Target   │  Target   │
  17377.    │           │ DAT │   Datum   │   Datum   │   Dis-    │
  17378.    │           │     │           │           │ Placement │
  17379.    │           │     │           │           │           │
  17380.    └───────────┴─────┼────///────┼────///────┼────///────│
  17381.                      │           │           │           │
  17382.                      └────────────conditional────────────┘
  17383.  
  17384.    The LOCAT field is a byte pair with the following format:
  17385.  
  17386.    ┌───┬───┬───┬───────────┬───────────────────────────────────────┐
  17387.    │   │   │   │           │                                       │
  17388.    │ 1 │ M │ 0 │    LOC    │  D a t a   R e c o r d   O f f s e t  │
  17389.    │   │   │   │           │                                       │
  17390.    ├───┴───┴───┴───────────┴───────┬───────────────────────────────┤
  17391.    │                               │                               │
  17392.    └────────────lo byte────────────┴────────────hi byte────────────┘
  17393.  
  17394.    M is a 1-bit field that specifies the mode of the fixups: self-relative
  17395.    (if M=0) or segment-relative (if M=1).
  17396.  
  17397.    ──────────────────────────────────────────────────────────────────────────
  17398.    Note
  17399.      Self-relative fixups may not be applied to LIDATA records.
  17400.    ──────────────────────────────────────────────────────────────────────────
  17401.  
  17402.    LOC is a 3-bit field indicating that the byte(s) in the preceding data
  17403.    record to be fixed up are a lobyte (if LOC=0), an offset (if LOC=1), a
  17404.    base (if LOC=2), a pointer (if LOC=3), a hibyte (if LOC=4), or a
  17405.    "loader-resolved" offset (if LOC=5). Any other values in LOC are invalid.
  17406.  
  17407.    The Data Record Offset field contains a number between 0 and 1023,
  17408.    inclusive, that gives the relative position of the lowest order byte of
  17409.    location (the actual bytes being fixed up) within the preceding data
  17410.    record. The Data Record Offset value is relative to the first byte in the
  17411.    data fields in the data records.
  17412.  
  17413.    ──────────────────────────────────────────────────────────────────────────
  17414.    Note
  17415.      If the preceding data record is an LIDATA record, it is possible for the
  17416.      Data Record Offset value to designate a location within a Repeat Count
  17417.      field or a Block Count field of the Iterated Data Block field. Such a
  17418.      reference is an error. The linker's action on such a malformed record is
  17419.      undefined.
  17420.    ──────────────────────────────────────────────────────────────────────────
  17421.  
  17422.    The FIX DAT field is a byte with the following format:
  17423.  
  17424.    ┌───┬───────────┬───┬───┬───────┐
  17425.    │   │           │   │   │       │
  17426.    │ F │   Frame   │ T │ P │ TARGT │
  17427.    │   │           │   │   │       │
  17428.    └───┴───────────┴───┴───┴───────┘
  17429.  
  17430.    F is a 1-bit subfield that specifies whether the frame for this fixup is
  17431.    specified by a thread (if F=1) or explicitly (if F=0).
  17432.  
  17433.    The Frame field contains a number that is interpreted in one of two ways,
  17434.    as indicated by the F bit. If F is zero, the Frame field contains a number
  17435.    between 0 and 5, inclusive, corresponding to methods F0,...,F5 for
  17436.    specifying a frame. If F=1, then the Frame field contains a thread number
  17437.    (0-3). It specifies the frame most recently defined by a Thread field that
  17438.    defined a frame thread with the same thread number. (Notice that the
  17439.    Thread field may appear in the same FIXUPP record, or in an earlier one.)
  17440.  
  17441.    T is a 1-bit field that specifies whether the target specified for this
  17442.    fixup is defined by reference to a thread (T=1), or is given explicitly in
  17443.    the Fixup field (T=0).
  17444.  
  17445.    P is a 1-bit field that indicates whether the Target is specified by a
  17446.    primary method (requires a target displacement, if P=0) or by a secondary
  17447.    method (requires no target displacement, if P=1). Since a target thread
  17448.    does not have a primary/secondary attribute, the P bit is the only field
  17449.    that contains the target specification attribute.
  17450.  
  17451.    TARGT is interpreted as a 2-bit field. When T=0, it provides a number
  17452.    between 0 and 3, inclusive, corresponding to methods T0, T1, T2 or T4, T5,
  17453.    T6, depending on the value of P (where P is interpreted as the high-order
  17454.    bit of T0, T1, T2, T4, T5, or T6). When a thread specifies the target (if
  17455.    T=1), then the TARGET field specifies a thread number (0-3).
  17456.  
  17457.    The Frame Datum field is the "referent" portion of a frame specification,
  17458.    and is a segment index, group index, or external index. The Frame Datum
  17459.    field is present only when the frame is not specified by a thread (if F=0)
  17460.    or explicitly by methods F4, F5, or F6.
  17461.  
  17462.    The Target Datum field is the "referent" portion of a target
  17463.    specification, and is a segment index, group index, or external index. The
  17464.    Target Datum field is present only when a thread does not specify the
  17465.    target (if T=0).
  17466.  
  17467.    The Target Displacement field is the 2-byte displacement required by
  17468.    primary methods of specifying targets. This field is present if P=0.
  17469.  
  17470.    ──────────────────────────────────────────────────────────────────────────
  17471.    Note
  17472.      All these methods are described in Section 7.3, "Conceptual Framework
  17473.      for Fixups."
  17474.    ──────────────────────────────────────────────────────────────────────────
  17475.  
  17476.  7.5.15  Module End Record (MODEND)
  17477.  
  17478.    ┌─────┬───────────┬─────┬────///────┬─────┐
  17479.    │     │           │     │           │     │
  17480.    │ REC │  Record   │ MOD │   START   │ CHK │
  17481.    │ TYP │  Length   │ TYP │   ADDRS   │ SUM │
  17482.    │ 8AH │           │     │           │     │
  17483.    │     │           │     │           │     │
  17484.    └─────┴───────────┴─────┼────///────┼─────┘
  17485.                            │           │
  17486.                            └conditional┘
  17487.  
  17488.    The MODEND record serves two purposes. It denotes the end of a module and
  17489.    indicates whether or not the module that just ended specifies an entry
  17490.    point to begin execution. If it does not, the linker specifies the
  17491.    execution address.
  17492.  
  17493.    MOD TYP
  17494.  
  17495.    The MOD TYP field specifies the attributes of the module. The bit
  17496.    allocation and associated meanings are as follows:
  17497.  
  17498.    ┌───────┬───┬───┬───┬───┬───┬───┐
  17499.    │       │   │   │   │   │   │   │
  17500.    │ MATTR │ 0 │ 0 │ 0 │ 0 │ 0 │ 1 │
  17501.    │       │   │   │   │   │   │   │
  17502.    └───────┴───┴───┴───┴───┴───┴───┘
  17503.  
  17504.    MATTR is a 2-bit field that specifies the following module attributes:
  17505.  
  17506.    MATTR              Module Attribute
  17507.    ──────────────────────────────────────────────────────────────────────────
  17508.    0                  Non-main module with no START ADDRS
  17509.    1                  Non-main module with START ADDRS
  17510.    2                  Main module with no START ADDRS
  17511.    3                  Main module with START ADDRS
  17512.    ──────────────────────────────────────────────────────────────────────────
  17513.  
  17514.    The START ADDRS field (present only if MATTR is 1 or 3) has the following
  17515.    format:
  17516.  
  17517.    ┌─────┬────///────┬────///────┬───────────┐
  17518.    │     │           │           │           │
  17519.    │ END │   Frame   │  Target   │  Target   │
  17520.    │ DAT │   Datum   │   Datum   │   Dis-    │
  17521.    │     │           │           │ Placement │
  17522.    │     │           │           │           │
  17523.    └─────┼────///────┴────///────┴───────────│
  17524.          │                                   │
  17525.          └────────────conditional────────────┘
  17526.  
  17527.    The starting address of a module has all the attributes of any other
  17528.    logical reference found in a module. The mapping of a logical starting
  17529.    address to a physical starting address is done in the same manner as
  17530.    mapping any other logical address to a physical address, as specified in
  17531.    the discussion of fixups and the FIXUPP record. The fields of the START
  17532.    ADDRS field have the same semantics as the FIX DAT, Frame Datum, Target
  17533.    Datum, and Target Displacement fields in the FIXUPP record. Only primary
  17534.    fixup methods are allowed. Frame method F4 is not allowed.
  17535.  
  17536.  7.5.16  Comment Record (COMENT)
  17537.  
  17538.    ┌─────┬───────────┬───────────┬────///────┬─────┐
  17539.    │     │           │           │           │     │
  17540.    │ REC │  Record   │  Comment  │           │ CHK │
  17541.    │ TYP │  Length   │   Type    │  Comment  │ SUM │
  17542.    │ 88H │           │           │           │     │
  17543.    │     │           │           │           │     │
  17544.    └─────┴───────────┴───────────┴────///────┴─────┘
  17545.  
  17546.    The COMENT record allows translators to include comments in object text.
  17547.  
  17548.    Comment Type
  17549.  
  17550.    The Comment Type field indicates the type of comment that this record
  17551.    carries, allowing you to structure comments for processes that selectively
  17552.    act on comments.
  17553.  
  17554.    The format of the Comment Type field is as follows:
  17555.  
  17556.    ┌───┬───┬───┬───┬───┬───┬───┬───┬──────────────────────┐
  17557.    │ N │ N │   │   │   │   │   │   │          Comment     │
  17558.    │ P │ L │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │           Class      │
  17559.    └───┴───┴───┴───┴───┴───┴───┴───┴──────────────────────┘
  17560.  
  17561.    The NP (NOPURGE) bit, if set to 1, indicates that this comment cannot be
  17562.    purged by object file utility programs that can delete Comment records.
  17563.  
  17564.    The NL (NOLIST) bit, if set to 1, indicates that the text in the Comment
  17565.    field should not appear in the listing file of object file utility
  17566.    programs that can list object Comment records.
  17567.  
  17568.    The Comment Class field is a byte defined as follows:
  17569.  
  17570. ╓┌─┌──────────────────┌──────────────────────────────────────────────────────╖
  17571.    Value              Meaning
  17572.    ──────────────────────────────────────────────────────────────────────────
  17573.    0                  Language Translator Comment (obsolete)
  17574.  
  17575.                       If the Comment field contains one of the strings "MS
  17576.                       PASCAL" or "FORTRAN 77," then the Comment record
  17577.                       enables the dsallocation switch on the Microsoft
  17578.                       linker.
  17579.    Value              Meaning
  17580.    ──────────────────────────────────────────────────────────────────────────
  17581.                      linker.
  17582.  
  17583.    156(9CH)           DOS Version
  17584.  
  17585.                       The Comment field contains a 2-byte integer that
  17586.                       specifies the DOS level number.
  17587.  
  17588.    157(9DH)           Memory Model
  17589.  
  17590.                       Indicates the memory model of the object module. The
  17591.                       Comment field contains a single byte with the values S,
  17592.                       M, L, or H, for SMALL, MEDIUM, LARGE, or HUGE,
  17593.                       respectively. This Comment record is used only by the
  17594.                       Microsoft XENIX linker.
  17595.  
  17596.    158(9EH)           Force Segment Ordering
  17597.  
  17598.                       Causes the linker to use a special segment ordering for
  17599.                       executable files. This Comment record has the same
  17600.    Value              Meaning
  17601.    ──────────────────────────────────────────────────────────────────────────
  17602.                      executable files. This Comment record has the same
  17603.                       effect as giving the dosseg switch to Microsoft
  17604.                       language versions of the linker.
  17605.  
  17606.    159(9FH)           Library Specifier
  17607.  
  17608.    129(81H)           Library Specifier (obsolete)
  17609.  
  17610.                       Specifies a library to add to the Microsoft linker's
  17611.                       library search list. The Comment field contains the
  17612.                       name of the library. Notice that, unlike all other name
  17613.                       specifications, the library name is not prefixed with
  17614.                       its length but is determined by the record length. The
  17615.                       nodefaultlibrarysearch switch causes the linker to
  17616.                       ignore these Comment records. The 159(9FH) class record
  17617.                       is ignored by XENIX versions of the Microsoft linker.
  17618.  
  17619.    161(A1H)           Microsoft Extensions
  17620.  
  17621.    Value              Meaning
  17622.    ──────────────────────────────────────────────────────────────────────────
  17623. 
  17624.                       Indicates that the object module contains extensions to
  17625.                       the original Microsoft adaptation of the Intel
  17626.                       Relocatable Object Module Format, such as the COMDEF
  17627.    ──────────────────────────────────────────────────────────────────────────
  17628.  
  17629.  
  17630.    Comment
  17631.  
  17632.    The Comment field provides the commentary information.
  17633.  
  17634.  
  17635.  7.6  Microsoft Type Representations for Communal Variables
  17636.  
  17637.    ──────────────────────────────────────────────────────────────────────────
  17638.    Note
  17639.      Object modules not containing the COMENT record from the Microsoft
  17640.      Extensions class can represent communal variable definitions only with
  17641.      the obsolete method described here. Also, Microsoft language linkers
  17642.      earlier than version 3.05 can recognize this method only. The newer
  17643.      method uses the Communal Variable Definitions (COMDEF) record.
  17644.    ──────────────────────────────────────────────────────────────────────────
  17645.  
  17646.    A communal variable is defined in the object text by an EXTDEF record and
  17647.    the TYPDEF record to which it refers.
  17648.  
  17649.    The TYPDEF record of a communal variable has the following format:
  17650.  
  17651.    ┌─────┬────────┬───┬─────///────┬─────┐
  17652.    │ REC │ Record │   │    Eight   │ CHK │
  17653.    │ TYP │ Length │ 0 │    Leaf    │ SUM │
  17654.    │ 8EH │        │   │ Descriptor │     │
  17655.    └─────┴────────┴───┴─────///────┴─────┘
  17656.  
  17657.    The Eight Leaf Descriptor field has the following format:
  17658.  
  17659.    ┌───┬────///─────┐
  17660.    │ E │    Leaf    │
  17661.    │ N │ Descriptor │
  17662.    └───┴────///─────┘
  17663.  
  17664.    The EN bitfield specifies whether the next eight leaves in the Leaf
  17665.    Descriptor field are EASY (if EN = 0) or NICE (if EN = l). This byte is
  17666.    always zero for TYPDEFs of communal variables. The Leaf Descriptor field
  17667.    has one of the following two formats. The format for communal variables in
  17668.    the default data segment (NEAR variables) is as follows:
  17669.  
  17670.    ┌──────┬─────┬────///───┬─///────┐
  17671.    │ NEAR │ VAR │  Length  │  VAR   │
  17672.    │ 62H  │ TYP │    In    │ SUBTYP │
  17673.    │      │     │   Bits   │        │
  17674.    └──────┴─────┴────///───┼──///───┤
  17675.                            │        │
  17676.                            └────────┘
  17677.                            (optional)
  17678.  
  17679.    The VARTYP (Variable Type) field may be either SCALAR (7BH), STRUCT (79H),
  17680.    or ARRAY (77H). The linker ignores the VAR SUBTYP field (if one exists).
  17681.    The format for communal variables not in the default data segment (FAR
  17682.    variables) is as follows:
  17683.  
  17684.    ┌─────┬─────┬────///───┬───///───┐
  17685.    │ FAR │ VAR │  Number  │ Element │
  17686.    │ 61H │ TYP │    of    │  Type   │
  17687.    │     │ 77H │ Elements │  Index  │
  17688.    └─────┴─────┴────///───┴───///───┘
  17689.  
  17690.    The VARTYP field must be ARRAY (77H). The Length in Bits field specifies
  17691.    the Number of Elements, and the Element Type Index is an index to a
  17692.    previously defined TYPDEF record whose format is that of a NEAR communal
  17693.    variable.
  17694.  
  17695.    The format for the Length in Bits or Number of Elements fields is the same
  17696.    as the format of the Communal Length field of the COMDEF record.
  17697.  
  17698.    Link-Time Semantics
  17699.  
  17700.    All EXTDEF records referencing a TYPDEF record of one of the previously
  17701.    described formats are treated as communal variables. All others are
  17702.    treated as externally defined symbols for which a matching PUBDEF record
  17703.    is expected.
  17704.  
  17705.    For more information, see "Link-Time Semantics" in Section 7.5.8,
  17706.    "Communal Names Definition Record (COMDEF)."
  17707.  
  17708.  
  17709.  
  17710.  ────────────────────────────────────────────────────────────────────────────
  17711.  Chapter 8  Programming Hints
  17712.  
  17713.      8.1   Introduction
  17714.      8.2   Interrupts
  17715.      8.3   System Calls
  17716.      8.4   Device Management
  17717.      8.5   Memory Management
  17718.      8.6   Process Management
  17719.      8.7   File and Directory Management
  17720.            8.7.1   Locking Files
  17721.      8.8   Miscellaneous
  17722.  
  17723.  
  17724.  8.1  Introduction
  17725.  
  17726.    This chapter describes recommended MS-DOS 4.0 programming procedures. By
  17727.    using these programming hints, you can ensure compatibility with future
  17728.    versions of MS-DOS.
  17729.  
  17730.    The hints are organized in the following categories:
  17731.  
  17732.    ■  Interrupts
  17733.  
  17734.    ■  System Calls
  17735.  
  17736.    ■  Device Management
  17737.  
  17738.    ■  Memory Management
  17739.  
  17740.    ■  Process Management
  17741.  
  17742.    ■  File and Directory Management
  17743.  
  17744.    ■  Miscellaneous
  17745.  
  17746.  
  17747.  8.2  Interrupts
  17748.  
  17749.    ■  Never explicitly issue Interrupt 22H (Terminate Process Exit Address).
  17750.  
  17751.       Only the DOS should do this. To change the terminate address, use
  17752.       Function 35H (Get Interrupt Vector) to get the current address and
  17753.       save it, then use Function 25H (Set Interrupt Vector) to change the
  17754.       Interrupt 22H entry in the vector table to point to the new terminate
  17755.       address.
  17756.  
  17757.    ■  Use Interrupt 24H (Critical-Error-Handler Address) with care. The
  17758.       Interrupt 24H handler must preserve the ES register.
  17759.  
  17760.       An Interrupt 24H handler can issue only the system calls 01H-0CH.
  17761.       Making any other calls destroys the MS-DOS stack and prevents
  17762.       successful use of the Retry or Ignore options.
  17763.  
  17764.       When using the Retry or Ignore options, you must preserve the SS, SP,
  17765.       DS, BX, CX, and DX registers.
  17766.  
  17767.    ■  When an Interrupt 24H (Critical-Error-Handler Address) is received,
  17768.       always IRET back to MS-DOS with one of the standard responses.
  17769.  
  17770.       Programs that do not IRET from Interrupt 24H leave the system in an
  17771.       unpredictable state until a function call other than 01H-0CH is made.
  17772.       The Ignore option may leave incorrect or invalid data in internal
  17773.       system buffers.
  17774.  
  17775.    ■  Avoid trapping Interrupt 23H (CONTROL+C Handler Address) and Interrupt
  17776.       24H (Critical-Error-Handler Address). Don't rely on trapping errors
  17777.       via Interrupt 24H as part of a copy protection scheme.
  17778.  
  17779.       These methods might not be included in future releases of MS-DOS.
  17780.  
  17781.    ■  A user program must never issue Interrupt 23H (CONTROL+C Handler
  17782.       Address).
  17783.  
  17784.       Only MS-DOS may issue Interrupt 23H.
  17785.  
  17786.    ■  Save any registers that your program uses before issuing Interrupt
  17787.       25H (Absolute Disk Read) or Interrupt 26H (Absolute Disk Write).
  17788.  
  17789.       These interrupts destroy all registers except for the segment
  17790.       registers.
  17791.  
  17792.       Avoid writing or reading an interrupt vector directly to or from
  17793.       memory.
  17794.  
  17795.    ■  Use Functions 25H and 35H (Set Interrupt Vector and Get Interrupt
  17796.       Vector) to set and get values in the interrupt table.
  17797.  
  17798.  
  17799.  8.3  System Calls
  17800.  
  17801.    ■  Use new system calls.
  17802.  
  17803.       Avoid using system calls that have been superseded by new calls unless
  17804.       the program must maintain backward compatibility with MS-DOS versions
  17805.       before 2.0. See Section 1.9, "Old System Calls," for a list of these
  17806.       new calls.
  17807.  
  17808.    ■  Avoid using functions 01H-0CH and 26H (Create New PSP).
  17809.  
  17810.       Use the new "tools" approach for reading and writing on standard input
  17811.       and output. Use Function 4B00H or 4B03H (Load and Execute Program or
  17812.       Overlay) instead of 26H to execute a child process.
  17813.  
  17814.    ■  Use file-sharing calls if more than one process is in effect.
  17815.  
  17816.       For more information, see "File Sharing" in Section 1.5.2,
  17817.       "File-Related Function Requests."
  17818.  
  17819.    ■  Use networking calls where appropriate.
  17820.  
  17821.       Some forms of IOCtl can only be used with Microsoft Networks. For more
  17822.       information and a list of these calls, see Section 1.6, "Microsoft
  17823.       Networks."
  17824.  
  17825.    ■  When selecting a disk with Function 0EH (Select Disk), treat the value
  17826.       returned in AL with care.
  17827.  
  17828.       The value in AL specifies the maximum number of logical drives; it does
  17829.       not specify which drives are valid.
  17830.  
  17831.  
  17832.  8.4  Device Management
  17833.  
  17834.    ■  Use installable device drivers.
  17835.  
  17836.       MS-DOS provides a modular device driver structure for the BIOS,
  17837.       allowing you to configure and install device drivers at boot time.
  17838.       Block device drivers transmit a block of data at a time, while
  17839.       character device drivers transmit a byte of data at a time.
  17840.  
  17841.       Examples of both types of device drivers are given in Chapter 2,
  17842.       "MS-DOS Device Drivers."
  17843.  
  17844.    ■  Use buffered I/O.
  17845.  
  17846.       The device drivers can handle streams of data up to 64 kilobytes. To
  17847.       improve performance when sending a large amount of output to the
  17848.       screen, you can send it with one system call.
  17849.  
  17850.    ■  Programs that use direct console I/O via Function 06H and 07H (Direct
  17851.       Console I/O and Direct Console Input) and that want to read CONTROL+C
  17852.       as data should ensure that CONTROL+C checking is off.
  17853.  
  17854.       The program should ensure that CONTROL+C checking is off by using
  17855.       Function 33H (CONTROL+C Check).
  17856.  
  17857.    ■  Be compatible with international support.
  17858.  
  17859.       To provide support for international character sets, MS-DOS recognizes
  17860.       all possible byte values as significant characters in filenames and
  17861.       data streams. MS-DOS versions earlier than 2.0 ignored the high bit in
  17862.       the MS-DOS filename.
  17863.  
  17864.  
  17865.  8.5  Memory Management
  17866.  
  17867.    ■  Use memory management.
  17868.  
  17869.       MS-DOS keeps track of allocated memory by writing a memory control
  17870.       block at the beginning of each area of memory. Programs should use
  17871.       Functions 48H (Allocate Memory), 49H (Free Allocated Memory), and
  17872.       4AH (Set Block) to release unneeded memory.
  17873.  
  17874.       This allows for future compatibility. For more information, see Section
  17875.       1.3, "Memory Management."
  17876.  
  17877.    ■  Use only allocated memory.
  17878.  
  17879.       Don't directly access memory that was not provided as a result of a
  17880.       system call. Do not use fixed addressing, use only relative references.
  17881.  
  17882.       A program that uses memory that has not been allocated to it may
  17883.       destroy other memory control blocks or cause other applications to
  17884.       fail.
  17885.  
  17886.  
  17887.  8.6  Process Management
  17888.  
  17889.    ■  Use Function 4B00H or 4B03H (Load and Execute Program or Overlay,
  17890.       also known as EXEC) to load and execute programs.
  17891.  
  17892.       EXEC is the preferred call to use when loading programs and program
  17893.       overlays. Using the EXEC call instead of hard-coding information about
  17894.       how to load a .exe file (or always assuming that your file is a .com
  17895.       file) isolates your program from changes in .exe file formats and
  17896.       future releases of MS-DOS.
  17897.  
  17898.    ■  Use Function 31H (Keep Process), instead of Interrupt 27H (Terminate
  17899.       But Stay Resident).
  17900.  
  17901.       Function 31H allows programs that are greater than 64 kilobytes to
  17902.       terminate and stay resident.
  17903.  
  17904.    ■  Programs should terminate using Function 4CH (End Process).
  17905.  
  17906.       Programs that terminate by one of the following must ensure that the CS
  17907.       register contains the segment address of the PSP:
  17908.  
  17909.       ■  A long jump to offset 0 in the PSP
  17910.  
  17911.       ■  Issuing an Interrupt 20H with CS:0 pointing at the PSP
  17912.  
  17913.       ■  Issuing an Interrupt 21H with AH=0, CS:0 pointing at the PSP
  17914.  
  17915.       ■  A long call to location 50H in the PSP with AH=0
  17916.  
  17917.  
  17918.  8.7  File and Directory Management
  17919.  
  17920.    ■  Use the MS-DOS file management system.
  17921.  
  17922.       Using the MS-DOS file system ensures program compatibility with future
  17923.       MS-DOS versions through compatible disk formats and consistent internal
  17924.       storage.
  17925.  
  17926.    ■  Use file handles instead of FCBs.
  17927.  
  17928.       A handle is a 16-bit number that MS-DOS returns when a file is opened
  17929.       or created using Functions 3CH, 3DH, 5AH, or 5BH (Create Handle,
  17930.       Open Handle, Create Temporary File, or Create New File). The MS-DOS
  17931.       file-related function requests that use handles are listed in Table
  17932.       1.5 in Chapter 1, "System Calls."
  17933.  
  17934.       Although the default maximum number of open files is 20, this limit can
  17935.       be raised to 64K by Function 67H (Set Handle Count). For more
  17936.       information on this system call, see Chapter 1, "System Calls."
  17937.  
  17938.       You should use these calls instead of the old file-related functions
  17939.       that use FCBs (file control blocks). This is because a file operation
  17940.       can simply pass its handle rather than maintaining FCB information. If
  17941.       you must use FCBs, be sure the program closes them and does not move
  17942.       them around in memory.
  17943.  
  17944.    ■  Close files that have changed in length before issuing an Interrupt
  17945.       20H (Program Terminate), Function 00H (Terminate Program), Function
  17946.       4CH (End Process), or Function 0DH (Reset Disk).
  17947.  
  17948.       If you do not close a changed file, its length will not be recorded
  17949.       correctly in the directory.
  17950.  
  17951.    ■  Close files when they are no longer needed.
  17952.  
  17953.       Closing unneeded files increases efficiency in a networking
  17954.       environment.
  17955.  
  17956.    ■  If a program does use FCBs, that program should not close an FCB file
  17957.       and then continue writing to it. This practice will not work in a
  17958.       network environment and is not recommended under any circumstances.
  17959.  
  17960.    ■  Change disks only if all files on the disk are closed.
  17961.  
  17962.       If you don't close all the files, any information in internal system
  17963.       buffers may be written incorrectly to a changed disk.
  17964.  
  17965.  8.7.1  Locking Files
  17966.  
  17967.    ■  Programs should not rely on being denied access to a locked region.
  17968.  
  17969.       To determine the status of a region, first attempt to lock it, then
  17970.       examine its error code.
  17971.  
  17972.    ■  Programs should not close a file with a locked region or terminate with
  17973.       an open file that contains a locked region.
  17974.  
  17975.       The result of this procedure is undefined. Programs that might be
  17976.       terminated by an Interrupt 23H or Interrupt 24H (CONTROL+C Handler
  17977.       Address or Critical-Error-Handler Address) should trap these interrupts
  17978.       and unlock any locked regions before exiting.
  17979.  
  17980.  
  17981.  8.8  Miscellaneous
  17982.  
  17983.    ■  Avoid timing dependencies.
  17984.  
  17985.       Various machines use CPUs of different speeds. Also, programs that rely
  17986.       upon the speed of the clock for timing are not dependable in a
  17987.       networking environment.
  17988.  
  17989.    ■  Use the documented interface to the operating system. If either the
  17990.       hardware or media change, the operating system can use the features
  17991.       without modification.
  17992.  
  17993.       Don't use the ROM support provided by the OEM (Original Equipment
  17994.       Manufacturer).
  17995.  
  17996.       Don't directly address the video memory.
  17997.  
  17998.       Don't use undocumented function calls, interrupts, or features.
  17999.  
  18000.       These items may change or may not exist in future MS-DOS versions. If
  18001.       you do use these features, you will make your program highly
  18002.       non-portable.
  18003.  
  18004.    ■  Use the .exe format rather than the .com format.
  18005.  
  18006.       .Exe files are relocatable; .com files are direct memory images that
  18007.       load at a specific place and have no room for additional control
  18008.       information. .Exe files have headers that can be expanded for
  18009.       compatibility with future MS-DOS versions.
  18010.  
  18011.    ■  Use the environment to pass information to applications.
  18012.  
  18013.       The environment allows a parent process to pass information to a child
  18014.       process. The command.com file is usually the parent process to every
  18015.       application, so it can easily pass default drive and path information
  18016.       to the application.
  18017.  
  18018.  
  18019.  
  18020.  ────────────────────────────────────────────────────────────────────────────
  18021.  Index
  18022.  
  18023.  Numbers
  18024.  
  18025.  80186 microprocessor
  18026.  80286 microprocessor
  18027.  8086 microprocessor
  18028.  8086 object language
  18029.  8086 object module format. See Object Module Formats (OMF)
  18030.  
  18031.  A
  18032.  
  18033.  Absolute Disk Read (Interrupt 25H)
  18034.  Absolute Disk Write (Interrupt 26H)
  18035.  Absolute segment, LSEG
  18036.  ACBP byte, SEG ATTR
  18037.  Address mode
  18038.  Alignment attribute
  18039.  Alignment subfield, SEG ATTR
  18040.  Allocate Memory (Function 48H)
  18041.  Application
  18042.    Frame Number, protected-mode
  18043.  Archive bit
  18044.  Array, character
  18045.  ASCII character set
  18046.  ASCIZ string
  18047.  Assign list
  18048.  Attribute
  18049.    primary
  18050.    secondary
  18051.    Target
  18052.  Attribute byte
  18053.  Attribute field
  18054.  Attribute, LSEG
  18055.    Alignment
  18056.    Combination
  18057.    SEG ATTR field, SEGDEF
  18058.  AUTOEXEC file
  18059.  Auxiliary Input (Function 03H)
  18060.  Auxiliary Output (Function 04H)
  18061.  
  18062.  B
  18063.  
  18064.  base, definition
  18065.  Big subfield, SEG ATTR
  18066.  BIN format file
  18067.  Binary line number
  18068.  BIOS Parameter ^Block (BPB)
  18069.  BIOS Parameter Block (BPB)
  18070.  Bit 8
  18071.  Bit 9
  18072.  Bitfield
  18073.  Block Count subfield, Iterated Data Block
  18074.  Block devices
  18075.    device drivers
  18076.    disk drives
  18077.    example
  18078.    installation
  18079.  Boot sector
  18080.  BPB pointer
  18081.  Buffered Keyboard Input (Function 0AH)
  18082.  BUILD BPB
  18083.  Build BPB
  18084.  Busy bit
  18085.  Byte, representation
  18086.  
  18087.  C
  18088.  
  18089.  C language
  18090.  CALL instruction
  18091.  Cancel Assign-List Entry (Function 5FH, Code 04H)
  18092.  Canonic Frame
  18093.  Canonic Frame, definition
  18094.  Carry flag
  18095.  Case-Mapping Call
  18096.  Change Current Directory (Function 3BH)
  18097.  Change Directory Entry (Function 56H)
  18098.  Character array
  18099.  Character device driver, example
  18100.  Character devices
  18101.  Character set
  18102.    definition
  18103.  Check Keyboard Status (Function 0BH)
  18104.  CHKSUM field, SAMREC
  18105.  Class Name, definition
  18106.  CLOCK device
  18107.  Close File (Function 10H)
  18108.  Close Handle (Function 3EH)
  18109.  Cluster
  18110.  Code page
  18111.    definition
  18112.  Code segment, CS
  18113.  Combination attribute
  18114.  Combination subfield, SEG ATTR
  18115.  COMDEF record
  18116.    field
  18117.      CHKSUM
  18118.      Communal Length, repeated
  18119.      Communal Name, repeated
  18120.      Data Segment Type, repeated
  18121.      Record Length
  18122.      RECTYP
  18123.      Type Index, repeated
  18124.    length fields, format
  18125.    order with respect to COMENT
  18126.    purpose
  18127.    schematic
  18128.  COMENT record
  18129.    field
  18130.      CHKSUM
  18131.      Comment
  18132.      Comment Type
  18133.      Record Length
  18134.      RECTYP
  18135.    order with respect to COMDEF
  18136.    order with respect to LOCSYM
  18137.    purpose
  18138.    schematic
  18139.    subfield of Comment Type
  18140.      Comment Class
  18141.  Command code field
  18142.  Command processor
  18143.  Command.com
  18144.  Commands, utility, NLS
  18145.  Comment class subfield, Comment Type
  18146.  Comment field, COMENT
  18147.  Comment record
  18148.  Comment Record (COMENT)
  18149.  Comment Type field, COMENT
  18150.    bit settings
  18151.    definition
  18152.    format
  18153.  Commit File (Function 68H)
  18154.  Common blocks, FORTRAN
  18155.  Communal Length field, COMDEF
  18156.  Communal Name field, COMDEF
  18157.  Communal Name, ordering with External Name
  18158.  Communal names definition record. See COMDEF record
  18159.  Communal Names Definition Record (COMDEF)
  18160.  Communal variable
  18161.    FAR
  18162.    HUGE
  18163.    NEAR
  18164.    similarity to FORTRAN common block
  18165.    uninitialized public variable
  18166.  Compatibility, ensuring
  18167.  Complete Name, definition
  18168.  Computer language
  18169.    C
  18170.    FORTRAN
  18171.  COMSPEC
  18172.  Con device
  18173.  config.sys
  18174.  config.sys file
  18175.  Content subfield, Iterated Data Block
  18176.  Control blocks
  18177.  Control information
  18178.  CONTROL+C Address (Interrupt 23H)
  18179.  CONTROL+C Check (Function 33H)
  18180.  CONTROL+C Handler Address (Interrupt 23H)
  18181.  Country code
  18182.    definition
  18183.  Country code, current
  18184.  Country-dependent information
  18185.    case conversion tables
  18186.    collating sequence, character sorting
  18187.    currency
  18188.    date
  18189.    DBCS environmental vector
  18190.    keyboard support
  18191.    time
  18192.    valid single-byte characters
  18193.  Country-dependent information, NLS
  18194.  Country.sys file
  18195.  Create Directory (Function 39H)
  18196.  Create File (Function 16H)
  18197.  Create Handle (Function 3CH)
  18198.  Create New File (Function 5BH)
  18199.  Create New PSP (Function 26H)
  18200.  Create Temporary File (Function 5AH)
  18201.  Critical Error Handler Address (Interrupt 24H)
  18202.  CS register
  18203.  
  18204.  D
  18205.  
  18206.  DAT field, LEDATA
  18207.  Data Record
  18208.  Data segment
  18209.    DS
  18210.    ES
  18211.    FAR
  18212.    NEAR
  18213.  Data Segment Type field, COMDEF
  18214.  Delete Directory Entry (Function 41H)
  18215.  Delete File (Function 13H)
  18216.  Descriptor, Group Component, GRPDEF
  18217.  Device control
  18218.  Device drivers
  18219.    block
  18220.    creating
  18221.    example
  18222.    installable
  18223.    installing
  18224.    non-resident
  18225.    preserving registers
  18226.    resident
  18227.  Device Handles
  18228.  Device header
  18229.  Device interrupt routine
  18230.  Device management, programming hints
  18231.  Device strategy routine
  18232.  Device-related function requests
  18233.  Direct Console Input (Function 07H)
  18234.  Direct Console I/O (Function 06H)
  18235.  Directory Entry
  18236.  Directory-Related Function Requests
  18237.  Directory-related function requests
  18238.  Disk allocation
  18239.  Disk Directory
  18240.  Disk formats
  18241.    IBM
  18242.    standard MS-DOS
  18243.  Disk Transfer Address (DTA)
  18244.  Dispatch table
  18245.  Display Character (Function 02H)
  18246.  Display String (Function 09H)
  18247.  Done bit
  18248.  DS register
  18249.  Duplicate File Handle (Function 45H)
  18250.  
  18251.  E
  18252.  
  18253.  Eight Leaf Descriptor field, TYPDEF
  18254.    format
  18255.    subfield
  18256.      EN
  18257.      Leaf Descriptor
  18258.  Element Type Index subfield, Leaf Descriptor
  18259.  EN subfield, Eight Leaf Descriptor
  18260.  End address
  18261.  End Process (Function 4CH)
  18262.  Enumerated Data Offset field, LEDATA
  18263.  Error bit
  18264.  Error codes
  18265.  Error Handling
  18266.  Error handling
  18267.  ES register
  18268.  EXE device drivers
  18269.  .exe files
  18270.  exe files
  18271.  EXE format file
  18272.  EXE loader
  18273.  EXTDEF record
  18274.    field
  18275.      CHKSUM
  18276.      External Name, repeated
  18277.      Record Length
  18278.      RECTYP
  18279.      Type Index, repeated
  18280.    purpose
  18281.    schematic
  18282.  Extended error codes
  18283.  Extended FCB
  18284.  Extensions class, Microsoft
  18285.  External Index
  18286.  External indices
  18287.  External Name
  18288.    mapping
  18289.    referenced in FIXUPP record
  18290.  External Name field, EXTDEF
  18291.  External names definition record. See EXTDEF record
  18292.  External Names Definition Record (EXTDEF)
  18293.  
  18294.  F
  18295.  
  18296.  FAR data segment
  18297.  FAR subfield, Leaf Descriptor
  18298.  FAR variable format, Leaf Descriptor
  18299.  FAT
  18300.  FAT ID byte
  18301.  FAT ID byte
  18302.  FBVAL, definition
  18303.  FCB
  18304.  File Allocation Table
  18305.  File and directory management, programming hints
  18306.  File attributes
  18307.  File Control Block
  18308.    definition
  18309.    extended
  18310.    fields
  18311.    format
  18312.    opened
  18313.    unopened
  18314.  File locking, programming hints
  18315.  Filename separators
  18316.  Filename terminators
  18317.  File-related function requests
  18318.  File-sharing function requests
  18319.  Find First File (Function 4EH)
  18320.  Find Next File (Function 4FH)
  18321.  FIX DAT subfield, Fixup
  18322.    internal structure
  18323.    schematic
  18324.  Fixup
  18325.    definition
  18326.    Frame
  18327.    Location
  18328.    segment-relative
  18329.    self-relative
  18330.    Target
  18331.  Fixup field, FIXUPP
  18332.    data type
  18333.      Frame
  18334.      Location
  18335.      Mode
  18336.      Target
  18337.    definition
  18338.    schematic
  18339.    subfield
  18340.      LOCAT
  18341.  Fixup mode
  18342.    segment-relative
  18343.    self-relative
  18344.  FIXUP record
  18345.  FIXUPP record
  18346.    External Name referenced in
  18347.    field
  18348.      CHKSUM
  18349.      Fixup, repeated
  18350.      Frame Datum, conditional
  18351.      Record Length
  18352.      RECTYP
  18353.      Target Datum, conditional
  18354.      Thread, repeated
  18355.    purpose
  18356.    schematic
  18357.    subfield of FIX DAT, Fixup
  18358.      F
  18359.      Frame
  18360.      P
  18361.      T
  18362.      TARGT
  18363.    subfield of Fixup
  18364.      Frame Datum, conditional
  18365.      Target Datum, conditional
  18366.      Target Displacement, conditional
  18367.    subfield of LOCAT, Fixup
  18368.      Data Record Offset
  18369.      LOC
  18370.      M (mode)
  18371.    subfield of Thread
  18372.      Index, conditional
  18373.      TRD DAT
  18374.    subfield of TRD DAT, Thread
  18375.      D
  18376.      Method
  18377.      THRED
  18378.  FIXUPP Record (FIXUPP)
  18379.  Flush
  18380.  Flush Buffer, Read Keyboard (Function 0CH)
  18381.  Force Duplicate File Handle (Function 46H)
  18382.  Format
  18383.  FORTRAN, common blocks
  18384.  FORTRAN language
  18385.  FOVAL, definition
  18386.  Frame
  18387.    definition
  18388.    Frame Number
  18389.    nomenclature
  18390.    specifying
  18391.    specifying, FIXUPP
  18392.  Frame Datum field, FIXUPP
  18393.  Frame Datum subfield, Fixup
  18394.    External Index
  18395.    Group Index
  18396.    Segment Index
  18397.  Frame Datum subfield, START ADDRS
  18398.  Frame Number
  18399.  Frame Number, conditional
  18400.  Frame Number, definition
  18401.  Frame Number subfield, Public Base
  18402.  Frame Number subfield, SEG ATTR
  18403.  Frames
  18404.    Thread Number, FIXUPP
  18405.  Free Allocated Memory (Function 49H)
  18406.  Function Requests
  18407.    alphabetic order
  18408.    calling
  18409.    definition
  18410.    device-related
  18411.    Directory-related
  18412.    directory-related
  18413.    file-related
  18414.    file-sharing
  18415.    Function 00H
  18416.    Function 01H
  18417.    Function 02H
  18418.    Function 03H
  18419.    Function 04H
  18420.    Function 05H
  18421.    Function 06H
  18422.    Function 07H
  18423.    Function 08H
  18424.    Function 09H
  18425.    Function 0AH
  18426.    Function 0BH
  18427.    Function 0CH
  18428.    Function 0DH
  18429.    Function 0EH
  18430.    Function 0FH
  18431.    Function 10H
  18432.    Function 11H
  18433.    Function 12H
  18434.    Function 13H
  18435.    Function 14H
  18436.    Function 15H
  18437.    Function 16H
  18438.    Function 17H
  18439.    Function 19H
  18440.    Function 1AH
  18441.    Function 1BH
  18442.    Function 1CH
  18443.    Function 21H
  18444.    Function 22H
  18445.    Function 23H
  18446.    Function 24H
  18447.    Function 25H
  18448.    Function 26H
  18449.    Function 27H
  18450.    Function 28H
  18451.    Function 29H
  18452.    Function 2AH
  18453.    Function 2BH
  18454.    Function 2CH
  18455.    Function 2DH
  18456.    Function 2EH
  18457.    Function 2FH
  18458.    Function 30H
  18459.    Function 31H
  18460.    Function 33H
  18461.    Function 35H
  18462.    Function 36H
  18463.    Function 38H
  18464.    Function 39H
  18465.    Function 3AH
  18466.    Function 3BH
  18467.    Function 3CH
  18468.    Function 3DH
  18469.    Function 3EH
  18470.    Function 3FH
  18471.    Function 40H
  18472.    Function 41H
  18473.    Function 42H
  18474.    Function 43H
  18475.    Function 44H, Code 08H
  18476.    Function 44H, Code 09H
  18477.    Function 44H, Code 0AH
  18478.    Function 44H, Code 0BH
  18479.    Function 44H, Code 0CH
  18480.    Function 44H, Code 0DH
  18481.    Function 44H, Codes 00H and 01H
  18482.    Function 44H, Codes 02H and 03H
  18483.    Function 44H, Codes 04H and 05H
  18484.    Function 44H, Codes 06H and 07H
  18485.    Function 44H, Codes 0EH and 0FH
  18486.    Function 45H
  18487.    Function 47H
  18488.    Function 48H
  18489.    Function 49H
  18490.    Function 4AH
  18491.    Function 4BH, Code 00H
  18492.    Function 4BH, Code 03H
  18493.    Function 4CH
  18494.    Function 4DH
  18495.    Function 4EH
  18496.    Function 4FH
  18497.    Function 54H
  18498.    Function 56H
  18499.    Function 57H
  18500.    Function 58H
  18501.    Function 59H
  18502.    Function 5AH
  18503.    Function 5BH
  18504.    Function 5CH, Code 00H
  18505.    Function 5CH, Code 01H
  18506.    Function 5EH, Code 00H
  18507.    Function 5EH, Code 02H
  18508.    Function 5FH, Code 02H
  18509.    Function 5FH, Code 03H
  18510.    Function 5FH, Code 04H
  18511.    Function 62H
  18512.    Function 65H
  18513.    Function 66H
  18514.    Function 67H
  18515.    Function 68H
  18516.    Handling errors
  18517.    memory management
  18518.    National Language Support
  18519.    Network-related
  18520.    network-related
  18521.    numeric order
  18522.    process management
  18523.    standard character I/O
  18524.    system-management
  18525.  Function requests
  18526.    definition
  18527.    Function 25H
  18528.    Function 35H
  18529.    Function 46H
  18530.  
  18531.  G
  18532.  
  18533.  Generic IOCtl for devices (Function 44H, Code 0DH)
  18534.  Generic IOCtl for handles (Function 44H, Code 0CH)
  18535.  Generic IOCtl Function
  18536.  Get Assign List Entry (Function 5FH, Code 02H)
  18537.  Get Country Data (Function 38H)
  18538.  Get Current Directory (Function 47H)
  18539.  Get Current Disk (Function 19H)
  18540.  Get Date (Function 2AH)
  18541.  Get Default Drive Data (Function 1BH)
  18542.  Get Disk Free Space (Function 36H)
  18543.  Get Disk Transfer Address (Function 2FH)
  18544.  Get Drive Data (Function 1CH)
  18545.  Get Extended Country Information (Function 65H)
  18546.  Get Extended Error (Function 59H)
  18547.  Get File Size (Function 23H)
  18548.  Get Interrupt Vector (Function 35H)
  18549.  Get Machine Name (Function 5EH, Code 00H)
  18550.  Get MS-DOS Version Number (Function 30H)
  18551.  Get PSP (Function 62H)
  18552.  Get Return Code Child Process (Function 4DH)
  18553.  Get Time (Function 2CH)
  18554.  Get Verify State (Function 54H)
  18555.  Get/Set Allocation Strategy (Function 58H)
  18556.  Get/Set Date/Time of File (Function 57H)
  18557.  Get/Set File Attributes (Function 43H)
  18558.  Get/Set Global Code Page (Function 66H)
  18559.  Get/Set IOCtl Drive Map (Function 44H, Codes 0EH and 0FH)
  18560.  Get/Set Logical Drive Map Function
  18561.  Group Component Descriptor field, GRPDEF
  18562.  Group, definition
  18563.  Group definition record. See GRPDEF record
  18564.  Group Definition Record (GRPDEF)
  18565.  Group Index
  18566.  Group Index subfield, Line Number Base
  18567.  Group Index subfield, Public Base
  18568.  Group Name Index field, GRPDEF
  18569.  GRPDEF record
  18570.    definition
  18571.    field
  18572.      CHKSUM
  18573.      Group Component Descriptor, repeated
  18574.      Group Name Index
  18575.      Record Length
  18576.      RECTYP
  18577.    schematic
  18578.  
  18579.  H
  18580.  
  18581.  Handles
  18582.    definition
  18583.    device
  18584.  Handling errors
  18585.  Header
  18586.  hibyte, definition
  18587.  Hidden files
  18588.  High-Level Language
  18589.  HUGE communal variable
  18590.  
  18591.  I
  18592.  
  18593.  IBM disk format
  18594.  Index
  18595.    definition
  18596.  Index fields
  18597.  Index Number
  18598.  Index subfield, Thread
  18599.    External Index
  18600.    Group Index
  18601.    Segment Index
  18602.  Indices
  18603.  Indices, external
  18604.  Init
  18605.  INIT code
  18606.  Installable device drivers
  18607.  Instruction
  18608.    CALL
  18609.    JUMP
  18610.    SHORT-JUMP
  18611.  Instruction Pointer (IP)
  18612.  Internal stack
  18613.  Interrupt entry point
  18614.  Interrupt handlers
  18615.  Interrupt routines
  18616.  Interrupt-handling routine
  18617.  Interrupts
  18618.    21H
  18619.    Address of handlers
  18620.    alphabetic order
  18621.    definition
  18622.    Interrupt 20H
  18623.    Interrupt 21H
  18624.    Interrupt 22H
  18625.    Interrupt 23H
  18626.    Interrupt 24H
  18627.    Interrupt 25H
  18628.    Interrupt 26H
  18629.    Interrupt 27H
  18630.    issuing
  18631.    numeric order
  18632.    programming hints
  18633.    Vector table
  18634.  I/O Control for Devices (Function 44H)
  18635.  IOCtl
  18636.  IOCtl bit
  18637.  IOCtl Block (Function 44H, Codes 4 and 5)
  18638.  IOCtl Character (Function 44H, Codes 2 and 3)
  18639.  IOCtl Data (Function 44H, Codes 0 and 1)
  18640.  IOCtl Is Changeable (Function 44H, Code 08H)
  18641.  IOCtl Is Redirected Block (Function 44H, Code 09H)
  18642.  IOCtl Is Redirected Handle (Function 44H, Code 0AH)
  18643.  IOCtl Retry (Function 44H, Code 0BH)
  18644.  IOCtl Status (Function 44H, Codes 6 and 7)
  18645.  io.sys file
  18646.  IP. See Instruction Pointer (IP)
  18647.  Iterated Data Block field, LIDATA
  18648.  Iterated Data Offset field, LIDATA
  18649.  
  18650.  J
  18651.  
  18652.  JUMP instruction
  18653.  
  18654.  K
  18655.  
  18656.  Keep Process (Function 31H)
  18657.  Keyboard layouts, national, NLS
  18658.  
  18659.  L
  18660.  
  18661.  Language
  18662.    C
  18663.    FORTRAN
  18664.  Leaf Descriptor subfield, Eight Leaf Descriptor
  18665.    format
  18666.      FAR variable
  18667.      NEAR variable
  18668.    subfield
  18669.      NEAR
  18670.      VARTYP
  18671.  LEDATA
  18672.    field
  18673.      CHKSUM
  18674.      Record Length
  18675.      RECTYP
  18676.    purpose
  18677.  LEDATA record
  18678.    field
  18679.      DAT, repeated
  18680.      Enumerated Data Offset
  18681.      Segment Index
  18682.    schematic
  18683.  Length fields, COMDEF, format
  18684.  Length in Bits subfield, Leaf Descriptor
  18685.  Length of Record Field
  18686.  LHEADR record
  18687.    field
  18688.      CHKSUM
  18689.      L-module Name
  18690.      Record Length
  18691.      RECTYP
  18692.    schematic
  18693.  LIDATA record
  18694.    field
  18695.      CHKSUM
  18696.      Iterated Data Block, repeated
  18697.      Iterated Data Offset
  18698.      Record Length
  18699.      RECTYP
  18700.      Segment Index
  18701.    purpose
  18702.    schematic
  18703.    subfield of Iterated Data Block
  18704.      Block Count
  18705.      Content
  18706.      Repeat Count
  18707.  Line Number Base field, LINNUM
  18708.  Line number, binary
  18709.  Line Number field, LINNUM
  18710.  Line Number Offset field, LINNUM
  18711.  Line Numbers Record (LINNUM)
  18712.  LINK
  18713.  Linker, Microsoft
  18714.  Linker, Microsoft
  18715.  Link-time semantics
  18716.  LINNUM record
  18717.    field
  18718.      CHKSUM
  18719.      Line Number Base
  18720.      Line Number Offset, repeated
  18721.      Line Number, repeated
  18722.      Record Length
  18723.      RECTYP
  18724.    purpose
  18725.    schematic
  18726.    subfield of Line Number Base
  18727.      Group Index
  18728.      Segment Index
  18729.  List of Names Record (LNAMES)
  18730.  L-module Header Record (LHEADR)
  18731.  L-module Name
  18732.  LNAMES record
  18733.    field
  18734.      CHKSUM
  18735.      Name, repeated
  18736.      Record Length
  18737.      RECTYP
  18738.    schematic
  18739.  Load and Execute Program (Function 4BH, Code 00H)
  18740.  Load module
  18741.  Load Overlay (Function 4BH, Code 03H)
  18742.  Loadsize
  18743.  lobyte, definition
  18744.  Local Base field, LOCSYM
  18745.  Local buffering
  18746.  Local Name field, LOCSYM
  18747.  Local Offset field, LOCSYM
  18748.  Local symbol
  18749.  Local Symbols Record (LOCSYM)
  18750.  LOCAT subfield, Fixup
  18751.    internal structure
  18752.    schematic
  18753.  Location
  18754.    types
  18755.      base
  18756.      hibyte
  18757.      lobyte
  18758.      offset
  18759.      pointer
  18760.  Lock (Function 5CH, Code 00H)
  18761.  LOCSYM record
  18762.    field
  18763.      CHKSUM
  18764.      Local Base
  18765.      Local Name, repeated
  18766.      Local Offset, repeated
  18767.      Record Length
  18768.      RECTYP
  18769.      Type Index, repeated
  18770.    order with respect to COMENT
  18771.    purpose
  18772.    schematic
  18773.  Logical Enumerated Data Record (LEDATA)
  18774.  Logical Iterated Data Record (LIDATA)
  18775.  Logical sector
  18776.  Logical sector numbers
  18777.  Logical Segment. See LSEG
  18778.  LSEG
  18779.    absolute
  18780.      Combination attribute
  18781.    Alignment attribute
  18782.      absolute segment
  18783.      relocatable segment
  18784.    canonic Frame
  18785.    Class name
  18786.    Combination attribute
  18787.      absolute segment
  18788.      relocatable segment
  18789.    combining
  18790.    Complete name
  18791.    definition
  18792.    Overlay Name
  18793.    relocatable
  18794.      byte-aligned
  18795.      Combination attribute
  18796.      page-aligned
  18797.      paragraph-aligned
  18798.      word-aligned
  18799.    Segment Name
  18800.  
  18801.  M
  18802.  
  18803.  Make Assign-List Entry (Function 5FH, Code 03H)
  18804.  Mapping
  18805.    logical to physical starting address
  18806.  MAS. See Memory Address Space (MAS)
  18807.  MATTR subfield, MOD TYP
  18808.  Maxalloc
  18809.  Media Check
  18810.  Media descriptor byte
  18811.  Media, determining
  18812.  Memory address
  18813.  Memory Address Space (MAS)
  18814.  Memory control block
  18815.  Memory image, 8086
  18816.  Memory image, LSEGs in
  18817.  Memory image, relocatable
  18818.  Memory management function requests
  18819.  Memory management, programming hints
  18820.  Memory model
  18821.    huge
  18822.    large
  18823.    medium
  18824.    small
  18825.  Microprocessor
  18826.    80186
  18827.    80286
  18828.    8086
  18829.  Microsoft Extensions class
  18830.  Microsoft linker
  18831.  Microsoft linker
  18832.  Microsoft Networks
  18833.  Microsoft Networks Manager's Guide
  18834.  Microsoft Networks User's Guide
  18835.  Minalloc
  18836.  MOD TYP field, MODEND
  18837.    MATTR subfield
  18838.    module attributes
  18839.  Mode
  18840.    fixup
  18841.      segment-relative
  18842.      self-relative
  18843.  Mode, address
  18844.  MODEND record
  18845.    field
  18846.      CHKSUM
  18847.      MOD TYP
  18848.      Record Length
  18849.      RECTYP
  18850.      START ADDRS, conditional
  18851.    purpose
  18852.    schematic
  18853.    subfield of START ADDRS
  18854.      Frame Datum, conditional
  18855.      Target Datum, conditional
  18856.      Target Displacement, conditional
  18857.  Module
  18858.    record ordering in
  18859.  Module, definition
  18860.  Module End Record (MODEND)
  18861.  Module header record, definition
  18862.  Move File Pointer (Function 42H)
  18863.  MS-DOS, 8086 object language
  18864.  MS-DOS initialization
  18865.  MS-DOS memory map
  18866.  MS-DOS User's Reference
  18867.  msdos.sys file
  18868.  Multitasking
  18869.  
  18870.  N
  18871.  
  18872.  Name field
  18873.  Name field, SAMREC
  18874.  Name Indices
  18875.  National keyboard layouts, NLS
  18876.  National Language Support Function Requests
  18877.  National Language Support (NLS)
  18878.    restrictions
  18879.    unsupported features
  18880.  National Language Support system calls
  18881.  NEAR data segment
  18882.  NEAR subfield, Leaf Descriptor
  18883.  NEAR variable format, Leaf Descriptor
  18884.  Network-related Function Requests
  18885.  Network-related function requests
  18886.  Non IBM format bit
  18887.  Non-destructive Read No Wait
  18888.  NUL device
  18889.  Number field, SAMREC
  18890.  Number of Elements subfield, Leaf Descriptor
  18891.  
  18892.  O
  18893.  
  18894.  Object language, 8086
  18895.  Object module
  18896.    restrictions
  18897.  Object Module Formats
  18898.  Object Module Formats (OMF)
  18899.  offset, definition
  18900.  Offset subfield, SEG ATTR
  18901.  Old system calls
  18902.  OMF. See Object Module Formats (OMF)
  18903.  Open File (Function 0FH)
  18904.  Open Handle (Function 3DH)
  18905.  Opened FCB
  18906.  Operating system
  18907.    MS-DOS
  18908.    PC-DOS
  18909.    XENIX
  18910.  Overlay Name, definition
  18911.  
  18912.  P
  18913.  
  18914.  Parameter block
  18915.  Parse File Name (Function 29H)
  18916.  Path command
  18917.  PC-DOS, 8086 object language
  18918.  Physical Segment. See PSEG
  18919.  Pointer to Next Device field
  18920.  Predefined device handles
  18921.  Print Character (Function 05H)
  18922.  Printer Setup (Function 5EH, Code 02H
  18923.  Process management function requests
  18924.  Process management, programming hints
  18925.  Processor. See Microprocessor
  18926.  Program End Process (Interrupt 20H)
  18927.  Program segment
  18928.  Program Segment Prefix
  18929.  Programming hints
  18930.    device management
  18931.    file and directory management
  18932.    file locking
  18933.    interrupts
  18934.    memory management
  18935.    miscellaneous
  18936.    process management
  18937.    recommendations
  18938.    system calls
  18939.  Programming interfaces, NLS
  18940.  Prompt command
  18941.  Protected-mode
  18942.    application Frame Number
  18943.  PSEG
  18944.    definition
  18945.  PUBDEF record
  18946.    field
  18947.      Public Base, repeated
  18948.      Public Name, repeated
  18949.      Public Offset, repeated
  18950.      Record Length
  18951.      RECTYP
  18952.      Type Index, repeated
  18953.    purpose
  18954.    schematic
  18955.    subfield of Public Base
  18956.      Frame Number, conditional
  18957.    subfield, Public Base
  18958.      Frame Number, conditional
  18959.      Group Index
  18960.      Segment Index
  18961.  Public Base field, PUBDEF
  18962.  Public Name field, PUBDEF
  18963.  Public names definition record. See PUBDEF record
  18964.  Public Names Definition Record (PUBDEF)
  18965.  Public Offset field, PUBDEF
  18966.  Public symbol
  18967.  Public variable
  18968.  
  18969.  R
  18970.  
  18971.  Random Block Read (Function 27H)
  18972.  Random Block Write (Function 28H)
  18973.  Random Read (Function 21H)
  18974.  Random Write (Function 22H)
  18975.  Read Handle (Function 3FH)
  18976.  Read Keyboard and Echo (Function 01H)
  18977.  Read Keyboard (Function 08H)
  18978.  Read Only Memory
  18979.  Read or Write
  18980.  Record
  18981.    COMDEF
  18982.    COMENT
  18983.    comment
  18984.    Data
  18985.    EXTDEF
  18986.    FIXUP
  18987.    FIXUPP
  18988.    GRPDEF
  18989.    LEDATA
  18990.    LHEADR
  18991.    LIDATA
  18992.    LINNUM
  18993.    LNAMES
  18994.    LOCSYM
  18995.    MODEND
  18996.    PUBDEF
  18997.    RECTYP(record type)
  18998.    SAMREC (sample record)
  18999.    SEGDEF
  19000.    symbol definition
  19001.      COMDEF
  19002.      EXTDEF
  19003.      PUBDEF
  19004.    THEADR
  19005.    TYPDEF
  19006.  Record format
  19007.    abbreviation
  19008.    bitfields
  19009.    conditional field
  19010.    repeated field
  19011.    sample (SAMREC)
  19012.    SAMREC (sample record)
  19013.      CHKSUM field
  19014.      Name field
  19015.      Number field
  19016.      Record Length field
  19017.    SAMREC(sample record)
  19018.      RECTYP field
  19019.    title
  19020.  Record formats
  19021.  Record Length field, SAMREC
  19022.  Record order
  19023.    definition
  19024.    semantic rules
  19025.    syntax
  19026.  Record Size
  19027.  RECTYP(record type)field
  19028.  Reference
  19029.    segment-relative
  19030.  Reference self-relative
  19031.  References
  19032.    WIRTH
  19033.      CACM, Nov. 1977)
  19034.  Register
  19035.    CS
  19036.    DS
  19037.    ES
  19038.    SS
  19039.  Registers, treatment of
  19040.  Relocatable memory image
  19041.  Relocatable segment, LSEG
  19042.  Relocation information
  19043.  Relocation item offset value to a word in the load
  19044.  Relocation table
  19045.  Remove Directory (Function 3AH)
  19046.  Rename File (Function 17H)
  19047.  Repeat Count subfield, Iterated Data Block
  19048.  request header
  19049.  Request packet
  19050.  Reset Disk (Function 0DH)
  19051.  Resident device drivers
  19052.  ROM
  19053.  Root directory
  19054.  
  19055.  S
  19056.  
  19057.  SAMREC (sample record)
  19058.    schematic
  19059.  Search for First Entry (Function 11H)
  19060.  Search for Next Entry (Function 12H)
  19061.  Sector count
  19062.  SEG ATTR field, SEGDEF
  19063.  SEGDEF record
  19064.    definition
  19065.    field
  19066.      CHKSUM
  19067.      Class Name Index
  19068.      Overlay Name Index
  19069.      Record Length
  19070.      RECTYP
  19071.      SEG ATTR
  19072.      Segment Name Index
  19073.    schematic
  19074.    subfield of SEG ATTR
  19075.      Alignment
  19076.      Big
  19077.      Combination
  19078.      Offset, conditional
  19079.  SEGDEF recrod
  19080.    field
  19081.      Segment Length
  19082.  Segment
  19083.    absolute, LSEG
  19084.    attribute
  19085.      Alignment
  19086.      Combination
  19087.    logical (LSEG)
  19088.    physical (PSEG)
  19089.    relocatable, LSEG
  19090.  Segment addressing
  19091.  Segment definition record. See SEGDEF record
  19092.  Segment Definition Record (SEGDEF)
  19093.  Segment Index
  19094.  Segment Index field, LEDATA
  19095.  Segment Index field, LIDATA
  19096.  Segment Index subfield, Group Component Descriptor
  19097.  Segment Index subfield, Line Number Base
  19098.  Segment Index subfield, Public Base
  19099.  Segment Length field, SEGDEF
  19100.  Segment Name, definition
  19101.  Segment Name Index field, SEGDEF
  19102.  Segment-relative fixup
  19103.  Segment-relative reference
  19104.  Select Disk (Function 0EH)
  19105.  Self-relative fixup
  19106.  Self-relative reference
  19107.  Semantic rules, record ordering
  19108.  Semantics, link-time
  19109.  Sequential Read (Function 14H)
  19110.  Sequential Write (Function 15H)
  19111.  Set Block (Function 4AH)
  19112.  Set command
  19113.  Set Country Data (Function 38H)
  19114.  Set Date (Function 2BH)
  19115.  Set Disk Transfer Address (Function 1AH)
  19116.  Set Handle Count(Function 67H)
  19117.  Set Interrupt Vector (Function 25H)
  19118.  Set Relative Record (Function 24H)
  19119.  Set Time (Function 2DH)
  19120.  Set/Reset Verify Flag (Function 2EH)
  19121.  SHORT-JUMP instruction
  19122.  SS register
  19123.  Stack segment, SS
  19124.  Standard character I/O function requests
  19125.  START ADDRS field, MODEND
  19126.    Format
  19127.  Start sector
  19128.  Start segment value the relocation item offset
  19129.  static request header
  19130.  Status
  19131.  Status field
  19132.  Strategy entry point
  19133.  Strategy routines
  19134.  Subfield
  19135.    Comment Type
  19136.      Comment Class
  19137.    Eight Leaf Descriptor
  19138.      EN
  19139.      Leaf Descriptor
  19140.    Fixup
  19141.      Frame Datum
  19142.      Target Datum
  19143.      Target Displacement
  19144.    Frame Number, conditional
  19145.    Group Component Descriptor
  19146.      Segment Index
  19147.    Iterated Data Block
  19148.      Block Count
  19149.      Content
  19150.      Repeat Count
  19151.    Leaf Descriptor
  19152.      Element Type Index
  19153.      FAR
  19154.      Length in Bits
  19155.      NEAR
  19156.      Number of Elements
  19157.      VAR SUBTYP
  19158.      VARTYP
  19159.    Line Number Base, LINNUM
  19160.      Group Index
  19161.      Segment Index
  19162.    MOD TYP
  19163.      MATTR
  19164.    Public Base
  19165.      Group INdex
  19166.    SEG ATTR
  19167.      Alignment
  19168.      Big
  19169.      Combination
  19170.    Segment Index
  19171.    START ADDRS
  19172.      Frame Datum
  19173.      Target Datum
  19174.      Target Displacement
  19175.    Thread
  19176.      Index
  19177.      TRD DAT
  19178.  Subfield OFFH
  19179.  Superseded system calls
  19180.  Symbol
  19181.    local
  19182.    public
  19183.  Symbol definition
  19184.  Symbol definition record
  19185.    COMDEF
  19186.    EXTDEF
  19187.    PUBDEF
  19188.  Syntax, record ordering
  19189.  Sysinit
  19190.  System call
  19191.    National Language Support:
  19192.  System Calls
  19193.    superseded calls
  19194.  System calls
  19195.    definition
  19196.    programming hints
  19197.    replacements for old
  19198.    types of
  19199.  System files
  19200.  System prompt
  19201.  System-management function requests
  19202.  
  19203.  T
  19204.  
  19205.  Target
  19206.    definition
  19207.    nomenclature
  19208.    specification attribute
  19209.    specifying
  19210.    specifying, FIXUPP
  19211.    Thread Number, FIXUPP
  19212.  Target Datum field, FIXUPP
  19213.  Target Datum subfield, Fixup
  19214.    External Index
  19215.    Group Index
  19216.    Segment Index
  19217.  Target Datum subfield, START ADDRS
  19218.  Target Displacement subfield, Fixup
  19219.  Target Displacment subfield, START ADDRS
  19220.  Terminate But Stay Resident (Interrupt 27H)
  19221.  Terminate Process Exit Address (Interrupt 22H)
  19222.  Terminate Program (Function 00H)
  19223.  THEADR record
  19224.    field
  19225.      CHKSUM
  19226.      Record Length
  19227.      RECTYP
  19228.      T-module Name
  19229.    schematic
  19230.  Thread Data subfield. See TRD DAT subfield, Thread
  19231.  Thread field, FIXUPP
  19232.    data type
  19233.      Frame
  19234.      Target
  19235.    definition
  19236.  Thread Number, THRED
  19237.  T-module, definition
  19238.  T-module Header Record (THEADR)
  19239.  T-Module Name
  19240.  Transfer address
  19241.  TRD DAT subfield, Thread
  19242.    D subfield
  19243.    internal structure
  19244.    Method subfield
  19245.    schematic
  19246.    THRED subfield
  19247.  TYPDEF record
  19248.    communal variable
  19249.    field
  19250.      CHKSUM
  19251.      Eight Leaf Descriptor
  19252.      Record Length
  19253.      RECTYP
  19254.    subfield of Eight Leaf Descriptor
  19255.      EN
  19256.    subfield of Leaf Descriptor
  19257.      Element Type Index
  19258.      FAR
  19259.      Length in Bits
  19260.      NEAR
  19261.      Number of Elements
  19262.      VAR SUBTYP, optional
  19263.      VARTYP
  19264.  Type Index field, COMDEF
  19265.  Type Index field, EXTDEF
  19266.  Type Index field, LOCSYM
  19267.  Type Index field, PUBDEF
  19268.  Type-ahead buffer
  19269.  
  19270.  U
  19271.  
  19272.  Unit code field
  19273.  Unlock (Function 5CH, Code 01H)
  19274.  Unopened FCB
  19275.  User Stack
  19276.  User stack
  19277.  Utility commands, NLS
  19278.  
  19279.  V
  19280.  
  19281.  VAR SUBTYP subfield, Leaf Descriptor
  19282.  Variable
  19283.    communal
  19284.      FAR
  19285.      HUGE"
  19286.      NEAR
  19287.    public
  19288.  VARTYP subfield, Leaf Descriptor
  19289.    ARRAY
  19290.    SCALAR
  19291.    STRUCT
  19292.  Vector table
  19293.  Volume ID
  19294.  Volume label
  19295.  
  19296.  W
  19297.  
  19298.  Wildcard characters
  19299.  Write Handle (Function 40H)
  19300.  
  19301.  X
  19302.  
  19303.  XENIX, 8086 object language
  19304.