 Microsoft MS-DOS Programmer's Reference


 ĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶ


 Microsoft(R) MS-DOS(R) Programmer's Reference

 Version 4.0


 ĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶ


   Information in this document is subject to change without notice and does
   not represent a commitment on the part of Microsoft Corporation. The
   software described in this document is furnished under a license agreement
   or non-disclosure agreement. The software may be used or copied only in
   accordance with the terms of the agreement. It is against the law to copy
   the software on any medium except as specifically allowed in the license
   or non-disclosure agreement. No part of this manual may be reproduced or
   transmitted in any form or by any means, electronic or mechanical,
   including photocopying and recording, for any purpose without the express
   written permission of Microsoft.

   (C) Copyright Microsoft Corporation, 1988. All rights reserved.

   Simultaneously published in the United States and Canada.

   Printed in the United States of America.

   Microsoft, the Microsoft logo, MS-DOS, and XENIX are registered trademarks
   of Microsoft Corporation.

   IBM, IBM Personal Computer, IBM PC, and PC-DOS are registered trademarks
   of International Business Machines Corporation.

   INTEL is a registered trademark of Intel Corporation.

 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Contents

 Chapter 1   System Calls
     1.1   Introduction
           1.1.1   System Calls That Have Been Superseded
           1.1.2   How to Use This Manual
     1.2   Standard Character Device I/O
     1.3   Memory Management
     1.4   Process Management
           1.4.1   Loading and Executing a Program
           1.4.2   Loading an Overlay
     1.5   File and Directory Management
           1.5.1   Handles
           1.5.2   File-Related Function Requests
           1.5.3   Device-Related Function Requests
           1.5.4   Directory-Related Function Requests
           1.5.5   File Attributes
     1.6   Microsoft Networks
     1.7   National Language Support
     1.8   Miscellaneous System-Management Functions
     1.9   Old System Calls
           1.9.1   File Control Block (FCB)
     1.10  Using the System Calls
           1.10.1  Issuing an Interrupt
           1.10.2  Calling a Function Request
           1.10.3  Using the Calls from a High-Level Language
           1.10.4  Treatment of Registers
           1.10.5  Handling Errors
           1.10.6  System Call Descriptions
     1.11  Interrupts
           1.11.1  Conditions upon Entry
           1.11.2  Requirements for an Interrupt 24H Handler
     1.12  Function Requests

 Chapter 2   MS-DOS Device Drivers
     2.1   Introduction
     2.2   Format of a Device Driver
     2.3   How to Create a Device Driver
           2.3.1   Device Strategy Routine
           2.3.2   Device Interrupt Routine
     2.4   Installing Device Drivers
     2.5   Device Headers
           2.5.1   Pointer to Next Device Field
           2.5.2   Attribute Field
           2.5.3   Strategy and Interrupt Routines
           2.5.4   Name Field
     2.6   Request Header
           2.6.1   Length of Record
           2.6.2   Unit Code Field
           2.6.3   Command Code Field
           2.6.4   Status Field
     2.7   Device Driver Functions
           2.7.1   The Init Function
           2.7.2   The Media Check Function
           2.7.3   The Build BPB Function
           2.7.4   The Read or Write Function
           2.7.5   The Non-destructive Read, No Wait Function
           2.7.6   The Open or Close Function
           2.7.7   The Removable Media Function
           2.7.8   The Status Function
           2.7.9   The Flush Function
           2.7.10  The Generic IOCtl Function
           2.7.11  The Get/Set Logical Drive Map Function
     2.8   The Media Descriptor Byte
     2.9   Format of a Media Descriptor Table
     2.10  The CLOCK Device
     2.11  Anatomy of a Device Call
     2.12  Two Sample Device Drivers

 Chapter 3   MS-DOS Technical Information
     3.1   Introduction
     3.2   MS-DOS Initialization
     3.3   The Command Processor
     3.4   MS-DOS Disk Allocation
     3.5   MS-DOS Disk Directory
     3.6   File Allocation Table (FAT)
           3.6.1   How to Use the FAT (12-Bit FAT Entries)
           3.6.2   How to Use the FAT (16-Bit FAT Entries)
     3.7   MS-DOS Standard Disk Formats

 Chapter 4   MS-DOS Control Blocks and Work Areas
     4.1   Introduction
     4.2   Typical Contents of an MS-DOS Memory Map
     4.3   The MS-DOS Program Segment

 Chapter 5   National Language Support
     5.1   Introduction
     5.2   National Language Support Calls
     5.3   Font Files
           5.3.1   Font File Structure

 Chapter 6   .Exe File Structure and Loading
     6.1   Introduction
     6.2   Format of a File Header
     6.3   The Relocation Table

 Chapter 7   Relocatable Object Module Formats
     7.1   Introduction
           7.1.1   Definition of Terms
     7.2   Module Identification and Attributes
           7.2.1   Segment Definition
           7.2.2   Addressing a Segment
           7.2.3   Symbol Definition
           7.2.4   Indices
     7.3   Conceptual Framework for Fixups
           7.3.1   Self-Relative Fixup
           7.3.2   Segment-Relative Fixup
     7.4   Record Sequence
     7.5   Introducing the Record Formats
           7.5.1   Sample Record Format (SAMREC)
           7.5.2   T-Module Header Record (THEADR)
           7.5.3   L-Module Header Record (LHEADR)
           7.5.4   List of Names Record (LNAMES)
           7.5.5   Segment Definition Record (SEGDEF)
           7.5.6   Group Definition Record (GRPDEF)
           7.5.7   Public Names Definition Record (PUBDEF)
           7.5.8   Communal Names Definition Record (COMDEF)
           7.5.9   Local Symbols Record (LOCSYM)
           7.5.10  External Names Definition Record (EXTDEF)
           7.5.11  Line Numbers Record (LINNUM)
           7.5.12  Logical Enumerated Data Record (LEDATA)
           7.5.13  Logical Iterated Data Record (LIDATA)
           7.5.14  Fixup Record (FIXUPP)
           7.5.15  Module End Record (MODEND)
           7.5.16  Comment Record (COMENT)
     7.6   Microsoft Type Representations for Communal Variables

 Chapter 8   Programming Hints
     8.1   Introduction
     8.2   Interrupts
     8.3   System Calls
     8.4   Device Management
     8.5   Memory Management
     8.6   Process Management
     8.7   File and Directory Management
           8.7.1   Locking Files
     8.8   Miscellaneous

 Figures
 Figure 1.1  Example of the 8088 Registers
 Figure 1.2  Sample Program with Common Skeleton
 Figure 2.1  Sample Device Header
 Figure 2.2  Attribute Word for Character Devices
 Figure 2.3  Attribute Word for Block Devices
 Figure 2.4  Request Header
 Figure 2.5  Status Field
 Figure 2.6  Format of a Boot Sector
 Figure 2.7  Format of a Clock Device
 Figure 4.1  Program Segment Prefix
 Figure 5.1  Font File Structure
 Figure 7.1  Location Types

 Tables
 Table 1.1   Standard-Character I/O Function Requests
 Table 1.2   Memory Management Function Requests
 Table 1.3   Process-Management Function Requests
 Table 1.4   Predefined Device Handles
 Table 1.5   File-Related Function Requests
 Table 1.6   File-Sharing Function Requests
 Table 1.7   Device-Related Function Requests
 Table 1.8   Directory-Related Function Requests
 Table 1.9   File Attributes
 Table 1.10  Microsoft Networks Function Requests
 Table 1.11  National-Language-Support Function Requests
 Table 1.12  Miscellaneous System-Management Function Requests
 Table 1.13  Old System Calls and Their Replacements
 Table 1.14  Format of the File Control Block (FCB)
 Table 1.15  Error Codes Returned in AX
 Table 1.16  MS-DOS Interrupts, Numeric Order
 Table 1.17  MS-DOS Interrupts, Alphabetic Order
 Table 1.18  MS-DOS Function Requests, Numeric Order
 Table 1.19  MS-DOS Function Requests, Alphabetic Order
 Table 1.20  Bit Values for Function 29H
 Table 1.21  Sharing Mode Bit Values
 Table 1.22  Access Code Bit Values
 Table 1.23  MS-DOS Data Bit Values
 Table 1.24  Contents of the Parameter Block
 Table 1.25  Contents of the Parameter Block
 Table 1.26  DTA Values After Successful Find First File
 Table 1.27  Allocation Strategy
 Table 2.1   For Character Devices:
 Table 2.2   For Block Devices:
 Table 3.1   MS-DOS Standard Removable-Disk Formats
 Table 3.2   MS-DOS Standard Removable-Disk Formats (High-Density)
 Table 7.1   Object Module Record Formats
 Table 7.2   Combination Attribute Example



 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Chapter 1  System Calls

     1.1   Introduction
           1.1.1   System Calls That Have Been Superseded
           1.1.2   How to Use This Manual
     1.2   Standard Character Device I/O
     1.3   Memory Management
     1.4   Process Management
           1.4.1   Loading and Executing a Program
           1.4.2   Loading an Overlay
     1.5   File and Directory Management
           1.5.1   Handles
           1.5.2   File-Related Function Requests
           1.5.3   Device-Related Function Requests
           1.5.4   Directory-Related Function Requests
           1.5.5   File Attributes
     1.6   Microsoft Networks
     1.7   National Language Support
     1.8   Miscellaneous System-Management Functions
     1.9   Old System Calls
           1.9.1   File Control Block (FCB)
     1.10  Using the System Calls
           1.10.1  Issuing an Interrupt
           1.10.2  Calling a Function Request
           1.10.3  Using the Calls from a High-Level Language
           1.10.4  Treatment of Registers
           1.10.5  Handling Errors
           1.10.6  System Call Descriptions
     1.11  Interrupts
           1.11.1  Conditions upon Entry
           1.11.2  Requirements for an Interrupt 24H Handler
     1.12  Function Requests


 1.1  Introduction

   The routines that MS-DOS uses to manage system operation and resources can
   be called by any application program. Using these system calls makes it
   easier to write machine-independent programs and increases the likelihood
   that a program will be compatible with future versions of MS-DOS. MS-DOS
   system calls fall into several categories:

   ž  Standard character device I/O

   ž  Memory management

   ž  Process management

   ž  File and directory management

   ž  Microsoft Network calls

   ž  National Language Support calls

   ž  Miscellaneous system functions

   Applications invoke MS-DOS services by using software interrupts. The
   current range of interrupts used for MS-DOS is 20H-27H; 28H-40H are
   reserved. Interrupt 21H is the function request service; it provides
   access to a wide variety of MS-DOS services. In some cases, the full AX
   register is used to specify the requested function. Each interrupt or
   function request uses values in various registers to receive or return
   function-specific information.

 1.1.1  System Calls That Have Been Superseded

   Many system calls introduced in versions of MS-DOS earlier than 2.0 have
   been superseded by function requests that are more efficient and easier to
   use. Although MS-DOS still includes these old system calls, they should
   not be used unless it is imperative that a program maintain
   backward-compatibility with versions of MS-DOS earlier than 2.0.

   A table of the pre-2.0 system calls and a description of the File Control
   Block (required by some of the old calls) appear in Section 1.8, "Old
   System Calls."

 1.1.2  How to Use This Manual

   The first part of this chapter explains how DOS manages its resourcesÄÄ
   such as memory, files, and processesÄÄand briefly describes the purpose of
   most of the system calls. The remainder of the chapter describes each
   interrupt and function request in detail.

   The system-call descriptions are in numeric order, interrupts followed by
   function requests. These descriptions include further detail on how MS-DOS
   manages its resources.

   Chapter 2 of this manual describes how to write an MS-DOS device driver.

   Chapters 3 and 4 contain more detailed information about MS-DOS,
   including how it manages disk space, uses control blocks, and loads and
   executes relocatable programs (files with an extension of .exe).

   Chapter 5 describes MS-DOS national language support.

   Chapter 6 describes .exe file structure and loading procedures (for
   versions of MS-DOS earlier than 2.0).

   Chapter 7 describes the Intel object module format.

   Chapter 8 gives some programming hints.


 1.2  Standard Character Device I/O

   The standard-character function requests handle all input and output to
   and from character devices such as consoles, printers, and serial ports.
   If a program uses these function requests, its input and output can be
   redirected.

   Table 1.1 lists the MS-DOS function requests for managing
   standard-character input and output.

   Table 1.1
   Standard-Character I/O Function Requests
ÖŚÄŚÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ·
   Code       Request              Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   01H       Read Keyboard and    Gets a character from standard input and
              Echo                 echoes it to standard output

   02H       Display Character    Sends a character to standard output

   03H       Auxiliary Input      Gets a character from standard auxiliary

   04H       Auxiliary Output     Sends a character to standard auxiliary

   05H       Print Character      Sends a character to the standard printer
   Code       Request              Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  05H       Print Character      Sends a character to the standard printer

   06H       Direct Console I/O   Gets a character from standard input or
                                   sends a character to standard output

   07H       Direct Console Input Gets a character from standard input

   08H       Read Keyboard        Gets a character from standard input

   09H       Display String       Sends a string to standard output

   0AH       Buffered Keyboard    Gets a string from standard input
              Input

   0BH       Check Keyboard       Reports on the status of the standard
              Status               input buffer

   0CH       Flush Buffer, Read   Empties the standard input buffer and
              Keyboard             calls one of the other standard character
   Code       Request              Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
             Keyboard             calls one of the other standard character
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


   Although several of these standard-character I/O function requests seem to
   do the same thing, they are distinguished by whether they check for
   control characters or echo characters from standard input to standard
   output. The detailed descriptions later in this chapter point out the
   differences.


 1.3  Memory Management

   MS-DOS keeps track of which areas of memory are allocated by writing a
   memory control block at the beginning of each. This control block
   specifies the size of the memory area; the name of the process, if any,
   that owns the memory area; and a pointer to the next area of memory. If
   the memory area is not owned, it is available.

   Table 1.2 lists the MS-DOS function requests for managing memory.

   Table 1.2
   Memory Management Function Requests
   Code       Request              Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   48H       Allocate Memory      Requests a block of memory

   49H       Free Allocated       Frees a block of memory previously
              Memory               allocated with 48H

   4AH       Set Block            Changes the size of an allocated memory
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   When a process requests additional memory with Function 48H (Allocate
   Memory), MS-DOS searches for a block of available memory large enough to
   satisfy the request. If it finds such a block of memory, it changes the
   memory control block to show the owning process. If the block of memory is
   larger than the requested amount, MS-DOS changes the size field of the
   memory control block to the requested amount, writes a new memory control
   block at the beginning of the unneeded portion showing that it is
   available, and updates the pointers to add this memory to the chain of
   memory control blocks. MS-DOS then returns the segment address of the
   first byte of the allocated memory to the requesting process.

   When a process releases an allocated block of memory with Function 49H
   (Free Allocated Memory), MS-DOS changes the memory control block to show
   that it is available (not owned by any process).

   When a process uses Function 4AH (Set Block) to shrink an allocated block
   of memory, MS-DOS builds a memory control block for the memory being
   released and adds it to the chain of memory control blocks. When a process
   tries to use Function 4AH (Set Block) to expand an allocated block of
   memory, MS-DOS treats it as a request for additional memory rather than
   returning the segment address of the additional memory to the requesting
   process. However, MS-DOS simply chains the additional memory to the
   existing memory block. If MS-DOS can't find a block of available memory
   large enough to satisfy a request for additional memory made with either
   Function 48H (Allocate Memory) or Function 4AH (Set Block), MS-DOS
   returns an error code to the requesting process.

   When a program receives control, it should call Function 4AH (Set Block)
   to shrink its initial memory-allocation block (the block that begins with
   its Program Segment Prefix) to the minimum it requires. This frees
   unneeded memory and makes the best application design for portability to
   future multitasking environments.

   When a program exits, MS-DOS automatically frees its initial
   memory-allocation block before returning control to the calling program
   (command.com is usually the calling program for application programs). DOS
   frees any memory owned by the exiting process.

   Any program that changes memory that is not allocated to it will most
   likely destroy at least one memory-management control block. This causes a
   memory-allocation error the next time MS-DOS tries to use the chain of
   memory-control blocks; the only cure is to restart the system.


 1.4  Process Management

   MS-DOS uses several function requests to load, execute, and terminate
   programs. Application programs can use these same function requests to
   manage other programs.

   Table 1.3 lists the MS-DOS function requests for managing processes.

   Table 1.3
   Process-Management Function Requests
   Code       Request              Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   31H       Keep Process         Terminates a process and returns control
                                   to the invoking process, but keeps the
                                   terminated process in memory

   4B00H,    Load and Execute     Loads and executes a program, or loads a
   4B03H     Program or Overlay   program overlay without executing it

   4CH       End Process          Returns control to the invoking process

   4DH       Get Return Code of   Returns a code passed by an exiting child
              Child Process        process

   62H       Get PSP              Returns the segment address of the current
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Function 4BH (Load and Execute Program or Overlay) has two subfunctions,
   4B00H (Load and Execute Program) and 4B03H (Load Overlay). The
   differences between them are described in the following sections.

 1.4.1  Loading and Executing a Program

   When a program uses Function 4B00H (Load and Execute Program) to load and
   execute another program, MS-DOS allocates memory, writes a Program Segment
   Prefix (PSP) for the new program at offset 0 of the allocated memory,
   loads the new program, and passes control to it. When the invoked program
   exits, control returns to the calling program.

   Command.com uses Function 4B00H to load and execute command files.
   Application programs have the same degree of control over process
   management as does command.com.

   In addition to these common features, there are some differences in the
   way MS-DOS loads .com and .exe files.

   Loading a .Com Program

   When command.com loads and executes a .com program, it allocates all
   available memory to the application and sets the stack pointer 100H bytes
   from the end of available memory. A .com program should set up its own
   stack before shrinking its initial memory-allocation block with Function
   4AH (Set Block) because the default stack is in the memory to be
   released.

   If a newly loaded program is allocated all of memoryÄÄas a .com program
   isÄÄor requests all of available memory by using Function 48H (Allocate
   Memory), MS-DOS allocates to it the memory occupied by the transient part
   of command.com. If the program changes this memory, MS-DOS must reload the
   transient portion of command.com before it can continue. If a program
   exits (via Function 31H, Keep Process) without releasing enough memory,
   the system halts and must be reset. To minimize this possibility, a .com
   program should use Function 4AH (Set Block) to shrink its initial
   allocation block before doing anything else. Also, before exiting, all
   programs must release all memory they allocate by using Function 48H
   (Allocate Memory).

   Loading a .Exe Program

   When command.com loads and executes a .exe program, it allocates the size
   of the program's memory image plus either the value in the MAXÄÄALLOC
   field (offset 0CH) of the file header (if that much memory is available)
   or the value in the MINÄÄALLOC field (offset 0AH). The linker sets these
   fields. Before passing control to the .exe file, MS-DOS uses the
   relocation information in the file header to calculate the correct
   relocation addresses.

   For a more detailed description of how MS-DOS loads .com and .exe files,
   see Chapter 3, "MS-DOS Technical Information," and Chapter 4, "MS-DOS
   Control Blocks and Work Areas."

   Executing a Program from Within Another Program

   Since command.com builds pathnames, searches directory paths for
   executable files, and relocates .exe files, the simplest way to load and
   execute a program is to load and execute an additional copy of
   command.com, passing it a command line that includes the /C switch, which
   invokes the .com or .exe file. The description of Function 4B00H (Load
   and Execute Program) describes how to do this.

 1.4.2  Loading an Overlay

   When a program uses Function 4B03H (Load Overlay) to load an overlay, it
   must pass MS-DOS the segment address at which the overlay is to be loaded.
   The program must call the overlay, which then returns directly to the
   calling program. The calling program is in complete control: MS-DOS does
   not write a PSP for the overlay or intervene in any other way.

   MS-DOS does not check to see if the calling program owns the memory where
   the overlay is to be loaded. If the calling program does not own the
   memory, loading the overlay will most likely destroy a memory-control
   block, causing an eventual memory-allocation error.

   Therefore, a program that loads an overlay must either allow room for the
   overlay when it calls Function 4AH (Set Block) to shrink its initial
   memory-allocation block, or shrink its initial memory-allocation block to
   the minimum and then use Function 48H (Allocate Memory) to allocate
   memory for the overlay.


 1.5  File and Directory Management

   The MS-DOS hierarchical (multilevel) file system is similar to that of the
   XENIX operating system. For a description of the multilevel directory
   system and how to use it, see the MS-DOS User's Reference.

 1.5.1  Handles

   To create or open a file, a program passes MS-DOS a pathname and the
   attribute to be assigned to the file. MS-DOS returns a 16-bit number,
   called a handle. For most subsequent actions, MS-DOS requires only this
   handle to identify the file.

   A handle can refer to either a file or a device. MS-DOS predefines five
   standard handles. These handles are always open, so you needn't open them
   before you use them. Table 1.4 lists these predefined handles.

   Table 1.4
   Predefined Device Handles
   Handle     Standard device      Comment
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0          Input                Can be redirected from command line
   1          Output               Can be redirected from command line
   2          Error
   3          Auxiliary
   4          Printer
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   When MS-DOS creates or opens a file, it assigns the first available
   handle. Since a program can have 20 open handles, including the five
   predefined handles, it typically can open 15 extra files. By using
   Function 46H (Force Duplicate File Handle), MS-DOS can temporarily force
   any of the five predefined handles to refer to an alternate file or
   device. For more information about Function 46H, see its description
   later in this chapter.

 1.5.2  File-Related Function Requests

   MS-DOS treats a file as a string of bytes; it assumes no record structure
   or access technique. An application program imposes whatever record
   structure it needs on this string of bytes. Reading from or writing to a
   file requires only pointing to the data buffer and specifying the number
   of bytes to read or write. Table 1.5 lists the MS-DOS function requests
   for managing files.

   Table 1.5
   File-Related Function Requests
ÖŚÄŚÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ·
   Code       Request              Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   3CH       Create Handle        Creates a file

   3DH       Open Handle          Opens a file

   3EH       Close Handle         Closes a file

   3FH       Read Handle          Reads from a file

   40H       Write Handle         Writes to a file

   42H       Move File Pointer    Sets the read/write pointer in a file

   45H       Duplicate File       Creates a new handle that refers to the
   Code       Request              Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  45H       Duplicate File       Creates a new handle that refers to the
              Handle               same file as an existing handle

   46H       Force Duplicate File Makes an existing handle refer to the same
              Handle               file as another existing handle

   5AH       Create Temporary     Creates a file with a unique name
              File

   5BH       Create New File      Attempts to create a file, but fails if a
                                   file with the same name exists

   67H       Set Handle Count     Increases or decreases the number of files
                                   a program can have open at one time

   68H       Commit File          Flushes buffered data for a file without
                                   closing it to ensure the disk image of
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Code       Request              Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


   File Sharing

   Version 3.1 of MS-DOS introduced file sharing, which let more than one
   process share access to a file. File sharing operates only after the share
   command has been executed to load file-sharing support. That is, you must
   use the share command to take advantage of file sharing.

   Table 1.6 lists the MS-DOS function requests for sharing files; if file
   sharing is not in effect, these function requests cannot be used. Function
   3DH (Open Handle) can operate in several modes. Here it is referred to in
   the file-sharing modes, which require file sharing to be in effect.
   (Compatibility mode is usable without file sharing being in effect.)

   Table 1.6
   File-Sharing Function Requests
   Code       Request              Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   3DH       Open Handle          Opens a file by using one of the
                                   file-sharing modes

   440BH     IOCtl Retry          (before Interrupt 24H is issued)
                                   Specifies how many times to retry an I/O
                                   operation that fails due to a file-sharing
                                   violation

   5C00H     Lock                 Locks a region of a file

   5C01H     Unlock               Unlocks a region of a file
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

 1.5.3  Device-Related Function Requests

   I/O Control for devices is implemented with Function 44H (IOCtl), which
   includes several subfunctions necessary to perform device-related tasks.
   Some forms of the IOCtl function request require that the device driver be
   written to support the IOCtl interface. Table 1.7 lists the MS-DOS
   function requests for managing devices.

   Table 1.7
   Device-Related Function Requests
ÖŚÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ·
   Code            Request                  Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   4400H, 4401H  IOCtl Data               Gets or sets device description

   4402H, 4403H  IOCtl Character          Gets or sets character-device
                                            control data

   4404H, 4405H  IOCtl Block              Gets or sets block-device control
                                            data

   4406H, 4407H  IOCtl Status             Checks device input or output
                                            status

   4408H          IOCtl Is Changeable      Checks whether block device
                                            contains removable medium

   440CH          Generic IOCtl (for       Sets Generic IOCtl for handles
                   handles)                 and supports code pages for
   Code            Request                  Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
                  handles)                 and supports code pages for
                                            devices or returns DCBS
                                            information.

   440DH          Generic IOCtl (for       Sets Generic IOCtl for devices
                   devices)

   440EH, 440FH  Get/Set IOCtl Drive Map  Gets or sets logical drive map
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


   Some forms of the IOCtl function request can be used only with Microsoft
   Networks; these forms are listed in Section 1.6, "Microsoft Networks."

 1.5.4  Directory-Related Function Requests

   A directory entry is a 32-byte record that includes the file's name,
   extension, date and time of last change, and size. An entry in a
   subdirectory is identical to an entry in the root directory. Directory
   entries are described in detail in Chapter 3.

   The root directory on a disk has room for a fixed number of entries: 64 on
   a standard single-sided disk, 112 on a standard double-sided disk. For
   hard disks, the number of directories depends on the DOS partition size. A
   subdirectory is simply a file with a unique attribute; there can be as
   many subdirectories on a disk as space allows. The depth of a directory
   structure, therefore, is limited only by the amount of storage on a disk
   and the maximum pathname length of 64 characters. Pre-2.0 disks appear to
   have only a root directory that contains files but no subdirectories.

   Table 1.8 lists the MS-DOS function requests for managing directories.

   Table 1.8
   Directory-Related Function Requests
ÖŚÄŚÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ·
   Code       Request              Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   39H       Create Directory     Creates a subdirectory

   3AH       Remove Directory     Deletes a subdirectory
   Code       Request              Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  3AH       Remove Directory     Deletes a subdirectory

   3BH       Change Current       Changes the current directory
              Directory

   41H       Delete Directory     Deletes a file
              Entry (Unlink)

   43H       Get/Set File         Retrieves or changes the attributes of a
              Attributes (Chmod)   file

   47H       Get Current          Returns current directory for a given
              Directory            drive

   4EH       Find First File      Searches a directory for the first entry
                                   that matches a filename

   4FH       Find Next File       Searches a directory for the next entry
                                   that matches a filename
   Code       Request              Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
                                  that matches a filename

   56H       Change Directory     Renames a file
              Entry

   57H       Get/Set Date/Time of Changes the time and date of last change
              File                 in a directory entry
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


 1.5.5  File Attributes

   Table 1.9 describes the file attributes and how they are represented in
   the attribute byte of the directory entry (offset 0BH). The attributes can
   be inspected or changed with Function 43H (Get/Set File Attributes
   [Chmod]).

   Table 1.9
   File Attributes
   Code                     Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   00H                      Normal; can be read or written without
                            restriction

   01H                      Read-only; cannot be opened for write; a file
                            with the same name cannot be created

   02H                      Hidden; not found by directory search

   04H                      System; not found by directory search

   08H                      VolumeID; only one file can have this attribute;
                            it must be in the root directory

   10H                      Subdirectory

   20H                      Archive; set whenever the file is changed, or
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   The VolumeID (08H) and Subdirectory (10H) attributes cannot be changed
   with Function 43H (Get/Set File Attributes [Chmod]).


 1.6  Microsoft Networks

   Microsoft Networks consists of a server and one or more workstations.
   MS-DOS maintains an assign list that keeps track of which workstation disk
   drives and devices have been redirected to the server. For a description
   of the operation and use of the network, see the Microsoft Networks
   Manager's Guide and Microsoft Networks User's Guide.

   Table 1.10 lists the MS-DOS function requests for managing a Microsoft
   Networks workstation.

   Table 1.10
   Microsoft Networks Function Requests
ÖŚÄŚÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ·
   Code       Request              Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   4409H     IOCtl Is Redirected  Checks whether a drive letter refers to a
              Block                local or redirected drive
   Code       Request              Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
             Block                local or redirected drive

   440AH     IOCtl Is Redirected  Checks whether a device name refers to a
              Handle               local or redirected device

   5E00H     Get Machine Name     Gets the network name of the workstation

   5E02H     Set Printer Setup    Defines a string of control characters to
                                   be added at the beginning of each file
                                   that is sent to a network printer

   5F02H     Get Assign-List      Gets an entry from the assign list, which
              Entry                shows the workstation drive letter or
                                   device name and the network name of the
                                   directory or device on the server to which
                                   the entry is reassigned

   5F03H     Make Network         Redirects a workstation drive or device to
              Connection           a server directory or device
   Code       Request              Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
             Connection           a server directory or device

   5F04H     Delete Network       Cancels the redirection of a workstation
              Connection           drive or device to a server directory or
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ



 1.7  National Language Support

   National language support of MS-DOS includes these major features:

   ž  Country-dependent information

   ž  Support for national keyboard layouts

   ž  Programming interfaces for national language support

   ž  Utility commands

   Country-dependent information is available on a per-country basis and
   includes the following:

   ž  Time, date, and currency

   ž  Lowercase-to-uppercase character-conversion tables

   ž  Collating sequence for character sorting

   ž  Valid single-byte characters used in filenames

   Keyboard support for different keyboard layouts is provided and
   selectable.

   Table 1.11 lists the MS-DOS national-language-support system calls that
   allow applications to use the country-dependent information just
   described.

   Table 1.11
   National-Language-Support Function Requests
   Code       Request              Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   65H       Get Extended Country Returns standard country information,
              Information          pointer to uppercase table, pointer to
                                   filename uppercasing table, or pointer to
                                   collating table.

   66H       Get/Set Global Code  Gets or sets the code page used by the
              Page                 kernel and all devices.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


 1.8  Miscellaneous System-Management Functions



   The remaining system calls manage other system functions and resources
   such as drives, addresses, and the clock. Table 1.12 lists the MS-DOS
   function requests for managing miscellaneous system resources and
   operations.

   Table 1.12
   Miscellaneous System-Management Function Requests
ÖŚÄŚÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ·
   Code       Request              Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0DH       Reset Disk           Empties all file buffers

   0EH       Select Disk          Sets the default drive

   19H       Get Current Disk     Returns the default drive

   1AH       Set Disk Transfer    Establishes the disk I/O buffer
              Address

   1BH       Get Default Drive    Returns disk-format data
              Data
   1CH       Get Drive Data       Returns disk-format data

   25H       Set Interrupt Vector Sets interrupt-handler address

   29H       Parse File Name      Checks string for valid filename
   Code       Request              Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  29H       Parse File Name      Checks string for valid filename

   2AH       Get Date             Returns system date

   2BH       Set Date             Sets system date

   2CH       Get Time             Returns system time

   2DH       Set Time             Sets system time

   2EH       Set/Reset Verify     Turns disk verify on or off
              Flag

   2FH       Get Disk Transfer    Returns system-disk-I/O-buffer address
              Address

   30H       Get MS-DOS Version   Returns MS-DOS version number
              Number
   33H       CONTROL+C Check      Returns CONTROL+C check status
   Code       Request              Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  33H       CONTROL+C Check      Returns CONTROL+C check status

   35H       Get Interrupt Vector Returns address of interrupt handler

   36H       Get Disk Free Space  Returns disk-space data

   38H       Get/Set Country Data Sets current country or retrieves country
                                   information

   54H       Get Verify State     Returns status of disk verify
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ



 1.9  Old System Calls

   Most of the superseded system calls deal with files. Table 1.13 lists
   these old calls and the function requests that have superseded them.

   Although MS-DOS still includes these old system calls, they should not be
   used unless a program must maintain backward-compatibility with earlier
   versions of MS-DOS.

   Table 1.13
   Old System Calls and Their Replacements
ÖŚÄŚÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ·
     Old System Call                       Has Been Superseded By
   Code        Function                 Code        Function
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   00H        Terminate Program        4CH        End Process
   0FH        Open File                3DH        Open Handle
   10H        Close File               3EH        Close Handle
   11H        Search for First Entry   4EH        Find First File
   12H        Search for Next Entry    4FH        Find Next File
   13H        Delete File              41H        Delete Directory Entry
   14H        Sequential Read          3FH        Read Handle
   15H        Sequential Write         40H        Write Handle
   16H        Create File              3CH        Create Handle
                                        5AH        Create Temporary File
                                        5BH        Create New File
     Old System Call                       Has Been Superseded By
   Code        Function                 Code        Function
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
                                       5BH        Create New File
   17H        Rename File              56H        Change Directory Entry
   21H        Random Read              3FH        Read Handle
   22H        Random Write             40H        Write Handle
   23H        Get File Size            42H        Move File Pointer
   24H        Set Relative Record      42H        Move File Pointer
   26H        Create New PSP           4B00H,     Load and Execute Program
                                        4B03H      or Overlay
   27H        Random Block Read        42H        Move File Pointer
                                        3FH        Read Handle
   28H        Random Block Write       42H        Move File Pointer
                                        40H        Write Handle

   Code        Interrupt                Code        Function
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   20H        Program Terminate        4CH        End Process
   27H        Terminate But Stay       31H        Keep Process
               Resident
     Old System Call                       Has Been Superseded By
   Code        Function                 Code        Function
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
              Resident
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


 1.9.1  File Control Block (FCB)

   The old file-related function requests require that a program maintain a
   File Control Block (FCB) for each file; this control block contains such
   information as a file's name, size, record length, and pointer to current
   record. MS-DOS does most of this housekeeping for the newer,
   handle-oriented function requests.

   Some descriptions of the old function requests refer to unopened and
   opened FCBs. An unopened FCB contains only a drive specifier and filename.
   An opened FCB contains all fields filled by Function 0FH (Open File).

   The Program Segment Prefix (PSP) includes room for two FCBs at offsets 5CH
   and 6CH. For a description of how to use the PSP and FCB calls, see
   Chapter 4, "MS-DOS Control Blocks and Work Areas." Table 1.14 describes
   the FCB fields.

   Table 1.14
   Format of the File Control Block (FCB)
         Offset
   Hex            Dec            Bytes                 Field
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   00H             0             1                     Drive Number
   01H             1             8                     Filename
   09H             9             3                     Extension
   0CH            12             2                     Current Block

   0EH            14             2                     Record Size
   10H            16             4                     File Size
   14H            20             2                     Date of Last Write
   16H            22             2                     Time of Last Write

   18H            24             8                     Reserved
   20H            32             1                     Current Record
   21H            33             4                     Relative Record
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Fields of the FCB

   Drive Number (offset 00H): Specifies the disk drive; 1 means drive A and 2
   means drive B. If you use the FCB to create or open a file, you can set
   this field to 0 to specify the default drive; Function 0FH (Open File)
   sets the field to the number of the default drive.

   Filename (offset 01H): Eight characters, left-aligned and padded (if
   necessary) with blanks. If you specify a reserved device name (such as
   PRN), do not put a colon at the end.

   Extension (offset 09H): Three characters, left-aligned and padded (if
   necessary) with blanks. This field can be all blanks (no extension).

   Current Block (offset 0CH): Points to the block (group of 128 records)
   that contains the current record. This field and the Current Record field
   (offset 1FH) make up the record pointer. This field is set to zero by the
   Open File system call.

   Record Size (offset 0EH): The size of a logical record, in bytes. Set to
   128 by the Open File system call. If the record size is not 128 bytes, you
   must set this field after opening the file.

   File Size (offset 10H): The size of the file, in bytes. The first word of
   this 4-byte field is the low-order part of the size.

   Date of Last Write (offset 14H): The date the file was created or last
   updated. The year, month, and day are mapped into two bytes as follows:

   Offset 15H          Offset 14H
   |Y|Y|Y|Y|Y|Y|Y|M|   |M|M|M|D|D|D|D|D|
   15              9   8    5 4        0

   Time of Last Write (offset 16H): The time the file was created or last
   updated. The hour, minutes, and seconds are mapped into two bytes as
   follows:

   Offset 17H          Offset 16H
   |H|H|H|H|H|M|M|M|   |M|M|M|S|S|S|S|S|
   15      11 10            5 4        0

   Reserved (offset 18H): These fields are reserved for use by MS-DOS.
   Current Record (offset 20H): Points to one of the 128 records in the
   current block. This field and the Current Block field (offset 0CH) make up
   the record pointer. The Open File system call does not initialize this
   field. You must set it before doing a sequential read or write to the
   file.

   Relative Record (offset 21H): Points to the currently selected record,
   counting from the beginning of the file (starting with 0). The Open File
   system call does not initialize this field. You must set it before doing a
   random read or write to the file. If the record size is less than 64
   bytes, both words of this field are used; if the record size is 64 bytes
   or more, only the first three bytes are used.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     If you use the FCB at offset 5CH of the Program Segment Prefix, the last
     byte of the Relative Record field is the first byte of the unformatted
     parameter area that starts at offset 80H. This is the default Disk
     Transfer Area.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Extended FCB

   The Extended File Control Block is used to create or search for directory
   entries of files with special attributes. It adds the following 7-byte
   prefix to the FCB:

   Name                 Bytes      Offset
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Flag byte (FFH)      1          07H
   Reserved             5          06H
   Attribute byte       1          01H
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   File attributes are described earlier in this chapter in Section 1.5.5,
   "File Attributes."

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     You must remember to point to the beginning of the extended FCB if you
     are using Functions 0FH-16H with extended FCBs.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


 1.10  Using the System Calls

   The remainder of this chapter describes how to use the system calls in
   application programs, and it lists the calls in numeric and alphabetic
   order, describing each call in detail.

 1.10.1  Issuing an Interrupt

   MS-DOS reserves Interrupts 28H through 3FH for its own use, and maintains
   the table of interrupt-handler addresses (the vector table) in locations
   80H-FCH. Also, in case you need to write your own routines for three
   particular MS-DOS interrupt handlers (Program Terminate, CONTROL+C, and
   Critical Error), this chapter includes descriptions of each. Function
   requests have superseded most of these interrupts.

   To issue an interrupt, move any required data into the registers and give
   the INT instruction with the number of the interrupt you want.

 1.10.2  Calling a Function Request

   A function request is an MS-DOS routine for managing system resources. Use
   the following procedure to call a function request:

   1. Move any required data into the registers.

   2. Move the function number into AH.

   3. Move the action code, if required, into AL.

   4. Issue Interrupt 21H.

 1.10.3  Using the Calls from a High-Level Language

   The system calls can be executed from any high-level language whose
   modules can be linked with assembly-language modules. In addition to this
   linking technique, you can:

   ž  Use the Interrupt 86 function of C to call a function request directly.

   ž  Use the DOSXQQ function of Pascal to call a function request directly.

   ž  Use the CALL statement or USER function to execute the required
      assembly-language code from the BASIC interpreter.

 1.10.4  Treatment of Registers

   When MS-DOS takes control after a function request, it switches to an
   internal stack, and preserves any registers not used to return information
   (except AX). The calling program's stack must be large enough to
   accommodate the interrupt systemÄÄat least 128 bytes in addition to other
   needs.

 1.10.5  Handling Errors

   Most of the function requests introduced with MD-DOS version 2.0 or later
   set the Carry flag if there is an error, identifying the specific error by
   returning a number in the AX register. Table 1.15 lists these error codes
   and their meanings.

   Table 1.15
   Error Codes Returned in AX
ÖŚÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ·
   Code           Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
    1             Invalid function code
    2             File not found
    3             Path not found
    4             Too many open files (no open handles left)
    5             Access denied
    6             Invalid handle
    7             Memory control blocks destroyed
    8             Insufficient memory
    9             Invalid memory block address

   10             Invalid environment
   11             Invalid format
   12             Invalid access code
   13             Invalid data
   14             Reserved
   15             Invalid drive
   Code           Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  15             Invalid drive
   16             Attempt to remove the current directory
   17             Not same device
   18             No more files
   19             Disk is write-protected

   20             Bad disk unit
   21             Drive not ready
   22             Invalid disk command
   23             CRC error
   24             Invalid length (disk operation)
   25             Seek error
   26             Not an MS-DOS disk
   27             Sector not found
   28             Out of paper
   29             Write fault

   30             Read Fault
   31             General failure
   Code           Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  31             General failure
   32             Sharing violation
   33             Lock violation
   34             Wrong disk
   35             FCB unavailable
   36             Sharing buffer exceeded
   37             Reserved
   38             Handle end-of-file operation not completed
   39-49          Reserved

   50             Network request not supported
   51             Remote computer not listening
   52             Duplicate name on network
   53             Network name not found
   54             Network busy
   55             Network device no longer exists
   56             Net BIOS command limit exceeded
   57             Network adapter hardware error
   58             Incorrect response from network
   Code           Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  58             Incorrect response from network
   59             Unexpected network error

   60             Incompatible remote adapter
   61             Print queue full
   62             Queue not full
   63             Not enough space for print file
   64             Network name was deleted
   65             Access denied
   66             Network device type incorrect
   67             Network name not found
   68             Network name limit exceeded
   69             Net BIOS session limit exceeded

   70             Temporarily paused
   71             Network request not accepted
   72             Print or disk redirection is paused
   73-79          Reserved

   Code           Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   80             File Exists
   81             Reserved
   82             Cannot make
   83             Interrupt 24 failure
   84             Out of structures
   85             Already assigned
   86             Invalid password
   87             Invalid parameter
   88             Net write fault
   89             Function not supported by network

   90             Required system component not installed
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


   To handle error conditions, put the following statement immediately after
   calls that return errors:

   JC <error>

   <Error> represents the label of an error-handling routine that gets the
   specific error condition by checking the value in AX. This routine then
   takes appropriate action.

   Some of the older system calls return a value in a register that specifies
   whether the operation was successful. To handle such errors, check the
   error code and take the appropriate action.

   Extended Error Codes

   Versions of MS-DOS after 2.0 have added new error messages. Any programs
   that use the older system calls cannot use these new error messages. To
   avoid incompatibility, MS-DOS maps these new error codes to the old error
   code that most closely matches the new one.

   Function 59H (Get Extended Error) has been added so that these new calls
   can be used. It provides as much detail as possible about the most recent
   error code returned by MS-DOS. The description of Function 59H lists the
   new, more detailed error codes and shows how to use this function request.

 1.10.6  System Call Descriptions

   Most system calls require that you move information into one or more
   registers before issuing the call that returns information in the
   registers. The description of each system call in this chapter includes
   the following:

   ž  A diagram of the 8088 registers that shows their contents before and
      after the system call

   ž  A more complete description of the register contents required before
      the system call

   ž  A description of the processing performed

   ž  A more complete description of the register contents after the system
      call

   ž  An example of how to use the system call

   The following figure is a sample illustration of the 8088 registers,
   showing how the information is presented. Shaded areas indicate that the
   register receives or returns information used by the call.

      ŚÄÄÄÄÄÄÄĀÄÄÄÄÄÄÄæ
   AX:³  AH   ³  AL   ³
      ĆÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄ“
   BX:³  BH   ³  BL   ³
      ĆÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄ“
   CX:³  CH   ³  CL   ³
      ĆÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄ“
   DX:³  DH   ³  DL   ³
      ĄÄÄÄÄÄÄÄĮÄÄÄÄÄÄÄŁ
      ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
      ³       SP      ³
      ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
      ³       BP      ³
      ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
      ³       SI      ³
      ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
      ³       DI      ³
      ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ
      ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
      ³       SP      ³
      ĆÄÄÄÄÄÄÄĀÄÄÄÄÄÄÄ“
      ³FLAGS H³FLAGS L³
      ĄÄÄÄÄÄÄÄĮÄÄÄÄÄÄÄŁ

      ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
      ³       CS      ³
      ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
      ³       DS      ³
      ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
      ³       SS      ³
      ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
      ³       ES      ³
      ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   Figure 1.1  Example of the 8088 Registers

   Sample Programs

   The sample programs show only data declarations and the code that you need
   to use the system calls. Unless stated otherwise, each example assumes a
   common program skeleton that defines the segments and returns control to
   MS-DOS. Each sample program is intended to be executed as a .com file.
   Figure 1.2 shows a complete sample program. The unshaded portion shows
   what appears in this chapter; the shaded portions are the common skeleton.


   ------------------------------------------------------------
   code       segment
              assume  cs:code,ds:code,es:nothing,ss:nothing
              org     100H
   start:     jmp    begin
   ;
   filename   db     "b:\textfile.asc",0
   buffer     db      129 dup (?)
   handle     dw      ?
   ;
   begin:     open_handle filename,0    ; Open the file
              jc      error_open        ; Routine not shown
              mov     handle,ax         ; Save handle
   read_line: read_handle handle,buffer,128 ; Read 128 bytes
              jc      error_read        ; Routine not shown
              cmp     ax,0              ; End of file?
              je      return            ; Yes, go home
              mov     bx,ax             ; No, AX bytes read
              mov     buffer[bx],"$"    ; To terminate string
              display buffer            ; See Function 09H
              jmp     read_line         ; Get next 128 bytes

   return:    end_process 0             ; Return to MS-DOS
   last_inst:                           ; To mark next byte
   ;
   code       ends
              end     start
   ------------------------------------------------------------

   Figure 1.2  Sample Program with Common Skeleton

   A macro has been defined for each system call to allow the examples to be
   more complete programs, rather than isolated uses of the system calls.
   These macros, plus some general-purpose ones, are used in the sample
   programs. For instance, the sample program in the preceding figure
   includes four such macros: open_handle, read_handle, display, and
   end_process. All the macro definitions are listed at the end of this
   chapter.

   The macros assume the environment for a .com program as described in
   Chapter 4; in particular, they assume that all the segment registers
   contain the same value. To conserve space, the macros generally leave
   error checking to the main code and do not protect registers. This keeps
   the macros short, yet useful. You may find that such macros are a
   convenient way to include system calls in your assembly-language programs.

   Error Handling in Sample Programs

   Whenever a system call returns an error code, the sample program shows a
   test for the error condition and a jump to an error routine. To conserve
   space, the error routines themselves aren't shown. Some error routines
   might simply display a message and continue processing. For more serious
   errors, the routine might display a message and end the program
   (performing any required housekeeping, such as closing files).

   Tables 1.16 through 1.19 list the Interrupts and Function Requests in
   numeric and alphabetic order.

   Table 1.16
   MS-DOS Interrupts, Numeric Order
   Interrupt                            Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   20H                                 Program Terminate
   21H                                 Function Request
   22H                                 Terminate Process Exit Address
   23H                                 CONTROL+C Handler Address
   24H                                 Critical-Error-Handler Address
   25H                                 Absolute Disk Read
   26H                                 Absolute Disk Write
   27H                                 Terminate But Stay Resident
   28H-3FH                              Reserved
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Table 1.17
   MS-DOS Interrupts, Alphabetic Order
   Description                          Interrupt
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Absolute Disk Read                   25H
   Absolute Disk Write                  26H
   CONTROL+C Handler Address            23H
   Critical-Error-Handler Address       24H
   Function Request                     21H
   Program Terminate                    20H
   Reserved                             28H-3FH
   Terminate Process Exit Address       22H
   Terminate But Stay Resident          27H
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Table 1.18
   MS-DOS Function Requests, Numeric Order
ÖŚÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ·
   Function           Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   00H               Terminate Program
   01H               Read Keyboard And Echo
   02H               Display Character
   03H               Auxiliary Input
   Function           Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  03H               Auxiliary Input
   04H               Auxiliary Output
   05H               Print Character
   06H               Direct Console I/O
   07H               Direct Console Input
   08H               Read Keyboard
   09H               Display String
   0AH               Buffered Keyboard Input
   0BH               Check Keyboard Status
   0CH               Flush Buffer, Read Keyboard
   0DH               Reset Disk
   0EH               Select Disk
   0FH               Open File
   10H               Close File
   11H               Search For First Entry
   12H               Search For Next Entry
   13H               Delete File
   14H               Sequential Read
   15H               Sequential Write
   Function           Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  15H               Sequential Write
   16H               Create File
   17H               Rename File
   18H                Reserved
   19H               Get Current Disk
   1AH               Set Disk Transfer Address
   1BH               Get Default Drive Data
   1CH               Get Drive Data
   1DH-20H            Reserved
   21H               Random Read
   22H               Random Write
   23H               Get File Size
   24H               Set Relative Record
   25H               Set Interrupt Vector
   26H               Create New PSP
   27H               Random Block Read
   28H               Random Block Write
   29H               Parse File Name
   2AH               Get Date
   Function           Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  2AH               Get Date
   2BH               Set Date
   2CH               Get Time
   2DH               Set Time
   2EH               Set/Reset Verify Flag
   2FH               Get Disk Transfer Address
   30H               Get MS-DOS Version Number
   31H               Keep Process
   32H                Reserved
   33H               CONTROL+C Check
   34H                Reserved
   35H               Get Interrupt Vector
   36H               Get Disk Free Space
   37H                Reserved
   38H               Get/Set Country Data
   39H               Create Directory
   3AH               Remove Directory
   3BH               Change Current Directory
   3CH               Create Handle
   Function           Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  3CH               Create Handle
   3DH               Open Handle
   3EH               Close Handle
   3FH               Read Handle
   40H               Write Handle
   41H               Delete Directory Entry (Unlink)
   42H               Move File Pointer
   43H               Get/Set File Attributes (Chmod)
   4400H, 4401H     IOCtl Data
   4402H, 4403H     IOCtl Character
   4404H, 4405H     IOCtl Block
   4406H, 4407H     IOCtl Status
   4408H             IOCtl Is Changeable
   4409H             IOCtl Is Redirected Block
   440AH             IOCtl Is Redirected Handle
   440BH             IOCtl Retry
   440CH             Generic IOCtl (for code page functions)
   440DH             Generic IOCtl (for devices)
   440EH             Get IOCtl Drive Map
   Function           Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  440EH             Get IOCtl Drive Map
   440FH             Set IOCtl Drive Map
   45H               Duplicate File Handle
   46H               Force Duplicate File Handle
   47H               Get Current Directory
   48H               Allocate Memory
   49H               Free Allocated Memory
   4AH               Set Block
   4B00H, 4B03H     Load and Execute Program or Overlay
   4CH               End Process
   4DH               Get Return Code of Child Process
   4EH               Find First File
   4FH               Find Next File
   50H-53H            Reserved
   54H               Get Verify State
   55H                Reserved
   56H               Change Directory Entry
   57H               Get/Set Date/Time of File
   58H               Get/Set Allocation Strategy
   Function           Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  58H               Get/Set Allocation Strategy
   59H               Get Extended Error
   5AH               Create Temporary File
   5BH               Create New File
   5C00H, 5C01H     Lock/Unlock Files
   5DH                Reserved
   5E00H             Get Machine Name
   5E02H             Set Printer Setup
   5E03H             Get Printer Setup
   5F02H             Get Assign-List Entry
   5F03H             Make Network Connection
   5F04H             Delete Network Connection
   60H-61H            Reserved
   62H               Get PSP
   63H,64H            Reserved
   65H               Get Extended Country Information
   66H               Get/Set Global Code Page
   67H               Set Handle Count
   68H               Commit File
   Function           Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  68H               Commit File
   69H-6BH            Reserved
   6CH               Extended Open/Create
   6DH-7FH            Reserved
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


   Table 1.19
   MS-DOS Function Requests, Alphabetic Order
ÖŚÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ·
   Description                                             Function
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Allocate Memory                                         48H
   Auxiliary Input                                         03H
   Auxiliary Output                                        04H
   Buffered Keyboard Input                                 0AH
   Change Current Directory                                3BH
   Change Directory Entry                                  56H
   Check Keyboard Status                                   0BH
   Description                                             Function
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  Check Keyboard Status                                   0BH
   Close File                                              10H
   Close Handle                                            3EH
   Commit FIle                                             68H
   CONTROL+C Check                                         33H
   Create Directory                                        39H
   Create File                                             16H
   Create Handle                                           3CH
   Create New File                                         5BH
   Create New PSP                                          26H
   Create Temporary File                                   5AH
   Delete Directory Entry (Unlink)                         41H
   Delete File                                             13H
   Delete Network Connection                               5F04H
   Direct Console I/O                                      06H
   Direct Console Input                                    07H
   Display Character                                       02H
   Display String                                          09H
   Duplicate File Handle                                   45H
   Description                                             Function
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  Duplicate File Handle                                   45H
   End Process                                             4CH
   Extended Open/Create                                    6CH
   Find First File                                         4EH
   Find Next File                                          4FH
   Flush Buffer, Read Keyboard                             0CH
   Force Duplicate File Handle                             46H
   Free Allocated Memory                                   49H
   Generic IOCtl (for devices)                             440DH
   Generic IOCtl (for code page functions)                 440CH
   Get Assign-List Entry                                   5F02H
   Get Current Directory                                   47H
   Get Current Disk                                        19H
   Get Date                                                2AH
   Get Default Drive Data                                  1BH
   Get Disk Free Space                                     36H
   Get Disk Transfer Address                               2FH
   Get Drive Data                                          1CH
   Get Extended Country Information                        65H
   Description                                             Function
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  Get Extended Country Information                        65H
   Get Extended Error                                      59H
   Get File Size                                           23H
   Get Interrupt Vector                                    35H
   Get IOCtl Drive Map                                     440EH
   Get Machine Name                                        5E00H
   Get MS-DOS Version Number                               30H
   Get PSP                                                 62H
   Get Printer Setup                                       5E03H
   Get Return Code of Child Process                        4DH
   Get Time                                                2CH
   Get Verify State                                        54H
   Get/Set Allocation Strategy                             58H
   Get/Set Country Data                                    38H
   Get/Set Date/Time Of File                               57H
   Get/Set File Attributes (Chmod)                         43H
   Get/Set Global Code Page                                66H
   IOCtl Block                                             4404H, 4405H
   IOCtl Character                                         4402H, 4403H
   Description                                             Function
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  IOCtl Character                                         4402H, 4403H
   IOCtl Data                                              4400H, 4401H
   IOCtl Is Changeable                                     4408H
   IOCtl Is Redirected Block                               4409H
   IOCtl Is Redirected Handle                              440AH
   IOCtl Retry                                             440BH
   IOCtl Status                                            4406H, 4407H
   Keep Process                                            31H
   Load and Execute Program                                4B00H
   Load Overlay                                            4B03H
   Lock/Unlock Files                                       5C00H, 5C01H
   Make Network Connection                                 5F03H
   Move File Pointer                                       42H
   Open File                                               0FH
   Open Handle                                             3DH
   Parse File Name                                         29H
   Print Character                                         05H
   Random Block Read                                       27H
   Random Block Write                                      28H
   Description                                             Function
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  Random Block Write                                      28H
   Random Read                                             21H
   Random Write                                            22H
   Read Handle                                             3FH
   Read Keyboard                                           08H
   Read Keyboard And Echo                                  01H
   Remove Directory                                        3AH
   Rename File                                             17H
   Reserved                                                18H
   Reserved                                                1DH-20H
   Reserved                                                32H
   Reserved                                                34H
   Reserved                                                37H
   Reserved                                                50H-53H
   Reserved                                                55H
   Reserved                                                5DH
   Reserved                                                60H-61H
   Reserved                                                63H, 64H
   Reserved                                                69H-6BH
   Description                                             Function
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  Reserved                                                69H-6BH
   Reserved                                                6DH-7FH
   Reset Disk                                              0DH
   Search for First Entry                                  11H
   Search for Next Entry                                   12H
   Select Disk                                             0EH
   Sequential Read                                         14H
   Sequential Write                                        15H
   Set Block                                               4AH
   Set Date                                                2BH
   Set Disk Transfer Address                               1AH
   Set Handle Count                                        67H
   Set Interrupt Vector                                    25H
   Set IOCtl Drive Map                                     440FH
   Set Printer Setup                                       5E02H
   Set Relative Record                                     24H
   Set Time                                                2DH
   Set/Reset Verify Flag                                   2EH
   Terminate Program                                       00H
   Description                                             Function
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  Terminate Program                                       00H
   Write Handle                                            40H
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


   A detailed description of each system call follows. These calls are listed
   in numeric order, interrupts first, followed by function requests.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     Unless stated otherwise, in the system call descriptionsÄÄboth text and
     codeÄÄall numbers are in hexadecimal.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


 1.11  Interrupts

   The following pages describe Interrupts 20H-27H.


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Program Terminate (Interrupt 20H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   CS
     Segment address of Program Segment Prefix

   Return:

   None


   Comments:

   Interrupt 20H terminates the current process and returns control to its
   parent process. It also closes all open file handles and clears the disk
   cache. When this interrupt is issued, CS must contain the segment address
   of the Program Segment Prefix.

   Interrupt 20H is provided only for compatibility with MS-DOS versions
   prior to 2.0. New programs should use Function 4CH (End Process), which
   permits returning a completion code to the parent process and does not
   require CS to contain the segment address of the Program Segment Prefix.

   The following exit addresses are restored from the Program Segment Prefix:

   Offset             Exit Address
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0AH                Program terminate
   0EH                CONTROL+C
   12H                Critical error
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   All file buffers are flushed to disk.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     You should close all files that have changed in length before issuing
     this interrupt. If you do not close a changed file, its length may not
     be recorded correctly in the directory. See Functions 10H and 3EH for
     a description of the Close File system calls. If sharing is loaded, you
     should remove all locks before using Interrupt 20H. See Function 5C00H
     (Lock) for more information.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   terminate  macro
              int 20H
              endm

   Example:

   The following program displays a message and returns to MS-DOS.

   message db "displayed by INT20H example". 0DH, 0AH, "$"
   ;
   begin:  display message  ; see Function 09H
           terminate        ; THIS INTERRUPT
   code    ends
           end     start


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Function Request (Interrupt 21H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH
     Function number

   Other registers
     As specified in individual function

   Return:

   None


   Comments:

   As specified in individual function. Interrupt 21H causes MS-DOS to carry
   out the function request whose number is in AH. See Section 1.12,
   "Function Requests," for a description of the MS-DOS functions.

   Example:

   To call the Get Time function:

   mov   ah,2CH           ; Get Time is Function 2CH
   int   21H              ; MS-DOS function request


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Terminate Process Exit Address (Interrupt 22H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   This interrupt may be issued only by MS-DOS; user programs must never
   issue it. If you must write your own terminate interrupt handler, use
   Function 35H (Get Interrupt Vector) to get the address of the standard
   routine, save the address, then use Function 25H (Set Interrupt Vector)
   to change the Interrupt 22H entry in the vector table so that it points to
   your routine.

   When a program terminates, MS-DOS transfers control to the routine that
   starts at the address in the Interrupt 22H entry in the vector table. When
   MS-DOS creates a program segment, it copies this address into the Program
   Segment Prefix, starting at offset 0AH.


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 CONTROL+C Handler Address (Interrupt 23H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   When you type CONTROL+C or CONTROL+BREAK (on IBM-compatibles), MS-DOS
   transfers control as soon as possible to the routine that starts at the
   address in the Interrupt 23H entry in the vector table. When MS-DOS
   creates a program segment, it copies the address currently in the
   interrupt table into the Program Segment Prefix, starting at offset 0EH.

   This interrupt may be issued only by MS-DOS; user programs must never
   issue it. If you must write your own CONTROL+C interrupt handler, use
   Function 35H (Get Interrupt Vector) to get the address of the standard
   routine, save the address, then use Function 25H (Set Interrupt Vector)
   to change the Interrupt 23H entry in the vector table to point to your
   routine.

   If the CONTROL+C routine preserves all registers, it can end with an IRET
   instruction (return from interrupt) to continue program execution. If a
   user-written interrupt program returns with a long return, the program
   uses the carry flag to determine whether or not the program will abort. If
   the carry flag is set, it will abort; otherwise, execution will continue
   as with a return by IRET.

   If a user-written CONTROL+BREAK routine interrupts function calls 09H,
   0AH, or buffered I/O, and if it continues execution with an IRET, then I/O
   continues from the start of the line. MS-DOS always outputs a CONTROL+C to
   the screen when it issues an Interrupt 23H. There is no way to turn this
   off.

   When the interrupt occurs, all registers are set to the value they had
   when the original call to MS-DOS was made. There are no restrictions on
   what a CONTROL+C handler can doÄÄincluding calling MS-DOS functionsÄÄas
   long as the program restores the registers.

   If a CONTROL+C interrupts Function 09H or 0AH (Display String or Buffered
   Keyboard Input), the three-byte sequence 03H-0DH-0AH (usually displayed as
   C followed by a carriage-return) is sent to the display and the function
   resumes at the beginning of the next line.

   Suppose a program uses Function 4BH (Load and Execute Program or Overlay)
   to create a second Program Segment Prefix and execute a second program,
   which then changes the CONTROL+C address in the vector table. MS-DOS
   restores this CONTROL+C vector to its original value before returning
   control to the calling program.


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 critical-error-handler address (Interrupt 24H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   If a critical error occurs during execution of an I/O function
   request (this often means a fatal disk error), MS-DOS transfers control to
   the routine at the address in the Interrupt 24H entry in the vector table.
   When MS-DOS creates a program segment, it copies this address into the
   Program Segment Prefix, starting at offset 12H.

   This interrupt may be issued only by MS-DOS; user programs must never
   issue it. If you must write your own critical-error interrupt handler, use
   Function 35H (Get Interrupt Vector) to get the address of the standard
   routine, save the address, then use Function 25H (Set Interrupt Vector)
   to change the Interrupt 24H entry in the vector table to point to your
   routine.

   MS-DOS does not issue Interrupt 24H if a failure occurs during execution
   of Interrupt 25H (Absolute Disk Read) or Interrupt 26H (Absolute Disk
   Write). A command.com error routine handles these errors. This routine
   retries the disk operation, then gives you the choice of aborting the
   operation, retrying it, allowing the system call to fail and the
   application process to continue, or ignoring the error.

   The following topics describe the requirements of an Interrupt 24H
   routine, including the error codes, registers, and stack.

 1.11.1  Conditions upon Entry

   After retrying an I/O error five times, MS-DOS issues Interrupt 24H,
   unless a File Allocation Table (FAT) or directory sector is involved. In
   those cases, DOS performs three retries. The interrupt handler receives
   control with interrupts disabled. AX and DI contain error codes, and BP
   contains the offset (to the segment address in SI) of a Device Header
   control block that describes the device on which the error occurred.

 1.11.2  Requirements for an Interrupt 24H Handler

   To issue the "Abort, Retry, Fail or Ignore" prompt to a user, a
   user-written critical-error handler should first push the flags and
   execute a FAR call to the address of the standard Interrupt 24H handler
   (the user program that changed the Interrupt 24H vector also should have
   saved this address). After a user responds to the prompt, MS-DOS returns
   control to the user-written routine.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     There are source applications which will have trouble handling critical
     errors, since this changes the stack frame.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   The error handler can then do its processing. However, before it does
   anything else, it must preserve BX, CX, DX, DS, ES, SS, and SP. Also, the
   error handler may use only function calls 01H-0CH (inclusive) and 59H (if
   it uses any others, the error handler destroys the MS-DOS stack and leaves
   MS-DOS in an unstable state). The contents of the Device Header should not
   be changed.

   It is recommended that the Interrupt 24H routine fail critical errors and
   let the application test for an extended error code when the Interrupt
   21H routine returns.

   User Stack

   This call uses the user stack that contains the following (starting with
   the top of the stack):

   IP     MS-DOS registers from issuing Interrupt 24H
   CS
   FLAGS

   AX     User registers at time of original
   BX     INT 21H
   CX
   DX
   SI
   DI
   BP
   DS
   ES

   IP     From the original INT 21H
   CS     from the user to MS-DOS
   FLAGS

   The registers are set such that if the user-written error handler issues
   an IRET, MS-DOS responds according to the value in AL:

   AL                 Action
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0                  Ignore the error.
   1                  Retry the operation.
   2                  Abort the program by issuing Interrupt 23H.
   3                  Fail the system call that is in progress.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Notice that the ignore option may cause unexpected results, such as
   causing MS-DOS to behave as if an operation had completed successfully.

   Disk Error Code in AX

   If bit 7 of AH is 0, the error occurred on a disk drive. AL contains the
   failing drive (0=A, 1=B, etc.). Bit 0 of AH specifies whether the error
   occurred during a read or write operation (0=read, 1=write), and bits 1
   and 2 of AH identify the area of the disk where the error occurred:

   Bits 1-2                             Location of error
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   00                                   MS-DOS area
   01                                   File Allocation Table
   10                                   Directory
   11                                   Data area
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Bits 3-5 of AH specify valid responses to the error prompt:

   Bit        Value                Response
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   3          0                    Fail not allowed
              1                    Fail allowed
   4          0                    Retry not allowed
              1                    Retry allowed
   5          0                    Ignore not allowed
              1                    Ignore allowed
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   If you specify Retry but it isn't allowed, MS-DOS changes it to Fail. If
   you specify Ignore but it isn't allowed, MS-DOS changes it to Fail. If you
   specify Fail but it isn't allowed, MS-DOS changes it to Abort. The Abort
   response is always allowed.

   Other Device Error Code in AX

   If bit 7 of AH is 1, either the memory image of the File Allocation Table
   (FAT) is bad or an error occurred on a character device. The device header
   pointed to by BP:SI contains a WORD of attribute bits that identify the
   type of device and, therefore, the type of error.

   The word of attribute bits is at offset 04H of the Device Header. Bit 15
   specifies the type of device (0=block, 1=character).

   If bit 15 is 0 (block device), the error was a bad memory image of the
   FAT.

   If bit 15 is 1 (character device), the error was on a character device. DI
   contains the error code, the contents of AL are undefined, and bits 0-3 of
   the attribute word have the following meaning:

   Bit                Meaning if Set
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0                  Current standard input
   1                  Current standard output
   2                  Current null device
   3                  Current clock device
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   See Chapter 2, "MS-DOS Device Drivers," for a complete description of the
   Device Header control block.

   Error Code in DI

   The high byte of DI is undefined. The low byte contains the following
   error codes:

   Error code         Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0                  Attempt to write on write-protected disk
   1                  Unknown unit
   2                  Drive not ready
   3                  Unknown command
   4                  CRC error in data
   5                  Bad drive request structure length
   6                  Seek error
   7                  Unknown media type
   8                  Sector not found
   9                  Printer out of paper
   A                  Write fault
   B                  Read fault
   C                  General failure
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   A user-written Interrupt 24H handler can use Function 59H (Get Extended
   Error) to get detailed information about the error that caused the
   interrupt to be issued.


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Absolute Disk Read (Interrupt 25H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AL
     Drive number
   DS:BX
     Disk Transfer Address or
     Far pointer to parameter packet if CX = -1
   CX
     Number of sectors or -1
   DX
     Beginning relative sector

   Return:

   AL
     Error code if CF=1
   FLAGS
     CF        = 0 if successful
           = 1 if not successful
     AX
      0207 if attempt made to access partition larger
      than 32 megabytes with MS-DOS 3.3 or earlier.


   Comments:

   The registers must contain the following:

   Register           Contents
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   AL                 Drive number (0=A, 1=B, etc.)

   DS:BX              Offset of Disk Transfer Address or far pointer to
                      parameter packet if CX = -1

   CX                 Number of sectors to read or -1

   DX                 Beginning relative sector
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Warning
     Avoid using this function unless absolutely necessary. Instead, you
     should access files through normal MS-DOS function requests. There is no
     guarantee of upward compatibility for the Absolute Disk I/O in future
     releases of MS-DOS.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   If CX = -1, DS:BX is the far pointer to the parameter packet. The
   parameter packet API provides access to partitions larger than 32
   megabytes. The parameter packet contains:

           Starting sector number  dd        ?
           Number of sectors       dw        ?
           Transfer address        dd        ?


   Interrupt 25H transfers control to the device driver and reads from the
   disk to the Disk-Transfer Address the number of sectors specified in CX.
   The interrupt has the same requirements as and processes identically to
   Interrupt 26H (Absolute Disk Write), except that it reads data rather
   than writes it. Also, since this interrupt does not check your input
   parameters too closely, make sure they are reasonable. If you use
   unreasonable parameters, you may get strange results or cause your system
   to crash.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     This call destroys all registers except the segment registers. So before
     issuing the interrupt, save any registers that your program uses.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   The system pushes the flags at the time of the call; they are still there
   upon return. To prevent uncontrolled growth, be sure to pop the stack upon
   return.

   If the disk operation is successful, the Carry Flag (CF) is 0. If the disk
   operation is not successful, CF is 1 and AL contains the MS-DOS error code
   (see Interrupt 24H earlier in this section for the codes and their
   meanings).

   Macro Definition:

   abs_disk_read  macro  disk,buffer,num_sectors,first_sector
                  mov    al,disk
                  mov    bx,offset buffer
                  mov    cx,num_sectors
                  mov    dx,first_sector
                  int    25H
                  popf
                  endm

   Example:

   The following program copies the contents of a single-sided disk in drive
   A to the disk in drive B.

   prompt     db   "Source in A, target in B",0DH,0AH
              db   "Any key to start. $"
   first      dw    0
   buffer     db    60 dup (512 dup (?))  ; 60 sectors
   ;
   begin:     display prompt         ; see Function 09H
              read_kbd               ; see Function 08H
              mov     cx,6           ; copy 6 groups of
                                       ; 60 sectors
   copy:      push    cx             ; save the loop counter
              abs_disk_read  0,buffer,60,first  ; THIS INTERRUPT
              abs_disk_write 1,buffer,60,first  ; see INT 26H
              add  first,60          ; do the next 60 sectors
              pop  cx                ; restore the loop counter
              loop copy

   The following code is an example of reading the absolute sector with
   Interrupt 25H.

             mov  al, 'C'-'A'       ; select drive C:
             mov  cx,-1             ; request new absolute format
             mov  bx,code            ; set ds:bx up to point to parameter
             mov  ds,bx              ; packet with sector number, length
             mov  bx,offset par_pck  ; and transfer address information
             int  25H                ; do operation
             jc   error_on_read      ; check for errors

   par_pck:
             dd   12345H             ; absolute sector number to read=12345H
             dw   2                  ; number of sectors to read
             dd   buffer             ; transfer address

   buffer    db   1024 dup (0)       ; target buffer for read


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Absolute Disk Write (Interrupt 26H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AL
     Drive number
   DS:BX
     Disk Transfer Address or
     Far pointer to parameter packet if CX = -1
   CX
     Number of sectors or -1
   DX
     Beginning relative sector

   Return:

   AL
     Error code if CF = 1
   FLAGS
     CF        = 0 if successful
           = 1 if not successful


   Comments:

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Warning
     Avoid using this function unless absolutely necessary. Instead, you
     should access files through normal MS-DOS function requests. There is no
     guarantee of upward compatibility for the Absolute Disk I/O in future
     releases of MS-DOS.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   The registers must contain the following:

   Register           Contents
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   AL                 Drive number (0=A, 1=B, etc.)

   DS:BX              Offset of Disk Transfer Address or far pointer to
                      parameter packet if CX = -1

   CX                 Number of sectors to write or -1

   DX                 Beginning relative sector
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   This interrupt transfers control to MS-DOS. The number of sectors
   specified in CX is written from the Disk Transfer Address to the disk. Its
   requirements and processing are identical to Interrupt 25H (Absolute Disk
   Read), except data is written to the disk rather than read from it. Also,
   since Interrupt 26H does not check your input parameters too closely, make
   sure they are reasonable. If you use unreasonable parameters, you may get
   strange results or cause your system to crash.

   If CX = -1, DS:BX is the far pointer to the parameter packet. The
   parameter packet contains:

           Starting sector number        dd        ?
           Number of sectors        dw        ?
           Transfer address        dd        ?


   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     This call destroys all registers except the segment registers. So before
     issuing the interrupt, be sure to save any registers your program uses.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   The system pushes the flags at the time of the call; they are still there
   upon return. To prevent uncontrolled growth, be sure to pop the stack upon
   return.

   If the disk operation is successful, the Carry Flag (CF) is 0. If the disk
   operation is not successful, CF is 1 and AL contains the MS-DOS error code
   (see Interrupt 24H for the codes and their meanings).

   Macro Definition:

   abs_disk_write  macro  disk,buffer,num_sectors,first_sector
                   mov    al,disk
                   mov    bx,offset buffer
                   mov    cx,num_sectors
                   mov    dx,first_sector
                   int    26H
                   popf
                   endm

   Example:

   The following program copies the contents of a single-sided disk in drive
   A to the disk in drive B, verifying each write. It uses a buffer of 32
   kilobytes.

   off        equ   0
   on         equ   1
   ;
   prompt     db   "Source in A, target in B",0DH,0AH
              db   "Any key to start. $"
   first      dw    0
   buffer     db    60 dup (512 dup (?))  ; 60 sectors
   ;
   begin:     display prompt       ; see Function 09H
              read_kbd             ; see Function 08H
              verify  on           ; see Function 2EH
              mov     cx,6         ; copy 6 groups of 60 sectors
   copy:      push    cx           ; save the loop counter
              abs_disk_read  0,buffer,60,first  ; see INT 25H
              abs_disk_write 1,buffer,60,first  ; THIS INTERRUPT
              add  first,60        ; do the next 60 sectors
              pop  cx              ; restore the loop counter
              loop copy
              verify  off          ; see Function 2EH

   The following code is an example of writing the absolute sector with
   Interrupt 26H.

            mov   al,'C'-'A'        ; select drive C:
            mov   cx,-1             ; request new absolute format
            mov   bx,code            ; set ds:bx up to point to parameter
            mov   ds,bx              ; packet with sector number, length
            mov   bx,offset par_pck  ; and transfer address information
            int   26H                ; do operation
            jc    error_on_write     ; check for errors

   par_pck:
           dd     12345H             ; absolute sector number to write=12345H
           dw     2                  ; number of sectors to write
           dd     buffer             ; transfer address

   buffer  db     1024 dup (0)       ; target buffer for write


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Terminate But Stay Resident (Interrupt 27H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   CS:DX
     Pointer to first byte following
     last byte of code.

   Return:

   None


   Comments:

   This interrupt is provided only for compatibility with MS-DOS versions
   prior to 2.0. Unless your resident program must be compatible with MS-DOS
   versions before 2.0, you should use Function 31H (Keep Process) to
   install it. Function 31H lets programs larger than 64K remain resident
   and allows return information to be passed.

   However, Interrupt 27H, which is often used to install device-specific
   interrupt handlers, forces programs that are up to 64K to remain resident
   after they terminate.

   DX must contain the offset (from the segment address in CS) of the first
   byte that follows the last byte of code in the program. When Interrupt 27H
   is executed, the program terminates and control returns to MS-DOS, but the
   program is not overlaid by other programs. Files left open are not closed.
   When the interrupt is called, CS must contain the segment address of the
   Program Segment Prefix (the value of DS and ES when execution started).
   .Exe programs that are loaded into high memory must not use this
   interrupt. Similarly, since it restores the Interrupt 22H, 23H, and
   24H vectors, you should not use Interrupt 27H to install new CONTROL+C or
   critical-error handlers.

   Macro Definition:

   stay_resident  macro last_instruc
                  mov   dx,offset last_instruc
                  inc   dx
                  int   27H
                  endm

   Example:

   Since the most common use of Interrupt 27H is to install a
   machine-specific routine, there is no general example that applies. The
   macro definition, however, shows the calling syntax.


 1.12  Function Requests

   The following pages describe function calls 00H-68H.


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Terminate Program (Function 00H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 00H
   CS
     Segment address of
     Program Segment Prefix

   Return:

   None


   Comments:

   Function 00H performs the same function as Interrupt 20H. It terminates
   the current process and returns control to its parent process. It also
   closes all open file handles and clears the disk cache. When this
   interrupt is issued, CS must contain the segment address of the Program
   Segment Prefix.

   The CS register must contain the segment address of the Program Segment
   Prefix before you call this interrupt.

   The following exit addresses are restored from the specified offsets in
   the Program Segment Prefix:

   Offset             Exit Address
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0AH                Program terminate
   0EH                CONTROL+C
   12H                Critical error
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   All file buffers are flushed to disk.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Warning
     Close all files that have changed in length before calling this
     function. If you do not close a changed file, its length is not
     correctly recorded in the directory. See Function 10H for a description
     of the Close File system call.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   terminate_program  macro
                      xor    ah,ah
                      int    21H
                      endm

   Example:

   The following program displays a message and returns to MS-DOS. It uses
   only the opening portion of the sample program skeleton shown in Figure
   1.2.

   message db "Displayed by FUNC00H example", 0DH,0AH,"$"
   ;
   begin:  display message    ; see Function 09H
           terminate_program  ; THIS FUNCTION
   code    ends
           end    start


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Read Keyboard and Echo (Function 01H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 01H

   Return:

   AL
     Character typed


   Comments:

   Function 01H waits for a character to be read from standard input, then
   echoes the character to standard output and returns it in AL. If the
   character is CONTROL+C, it executes Interrupt 23H.

   Macro Definition:

   read_kbd_and_echo  macro
                      mov  ah, 01H
                      int  21H
                      endm

   Example:

   The following program displays and prints characters as you type them. If
   you press the ENTER key, the program sends a linefeed/carriage-return
   sequence to both the display and the printer.

   begin:     read_kbd_and_echo         ; THIS FUNCTION
              print_char   al           ; see Function 05H
              cmp          al,0DH       ; is it a CR?
              jne          begin        ; no, print it
              print_char   0AH          ; see Function 05H
              display_char 0AH          ; see Function 02H
              jmp          begin        ; get another character


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Display Character (Function 02H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 02H
   DL
     Character to be displayed

   Return:

   None


   Comments:

   Function 02H sends the character in DL to standard output. If you press
   CONTROL+C, it issues Interrupt 23H.

   Macro Definition:

   display_char macro   character
                mov     dl,character
                mov     ah,02H
                int     21H
                endm

   Example:

   The following program converts lowercase characters to uppercase before
   displaying them.

   begin:     read_kbd                 ; see Function 08H
              cmp     al,"a"
              jl      uppercase        ; don't convert
              cmp     al,"z"
              jg      uppercase        ; don't convert
              sub     al,20H           ; convert to ASCII code
                                       ; for uppercase
   uppercase: display_char al          ; THIS FUNCTION
              jmp     begin:           ; get another character


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Auxiliary Input (Function 03H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 03H

   Return:

   AL
     Character from auxiliary device


   Comments:

   Function 03H waits for a character from standard auxiliary devices (AUX,
   COM1, COM2, COM3, COM4), then returns the character in AL. This system
   call does not return a status or error code.

   If you press CONTROL+C, it issues Interrupt 23H.

   Macro Definition:

   aux_input  macro
              mov  ah,03H
              int  21H
              endm

   Example:

   The following program prints characters as soon as it receives them from
   the auxiliary device. It stops printing when it receives an end-of-file
   character (ASCII 26, or CONTROL+Z).

   begin:     aux_input        ; THIS FUNCTION
              cmp   al,1AH     ; end of file?
              je    return     ; yes, all done
              print_char  al   ; see Function 05H
              jmp   begin      ; get another character


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Auxiliary Output (Function 04H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 04H
   DL
     Character for auxiliary device

   Return:

   None


   Comments:

   Function 04H sends the character in DL to standard auxiliary. This system
   call does not return a status or error code.

   If you press CONTROL+C, it issues Interrupt 23H.

   Macro Definition:

   aux_output  macro  character
               mov  dl,character
               mov  ah,04H
               int  21H
               endm

   Example:

   The following program gets a series of strings of up to 80 bytes from the
   keyboard and sends each string to the auxiliary device. It stops when you
   type a null string (carriage-return only).

   string   db    81 dup(?) ; see Function 0AH
   ;
   begin:   get_string  80,string       ; see Function 0AH
            cmp  string[1],0            ; null string?
            je   return                 ; yes, all done
            mov  cx, word ptr string[1] ; get string length
            mov  bx,0                   ; set index to 0
   send_it: aux_output string[bx+2]     ; THIS FUNCTION
            inc  bx                     ; bump index
            loop  send_it               ; send another character
            jmp  begin                  ; get another string


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Print Character (Function 05H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 05H
   DL
     Character for printer

   Return:

   None


   Comments:

   Function 05H sends the character in DL to the standard printer. If you
   press CONTROL+C, it issues Interrupt 23H. This function does not return a
   status or error code.

   Macro Definition:

   print_char macro character
              mov   dl,character
              mov   ah,05H
              int   21H
              endm

   Example:

   The following program prints a walking test pattern on the printer. It
   stops if you press CONTROL+C.

   line_num    db    0
   ;
   begin:      mov   cx,60        ; print 60 lines
   start_line: mov   bl,33        ; first printable ASCII
                                  ; character (!)
               add   bl,line_num  ; to offset one character
               push  cx           ; save number-of-lines counter
               mov   cx,80        ; loop counter for line
   print_it:   print_char bl      ; THIS FUNCTION
               inc   bl           ; move to next ASCII character
               cmp   bl,126       ; last printable ASCII
                                  ; character (~)
               jl    no_reset     ; not there yet
               mov   bl,33        ; start over with (!)
   no_reset:   loop  print_it     ; print another character
               print_char 0DH     ; carriage return
               print_char 0AH     ; linefeed
               inc   line_num     ; to offset 1st char. of line
               pop   cx           ; restore #-of-lines counter
               loop  start_line   ; print another line


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Direct Console I/O (Function 06H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 06H
   DL
     See text

   Return:

   AL
     If DL = FFH  before call,
     then zero flag not set means AL
     has character from standard input.
     Zero flag set means there was not
     a character to get, and AL = 0.


   Comments:

   The action of Function 06H depends on the value in DL when the function is
   called:

   Value in DL        Action
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   FFH                If a character has been read from standard input, it is
                      returned in AL and the zero flag is cleared (0); if a
                      character has not been read, the zero flag is set (1).

   Not FFH            The character in DL is sent to standard output.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   This function does not check for CONTROL+C.

   Macro Definition:

   dir_console_io  macro switch
                   mov  dl,switch
                   mov  ah,06H
                   int  21H
                   endm

   Example:

   The following program sets the system clock to 0 and displays the time
   continuously. When you type any character, the display freezes; when you
   type any character again, the clock is reset to 0 and the display starts
   again.

   time      db  "00:00:00.00",0DH,0AH,"$"  ; see Function 09H
   ;                                      ; for explanation of $
   ;
   begin:        set_time  0,0,0,0       ; see Function 2DH
   read_clock:   get_time                ; see Function 2CH
                 CONVERT  ch,time        ; see end of chapter
                 CONVERT  cl,time[3]     ; see end of chapter
                 CONVERT  dh,time[6]     ; see end of chapter
                 CONVERT  dl,time[9]     ; see end of chapter
                 display  time           ; see Function 09H
                 dir_console_io  FFH     ; THIS FUNCTION
                 cmp      al,0           ; character typed?
                 jne      stop           ; yes, stop timer
                 jmp      read_clock     ; no, keep timer
                                         ; running
   stop:         read_kbd                ; see Function 08H
                 jmp      begin          ; start over


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Direct Console Input (Function 07H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 07H

   Return:

   AL
     Character from keyboard


   Comments:

   Function 07H waits for a character to be read from standard input, then
   returns it in AL. This function does not echo the character or check for
   CONTROL+C. (For a keyboard input function that echoes or checks for
   CONTROL+C, see Function 01H or 08H.)

   Macro Definition:

   dir_console_input  macro
                      mov  ah,07H
                      int  21H
                      endm

   Example:

   The following program prompts for a password (eight characters maximum)
   and places the characters into a string without echoing them.

   password  db  8 dup(?)
   prompt    db "Password: $"       ; see Function 09H for
                                    ; explanation of $
   begin:    display prompt         ; see Function 09H
             mov  cx,8              ; maximum length of password
             xor  bx,bx             ; so BL can be used as index
   get_pass: dir_console_input      ; THIS FUNCTION
             cmp  al,0DH            ; was it a carriage return?
             je   return            ; yes, all done
             mov  password[bx],al   ; no, put character in string
             inc  bx                ; bump index
             loop get_pass          ; get another character


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Read Keyboard (Function 08H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 08H

   Return:

   AL
     Character from keyboard


   Comments:

   Function 08H waits for a character to be read from standard input, then
   returns it in AL. If you press CONTROL+C, it issues Interrupt 23H. This
   function does not echo the character. (For a keyboard input function that
   echoes the character or checks for CONTROL+C, see Function 01H.)

   Macro Definition:

   read_kbd  macro
             mov   ah,08H
             int   21H
             endm

   Example:

   The following program prompts for a password (eight characters maximum)
   and places the characters into a string without echoing them.

   password  db  8 dup(?)
   prompt    db "Password: $"      ; see Function 09H
                                   ; for explanation of $
   begin:    display prompt        ; see Function 09H
             mov  cx,8             ; maximum length of password
             xor  bx,bx            ; BL can be an index
   get_pass: read_kbd              ; THIS FUNCTION
             cmp  al,0DH           ; was it a carriage return?
             je   return           ; yes, all done
             mov  password[bx],al  ; no, put char. in string
             inc  bx               ; bump index
             loop get_pass         ; get another character


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Display String (Function 09H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 09H
   DS:DX
     Pointer to string to be displayed

   Return:

   None


   Comments:

   Function 09H sends to standard output a string that ends with "$" (the $
   is not displayed).

   The DX register must contain the offset (from the segment address in DS)
   of the string.

   Macro Definition:

   display  macro string
            mov   dx,offset string
            mov   ah,09H
            int   21H
            endm

   Example:

   The following program displays the hexadecimal code of the key that is
   typed.

   table    db     "0123456789ABCDEF"
   result   db     " - 00H",0DH,0AH,"$"  ; see text for
                                         ; explanation of $
   begin:   read_kbd_and_echo            ; see Function 01H
            xor     ah,ah                ; clear upper byte
            convert ax,16,result[3] ; see end of chapter
            display result               ; THIS FUNCTION
            jmp     begin                ; do it again


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Buffered Keyboard Input (Function 0AH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 0AH
   DS:DX
     Pointer to input buffer

   Return:

   None


   Comments:

   Function 0AH gets a string from standard input. DX must contain the offset
   (from the segment address in DS) of an input buffer of the following form:

   Byte               Contents
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  Maximum number of characters in buffer, including the
                      carriage return (you must set this value).

   2                  Actual number of characters typed, not counting the
                      carriage return (the function sets this value).

   3-n                Buffer; must be at least as long as the number in byte
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Characters are read from standard input and placed in the buffer beginning
   at the third byte until an ENTER character (ASCII 0DH) is read. If the
   buffer fills to one less than the maximum, additional characters read are
   ignored and ASCII 07H (Bel) is sent to standard output until an ENTER
   character is read. If you type the string at the console, it can be edited
   as it is being entered. If you press CONTROL+C, it issues Interrupt 23H.

   MS-DOS sets the second byte of the buffer to the number of characters read
   (not counting the carriage return).

   Macro Definition:

   get_string  macro  limit,string
               mov    dx,offset string
               mov    string,limit
               mov    ah,0AH
               int    21H
               endm

   Example:

   The following program gets a 16-byte (maximum) string from the keyboard
   and fills a 24-line by 80-character screen with it.

   buffer           label byte
   max_length       db    ?                ; maximum length
   chars_entered    db    ?                ; number of chars.
   string           db    17 dup (?)       ; 16 chars + CR
   strings_per_line dw    0                ; how many strings
                                           ; fit on line
   crlf             db    0DH,0AH
   ;
   begin:           get_string 17,buffer   ; THIS FUNCTION
                    xor  bx,bx             ; so byte can be
                                           ; used as index
                    mov  bl,chars_entered  ; get string length
                    mov  buffer[bx+2],"$"  ; see Function 09H
                    mov  al,50H            ; columns per line
                    cbw
                    div  chars_entered     ; times string fits
                                           ; on line
                    xor  ah,ah             ; clear remainder
                    mov  strings_per_line,ax ; save col. counter
                    mov  cx,24             ; row counter
   display_screen:  push cx                ; save it
                    mov  cx,strings_per_line ; get col. counter
   display_line:    display  string        ; see Function 09H
                    loop display_line
                    display crlf           ; see Function 09H
                    pop  cx                ; get line counter
                    loop display_screen    ; display 1 more line


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Check Keyboard Status (Function 0BH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 0BH

   Return:

   AL
     00H        = no characters in type-ahead buffer
     FFH        = characters in type-ahead buffer


   Comments:

   Function 0BH checks whether characters are available from standard input
   (if standard input has not been redirected, it checks the type-ahead
   buffer). If characters are available, AL returns FFH; if not, AL returns
   0. If CONTROL+C is in the buffer, it issues Interrupt 23H.

   Macro Definition:

   check_kbd_status  macro
                     mov   ah,0BH
                     int   21H
                     endm

   Example:

   The following program displays the time continuously until you press any
   key:

   time        db       "00:00:00.00",0DH,0AH,"$"
              .
              .
   begin:      get_time                  ; see Function 2CH
               byte_to_dec ch,time       ; see end of chapter
               byte_to_dec cl,time[3]    ; see end of chapter
               byte_to_dec dh,time[6]    ; see end of chapter
               byte_to_dec dl,time[9]    ; see end of chapter
               display time              ; see Function 09H
               check_kbd_status          ; THIS FUNCTION
               cmp     al,0FFH           ; has a key been typed?
               je      return            ; yes, go home
               jmp     begin             ; no, keep displaying
                                         ; time


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Flush Buffer, Read Keyboard (Function 0CH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 0CH
   AL
     1, 6, 7, 8, or 0AH = the
     corresponding function
     is called.
     Any other value = no
     further processing.

   Return:

   AL
     00H = Type-ahead buffer
     was flushed; no other
     processing performed.


   Comments:

   Function 0CH empties the standard input buffer (if standard input has not
   been redirected, Function 0CH empties the type-ahead buffer). Further
   processing depends on the value in AL when the function is called.

   AL                 Action
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1,6,7,8, or 0AH    The corresponding MS-DOS function is executed.
   Any other value    No further processing; AL returns 0.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   flush_and_read_kbd  macro switch
                       mov   al,switch
                       mov   ah,0CH
                       int   21H
                       endm

   Example:

   The following program both displays and prints characters as you type
   them. If you press the ENTER key, the program sends a
   carriage-return/linefeed sequence to both the display and the printer.

   begin:     flush_and_read_kbd 1      ; THIS FUNCTION
              print_char   al           ; see Function 05H
              cmp          al,0DH       ; is it a carriage return?
              jne          begin        ; no, print it
              print_char   0AH          ; see Function 05H
              display_char 0AH          ; see Function 02H
              jmp          begin        ; get another character


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Reset Disk (Function 0DH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 0DH

   Return:

   None


   Comments:

   Function 0DH flushes all file buffers to ensure that the internal buffer
   cache matches the disks in the drives. It writes out buffers that have
   been modified and marks all buffers in the internal cache as free. This
   function request is normally used to force a known state of the system;
   CONTROL+C interrupt handlers should call this function.

   This function does not update directory entries; you must close changed
   files to update their directory entries (see Function 10H, Close File).

   Macro Definition:

   reset_disk macro
              mov   ah,0DH
              int   21H
              endm

   Example:

   The following program flushes all file buffers and selects disk A.

   begin:  reset_disk
           select_disk "A"


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Select Disk (Function 0EH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 0EH
   DL
     Logical drive number
     (0 = A, 1 = B, etc.)

   Return:

   AL
     Number of logical drives


   Comments:

   Function 0EH selects the drive specified in DL (0=A, 1=B, etc.) as the
   current logical drive. AL returns the number of logical drives.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     For future compatibility, treat the value returned in AL with care. For
     example, if AL returns 5, it is not safe to assume that drives A, B, C,
     D, and E are all valid drive designators.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   select_disk macro disk
               mov   dl,disk[-64]
               mov   ah,0EH
               int   21H
               endm

   Example:

   The following program toggles between drive A and drive B to select the
   current drive (in a two-drive system).

   begin:    current_disk       ; see Function 19H
             cmp    al,00H      ; drive A: selected?
             je     select_b    ; yes, select B
             select_disk "A"    ; THIS FUNCTION
             jmp    return
   select_b: select_disk "B"    ; THIS FUNCTION


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Open File (Function 0FH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 0FH
   DS:DX
     Pointer to unopened FCB

   Return:

   AL
     00H        = Directory entry found
     FFH        = No directory entry found


   Comments:

   Function 0FH opens a file. DX must contain the offset (from the segment
   address in DS) of an unopened File Control Block (FCB). This call searches
   the disk directory for the named file.

   If the call finds a directory entry for the file, AL returns 0 and the FCB
   is filled as follows:

   ž  If the drive code was 0 (current drive), it is changed to the actual
      drive used (1=A, 2=B, etc.). This lets you change the current drive
      without interfering with subsequent operations on this file.

   ž  Current Block (offset 0CH) is set to 0.

   ž  Record Size (offset 0EH) is set to the system default of 128.

   ž  File Size (offset 10FH), Date of Last Write (offset 14H), and Time of
      Last Write (offset 16H) are set from the directory entry.

   Before performing a sequential disk operation on the file, you must set
   the Current Record field (offset 20H). Before performing a random disk
   operation on the file, you must set the Relative Record field (offset
   21H). If the default record size (128 bytes) is not correct, set it to the
   correct length.

   If the call doesn't find a directory entry for the file, or if the file
   has the hidden or system attribute, AL returns FFH.

   Macro Definition:

   open  macro fcb
         mov   dx,offset fcb
         mov   ah,0FH
         int   21H
         endm

   Example:

   The following program prints a file named textfile.asc that is on the disk
   in drive B. If a partial record is in the buffer at end-of-file, the
   routine that prints the partial record prints characters until it
   encounters an end-of-file mark (ASCII 26, or CONTROL+Z).

   fcb            db    2,"TEXTFILEASC"
                  db    26 dup (?)
   buffer         db    128 dup (?)
   ;
   begin:         set_dta  buffer       ; see Function 1AH
                  open  fcb             ; THIS FUNCTION
   read_line:     read_seq  fcb         ; see Function 14H
                  cmp   al,02H          ; end of file?
                  je    all_done        ; yes, go home
                  cmp   al,00H          ; more to come?
                  jg    check_more      ; no, check for partial
                                        ; record
                  mov   cx,80H          ; yes, print the buffer
                  xor   si,si           ; set index to 0
   print_it:      print_char buffer[si] ; see Function 05H
                  inc   si              ; bump index
                  loop  print_it        ; print next character
                  jmp   read_line       ; read another record
   check_more:    cmp   al,03H          ; part. record to print?
                  jne   all_done        ; no
                  mov   cx,80H          ; yes, print it
                  xor   si,si           ; set index to 0
   find_eof:      cmp   buffer[si],26   ; end-of-file mark?
                  je    all_done        ; yes
                  print_char buffer[si] ; see Function 05H
                  inc   si              ; bump index to next
                                        ; character
                  loop  find_eof
   all_done:      close fcb             ; see Function 10H


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Close File (Function 10H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 10H
   DS:DX
     Pointer to opened FCB

   Return:

   AL
     00H        = Directory entry found
     FFH        = No directory entry found


   Comments:

   Function 10H closes a file. DX must contain the offset (to the segment
   address in DS) of an opened FCB. This call searches the disk directory for
   the file named in the FCB. If it finds a directory entry for the file, it
   compares the location of the file with the corresponding entries in the
   FCB. The call then updates the directory entry, if necessary, to match the
   FCB, and AL returns 0.

   After you change a file, you must call this function to update the
   directory entry. You should close any FCB (even one for a file that has
   not been changed) when you no longer need access to a file.

   If this call doesn't find a directory entry for the file, AL returns FFH.

   Macro Definition:

   close  macro fcb
          mov   dx,offset fcb
          mov   ah,10H
          int   21H
          endm

   Example:

   The following program checks the first byte of the file named mod1.bas in
   drive B to see if it is FFH and, if it is, prints a message.

   message        db   "Not saved in ASCII format",0DH,0AH,"$"
   fcb            db    2,"MOD1    BAS"
                  db    26  dup (?)
   buffer         db    128 dup (?)
   ;
   begin:         set_dta  buffer       ; see Function 1AH
                  open  fcb             ; see Function 0FH
                  read_seq  fcb         ; see Function 14H

                  cmp   buffer,0FFH     ; is first byte FFH?
                  jne   all_done        ; no
                  display  message      ; see Function 09H
   all_done:      close fcb             ; THIS FUNCTION


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Search for First Entry (Function 11H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 11H
   DS:DX
     Pointer to unopened FCB

   Return:

   AL
     00H        = Directory entry found
     FFH        = No directory entry found


   Comments:

   Function 11H searches the disk directory for the first matching filename.
   DX must contain the offset (from the segment address in DS) of an unopened
   FCB. The filename in the FCB can include wildcard characters. To search
   for hidden or system files, DX must point to the first byte of an extended
   FCB prefix.

   If this call does not find a directory entry for the filename in the FCB,
   AL returns FFH.

   But if the call does find a directory entry for the filename in the FCB,
   AL returns 0 and the call creates an unopened FCB of the same type (normal
   or extended) at the Disk Transfer Address as follows:

   1. If the search FCB was normal, the first byte at the Disk Transfer
      Address is set to the drive number used in the search (1=A, 2=B, etc.)
      and the next 32 bytes contain the directory entry.

   2. If the search FCB was extended, the first byte at the Disk Transfer
      Address is set to FFH, the next 5 bytes are set to 00H, and the
      following byte is set to the value of the attribute byte in the search
      FCB. The remaining 33 bytes are the same as the result of the normal
      FCB (drive number and 32 bytes of directory entry).

   If you use Function 12H (Search for Next Entry) to continue searching for
   matching filenames, you must not alter or open the original FCB at DS:DX.

   The attribute field is the last byte of the extended FCB fields that
   precede the FCB (see Extended FCB in Section 1.9.1). If the attribute
   field is zero, Function 11H searches only normal file entries. It does not
   search directory entries for hidden files, system files, volume label, and
   subdirectories.

   If the attribute field is hidden file, system file, or subdirectory entry
   (02H, 04H, or 10H), or any combination of those values, this call also
   searches all normal file entries. To search all directory entries except
   the volume label, set the attribute byte to 16H (hidden file and system
   file and subdirectory entry).

   If the attribute field is Volume ID (08H), the call searches only the
   volume label entry.

   Macro Definition:

   search_first  macro fcb
                 mov   dx,offset fcb
                 mov   ah,11H
                 int   21H
                 endm

   Example:

   The following program verifies the existence of a file named report.asm on
   the disk in drive B.

   yes        db   "FILE EXISTS.$"
   no         db   "FILE DOES NOT EXIST.$"
   crlf       db    0DH,0AH,"$"
   fcb        db    2,"REPORT  *ASM"
              db    26 dup (?)
   buffer     db    128 dup (?)
   ;
   begin:     set_dta  buffer           ; see Function 1AH
              search_first fcb          ; THIS FUNCTION
              cmp      al,0FFH          ; directory entry found?
              je       not_there        ; no
              display  yes              ; see Function 09H
              jmp      continue
   not_there: display  no               ; see Function 09H
   continue:  display  crlf             ; see Function 09H


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Search for Next Entry (Function 12H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 12H
   DS:DX
     Pointer to unopened FCB

   Return:

   AL
     00H        = Directory entry found
     FFH        = No directory entry found


   Comments:

   After you use Function 11H (Search for First Entry), you can use Function
   12H to find any additional directory entries that match a filename
   (containing wildcard characters). Function 12H searches the disk directory
   for the next matching name. DX must contain the offset (from the segment
   address in DS) of an FCB specified in a previous call to Function 11H. To
   search for hidden or system files, DX must point to the first byte of an
   extended FCB prefixÄÄone that includes the appropriate attribute value.

   If the call does not find a directory entry for the filename in the FCB,
   AL returns FFH.

   But if the call does find a directory entry for the filename in the FCB,
   AL returns 0 and the call creates an unopened FCB of the same type (normal
   or extended) at the Disk Transfer Address (see Function 11H for a
   description of how the unopened FCB is formed).

   Macro Definition:

   search_next  macro fcb
                mov   dx,offset fcb
                mov   ah,12H
                int   21H
                endm

   Example:

   The following program displays the number of files on the disk in drive B.


   message     db   "No files",0DH,0AH,"$"
   files       db    0
   fcb         db    2,"???????????"
               db    26  dup (?)
   buffer      db    128 dup (?)
   ;
   begin:      set_dta  buffer         ; see Function 1AH
               search_first  fcb       ; see Function 11H
               cmp  al,0FFH            ; directory entry found?
               je   all_done           ; no, no files on disk
               inc  files              ; yes, increment file
                                       ; counter
   search_dir: search_next  fcb        ; THIS FUNCTION
               cmp  al,0FFH            ; directory entry found?
               je   done               ; no
               inc  files              ; yes, increment file
                                       ; counter
               jmp  search_dir         ; check again
   done:       convert files,10,message ; see end of chapter
   all_done:   display  message        ; see Function 09H


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Delete File (Function 13H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 13H
   DS:DX
     Pointer to unopened FCB

   Return:

   AL
    00H        = Directory entry found
    FFH        = No directory entry found


   Comments:

   Function 13H deletes a file. DX must contain the offset (from the segment
   address in DS) of an unopened FCB. This call searches the directory for a
   matching filename. The filename in the FCB can contain wildcard
   characters.

   If the call does not find a matching directory entry, AL returns FFH.

   But if the call does find a matching directory entry, AL returns 0 and the
   call deletes the entry from the directory. If the filename contains a
   wildcard character, the call will delete all files that match.

   Do not delete open files.

   Macro Definition:

   delete  macro  fcb
           mov    dx,offset fcb
           mov    ah,13H
           int    21H
           endm

   Example:

   The following program deletes each file on the disk in drive B that was
   last written before December 31, 1982.

   year           dw    1982
   month          db    12
   day            db    31
   files          db    0
   message        db   "No files deleted.",0DH,0AH,"$"
   fcb            db    2,"???????????"
                  db    26 dup  (?)
   buffer         db    128 dup (?)
   ;
   begin:         set_dta  buffer      ; see Function 1AH
                  search_first fcb     ; see Function 11H
                  cmp   al,0FFH        ; directory entry found?
                  jne   compare        ; yes
                  jmp   all_done       ; no, no files on disk
   compare:       convert_date buffer  ; see end of chapter
                  cmp  cx,year         ; next several lines
                  jg   next            ; check date in directory
                  cmp  dl,month        ; entry against date
                  jg   next            ; above & check next file
                  cmp  dh,day          ; if date in directory
                  jge  next            ; entry isn't earlier.
                  delete  buffer       ; THIS FUNCTION
                  inc  files           ; bump deleted-files
                                       ; counter
   next:          search_next fcb      ; see Function 12H
                  cmp  al,00H          ; directory entry found?
                  je   compare         ; yes, check date
                  cmp  files,0         ; any files deleted?
                  je   all_done        ; no, display No files
                                       ; message.
                  convert files,10,message ; see end of chapter
   all_done:      display message      ; see Function 09H


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Sequential Read (Function 14H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 14H
   DS:DX
     Pointer to opened FCB

   Return:

   AL
     00H = Read completed successfully
     01H = EOF
     02H = DTA too small
     03H = EOF, partial record


   Comments:

   Function 14H reads a record from a specified file. DX must contain the
   offset (from the segment address in DS) of an opened FCB. This call loads
   the record pointed to by the Current Block field (offset 0CH) and Current
   Record (offset 20H) field at the Disk Transfer Address, then increments
   the Current Block and Current Record fields.

   The length of the record is taken from the Record Size field (offset 0EH)
   of the FCB.

   AL returns a code that describes the processing:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0                  Read completed successfully

   1                  End-of-file; no data in the record

   2                  Not enough room at the Disk Transfer Address to read
                      one record; read canceled

   3                  End-of-file; a partial record was read and padded to
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   read_seq  macro fcb
             mov   dx,offset fcb
             mov   ah,14H
             int   21H
             endm

   Example:

   The following program displays a file named textfile.asc that is on the
   disk in drive B; its function is similar to the MS-DOS type command. If a
   partial record is in the buffer at end-of-file, the routine that displays
   the partial record displays characters until it encounters an end-of-file
   mark (ASCII 26, or CONTROL+Z).

   fcb            db    2,"TEXTFILEASC"
                  db    26  dup (?)
   buffer         db    128 dup (?),"$"
   ;
   begin:         set_dta  buffer    ; see Function 1AH
                  open  fcb          ; see Function 0FH
   read_line:     read_seq  fcb      ; THIS FUNCTION
                  cmp   al,02H       ; DTA too small?
                  je    all_done     ; yes
                  cmp   al,00H       ; end-of-file?
                  jg    check_more   ; yes
                  display  buffer    ; see Function 09H
                  jmp   read_line    ; get another record
   check_more:    cmp   al,03H       ; partial record in buffer?
                  jne   all_done     ; no, go home
                  xor   si,si        ; set index to 0
   find_eof:      cmp   buffer[si],26 ; is character EOF?
                  je    all_done     ; yes, no more to display
                  display_char buffer[si]  ; see Function 02H
                  inc   si           ; bump index
                  jmp   find_eof     ; check next character
   all_done:      close fcb          ; see Function 10H


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Sequential Write (Function 15H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 15H
   DS:DX
     Pointer to opened FCB

   Return:

   AL
     00H = Write completed successfully
     01H = Disk full
     02H = DTA too small


   Comments:

   Function 15H writes a record to a specified file. DX must contain the
   offset (from the segment address in DS) of an opened FCB. This call writes
   the record pointed to by the Current Block field (offset 0CH) and Current
   Record field (offset 20H) at the Disk Transfer Address, then increments
   the Current Block and Current Record fields.

   The record size is taken from the value of the Record Size field (offset
   0EH) of the FCB. If the record size is less than a sector, the call writes
   the data at the Disk Transfer Address to an MS-DOS buffer; MS-DOS writes
   the buffer to disk when it contains a full sector of data, when the file
   is closed, or when Function 0DH (Reset Disk) is issued.

   AL returns a code that describes the processing:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0                  Write completed successfully

   1                  Disk full; write canceled

   2                  Not enough room at the Disk Transfer Address to write
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   write_seq  macro fcb
              mov   dx,offset fcb
              mov   ah,15H
              int   21H
              endm


   Example:

   The following program creates a file named dir.tmp on the disk in drive B
   containing the disk number (0=A, 1=B, etc.) and filename from each
   directory entry on the disk.

   record_size    equ   0EH           ; offset of Record Size
   ;                                   field in FCB
   fcb1           db    2,"DIR     TMP"
                  db    26 dup (?)
   fcb2           db    2,"???????????"
                  db    26 dup (?)
   buffer         db    128 dup (?)
   ;
   begin:      set_dta      buffer     ; see Function 1AH
               search_first fcb2       ; see Function 11H
               cmp          al,0FFH    ; directory entry found?
               je           all_done   ; no, no files on disk
               create       fcb1       ; see Function 16H
               mov          fcb1[record_size],12
                                       ; set record size to 12
   write_it:   write_seq    fcb1       ; THIS FUNCTION
               cmp          al,0       ; write successful?
               jne          all_done   ; no, go home
               search_next  fcb2       ; see Function 12H
               cmp          al,FFH     ; directory entry found?
               je           all_done   ; no, go home
               jmp          write_it   ; yes, write the record
   all_done:   close        fcb1       ; see Function 10H


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Create File (Function 16H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 16H
   DS:DX
     Pointer to unopened FCB

   Return:

   AL
     00H        = Empty directory found
     FFH        = No empty directory available


   Comments:

   Function 16H creates a file. DX must contain the offset (from the segment
   address in DS) of an unopened FCB. MS-DOS searches the directory for an
   entry that matches the specified filename or, if there is no matching
   entry, an empty entry.

   If MS-DOS finds a matching entry, it opens the file and sets the length to
   zero (in other words, if you try to create a file that already exists,
   MS-DOS erases it and creates a new, empty file). If MS-DOS doesn't find a
   matching entry but does find an empty directory entry, it opens the file
   and sets its length to zero. In either case, the call creates the file,
   and AL returns 0. If MS-DOS doesn't find a matching entry and there is no
   empty entry, the call doesn't create the file, and AL returns FFH.

   You can assign an attribute to the file by using an extended FCB with the
   attribute byte set to the appropriate value (see "Extended FCB" in Section
   1.9.1).

   Macro Definition:

   create  macro fcb
           mov   dx,offset fcb
           mov   ah,16H
           int   21H
           endm

   Example:

   The following program creates a file named dir.tmp on the disk in drive B
   containing the disk number (0 = A, 1 = B, etc.) and filename from each
   directory entry on the disk.

   record_size    equ   0EH           ; offset of Record Size
   ;                                   field of FCB
   fcb1           db    2,"DIR     TMP"
                  db    26  dup (?)
   fcb2           db    2,"???????????"
                  db    26  dup (?)
   buffer         db    128 dup (?)
   ;
   begin:         set_dta   buffer     ; see Function 1AH
                  search_first  fcb2   ; see Function 11H
                  cmp       al,0FFH    ; directory entry found?
                  je        all_done   ; no, no files on disk
                  create    fcb1       ; THIS FUNCTION
                  mov       fcb1[record_size],12
                                       ; set record size to 12
   write_it:      write_seq fcb1       ; see Function 15H
                  cmp       al,0       ; write successful
                  jne       all_done   ; no, go home
                  search_next  fcb2    ; see Function 12H
                  cmp       al,FFH     ; directory entry found?
                  je        all_done   ; no, go home
                  jmp       write_it   ; yes, write the record
   all_done:      close     fcb1       ; see Function 10H


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Rename File (Function 17H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 17H
   DS:DX
     Pointer to modified FCB in the following
     nonstandard format:


      Byte(s)           Contents
      ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
      00H               Drive number
      01H-08H           Old filename (padded with blanks, if necessary)
      09H-0BH           Old file extension (padded with blanks, if necessary)
      0CH-10H           Zeroed out
      11H-18H           New filename (padded with blanks, if necessary)
      19H-1BH           New file extension (padded with blanks, if necessary)
      11CH-24H          Zeroed out
      ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Return:

   AL
     00H        =        Directory entry found
     FFH        =        No directory entry found
                   or destination already exists


   Comments:

   Function 17H changes the name of an existing file. DX must contain the
   offset (from the segment address in DS) of an FCB with the drive number
   and filename filled in, followed by a second filename at offset 11H. DOS
   searches the disk directory for an entry that matches the first filename.
   This filename can contain wildcard characters.

   If MS-DOS finds a matching directory entry and there is no directory entry
   that matches the second filename, it changes the filename in the directory
   entry to match the second filename in the modified FCB. AL then returns
   zero. If the second filename does contain a wildcard character, this call
   does not change the corresponding characters in the filename of the
   directory entry. You cannot use this function request to rename a hidden
   file, a system file, or a subdirectory. If MS-DOS does not find a matching
   directory entry or if it finds an entry for the second filename, AL
   returns FFH.

   Macro Definition:

   rename macro fcb,newname
          mov   dx,offset fcb
          mov   ah,17H
          int   21H
          endm

   Example:

   The following program prompts for the name of a file and a new name; it
   then renames the file.

   fcb               db    37 dup (?)
   prompt1           db   "Filename: $"
   prompt2           db   "New name: $"
   reply             db    15 dup(?)
   crlf              db    0DH,0AH,"$"
   ;
   begin:            display  prompt1       ; see Function 09H
                     get_string  15,reply   ; see Function 0AH
                     display  crlf          ; see Function 09H
                     parse    reply[2],fcb  ; see Function 29H
                     display  prompt2       ; see Function 09H
                     get_string  15,reply   ; see Function 0AH
                     display  crlf          ; see Function 09H
                     parse    reply[2],fcb[16]
                                            ; see Function 29H
                     rename   fcb           ; THIS FUNCTION


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get Current Disk (Function 19H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 19H

   Return:

   AL
     Currently selected drive
     (0 = A, 1 = B, etc.)


   Comments:

   Function 19H returns the current drive in AL (0=A, 1=B, etc.).

   Macro Definition:

   current_disk  macro
                 mov   ah,19H
                 int   21H
                 endm

   Example:

   The following program displays the default drive in a two-drive system.

   message    db  "Current disk is $"
   crlf       db   0DH,OAH,"$"
   ;
   begin:     display  message         ; see Function 09H
              current_disk             ; THIS FUNCTION
              cmp      al,00H          ; is it disk A?
              jne      disk_b          ; no, it's disk B:
              display_char "A"         ; see Function 02H
              jmp      all_done
   disk_b:    display_char "B"         ; see Function 02H
   all_done:  display  crlf            ; see Function 09H


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Set Disk Transfer Address (Function 1AH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 1AH
   DS:DX
    Disk Transfer Address

   Return:

   None


   Comments:

   Function 1AH sets the Disk Transfer Address. DX must contain the offset
   (from the segment address in DS) of the Disk Transfer Address. Disk
   transfers cannot wrap around from the end of the segment to the beginning,
   nor can they overflow into another segment.

   If you do not set the Disk Transfer Address, MS-DOS defaults to offset 80H
   in the Program Segment Prefix. You can check the current Disk Transfer
   Address with Function 2FH (Get Disk Transfer Address).

   Macro Definition:

   set_dta  macro  buffer
            mov    dx,offset buffer
            mov    ah,1AH
            int    21H
            endm

   Example:

   The following program prompts for a letter, converts it to its alphabetic
   sequence (A=1, B=2, etc.), then reads and displays the corresponding
   record from a file named alphabet.dat that is on the disk in drive B. The
   file contains 26 records, each 28 bytes long.

   record_size     equ   0EH      ; offset of Record Size
                                  ; field of FCB
   relative_record equ   21H      ; offset of Relative Record
   ;                               field of FCB
   fcb           db    2,"ALPHABETDAT"
                 db    26  dup (?)
   buffer        db    28 dup(?),"$"
   prompt        db   "Enter letter: $"
   crlf          db    0DH,0AH,"$"
   ;
   begin:        set_dta  buffer       ; THIS FUNCTION
                 open     fcb          ; see Function 0FH
                 mov      fcb[record_size],28 ; set record size
   get_char:     display  prompt       ; see Function 09H
                 read_kbd_and_echo     ; see Function 01H
                 cmp      al,0DH       ; just a CR?
                 je       all_done     ; yes, go home
                 sub      al,41H       ; convert ASCII
                                       ; code to record #
                 mov      fcb[relative_record],al
                                       ; set relative record
                 display  crlf         ; see Function 09H
                 read_ran fcb          ; see Function 21H
                 display  buffer       ; see Function 09H
                 display  crlf         ; see Function 09H
                 jmp      get_char     ; get another character
   all_done:     close    fcb          ; see Function 10H


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get Default Drive Data (Function 1BH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 1BH

   Return:

   AL
      Sectors per cluster
   CX
      Bytes per sector
   DX
      Clusters per drive
   DS:BX
      Pointer to FAT ID byte


   Comments:

   Function 1BH retrieves data about the disk in the default drive. The data
   returns in the following registers:

   Register           Contents
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   AL                 Number of sectors in a cluster (allocation unit)
   CX                 Number of bytes in a sector
   DX                 Number of clusters on the disk
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   BX returns the offset (to the segment address in DS) of the first byte of
   the File Allocation Table (FAT), which identifies the type of disk in the
   drive:

   Value       Type of Drive
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   FF          Double-sided disk, 8 sectors per track, 40 tracks per side
   FE          Single-sided disk, 8 sectors per track, 40 tracks per side
   FD          Double-sided disk, 9 sectors per track, 40 tracks per side
   FC          Single-sided disk, 9 sectors per track, 40 tracks per side
   F9          Double-sided disk, 15 sectors per track, 40 tracks per side
   F9          Double-sided disk, 9 sectors per track, 80 tracks per side
   F8          Fixed disk
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   This call is similar to Function 36H (Get Disk Free Space), except that
   it returns the address of the FAT ID byte in BX instead of the number of
   available clusters. It is also similar to Function 1CH (Get Drive Data),
   except that it returns data on the disk in the default drive instead of on
   the disk in a specified drive. For a description of how MS-DOS stores data
   on a disk, including a description of the File Allocation Table, see
   Chapter 3, "MS-DOS Technical Information."

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Warning
     The FAT ID byte is no longer adequate to identify the type of drive
     being used. See Chapter 2, "MS-DOS Device Drivers," for more details.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   def_drive_data  macro
                   push   ds
                   mov    ah,1BH
                   int    21H
                   mov    al,byte ptr[bx]
                   pop    ds
                   endm

   Example:

   The following program displays a message that tells whether the default
   drive is a floppy disk or a hard disk drive.

   stdout      equ         1
   ;
   msg         db          "Default drive is "
   dskt        db          "disk."
   fixed       db          "fixed."
   crlf        db          ODH,OAH
   ;
   begin:      write_handle stdout,msg,17      ; display message
               jc           write_error        ; routine not shown
               def_drive_data                  ; THIS FUNCTION
               cmp          byte ptr [bx],0F8H ; check FAT ID byte
               jne          disk           ; it's a disk
               write_handle stdout,fixed,6     ; see Function 40H
               jc           write_error        ; see Function 40H
               jmp short    all_done           ; clean up & go home
   disk:   write_handle stdout,dskt,9      ; see Function 40H
   all_done:   write_handle stdout,crlf,2      ; see Function 40H
               jc           write_error        ; routine not shown


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get Drive Data (Function 1CH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 1CH
   DL
      Drive (0=default, 1=A, etc.)


   Return:

   AL
      0FFH if drive number is invalid;
      otherwise, sectors per cluster
   CX
      Bytes per sector
   DX
      Clusters per drive
   DS:BX
      Pointer to FAT ID byte




   Comments:

   Function 1CH retrieves data about the disk in the specified drive. DL must
   contain the drive number (0=default, 1=A, etc.). The data returns in the
   following registers:

   Register           Contents
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   AL                 Number of sectors in a cluster (allocation unit)
   CX                 Number of bytes in a sector
   DX                 Number of clusters on the disk
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   BX returns the offset (to the segment address in DS) of the first byte of
   the File Allocation Table (FAT), which identifies the type of disk in the
   drive:

   Value       Type of Drive
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   FF          Double-sided disk, 8 sectors per track, 40 tracks per side
   FE          Single-sided disk, 8 sectors per track, 40 tracks per side
   FD          Double-sided disk, 9 sectors per track, 40 tracks per side
   FC          Single-sided disk, 9 sectors per track, 40 tracks per side
   F9          Double-sided disk, 15 sectors per track, 40 tracks per side
   F9          Double-sided disk, 9 sectors per track, 80 tracks per side
   F8          Fixed disk
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   If the drive number in DL is invalid, AL returns 0FFH.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Warning
     The FAT ID byte is no longer adequate to identify the type of drive
     being used. See Chapter 2, "MS-DOS Device Drivers," for more details.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   This call is similar to Function 36H (Get Disk Free Space), except that
   it returns the address of the FAT ID byte in BX instead of the number of
   available clusters. It is also similar to Function 1BH (Get Default Drive
   Data), except that it returns data on the disk in the drive specified in
   DL instead of the disk in the default drive. For a description of how
   MS-DOS stores data on a disk, including a description of the File
   Allocation Table, see Chapter 3, "MS-DOS Technical Information."

   Macro Definition:

   drive_data  macro  drive
               push   ds
               mov    dl,drive
               mov    ah,1BH
               int    21H
               mov    al, byte ptr[bx]
               pop    ds
               endm

   Example:

   The following program displays a message that tells whether drive B is a
   floppy disk or a hard disk drive.

   stdout      equ          1
   :
   msg         db           "Drive B is "
   dskt        db           "disk."
   fixed       db           "fixed."
   crlf        db           ODH,OAH
   ;
   begin:      write_handle stdout,msg,11      ; display message
               jc           write_error        ; routine not shown
               drive_data   2                  ; THIS FUNCTION
               cmp          byte ptr [bx],0F8H ; check FAT ID byte
               jne          disk           ; it's a disk
               write_handle stdout,fixed,6     ; see Function 40H
               jc           write_error        ; routine not shown
               jmp          all_done           ; clean up & go home
   disk:   write_handle stdout,dskt,9      ; see Function 40H
   all_done:   write_handle stdout,crlf,2      ; see Function 40H
               jc           write_error        ; routine not shown


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Random Read (Function 21H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 21H
   DS:DX
     Pointer to opened FCB

   Return:

   AL
     0 = Read completed successfully
     1 = End of file, record empty
     2 = DTA too small
     3 = End of file, partial record


   Comments:

   Function 21H reads (into the Disk Transfer Address) the record pointed to
   by the Relative Record field (offset 21H) of the FCB. DX must contain the
   offset (from the segment address in DS) of an opened FCB. The Current
   Block field (offset 0CH) and Current Record field (offset 20H) are set to
   agree with the Relative Record field (offset 21H). The record is then
   loaded at the Disk Transfer Address. The record length is taken from the
   Record Size field (offset 0EH) of the FCB.

   AL returns a code that describes the processing:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0                  Read completed successfully

   1                  End-of-file; no data in the record

   2                  Not enough room at the Disk Transfer Address to read
                      one record; read canceled

   3                  End-of-file; a partial record was read and padded to
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   read_ran  macro  fcb
             mov    dx,offset fcb
             mov    ah,21H
             int    21H
             endm

   Example:

   The following program prompts for a letter, converts it to its alphabetic
   sequence (A = 1, B = 2, etc.), then reads and displays the corresponding
   record from a file named alphabet.dat that is on the disk in drive B. The
   file contains 26 records, each 28 bytes long.

   record_size     equ   0EH      ; offset of Record Size
                                  ; field of FCB
   relative_record equ   21H      ; offset of Relative Record
   ;                               field of FCB
   fcb           db    2,"ALPHABETDAT"
                 db    26  dup (?)
   buffer        db    28 dup(?),"$"
   prompt        db   "Enter letter: $"
   crlf          db    0DH,0AH,"$"
   ;
   begin:        set_dta  buffer            ; see Function 1AH
                 open     fcb               ; see Function 0FH
                 mov      fcb[record_size],28 ; set record size
   get_char:     display  prompt            ; see Function 09H
                 read_kbd_and_echo          ; see Function 01H
                 cmp      al,0DH            ; just a CR?
                 je       all_done          ; yes, go home
                 sub      al,41H            ; convert ASCII code
                                            ; to record #
                 mov      fcb[relative_record],al ; set relative
                                            ; record
                 display  crlf              ; see Function 09H
                 read_ran fcb               ; THIS FUNCTION
                 display  buffer            ; see Function 09H
                 display  crlf              ; see Function 09H
                 jmp      get_char          ; get another char.
   all_done:     close    fcb               ; see Function 10H


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Random Write (Function 22H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 22H
   DS:DX
     Pointer to opened FCB

   Return:

   AL
     00H = Write completed successfully
     01H = Disk full
     02H = DTA too small


   Comments:

   Function 22H writes (from the Disk Transfer Address) the record pointed to
   by the Relative Record field (offset 21H) of the FCB. DX must contain the
   offset from the segment address in DS of an opened FCB. The Current Block
   (offset 0CH) and Current Record (offset 20H) fields are set to agree with
   the Relative Record field (offset 21H). This record is then written from
   the Disk Transfer Address.

   The record length is taken from the Record Size field (offset 0EH) of the
   FCB. If the record size is less than a sector, the data at the Disk
   Transfer Address is written to a buffer. The buffer is written to a disk
   when it contains a full sector of data, or when a program closes the file,
   or when it issues Function 0DH (Reset Disk).

   AL returns a code that describes the processing:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0                  Write completed successfully

   1                  Disk is full

   2                  Not enough room at the Disk Transfer Address to write
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   write_ran  macro  fcb
              mov    dx,offset fcb
              mov    ah,22H
              int    21H
              endm

   Example:

   The following program prompts for a letter, converts it to its alphabetic
   sequence (A = 1, B = 2, etc.), then reads and displays the corresponding
   record from a file named alphabet.dat that is on the disk in drive B.
   After displaying the record, it prompts you to enter a changed record. If
   you type a new record, it is written to the file, but if you just press
   the ENTER key, the record is not replaced. The file contains 26 records,
   each 28 bytes long.

   record_size     equ   0EH      ; offset of Record Size
                                  ; field of FCB
   relative_record equ   21H      ; offset of Relative Record
   ;                               field of FCB
   fcb        db    2,"ALPHABETDAT"
              db    26  dup (?)
   buffer     db    28 dup(?),0DH,0AH,"$"
   prompt1    db   "Enter letter: $"
   prompt2    db   "New record (ENTER for no change): $"
   crlf       db    0DH,0AH,"$"
   reply      db    28 dup (32)
   blanks     db    26 dup (32)
   ;

   begin:     set_dta  buffer            ; see Function 1AH
              open     fcb               ; see Function 0FH
              mov      fcb[record_size],28 ; set record size
   get_char:  display  prompt1           ; see Function 09H
              read_kbd_and_echo          ; see Function 01H
              cmp      al,0DH            ; just a carriage return?
              je       all_done          ; yes, go home
              sub      al,41H            ; convert ASCII
                                         ; code to record #
              mov      fcb[relative_record],al
                                         ; set relative record
              display  crlf              ; see Function 09H
              read_ran fcb               ; THIS FUNCTION
              display  buffer            ; see Function 09H
              display  crlf              ; see Function 09H
              display  prompt2           ; see Function 09H
              get_string 27,reply        ; see Function 0AH
              display  crlf              ; see Function 09H
              cmp      reply[1],0        ; was anything typed
                                         ; besides CR?
              je       get_char          ; no
                                         ; get another char.
              xor      bx,bx             ; to load a byte
              mov      bl,reply[1]       ; use reply length as
                                         ; counter
              move_string blanks,buffer,26 ; see chapter end
              move_string reply[2],buffer,bx ; see chapter end
              write_ran fcb              ; THIS FUNCTION
              jmp      get_char          ; get another character
   all_done:  close    fcb               ; see Function 10H


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get File Size (Function 23H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 23H
   DS:DX
     Pointer to unopened FCB

   Return:

   AL
     00H = Directory entry found
     FFH = No directory entry found


   Comments:

   Function 23H returns the size of a specified file. DX must contain the
   offset (from the segment address in DS) of an unopened FCB.

   If there is a directory entry that matches the specified file, MS-DOS
   divides the File Size field (offset 10H) of the directory entry by the
   Record Size field (offset 0EH) of the FCB, puts the result in the Relative
   Record field (offset 21H) of the FCB, and returns 0 in AL.

   You must set the Record Size field of the FCB to the correct value before
   calling this function. If the Record Size field is not an even divisor of
   the File Size field, the value set in the Relative Record field is rounded
   up, yielding a value larger than the actual number of records.

   If this call does not find a matching directory, AL returns FFH.

   Macro Definition:

   file_size  macro  fcb
              mov    dx,offset fcb
              mov    ah,23H
              int    21H
              endm

   Example:

   The following program prompts for the name of a file, opens the file to
   fill in the Record Size field of the FCB, issues a File Size system call,
   and displays the record length and number of records.

   fcb           db      37 dup  (?)
   prompt        db     "File name: $"
   msg1          db     "Record length:     ",0DH,0AH,"$"
   msg2          db     "Records:      ",0DH,0AH,"$"
   crlf          db      0DH,0AH,"$"
   reply         db      17 dup(?)
   ;
   begin:        display prompt            ; see Function 09H
                 get_string 17,reply       ; see Function 0AH
                 cmp     reply[1],0        ; just a CR?
                 jne     get_length        ; no, keep going
                 jmp     all_done          ; yes, go home
   get_length:   display crlf              ; see Function 09H
                 parse   reply[2],fcb      ; see Function 29H
                 open    fcb               ; see Function 0FH
                 file_size fcb             ; THIS FUNCTION
                 mov     ax,word ptr fcb[33] ; get record length
                 convert ax,10,msg2[9]     ; see end of chapter
                 mov     ax,word ptr fcb[14] ;  get record number
                 convert ax,10,msg1[15]    ; see end of chapter
                 display msg1              ; see Function 09H
                 display msg2              ; see Function 09H
   all_done:     close   fcb               ; see Function 10H


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Set Relative Record (Function 24H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 24H
   DS:DX
     Pointer to opened FCB

   Return:

   None
   AL=00H
    Relative Record field is modified in FCB.


   Comments:

   Function 24H sets the Relative Record field (offset 21H) to the file
   address specified by the Current Block field (offset 0CH) and Current
   Record field (offset 20H). DX must contain the offset (from the segment
   address in DS) of an opened FCB. You use this call to set the file pointer
   before a Random Read or Write (Functions 21H, 22H, 27H, or 28H).

   Macro Definition:

   set_relative_record  macro  fcb
                        mov    dx,offset fcb
                        mov    ah,24H
                        int    21H
                        endm

   Example:

   The following program copies a file using the Random Block Read and Random
   Block Write system calls. It speeds the copy by setting the record length
   equal to the file size and the record count to 1, and by using a buffer of
   32 kilobytes. It positions the file pointer by setting the Current Record
   field (offset 20H) to 1 and using Function 24H (Set Relative Record) to
   make the Relative Record field (offset 21H) point to the same record that
   the combination of the Current Block field (offset 0CH) and Current Record
   field (offset 20H) points to.

   current_record  equ   20H        ; offset of Current Record
                                    ; field of FCB
   fil_size        equ   10H        ; offset of File Size
   ;                                 field of FCB
   fcb       db      37 dup (?)
   filename  db      17 dup(?)
   prompt1   db     "File to copy: $"  ; see Function 09H for
   prompt2   db     "Name of copy: $"  ; explanation of $
   crlf      db      0DH,0AH,"$"
   file_length  dw   ?
   buffer    db      32767 dup(?)
   ;
   begin:    set_dta  buffer              ; see Function 1AH
             display  prompt1             ; see Function 09H
             get_string  15,filename      ; see Function 0AH
             display  crlf                ; see Function 09H
             parse    filename[2],fcb     ; see Function 29H
             open     fcb                 ; see Function 0FH
             mov      fcb[current_record],0 ; set Current Record
                                          ; field
             set_relative_record  fcb     ; THIS FUNCTION
             mov      ax,word ptr fcb[fil_size] ; get file size
             mov      file_length,ax      ; save it for
                                          ; ran_block_write
             ran_block_read  fcb,1,ax     ; see Function 27H
             display  prompt2             ; see Function 09H
             get_string  15,filename      ; see Function 0AH
             display  crlf                ; see Function 09H
             parse    filename[2],fcb     ; see Function 29H
             create   fcb                 ; see Function 16H
             mov      fcb[current_record],0 ; set Current Record
                                          ; field
             set_relative_record  fcb     ; THIS FUNCTION
             mov      ax,file_length      ; get original file
             ran_block_write  fcb,1,ax    ; see Function 28H
             close    fcb                 ; see Function 10H


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Set Interrupt Vector (Function 25H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 25H
   AL
     Interrupt number
   DS:DX
     Pointer to interrupt-handling
     routine

   Return:

   None


   Comments:

   Function 25H sets the address in the interrupt vector table for the
   specified interrupt.

   AL must contain the number of the interrupt. DX must contain the offset
   (to the segment address in DS) of the interrupt-handling routine.

   To avoid compatibility problems, programs should never set an interrupt
   vector directly and should never use Interrupt 25H to read directly from
   memory. To get a vector, use Function 35H (Get Interrupt Vector), and to
   set a vector, use Function 25H, unless your program must be compatible
   with MS-DOS versions earlier than 2.0.

   Macro Definition:

   set_vector  macro  interrupt,handler_start
               mov    al,interrupt
               mov    dx,offset handler_start
               mov    ah,25H
               endm

   Example:

   Because interrupts tend to be machine-specific, no example is shown.


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Create New PSP (Function 26H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 26H
   DX
     Segment address of new PSP

   Return:

   None


   Comments:

   This function request has been superseded. Use Function 4B00H or 4B03H
   (Load and Execute Program or Overlay) to run a child process, unless your
   program must be compatible with MS-DOS versions earlier than 2.0.

   Function 26H creates a new Program Segment Prefix. DX must contain the
   segment address where the new PSP is to be created.

   Macro Definition:

   create_psp  macro  seg_addr
               mov    dx,seg_addr
               mov    ah,26H
               endm

   Example:

   Because Functions 4B00H (Load and Execute Program) and 4B03H (Load
   Overlay) have superseded this function request, no example is shown.


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Random Block Read (Function 27H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 27H
   DS:DX
     Pointer to opened FCB
   CX
     Number of blocks to read

   Return:

   AL
     0 = Read completed successfully
     1 = End of file, empty record
     2 = DTA too small
     3 = End of file, partial record
   CX
     Number of blocks read


   Comments:

   Function 27H reads one or more records from a specified file to the Disk
   Transfer Address. DX must contain the offset (to the segment address in
   DS) of an opened FCB. CX must contain the number of records to read.
   Reading starts at the record specified by the Relative Record field
   (offset 21H); you must set this field with Function 24H (Set Relative
   Record) before calling this function.

   DOS calculates the number of bytes to read by multiplying the value in CX
   by the Record Size field (offset 0EH) of the FCB.

   CX returns the number of records read. The Current Block field (offset
   0CH), Current Record field (offset 20H), and Relative Record field (offset
   21H) are set to address the next record.

   If you call this function with CX=0, no records are read. AL returns a
   code that describes the processing:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0                  Read completed successfully

   1                  End-of-file; no data in the record

   2                  Not enough room at the Disk Transfer Address to read
                      one record; read canceled

   3                  End-of-file; a partial record was read and padded to
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   ran_block_read  macro  fcb,count,rec_size
                   mov    dx,offset fcb
                   mov    cx,count
                   mov    word ptr fcb[14],rec_size
                   mov    ah,27H
                   int    21H
                   endm

   Example:

   The following program copies a file by using Function 27H (Random Block
   Read). This program speeds the copy process by specifying a record count
   of 1 and a record length equal to the file size, and by using a buffer of
   32 kilobytes; the file is read as a single record (compare to the sample
   program for Function 28H that specifies a record length of 1 and a record
   count equal to the file size).

   current_record  equ  20H  ; offset of Current Record field
   fil_size        equ  10H  ; offset of File Size field
   ;
   fcb       db      37 dup (?)
   filename  db      17 dup(?)
   prompt1   db     "File to copy: $"   ; see Function 09H for
   prompt2   db     "Name of copy: $"   ; explanation of $
   crlf      db      0DH,0AH,"$"
   file_length  dw   ?
   buffer    db      32767 dup(?)
   ;



   begin:    set_dta    buffer           ; see Function 1AH
             display    prompt1          ; see Function 09H
             get_string 15,filename      ; see Function 0AH
             display    crlf             ; see Function 09H
             parse      filename[2],fcb  ; see Function 29H
             open       fcb              ; see Function 0FH
             mov        fcb[current_record],0  ; set Current
                                         ; Record field
             set_relative_record fcb     ; see Function 24H
             mov        ax, word ptr fcb[fil_size]
                                         ; get file size
             mov        file_length,ax   ; save it
             ran_block_read  fcb,1,ax    ; THIS FUNCTION
             display    prompt2          ; see Function 09H
             get_string 15,filename      ; see Function 0AH
             display    crlf             ; see Function 09H
             parse      filename[2],fcb  ; see Function 29H
             create     fcb              ; see Function 16H
             mov        fcb[current_record],0; set current
                                         ; Record field
             set_relative_record fcb     ; see Function 24H
             ran_block_write  fcb,1,ax   ; see Function 28H
             close      fcb              ; see Function 10H


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Random Block Write (Function 28H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 28H
   DS:DX
     Pointer to opened FCB
   CX
     Number of blocks to write
     (0 = set File Size field)

   Return:

   AL
     00H = Write completed successfully
     01H = Disk full
     02H = End of segment
   CX
     Number of blocks written


   Comments:

   Function 28H writes one or more records to a specified file from the Disk
   Transfer Address. DX must contain the offset (to the segment address in
   DS) of an opened FCB; CX must contain either the number of records to
   write or 0.

   If CX is not 0, the specified number of records is written to the file,
   starting at the record specified in the Relative Record field (offset 21H)
   of the FCB. If CX is 0, no records are written, but MS-DOS sets the File
   Size field (offset 10H) of the directory entry to the value in the
   Relative Record field (offset 21H) of the FCB. To satisfy this new file
   size, disk allocation units are allocated or released, as required.

   MS-DOS calculates the number of bytes to write by multiplying the value in
   CX by the Record Size field (offset 0EH) of the FCB. CX returns the number
   of records written; the Current Block field (offset 0CH), Current Record
   field (offset 20H), and Relative Record (offset 21H) field are set to
   address the next record. AL returns a code that describes the processing:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0                  Write completed successfully

   1                  Disk full. No records written

   2                  Not enough room at the Disk Transfer Address to write
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   ran_block_write  macro  fcb,count,rec_size
                    mov    dx,offset fcb
                    mov    cx,count
                    mov    word ptr fcb[14],rec_size
                    mov    ah,28H
                    int    21H
                    endm

   Example:

   The following program copies a file using Function 27H (Random Block
   Read) and Function 28H (Random Block Write). This program speeds the copy
   process by specifying a record count equal to the file size and a record
   length of 1, and by using a buffer of 32 kilobytes. The file is copied
   quickly with one disk access each to read and write (compare to the sample
   program of Function 27H, which specifies a record count of 1 and a record
   length equal to file size).

   current_record  equ  20H   ; offset of Current Record field
   fil_size        equ  10H   ; offset of File Size field
   ;
   fcb       db      37 dup (?)
   filename  db      17 dup(?)
   prompt1   db     "File to copy: $"   ; see Function 09H for
   prompt2   db     "Name of copy: $"   ; explanation of $
   crlf      db      0DH,0AH,"$"
   num_recs  dw      ?
   buffer    db      32767 dup(?)
   ;



   begin:    set_dta    buffer      ; see Function 1AH
             display    prompt1     ; see Function 09H
             get_string 15,filename ; see Function 0AH
             display    crlf        ; see Function 09H
             parse      filename[2],fcb  ; see Function 29H
             open       fcb              ; see Function 0FH
             mov        fcb[current_record],0; set Current
                                         Record field
             set_relative_record fcb     ; see Function 24H
             mov        ax, word ptr fcb[fil_size]
                                         ; get file size
             mov        num_recs,ax      ; save it
             ran_block_read  fcb,num_recs,1  ; THIS FUNCTION
             display    prompt2          ; see Function 09H
             get_string 15,filename      ; see Function 0AH
             display    crlf             ; see Function 09H
             parse      filename[2],fcb  ; see Function 29H
             create     fcb              ; see Function 16H
             mov        fcb[current_record],0  ; set Current
                                         ; Record field
             set_relative_record fcb     ; see Function 24H
             ran_block_write fcb,num_recs,1 ; see Function 28H
             close      fcb              ; see Function 10H


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Parse File Name (Function 29H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 29H
   AL
     Controls parsing (see text)
   DS:SI
     Pointer to string to parse
   ES:DI
     Pointer to buffer for unopened FCB

   Return:

   AL
     00H        = No wildcard characters
     01H        = Wildcard characters used
     FFH        = Drive letter invalid
   DS:SI
     Pointer to first byte past
     string that was parsed
   ES:DI
     Pointer to unopened FCB


   Comments:

   Function 29H parses a string for a filename of the form
   drive:filename.extension. SI must contain the offset (to the segment
   address in DS) of the string to parse; DI must contain the offset (to the
   segment address in ES) of an area of memory large enough to hold an
   unopened FCB. If the string contains a valid filename, this call creates a
   corresponding unopened FCB at ES:DI.

   AL controls the parsing. Bits 4-7 must be 0; bits 0-3 have the following
   meaning:

   Table 1.20
   Bit Values for Function 29H
ÖŚÄŚÄÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ·
   Bit         Value        Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0           0            Stops parsing if a file separator is encountered

               1            Ignores leading separators

   1           0            Sets the drive number in the FCB to 0 (current
                            drive) if the string does not contain a drive
                            number

               1            Leaves the drive number in the FCB unchanged if
                            the string does not contain a drive number

   2           0            Sets the filename in the FCB to eight blanks if
                            the string does not contain a filename

               1            Leaves the filename in the FCB unchanged if the
                            string does not contain a filename

   3           0            Sets the extension in the FCB to three blanks if
                            the string does not contain an extension
   Bit         Value        Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
                           the string does not contain an extension

               1            Leaves the extension in the FCB unchanged if the
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


   If the string contains a filename or extension that includes an asterisk
   (*), all remaining characters in the name or extension are set to question
   marks (?).

   Filename Separators:



    :  ;  .  ,  =  +  /  "  [  ]  \  <  >  |  space  tab

   Filename terminators include all the filename separators, plus any control
   character. A filename cannot contain a filename terminator, since, if the
   call encounters one, parsing stops.

   If the string contains a valid filename:

   ž  AL returns 1 if the filename or extension contains a wildcard character
      (* or ?); AL returns 0 if neither the filename nor extension contains a
      wildcard character.

   ž  DS:SI points to the first character following the parsed string.

   ž  ES:DI points to the first byte of the unopened FCB.

   If the drive letter is invalid, AL returns FFH. If the string does not
   contain a valid filename, ES:DI+1 points to a blank.

   Macro Definition:

   parse macro string,fcb
         mov   si,offset string
         mov   di,offset fcb
         push  es
         push  ds
         pop   es
         mov   al,0FH        ; bits 0-3 on
         mov   ah,29H
         int   21H
         pop   es
         endm

   Example:

   The following program verifies the existence of the file named in reply to
   the prompt.

   fcb           db      37 dup (?)
   prompt        db     "Filename: $"
   reply         db      17 dup(?)
   yes           db     "File exists",0DH,0AH,"$"
   no            db     "File does not exist",0DH,0AH,"$"
                 crlf    db 0DH,0AH,"$"
   ;
   begin:        display    prompt        ; see Function 09H
                 get_string 15,reply      ; see Function 0AH
                 parse      reply[2],fcb  ; THIS FUNCTION
                 display    crlf          ; see Function 09H
                 search_first  fcb        ; see Function 11H
                 cmp        al,0FFH       ; dir. entry found?
                 je         not_there     ; no
                 display    yes           ; see Function 09H
                 jmp        return
   not_there:    display    no


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get Date (Function 2AH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 2AH

   Return:

   CX
     Year (1980-2099)
   DH
     Month (1-12)
   DL
     Day (1-31)
   AL
     Day of week (0=Sun., 6=Sat.)


   Comments:

   Function 2AH returns the current date set in the operating system as
   binary numbers in CX and DX:

   Register           Contents
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   CX                 Year (1980-2099)
   DH                 Month (1=January, 2=February, etc.)
   DL                 Day of month (1-31)
   AL                 Day of week (0=Sunday, 1=Monday, etc.)
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   get_date  macro
             mov   ah,2AH
             int   21H
             endm

   Example:

   The following program gets the date, increments the day, increments the
   month or year, if necessary, and sets the new date.

   month      db      31,28,31,30,31,30,31,31,30,31,30,31
   ;
   begin:     get_date            ; THIS FUNCTION
              inc    dl           ; increment day
              xor    bx,bx        ; so BL can be used as index
              mov    bl,dh        ; move month to index register
              dec    bx           ; month table starts with 0
              cmp    dl,month[bx] ; past end of month?
              jle    month_ok     ; no, set new date
              mov    dl,1         ; yes, set day to 1
              inc    dh           ; and increment month
              cmp    dh,12        ; past end of year?
              jle    month_ok     ; no, set new date
              mov    dh,1         ; yes, set month to 1
              inc    cx           ; increment year
   month_ok:  set_date cx,dh,dl   ; see Function 2AH


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Set Date (Function 2BH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 2BH
   CX
     Year (1980-2099)
   DH
     Month (1-12)
   DL
     Day (1-31)

   Return:

   AL
     00H        = Date was valid
     FFH        = Date was invalid


   Comments:

   Function 2BH sets the date in the operating system (and in the CMOS clock,
   if one exists). Registers CX and DX must contain a valid date in binary:

   Register           Contents
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   CX                 Year (1980-2099)
   DH                 Month (1=January, 2=February, etc.)
   DL                 Day of month (1-31)
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   If the date is valid, the call sets it and AL returns 0. If the date is
   not valid, the function aborts and AL returns FFH.

   Macro Definition:

   set_date  macro  year,month,day
             mov    cx,year
             mov    dh,month
             mov    dl,day
             mov    ah,2BH
             int    21H
             endm

   Example:

   The following program gets the date, increments the day, increments the
   month or year, if necessary, and sets the new date.

   month      db      31,28,31,30,31,30,31,31,30,31,30,31
   ;
   begin:     get_date            ; see Function 2AH
              inc    dl           ; increment day
              xor    bx,bx        ; so BL can be used as index
              mov    bl,dh        ; move month to index register
              dec    bx           ; month table starts with 0
              cmp    dl,month[bx] ; past end of month?
              jle    month_ok     ; no, set the new date
              mov    dl,1         ; yes, set day to 1
              inc    dh           ; and increment month
              cmp    dh,12        ; past end of year?
              jle    month_ok     ; no, set the new date
              mov    dh,1         ; yes, set the month to 1
              inc    cx           ; increment year
   month_ok:  set_date cx,dh,dl   ; THIS FUNCTION


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get Time (Function 2CH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 2CH

   Return:

   CH
     Hour (0-23)
   CL
     Minutes (0-59)
   DH
     Seconds (0-59)
   DL
     Hundredths (0-99)


   Comments:

   Function 2CH returns the current time set in the operating system (and
   sets the CMOS clock, if one exists) as binary numbers in CX and DX:

   Register           Contents
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   CH                 Hour (0-23)
   CL                 Minutes (0-59)
   DH                 Seconds (0-59)
   DL                 Hundredths of a second (0-99)
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Depending on how your hardware keeps time, some of these fields may be
   irrelevant. As an example, many CMOS clock chips do not resolve more than
   seconds. In such a case, the value in DL will probably always be 0.

   Macro Definition:

   get_time  macro
             mov   ah,2CH
             int   21H
             endm

   Example:

   The following program displays the time continuously until you press any
   key.

   time         db    "00:00:00.00",0DH,"$"
   ;
   begin:       get_time               ; THIS FUNCTION
                byte_to_dec ch,time    ; see end of chapter
                byte_to_dec cl,time[3] ; see end of chapter
                byte_to_dec dh,time[6] ; see end of chapter
                byte_to_dec dl,time[9] ; see end of chapter
                display time           ; see Function 09H
                check_kbd_status       ; see Function 0BH
                cmp     al,0FFH        ; has a key been pressed?
                je      return         ; yes, terminate
                jmp     begin          ; no, display time


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Set Time (Function 2DH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 2DH
   CH
     Hour (0-23)
   CL
     Minutes (0-59)
   DH
     Seconds (0-59)
   DL
     Hundredths (0-99)

   Return:

   AL
     00H        = Time was valid
     FFH        = Time was invalid


   Comments:

   Function 2DH sets the time in the operating system. Registers CX and DX
   must contain a valid time in binary:

   Register           Contents
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   CH                 Hour (0-23)
   CL                 Minutes (0-59)
   DH                 Seconds (0-59)
   DL                 Hundredths of a second (0-99)
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Depending on how your hardware keeps time, some of these fields may be
   irrelevant. As an example, many CMOS clock chips do not resolve more than
   seconds. In such a case, the value in DL will not be relevant.

   If the time is valid, the call sets it and AL returns 0. If the time is
   not valid, the function aborts and AL returns FFH.

   Macro Definition:

   set_time  macro  hour,minutes,seconds,hundredths
             mov    ch,hour
             mov    cl,minutes
             mov    dh,seconds
             mov    dl,hundredths
             mov    ah,2DH
             int    21H
             endm

   Example:

   The following program sets the system clock to 0 and displays the time
   continuously. When you type a character, the display freezes; when you
   type another character, the clock is reset to 0 and the display starts
   again.

   time          db  "00:00:00.00",0DH,0AH,"$"
   ;
   begin:        set_time  0,0,0,0       ; THIS FUNCTION
   read_clock:   get_time                ; see Function 2CH
                 byte_to_dec  ch,time    ; see end of chapter
                 byte_to_dec  cl,time[3] ; see end of chapter
                 byte_to_dec  dh,time[6] ; see end of chapter
                 byte_to_dec  dl,time[9] ; see end of chapter
                 display  time           ; see Function 09H
                 dir_console_io 0FFH     ; see Function 06H
                 cmp      al,00H         ; was a char. typed?
                 jne      stop           ; yes, stop the timer
                 jmp      read_clock     ; no keep timer on
   stop:         read_kbd                ; see Function 08H
                 jmp      begin          ; keep displaying time


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Set/Reset Verify Flag (Function 2EH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 2EH
   AL
     0 = Do not verify
     1 = Verify

   Return:

   None


   Comments:

   Function 2EH tells MS-DOS whether or not to verify each disk write. If AL
   is 1, verify is on; if AL is 0, verify is off. MS-DOS checks this flag
   each time it writes to a disk.

   The flag is normally off; you may wish to turn it on when writing critical
   data to disk. Because disk errors are rare and verification slows writing,
   you will probably want to leave it off at other times. You can check the
   setting with Function 54H (Get Verify State).

   Macro Definition:

   verify  macro  switch
           mov    al,switch
           mov    ah,2EH
           int    21H
           endm

   Example:

   The following program copies the contents of a single-sided disk in drive
   A to the disk in drive B, verifying each write. It uses a buffer of 32
   kilobytes.

   on           equ   1
   off          equ   0
   ;
   prompt       db   "Source in A, target in B",0DH,0AH
                db   "Any key to start. $"
   first        dw    0
   buffer       db    60 dup (512 dup(?))   ; 60 sectors
   ;
   begin:       display prompt              ; see Function 09H
                read_kbd                    ; see Function 08H
                verify on                   ; THIS FUNCTION
                mov    cx,6                 ; copy 60 sectors
                                            ; 6 times
   copy:        push   cx                   ; save counter
                abs_disk_read  0,buffer,60,first ; see Int 25H
                abs_disk_write  1,buffer,64,first ; see Int 26H
                add    first,60             ; do next 60 sectors
                pop    cx                   ; restore counter
                loop   copy                 ; do it again
                verify off                  ; THIS FUNCTION


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get Disk Transfer Address (Function 2FH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 2FH

   Return:

   ES:BX
     Pointer to Disk Transfer Address


   Comments:

   Function 2FH returns the segment address of the current Disk Transfer
   Address in ES and the offset in BX.

   Macro Definition:

   get_dta  macro
            mov    ah,2fH
            int    21H
            endm

   Example:

   The following program displays the current Disk Transfer Address in the
   form: segment:offset.

   message   db      "DTA --        :    ",0DH,0AH,"$"
   sixteen   db       10H
   temp      db       2 dup (?)
   ;
   begin:    get_dta                      ; THIS FUNCTION
             mov    word ptr temp,ex      ; To access each byte
             convert temp[1],sixteen,message[07H]  ; See end of
             convert temp,sixteen,message[09H]    ; chapter for
             convert bh,sixteen,message[0CH]      ; description
             convert bl,sixteen,message[0EH]      ; of CONVERT
             display message              ; See Function 09H


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get MS-DOS Version Number (Function 30H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 30H

   Return:

   AL
     Major version number
   AH
     Minor version number
   BH
     OEM serial number
   BL:CX
     24-bit user (serial) number


   Comments:

   Function 30H returns the MS-DOS version number. AL returns the major
   version number; AH returns the minor version number. (For example, MS-DOS
   3.0 returns 3 in AL and 0 in AH.)

   If AL returns 0, the MS-DOS version is earlier than 2.0.

   Macro Definition:

   get_version  macro
                mov    ah,30H
                int    21H
                endm

   Example:

   The following program displays the MS-DOS version if it is 1.28 or
   greater.

   message   db      "MS-DOS Version  . ",0DH,0AH,"$"
   ten       db       0AH                 ; For CONVERT
   ;
   begin:    get_version                  ; THIS FUNCTION
             cmp     al,0                 ; 1.28 or later?
             jng     return               ; No, go home
             convert al,ten,message[0FH]  ; See end of chapter
             convert ah,ten,message[12H]  ; for description
             display message              ; See Function 9


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Keep Process (Function 31H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 31H
   AL
     Return code
   DX
     Memory size, in paragraphs

   Return:

   None


   Comments:

   Function 31H makes a program remain resident after it terminates. You can
   use it to install device-specific interrupt handlers. But unlike Interrupt
   27H (Terminate But Stay Resident), this function request allows more than
   64K bytes to remain resident and does not require CS to contain the
   segment address of the Program Segment Prefix. You should use Function 31H
   to install a resident program unless your program must be compatible with
   MS-DOS versions earlier than 2.0.

   DX must contain the number of paragraphs of memory required by the program
   (one paragraph = 16 bytes). AL contains an exit code.

   Be careful when using this function with .exe programs. The value in DX
   must be the total size to remain resident, not just the size of the code
   segment which is to remain resident. A typical error is to forget about
   the 100H-byte program-header-prefix and give a value in DX that doesn't
   account for the size of this prefix. MS-DOS terminates the current process
   and tries to set the memory allocation to the number of paragraphs in DX.
   No other allocation blocks belonging to the process are released.

   By using Function 4DH (Get Return Code of Child Process), the parent
   process can retrieve the process's exit code from AL. (You can test this
   exit code by using the if command with errorlevel.)

   Macro Definition:

   keep_process  macro return_code,last_byte
                 mov   al,return_code
                 mov   dx,offset last_byte
                 mov   cl,4
                 shr   dx,cl
                 inc   dx
                 mov   ah,31H
                 int   21H
                 endm

   Example:

   Because the most common use of this call is to install a machine-specific
   routine, an example is not shown. The macro definition, however, shows the
   calling syntax.


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 CONTROL+C Check (Function 33H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 33H
   AL
      0 = Get state of CONTROL+C
      1 = Set state of CONTROL+C
      5 = Query DOS boot drive
   DL (if AL=1)
      0 = Off
      1 = On

   Return:

   DL (if AL=0)
      0 = Off
      1 = On
   DL (if AL=5)
      1 = A, 2 = B, etc.
   AL
      FFH = error (AL was neither 0, 1, nor 5
                  when call was made)


   Comments:

   Function 33H gets or sets the state of CONTROL+C (or CONTROL+BREAK for IBM
   compatibles) checking in MS-DOS and can query the DOS boot drive. AL must
   contain a code that specifies the requested action:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0                  Current state of CONTROL+C checking in DL
   1                  Set state of CONTROL+C checking to the value in DL
   5                  Query DOS boot drive in DL
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   If AL is 0, DL returns the current state (0=off, 1=on). If AL is 1, the
   value in DL specifies the state to be set (0=off, 1=on). If AL is neither
   0, 1, nor 5, AL returns FFH and the state of CONTROL+C checking is
   unaffected.

   MS-DOS normally checks for CONTROL+C only when carrying out certain
   function requests in the 01H through 0CH group (see the description of
   specific calls for details). When CONTROL+C checking is on, MS-DOS checks
   for CONTROL+C when carrying out any function request. For example, if
   CONTROL+C checking is off, all disk I/O proceeds without interruption, but
   if it is on, the CONTROL+C interrupt is issued at the function request
   that initiates the disk operation.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     Programs that use Function 06H (Direct Console I/O) or 07H (Direct
     Console Input) to read CONTROL+C as data must ensure that the CONTROL+C
     checking is off.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   ctrl_c_ck  macro  action,state
              mov    al,action
              mov    dl,state
              mov    ah,33H
              int    21H
              endm

   Example:

   The following program displays a message that tells whether CONTROL+C
   checking is on or off:

   message   db       "CONTROL+C checking ","$"
   on        db       "on","$",0DH,0AH,"$"
   off       db       "off","$",0DH,0AH,"$"
   ;
   begin:    display   message          ; See Function 09H
             ctrl_c_ck 0                ; THIS FUNCTION
             cmp       dl,0             ; Is checking off?
             jg        ck_on            ; No
             display   off              ; See Function 09H
             jmp       return           ; Go home
   ck_on:    display   on               ; See Function 09H

   To query the DOS boot drive value, add the following programs segment:

             mov       AH,33H           ; Query DOS value
             mov       AL,05H           ; DOS boot drive
             int       21H
             jc        ERROR            ; DL=Boot drive (A=1)


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get Interrupt Vector (Function 35H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 35H
   AL
      Interrupt number

   Return:

   ES:BX
      Pointer to interrupt routine


   Comments:

   Function 35H gets the address from the interrupt-vector table for the
   specified interrupt. AL must contain the number of an interrupt.

   ES returns the segment address of the interrupt handler; BX returns the
   offset.

   To avoid compatibility problems, programs should never read an interrupt
   vector directly from memory, nor set an interrupt vector by writing it
   into memory. Use this function request to get a vector and Function 25H
   (Set Interrupt Vector) to set a vector, unless your program must be
   compatible with MS-DOS versions earlier than 2.0.

   Macro Definition:

   get_vector  macro  interrupt
               mov    al,interrupt
               mov    ah,35H
               int    21H
               endm

   Example:

   The following program displays the segment and offset (CS:IP) for the
   handler for Interrupt 25H (Absolute Disk Read).

   message   db     "Interrupt 25H -- CS:0000 IP:0000"
             db      0DH,0AH,"$"
   vec_seg   db      2 dup (?)
   vec_off   db      2 dup (?)
   ;
   begin:    push    es                    ; save ES
             get_vector 25H                ; THIS FUNCTION
             mov     ax,es                 ; INT25H segment in AX
             pop     es                    ; save ES
             convert ax,16,message[20]     ; see end of chapter
             convert bx,16,message[28]     ; see end of chapter
             display message               ; See Function 9


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get Disk Free Space (Function 36H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 36H
   DL
      Drive (0=default, 1=A, etc.)

   Return:

   AX
      0FFFFH if drive number is invalid;
      otherwise, sectors per cluster
   BX
      Available clusters
   CX
      Bytes per sector
   DX
      Clusters per drive


   Comments:

   Function 36H returns the number of clusters available on the disk in the
   specified drive and the information necessary to calculate the number of
   bytes available on the disk. DL must contain a drive number (0=default,
   1=A, etc.). If the drive number is valid, MS-DOS returns the information
   in the following registers:

   Register           Contents
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   AX                 Sectors per cluster
   BX                 Available clusters
   CX                 Bytes per sector
   DX                 Total clusters
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   If the drive number is invalid, AX returns 0FFFFH.

   This call supersedes Functions 1BH and 1CH in earlier MS-DOS versions.

   Macro Definition:

   get_disk_space  macro  drive
                   mov    dl,drive
                   mov    ah,36H
                   int    21H
                   endm

   Example:

   The following program displays space information for the disk in drive B.

   message   db "      clusters on drive B.",0DH,0AH   ; DX
             db "      clusters available.",0DH,0AH    ; BX
             db "      sectors per cluster.",0DH,0AH   ; AX
             db "      bytes per sector,",0DH,0AH,"$"  ; CX
   ;
   begin:    get_disk_space 2                 ; THIS FUNCTION
             convert    ax,10,message[55]     ; see end of chapter
             convert    bx,10,message[28]     ; see end of chapter
             convert    cx,10,message[83]     ; see end of chapter
             convert    dx,10,message         ; see end of chapter
             display message                  ; See Function 09H


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get Country Data (Function 38H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 38H
   AL
      00H = Current country
      1-0FEH = Country code
      0FFH = BX contains country code
   BX (if AL = 0FFH)
      Country code 255 or higher
   DS:DX
      Pointer to 32-byte memory area

   Return:

   Carry set:
   AX
      2 = Invalid country code
   DS:DX
      Segment:offset pointer to 32-byte memory area
   Carry not set:
   BX
      Country code


   Comments:

   Function 38H gets the country-dependent information that MS-DOS uses to
   control the keyboard and display, or it sets the currently defined country
   (to set the country code, see the next function request description, Set
   Country Data). To get the information, DX must contain the offset (from
   the segment address in DS) of a 32-byte memory area to which the country
   data returns. AL specifies the country code:

   Value in AL        Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   00H                Retrieves information about the country currently set
   1 to 0FEH          Retrieves information about the country identified by
                      this code
   0FFH               Retrieves information about the country identified by
                      the code in BX
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   BX must contain the country code if the code is 255 or greater. The
   country code is usually the international telephone-prefix code. The
   country-dependent information returns in the following form:

     Offset
   Hex        Decimal   Field Name                      Length in bytes
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   00H        0         Date format                     2 (word)
   02H        2         Currency symbol                 5 (ASCIZ string)
   07H        7         Thousands separator             2 (ASCIZ string)
   09H        9         Decimal separator               2 (ASCIZ string)
   0BH        11        Date separator                  2 (ASCIZ string)
   0DH        13        Time separator                  2 (ASCIZ string)
   0FH        15        Bit field                       1
   10H        16        Currency places                 1
   11H        17        Time format                     1
   12H        18        Case-map call address           4 (DWORD)
   16H        22        Data-list separator             2 (ASCIZ string)
   18H        24        Reserved                        10
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Date Format:

   0 = USA        (month/day/year)
   1 = Europe        (day/month/year)
   2 = Japan        (year/month/day)


   Bit Field:

   Bit         Value        Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0           0            Currency symbol precedes amount
               1            Currency symbol follows amount
   1           0            No space between symbol and amount
               1            One space between symbol and amount
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   All other bits are undefined.

   Time Format:

   0 = 12-hour clock
   1 = 24-hour clock

   Currency Places:

   Specifies the number of places that appear after the decimal point on
   currency amounts.

   Case-Mapping Call Address:

   Specifies the segment and offset of a FAR procedure that performs
   country-specific lowercase-to-uppercase mapping on character values from
   80H to 0FFH. You call it with the character to be mapped in AL. If there
   is an uppercase code for the character, it is returned in AL; if there is
   not, or if you call it with a value less than 80H in AL, AL returns
   unchanged. AL and the FLAGS are the only altered registers.

   If there is an error, the carry flag (CF) is set and the error code
   returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   2                  Invalid country code (no table for it).
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   get_country macro  country,buffer
               local     gc_01
               mov       dx,offset buffer
               mov       ax,country
               cmp       ax,OFFH
               jl        gc_01
               mov       al,OFFh
               mov       bx,country
   gc_01:      mov       ah,38h
               int       21H
               endm

   Example:

   The following program displays the time and date in the format appropriate
   to the current country code, and the number 999,999 and 99/100 as a
   currency amount with the proper currency symbol and separators.

   time       db     "  :  :  ",5 dup (20H),"$"
   date       db     "  /  /  ",5 dup (20H),"$"
   number     db     "999?999?99",0DH,0AH,"$"
   data_area  db      32 dup (?)
   ;
   begin:    get_country  0,data_area       ; THIS FUNCTION
             get_time                       ; See Function 2CH
             byte_to_dec  ch,time           ; See end of chapter
             byte_to_dec  cl,time[03H]      ; for description of
             byte_to_dec  dh,time[06H]      ; CONVERT macro
             get_date                       ; See Function 2AH
             sub      cx,1900               ; Want last 2 digits
             byte_to_dec  cl,date[06H]      ; See end of chapter
             cmp      word ptr data_area,0  ; Check country code
             jne      not_usa               ; It's not USA
             byte_to_dec  dh,date           ; See end of chapter
             byte_to_dec  dl,date[03H]      ; See end of chapter
             jmp      all_done              ; Display data
   not_usa:  byte_to_dec  dl,date           ; See end of chapter
             byte_to_dec  dh,date[03H]      ; See end of chapter
   all_done: mov      al,data_area[07H]     ; Thousand separator
             mov      number[03H],al        ; Put in NUMBER
             mov      al,data_area[09H]     ; Decimal separator
             mov      number[07H],al        ; Put in AMOUNT
             display  time                  ; See Function 09H
             display  date                  ; See Function 09H
             display_char  data_area[02H]   ; See Function 02H
             display  number                ; See Function 09H


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Set Country Data (Function 38H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 38H
   DX = -1 (0FFFFH)
   AL
      Country code less than 255, or
      0FFH if the country code is in BX
   BX (if AL=0FFH)
      Country code 255 or higher

   Return:

   Carry set:
   AX
      2 = Invalid country code
   Carry not set:
      No error


   Comments:

   Function 38H sets the country code that MS-DOS uses to control the
   keyboard and the display, or it retrieves the country-dependent
   information (to get the country data, see the previous function request
   description, Get Country Data). To set the information, DX must contain
   0FFFFH. AL must contain either the country code, if it is less than 255,
   or 255 to indicate that the country code is in BX. If AL contains 0FFH, BX
   must contain the country code.

   The country code is usually the international telephone prefix-code. See
   "Get Country Data" for a description of the country data and how it is
   used.

   If there is an error, the carry flag (CF) is set and the error code
   returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   2                  Invalid country code (no table for it).
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   set_country macro  country
               local  sc_01
               mov    dx,0FFFFH
               mov    ax,country
               cmp    ax,0FFH
               jl     sc_01
               mov    bx,country
               mov    al,0ffh
   sc_01:      mov    ah,38H
               int    21H
               endm

   Example:

   The following program sets the country code to the United Kingdom (44).

   uk        equ         44
   ;
   begin:    set_country uk     ; THIS FUNCTION
             jc          error  ; routine not shown


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Create Directory (Function 39H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 39H
   DS:DX
      Pointer to pathname

   Return:

   Carry set:
   AX
      2 = File not found
      3 = Path not found
      5 = Access denied
   Carry not set:
      No error


   Comments:

   Function 39H creates a new subdirectory. DX must contain the offset (from
   the segment address in DS) of an ASCIZ string that specifies the pathname
   of the new subdirectory.

   If there is an error, the carry flag (CF) is set and the error code
   returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   2                  File not found

   3                  Path not found

   5                  No room in the parent directory, a file with the same
                      name exists in the current directory, or the path
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   make_dir  macro path
             mov    dx,offset path
             mov    ah,39H
             int    21H
             endm

   Example:

   The following program adds a subdirectory named new_dir to the root
   directory on the disk in drive B and changes the current directory to
   new_dir. The program then changes the current directory back to the
   original directory and then deletes new_dir. It displays the current
   directory after each step to confirm the changes.

   old_path  db        "b:",0,63 dup (?)
   new_path  db        "b:\new_dir",0
   buffer    db        "b:",0,63 dup (?)
   ;
   begin:    get_dir    2,old_path[03H]  ; See Function 47H
             jc         error_get        ; Routine not shown
             display_asciz  old_path     ; See end of chapter
             make_dir   new_path         ; THIS FUNCTION
             jc         error_make       ; Routine not shown
             change_dir new_path         ; See Function 3BH
             jc         error_change     ; Routine not shown
             get_dir    2,buffer[03H]    ; See Function 47H
             jc         error_get        ; Routine not shown
             display_asciz  buffer       ; See end of chapter
             change_dir old_path         ; See Function 3BH
             jc         error_change     ; Routine not shown
             rem_dir    new_path         ; See Function 3AH
             jc         error_rem        ; Routine not shown
             get_dir    2,buffer[03H]    ; See Function 47H
             jc         error_get        ; Routine not shown
             display_asciz  buffer      ; See end of chapter


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Remove Directory (Function 3AH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 3AH
   DS:DX
      Pointer to pathname

   Return:

   Carry set:
   AX
      2        = File not found
      3        = Path not found
      5        = Access denied
     16        = Current directory
   Carry not set:
      No error


   Comments:

   Function 3AH deletes a subdirectory. DX must contain the offset (from the
   segment address in DS) of an ASCIZ string that specifies the pathname of
   the subdirectory you want to delete.

   The subdirectory must not contain any files. You cannot erase the current
   directory. If there is an error, the carry flag (CF) is set and the error
   code returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   2                  File not found

   3                  Path not found

   5                  Directory not empty, or path doesn't specify a
                      directory, or it specifies the root directory, or it is
                      invalid

   16                 Path specifies current directory
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   rem_dir  macro  path
            mov    dx,offset path
            mov    ah,3AH
            int    21H
            endm

   Example:

   The following program adds a subdirectory named new_dir to the root
   directory on the disk in drive B and changes the current directory to
   new_dir. The program then changes the current directory back to the
   original directory and deletes new_dir. It displays the current directory
   after each step to confirm the changes.

   old_path  db        "b:",0,63 dup (?)
   new_path  db        "b:\new_dir",0
   buffer    db        "b:",0,63 dup (?)
   ;
   begin:    get_dir    2,old_path[03H]  ; See Function 47H
             jc         error_get        ; Routine not shown
             display_asciz  old_path    ; See end of chapter
             make_dir   new_path         ; See Function 39H
             jc         error_make       ; Routine not shown
             change_dir new_path         ; See Function 3BH
             jc         error_change     ; Routine not shown
             get_dir    2,buffer[03H]    ; See Function 47H
             jc         error_get        ; Routine not shown
             display_asciz  buffer      ; See end of chapter
             change_dir old_path         ; See Function 3BH
             jc         error_change     ; Routine not shown
             rem_dir    new_path         ; THIS FUNCTION
             jc         error_rem        ; Routine not shown
             get_dir    2,buffer[03H]    ; See Function 47H
             jc         error_get        ; Routine not shown
             display_asciz  buffer      ; See end of chapter


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Change Current Directory (Function 3BH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 3BH
   DS:DX
      Pointer to pathname

   Return:

   Carry set:
   AX
      2 = File not found
      3 = Path not found
   Carry not set:
      No error


   Comments:

   Function 3BH changes the current directory. DX must contain the offset
   (from the segment address in DS) of an ASCIZ string that specifies the
   pathname of the new current directory.

   The directory string is limited to 64 characters.

   If any member of the path doesn't exist, the path is unchanged. If there
   is an error, the carry flag (CF) is set and the error code returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   2                  File not found

   3                  Path either doesn't exist or it specifies a file
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   change_dir  macro  path
               mov    dx,offset path
               mov    ah,3BH
               int    21H
               endm

   Example:

   The following program adds a subdirectory named new_dir to the root
   directory that is on the disk in drive B and changes the current directory
   to new_dir. The program then changes the current directory back to the
   original directory and deletes new_dir. It displays the current directory
   after each step to confirm the changes.

   old_path  db        "b:",0,63 dup (?)
   new_path  db        "b:\new_dir",0
   buffer    db        "b:",0,63 dup (?)
   ;
   begin:    get_dir    2,old_path[03H]  ; See Function 47H
             jc         error_get        ; Routine not shown
             display_asciz  old_path    ; See end of chapter
             make_dir   new_path         ; See Function 39H
             jc         error_make       ; Routine not shown
             change_dir new_path         ; THIS FUNCTION
             jc         error_change     ; Routine not shown
             get_dir    2,buffer[03H]    ; See Function 47H
             jc         error_get        ; Routine not shown
             display_asciz  buffer      ; See end of chapter
             change_dir old_path         ; See Function 3BH
             jc         error_change     ; Routine not shown
             rem_dir    new_path         ; See Function 3AH
             jc         error_rem        ; Routine not shown
             get_dir    2,buffer[03H]    ; See Function 47H
             jc         error_get        ; Routine not shown
             display_asciz  buffer      ; See end of chapter


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Create Handle (Function 3CH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 3CH
   DS:DX
      Pointer to pathname
   CX
      File attribute

   Return:

   Carry set:
   AX
      2        = File not found
      3        = Path not found
      4        = Too many open files
      5        = Access denied
   Carry not set:
   AX
      Handle


   Comments:

   Function 3CH creates a file and assigns it the first available handle. DX
   must contain the offset (from the segment address in DS) of an ASCIZ
   string that specifies the pathname of the file to be created. CX must
   contain the attribute to be assigned to the file, as described under "File
   Attributes" earlier in this chapter.

   If the specified file does not exist, this function creates it. But if the
   file already exists, it is truncated to a length of 0. Function 3CH then
   assigns the attribute in CX to the file and opens it for read/write. AX
   returns the file handle. If there is an error, the carry flag (CF) is set
   and the error code returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   2                  File not found

   3                  Path is invalid

   4                  Too many open files (no handle available)

   5                  Directory is full, a directory with the same name
                      exists, or a file with the same name exists with more
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   create_handle  macro  path,attrib
                  mov    dx,offset path
                  mov    cx,attrib
                  mov    ah,3CH
                  int    21H
                  endm

   Example:

   The following program creates a file named dir.tmp, containing the name
   and extension of each file in the current directory, on the disk in drive
   B.

   srch_file db      "b:*.*",0
   tmp_file  db      "b:dir.tmp",0
   buffer    db       43 dup (?)
   handle    dw       ?
   ;
   begin:    set_dta buffer                ; See Function 1AH
             find_first_file  srch_file,16H  ; See Function 4EH
             cmp     ax,12H                ; Directory empty?
             je      all_done              ; Yes, go home
             create_handle  tmp_file,0     ; THIS FUNCTION
             jc      error                 ; Routine not shown
             mov     handle,ax             ; Save handle
   write_it: write_handle handle,buffer[1EH],12 ; Function 40H
             find_next_file                ; See Function 4FH
             cmp     ax,12H                ; Another entry?
             je      all_done              ; No, go home
             jmp     write_it              ; Yes, write record
   all_done: close_handle  handle          ; See Function 3EH


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Open Handle (Function 3DH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 3DH
   AL
      Access code (see text)
   DS:DX
      Pointer to pathname

   Return:

   Carry set:
   AX
      2        = File not found
      3        = Path not found
      4        = Too many open files
      5        = Access denied
     12        = Invalid access
   Carry not set:
      No error


   Comments:

   Function 3DH opens any file, including hidden and system files, for input
   or output. DX contains the offset (from the segment address in DS) of an
   ASCIZ string that specifies the pathname of the file to be opened. AL
   contains a code that specifies how the file is to be opened. This code is
   described later under "Controlling Access to the File."

   If there is no error, AX returns the file handle. MS-DOS sets the
   read/write pointer to the first byte of the file.

   Controlling Access to the File

   The value in AL is made up of three parts that specify whether the file is
   to be opened for read, write, or both (access code); what access other
   processes have to the file (sharing mode); and whether a child process
   inherits the file (inherit bit).

        ŚÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   Bit  ³ 7 ³ 6   5   4 ³ 3   2   1   0 ³
        ĄÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

         \_/ \_________/ \______________/
          ³       ³             ³
          ³       ³             ĄÄÄÄÄÄÄÄÄ>  Access code
          ³       ³
          ³       ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ>  Sharing mode
          ³
          ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ>  Inherit bit

   Inherit Bit

   The high-order bit (bit 7) specifies whether the file is inherited by a
   child process created with Function 4B00H or 4B03H (Load and Execute
   Program or Overlay). If the bit is 0, the child process inherits the file;
   if the bit is 1, it doesn't.

   Sharing Mode

   The sharing mode bits (bits 4-6) specify what access, if any, other
   processes have to the open file. It can have the following values:

   Table 1.21
   Sharing Mode Bit Values
   Bits 4-6   Sharing Mode         Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   000        Compatibility        On a given machine, any process can open
                                   the file any number of times with this
                                   mode. Fails if the file has been opened
                                   with any of the other sharing modes.

   001        Deny both            Fails if the file has been opened in
                                   compatibility mode or for read or write
                                   access, even if by the current process.

   010        Deny write           Fails if the file has been opened in
                                   compatibility mode or for write access by
                                   any other process.

   011        Deny read            Fails if the file has been opened in
                                   compatibility mode or for read access by
                                   any other process.

   100        Deny none            Fails if the file has been opened in
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Access Code

   The access code (bits 0-3) specifies how the file is to be used. It can
   have the following values:

   Table 1.22
   Access Code Bit Values
                 Access
   Bits 0-3     Allowed       Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0000         Read          Fails if the file has been opened in deny read
                              or deny both sharing mode.

   0001         Write         Fails if the file has been opened in deny write
                              or deny both sharing mode.

   0010         Both          Fails if the file has been opened in deny read,
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   If there is an error, the carry flag (CF) is set and the error code is
   returned in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   2                  Specified file is invalid or doesn't exist

   3                  Specified path is invalid or doesn't exist

   4                  No handles are available in the current process or the
                      internal system tables are full

   5                  Program attempted to open a directory or VolumeID, or
                      tried to open a read-only file for writing

   12                 Access code (bits 0-3 of AL) not 0, 1, or 2
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   If this system call fails because of a file-sharing error, MS-DOS issues
   Interrupt 24H with error code 2 (Drive Not Ready). A subsequent Function
   59H (Get Extended Error) returns the extended error code that specifies a
   sharing violation.

   When opening a file, it is important to inform MS-DOS of any operations
   that other processes may perform on this file (sharing mode). The default
   (compatibility mode) denies all other processes access to the file, unless
   they also attempt to open the file in compatibility mode. The following
   table shows the effect of opening a file with compatibility mode set:

   Type of File Opening            Read-Only File       Not Read-Only
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   First open for read, write, or  Succeeds             Succeeds
   both by machine/process "N"

   Subsequent opens by machine or  Succeeds             Succeeds
   process "N"

   An open by another machine or   Succeeds             Fails
   process
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Files may be read-only with the MS-DOS attrib command or by a read-only
   share over the network.

   It may be all right for other processes to continue to read the file while
   your process is operating on it. In this case, you should specify "Deny
   Write," which inhibits other processes from writing to your files but
   allows them to read from these files.

   Similarly, it is important for you to specify what operations your process
   will perform ("Access" mode). If another process has the file open with
   any sharing mode other than "Deny" mode, then the default mode
   ("Read/Write") causes the open request to fail. If you only want to read
   the file, your open request succeeds unless all other processes have
   specified "Deny" mode or "Deny write."

   Macro Definition:

   open_handle  macro  path,access
                mov    dx, offset path
                mov    al, access
                mov    ah, 3DH
                int    21H
                endm

   Example:

   The following program prints a file named textfile.asc that is on the disk
   in drive B.

   file       db  "b:textfile.asc",0
   buffer     db   ?
   handle     dw   ?
   ;
   begin:     open_handle  file,0          ; THIS FUNCTION
              mov  handle,ax               ; Save handle
   read_char: read_handle handle,buffer,1  ; Read 1 character
              jc   error_read              ; Routine not shown
              cmp  ax,0                    ; End of file?
              je   return                  ; Yes, go home
              print_char  buffer           ; See Function 05H
              jmp  read_char               ; Read another


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Close Handle (Function 3EH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 3EH
   BX
      Handle

   Return:

   Carry set:
   AX
      6 = Invalid handle
   Carry not set:
      No error


   Comments:

   Function 3EH closes a file opened with Function 3DH (Open Handle) or
   3CH (Create Handle). BX must contain the handle of the open file that you
   want to close.

   If there is no error, MS-DOS closes the file and flushes all internal
   buffers. If there is an error, the carry flag (CF) is set and the error
   code returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   6                  Handle not open or invalid
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   close_handle  macro  handle
                 mov    bx,handle
                 mov    ah,3EH
                 int    21H
                 endm

   Example:

   The following program creates a file named dir.tmp, containing the
   filename and extension of each file in the current directory, in the
   current directory on the disk in drive B.

   srch_file  db  "b:*.*",0
   tmp_file   db  "b:dir.tmp",0
   buffer     db   43 dup (?)
   handle     dw   ?
   ;
   begin:     set_dta  buffer              ; See Function 1AH
              find_first_file  srch_file,16H  ; See Function 4EH
              cmp      ax,12H              ; Directory empty?
              je       all_done            ; Yes, go home
              create_handle  tmp_file,0    ; See Function 3CH
              jc       error_create        ; Routine not shown
              mov      handle,ax           ; Save handle
   write_it:  write_handle  handle,buffer[1EH],12 ; See Function
              jc       error_write                ; 40H
              find_next_file               ; See Function 4FH
              cmp      ax,12H              ; Another entry?
              je       all_done            ; No, go home
              jmp      write_it            ; Yes, write record
   all_done:  close_handle  handle         ; See Function 3EH
              jc       error_close         ; Routine not shown


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Read Handle (Function 3FH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 3FH
   BX
      Handle
   CX
      Bytes to read
   DS:DX
      Pointer to buffer

   Return:

   Carry set:
   AX
      5 = Access denied
      6 = Invalid handle
   Carry not set:
   AX
      Bytes read


   Comments:

   Function 3FH reads from the file or device associated with the specified
   handle. BX must contain the handle. CX must contain the number of bytes to
   be read. DX must contain the offset (to the segment address in DS) of the
   buffer.

   If there is no error, AX returns the number of bytes read; if you attempt
   to read starting at end of file, AX returns 0. The number of bytes
   specified in CX is not necessarily transferred to the buffer; if you use
   this call to read from the keyboard, for example, it reads only up to the
   first carriage-return.

   If you use this function request to read from standard input, you can
   redirect the input.

   If there is an error, the carry flag (CF) is set and the error code
   returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   5                  Handle not open for reading
   6                  Handle not open or invalid
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   read_handle  macro  handle,buffer,bytes
                mov    bx,handle
                mov    dx,offset buffer
                mov    cx,bytes
                mov    ah,3FH
                int    21H
                endm

   Example:

   The following program displays a file named textfile.asc that is on the
   disk in drive B.

   filename   db     "b:\textfile.asc",0
   buffer     db      129 dup (?)
   handle     dw      ?
   ;
   begin:     open_handle  filename,0        ; See Function 3DH
              jc           error_open        ; Routine not shown
              mov          handle,ax         ; Save handle
   read_file: read_handle  buffer,file_handle,128
              jc           error_open        ; Routine not shown
              cmp          ax,0              ; End of file?
              je           return            ; Yes, go home
              mov          bx,ax             ; # of bytes read
              mov          buffer[bx],"$"    ; Make a string
              display      buffer            ; See Function 09H
              jmp          read_file         ; Read more


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Write Handle (Function 40H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 40H
   BX
      Handle
   CX
      Bytes to write
   DS:DX
      Pointer to buffer

   Return:

   Carry set:
   AX
      5 = Access denied
      6 = Invalid handle
   Carry not set:
   AX
      Bytes written


   Comments:

   Function 40H writes to the file or device associated with the specified
   handle. BX must contain the handle. CX must contain the number of bytes to
   be written. DX must contain the offset (to the segment address in DS) of
   the data to be written.

   If you set CX to zero, the file will be truncated at the current position
   of the file pointer. MS-DOS will not perform the write if the handle is
   read-only.

   If there is no error, AX returns the number of bytes written. Be sure to
   check AX after performing a write. If its value is less than the number in
   CX when the call was made, it indicates an error, even though the carry
   flag isn't set. If AX contains 0, and if the target is a disk file, the
   disk is full.

   If you use this function request to write to standard output, you can
   redirect the output. If you call this request with CX=0, the file size is
   set to the value of the read/write pointer. To satisfy the new file size,
   allocation units are allocated or released, as required. If there is an
   error, the carry flag (CF) is set and the error code returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   5                  Handle not open for writing
   6                  Handle not open or invalid
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   write_handle  macro  handle,buffer,bytes
                 mov    bx,handle
                 mov    dx,offset buffer
                 mov    cx,bytes
                 mov    ah,40H
                 int    21H
                 endm

   Example:

   The following program creates a file named dir.tmp, containing the
   filename and extension of each file in the current directory, in the
   current directory on the disk in drive B.

   srch_file db     "b:*.*",0
   tmp_file  db     "b:dir.tmp",0
   buffer    db      43 dup (?)
   handle    dw      ?
   ;
   begin:    set_dta buffer                ; See Function 1AH
             find_first_file  srch_file,16H ; Check directory
             cmp     ax,12H                ; Directory empty?
             je      return                ; Yes, go home
             create_handle  tmp_file,0     ; See Function 3CH
             jc      error_create          ; Routine not shown
             mov     handle,ax             ; Save handle
   write_it: write_handle handle,buffer[1EH],12 ; THIS FUNCTION
             jc      error_write           ; Routine not shown
             find_next_file                ; Check directory
             cmp     ax,12H                ; Another entry?
             je      all_done              ; No, go home
             jmp     write_it              ; Yes, write record
   all_done: close_handle  handle          ; See Function 3EH
             jc      error_close           ; Routine not shown


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Delete Directory Entry [Unlink] (Function 41H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 41H
   DS:DX
      Pointer to pathname

   Return:

   Carry set:
   AX
      2 = File not found
      3 = Path not found
      5 = Access denied
   Carry not set:
      No error


   Comments:

   Function 41H erases a file by deleting its directory entry. DX must
   contain the offset (from the segment address in DS) of an ASCIZ string
   that specifies the pathname of the file that you want to delete. You
   cannot use wildcard characters.

   If the file exists and is not read-only, the call deletes it. If there is
   an error, the call sets the carry flag (CF) and the error code returns in
   AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   2                  File doesn't exist, or specifies a directory
   3                  Path is invalid
   5                  File is read-only
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   To delete a file with the read-only attribute, first change its attribute
   to 0 with Function 43H (Get/Set File Attributes).

   Macro Definition:

   delete_entry  macro  path
                 mov    dx,offset path
                 mov    ah,41H
                 int    21H
                 endm

   Example:

   The following program deletes all files, dated before December 31, 1986,
   from the disk in drive B.

   year      db       1986
   month     db       12
   day       db       31
   files     db       ?
   message   db      "NO FILES DELETED.",0DH,0AH,"$"
   path      db      "b:*.*", 0
   buffer    db       43 dup (?)
   ;
   begin:    set_dta  buffer          ; See Function 1AH
             select_disk "B"          ; See Function 0EH
             find_first_file  path,0  ; See Function 4EH
             jnc      compare         ; got one
             jmp      all_done        ; no match, go home
   compare:  convert_date  buffer[-1] ; See end of chapter
             cmp      cx,year         ; After 1986?
             jg       next            ; Yes, don't delete
             cmp      dl,month        ; After December?
             jg       next            ; Yes, don't delete
             cmp      dh,day          ; 31st or after?
             jge      next            ; Yes, don't delete
             delete_entry  buffer[1EH] ; THIS FUNCTION
             jc       error_delete    ; Routine not shown
             inc      files           ; Bump file counter
   next:     find_next_file           ; Check directory
             jnc      compare         ; Go home if done
   how_many: cmp      files,0         ; Was directory empty?
             je       all_done        ; Yes, go home
             convert  files,10,message ; See end of chapter
   all_done: display  message         ; See Function 09H
             select_disk "A"          ; See Function 0EH


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Move File Pointer (Function 42H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 42H
   AL
      Method of moving
   BX
      Handle
   CX:DX
      Distance in bytes (offset)

   Return:

   Carry set:
   AX
      1 = Invalid function
      6 = Invalid handle
   Carry not set:
   DX:AX
      New read/write pointer location


   Comments:

   Function 42H moves the read/write pointer of the file associated with the
   specified handle. BX must contain the handle. CX and DX must contain a
   32-bit offset (CX contains the most significant byte). AL must contain a
   code that specifies how to move the pointer:

   Code               Cursor Moved to
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0                  Beginning of file plus the offset
   1                  Current pointer location plus the offset
   2                  End of file plus the offset
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   DX and AX return the new location of the read/write pointer (a 32-bit
   integer; DX contains the most significant byte). You can determine the
   length of a file by setting CX:DX to 0, AL to 2, and calling this
   function. DX:AX returns the offset of the byte following the last byte in
   the file (size of the file in bytes). If there is an error, the carry flag
   (CF) is set and the error code returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  AL not 0, 1, or 2
   6                  Handle not open
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   move_ptr  macro  handle,high,low,method
             mov    bx,handle
             mov    cx,high
             mov    dx,low
             mov    al,method
             mov    ah,42H
             int    21H
             endm

   Example:

   The following program prompts for a letter, converts it to its alphabetic
   sequence (A=1, B=2, etc.), then reads and displays the corresponding
   record from the file named alphabet.dat that is in the current directory
   on the disk in drive B. The file contains 26 records, each 28 bytes long.

   file      db      "b:alphabet.dat",0
   buffer    db       28 dup (?),"$"
   prompt    db      "Enter letter: $"
   crlf      db       0DH,0AH,"$"
   handle    db       ?
   record_length  dw  28
   ;
   begin:    open_handle  file,0    ; See Function 3DH
             jc       error_open    ; Routine not shown
             mov      handle,ax     ; Save handle
   get_char: display  prompt        ; See Function 09H
             read_kbd_and_echo      ; See Function 01H
             sub      al,41h        ; Convert to sequence
             mul      byte ptr record_length  ; Calculate offset
             move_ptr handle,0,ax,0 ; THIS FUNCTION
             jc       error_move    ; Routine not shown
             read_handle handle,buffer,record_length
             jc       error_read    ; Routine not shown
             cmp      ax,0          ; End of file?
             je       return        ; Yes, go home
             display  crlf          ; See Function 09H
             display  buffer        ; See Function 09H
             display  crlf          ; See Function 09H
             jmp      get_char      ; Get another character


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get/Set File Attributes (Function 43H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 43H
   AL
      0 = Get attributes
      1 = Set attributes
   CX (if AL=1)
      Attributes to be set
   DS:DX
      Pointer to pathname

   Return:

   Carry set:
   AX
      1 = Invalid function
      2 = File not found
      3 = Path not found
      5 = Access denied
   Carry not set:
   CX
      Attribute byte (if AL=0)


   Comments:

   Function 43H gets or sets the attributes of a file. DX must contain the
   offset (from the segment address in DS) of an ASCIZ string that specifies
   the pathname of a file. AL must specify whether to get or set the
   attribute (0=get, 1=set).

   If AL is 0 (get the attribute), the attribute byte returns in CX. If AL is
   1 (set the attribute), CX must contain the attributes to be set. See
   Section 1.5.5, "File Attributes," for a description of the attributes.

   You cannot change the VolumeID bit (08H) or the Subdirectory bit (10H) of
   the attribute byte with this function.

   If there is an error, the carry flag (CF) is set and the error code
   returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  AL not 0 or 1

   2                  File doesn't exist

   3                  Path invalid

   5                  Attribute in CX cannot be changed (Subdirectory or
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   change_attr  macro  path,action,attrib
                mov    dx,offset path
                mov    al,action
                mov    cx,attrib
                mov    ah,43H
                int    21H
                endm

   Example:

   The following program displays the attributes assigned to the file named
   report.asm that is in the current directory on the disk in drive B.

   header    db      15 dup (20h),"Read-",0DH,0AH
             db     "Filename       Only      Hidden    "
             db     "System    Volume    Sub-Dir   Archive"
             db      0DH,0AH,0DH,0AH,"$"
   path      db     "b:report.asm",3 dup (0),"$"
   attribute dw      ?
   blanks    db      9 dup (20h),"$"
   ;
   begin:    change_attr  path,0,0  ; THIS FUNCTION
             jc      error_mode   ; Routine not shown
             mov     attribute,cx ; Save attribute byte
             display header       ; See Function 09H
             display path         ; See Function 09H
             mov     cx,6         ; Check 6 bits (0-5)
             mov     bx,1         ; Start with bit 0
   chk_bit:  test    attribute,bx ; Is the bit set?
             jz      no_attr      ; No
             display_char "X"     ; See Function 02H
             jmp short  next_bit  ; Done with this bit
   no_attr:  display_char  20h    ; See Function 02H
   next_bit: display blanks       ; See Function 09H
             shl     bx,1         ; Move to next bit
             loop    chk_bit      ; Check it


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 IOCtl Data (Function 44H, Codes 0 and 1)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 44H
   AL
      0 = Get device data
      1 = Set device data
   BX
      Handle
   DX
      Device data (see text)

   Return:

   Carry set:
   AX
      1 = Invalid function
      6 = Invalid handle
   Carry not set:
   DX
     Device data


   Comments:

   Function 44H, Codes 0 and 1, either gets or sets the data MS-DOS uses to
   control the device. AL must contain 0 to get the data or 1 to set it. BX
   must contain the handle. If AL is 1, DH must contain 0.

   The device-data word is specified or returned in DX. If bit 7 of the data
   is 1, the handle refers to a device and the other bits have the meanings
   shown in Table 1.23.

   Table 1.23
   MS-DOS Data Bit Values
ÖŚÄŚÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ·
   Bit        Value                Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Bit        Value                Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0          1                    Console input device

   1          1                    Console output device

   2          1                    Null device

   3          1                    Clock device

   4          1                    Reserved

   5          1                    Don't check for control characters

              0                    Check for control characters

   6          0                    End of file on input

   8-10                            Reserved

   11         1                    Device understands open/close
   Bit        Value                Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  11         1                    Device understands open/close

   12                              Reserved

   13         1                    Device supports output until busy

   14         1                    Device can process control strings sent
                                   with Functions 4402H and 4403H (IOCtl
                                   character); bit can be read only, but not
                                   set

   15                              Reserved
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


   You must set the reserved bits to zero.

   The control characters referred to in the description of bit 5 are
   CONTROL+C, CONTROL+P, CONTROL+S, and CONTROL+Z. To read these characters
   as data, instead of as control characters, you must set bit 5 and use
   either Function 33H, CONTROL+C Check, or the MS-DOS break command to turn
   off CONTROL+C checking.

   If bit 7 of DX is 0, the handle refers to a file and the other bits have
   the following meanings:

   Bit        Value                Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0-5                             Drive number (0=A, 1=B, etc.)
   6          0                    The file has been written
   8-15                            Reserved
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   If there is an error, the carry flag (CF) is set and the error code
   returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  AL not 0 or 1, or AL is 1 but DH is not 0
   6                  Handle in BX not open or is invalid
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   ioctl_data macro  code,handle
              mov    bx,handle
              mov    al,code
              mov    ah,44H
              int    21H
              endm

   Example:

   The following program gets the device data for standard output, sets the
   bit that specifies not to check for control characters (bit 5), and then
   clears the bit.

   get     equ         0
   set     equ         1
   stdout  equ         1
   ;
   begin:  ioctl_data  get,stdout          ; THIS FUNCTION
           jc          error               ; routine not shown
           mov         dh,0                ; clear DH
           or          dl,20H              ; set bit 5
           ioctl_data  set,stdout          ; THIS FUNCTION
           jc          error               ; routine not shown
   ;
   ;   <control characters now treated as data, or "raw mode">
   ;
           ioctl_data  get,stdout          ; THIS FUNCTION
           jc          error               ; routine not shown
           mov         dh,0                ; clear DH
           and         dl,0DFH             ; clear bit 5
           ioctl_data  set,stdout          ; THIS FUNCTION
   ;
   ;  <control characters now interpreted, or "cooked mode">
   ;


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 IOCtl Character (Function 44H, Codes 2 and 3)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 44H
   AL
      2 = Send control data
      3 = Receive control data
   BX
      Handle
   CX
      Bytes to read or write
   DS:DX
      Pointer to buffer

   Return:

   Carry set:
   AX
      1 = Invalid function
      6 = Invalid handle
   Carry not set:
   AX
      Bytes transferred


   Comments:

   Function 44H, Codes 2 and 3, sends or receives control data to or from a
   character device. AL must contain 2 to send data or 3 to receive. BX must
   contain the handle of a character device, such as a printer or serial
   port. CX must contain the number of bytes to be read or written. DX must
   contain the offset (to the segment address in DS) of the data buffer.

   AX returns the number of bytes transferred. The device driver must support
   the IOCtl interface. If there is an error, the carry flag (CF) is set and
   the error code returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  AL not 2 or 3, or device cannot perform the specified
                      function

   6                  Handle in BX not open or doesn't exist
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   ioctl_char  macro  code,handle,buffer
               mov    bx,handle
               mov    dx,offset buffer
               mov    al,code
               mov    ah,44H
               int    21H
               endm


   Example:

   No general example is applicable, since processing of IOCtl control data
   depends on the device being used, as well as the device driver.


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 IOCtl Block (Function 44H, Codes 4 and 5)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 44H
   AL
      4 = Send control data
      5 = Receive control data
   BL
      Drive number (0=default, 1=A, etc.)
   CX
      Bytes to read or write
   DS:DX
      Pointer to buffer

   Return:

   Carry set:
   AX
      1 = Invalid function
      5 = Invalid drive
   Carry not set:
   AX
      Bytes transferred


   Comments:

   Function 44H, Codes 4 and 5, sends or receives control data to or from a
   block device. AL must contain 4 to send data or 5 to receive. BL must
   contain the drive number (0=default, 1=A, etc.). CX must contain the
   number of bytes to be read or written. DX must contain the offset (to the
   segment address in DS) of the data buffer.

   AX returns the number of bytes transferred. The device driver must support
   the IOCtl interface. To determine whether or not it does, use Function
   4400H to get the device data, and test bit 14; if the bit is set, the
   driver supports IOCtl. If there is an error, the carry flag (CF) is set
   and the error code returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  AL not 4 or 5, or device cannot perform the specified
                      function

   5                  Number in BL not a valid drive number
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   ioctl_status macro  code,drive,buffer
                mov    bl,drive
                mov    dx,offset buffer
                mov    al,code
                mov    ah,44H
                int    21H
                endm

   Example:

   No general example is applicable, since processing of IOCtl control data
   depends on the device being used, as well as the device driver.


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 IOCtl Status (Function 44H, Codes 6 and 7)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 44H
   AL
      6 = Check input status
      7 = Check output status
   BX
      Handle

   Return:

   Carry set:
   AX
      1        = Invalid function
      5        = Access denied
      6        = Invalid handle
     13        = Invalid data
   Carry not set:
   AL
      00H = Not ready
      0FFH = Ready


   Comments:

   Function 44H, Codes 6 and 7, checks whether or not the file or device
   associated with a handle is ready. AL must contain 6 to check whether the
   handle is ready for input or 7 to check whether the handle is ready for
   output. BX must contain the handle.

   AL returns the status:

                  Meaning for    Meaning for            Meaning for
   Value          Device         Input File            Output File
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   00H            Not ready      Pointer is at EOF     Ready
   0FFH           Ready          Ready                 Ready
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   An output file always returns ready, even if the disk is full. bp If there
   is an error, the carry flag (CF) is set and the error code returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  AL not 6 or 7
   5                  Access denied
   6                  Number in BX not a valid, open handle
   13                 Invalid data
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   ioctl_status  macro  code,handle
                 mov    bx,handle
                 mov    al,code
                 mov    ah,44H
                 int    21H
                 endm

   Example:

   The following program displays a message that tells whether the file
   associated with handle 6 is ready for input or whether it is at
   end-of-file.

   stdout      equ          1
   ;
   message     db           "File is "
   ready       db           "ready."
   at_eof      db           "at EOF."
   crlf        db           ODH,OAH
   ;
   begin:      write_handle stdout,message,8   ; display message
               jc           write_error        ; routine not shown
               ioctl_status 6                  ; THIS FUNCTION
               jc           ioctl_error        ; routine not shown
               cmp          al,0               ; check status code
               jne          not_eof            ; file is ready
               write_handle stdout,at_eof,7    ; see Function 40H
               jc           write_error        ; routine not shown
               jmp          all_done           ; clean up & go home
   not_eof:    write_handle stdout,ready,6     ; see Function 40H
   all_done:   write_handle stdout,crlf,2      ; see Function 40H
               jc           write_error        ; routine not shown


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 IOCtl Is Changeable (Function 44H, Code 08H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 44H
   AL = 08H
   BL
      Drive number (0=default, 1=A, etc.)

   Return:

   Carry set:
   AX
       1        = Invalid function
      15        = Invalid drive
   Carry not set:
   AX
      0 = Changeable
      1 = Not changeable


   Comments:

   Function 44H, Code 08H, checks whether a drive contains a removable or
   nonremovable disk. BL must contain the drive number (0=default, 1=A,
   etc.). AX returns 0 if the disk can be changed, 1 if it cannot.

   This call lets a program determine whether or not to issue a message to
   change disks.

   If there is an error, the carry flag (CF) is set and the error code
   returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  Device does not support this call
   15                 Number in BL not a valid drive number
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   When the call returns error 1 (because the driver doesn't support it), the
   caller assumes that the driver cannot be changed.

   Macro Definition:

   ioctl_change  macro  drive
                 mov    bl, drive
                 mov    al, 08H
                 mov    ah, 44H
                 int    21H
                 endm

   Example:

   The following program checks whether or not the current drive contains a
   removable disk. If not, processing continues; if so, the program prompts
   the user to replace the disk in the current drive.

   stdout    equ        1
   ;
   message   db        "Please replace disk in drive "
   drives    db        "ABCD"
   crlf      db         0DH,0AH
   ;
   begin:    ioctl_change 0          ; THIS FUNCTION
             jc           ioctl_error ; routine not shown
             cmp          ax,0       ; current drive changeable?
             jne          continue   ; no, continue processing
             write_handle stdout,message,29 ; see Function 40H
             jc           write_error ; routine not shown
             current_disk            ; see Function 19H
             xor          bx,bx      ; clear index
             mov          bl,al      ; get current drive
             display_char drives[bx] ; see Function 02H
             write_handle stdout,crlf,2 ; see Function 40H
             jc           write_error ; routine not shown
   continue:
   ;          (Further processing here)


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 IOCtl Is Redirected Block (Function 44H, Code 09H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 44H
   AL = 09H
   BL
      Drive number (0=default, 1=A, etc.)

   Return:

   Carry set:
   AX
      1        = Invalid function code
     15        = Invalid drive number
   Carry not set:
   DX
      Device-attribute bits


   Comments:

   Function 44H, Code 09H, checks whether a drive letter refers to a drive on
   a Microsoft Networks workstation (local) or is redirected to a server
   (remote). BL must contain the drive number (0=default, 1=A, etc.).

   If the block device is local, DX returns the attribute word from the
   device header. If the block device is remote, only bit 12 (1000H) is set;
   the other bits are 0 (reserved).

   An application program should not test bit 12, because applications should
   not make distinctions between local and remote files (or devices).
   Programs should be written so that they will be independent of the
   location of a device that has been removed.

   If there is an error, the carry flag (CF) is set and the error code
   returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  File sharing must be loaded to use this system call
   15                 Number in BL not a valid drive number
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   ioctl_rblock  macro  drive
                 mov    bl, drive
                 mov    al, 09H
                 mov    ah, 44H
                 int    21H
                 endm

   Example:

   The following program checks whether or not drive B is local or remote and
   displays the appropriate message.

   stdout    equ        1
   ;
   message   db        "Drive B: is "
   loc       db        "local."
   rem       db        "remote."
   crlf      db         0DH,0AH
   ;
   begin:    write_handle stdout,message,12  ; display message
             jc           write_error      ; routine not shown
             ioctl_rblock 2                ; THIS FUNCTION
             jc           ioctl_error      ; routine not shown
             test         dx,1000h         ; bit 12 set?
             jnz          not_loc          ; yes, it's remote
             write_handle stdout,loc,6     ; see Function 40H
             jc           write_error      ; routine not shown
             jmp          done
   not_loc:  write_handle stdout,rem,7     ; see Function 40H
             jc           write_error      ; routine not shown
   done:     write_handle stdout,crlf,2    ; see Function 40H
             jc           write_error      ; routine not shown


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 IOCtl Is Redirected Handle (Function 44H, Code 0AH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 44H
   AL = 0AH
   BX
      Handle

   Return:

   Carry set:
   AX
      1 = Invalid function code
      6 = Invalid handle
   Carry not set:
   DX
      IOCtl bit field


   Comments:

   Function 44H, Code 0AH, checks whether a handle refers to a file or a
   device on a Microsoft Networks workstation (local) or is redirected to a
   server (remote). BX must contain the file handle. DX returns the IOCtl bit
   field; bit 15 is set if the handle refers to a remote file or device.

   An application program should not test bit 15, because applications should
   not make distinctions between local and remote files (or devices).
   Programs should be written so that they will be independent of the
   location of a device that has been removed.

   If there is an error, the carry flag (CF) is set and the error code
   returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  Network must be loaded to use this system call
   6                  Handle in BX not a valid, open handle
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   ioctl_rhandle macro  handle
                 mov    bx, handle
                 mov    al, 0AH
                 mov    ah, 44H
                 int    21H
                 endm

   Example:

   The following program checks whether handle 5 refers to a local or remote
   file or a device and displays the appropriate message.

   stdout    equ        1
   ;
   message   db        "Handle 5 is "
   loc       db        "local."
   rem       db        "remote."
   crlf      db         0DH,0AH
   ;
   begin:    write_handle stdout,message,12; display message
             jc           write_error      ; routine not shown
             ioctl_rhandle 5               ; THIS FUNCTION
             jc           ioctl_error      ; routine not shown
             test         dx,8000h         ; bit 15 set?
             jnz          not_loc          ; yes, it's remote
             write_handle stdout,loc,6     ; see Function 40H
             jc           write_error      ; routine not shown
             jmp          done
   not_loc:  write_handle stdout,rem,7     ; see Function 40H
             jc           write_error      ; routine not shown
   done:     write_handle stdout,crlf,2    ; see Function 40H
             jc           write_error      ; routine not shown


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 IOCtl Retry (Function 44H, Code 0BH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 44H
   AL = 0BH
   DX
      Number of retries
   CX
      Wait time

   Return:

   Carry set:
   AX
      1 = Invalid function code
   Carry not set:
      No error


   Comments:

   Function 44H, Code 0BH, specifies how many times MS-DOS should retry a
   disk operation that fails because of a file-sharing violation. DX must
   contain the number of retries. CX controls the pause between retries.

   MS-DOS retries this type of disk operation three times, unless you use
   this system call to specify a different number. After the specified number
   of retries, MS-DOS issues Interrupt 24H (Critical-Error-Handler Address)
   for the requesting process.

   The effect of the delay parameter in CX is machine-dependent because it
   specifies how many times MS-DOS should execute an empty loop. The actual
   time varies, depending on the processor and clock speed. You can determine
   the effect on your machine by using debug. Set the number of retries to 1
   and then time several values of CX. If there is an error, the carry flag
   (CF) is set and the error code returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  File sharing must be loaded to use this system call
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   ioctl_retry  macro  retries, wait
                mov    dx, retries
                mov    cx, wait
                mov    al, 0BH
                mov    ah, 44H
                int    21H
                endm

   Example:

   The following program sets the number of sharing retries to 10 and
   specifies a delay of 1000 between retries.

   begin:    ioctl_retry  10,1000          ; THIS FUNCTION
             jc           error            ; routine not shown


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Generic IOCtl (for Handles) (Function 44H, Code 0CH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 44H
   AL = 0CH
   BX
       Handle
   CH = 05H
       Category code (printer device)
   CL
       Function (minor) code
   DS:DX
       Pointer to data buffer

   Return:

   Carry set:
   AX
       1        = Invalid function code
      --        = Any device error
   Carry not set:
       No error


   Comments:

   This call loads and selects code pages for devices on a per-device basis.
   It also sets or gets the output iteration count for a printer that
   supports "PRINT 'TIL BUSY."

   The video functions (type=display) are supported only if ansi.sys has been
   installed. If ansi.sys is not installed, mode sets the video state
   directly. This information reflects the latest mode command or any changes
   made by use of BIOS. This call uses BIO to get and set the states.

   The MS-DOS 4.0 mode command sets the values through this interface and the
   DOS utilities access the information through this interface.

   The category code may be one of the following:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   00                 Unknown device
   01                 Serial printer
   03                 Console (display) device
   05                 Parallel printer
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   The function code may be one of the following:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   45H                Sets iteration count for printer
   4AH                Selects code page
   4CH                Starts prepare list
   4DH                Ends prepare list
   5FH                Sets display device
   65H                Gets iteration count for printer
   6AH                Query code page selected
   6BH                Query code page prepare list
   7FH                Gets display character (screen width, length, and
                      color)
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     DS:DX points to a word that contains the new value for the total number
     of output iterations performed before proceeding. Thus, DS:DX points to
     a word that contains the character iteration count for the "PRINT 'TIL
     BUSY" loop. This is the number of times the device driver will wait for
     the device to signal "ready" before acknowledging "Device busy."
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   ioctl_handles        macro handle,function,category,buffer
                   mov ch,05H
                   mov cl,function
                   mov dx,offset buffer
                   mov bx,handle
                   mov ah,44H
                   mov al,0CH
                   int 21H
                   endm

   Example:

   The following program obtains device characteristics.

           mov    ax,440CH    ; Handle based generic IOCTL
           mov    bx,handle   ; Handle of open device
           mov    ch,03H      ; Type = display
           mov    cl,7FH      ; Subfunction for get
           lds    dx,buffer   ; Info buffer
           int    21H
           jc     error
        buffer  label  byte   ; Return buffer
           db     0           ; Info level (set to 0
                              ; before call)
           db     0           ; reserved    (")
                              ; for type display
           dw     7*2         ; length of data
           dw     flags       ; control flags
                              ; 0001H=intense (vs blink)
                              ; display mode
                              ; 1=text
                              ; 2=APA
           db     0           ; reserved
           dw     colors      ; # of colors (monochrome=0)
           dw     width       ; width of display (pixels)
           dw     length      ; length of display (pixels)
           dw     cols        ; width of display (chars)
           dw     rows        ; length of display (lines)

   To fetch code-page information, return the DBCS range vector and add the
   following:

           mov    ax=440Ch    ; Handle generic IOCTL
           mov    cx,036AH    ; Query display
           mov    bx,handle
           lds    dx,buffer   ; change buffer content
           int    21H
           jc     error

       Buffer   Label   Word
           dw   end-start     ; length
   start:
           dw   codepage      ; code page
           db   s1,e1         ; DBCS range
           db   0,0           ; end of list

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     Some device drivers may only support the codepage value. As a result,
     the user of this call must check the returned length before assuming the
     DBCS information is present. The display.sys and printer.sys device
     drivers do not need to support the DBCS information. Only the drivers
     supplied with the Asian MS-DOS 4.0 will provide this support.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Generic IOCtl (for Devices) (Function 44H, Code 0DH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 44H
   AL = 0DH
   BL
       Drive number
           (0 = default, 1 = A, etc.)
   CH = 08H
       Category (major) code
   CL
       Function (minor) code
   DS:DX
       Pointer to parameter block -1

   Return:

   Carry set:
   AX
       1        = Invalid function code
       2        = Invalid drive
       -        = Any device error
   Carry not set:
       No error


   Comments:

   The function code may be one of the following:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   40                 Set device parameters
   41                 Write track on logical device
   42                 Format track on logical device
   60                 Get device parameters
   61                 Read track on logical device
   62                 Verify track on logical device
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     You must issue "Set Parameters Device" before you can read, write,
     format, or verify a logical drive.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   You should use the following procedure when you want to read, write,
   format, or verify a logical drive:

   1. Save drive parameters using "Get Device Parameters."

   2. Set desired drive parameters using "Set Device Parameters."

   3. Perform the I/O operation.

   4. Restore the original drive parameters using "Set Device Parameters."

   Set Device Parameters (Function 440DH, CL=40H)

   When CL=40H, the parameter block has the following field format:

   ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³ BYTE      Special Functions        ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ BYTE      Device Type              ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ WORD      Device Attributes        ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ WORD      Number of Cylinders      ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ BYTE      Media Type               ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³           Device BPB               ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³           Track Layout             ³
   ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   These fields have the following meanings:

   Special Functions

ÖŚÄŚÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ·
   Bit        Value     Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Bit        Value     Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0          0         The Device BPB (BIOS Parameter Block) field contains
                        the new default BPB for this device. If a previous
                        Set Device Parameters call set this bit, Build BPB
                        returns the actual media BPB otherwise, it returns
                        the default BPB for the device.

              1         All subsequent Build BPB requests return the device
                        BPB.

   1          0         Read all fields of the parameter block.

              1         Ignore all fields of the parameter block except for
                        the Track Layout field.

   2          0         The sectors in the track may not all be the same
                        size. (You should not use this setting.)

              1         The sectors in the track are all the same size and
                        the sector numbers range between 1 and the total
   Bit        Value     Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
                       the sector numbers range between 1 and the total
                        number of sectors actually in the track. You should
                        always set this bit.

   3-7        0         These bits must be zero.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


   Device Type

   This byte describes the physical device and is set by the device. When
   set, it has the following meanings:

   Value                                Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0                                    320/360kilobytes
   1                                    1.2 megabytes
   2                                    720 kilobytes
   3                                    8-inch, single-density
   4                                    8-inch, double-density
   5                                    Hard disk
   6                                    Tape drive
   7                                    1.44 megabytes
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Device Attributes

   Bit     Value            Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
           0                The media is removable.
   0       1                The media is not removable.
   1       0                Disk change-line is not supported (no door lock
                            support).
           1                Disk change-line is supported (door lock
                            support).
   2-7     0                These bits must be zero.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Number of Cylinders

   This field indicates the maximum number of cylinders that the physical
   device can support. This information is set by the device.

   Media Type

   For drives that may contain different media, this field (which is
   device-dependent) indicates which media the drive expects.

   For a 1.2-megabyte disk, bit zero has the following meaning:

   Bit        Value                Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0          0                    Quad-density, 1.2-megabyte disk
              1                    Double-density, 320/360-kilobyte disk
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   The default media type is a quad-density, 1.2-megabyte disk.

   Device BPB

   If bit 0 of the Special Functions field is clear, the BPB in this field is
   the new default BPB for the device.

   If bit 0 of the Special Functions field is set, the device driver returns
   the BPB from this field for subsequent Build BPB requests.

   Track Layout

   This field contains a table of variable length for each logical device and
   indicates the expected layout of the sectors on the media track. The field
   has the following format:

   ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³ WORD      Sector Count -- total # of sectors ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ WORD      Sector Number -- sector #1         ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ WORD      Sector Size -- sector #1           ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ WORD      Sector Number -- sector #2         ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ WORD      Sector Size -- sector #2           ³
   ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ
                         .
                         .
                         .
   ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³ WORD      Sector Number -- sector #n         ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ³
   ³ WORD      Sector Size -- sector #n           ³
   ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   The Sector Count field indicates the total number of sectors. Each sector
   number must be unique and in the range of 1 to sector count (n).

   If bit 2 of the Special Functions field is set, all sector sizes must be
   the same.

   Get Device Parameters (Function 440DH, CL=60H)

   When CL=60H, the parameter block has the same field layout as for CL=40H.
   However, some of the fields have different meanings. These are described
   as follows:

   Special Functions

   Bit     Value            Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0       0                Returns the default BPB for the device.
           1                Returns the BPB that Build BPB would return.
   1-7     0                These bits must be zero.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Track Layout

   The Get Device Parameters call does not use this field.

   Read/Write Track on Logical Drive (Function 440DH, CL=61H/CL=41H)

   To write to a track on a logical drive, set CL=41H. To read a track on a
   logical drive, set CL=61H.

   When CL=41H or 61H, the parameter block has the following format:

   ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³ BYTE      Special Functions  ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ WORD      Head               ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ WORD      Cylinder           ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ WORD      First Sector       ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ WORD      Number of Sectors  ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ³
   ³ DWORD     Transfer Address   ³
   ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   These fields are described as follows:

   Special Functions

   This byte must be zero.

   Head

   This field contains the number of the head on which you perform the write
   or read.

   Cylinder

   This field contains the number of the cylinder on which you perform the
   write or read.

   First Sector

   This field contains the number of the first sector on which you perform
   the write or read. Sectors are numbered starting with zero, so the fourth
   sector is numbered 3.

   Number of Sectors

   This field contains the total number of sectors.

   Transfer Address

   This field contains the address for storing the data to be written or the
   data just read.

   Format/Verify Track on Logical Drive (Function 440DH, CL=42H/CL=62H)

   To format and verify a track on a logical drive, set CL=42H. To verify a
   track on a logical drive, set CL=62H.

   When CL=42H or 62H, the parameter block has the following format:

   ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³ BYTE      Special Functions  ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ WORD      Head               ³
   ³ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ WORD      Cylinder           ³
   ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   These fields are described as follows:

   Special Functions

   This byte must be zero.

   Head

   This field contains the number of the head on which you perform the format
   or verify.

   Cylinder

   This field contains the number of the cylinder on which you perform the
   format or verify.


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get/Set IOCtl Drive Map (Function 44H, Codes 0EH and 0FH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 44H
   AL
       OEH = Get logical drive map
       OFH = Set logical drive map
   BX
       Drive number
           (0 = default, 1 = A, etc.)

   Return:

   Carry set:
   AX
       1 = Invalid function code
       5 = Invalid drive
   Carry not set:
   AL = Logical drive mapped onto physical drive
        (= 0 if only one drive is
        assigned to this physical drive)


   Comments:

   MS-DOS supports the mapping of multiple logical drives onto a single
   physical block device. Get IOCtl Drive Map lets you query the DOS about
   which logical drive is currently mapped onto the corresponding physical
   device. Set IOCtl Drive Map alters the device that is currently mapped
   onto the physical device. These functions are only useful if there is more
   than one logical block device mapped onto a single physical device.

   A possible use for these functions is with applications that want to
   disable the DOS prompt in order to place the correct floppy disk in the
   drive when accessing the other logical drive.

   To detect whether or not a logical device currently owns the physical
   device to which it is mapped, a program needs to check the value in AL
   after calling Function 440EH or 440FH (Get/Set IOCtl Drive Map).


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Duplicate File Handle (Function 45H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 45H
   BX
      Handle

   Return:

   Carry set:
   AX
      4 = Too many open files
      6 = Invalid handle
   Carry not set:
   AX
      New handle


   Comments:

   Function 45H creates an additional handle for a file. BX must contain the
   handle of an open file.

   MS-DOS returns the new handle in AX. The new handle refers to the same
   file as the handle in BX, with the file pointer at the same position.

   After you use this function request, moving the read/write pointer of
   either handle also moves the pointer for the other handle. You usually use
   this function request to redirect standard input (handle 0) and standard
   output (handle 1). For a description of standard input, standard output,
   and the advantages and techniques of manipulating them, see Software Tools
   by Brian W. Kernighan and P.J. Plauger (Addison-Wesley Publishing Co.,
   1976).

   If there is an error, the carry flag (CF) is set and the error code
   returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   4                  Too many open files (no handle available)
   6                  Handle not open or is invalid
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   xdup  macro  handle
         mov    bx,handle
         mov    ah,45H
         int    21H
         endm

   Example:

   The following program redirects standard output (handle 1) to a file named
   dirfile, invokes a second copy of command.com to list the directory (which
   writes the directory to dirfile), and then restores standard input to
   handle 1.

   pgm_file  db    "command.com",0
   cmd_line  db    9,"/c dir /w",0dH
   parm_blk  db    14 dup (0)
   path            db  "dirfile",0
   dir_file        dw      ?       ;  For handle
   sav_stdout dw   ?               ;  For handle
   ;
   begin:    set_block  last_inst  ;  See Function 4AH
             jc      error_setblk  ;  Routine not shown
             create_handle  path,0 ;  See Function 3CH
             jc      error_create  ;  Routine not shown
             mov     dir_file,ax   ;  Save handle
             xdup    1             ;  THIS FUNCTION
             jc      error_xdup    ;  Routine not shown
             mov     sav_stdout,ax ;  Save handle
             xdup2   dir_file,1    ;  See Function 46H
             jc      error_xdup2   ;  Routine not shown
             exec    pgm_file,cmd_line,parm_blk ;  See Function 4BH
             jc      error_exec    ;  Routine not shown
             xdup2   sav_stdout,1  ;  See Function 46H
             jc      error_xdup2   ;  Routine not shown
             close_handle sav_stdout ;  See Function 3EH
             jc      error_close   ;  Routine not shown
             close_handle dir_file ;  See Function 3EH
             jc      error_close   ;  Routine not shown


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Force Duplicate File Handle (Function 46H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 46H
   BX
      Handle
   CX
      Second handle

   Return:

   Carry set:
   AX
      4 = Too many open files
      6 = Invalid handle
   Carry not set:
      No error


   Comments:

   Function 46H forces a specified handle to refer to the same file as a
   second handle already associated with an open file. BX must contain the
   handle of the open file; CX must contain the second handle.

   On return, the handle in CX now refers to the same file at the same
   position as the handle in BX. If the file referred to by the handle in CX
   was open at the time of the call, this function closes it.

   After you use this call, moving the read/write pointer of either handle
   also moves the pointer for the other handle. Normally, you would use this
   function request to redirect standard input (handle 0) and standard output
   (handle 1). For a description of standard input, standard output, and the
   advantages and techniques of manipulating them, see Software Tools by
   Brian W. Kernighan and P.J. Plauger (Addison-Wesley Publishing Co., 1976).

   If there is an error, the carry flag (CF) is set and the error code
   returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   4                  Too many open files (no handle available)
   6                  Handle not open or is invalid
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   xdup2  macro  handle1,handle2
          mov    bx,handle1
          mov    cx,handle2
          mov    ah,46H
          int    21H
          endm

   Example:

   The following program redirects standard output (handle 1) to a file named
   dirfile, invokes a second copy of command.com to list the directory (which
   writes the directory to dirfile), and then restores standard input to
   handle 1.

   pgm_file  db    "command.com",0
   cmd_line  db    9,"/c dir /w",0dH
   parm_blk  db    14 dup (0)
   path            db  "dirfile",0
   dir_file        dw      ?       ;  For handle
   sav_stdout dw   ?               ;  For handle
   ;
   begin:    set_block  last_inst  ;  See Function 4AH
             jc      error_setblk  ;  Routine not shown
             create_handle  path,0 ;  See Function 3CH
             jc      error_create  ;  Routine not shown
             mov     dir_file,ax   ;  Save handle
             xdup    1             ;  See Function 45H
             jc      error_xdup    ;  Routine not shown
             mov     sav_stdout,ax ;  Save handle
             xdup2   dir_file,1    ;
             jc      error_xdup2   ;  Routine not shown
             exec    pgm_file,cmd_line,parm_blk ;  See Function 4BH
             jc      error_exec    ;  Routine not shown
             xdup2   sav_stdout,1  ;  THIS FUNCTION
             jc      error_xdup2   ;  Routine not shown
             close_handle sav_stdout ;  See Function 3EH
             jc      error_close   ;  Routine not shown
             close_handle dir_file ;  See Function 3EH
             jc      error_close   ;  Routine not shown


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get Current Directory (Function 47H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 47H
   DS:SI
      Pointer to 64-byte memory area
   DL
      Drive number
           (0 = default, 1 = A, etc.)

   Return:

   Carry set:
   AX
      15 = Invalid drive number
   Carry not set:
      No error


   Comments:

   Function 47H returns the pathname of the current directory on a specified
   drive. DL must contain a drive number (0=default, 1=A, etc.). SI must
   contain the offset (from the segment address in DS) of a 64-byte memory
   area.

   MS-DOS places an ASCIZ string in the memory area, consisting of the path
   (starting from the root directory) of the current directory for the drive
   specified in DL. The string does not begin with a backslash and does not
   include the drive letter.

   If there is an error, the carry flag (CF) is set and the error code
   returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   15                 Number in DL not a valid drive number
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   get_dir  macro   drive,buffer
            mov     dl,drive
            mov     si,offset buffer
            mov     ah,47H
            int     21H
            endm

   Example:

   The following program displays the current directory that is on the disk
   in drive B.

   disk        db      "b:\#"
   buffer      db       64 dup (?)
   ;
   begin:      get_dir  2,buffer       ; THIS FUNCTION
               jc       error_dir      ; Routine not shown
               display  disk           ; See Function 09H
               display_asciz  buffer  ; See end of chapter


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Allocate Memory (Function 48H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 48H
   BX
     Paragraphs of memory requested

   Return:

   Carry set:
   AX
     7 = Memory-control blocks damaged
     8 = Insufficient memory
   BX
     Paragraphs of memory available
   Carry not set:
   AX
     Segment address of allocated memory


   Comments:

   Function 48H tries to allocate the specified amount of memory to the
   current process. BX must contain the number of paragraphs of memory (one
   paragraph is 16 bytes).

   If sufficient memory is available to satisfy the request, AX returns the
   segment address of the allocated memory (the offset is 0). If sufficient
   memory is not available, BX returns the number of paragraphs of memory in
   the largest available block.

   If there is an error, the carry flag (CF) is set and the error code
   returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   7                  Memory-control blocks damaged (a user program changed
                      memory that didn't belong to it)

   8                  Not enough free memory to satisfy the request
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   allocate_memory  macro   bytes
                    mov     bx,bytes
                    mov     cl,4
                    shr     bx,cl
                    inc     bx
                    mov     ah,48H
                    int     21H
                    endm

   Example:

   The following program opens the file named textfile.asc, calculates its
   size with Function 42H (Move File Pointer), allocates a block of memory
   the size of the file, reads the file into the allocated memory block, and
   then frees the allocated memory.

   path      db      "textfile.asc",0
   msg1      db      "File loaded into allocated memory block.",
                      0DH,0AH
   msg2      db      "Allocated memory now being freed
                      (deallocated).",0DH,0AH
   handle    dw       ?
   mem_seg   dw       ?
   file_len  dw       ?
   ;
   begin:    open_handle  path,0
             jc       error_open    ; Routine not shown
             mov      handle,ax     ; Save handle
             move_ptr handle,0,0,2  ; See Function 42H
             jc       error_move    ; Routine not shown
             mov      file_len,ax   ; Save file length
             set_block  last_inst   ; See Function 4AH
             jc       error_setblk  ; Routine not shown
             allocate_memory  file_len ; THIS FUNCTION
             jc       error_alloc   ; Routine not shown
             mov      mem_seg,ax    ; Save address of new memory
             move_ptr handle,0,0,0  ; See Function 42H
             jc       error_move    ; Routine not shown
             push     ds            ; Save DS
             mov      ax,mem_seg    ; Get segment of new memory
             mov      ds,ax         ; Point DS at new memory
             read_handle  cs:handle,0,cs:file_len ; Read file into
   ;                                                new memory
             pop      ds            ; Restore DS
             jc       error_read    ; Routine not shown
   ;          (CODE TO PROCESS FILE GOES HERE)
             write_handle stdout,msg1,42 ; See Function 40H
             jc       write_error   ; Routine not shown
             free_memory  mem_seg   ; See Function 49H
             jc       error_freemem ; Routine not shown
             write_handle stdout,msg2,49 ; See Function 40H
             jc       write_error   ; Routine not shown


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Free Allocated Memory (Function 49H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 49H
   ES
      Segment address of memory to be
      freed

   Return:

   Carry set:
   AX
      7 = Memory-control blocks damaged
      9 = Incorrect segment
   Carry not set:
      No error


   Comments:

   Function 49H frees (makes available) a block of memory previously
   allocated with Function 48H (Allocate Memory). ES must contain the
   segment address of the memory block to be freed.

   If there is an error, the carry flag (CF) is set and the error code
   returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   7                  Memory-control blocks damaged (a user program changed
                      memory that didn't belong to it)

   9                  Memory pointed to by ES was not allocated with
                      Function 48H
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   free_memory  macro   seg_addr
                mov     ax,seg_addr
                mov     es,ax
                mov     ah,49H
                int     21H
                endm

   Example:

   The following program opens a file named textfile.asc, calculates its size
   with Function 42H (Move File Pointer), allocates a block of memory the
   size of the file, reads the file into the allocated memory block, and then
   frees the allocated memory.

   path      db      "textfile.asc",0
   msg1      db      "File loaded into allocated memory block.",
                      0DH,0AH
   msg2      db      "Allocated memory now being freed
                      (deallocated).",0DH,0AH
   handle    dw       ?
   mem_seg   dw       ?
   file_len  dw       ?
   ;
   begin:    open_handle  path,0
             jc       error_open    ; Routine not shown
             mov      handle,ax     ; Save handle
             move_ptr handle,0,0,2  ; See Function 42H
             jc       error_move    ; Routine not shown
             mov      file_len,ax   ; Save file length
             set_block  last_inst   ; See Function 4AH
             jc       error_setblk  ; Routine not shown
             allocate_memory  file_len ; See Function 48H
             jc       error_alloc   ; Routine not shown
             mov      mem_seg,ax    ; Save address of new memory
             mov_ptr  handle,0,0,0  ; See Function 42H
             jc       error_move    ; Routine not shown
             push     ds            ; Save DS
             mov      ax,mem_seg    ; Get segment of new memory
             mov      ds,ax         ; Point DS at new memory
             read_handle  handle,code,file_len ; Read file into
   ;                                             new memory
             pop      ds            ; Restore DS
             jc       error_read    ; Routine not shown
   ;          (CODE TO PROCESS FILE GOES HERE)
             write_handle stdout,msg1,42 ; See Function 40H
             jc       write_error   ; Routine not shown
             free_memory  mem_seg   ; THIS FUNCTION
             jc       error_freemem ; Routine not shown
             write_handle stdout,msg2,49 ; See Function 40H
             jc       write_error   ; Routine not shown


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Set Block (Function 4AH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 4AH
   BX
      Paragraphs of memory
   ES
      Segment address of memory area

   Return:

   Carry set:
   AX
      7 = Memory-control blocks damaged
      8 = Insufficient memory
      9 = Incorrect segment
   BX
      Paragraphs of memory available
   Carry not set:
      No error


   Comments:

   Function 4AH changes the size of a memory-allocation block. ES must
   contain the segment address of the memory block. BX must contain the new
   size of the memory block, in paragraphs (one paragraph is 16 bytes).

   MS-DOS attempts to change the size of the memory block. If the call fails
   on a request to increase memory, BX returns the maximum size (in
   paragraphs) to which the block can be increased.

   Since MS-DOS allocates all available memory to a .com program, you would
   use this call most often to reduce the size of a program's initial
   memory-allocation block.

   If there is an error, the carry flag (CF) is set and the error code
   returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   7                  Memory-control blocks destroyed (a user program changed
                      memory that didn't belong to it)

   8                  Not enough free memory to satisfy the request

   9                  Wrong address in ES (the memory block it points to
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   The following macro shrinks the initial memory-allocation block of a .com
   program. It takes as a parameter the offset of the first byte following
   the last instruction of a program (LAST_INST in the sample programs), uses
   it to calculate the number of paragraphs in the program, and then adds 17
   to the result: one to round up and 16 to set aside 256 bytes for a stack.
   It then sets up SP and BP to point to this stack.

   Macro Definition:

   set_block  macro   last_byte
              mov     bx,offset last_byte
              mov     cl,4
              shr     bx,cl
              add     bx,17
              mov     ah,4AH
              int     21H
              mov     ax,bx
              shl     ax,cl
              dec     ax
              mov     sp,ax
              mov     bp,sp
              endm

   Example:

   The following program invokes a second copy of command.com and executes a
   dir (directory) command.

   pgm_file  db      "command.com",0
   cmd_line  db       9,"/c dir /w",0DH
   parm_blk  db       14 dup (?)
   reg_save  db       10 dup (?)
   ;
   begin: set_block  last_inst                   ; THIS FUNCTION
          exec       pgm_file,cmd_line,parm_blk,0 ; See Function 4BH


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Load and Execute Program (Function 4BH, Code 00H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 4BH
   AL = 00H
   DS:DX
      Pointer to pathname
   ES:BX
      Pointer to parameter block

   Return:

   Carry set:
   AX
      1        = Invalid function
      2        = File not found
      3        = Path not found
      4        = Too many open files
      5        = Access denied
      8        = Insufficient memory
     10        = Bad environment
     11        = Bad format
   Carry not set:
     No error


   Comments:

   Function 4BH, Code 00H, loads and executes a program. DX must contain the
   offset (from the segment address in DS) of an ASCIZ string that specifies
   the drive and pathname of an executable program file. BX must contain the
   offset (from the segment address in ES) of a parameter block. AL must
   contain 0.

   There must be enough free memory for MS-DOS to load the program file.
   MS-DOS allocates all available memory to a program when it loads it, so
   you must free some memory with Function 4AH (Set Block) before using this
   function request to load and execute another program. Unless you or MS-DOS
   needs the memory for some other purpose, you should shrink the memory to
   the minimum amount required by the current process before issuing this
   request. MS-DOS creates a Program Segment Prefix for the program being
   loaded and sets the terminate and CONTROL+C addresses to the instruction
   that immediately follows the call to Function 4BH in the invoking program.

   The parameter block consists of four addresses:

   Table 1.24
   Contents of the Parameter Block
   Offset     Length
   (Hex)      (Bytes)              Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   00         2 (word)             Segment address of the environment to be
                                   passed; 00H means copy the parent
                                   program's environment

   02         4 (dword)            Segment: Offset of command line to be
                                   placed at offset 80H of the new Program
                                   Segment Prefix. Must be a correctly formed
                                   command line no longer than 128 bytes

   06         4 (dword)            Segment: Offset of FCB to be placed at
                                   offset 5CH of the new Program Segment
                                   Prefix (the Program Segment Prefix is
                                   described in Chapter 4, "MS-DOS Control
                                   Blocks and Work Areas")

   0A         4 (dword)            Segment: Offset of FCB to be placed at
                                   offset 6CH of the new Program Segment
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   All open files of a program are available to the newly loaded program,
   giving the parent program control over the definition of standard input,
   output, auxiliary, and printer devices. For example, a program could write
   a series of records to a file, open the file as standard input, open a
   second file as standard output, and then use Function 4BH, Code 00H, (Load
   and Execute Program) to load and execute a program that takes its input
   from standard input, sorts records, and writes to standard output.

   The loaded program also receives an environment, a series of ASCIZ strings
   of the form parameter=value (for example, verify= on). The environment
   must begin on a paragraph boundary, be less than 32 kilobytes long, and
   end with a byte of 00H (that is, the final entry consists of an ASCIZ
   string followed by two bytes of 00H). Following the last byte of zeros is
   a set of initial arguments passed to a program containing a word count
   followed by an ASCIZ string. If the call finds the file in the current
   directory, the ASCIZ string contains the drive and pathname of the
   executable program as passed to Function 4BH. If the call finds the file
   in the path, it concatenates the filename with the path information. (A
   program may use this area to determine from where it was loaded.) If the
   word-environment address is 0, the loaded program either inherits a copy
   of the parent program's environment or receives a new environment built
   for it by the parent. Place the segment address of the environment at
   offset 2CH of the new Program Segment Prefix. To build an environment for
   the loaded program, put it on a paragraph boundary and place the segment
   address of the environment in the first word of the parameter block. To
   pass a copy of the parent's environment to the loaded program, put 00H in
   the first word of the parameter block.

   If there is an error, the carry flag (CF) is set and the error code
   returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  AL not 0 or 3

   2                  Program file not found

   3                  Path invalid or not found

   4                  Too many open files (no handle available)

   5                  Directory full, a directory with the same name exists,
                      or a file with the same name exists

   8                  Not enough memory to load the program

   10                 Environment appears longer than 32 kilobytes

   11                 Program file is a .exe file that contains internally
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Executing Another Copy of Command.com

   Since command.com builds pathnames, searches command paths for program
   files, and relocates .exe files, the simplest way to load and execute
   another program is to load and execute an additional copy of command.com,
   passing it a command line that includes the /c switch, which invokes the
   .com or .exe file.

   This action requires 17 kilobytes of available memory, so a program that
   does it should be sure to shrink its initial memory-allocation block with
   Function 4AH (Set Block). The following is the format of a command line
   that contains the /c switch:

   length,/c command,0DH

   where:

   Length is the length of the command line, counting the length byte but not
   the ending carriage-return (0DH).

   Command is any valid MS-DOS command.

   0DH is a carriage-return character.

   If a program executes another program directlyÄÄnaming it as the program
   file to Function 4BH instead of command.comÄÄit must perform all the
   processing normally done by command.com.

   Macro Definition:

   exec  macro  path,command,parms
         mov    dx,offset path
         mov    bx,offset parms
         mov    word ptr parms[02H],offset command
         mov    word ptr parms[04H],cs
         mov    word ptr parms[06H],5CH
         mov    word ptr parms[08H],es
         mov    word ptr parms[0AH],6CH
         mov    word ptr parms[0CH],es
         mov    al,0
         mov    ah,4BH
         int    21H
         endm

   Example:

   The following program invokes a second copy of command.com and executes a
   dir (directory) command by using the /w (wide) switch:

   pgm_file  db      "command.com",0
   cmd_line  db       9,"/c dir /w",0DH
   parm_blk  db       14 dup (?)
   reg_save  db       10 dup (?)
   ;
   begin:
      set_block  last_inst                    ; See Function 4AH
      exec       pgm_file,cmd_line,parm_blk,0 ; THIS FUNCTION


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Load Overlay (Function 4BH, Code 03H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 4BH
   AL = 03H
   DS:DX
      Pointer to pathname
   ES:BX
      Pointer to parameter block

   Return:

   Carry set:
   AX
      1        = Invalid function
      2        = File not found
      3        = Path not found
      4        = Too many open files
      5        = Access denied
      8        = Insufficient memory
     10        = Bad environment
   Carry not set:
     No error


   Comments:

   Function 4BH, Code 03H, loads a program segment (overlay). DX must contain
   the offset (from the segment address in DS) of an ASCIZ string that
   specifies the drive and pathname of the program file. BX must contain the
   offset (from the segment address in ES) of a parameter block. AL must
   contain 3.

   MS-DOS assumes that since the invoking program is loading into its own
   address space, it requires no free memory. This call does not create a
   Program Segment Prefix. The parameter block is four bytes long:

   Table 1.25
   Contents of the Parameter Block
   Offset     Length
   (Hex)      (Bytes)              Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   00         2 (word)             Segment address at which program is to be
                                   loaded

   02         2 (word)             Relocation factor; usually the same as the
                                   first word of the parameter block (for a
                                   description of a .exe file and of
                                   relocation, see Chapter 6, ".Exe File
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   If there is an error, the carry flag (CF) is set and the error code
   returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  AL not 00H or 03H

   2                  Program file not found

   3                  Path invalid or not found

   4                  Too many open files (no handle available)

   5                  Directory is full, a directory with the same name
                      exists, or a file with the same name exists

   8                  Not enough memory to load the program

   10                 Environment appears longer than 32 kilobytes
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   exec_ovl  macro  path,parms,seg_addr
             mov    dx,offset path
             mov    bx,offset parms
             mov    parms,seg_addr
             mov    parms[02H],seg_addr
             mov    al,3
             mov    ah,4BH
             int    21H
             endm

   Example:

   The following program opens a file named textfile.asc, redirects standard
   input to that file, loads more.com as an overlay, and calls an overlay
   named bit.com, which reads textfile.asc as standard input. The overlay
   must establish its own addressability and end with a FAR return.

   stdin     equ       0
   ;
   file      db    "TEXTFILE.ASC",0
   cmd_file  db    "\bit.com",0
   parm_blk  dw     4 dup (?)
   overlay   label  dword
             dw     0
   handle    dw     ?
   new_mem   dw     ?
   ;
   begin:    set_block   last_inst        ; see Function 4AH
             jc          setblock_error   ; routine not shown
             allocate_memory  2000        ; see Function 48H
             jc          allocate_error   ; routine not shown
             mov         new_mem,ax       ; save seg of memory
             open_handle file,0           ; see Function 3DH
             jc          open_error       ; routine not shown
             mov         handle,ax        ; save handle
             xdup2       handle,stdin     ; see Function 45H
             jc          dup2_error       ; routine not shown
             close_handle handle          ; see Function 3EH
             jc          close_error      ; routine not shown
             mov         ax,new_mem       ; addr of new memory
             exec_ovl cmd_file,parm_blk,ax    ; THIS FUNCTION
             jc          exec_error       ; routine not shown
             call        overlay          ; call the overlay
             free_memory new_mem          ; see Function 49H
             jc          free_error       ; routine not shown
   ;


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 End Process (Function 4CH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 4CH
   AL
      Return code

   Return:

   None


   Comments:

   Function 4CH terminates a process and returns to MS-DOS. AL contains a
   return code that can be retrieved by the parent process with Function
   4DH (Get Return Code of Child Process) or the if command, using
   errorlevel.

   MS-DOS closes all open handles, ends the current process, and returns
   control to the invoking process.

   This function request doesn't require CS to contain the segment address of
   the Program Segment Prefix. You should use it to end a program (rather
   than Interrupt 20H or a jump to location 0) unless your program must be
   compatible with MS-DOS versions earlier than 2.0.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     If you use file sharing, you must remove all locks issued by this
     process or DOS will be in an uncertain state.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   end_process  macro  return_code
                mov    al,return_code
                mov    ah,4CH
                int    21H
                endm

   Example:

   The following program displays a message and returns to MS-DOS with a
   return code of 8. It uses only the opening portion of the sample program
   skeleton shown at the beginning of this chapter.

   message   db     "Displayed by FUNC_4CH example",0DH,0AH,"$"
   ;
   begin:    display      message   ; See Function 09H
             end_process  8         ; THIS FUNCTION
   code      ends
             end          code


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get Return Code of Child Process (Function 4DH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 4DH

   Return:

   AX
      Return code


   Comments:

   Function 4DH retrieves the return code specified when a child process
   terminates via either Function 31H (Keep Process) or Function 4CH (End
   Process). The code returns in AL. AH returns a code that specifies why the
   program ended:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0                  Normal termination
   1                  Terminated by CONTROL+C
   2                  Critical device error
   3                  Function 31H (Keep Process)
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   This call can retrieve the exit code only once.

   Macro Definition:

   ret_code  macro
             mov    ah,4DH
             int    21H
             endm

   Example:

   No example is included for this function request because the meaning of a
   return code varies.


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Find First File (Function 4EH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 4EH
   DS:DX
      Pointer to pathname
   CX
      Attributes to match

   Return:

   Carry set:
   AX
      2        = File not found
      3        = Path not found
     18        = No more files
   Carry not set:
      No error


   Comments:

   Function 4EH searches the current or specified directory for the first
   entry that matches the specified pathname. DX must contain the offset
   (from the segment address in DS) of an ASCIZ string that specifies the
   pathname, which can contain wildcard characters. CX must contain the
   attribute to be used in searching for the file, as described in Section
   1.5.5, "File Attributes."

   If the attribute field is hidden file, system file, or subdirectory entry
   (02H, 04H, or 10H), or any combination of these values, all normal file
   entries are also searched. To search all directory entries except the
   volume label, set the attribute byte to 16H (hidden file, system file, and
   directory entry). If this function finds a directory entry that matches
   the name and attribute, it fills the current DTA as follows:

   Table 1.26
   DTA Values After Successful Find First File
   Offset   Length    Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   00H      21        Reserved for subsequent Function 4FH (Find Next File)

   15H      1         Attribute found

   16H      2         Time file was last written

   18H      2         Date file was last written

   1AH      2         Low word of file size

   1CH      2         High word of file size

   1EH      13        Name and extension of the file, followed by 00H. All
                      blanks are removed; if there is an extension, it is
                      preceded by a period. (Volume labels include a period
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   If there is an error, the carry flag (CF) is set and the error code
   returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   2                  Specified file invalid or doesn't exist
   3                  Specified path invalid or doesn't exist
   18                 No matching directory entry found
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   find_first_file  macro  path,attrib
                    mov    dx,offset path
                    mov    cx,attrib
                    mov    ah,4EH
                    int    21H
                    endm

   Example:

   The following program displays a message that specifies whether a file
   named report.asm exists in the current directory on the disk in drive B.

   yes        db      "File exists.",0DH,0AH,"$"
   no         db      "File does not exist.",0DH,0AH,"$"
   path       db      "b:report.asm",0
   buffer     db       43 dup (?)
   ;
   begin:     set_dta  buffer           ; See Function 1AH
              find_first_file  path,0   ; THIS FUNCTION
              jc       error_findfirst  ; Routine not shown
              cmp      al,12H           ; File found?
              je       not_there        ; No
              display  yes              ; See Function 09H
              jmp      return           ; All done
   not_there: display  no               ; See Function 09H


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Find Next File (Function 4FH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 4FH

   Return:

   Carry set:
   AX
     18 = No more files
   Carry not set:
      No error


   Comments:

   Function 4FH searches for the next directory entry that matches the name
   and attributes specified in a previous Function 4EH (Find First File).
   The current DTA must contain the information filled in by Function 4EH
   (Find First File).

   If the function finds a matching entry, it fills the current DTA just as
   it did for Find First File (see Function 4EH (Find First File)).

   If there is an error, the carry flag (CF) is set and the error code
   returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   2                  Specified path invalid or doesn't exist
   18                 No matching directory entry found
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   find_next_file  macro
                   mov    ah,4FH
                   int    21H
                   endm

   Example:

   The following program displays the number of files contained in the
   current directory on the disk in drive B.

   message     db      "No files",0DH,0AH,"$"
   files       dw       ?
   path        db      "b:*.*",0
   buffer      db       43 dup (?)
   ;
   begin:      set_dta  buffer          ; See Function 1AH
               find_first_file  path,0  ; See Function 4EH
               jc       error_findfirst ; Routine not shown
               cmp      al,12H          ; Directory empty?
               je       all_done        ; Yes, go home
               inc      files           ; No, bump file counter
   search_dir: find_next_file           ; THIS FUNCTION
               jc       error_findnext  ; Routine not shown
               cmp      al,12H          ; Any more entries?
               je       done            ; No, go home
               inc      files           ; Yes, bump file counter
               jmp      search_dir      ; And check again
   done:       convert  files,10,message ; See end of chapter
   all_done:   display  message         ; See Function 09H


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get Verify State (Function 54H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 54H

   Return:

   AL
      0 = No verify after write
      1 = Verify after write


   Comments:

   Function 54H checks whether MS-DOS verifies write operations to disk
   files. The status returns in AL: 0 if verify is off, 1 if verify is on.

   You can set the verify status with Function 2EH (Set/Reset Verify Flag).

   Macro Definition:

   get_verify  macro
               mov    ah,54H
               int    21H
               endm

   Example:

   The following program displays the verify status:

   message   db     "Verify ","$"
   on        db     "on.",0DH,0AH,"$"
   off       db     "off.",0DH,0AH,"$"
   ;
   begin:    display message      ; See Function 09H
             get_verify           ; THIS FUNCTION
             cmp     al,0         ; Is flag off?
             jg      ver_on       ; No, it's on
             display off          ; See Function 09H
             jmp     return       ; Go home
   ver_on:   display on           ; See Function 09H


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Change Directory Entry (Function 56H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 56H
   DS:DX
      Pointer to pathname
   ES:DI
      Pointer to second pathname

   Return:

   Carry set:
   AX
      2        = File not found
      3        = Path not found
      5        = Access denied
     17        = Not same device
   Carry not set:
      No error


   Comments:

   Function 56H renames a file by changing its directory entry. DX must
   contain the offset (from the segment address in DS) of an ASCIZ string
   that contains the pathname of the entry to be changed. DI must contain the
   offset (from the segment address in ES) of an ASCIZ string that contains a
   second pathname to which the first is to be changed.

   If a directory entry for the first pathname exists, it is changed to the
   second pathname.

   The directory paths need not be the same; in effect, you can move the file
   to another directory by renaming it. You cannot use this function request
   to copy a file to another drive, however; if the second pathname specifies
   a drive, the first pathname must specify or default to the same drive.

   You cannot use this function request to rename an open file, a hidden
   file, a system file, or a subdirectory, because it may corrupt your disk.
   If there is an error, the carry flag (CF) is set and the error code
   returns in AX.

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   2                  One of files is invalid or not open

   3                  One of paths is invalid or not open

   5                  First pathname specifies a directory, second pathname
                      specifies an existing file; or second directory entry
                      could not be opened

   17                 Both files not on the same drive
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   rename_file  macro  old_path,new_path
                mov    dx,offset old_path
                push   ds
                pop    es
                mov    di,offset new_path
                mov    ah,56H
                int    21H
                endm

   Example:

   The following program prompts for the name of a file and a new name, then
   renames the file.

   prompt1   db     "Filename: $"
   prompt2   db     "New name: $"
   old_path  db      15,?,15 dup (?)
   new_path  db      15,?,15 dup (?)
   crlf      db      0DH,0AH,"$"
   ;
   begin:    display prompt1           ; See Function 09H
             get_string  15,old_path   ; See Function 0AH
             xor     bx,bx             ; To use BL as index
             mov     bl,old_path[1]    ; Get string length
             mov     old_path[bx+2],0  ; Make an ASCIZ string
             display crlf              ; See Function 09H
             display prompt2           ; See Function 09H
             get_string  15,new_path   ; See Function 0AH
             xor     bx,bx             ; To use BL as index
             mov     bl,new_path[1]    ; Get string length
             mov     new_path[bx+2],0  ; Make an ASCIZ string
             display crlf              ; See Function 09H
             rename_file old_path[2],new_path[2]; THIS FUNCTION
             jc      error_rename      ; Routine not shown




 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get/Set Date/Time of File (Function 57H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 57H
   AL = Function code
      0 = Get date and time
      1 = Set date and time
   BX
      Handle
   CX (if AL = 1)
      Time to be set
   DX (if AL = 1)
      Date to be set

   Return:

   Carry set:
   AX
      1 = Invalid function
      6 = Invalid handle
   Carry not set:
   CX (if AL = 0)
      Time file last written
   DX (if AL = 0)
      Date file last written


   Comments:

   Function 57H gets or sets the time and date when a file was last written.
   To get the time and date, AL must contain 0; the time and date return in
   CX and DX. To set the time and date, AL must contain 1; CX and DX must
   contain the time and date. BX must contain the file handle. The time and
   date are in the form described in "Fields of the FCB" in Section 1.9.1.

   If there is an error, the carry flag (CF) is set and the error code
   returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  AL not 0 or 1
   6                  Handle in BX invalid or not open
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   get_set_date_time macro  handle,action,time,date
                     mov    bx,handle
                     mov    al,action
                     mov    cx,word ptr time
                     mov    dx,word ptr date
                     mov    ah,57H
                     int    21H
                     endm

   Example:

   The following program gets the date of a file named report.asm in the
   current directory on the disk in drive B, increments the day, increments
   the month and/or year, if necessary, and sets the new date of the file.

   month     db      31,28,31,30,31,30,31,31,30,31,30,31
   path      db     "b:report.asm",0
   handle    dw      ?
   time      db      2 dup (?)
   date      db      2 dup (?)
   ;
   begin:    open_handle  path,0         ; See Function 3DH
             mov     handle,ax           ; Save handle
             get_set_date_time handle,0,time,date ; THIS FUNCTION
             jc      error_time          ; Routine not shown
             mov     word ptr time,cx    ; Save time
             mov     word ptr date,dx    ; Save date
             convert_date  date[-24]     ; See end of chapter
             inc     dh                  ; Increment day
             xor     bx,bx               ; To use BL as index
             mov     bl,dl               ; Get month
             cmp     dh,month[bx-1]      ; Past last day?
             jle     month_ok            ; No, go home
             mov     dh,1                ; Yes, set day to 1
             inc     dl                  ; Increment month
             cmp     dl,12               ; Is it past December?
             jle     month_ok            ; No, go home
             mov     dl,1                ; Yes, set month to 1
             inc     cx                  ; Increment year
   month_ok: pack_date  date             ; See end of chapter
             get_set_date_time handle,1,time,date ; THIS FUNCTION
             jc      error_time          ; Routine not shown
             close_handle  handle        ; See Function 3EH
             jc      error_close         ; Routine not shown


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get/Set Allocation Strategy (Function 58H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 58H
   AL
      0 = Get strategy
      1 = Set strategy
   BX (AL = 1)
      0 = First fit
      1 = Best fit
      2 = Last fit

   Return:

   Carry set:
   AX
      1 = Invalid function code
   Carry not set:
   AX (AL = 0)
      0 = First fit
      1 = Best fit
      2 = Last fit


   Comments:

   Function 58H gets or sets the strategy that MS-DOS uses to allocate memory
   when a process requests it. If AL contains 0, the strategy is returned in
   AX. If AL contains 1, BX must contain the strategy. The three possible
   strategies are shown in the following table.

   Table 1.27
   Allocation Strategy
   Value      Name                 Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0          First fit            MS-DOS starts searching at the lowest
                                   available block and allocates the first
                                   block it finds (the allocated memory is
                                   the lowest available block). This is the
                                   default strategy.

   1          Best fit             MS-DOS searches each available block and
                                   allocates the smallest available block
                                   that satisfies the request.

   2          Last fit             MS-DOS starts searching at the highest
                                   available block and allocates the first
                                   block it finds (the allocated memory is
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   You can use this function request to control how MS-DOS uses its memory
   resources.

   If there is an error, the carry flag (CF) is set and the error code
   returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  AL doesn't contain 0 or 1, or BX doesn't contain 0, 1,
                      or 2.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   alloc_strat macro  code,strategy
               mov    bx,strategy
               mov    al,code
               mov    ah,58H
               int    21H
               endm

   Example:

   The following program displays the memory-allocation strategy in effect,
   then forces subsequent memory allocations to the top of memory by setting
   the strategy to last fit (code 2).

   get       equ       0
   set       equ       1
   stdout    equ       1
   last_fit  equ       2
   ;
   first     db       "First fit     ",0DH,0AH
   best      db       "Best fit      ",0DH,0AH
   last      db       "Last fit      ",0DH,0AH
   ;
   begin:    alloc_strat get               ; THIS FUNCTION
             jc         alloc_error        ; routine not shown
             mov        cl,4               ; multiply code by 16
             shl        ax,cl              ; to calculate offset
             mov        dx,offset first    ; point to first msg
             add        dx,ax              ; add to base address
             mov        bx,stdout          ; handle for write
             mov        cs,16              ; write 16 bytes
             mov        ah,40h             ; write handle
             int        21H                ; system call
   ;          jc         write_error        ; routine not shown
             alloc_strat set,last_fit      ; THIS FUNCTION
   ;          jc         alloc_error        ; routine not shown


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get Extended Error (Function 59H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 59H
   BX = 00H

   Return:

   AX
      Extended-error code
   BH
      Error class (see text)
   BL
      Suggested action (see text)
   CH
      Locus (see text)

   CL, DX, SI, DI, DS, ES destroyed


   Comments:

   Function 59H retrieves an extended-error code for the preceding system
   call. Each release of MS-DOS extends the error codes to cover new
   capabilities. These new codes are mapped to a simpler set of error codes
   based on MS-DOS Version 2.0, so that existing programs can continue to
   operate correctly. Notice that this call destroys all registers except
   CS:IP and SS:SP.

   A user-written Interrupt 24H (Critical-Error Handler Address) can use
   Function 59H to get detailed information about the error that caused the
   interrupt to be issued.

   The input BX is a version indicator that specifies for what level of error
   handling the application was written. The current level is 00H.

   The extended-error code consists of four separate codes in AX, BH, BL, and
   CH that give as much detail as possible about the error and suggest how
   the issuing program should respond.

   BHÄÄError Class

   BH returns a code that describes the class of error that occurred:

ÖŚÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ·
   Class              Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  Out of a resource, such as storage or channels

   2                  Not an error, but a temporary situation (such as a
                      locked region in a file) that is expected to end

   3                  Authorization problem

   4                  Internal error in system software

   5                  Hardware failure

   6                  System software failure not the fault of the active
                      process (could be caused by missing or incorrect
                      configuration files, for example)

   7                  Application program error

   8                  File or item not found

   Class              Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   9                  File or item of invalid format or type, or that is
                      otherwise invalid or unsuitable

   10                 Interlocked file or item

   11                 Wrong disk in drive, bad spot on disk, or other problem
                      with storage medium

   12                 Other error
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


   BLÄÄSuggested Action

   BL returns a code that suggests how the issuing program can respond to the
   error:

   Action             Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  Retry, then prompt user

   2                  Retry after a Pause

   3                  If user entered data such as drive letter or filename,
                      prompt for it again

   4                  Terminate with cleanup

   5                  Terminate immediately; system so unhealthy that program
                      should exit as soon as possible without taking time to
                      close files and update indexes

   6                  Error is informational

   7                  Prompt user to perform some action, such as changing
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   CHÄÄLocus

   CH returns a code that provides additional information to help locate the
   area involved in the failure. This code is particularly useful for
   hardware failures (BH=5).

   Locus          Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1              Unknown
   2              Related to random-access block devices, such as a disk
                  drive
   3              Related to Network
   4              Related to serial-access character devices, such as a
                  printer
   5              Related to random-access memory
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Your programs should handle errors by noting the error return from the
   original system call and then issuing this system call to get the
   extended-error code. If the program does not recognize the extended-error
   code, it should respond to the original error code.

   This system call is available during Interrupt 24H and may be used to
   return network-related errors.

   Macro Definition:

   get_error  macro
              mov    ah, 59H
              int    21H
              endm

   Example:

   Since this function request provides such detailed information, a general
   example is not practical. User programs can interpret the various codes to
   determine what sort of messages or prompts should be displayed, what
   action to take, and whether or not to terminate the program if recovery
   from the errors isn't possible.


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Create Temporary File (Function 5AH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 5AH
   CX
      Attribute
   DS:DX
      Pointer to pathname, followed by a
      byte of 0, and then by 13 bytes of memory

   Return:

   Carry set:
   AX
      2 = File not found
      3 = Path not found
      4 = Too many open files
      5 = Access denied
   Carry not set:
   AX
      Handle


   Comments:

   Function 5AH creates a file with a unique name. DX must contain the offset
   (from the segment address in DS) of an ASCIZ string that specifies a
   pathname and 13 bytes of memory (to hold the filename). CX must contain
   the attribute to be assigned to the file, as described in Section 1.5.5,
   "File Attributes."

   MS-DOS creates a unique filename and appends it to the pathname pointed to
   by DS:DX, creates the file and opens it in compatibility mode, then
   returns the file handle in AX. A program that needs a temporary file
   should use this function request to avoid name conflicts.

   When the creating process exits, MS-DOS does not automatically delete a
   file created with Function 5AH. When you no longer need the file, you
   should delete it. If there is an error, the carry flag (CF) is set and the
   error code returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   2                  File is invalid or doesn't exist

   3                  Directory pointed to by DS:DX is invalid or doesn't
                      exist

   4                  Too many open files (no handle available)

   5                  Access denied
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   create_temp macro  pathname,attrib
               mov    cx,attrib
               mov    dx,offset pathname
               mov    ah,5AH
               int    21H
               endm

   Example:

   The following program creates a temporary file in the directory named
   \wp\docs, copies a file named textfile.asc that is in the current
   directory into the temporary file, and then closes both files.

   stdout   equ       1
   ;
   file     db       "TEXTFILE.ASC",0
   path     db       "\WP\DOCS",0
   temp     db        13 dup (0)
   open_msg db       " opened.",0DH,0AH
   crl_msg  db       " created.",0DH,0AH
   rd_msg   db       " read into buffer.",0DH,0AH
   wr_msg   db       "Buffer written to "
   cl_msg   db       "Files closed.",0DH,0AH
   crlf     db       0DH,0AH
   handle1  dw        ?
   handle2  dw        ?
   buffer   db        512 dup (?)
   ;



   begin:   open_handle file,0            ; see Function 3DH
            jc         open_error         ; routine not shown
            mov        handle1,ax         ; save handle
            write_handle stdout,file,12   ; see Function 40H
            jc         write_error        ; routine not shown
            write_handle stdout,open_msg,10 ; see Function 40H
            jc         write_error        ; routine not shown
            create_temp path,0            ; THIS FUNCTION
            jc         create_error       ; routine not shown
            mov        handle2,ax         ; save handle
            write_handle stdout,path,8    ; see Function 40H
            jc         write_error        ; routine not shown
            display_char ""              ; see Function 02H
            write_handle stdout,temp,12   ; see Function 40H
            jc         write_error        ; routine not shown
            write_handle stdout,crl_msg,11 ; See Function 40H
            jc         write_error        ; routine not shown
            read_handle handle1,buffer,512  ; see Function 3FH
            jc        read_error          ; routine not shown
            write_handle stdout,file,12   ; see Function 40H
            jc        write_error         ; routine not shown
            write_handle stdout,rd_msg,20 ; see Function 40H
            jc        write_error         ; routine not shown
            write_handle handle2,buffer,512 ; see Function 40H
            jc        write_error         ; routine not shown
            write_handle stdout,wr_msg,18 ; see Function 40H
            jc         write_error        ; routine not shown
            write_handle stdout,temp,12   ; see Function 40H
            jc         write_error        ; routine not shown
            write_handle stdout,crlf,2    ; see Function 40H
            jc        write_error         ; routine not shown
            close_handle handle1          ; see Function 3EH
            jc        close_error         ; routine not shown
            close_handle handle2          ; see Function 3EH
            jc        close_error         ; routine not shown
            write_handle stdout,cl_msg,15 ; see Function 40H
            jc        write_error         ; routine not shown


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Create New File (Function 5BH)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 5BH
   CX
      Attribute
   DS:DX
      Pointer to pathname

   Return:

   Carry set:
   AX
       2        = File not found
       3        = Path not found
       4        = Too many open files
       5        = Access denied
      80        = File already exists
   Carry not set:
   AX
      Handle


   Comments:

   Function 5BH creates a new file. DX must contain the offset (from the
   segment address in DS) of an ASCIZ string that specifies a pathname. CX
   contains the attribute to be assigned to the file, as described in Section
   1.5.5, "File Attributes."

   If there is no existing file with the same filename, MS-DOS creates the
   file, opens it in compatibility mode, and returns the file handle in AX.

   This function request fails if the specified file exists, unlike Function
   3CH (Create Handle), which, under the same circumstances, truncates the
   file to a length of 0. In a multitasking system, the existence of a file
   is used as a semaphore; you can use this system call as a test-and-set
   semaphore. If there is an error, the carry flag (CF) is set and the error
   code returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   2                  File is invalid or doesn't exist

   3                  Directory pointed to by DS:DX is invalid or doesn't
                      exist

   4                  No free handles are available in the current process,
                      or internal system tables are full

   5                  Access denied

   80                 File with the same specification pointed to by DS:DX
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   create_new macro  pathname,attrib
              mov    cx, attrib
              mov    dx, offset pathname
              mov    ah, 5BH
              int    21H
              endm

   Example:

   The following program attempts to create a new file named report.asm in
   the current directory. If the file already exists, the program displays an
   error message and returns to MS-DOS. If the file doesn't exist and there
   are no other errors, the program saves the handle and continues
   processing.

   err_msg  db       "FILE ALREADY EXISTS",0DH,0AH,"$"
   path     db       "report.asm",0
   handle   dw        ?
   ;
   begin:    create_new path,0             ; THIS FUNCTION
             jnc        continue           ; further processing
             cmp        ax,80              ; file already exist?
             jne        error              ; routine not shown
             display    err_msg            ; see Function 09H
             jmp        return             ; return to MS-DOS
   continue: mov        handle,ax          ; save handle
   ;
   ;          (further processing here)


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Lock (Function 5CH, Code 00H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 5CH
   AL = 00H
   BX
      Handle
   CX:DX
      Offset of region to be locked
   SI:DI
      Length of region to be locked

   Return:

   Carry set:
   AX
      1        = Invalid function code
      6        = Invalid handle
     33        = Lock violation
     36        = Sharing buffer exceeded
   Carry not set:
      No error


   Comments:

   Function 5CH, Code 00H, denies all access (read or write) by any other
   process to the specified region of the file. BX must contain the handle of
   the file that contains the region to be locked. CX:DX (a four-byte
   integer) must contain the offset in the file of the beginning of the
   region. SI:DI (a four-byte integer) must contain the length of the region.

   If another process attempts to use (read or write) a locked region, MS-DOS
   retries three times; if the retries fail, MS-DOS issues Interrupt 24H for
   the requesting process. You can change the number of retries with Function
   440BH (IOCtl Retry).

   The locked region can be anywhere in the file. For instance, locking
   beyond the end of the file is not an error. A region should be locked for
   only a brief period, so if it is locked for more than ten seconds you
   should consider it to be an error. Function 45H (Duplicate File Handle)
   and Function 46H (Force Duplicate File Handle) duplicate access to any
   locked region. Passing an open file to a child process with Function
   4B00H (Load and Execute Program) does not duplicate access to locked
   regions.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Warning
     If a program closes a file that contains a locked region or terminates
     with an open file that contains a locked region, the result is
     undefined.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Programs that might be terminated by Interrupt 23H (CONTROL+C Handler
   Address) or Interrupt 24H (Critical-Error-Handler Address) should trap
   these interrupts and unlock any locked regions before exiting.

   Programs should not rely on being denied access to a locked region. A
   program can determine the status of a region (locked or unlocked) by
   attempting to lock the region and examining the error code.

   If there is an error, the carry flag (CF) is set and the error code is
   returned in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  File sharing must be loaded to use this function
                      request.

   6                  The handle in BX is not a valid, open handle.

   33                 All or part of the specified region is already locked.

   36                 There is no more room for lock entries in the buffer.
                      Refer to the share command in the MS-DOS User's
                      Reference for information on allocating more lock
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   lock  macro  handle,start,bytes
         mov    bx, handle
         mov    cx, word ptr start
         mov    dx, word ptr start+2
         mov    si, word ptr bytes
         mov    di, word ptr bytes+2
         mov    al, 0
         mov    ah, 5CH
         int    21H
         endm

   Example:

   The following program opens a file named finalrpt in "Deny None" mode and
   locks two portions of it: the first 128 bytes and bytes 1024 through 5119.
   After some (unspecified) processing, it unlocks the same portions and
   closes the file.

   stdout    equ        1
   ;
   start1    dd         0
   lgth1     dd         128
   start2    dd         1023
   lgth2     dd         4096
   file      db        "FINALRPT",0
   op_msg    db        " opened.",0DH,0AH
   11_msg    db        "First 128 bytes locked.",0DH,0AH
   12_msg    db        "Bytes 1024-5119 locked.",0DH,0AH
   u1_msg    db        "First 128 bytes unlocked.",0DH,0AH
   u2_msg    db        "Bytes 1024-5119 unlocked.",0DH,0AH
   cl_msg    db        " closed.:,0DH,0AH
   handle    dw         ?
   ;
   begin:    open_handle file,01000010b     ; see Function 3DH
             jc         open_error          ; routine not shown
             write_handle stdout,file,8     ; see Function 40H
             jc         write_error         ; routine not shown
             write_handle stdout,op_msg,10  ; see Function 40H
             jc         write_error         ; routine not shown
             mov        handle,ax           ; save handle
             lock       handle,start1,lgth1 ; THIS FUNCTION
             jc         lock_error          ; routine not shown
             write_handle stdout,11_msg,25  ; see Function 40H
             jc         write_error         ; routine not shown
             lock       handle,start2,lgth2 ; THIS FUNCTION
             jc         lock_error          ; routine not shown
             write_handle stdout,12_msg,25  ; see Function 40H
             jc         write_error         ; routine not shown
   ;
   ;  ( Further processing here )
   ;
             unlock     handle,start1,lgth1 ; See Function 5C01H
             jc         unlock_error        ; routine not shown
             write_handle stdout,ul_msg,27  ; see Function 40H
             jc         write_error         ; routine not shown
             unlock     handle,start2,lgth2 ; See Function 5C01H
             jc         unlock_error        ; routine not shown
             write_handle stdout,u2_msg,27  ; See Function 40H
             jc         write_error         ; routine not shown
             close_handle handle            ; See Function 3EH
             jc         close_error         ; routine not shown
             write_handle stdout,file,8     ; see Function 40H
             jc         write_error         ; routine not shown
             write_handle stdout,cl_msg,10  ; see Function 40H
             jc         write_error         ; routine not shown


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Unlock (Function 5CH, Code 01H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 5CH
   AL = 01H
   BX
      Handle
   CX:DX
      Offset of area to be unlocked
   SI:DI
      Length of area to be unlocked

   Return:

   Carry set:
   AX
      1        = Invalid function code
      6        = Invalid handle
     33        = Lock violation
     36        = Sharing buffer exceeded
   Carry not set:
      No error


   Comments:

   Function 5CH, Code 01H, unlocks a region previously locked by the same
   process. BX must contain the handle of the file that contains the region
   to be unlocked. CX:DX (a four-byte integer) must contain the offset in the
   file of the beginning of the region. SI:DI (a four-byte integer) must
   contain the length of the region. The offset and length must be exactly
   the same as the offset and length specified in the previous Function
   5C00H (Lock).

   The description of Function 5C00H (Lock) describes how to use locked
   regions. If there is an error, the carry flag (CF) is set and the error
   code returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  File sharing must be loaded to use this function
                      request.

   6                  The handle in BX is not a valid, open handle.

   33                 The region specified is not identical to one that was
                      previously locked by the same process.

   36                 There is no more room for lock entries in the buffer.
                      Refer to the share command in the MS-DOS User's
                      Reference for information on allocating more lock
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   You should issue Function 59H (Get Extended Error) to list the possible
   errors returned by this function.

   Macro Definition:

   unlock  macro  handle,start,bytes
           mov    bx, handle
           mov    cx, word ptr start
           mov    dx, word ptr start+2
           mov    si, word ptr bytes
           mov    di, word ptr bytes+2
           mov    al, 1
           mov    ah, 5CH
           int    21H
           endm

   Example:

   The following program opens a file named finalrpt in "Deny None" mode and
   locks two portions of it: the first 128 bytes and bytes 1024 through 5119.
   After some (unspecified) processing, it unlocks the same portions and
   closes the file.

   stdout    equ        1
   ;
   start1    dd         0
   lgth1     dd         128
   start2    dd         1023
   lgth2     dd         4096
   file      db        "FINALRPT",0



   op_msg    db        " opened.",0DH,0AH
   11_msg    db        "First 128 bytes locked.",0DH,0AH
   12_msg    db        "Bytes 1024-5119 locked.",0DH,0AH
   u1_msg    db        "First 128 bytes unlocked.",0DH,0AH
   u2_msg    db        "Bytes 1024-5119 unlocked.",0DH,0AH
   cl_msg    db        " closed.",0DH,0AH
   handle    dw         ?
   ;
   begin:    open_handle file,01000010b     ; see Function 3DH
             jc         open_error          ; routine not shown
             write_handle stdout,file,8     ; see Function 40H
             jc         write_error         ; routine not shown
             write_handle stdout,op_msg,10  ; see Function 40H
             jc         write_error         ; routine not shown
             mov        handle,ax           ; save handle
             lock       handle,start1,lgth1 ; See Function 5C00H
             jc         lock_error          ; routine not shown
             write_handle stdout,11_msg,25  ; see Function 40H
             jc         write_error         ; routine not shown
             lock       handle,start2,lgth2 ; See Function 5C00H
             jc         lock_error          ; routine not shown
             write_handle stdout,12_msg,25  ; see Function 40H
             jc         write_error         ; routine not shown
   ;
   ;  ( Further processing here )
   ;
             unlock     handle,start1,lgth1 ; THIS FUNCTION
             jc         unlock_error        ; routine not shown
             write_handle stdout,u1_msg,27  ; see Function 40H
             jc         write_error         ; routine not shown
             unlock     handle,start2,lgth2 ; THIS FUNCTION
             jc         unlock_error        ; routine not shown
             write_handle stdout,u2_msg,27  ; see Function 40H
             jc         write_error         ; routine not shown
             close_handle handle            ; See Function 3EH
             jc         close_error         ; routine not shown
             write_handle stdout,file,8     ; see Function 40H
             jc         write_error         ; routine not shown
             write_handle stdout,cl_msg,10  ; see Function 40H
             jc         write_error         ; routine not shown


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get Machine Name (Function 5EH, Code 00H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 5EH
   AL = 0
   DS:DX
      Pointer to 16-byte buffer

   Return:

   Carry set:
   AX
      1 = Invalid function code
   Carry not set:
   CX
      Identification number of local
      computer
   CH
      Validity of machine name:
      00H = invalid
      nonzero = valid
   CL
      NETBIOS number assigned to machine name
   DS:DX
      Segment:offset of ASCIZ machine name


   Comments:

   Function 5EH, Code 00H, retrieves the net name of the local computer. DX
   must contain the offset (to the segment address in DS) of a 16-byte
   buffer. Microsoft Networks must be running.

   MS-DOS returns the local computer name (a 16-byte ASCIZ string, padded
   with blanks) in the buffer pointed to by DS:DX. CX returns the
   identification number of the local computer. If the network was never
   installed, the CH register returns with zero and the value in the CL
   register is invalid. If there is an error, the carry flag (CF) is set and
   the error code returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  Microsoft Networks must be running to use this function
                      request.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   get_machine_name  macro  buffer
                     mov    dx,offset buffer
                     mov    al,0
                     mov    ah,5EH
                     int    21H
                     endm

   Example:

   The following program displays the name of a Microsoft Networks
   workstation.

   stdout equ 1
   ;
   msg        db   "Netname: "
   mac_name   db   16 dup (?),0DH,0AH
   ;
   begin:    get_machine_name  mac_name        ; THIS FUNCTION
             jc                name_error      ; routine not shown
             write_handle      stdout,msg,27   ; see Function 40H
             jc                write_error     ; routine not shown


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get/Set Printer Setup (Function 5EH, Codes 02H and 03H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 5EH
   AL
       02H = Set printer setup string
       03H = Get printer setup string
   BX
       Assign-list index
   If AL = 02H
       CX
           Length of setup string

       DS:SI
       Pointer to setup string
   If AL = 03H
       ES:DI = Segment: offset of 64-byte buffer
                     to receive string

   Return:

   Carry set:
   AX
       1 = Invalid function code
   Carry not set:
   CX = Length of printer setup string in bytes
             (if AL=03H)
   ES:DI = Segment:offset of ASCII printer setup
                 string (if AL=03H)


   Comments:

   Function 5EH, Code 02H, defines a string of control characters that MS-DOS
   adds to the beginning of each file sent to the network printer. BX must
   contain the index into the assign list that identifies the printer (entry
   0 is the first entry). CX must contain the length of the string. SI must
   contain the offset (to the segment address in DS) of the string itself.
   Microsoft Networks must be running.

   MS-DOS adds the setup string to the beginning of each file sent to the
   printer, which is specified by the assign-list index in BX. This function
   request lets each program that shares a printer have its own printer
   configuration. You can use Function 5F02H (Get Assign-List Entry) to
   determine which entry in the assign list refers to the printer. If there
   is an error, the carry flag (CF) is set and the error code returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  Microsoft Networks must be running to use this function
                      request.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   printer_setup  macro  index,lgth,string
                  mov    bx, index
                  mov    cx, lgth
                  mov    dx, offset string
                  mov    al, 2
                  mov    ah, 5EH
                  int    21H
                  endm

   Example:

   The following program defines a printer-setup string that consists of the
   control character to print expanded type on Epson-compatible printers. The
   printer cancels this mode at the first carriage return, so the effect is
   to print the first line of each file sent to the network printer as a
   title in expanded characters. The setup string is one character. This
   example assumes that the printer is the entry number 3 (the fourth entry)
   in the assign list. Use Function 5F02H (Get Assign-List Entry) to
   determine this value.

   setup     db   0EH
   ;
   begin:    printer_setup 3,1,setup       ; THIS FUNCTION
             jc            error           ; routine not shown


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get Assign-List Entry (Function 5FH, Code 02H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 5FH
   AL = 02H
   BX
      Assign-list index
   DS:SI
      Pointer to buffer for local name
   ES:DI
      Pointer to buffer for remote name

   Return:

   Carry set:
   AX
      1        = Invalid function code
     18        = No more files
   Carry not set:
   BL
      3 = Printer
      4 = Drive
   CX
      Stored user value


   Comments:

   Function 5FH, Code 02H, retrieves the specified entry from the network
   list of assignments. BX must contain the assign-list index (entry 0 is the
   first entry). SI must contain the offset (to the segment address in DS) of
   a 16-byte buffer for the local name. DI must contain the offset (to the
   segment address in ES) of a 128-byte buffer for the remote name. Microsoft
   Networks must be running.

   MS-DOS puts the local name in the buffer pointed to by DS:SI and the
   remote name in the buffer pointed to by ES:DI. The local name can be a
   null ASCIZ string. BL returns 3 if the local device is a printer or 4 if
   the local device is a drive. CX returns the stored user value set with
   Function 5F03H (Make Network Connection). The contents of the assign list
   can change between calls. You can use this function request to retrieve
   any entry, or to make a copy of the complete list by stepping through the
   table. To detect the end of the assign list, check for error code 18 (no
   more files), as you would when stepping through a directory by using
   Functions 4EH (Find First File) and 4FH (Find Next File).

   If there is an error, the carry flag (CF) is set and the error code
   returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  Microsoft Networks must be running to use this function
                      request.

   18                 The index passed in BX is greater than the number of
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   get_list  macro  index,local,remote
             mov    bx, index
             mov    si, offset local
             mov    di, offset remote
             mov    al,2
             mov    ah, 5FH
             int    21H
             endm

   Example:

   The following program displays the assign list on a Microsoft Networks
   workstation, showing the local name, remote name, and device type (drive
   or printer) for each entry.

   stdout    equ        1
   printer   equ        3
   ;
   local_nm  db         16 dup (?),2 dup (20h)
   remote_nm db         128 dup (?),2 dup (20h)
   header    db        "Local name",8 dup (20h)
             db        "Remote name",7 dup (20h)
             db        "Device Type"
   crlf      db         0dh,0ah,0dh,0ah
   drive_msg db        "drive"
   print_msg db        "printer"
   index     dw         ?
   ;



   begin:    write_handle stdout,header,51   ; see Function 40H
             jc         write_error          ; routine not shown
             mov        index,0              ; assign list index
   ck_list:  get_list   index,local_nm,remote_nm ; THIS FUNCTION
             jnc        got_one              ; got an entry
   error:    cmp        ax,18

             je         last_one             ; yes
             jmp        error                ; routine not shown
   got_one:  push       bx                   ; save device type
             write_handle  stdout,local_nm,148 ; see Function 40H
             jc         write_error          ; routine not shown
             pop        bx                   ; get device type
             cmp        bl,printer           ; is it a printer?
             je         prntr                ; yes
             write_handle stdout,drive_msg,5 ; see Function 40H
             jc         write_error          ; routine not shown
             jmp        get_next             ; finish message
   prntr:    write_handle stdout,print_msg,7 ; see Function 40H
             jc         write_error          ; routine not shown
   get_next: write_handle stdout,crlf,2      ; see Function 40H
             jc         write_error          ; routine not shown
             inc        index                ; bump index
             jmp        ck_list              ; get next entry
   last_one: write_handle stdout,crlf,4      ; see Function 40H
             jc         write_error          ; routine not shown
   ;


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Make Network Connection (Function 5FH, Code 03H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 5FH
   AL = 03H
   BL
      3 = Printer
      4 = Drive
   CX
      User value
   DS:SI
      Pointer to name of source device
   ES:DI
      Pointer to name of destination
      device

   Return:

   Carry set:
   AX
      1 = Invalid function code
      5 = Access denied
      3 = Path not found
      8 = Insufficient memory
      (Other errors particular to the
      network may occur.)
   Carry not set:
      No error


   Comments:

   Function 5FH, Code 03H, redirects a printer or disk drive (source device)
   to a network directory (destination device). BL must contain 3 if the
   source device is a printer or 4 if it is a disk drive. SI must contain the
   offset (to the segment address in DS) of an ASCIZ string that specifies
   the name of the printer, or a drive letter followed by a colon, or a null
   string (one byte of 00H). DI must contain the offset (to the segment
   address in ES) of an ASCIZ string that specifies the name of a network
   directory. CX contains a user-specified 16-bit value that MS-DOS
   maintains. Microsoft Networks must be running. The destination string must
   be an ASCIZ string of the following form:

   machine-name pathname 00H password 00H

   where:

   Machine-name is the net name of the server that contains the network
   directory.

   Pathname is the alias of the network directory (not the directory path) to
   which the source device is to be redirected.

   00H is a null byte.

   Password is the password for access to the network directory. If no
   password is specified, both null bytes must immediately follow the
   pathname.

   If BL=3, the source string must be PRN, LPT1, LPT2, or LPT3. This function
   buffers and sends all output for the named printer to the remote-printer
   spooler named in the destination string.

   If BL=4, the source string can be either a drive letter followed by a
   colon, or a null string. If the source string contains a valid drive
   letter and colon, this call redirects all subsequent drive-letter
   references to the network directory named in the destination string. If
   the source string is a null string, MS-DOS attempts to grant access to the
   network directory with the specified password.

   The maximum length of the destination string is 128 bytes. You can
   retrieve the value in CX by using Function 5F02H (Get Assign-List Entry).

   If there is an error, the carry flag (CF) is set and the error code
   returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  Microsoft Networks must be running to use this function
                      request; the value in BX is not 1 to 4, the source
                      string is in the wrong format; the destination string
                      is in the wrong format; or the source device is already
                      redirected.

   3                  The network directory path is invalid or doesn't exist.

   5                  The network directory/password combination is not
                      valid. This does not mean that the password itself was
                      invalid; the directory might not exist on the server.

   8                  There is not enough memory for string substitutions.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   redir macro  device,value,source,destination
         mov    bl, device
         mov    cx, value
         mov    si, offset source
         mov    es, seg destination
         mov    di, offset destination
         mov    al, 03H
         mov    ah, 5FH
         int    21H
         endm

   Example:

   The following program redirects two drives and a printer from a
   workstation to a server named harold. It assumes the machine name,
   directory names, and driver letters shown:

   Local drive     Netname
   or printer      on server    Password

   E:              WORD         none
   F:              COMM         fred
   PRN:            PRINTER      quick

   printer   equ  3
   drive     equ  4
   ;
   local_1   db  "e:",0
   local_2   db  "f:",0
   local_3   db  "prn",0
   remote_1  db  "\harold\word",0,0
   remote_2  db  "\harold\comm",0,"fred",0
   remote_3  db  "\harold\printer",0,"quick",0
   ;
   begin:    redir  local_1,remote_1,drive,0   ; THIS FUNCTION
             jc     error                      ; routine not shown
             redir  local_2,remote_2,drive,0   ; THIS FUNCTION
             jc     error                      ; routine not shown
             redir  local_3,remote_3,printer,0 ; THIS FUNCTION
             jc     error                      ; routine not shown


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Delete Network Connection (Function 5FH, Code 04H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 5FH
   AL = 04H
   DS:SI
      Pointer to name of source device

   Return:

   Carry set:
   AX
      1        = Invalid function code
     15        = Redirection paused on server
     (Other errors particular to the network
     may occur.)
   Carry not set:
      No error


   Comments:

   Function 5FH, Code 04H, cancels the redirection of a printer or disk drive
   (source device) to a network directory (destination device) made with
   Function 5F03H (Make Network Connection). SI must contain the offset (to
   the segment address in DS) of an ASCIZ string that specifies the name of
   the printer or drive whose redirection is to be canceled. Microsoft
   Networks must be running.

   The ASCIZ string pointed to by DS:SI can contain one of three values:

   ž  The letter of a redirected drive, followed by a colon. Cancels the
      redirection and restores the drive to its physical meaning.

   ž  The name of a redirected printer (PRN, LPT1, LPT2, LPT3, or their
      machine-specific equivalents). Cancels the redirection and restores the
      printer name to its physical meaning.

   ž  A string starting with \\ (2 backslashes). Terminates the connection
      between the local machine and the network directory.

   If there is an error, the carry flag (CF) is set and the error code
   returns in AX:

   Code               Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  Microsoft Networks must be running to use this function
                      request; or the ASCIZ string names a nonexistent source
                      device.

   15                 Disk or printer redirection on the network server is
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Macro Definition:

   cancel_redir  macro  local
                 mov    si, offset local
                 mov    al, 4
                 mov    ah, 5FH
                 int    21H
                 endm

   Example:

   The following program cancels the redirection of drives E and F and the
   printer (PRN) of a Microsoft Networks workstation. It assumes that these
   local devices were redirected previously.

   local_1   db        "e:",0
   local_2   db        "f:",0
   local_3   db        "prn",0
   ;
   begin:    cancel_redir  local_1    ; THIS FUNCTION
             jc            error      ; routine not shown
             cancel_redir  local_2    ; THIS FUNCTION
             jc            error      ; routine not shown
             cancel_redir  local_3    ; THIS FUNCTION
             jc            error      ; routine not shown


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get PSP (Function 62H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 62H

   Return:

   BX
      Segment address of the Program
      Segment Prefix of the current process


   Comments:

   Function 62H retrieves the segment address of the currently active process
   (the start of the Program Segment Prefix). The address returns in BX.

   Macro Definition:

   get_psp macro
           mov    ah, 62H
           int    21H
           endm

   Example:

   The following program displays the segment address of its Program Segment
   Prefix (PSP) in hexadecimal.

   msg       db       "PSP segment address:  H",0DH,0AH,"$"
   ;
   begin:    get_psp                       ; THIS FUNCTION
             convert   bx,16,msg[21]       ; see end of chapter
             display   msg                 ; see Function 09H


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get Extended Country Information (Function 65H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 65H
   AL
     Function (minor) code

   BX
     Code page (-1 = active CON device)
   CX
     Amount of data to return
   DX
     Country ID for which information is to be returned
     (-1=default country)
   ES:DI
     Address of country information buffer

   Return:


   Carry set:
     1 = Buffer has been filled
     2 = File not found
   Carry not set:
     ES:DI = Pointer to country information buffer


   Comments:

   Function 65H retrieves standard country information. This information
   includes country ID, code page, date and time format, currency symbol,
   separators (for thousands, decimals, data list, date and time) currency
   format flags, digits in currency, and case-mapping information. The
   function code passed in AL may be one of the following:

   Code               Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  Return standard information
   2                  Return pointer to uppercase table
   4                  Return pointer to filename uppercase table
   6                  Return pointer to collating table
   7                  Selects the Double Byte Character Set (DBCS)
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Only the information for the default country is kept in the kernel.
   Country-dependent information for all other countries is contained in the
   country.sys file. The MS-DOS nlsfunc command is used to access the
   country-dependent information in country.sys using this call. If the
   country code and code page number do not match, or if either is invalid,
   error code 2 is returned to AX. If CX is less than 5, error code 1 is
   returned. If the amount of information requested is greater than the value
   of CX, only CX bytes are returned and no error is reported.

   If AL = 1, the buffer is filled with the following information:

   db    1    ;   Information ID
   dw    ?    ;   Size (<=38)
   dw    ?    ;   Country ID
   dw    ?    ;   Code page

   If AL = 2, the buffer is filled with the following information:

   db    2    ;   Information ID
   dd    ?    ;   Double-word pointer to uppercase table

   If AL = 4, the buffer is filled with the following information:

   db    4    ;   Information ID
   dd    ?    ;   Double-word pointer to filename uppercase table

   Both of these tables consist of a length field (two bytes) followed by 128
   uppercase values for the upper 128 ASCII characters. The following formula
   is used to compute the address of an uppercase equivalent in the table:

   Address of outchar = inchar - (256-tableÄÄlen) = tableÄÄstart

   where:

   Parameter          Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   inchar             Character to be generated
   tableÄÄlen         Length of list of uppercase values (two bytes)
   tableÄÄstart       Starting address of uppercase table
   outchar            Uppercase value for inchar
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   If inchar is greater than or equal to (256 - tableÄÄlen), then there is an
   uppercase equivalent in the table; otherwise, there is not.

   If AL = 6, the buffer is filled with the following information:

   db    6    ;   Information ID
   dd    ?    ;   Double-word pointer to collating sequence

   The table is 258 bytes long. The first word is the length of the table.
   The rest of the table is 256 ASCII values in the appropriate order.


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Get/Set Global Code Page (Function 66H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 66H
   AL
     Function (minor) code
   BX
     Code page to set (AL = 2)

   Return:

   Carry set:
   AX
    02 = File not found
    65 = Device not selected
   Carry not set:
     No error


   Comments:

   Function 66H gets or sets the code page used by the kernel and all
   devices. If no other code page has been set, this function gets the
   default code page from DX. If another code page is set, this function
   retrieves the active code page from BX.

   The MS-DOS nlsfunc command and country.sys must be on the system if this
   function is to be used to change the global code page. The function code
   may be one of the following:

   Code               Description
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1                  Get code page
   2                  Set code page
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   MS-DOS gets the new code page from the country.sys file. Devices must be
   prepared for code page switching before a code page can be selected. To
   prepare a device, a device driver that supports code-page switching must
   be installed by using the device command in the config.sys file. The user
   must also use the prepare keyword with the MS-DOS mode command to prepare
   the device for code-page switching.

   The code page selected must be compatible with the country code specified
   in the config.sys file. If MS-DOS cannot read country.sys or another
   specified country information file, error code 02 is returned to AX.


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Set Handle Count (Function 67H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 67H
   BX
     Number of allowed handles

   Return:

   Carry set:
   AX
   Carry not set:
     No error


   Comments:

   Function 67H increases or decreases the number of files a program can have
   open at one time. The maximum number of file handles is 64K. If less than
   20 are specified, the minimum handle number, 20, is assumed. If this call
   is used to reduce the number of allowed handles, the new limit does not
   take affect until any handles above the new limit are closed.

   The user should use Function 4AH (Set Block) to allocate memory for the
   extended handle list if BX is greater than 255. The maximum number for the
   value of the config.sys command files is 255.


 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Commit File (Function 68H)
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Call:

   AH = 68H
   BX
     File handle

   Return:

   Carry set:
   AX = error
   Carry not set
     No error


   Comments:

   Function 68H flushes all buffered data for a file without closing it.
   Using this call is more efficient than using the traditional close-open
   sequence, and is more effective for network environments. This call makes
   sure that the disk image of a file is current.

   ;  Macro Definitions for MS-DOS System Call Examples
   ;
   ; *******************
   ;  Interrupts
   ; *******************
   ;                                 Interrupt 25H
   ABS_DISK_READ  macro  disk,buffer,num_sectors,first_sector
        mov    al,disk
        mov    bx,offset buffer
        mov    cx,num_sectors
        mov    dx,first_sector
        int    25H
        popf
        endm
   ;                                 Interrupt 26H
   ABS_DISK_WRITE  macro  disk,buffer,num_sectors,first_sector
        mov    al,disk
        mov    bx,offset buffer
        mov    cx,num_sectors
        mov    dx,first_sector
        int    26H
        popf
        endm
   ;                                 Interrupt 27H
   STAY_RESIDENT  macro  last_instruc
        mov    dx,offset last_instruc
        inc    dx
        int    27H
        endm
   ;
   ;
   ; *******************
   ;  Function Requests
   ; *******************
   ;                                 Function Request 00H
   TERMINATE_PROGRAM  macro
        xor    ah,ah
        int    21H
        endm
   ;                                 Function Request 01H
   READ_KBD_AND_ECHO  macro
        mov    ah,01H
        int    21H
        endm
   ;                                 Function Request 02H
   DISPLAY_CHAR  macro  character
        mov    dl,character
        mov    ah,02H
        int    21H
        endm
   ;                                 Function Request 03H
   AUX_INPUT    macro
        mov     ah,03H
        int     21H
        endm
   ;                                 Function Request 04H
   AUX_OUTPUT  macro
        mov    ah,04H
        int    21H
        endm
   ;                                 Function Request 05H
   PRINT_CHAR  macro  character
        mov    dl,character
        mov    ah,05H
        int    21H
        endm
   ;                                 Function Request 06H
   DIR_CONSOLE_IO  macro  switch
        mov    dl,switch
        mov    ah,06H
        int    21H
        endm
   ;                                 Function Request 07H
   DIR_CONSOLE_INPUT  macro
        mov    ah,07H
        int    21H
        endm
   ;                                 Function Request 08H
   READ_KBD  macro
        mov    ah,08H
        int    21H
        endm
   ;                                 Function Request 09H
   DISPLAY  macro  string
        mov    dx,offset string
        mov    ah,09H
        int    21H
        endm
   ;                                 Function Request 0AH
   GET_STRING  macro  limit,string
        mov    dx,offset string
        mov    string,limit
        mov    ah,0AH
        int    21H
        endm
   ;                                 Function Request 0BH
   CHECK_KBD_STATUS  macro
        mov    ah,0BH
        int    21H
        endm
   ;                                 Function Request 0CH
   FLUSH_AND_READ_KBD  macro  switch
        mov    al,switch
        mov    ah,0CH
        int    21H
        endm
   ;                                 Function Request 0DH
   RESET_DISK  macro
        mov    ah,0DH
        int    21H
        endm
   ;                                 Function Request 0EH
   SELECT_DISK  macro  disk
        mov    dl,disk[-65]
        mov    ah,0EH
        int    21H
        endm
   ;                                 Function Request 0FH
   OPEN  macro  fcb
        mov    dx,offset fcb
        mov    ah,0FH
        int    21H
        endm
   ;                                 Function Request 10H
   CLOSE  macro  fcb
        mov    dx,offset fcb
        mov    ah,10H
        int    21H
        endm
   ;                                 Function Request 11H
   SEARCH_FIRST  macro  fcb
        mov    dx,offset fcb
        mov    ah,11H
        int    21H
        endm
   ;                                 Function Request 12H
   SEARCH_NEXT  macro  fcb
        mov    dx,offset fcb
        mov    ah,12H
        int    21H
        endm
   ;                                 Function Request 13H
   DELETE  macro  fcb
        mov    dx,offset fcb
        mov    ah,13H
        int    21H
        endm
   ;                                 Function Request 14H
   READ_SEQ  macro  fcb
        mov    dx,offset fcb
        mov    ah,14H
        int    21H
        endm
   ;                                 Function Request 15H
   WRITE_SEQ  macro  fcb
        mov    dx,offset fcb
        mov    ah,15H
        int    21H
        endm
   ;                                 Function Request 16H
   CREATE  macro  fcb
        mov    dx,offset fcb
        mov    ah,16H
        int    21H
        endm
   ;                                 Function Request 17H
   RENAME  macro  fcb,newname
        mov    dx,offset fcb
        mov    ah,17H
        int    21H
        endm
   ;                                 Function Request 19H
   CURRENT_DISK  macro
        mov    ah,19H
        int    21H
        endm
   ;                                 Function Request 1AH
   SET_DTA  macro  buffer
        mov    dx,offset buffer
        mov    ah,1AH
        endm
   ;                                 Function Request 1BH
   DEF_DRIVE_DATA  macro
        mov    ah,1BH
        int    21H
        endm
   ;                                 Function Request 1CH
   DRIVE_DATA  macro  drive
        mov    dl,drive
        mov    ah,1CH
        int    21H
        endm
   ;                                 Function Request 21H
   READ_RAN  macro  fcb
        mov    dx,offset fcb
        mov    ah,21H
        int    21H
        endm
   ;                                 Function Request 22H
   WRITE_RAN  macro  fcb
        mov    dx,offset fcb
        mov    ah,22H
        int    21H
        endm
   ;                                 Function Request 23H
   FILE_SIZE  macro  fcb
        mov    dx,offset fcb
        mov    ah,23H
        int    21H
        endm
   ;                                 Function Request 24H
   SET_RELATIVE_RECORD  macro  fcb
        mov    dx,offset fcb
        mov    ah,24H
        int    21H
        endm
   ;                                 Function Request 25H
   SET_VECTOR  macro  interrupt,handler_start
        mov    al,interrupt
        mov    dx,offset handler_start
        mov    ah,25H
        int    21H
        endm
   ;                                 Function Request 26H
   CREATE_PSP  macro  seg_addr
        mov    dx,offset seg_addr
        mov    ah,26H
        int    21H
        endm
   ;                                  Function Request 27H
   RAN_BLOCK_READ  macro  fcb,count,rec_size
        mov    dx,offset fcb
        mov    cx,count
        mov    word ptr fcb[14],rec_size
        mov    ah,27H
        int    21H
        endm
   ;                                  Function Request 28H
   RAN_BLOCK_WRITE  macro  fcb,count,rec_size
        mov    dx,offset fcb
        mov    cx,count
        mov    word ptr fcb[14],rec_size
        mov    ah,28H
        int    21H
        endm
   ;                                 Function Request 29H
   PARSE  macro  string,fcb
        mov    si,offset string
        mov    di,offset fcb
        push   es
        push   ds
        pop    es
        mov    al,0FH
        mov    ah,29H
        int    21H
        pop    es
        endm
   ;                                  Function Request 2AH
   GET_DATE  macro
        mov    ah,2AH
        int    21H
        endm
   ;                                  Function Request 2BH
   SET_DATE  macro  year,month,day
        mov    cx,year
        mov    dh,month
        mov    dl,day
        mov    ah,2BH
        int    21H
        endm
   ;                                  Function Request 2CH
   GET_TIME  macro
        mov    ah,2CH
        int    21H
        endm
   ;                                  Function Request 2DH
   SET_TIME  macro  hour,minutes,seconds,hundredths
        mov    ch,hour
        mov    cl,minutes
        mov    dh,seconds
        mov    dl,hundredths
        mov    ah,2DH
        int    21H
        endm
   ;                                  Function Request 2EH
   VERIFY  macro  switch
        mov    al,switch
        mov    ah,2EH
        int    21H
        endm
   ;                                  Function Request 2FH
   GET_DTA  macro
        mov    ah,2FH
        int    21H
        endm
   ;                                  Function Request 30H
   GET_VERSION  macro
        mov    ah,30H
        int    21H
        endm
   ;                                  Function Request 31H
   KEEP_PROCESS  macro  return_code,last_byte
        mov    al,return_code
        mov    dx,offset last_byte
        mov    cl,4
        shr    dx,cl
        inc    dx
        mov    ah,31H
        int    21H
        endm
   ;                                  Function Request 33H
   CTRL_C_CK  macro  action,state
        mov    al,action
        mov    dl,state
        mov    ah,33H
        int    21H
        endm
   ;                                  Function Request 35H
   GET_VECTOR  macro  interrupt
        mov    al,interrupt
        mov    ah,35H
        int    21H
        endm
   ;                                  Function Request 36H
   GET_DISK_SPACE  macro  drive
        mov    dl,drive
        mov    ah,36H
        int    21H
        endm
   ;                                  Function Request 38H
   GET_COUNTRY  macro  country,buffer
                local  gc_01
                mov    dx,offset buffer
                mov    ax,country
                cmp    ax,0FFH
                jl     gc_01
                mov    al,0ffh
                mov    bx,country
   gc_01:       mov    ah,38H
                int    21H
                endm
   ;                                  Function Request 38H
   SET_COUNTRY  macro  country
                local  sc_01
                mov    dx,0FFFFH
                mov    ax,country
                cmp    ax,0FFH
                jl     sc_01
                mov    al,0ffh
                mov    bx,country
   sc_01:       mov    ah,38H
                int    21H
                endm
   ;                                  Function Request 39H
   MAKE_DIR  macro  path
        mov    dx,offset path
        mov    ah,39H
        int    21H
        endm
   ;                                  Function Request 3AH
   REM_DIR  macro  path
        mov    dx,offset path
        mov    ah,3AH
        int    21H
        endm
   ;                                  Function Request 3BH
   CHANGE_DIR  macro  path
        mov    dx,offset path
        mov    ah,3BH
        int    21H
        endm
   ;                                  Function Request 3CH
   CREATE_HANDLE  macro  path,attrib
        mov    dx,offset path
        mov    cx,attrib
        mov    ah,3CH
        int    21H
        endm
   ;                                  Function Request 3DH
   OPEN_HANDLE  macro  path,access
        mov    dx,offset path
        mov    al,access
        mov     ah,3DH
        int    21H
        endm
   ;                                  Function Request 3EH
   CLOSE_HANDLE  macro  handle
        mov    bx,handle
        mov    ah,3EH
        int    21H
        endm
   ;                                  Function Request 3FH
   READ_HANDLE  macro  handle,buffer,bytes
        mov    bx,handle
        mov    dx,offset buffer
        mov    cx,bytes
        mov    ah,3FH
        int    21H
        endm
   ;                                  Function Request 40H
   WRITE_HANDLE  macro  handle,buffer,bytes
        mov    bx,handle
        mov    dx,offset buffer
        mov    cx,bytes
        mov    ah,40H
        int    21H
        endm
   ;                                  Function Request 41H
   DELETE_ENTRY  macro  path
        mov    dx,offset path
        mov    ah,41H
        int    21H
        endm
   ;                                  Function Request 42H
   MOVE_PTR  macro  handle,high,low,method
        mov    bx,handle
        mov    cx,high
        mov    dx,low
        mov    al,method
        mov    ah,42H
        int    21H
        endm
   ;                                  Function Request 43H
   CHANGE_MODE  macro  path,action,attrib
        mov    dx,offset path
        mov    al,action
        mov    cx,attrib
        mov    ah,43H
        int    21H
        endm
   ;                                  Function Request 4400H,01H
   IOCTL_DATA  macro  code,handle
        mov    bx,handle
        mov    al,code
        mov    ah,44H
        int    21H
        endm
   ;                                  Function Request 4402H,03H
   IOCTL_CHAR  macro  code,handle,buffer
        mov    bx,handle
        mov    dx,offset buffer
        mov    al,code
        mov    ah,44H
        int    21H
        endm
   ;                                  Function Request 4404H,05H
   IOCTL_STATUS  macro  code,drive,buffer
        mov    bl,drive
        mov    dx,offset buffer
        mov    al,code
        mov    ah,44H
        int    21H
        endm
   ;                                  Function Request 4406H,07H
   IOCTL_STATUS macro  code,handle
        mov    bx,handle
        mov    al,code
        mov    ah,44H
        int    21H
        endm
   ;                                  Function Request 4408H
   IOCTL_CHANGE  macro  drive
        mov    bl,drive
        mov    al,08H
        mov    ah,44H
        int    21H
        endm
   ;                                  Function Request 4409H
   IOCTL_RBLOCK  macro  drive
        mov    bl,drive
        mov    al,09H
        mov    ah,44H
        int    21H
        endm
   ;                                  Function Request 440AH
   IOCTL_RHANDLE  macro  handle
        mov    bx,handle
        mov    al,0AH
        mov    ah,44H
        int    21H
        endm
   ;                                  Function Request 440BH
   IOCTL_RETRY  macro  retries,wait
        mov    dx,retries
        mov    cx,wait
        mov    al,0BH
        mov    ah,44H
        int    21H
        endm
   ;                                  Function Request 440CH
   GENERIC_IOCTL_HANDLES macro handle,function,category,buffer
        mov    ch,05H
        mov    cl,function
        mov    dx,offset buffer
        mov    bx,handle
        mov    ah,44H
        mov    al,0CH
        int    21H
        endm
   ;                                  Function Request 440DH
   GENERIC_IOCTL_BLOCK macro drive_num,function,category,parm_blk
        mov    ch,08H
        mov    cl,function
        mov    dx,offset parm_blk - 1
        mov    bx,drive_num
        mov    ah,44H
        mov    al,0DH
        int    21H
        endm
   ;                                  Function Request 440EH
   IOCTL_GET_DRIVE_MAP macro   logical_drv
        mov    bx,logical_drv
        mov    ah,44H
        mov    al,0EH
        int    21H
        endm
   ;                                  Function Request 440FH
   IOCTL_SET_DRIVE_MAP macro   logical_drv
        mov    bx,logical_drv
        mov    ah,44H
        mov    al,0FH
        int    21H
        endm
   ;                                  Function Request 45H
   XDUP  macro  handle
        mov    bx,handle
        mov    ah,45H
        int    21H
        endm
   ;                                  Function Request 46H
   XDUP2  macro  handle1,handle2
        mov    bx,handle1
        mov    cx,handle2
        mov    ah,46H
        int    21H
        endm
   ;                                  Function Request 47H
   GET_DIR  macro  drive,buffer
        mov    dl,drive
        mov    si,offset buffer
        mov    ah,47H
        int    21H
        endm
   ;                                  Function Request 48H
   ALLOCATE_MEMORY  macro  bytes
        mov    bx,bytes
        mov    cl,4
        shr          bx,cl
        inc    bx
        mov    ah,48H
        int    21H
        endm
   ;                                  Function Request 49H
   FREE_MEMORY  macro  seg_addr
        mov    ax,seg_addr
        mov    es,ax
        mov    ah,49H
        int    21H
        endm
   ;                                  Function Request 4AH
   SET_BLOCK  macro  last_byte
        mov    bx,offset last_byte
        mov    cl,4
        shr    bx,cl
        add    bx,17
        mov    ah,4AH
        int    21H
        mov     ax,bx
        shl     ax,cl
        dec     ax
        mov     sp,ax
        mov     bp,sp
        endm
   ;                                  Function Request 4B00H
   EXEC macro  path,command,parms
        mov    dx,offset path
        mov    bx,offset parms
        mov    word ptr parms[02h],offset command
        mov    word ptr parms[04h],cs
        mov    word ptr parms[06h],5ch
        mov    word ptr parms[08h],es
        mov    word ptr parms[0ah],6ch
        mov    word ptr parms[0ch],es
        mov    al,0
        mov    ah,4BH
        int    21H
        endm
   ;                                  Function Request 4B03H
   EXEC_OVL  macro  path,parms,seg_addr
         mov    dx,offset path
         mov    bx,offset parms
         mov    parms,seg_addr
         mov    parms[02H],seg_addr
         mov    al,3
         mov    ah,4BH
         int    21H
         endm
   ;                                  Function Request 4CH
   END_PROCESS  macro  return_code
                mov    al,return_code
                mov    ah,4CH
                int    21H
                endm
   ;                                  Function Request 4DH
   RET_CODE macro
         mov    ah,4DH
         int    21H
         endm
   ;                                  Function Request 4EH
   FIND_FIRST_FILE  macro  path,attrib
        mov    dx,offset path
        mov    cx,attrib
        mov    ah,4EH
        int    21H
        endm
   ;                                  Function Request 4FH
   FIND_NEXT_FILE  macro
        mov    ah,4FH
        int    21H
        endm
   ;                                  Function Request 54H
   GET_VERIFY  macro
        mov    ah,54H
        int    21H
        endm
   ;                                  Function Request 56H
   RENAME_FILE  macro  old_path,new_path
        mov    dx,offset old_path
        push   ds
        pop    es
        mov    di,offset new_path
        mov    ah,56H
        int    21H
        endm
   ;                                  Function Request 57H
   GET_SET_DATE_TIME  macro  handle,action,time,date
        mov     bx,handle
        mov    al,action
        mov    cx,word ptr time
        mov    dx,word ptr date
        mov    ah,57H
        int    21H
        endm
   ;                                  Function Request 58H
   ALLOC_STRAT  macro  code,strategy
        mov    bx,strategy
        mov    al,code
        mov    ah,58H
        int    21H
        endm
   ;                                  Function Request 59H
   GET_ERROR  macro
        mov    ah,59
        int    21H
        endm
   ;                                  Function Request 5AH
   CREATE_TEMP  macro  pathname,attrib
                mov    cx,attrib
                mov    dx,offset pathname
                mov    ah,5AH
                int    21H
                endm
   ;                                  Function Request 5BH
   CREATE_NEW  macro  pathname,attrib
               mov    cx,attrib
               mov    dx,offset pathname
               mov    ah,5BH
               int    21H
               endm
   ;                                  Function Request 5C00H
   LOCK        macro  handle,start,bytes
               mov    bx,handle
               mov    cx,word ptr start
               mov    dx,word ptr start+2
               mov    si,word ptr bytes
               mov    di,word ptr bytes+2
               mov    al,0
               mov    ah,5CH
               int    21H
               endm
   ;                                  Function Request 5C01H
   UNLOCK      macro  handle,start,bytes
               mov    bx,handle
               mov    cx,word ptr start
               mov    dx,word ptr start+2
               mov    si,word ptr bytes
               mov    di,word ptr bytes+2
               mov    al,1
               mov    ah,5CH
               int    21H
               endm
   ;                                  Function Request 5E00H
   GET_MACHINE_NAME  macro  buffer
               mov    dx,offset buffer
               mov    al,0
               mov    ah,5EH
               int    21H
               endm
   ;                                  Function Request 5E02H
   PRINTER_SETUP  macro  index,lgth,string
               mov    bx,index
               mov    cx,lgth
               mov    dx,offset string
               mov    al,2
               mov    ah,5EH
               int    21H
               endm
   ;                                  Function Request 5F02H
   GET_LIST    macro  index,local,remote
               mov    bx,index
               mov    si,offset local
               mov    di,offset remote
               mov    al,2
               mov    ah,5FH
               int    21H
               endm
   ;                                  Function Request 5F03H
   REDIR       macro  device,value,source,destination
               mov    bl,device
               mov    cx,value
               mov    si,offset source
               mov    es,seg destination
               mov    di,offset destination
               mov    al,03H
               mov    ah,5FH
               int    21H
               endm
   ;                                  Function Request 5F04H
   CANCEL_REDIR  macro  local
               mov    si,offset local
               mov    al,4
               mov    ah,5FH
               int    21H
               endm
   ;                                  Function Request 62H
   GET_PSP     macro
               mov    ah,62H
               int    21H
               endm
   ;
   ;
   ; *******************
   ;  General
   ; *******************
   ;
   DISPLAY_ASCIZ  macro  asciz_string
        local  search,found_it
        mov    bx,offset asciz_string

   search:
        cmp    byte ptr [bx],0
        je     found_it
        inc    bx
        jmp short search

   found_it:
        mov    byte ptr [bx],"$"
        display asciz_string
        mov    byte ptr [bx],0
        display_char 0DH
        display_char 0AH
        endm
   ;
   MOVE_STRING  macro  source,destination,count
        push   es
        push   ds
        pop    es
        assume es:code
        mov    si,offset source
        mov    di,offset destination
        mov    cx,count
    rep movs   es:destination,source
        assume es:nothing
        pop    es
        endm
   ;
   CONVERT  macro  value,base,destination
        local  table,start
        jmp    start
   table  db   "0123456789ABCDEF"

   start:
        push   ax
        push   bx
        push   dx
        mov    al,value
        xor    ah,ah
        xor    bx,bx
        div    base
        mov    bl,al
        mov    al,cs:table[bx]
        mov    destination,al
        mov    bl,ah
        mov    al,cs:table[bx]
        mov    destination[1],al
        pop    dx
        pop    bx
        pop    ax
        endm
   ;
   CONVERT_TO_BINARY  macro  string,number,value
        local  ten,start,calc,mult,no_mult
        jmp    start
   ten  db     10

   start:
        mov    value,0
        xor    cx,cx
        mov    cl,number
        xor    si,si

   calc:
        xor    ax,ax
        mov    al,string[si]
        sub    al,48
        cmp    cx,2
        jl     no_mult
        push   cx
        dec    cx

   mult:
        mul    cs:ten
        loop   mult
        pop    cx

   no_mult:
        add    value,ax
        inc    si
        loop   calc
        endm
   ;
   CONVERT_DATE  macro  dir_entry
        mov    dx,word ptr dir_entry[24]
        mov    cl,5
        shr    dl,cl
        mov    dh,dir_entry[24]
        and    dh,1FH
        xor    cx,cx
        mov    cl,dir_entry[25]
        shr    cl,1
        add    cx,1980
        endm
   ;
   PACK_DATE  macro  date
        local set_bit
   ;
   ;  On entry: DH=day, DL=month, CX=(year-1980)
   ;
        sub   cx,1980
        push  cx
        mov   date,dh
        mov   cl,5
        shl   dl,cl
        pop   cx
        jnc   set_bit
        or    cl,80h

   set_bit:
        or    date,dl
        rol   cl,1
        mov   date[1],cl
        endm
   ;






 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Chapter 2  MS-DOS Device Drivers

     2.1   Introduction
     2.2   Format of a Device Driver
     2.3   How to Create a Device Driver
           2.3.1   Device Strategy Routine
           2.3.2   Device Interrupt Routine
     2.4   Installing Device Drivers
     2.5   Device Headers
           2.5.1   Pointer to Next Device Field
           2.5.2   Attribute Field
           2.5.3   Strategy and Interrupt Routines
           2.5.4   Name Field
     2.6   Request Header
           2.6.1   Length of Record
           2.6.2   Unit Code Field
           2.6.3   Command Code Field
           2.6.4   Status Field
     2.7   Device Driver Functions
           2.7.1   The Init Function
           2.7.2   The Media Check Function
           2.7.3   The Build BPB Function
           2.7.4   The Read or Write Function
           2.7.5   The Non-destructive Read, No Wait Function
           2.7.6   The Open or Close Function
           2.7.7   The Removable Media Function
           2.7.8   The Status Function
           2.7.9   The Flush Function
           2.7.10  The Generic IOCtl Function
           2.7.11  The Get/Set Logical Drive Map Function
     2.8   The Media Descriptor Byte
     2.9   Format of a Media Descriptor Table
     2.10  The CLOCK Device
     2.11  Anatomy of a Device Call
     2.12  Two Sample Device Drivers


 2.1  Introduction

   The io.sys file comprises the "resident" device drivers, which form the
   MS-DOS BIOS. These drivers are called upon by MS-DOS to handle
   input/output (I/O) requests initiated by application programs.

   One of the most powerful features of MS-DOS is the ability to add new
   devices such as printers, plotters, and mouse input devices without
   rewriting the BIOS. The MS-DOS BIOS is configurable; that is, new drivers
   can be added and existing drivers can be preempted. Nonresident, or
   installable, device drivers may be easily added at boot time by including
   a device command line in the config.sys file.

   At boot time, a minimum of five resident device drivers must be present.
   These drivers are in a linked list: the header of each one contains a
   DWORD pointer to the next. The last driver in the chain has an end-of-list
   marker of -1, -1 (all bits on).

   Each driver in the chain has two entry points: the strategy entry point
   and the interrupt entry point. MS-DOS does not take advantage of the two
   entry points: it calls the strategy routine, then immediately calls the
   interrupt routine.

   The dual entry points will accomodate future multitasking versions of
   MS-DOS. In multitasking environments, I/O must be asynchronous; to
   accomplish this, the strategy routine will be called to (internally) queue
   a request and return quickly. It is then the responsibility of the
   interrupt routine to perform the I/O at interrupt time by getting requests
   from the internal queue and processing them. When a request is completed,
   it is flagged as "done" by the interrupt routine. MS-DOS periodically
   scans the list of requests looking for those that are flagged as done, and
   "wakes up" the process waiting for the completion of the request.

   When requests are queued in this manner, it is no longer sufficient to
   pass I/O information in registers, since many requests may be pending at
   any time. Therefore, the MS-DOS device interface uses "packets" to pass
   request information. These request packets vary in size and format, and
   are composed of two parts:

   1. The static request header section, which has the same format for all
      requests

   2. A section which has information specific to the type of request

   A driver is called with a pointer to a packet. In multitasking versions,
   this packet will be linked into a global chain of all pending I/O requests
   maintained by MS-DOS.

   MS-DOS does not implement a global or local queue. Only one request is
   pending at any one time. The strategy routine must store the address of
   the packet at a fixed location, and the interrupt routine, which is called
   immediately after the strategy routine, should process the packet by
   completing the request and returning. It is assumed that the request is
   completed when the interrupt routine returns.

   To make a device driver that sysinit can install, a .bin (core image) or
   .exe format file must be created with the device driver header at the
   beginning of the file. The link field should be initialized to -1 (sysinit
   fills it in). Device drivers which are part of the BIOS should have their
   headers point to the next device in the list and the last header should be
   initialized to -1,-1. The BIOS must be a .bin (core image) format file.

   The .exe format installable device drivers may be used in non-IBM versions
   of MS-DOS. On the IBM Personal Computer, the .exe loader is located in
   command.com, which is not present at the time that installable devices are
   being loaded.


 2.2  Format of a Device Driver

   A device driver is a program segment responsible for communication between
   DOS and the system hardware. It has a special header at the beginning
   identifying it as a device driver, defining entry points, and describing
   various attributes of the device.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     For device drivers, the file must not use the ORG 100H (like .com
     files). Because it does not use the Program Segment Prefix (PSP), the
     device driver is simply loaded; therefore, the file must have an origin
     of zero (ORG 0 or no ORG statement).
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   There are two kinds of device drivers:

   ž  Character device drivers

   ž  Block device drivers

   Character devices perform serial character I/O. Examples are the console,
   communications port, and printer. These devices are named (i.e., CON, AUX,
   CLOCK, etc.), and programs may open channels (handles or file control
   blocks) to do I/O to them.

   Block devices include all the disk drives on the system. They can perform
   random I/O in structured pieces called blocks (usually the physical sector
   size). These devices are not named as the character devices are and,
   therefore, cannot be opened directly. Instead they have unit numbers and
   are identified by drive letters such as A, B, and C.

   A single block device driver may be responsible for one or more logically
   contiguous disk drives. For example, block device driver ALPHA may be
   responsible for drives A, B, C, and D. This means that it has four units
   defined (0-3) and, therefore, takes up four drive letters. The position of
   the driver in the list of all drivers determines which units correspond to
   which driver letters. If driver ALPHA is the first block driver in the
   device list, and it defines four units (0-3), then they will be A, B, C,
   and D. If BETA is the second block driver and defines three units (0-2),
   then they will be E, F, and G, and so on. The theoretical limit is 63, but
   it should be noted that the device installation code will not allow the
   installation of a device if it would result in a drive letter greater than
   Z (5AH). All block device drivers present in the standard resident BIOS
   will be placed ahead of installable block device drivers in the list.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     Because they have only one name, character devices cannot define
     multiple units.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


 2.3  How to Create a Device Driver

   To create a device driver that MS-DOS can install, you must create a
   binary file (.com or .exe format) with a device header at the beginning of
   the file. Notice that for device drivers, the code should not be
   originated at 100H, but at 0. The device header contains a link field (a
   pointer to the next device header) that should be -1, unless there is more
   than one device driver in the file. The attribute field and entry points
   must be set correctly.

   If it is a character device, the name field should be filled in with the
   name of that character device. The name can be any legal eight-character
   filename. If the name is less than eight characters, it should be padded
   out to eight characters with spaces (20H). Notice that device names do not
   include colons (:). The fact that CON is the same as CON: is a property of
   the default MS-DOS command interpreter (command.com) and not of the device
   driver or the MS-DOS interface. All character device names are handled in
   this way.

   MS-DOS always processes installable device drivers before handling the
   default devices; so, to install a new CON device, simply name the device
   CON. Remember to set the standard input device and standard output device
   bits in the attribute word on a new CON device. The scan of the device
   list stops on the first match, so the installable device driver takes
   precedence.

   It is not possible to replace the resident disk block device driver with
   an installable device driver the same way you can replace the other device
   drivers in the BIOS. Block drivers can be used only for devices not
   directly supported by the default disk drivers in AE@%
   database installed. As an example, if your SQL Server is named sql_svr,
   e
   Note
     Because MS-DOS can install the driver anywhere in memory, care must be
     taken when making far memory references. You should not expect that your
     driver will always be loaded in the same place every time.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

 2.3.1  Device Strategy Routine

   The device strategy routine, which is called by MS-DOS for each device
   driver service request, is primarily responsible for queuing these
   requests in the order in which they are to be processed by the device
   interrupt routine. Such queuing can be a very important performance
   feature in a multitasking environment, or where asynchronous I/O is
   supported. As MS-DOS does not currently support these facilities, only one
   request can be serviced at a time, and this routine is usually very short.
   In the coding examples in Section 2.12, "Two Sample Device Drivers," each
   request is simply stored in a single pointer area.

 2.3.2  Device Interrupt Routine

   The device interrupt routine contains the code necessary to process the
   service request. It may interface to the hardware, or it may use ROM BIOS
   calls. It usually consists of a series of procedures that handle the
   specific command codes to be supported as well as some exit and
   error-handling routines. See the coding examples in Section 2.12, "Two
   Sample Device Drivers."


 2.4  Installing Device Drivers

   MS-DOS allows new device drivers to be installed dynamically at boot time.
   This is accomplished by initialization code in the io.sys file that reads
   and processes the config.sys file.

   MS-DOS calls upon the device drivers to perform their function in the
   following manner:

   1. MS-DOS makes a FAR call to the strategy entry.

   2. MS-DOS passes device driver information in a request header to the
      strategy routine.

   3. MS-DOS makes a FAR call to the interrupt entry.

   This calling structure is designed to be easily upgraded to support any
   future multitasking environment.


 2.5  Device Headers

   A device header is required at the beginning of a device driver. A device
   header looks like this:

   ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³ DWORD Pointer to next device         ³
   ³ (Usually set to -1 if this driver    ³
   ³ is the last or only driver in the    ³
   ³ file)                                ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ WORD Attributes                      ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ WORD Pointer to device strategy      ³
   ³      entry point                     ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ WORD Pointer to device interrupt     ³
   ³      entry point                     ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ 8-BYTE Character device name field   ³
   ³ Character devices set a device name. ³
   ³ For block devices the first byte is  ³
   ³ the number of units.                 ³
   ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   Figure 2.1  Sample Device Header

   Notice that the device entry points are words. They must be offsets from
   the same segment number used to point to this table. For example, if
   xxx:yyy points to the start of this table, then xxx:strategy and
   xxx:interrupt are the entry points.

   The device header fields are described in the following section.

 2.5.1  Pointer to Next Device Field

   The pointer to the next device header field is a double-word field (offset
   followed by segment) that is set by MS-DOS to point at the next driver in
   the system list at the time the device driver is loaded. It is important
   that this field be set to -1 prior to load (when it is on the disk as a
   file) unless there is more than one device driver in the file. If there is
   more than one driver in the file, the first word of the double-word
   pointer should be the offset of the next driver's device header.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     If there is more than one device driver in the file, the last driver in
     the file must have the pointer to the next device header field set to
     -1.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

 2.5.2  Attribute Field

   The attribute field is used to identify the type of device for which this
   driver is responsible. In addition to distinguishing between block and
   character devices, these bits are used to give selected character devices
   special treatment. (Notice that if a bit in the attribute word is defined
   only for one type of device, a driver for the other type of device must
   set that bit to 0.)

   Table 2.1
   For Character Devices:
   Bit        Value                Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0          1                    Device is console input (sti) device
   1          1                    Device is console output (sto) device
   2          1                    Device is nul device
   3          1                    Device is clock device
   4-5                             Reserved (must be 0)
   6          1                    Device supports 3.2 functions
   7-10                            Reserved (must be 0)
   11         1                    Device understands Open/Close
   12                              Reserved (must be 0)
   13         1                    Device supports Output Until Busy (OUB)
   14         1                    Device supports IOCtl control strings
   15         1                    Character device
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Table 2.2
   For Block Devices:
   Bit        Value                Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0                               Reserved (must be 0)
   1          1                    Device supports 32-bit sector addressing
   2-5                             Reserved (must be 0)
   6          1                    Device supports 3.2 functions and Generic
                                   IOCtl function calls
   7-10                            Reserved (must be 0)
   11         1                    Device understands Open/Close/Removable
                                   Media
   12                              Reserved (must be 0)
   13         1                    Device determines the media by examining
                                   the FATID byte
   14         1                    Device supports IOCtl control strings
   15         0                    Block device
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   For example, assume that you have a new device driver that you want to use
   as the standard input and output. In addition to installing the driver,
   you must tell MS-DOS that you want the new driver to override the current
   standard input and standard output (the CON device). This is accomplished
   by setting the attributes to the desired characteristics, so you would set
   bits 0 and 1 to 1 (notice that they are separate). Similarly, a new CLOCK
   device could be installed by setting that attribute. (Refer to Section
   2.10, "The CLOCK Device," in this chapter for more information.) Although
   there is a NUL device attribute, the NUL device cannot be reassigned. This
   attribute exists so that MS-DOS can determine if the NUL device is being
   used.

   Bit 13 for block devices affects the operation of the Build BPB (BIOS
   Parameter Block) device call. If set, it requires the first sector of the
   FAT always to reside in the same place. This bit has a different meaning
   on character devices. It indicates that the device implements the Output
   Until Busy device call.

   The IOCtl bit (bit 14) has meaning on character and block devices. The
   IOCtl functions allow data to be sent and received by the device for its
   own use (to set baud rate, stop bits, form length, etc.) instead of
   passing data over the device channel as a normal read or write does. The
   interpretation of the passed information is up to the device but it must
   not be treated as normal I/O. This bit tells MS-DOS whether the device can
   handle control strings by using the IOCtl system call, Function 44H.

   If a driver cannot process control strings, it should initially set this
   bit to 0. This tells MS-DOS to return an error if an attempt is made (via
   Function 44H) to send or receive control strings to this device. A device
   which can process control strings should initialize the IOCtl bit to 1.
   For drivers of this type, MS-DOS will make calls to the IOCtl input and
   output device functions to send and receive IOCtl strings. The IOCtl
   functions allow data to be sent and received by the device for its own use
   (for example, to set baud rate, stop bits, and form length), instead of
   passing data over the device channel as does a normal read or write. The
   interpretation of the passed information is up to the device, but it must
   not be treated as a normal I/O request.

   The Open/Close/Removable Media bit (bit 11) signals to MS-DOS 3.x and
   later versions whether this driver supports additional MS-DOS 3.x
   functionality. To support these old drivers, it is necessary to detect
   them. This bit was reserved in MS-DOS 2.x, and is 0. All new devices
   should support the Open, Close, and Removable Media calls and set this bit
   to 1. Since MS-DOS 2.x never makes these calls, the driver will be
   backward-compatible.

   The MS-DOS 3.2 bit (bit 6) signals whether the device supports logical
   drive mapping via Function 440EH (Get Logical Drive Map) and Function
   440FH (Set Logical Drive Map). This bit also supports generic IOCtl
   functions via Function 440CH (Generic IOCtl for Handles) and Function
   440DH (Generic IOCtl for Block Devices).

   Bit 1 for block devices indicates the driver's ability to manipulate
   32-bit sector addresses. If bit 1 = 1, 32-bit sector addressing is
   supported. If bit 1 is set, the sector number field of all requests is a
   DWORD added to the end of the request header. The old WORD length sector
   number should be -1.

   The driver requests affected are:

   ž  BUILD BPD command 2

   ž  INPUT/OUTPUT command 3 ,4, 8, 9, and 12

   ž  GENERIC IOCTL command 19

   If bit 1 for block devices is 0, only 16-bit sector addressing is
   available.

     15  14  13  12  11  10  9   8   7   6   5   4   3   2   1   0
   ŚÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄæ
   ³ C ³ I ³   ³   ³ O ³   ³   ³   ³   ³ 3 ³   ³   ³ C ³ N ³ S ³ S ³
   ³ H ³ O ³   ³   ³ P ³   ³   ³   ³   ³ . ³   ³   ³ L ³ U ³ T ³ T ³
   ³ R ³ C ³   ³   ³ N ³   ³   ³   ³   ³ 2 ³   ³   ³ K ³ L ³ O ³ I ³
   ĄÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄŁ

   Figure 2.2  Attribute Word for Character Devices



     15  14  13  12  11  10  9   8   7   6   5   4   3   2   1   0
   ŚÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄæ
   ³   ³ I ³ F ³   ³ O ³   ³   ³   ³   ³ 3 ³   ³   ³   ³   ³ > ³   ³
   ³   ³ O ³ A ³   ³ P ³   ³   ³   ³   ³ . ³   ³   ³   ³   ³ 3 ³   ³
   ³   ³ C ³ T ³   ³ N ³   ³   ³   ³   ³ 2 ³   ³   ³   ³   ³ 2 ³   ³
   ĄÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄŁ

   Figure 2.3  Attribute Word for Block Devices

 2.5.3  Strategy and Interrupt Routines

   These two fields are the pointers to the entry points of the strategy and
   interrupt routines. They are word values, so they must be in the same
   segment as the device header.

 2.5.4  Name Field

   This is an eight-byte field that contains the name of a character device
   or the number of units of a block device. If the field refers to a block
   device, the number of units can be put in the first byte. This is
   optional, because MS-DOS will fill in this location with the value
   returned by the driver's Init code. For more information, see Section
   2.4, "Installing Device Drivers."


 2.6  Request Header

   When MS-DOS calls a device driver to perform a function, it passes a
   request header in ES:BX to the strategy entry point. This is a fixed
   length header, followed by data pertinent to the operation being
   performed. Notice that it is the device driver's responsibility to
   preserve the machine state (for example, save all registers, including
   flags, on entry, and restore them on exit). There is enough room on the
   stack when the strategy or interrupt routine is called to do about 20
   pushes. If more room on the stack is needed, the driver should set up its
   own stack.

   The following figure illustrates a request header.

   REQUEST HEADER ->
   ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³ BYTE Length of record       ³
   ³  Length in bytes of this    ³
   ³  request header             ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ BYTE Unit code              ³
   ³  The subunit the operation  ³
   ³  is for (minor device)      ³
   ³  (no meaning on character   ³
   ³   devices)                  ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ BYTE Command code           ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ WORD Status                 ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ 8 BYTES Reserved            ³
   ³                             ³
   ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   Figure 2.4  Request Header

   The request header fields are described below.

 2.6.1  Length of Record

   This field contains the length (in bytes) of the request header.

 2.6.2  Unit Code Field

   The unit code field identifies which unit in your device driver the
   request is for. For example, if your device driver has three units
   defined, then the possible values of the unit code field would be 0, 1,
   and 2.

 2.6.3  Command Code Field

   The command code field in the request header can have the following
   values:

ÖŚÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ·
   Code               Function
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0                  Init
   1                  Media Check (Block devices only)
   2                  Build BPB (Block devices only)
   3                  IOCtl Input (Only called if device has IOCtl)
   4                  Input (Read)
   5                  Non-destructive Read, No Wait (Character devices only)
   6                  Input Status (Character devices only)
   7                  Input Flush (Character devices only)
   8                  Output (Write)
   9                  Output (Write) with Verify
   10                 Output Status (Character devices only)
   11                 Output Flush (Character devices only)
   Code               Function
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  11                 Output Flush (Character devices only)
   12                 IOCtl Output (Only called if device has IOCtl)
   13                 Device Open (Only called if Open/Close/Removable Media
                      bit set)
   14                 Device Close (Only called if Open/Close/Removable Media
                      bit set)
   15                 Removable Media (Only called if Open/Close/Removable
                      Media bit set and device is block)
   16                 Output Until Busy (Only called if bit 13 is set on
                      character devices)
   19                 Generic IOCtl Request
   23                 Get Logical Device
   24                 Set Logical Device
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


 2.6.4  Status Field

   The following figure illustrates the status field in the request header.

     15  14 13 12 11 10  9   8   7  6  5  4  3  2  1  0
   ŚÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³ E ³               ³ B ³ D ³                       ³
   ³ R ³   Reserved    ³ U ³ O ³ Error code (bit 15 on)³
   ³ R ³               ³ S ³ N ³                       ³
   ³   ³               ³ Y ³ E ³                       ³
   ĄÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   Figure 2.5  Status Field

   The status word is zero on entry and is set by the driver interrupt
   routine on return.

   Bit 8 is the done bit. When set, it means the operation has completed. The
   driver sets it to 1 when it exits.

   Bit 15 is the error bit. If it is set, then the low eight bits indicate
   the error. The errors are as follows:

   Error              Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0                  Write protect violation
   1                  Unknown unit
   2                  Drive not ready
   3                  Unknown command
   4                  CRC error
   5                  Bad drive request structure length
   6                  Seek error
   7                  Unknown media
   8                  Sector not found
   9                  Printer out of paper
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Error              Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   A                  Write fault
   B                  Read fault
   C                  General failure
   D                  Reserved
   E                  Reserved
   F                  Invalid disk change
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Bit 9 is the busy bit, which is set only by Status calls and the Removable
   Media call.


 2.7  Device Driver Functions

   Device drivers may perform all or some of these general functions. In some
   cases, these functions break down into several command codes, for specific
   cases. Each of the following general functions is described in this
   section.

   ž  Init

   ž  Media Check

   ž  Build BPB

   ž  Read, or Write, or Write Until Busy, or Write with Verify, or Read
      IOCtl, or Write IOCtl

   ž  Non-destructive Read, No Wait

   ž  Open or Close (3.x)

   ž  Removable Media (3.x)

   ž  Status

   ž  Flush

   ž  Generic IOCtl

   ž  Get or Set Logical Device

   All strategy routines are called with ES:BX pointing to the request
   header. The interrupt routines get the pointers to the request header from
   the queue that the strategy routines store them in. The command code in
   the request header tells the driver which function to perform and what
   data follows the request header.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     All DWORD pointers are stored offset first, then segment.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

 2.7.1  The Init Function

   Command code = 0

   INIT - ES:BX ->
   ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³ 13-BYTE Request header             ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ BYTE Number of units               ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ DWORD End Address                  ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ DWORD Pointer to BPB array         ³
   ³ (Not set by character devices)     ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ BYTE Block device number           ³
   ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   One of the functions defined for each device driver is Init. This routine
   is called only once when the device is installed. The Init routine must
   return the end address, which is a DWORD pointer to the end of the portion
   of the device driver to remain resident. To save space, you can use this
   pointer method to delete initialization code that is needed only once.

   The number of units, end address, and BPB pointer are to be set by the
   driver. However, on entry for installable device drivers, the DWORD that
   is to be set by the driver to the BPB array (on block devices) points to
   the character after the "=" on the line in config.sys that caused this
   device driver to be loaded. This allows drivers to scan the config.sys
   invocation line for parameters that might be passed to the driver. This
   line is terminated by an ENTER or a linefeed character. This data is
   read-only and allows the device to scan the config.sys command line for
   arguments.

        device=\dev\vt52.sys /l
               ³
               ĄÄÄÄÄÄBPB address points here

   Also, for block devices only, the drive number assigned to the first unit
   defined by this driver (A=0) is contained in the block device number
   field. This is also read-only.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     The Init routine can issue only Functions 01H-0CH, 25H, 30H, and
     35H.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   For installable character devices, the end address parameter must be
   returned. This is a pointer to the first available byte of memory above
   the driver and may be used to throw away initialization code.

   Block devices must return the following information:

   1. The number of units. MS-DOS uses this number to determine logical
      device names. If the current maximum logical device letter is F at the
      time of the install call, and the Init routine returns 4 as the number
      of units, then they will have logical names G, H, I, and J. This
      mapping is determined by the position of the driver in the device list,
      and by the number of units on the device (stored in the first byte of
      the device name field).

   2. A DWORD pointer to an array of word offsets (pointers) to BPBs (BIOS
      Parameter Blocks). The BPBs passed by the device driver are used by
      MS-DOS to create an internal structure. There must be one entry in this
      array for each unit defined by the device driver. In this way, if all
      units are the same, all the pointers can point to the same BPB, thereby
      saving space. If the device driver defines two units, then the DWORD
      pointer points to the first of two one-word offsets which in turn point
      to BPBs. The format of the BPB is described in Section 2.7.3, "The
      Build BPB Function."

      Notice that this array of word offsets must be protected (below the
      free pointer set by the return), since an internal DOS structure will
      be built starting at the byte pointed to by the free pointer. The
      defined sector size must be less than or equal to the maximum sector
      size defined by the resident device drivers (BIOS) during
      initialization. If it isn't, the installation will fail.

   3. The media descriptor byte. This byte means nothing to MS-DOS, but is
      passed to devices so that they know what parameters MS-DOS is currently
      using for a particular drive.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     If there are multiple device drivers in a single file, MS-DOS uses the
     ending address returned by the last Init function called. All device
     drivers in a single file should return the same ending address. All
     devices in a single file should be grouped together low in memory with
     the initialization code for all devices following it in memory.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

 2.7.2  The Media Check Function

   Command Code = 1

   MEDIA CHECK - ES:BX ->
   ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³ 13-BYTE Request header             ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ BYTE Media descriptor from BPB     ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ BYTE Returned                      ³
   ³ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ Returned DWORD pointer to previous ³
   ³ Volume ID if bit 11 set and        ³
   ³ Disk Changed is returned           ³
   ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   The Media Check function is used only with block devices. It is called
   when there is a pending drive-access call other than a file read or write,
   such as Open, Close, delete, and rename. Its purpose is to determine
   whether the media in the drive has been changed. If the driver can assure
   that the media has not been changed (through a door-lock or other
   interlock mechanism), MS-DOS performance is enhanced, because MS-DOS does
   not need to reread the FAT and invalidate in-memory buffers for each
   directory access.

   When a disk-access call to the DOS occurs (other than a file read or
   write), the following sequence of events takes place:

   1. The DOS converts the drive letter into a unit number of a particular
      block device.

   2. The device driver is then called to request a media check on that
      subunit to see if the disk might have been changed. MS-DOS passes the
      old media descriptor byte. The driver returns one of the following:

      Return            Meaning
      ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
      (1)               Media not changed
      (0)               Don't know if changed
      (-1)              Media changed
      value             Error (value is a standard error code value)
      ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

      If the media has not been changed, MS-DOS proceeds with the disk
      access.

      If the value returned is -1, and there are any disk sectors that have
      been modified and not written back out to the disk for this unit,
      MS-DOS assumes that the disk has not been changed and proceeds. MS-DOS
      invalidates any other buffers for the unit and does a Build BPB call
      (see Step 3, following).

      If the media has been changed, MS-DOS invalidates all buffers
      associated with this unit including buffers with modified data that are
      waiting to be written, and requests a new BIOS Parameter Block via the
      Build BPB call (see Step 3).

   3. Once the BPB has been returned, MS-DOS corrects its internal structure
      for the drive from the new BPB and proceeds with the access after
      reading the directory and the FAT.

   Notice that the previous media ID byte is passed to the device driver. If
   the old media ID byte is the same as the new one, the disk might have been
   changed and a new disk may be in the drive; therefore, all FAT, directory,
   and data sectors that are buffered in memory for the drive are considered
   invalid.

   If the driver has bit 11 of the device attribute word set to 1, and the
   driver returns -1 (Media Changed), the driver must set the DWORD pointer
   to the previous Volume ID field. If the DOS determines that "Media
   changed" is an error based on the state of the DOS buffer cache, the DOS
   will generate a 0FH error on behalf of the device. If the driver does not
   implement volume ID support, but has bit 11 set, it should set a static
   pointer to the string "NO NAME" ,0. It is not possible for a user to
   change a disk in less than two seconds. So when Media Check occurs within
   two seconds of a disk access, the driver reports "Media not changed (1)."
   This improves performance tremendously.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     If the media ID byte in the returned BPB is the same as the previous
     media ID byte, MS-DOS will assume that the format of the disk is the
     same (even though the disk may have been changed) and will skip the step
     of updating its internal structure. Therefore, all BPBs must have unique
     media bytes regardless of FAT ID bytes.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

 2.7.3  The Build BPB Function

   Command code = 2

   BUILD BPB - ES:BX ->
   ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³ 13-BYTE Request header             ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ BYTE Media descriptor from BPB     ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ DWORD Transfer address             ³
   ³ (Points to one sector worth of     ³
   ³  scratch space or first sector     ³
   ³  of FAT depending on the value     ³
   ³  of Bit 13 in the device attribute ³
   ³  word.)                            ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ DWORD Pointer to BPB               ³
   ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   The Build BPB function is used with block devices only. As described in
   the Media Check function, the Build BPB function will be called any time
   that a preceding Media Check call indicates that the disk has been or
   might have been changed. The device driver must return a pointer to a BPB.
   This is different from the Init call where the device driver returns a
   pointer to an array of word offsets to BPBs. The Build BPB call gets a
   DWORD pointer to a one-sector buffer. The contents of this buffer are
   determined by the non-FAT ID bit (bit 13) in the attribute field. If the
   bit is zero, then the buffer contains the first sector of the first FAT.
   The FAT ID byte is the first byte of this buffer. In this case, the driver
   must not alter this buffer. Notice that the location of the FAT must be
   the same for all possible media because this first FAT sector must be read
   before the actual BPB is returned. If the non-FAT ID bit is set, the
   pointer points to one sector of scratch space (which may be used for
   anything). For information on how to construct the BPB, see Section 2.8,
   "The Media Descriptor Byte," and Section 2.9, "Format of a Media
   Descriptor Table."

   MS-DOS 4.0 includes additional support for devices that have door-locks or
   some other means of telling when a disk has been changed. There is an
   error that can be returned from the device driver (error 15). The error
   means "the disk has been changed when it shouldn't have been," and the
   user is prompted for the correct disk using a volume ID. The driver may
   generate this error on read or write. The DOS may generate the error on
   Media Check calls if the driver reports media changed and there are
   buffers in the DOS buffer cache that need to be flushed to the previous
   disk.

   For drivers that support this error, the Build BPB function is a trigger
   that causes a new volume ID to be read off the disk. This action indicates
   that the disk has been legally changed. A volume ID is placed on a disk by
   the format command and is simply an entry in the root directory of the
   disk that has the Volume ID attribute. It is stored by the driver as an
   ASCIZ string.

   The requirement that the driver return a volume ID does not exclude some
   other volume identifier scheme as long as the scheme uses ASCIZ strings. A
   NUL (nonexistent or unsupported) volume ID is by convention the following
   string:

   DB     "NO NAME     ",0

 2.7.4  The Read or Write Function

   Command codes = 3,4,8,9,12, and 16

   READ OR WRITE (Including IOCtl) or
      OUTPUT UNTIL BUSY - ES:BX ->
   ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³ 13-BYTE Request header             ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ BYTE Media descriptor from BPB     ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ DWORD Transfer address             ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ WORD Byte/sector count             ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ WORD Starting sector number        ³
   ³ or -1 if the drive supports        ³
   ³ greater than 16-bit sector         ³
   ³ addresses                          ³
   ³  (Ignored on character devices)    ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ DWORD pointer to the Volume ID     ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ Starting sector number             ³
   ³ (high-word first) if WORD starting ³
   ³ sector number is -1                ³
   ³ or                                 ³
   ³ Returned DWORD pointer to requested³
   ³ Volume ID if error 0FH             ³
   ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   Code               Request
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   3                  IOCtl read
   4                  Read (block or character device)
   8                  Write (block or character device)
   9                  Write with Verify
   12                 IOCtl Write
   16                 Output Until Busy (character device only)
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   The driver must perform the Read or Write call depending on which command
   code is set. Block devices read or write sectors; character devices read
   or write bytes.

   When I/O completes, the device driver must set the status word and report
   the number of sectors or bytes successfully transferred. This should be
   done even if an error prevented the transfer from being completed. Setting
   the error bit and error code alone is not sufficient. In addition to
   setting the status word, the driver must set the sector count to the
   actual number of sectors (or bytes) transferred. No error check is
   performed on an IOCtl I/O call. The device driver must always set the
   return byte/sector count to the actual number of bytes/sectors
   successfully transferred.

   If the verify switch is on, the device driver will be called with command
   code 9 (Write with Verify). Your device driver will be responsible for
   verifying the write.

   If the driver returns error code 0FH (Invalid disk change), it must return
   a DWORD pointer to an ASCIZ string (which is the correct volume ID).
   Returning this error code triggers the DOS to prompt the user to re-insert
   the disk. The device driver should have read the volume ID as a result of
   the Build BPB function.

   Drivers may maintain a reference count of open files on the disk by
   monitoring the Open and Close functions. This allows the driver to
   determine when to return error 0FH. If there are no open files (reference
   count = 0), and the disk has been changed, the I/O is okay. If there are
   open files, however, an 0FH error may exist.

   The Output Until Busy call is a speed optimization on character devices
   only for print spoolers. The device driver is expected to output all the
   characters possible until the device returns busy. Under no circumstances
   should the device driver block during this function. Notice that it is not
   an error for the device driver to return the number of bytes output as
   being less than the number of bytes requested (or = 0).

   The Output Until Busy call allows spooler programs to take advantage of
   the "burst" behavior of most printers. Many printers have on-board RAM
   buffers that typically hold a line or a fixed amount of characters. These
   buffers fill up without the printer going busy, or going busy for a short
   period (less than ten instructions) between characters. A line of
   characters can be output quickly to the printer, after which the printer
   is busy for a long time while the characters are being printed. This new
   device call allows background spooling programs to use this burst behavior
   efficiently. Rather than take the overhead of a device driver call for
   each character, or risk getting stuck in the device driver outputting a
   block of characters, this call allows a burst of characters to be output
   without the device driver having to wait for the device to be ready.

   The Following Applies to Block Device Drivers:

   Under certain circumstances, the BIOS may be asked to perform a write
   operation of 64 kilobytes, which seems to be a "wrap-around" of the
   transfer address in the BIOS I/O packet. This request, which arises due to
   an optimization added to the write code in MS-DOS, will manifest itself
   only on user writes that are within a sector size of 64 kilobytes on files
   "growing" past the current end-of-file (EOF) mark. It is allowable for the
   BIOS to ignore the balance of the write that "wraps around" if it so
   chooses. For example, a write of 10000H bytes-worth of sectors with a
   transfer address of xxx:1 could ignore the last two bytes. A user program
   can never request an I/O of more than FFFFH bytes and cannot wrap around
   (even to 0) in the transfer segment. Therefore, in this case, the last two
   bytes can be ignored.

   MS-DOS maintains two FATs. If the DOS has problems reading the first, it
   automatically tries the second before reporting the error. The BIOS is
   responsible for all retries.

   Although the command.com handler does no automatic retries, there are
   applications that have their own Interrupt 24H handlers that do automatic
   retries on certain types of Interrupt 24H errors before reporting them.

 2.7.5  The Non-destructive Read, No Wait Function

   Command code = 5

   NON-DESTRUCTIVE READ NO WAIT - ES:BX ->
   ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³ 13-BYTE Request header             ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ BYTE Read from device              ³
   ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   The Non-destructive Read, No Wait function allows MS-DOS to look ahead one
   input character. The device sets the done bit in the status word.

   If the character device returns busy bit = 0 (there are characters in the
   buffer), then the next character that would be read is returned. This
   character is not removed from the input buffer (hence the term
   "Non-destructive Read"). If the character device returns busy bit = 1,
   there are no characters in the buffer.

 2.7.6  The Open or Close Function

   Command codes = 13 and 14

   OPEN or CLOSE  - ES:BX ->
   ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³ 13-BYTE Static request header      ³
   ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   The Open and Close functions are called by MS-DOS only if the device
   driver sets the Open/Close/Removable Media attribute bit in the device
   header. They are designed to inform the device about current file activity
   on the device. On block devices, they can be used to manage local
   buffering. The device can keep a reference count. Every Open causes the
   device to increment the count, every Close to decrement. When the count
   goes to zero, it means there are no open files on the device. Therefore,
   the device should flush any buffers that have been written to that may
   have been used inside the device, because it is now "legal" for the user
   to change the media on a removable media drive.

   There are problems with this mechanism on block devices because programs
   that use FCB calls can open files without closing them. It is, therefore,
   advisable to reset the count to zero without flushing the buffers when the
   answer to "Has the media been changed?" is yes, and the Build BPB call is
   made to the device.

   These calls are more useful on character devices. The Open call, for
   instance, can be used to send a device initialization string. On a
   printer, this could cause a string for setting font and page size
   characteristics to be sent to the printer so that it would always be in a
   known state at the start of an I/O stream. Using IOCtl to set these pre-
   and post- strings provides a flexible mechanism of serial I/O device
   stream control. The reference count mechanism can also be used to detect a
   simultaneous access error. It may be desirable to disallow more than one
   Open on a device at any given time. In this case, a second Open would
   result in an error.

   Notice that since all processes have access to stdin, stdout, stderr,
   stdaux, and stdprn (handles 0,1,2,3,4), the CON, AUX, and PRN devices are
   always open.

 2.7.7  The Removable Media Function

   Command code = 15

   REMOVABLE MEDIA - ES:BX ->
   ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³ 13-BYTE Static request header      ³
   ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   The Removable Media function is called by MS-DOS only if the device driver
   sets the Open/Close/Removable Media attribute bit in the device header.
   This call is given only to block devices by a subfunction of the IOCtl
   system call. It is sometimes desirable for a utility to know whether it is
   dealing with a nonremovable media drive (such as a hard disk), or a
   removable media drive (like a floppy). An example is the format command,
   which prints different versions of some of the prompts.

   The information is returned in the busy bit of the status word. If the
   busy bit is 1, then the media is nonremovable. If the busy bit is 0, then
   the media is removable. Notice that the error bit is not checked. It is
   assumed that this call always succeeds.

 2.7.8  The Status Function

   Command codes = 6 and 10

   STATUS Calls ES:BX ->
   ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³ 13-BYTE Request header             ³
   ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   The Status function returns information to the DOS as to whether data is
   waiting for input or output. All the driver must do is set the status word
   and the busy bit as follows:

   ž  For output on character devices ÄÄ if the driver sets bit 9 to 1 on
      return, it informs the DOS that a write request (if made) would wait
      for completion of a current request. If it is 0, there is no current
      request, and a write request (if made) would start immediately.

   ž  For input on character devices with a buffer ÄÄ A return of 1 implies
      that no characters are buffered and that a read request (if made) would
      go to the physical device. If it is 0 on return, then there are
      characters in the device buffer and a read would not be blocked. A
      return of 0 implies that the user has typed something. MS-DOS assumes
      that all character devices have an input type-ahead buffer.

   Devices that do not have a type-ahead buffer should always return busy = 0
   so that the DOS will not "hang" waiting for something to get into a
   non-existent buffer.

 2.7.9  The Flush Function

   Command codes = 7 and 11

   FLUSH Calls - ES:BX ->
   ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³ 13-BYTE Request header             ³
   ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   The Flush function tells the driver to flush (terminate) all pending
   requests. This call is used to flush the input queue on character devices.

   The device driver performs the flush function, sets the status word, and
   returns.

 2.7.10  The Generic IOCtl Function

   Command code = 19

   ES:BX ->
   ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³ 13-BYTE Static request header      ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ BYTE Category (Major) code         ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ BYTE Function (Minor) code         ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ WORD (SI) Contents                 ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ WORD (DI) Contents                 ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ DWORD Pointer to data buffer       ³
   ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   The Generic IOCtl function provides a generic, expandable IOCtl facility
   that replaces and makes the Read IOCtl and Write IOCtl device driver
   functions obsolete. The MS-DOS 2.0 IOCtl functions remain to support
   existing uses of the IOCtl system call (Subfunctions 2, 3, 4, and 5), but
   new device drivers should use this generic MS-DOS IOCtl facility. The
   Generic IOCtl function contains both a category and function code. The DOS
   examines the category field in order to intercept and obey device commands
   that are actually serviced by the DOS code; all other command categories
   are forwarded to the device driver for servicing.

   For more information on these category and function codes, refer to
   Function 440CH (Generic IOCtl for Handles) and Function 440DH (Generic
   IOCtl for Block Devices) in Chapter 1, "System Calls."

 2.7.11  The Get/Set Logical Drive Map Function

   Command codes = 23 (Get) or 24 (Set)

   ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³ 13-BYTE Static request header          ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ BYTE    Input (unit code)              ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ BYTE    Output (last device referenced)³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ BYTE    Command code                   ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ WORD    Status                         ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ DWORD   Reserved                       ³
   ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   The Get/Set Logical Drive Map function is called by MS-DOS only if the
   device driver sets the DOS 3.2 attribute bit in the device header. The
   call is issued only to block devices by the subfunction of the IOCtl
   system call. The logical drive to be mapped is passed in the Unit field of
   the header to the device driver. The device driver returns the current
   logical drive owner of the physical device that maps to the requested
   physical drive. To detect whether or not a logical device currently owns
   the physical device to which it is mapped, a program needs to verify that,
   after a call of Function 440EH or 440FH (Get/Set Logical Drive Map), the
   value of the Unit field is unchanged.


 2.8  The Media Descriptor Byte

   In MS-DOS, the media descriptor byte is used to inform the DOS that a
   different type of media is present. The media descriptor byte can be any
   value between 0 and FFH. It does not have to be the same as the FAT ID
   byte. The FAT ID byte, which is the first byte of the FAT, was used in
   MS-DOS 1.00 to distinguish between different types of disk media, and may
   be used as well under 2.x and 3.x disk device drivers. However, FAT ID
   bytes have significance only for block device drivers where the non-FAT ID
   bit is not set (0).

   Values of the media descriptor byte or the FAT ID byte have no
   significance to MS-DOS. They are passed to the device driver so that
   programs can determine the media type.


 2.9  Format of a Media Descriptor Table

   The MS-DOS file system uses a linked list of pointers (one for each
   cluster or allocation unit) called the File Allocation Table (FAT). Unused
   clusters are represented by zero and end-of-file by FFFH (or FFFFH on
   units with 16-bit FAT entries). No valid entry should ever point to a zero
   entry, but if one does, the first FAT entry (which would be pointed to by
   a zero entry) was reserved and set to end of chain. Eventually, several
   end of chain values were defined ([F]FF8H[F]FFFH), and these were used to
   distinguish different types of media.

   A preferable technique is to write a complete media descriptor table in
   the boot sector and use it for media identification. To ensure backward
   compatibility for systems whose drivers do not set the non-FAT ID bit
   (including the IBM PC implementation), it is also necessary to write the
   FAT ID bytes during the format process.

   To allow more flexibility for supporting many different disk formats in
   the future, it is recommended that the information relating to the BPB for
   a particular piece of media be kept in the boot sector. Figure 2.6 shows
   the format of such a boot sector.

      ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
      ³ 3 BYTE Near JUMP to boot code      ³
      ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
      ³ 8 BYTES OEM name and version       ³
      ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   B  ³ WORD Bytes per sector              ³
   P  ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   B  ³ BYTE Sectors per allocation unit   ³
      ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
     ³ WORD Reserved sectors              ³
      ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
      ³ BYTE Number of FATs                ³
      ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
      ³ WORD Number of root dir entries    ³
      ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
      ³ WORD Number of sectors in logical  ³
     ³ | image or 0                       ³
      ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   B  ³ BYTE Media descriptor              ³
   P  ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   B  ³ WORD Number of FAT sectors         ³
      ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
      ³ WORD Sectors per track             ³
      ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
      ³ WORD Number of heads               ³
      ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
      ³ WORD Number of hidden sectors      ³
      ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
      ³ WORD High order number of hidden   ³
      ³ sectors                            ³
      ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
      ³ DWORD Number of logical sectors    ³
      ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   Figure 2.6  Format of a Boot Sector

   Although MS-DOS does not use the five fields that follow the BPB, these
   fields may be used by a device driver to help it understand the media.

   The "Sectors per track" and "Number of heads" fields are useful for
   supporting different media that may have the same logical layout, but a
   different physical layout (for example, 40-track, double-sided versus
   80-track, single-sided). "Sectors per track" tells the device driver how
   the logical disk format is laid out on the physical disk. The "Number of
   hidden sectors" and "High order number of hidden sectors" fields may be
   used to support drive-partitioning schemes.

   The "Number of logical sectors" field tells the device driver how many
   sectors to reserve if the "Number of sectors in logical image" field is
   zero. (Notice that this is intended for supporting devices that access
   more than 32 megabytes.)

   The following procedure is recommended for media determination by NON FAT
   ID format drivers:

   1. Read the boot sector of the drive into the one-sector scratch space
      pointed to by the DWORD transfer address.

   2. Determine if the first byte of the boot sector is an E9H or EBIT (the
      first byte of a 3-byte NEAR or 2-byte SHORT jump) or an EBH (the first
      byte of a 2-byte jump followed by an NOP). If so, a BPB is located
      beginning at offset 3. Return a pointer to it.

   3. If the boot sector does not have a BPB table, it is probably a disk
      formatted under a 1.x version of MS-DOS and probably uses a FAT ID byte
      for determining media.

      The driver may optionally attempt to read the first sector of the FAT
      into the one-sector scratch area and read the first byte to determine
      media type based upon whatever FAT ID bytes may have been used on disks
      that are expected to be read by this system. Return a pointer to a
      hard-coded BPB.


 2.10  The CLOCK Device

   MS-DOS assumes that some sort of clock is available in the system. This
   may either be a CMOS real-time clock or an interval timer that is
   initialized at boot time by the user. The CLOCK device defines and
   performs functions like any other character device, except that it is
   identified by a bit in the attribute word. The DOS uses this bit to
   identify it; consequently, the CLOCK device may take any name. The IBM
   implementation uses the name $CLOCK so as not to conflict with existing
   files named clock.

   The CLOCK device is unique in that MS-DOS will read or write a 6-byte
   sequence that encodes the date and time. A write to this device will set
   the date and time; a read will get the date and time. Figure 2.7
   illustrates the binary time format used by the CLOCK device:

     byte 0   byte 1   byte 2    byte 3   byte 4   byte 5
   ŚÄÄÄÄÄÄÄÄĀÄÄÄÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄĀÄÄÄÄÄÄÄÄĀÄÄÄÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄæ
   ³        ³        ³         ³        ³        ³         ³
   ³days since 1-1-80³ minutes ³  hours ³ sec/100³ seconds ³
   ³low byte|hi byte ³         ³        ³        ³         ³
   ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄĮÄÄÄÄÄÄÄÄĮÄÄÄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄŁ

   Figure 2.7  Format of a Clock Device


 2.11  Anatomy of a Device Call

   The following steps illustrate what happens when MS-DOS calls on a block
   device driver to perform a Write request:

   1. MS-DOS writes a request packet in a reserved area of memory.

   2. MS-DOS calls the strategy entry point of the block device driver.

   3. The device driver saves the ES and BX registers (ES:BX points to the
      request packet) and does a FAR return.

   4. MS-DOS calls the interrupt entry point.

   5. The device driver retrieves the pointer to the request packet and reads
      the command code (offset 2) to determine that this is a Write request.
      The device driver converts the command code to an index into a dispatch
      table and control passes to the Write routine.

   6. The device driver reads the unit code (offset 1) to determine which
      disk drive it is supposed to write to.

   7. Since the command is a disk Write, the device driver must get the
      transfer address (offset 14), the sector count (offset 18), and the
      start sector (offset 20) in the request packet.

   8. The device driver translates the first logical sector number into a
      track, head, and sector number.

   9. The device driver writes the specified number of sectors, starting at
      the beginning sector on the drive defined by the unit code (the subunit
      defined by this device driver), and transfers data from the transfer
      address indicated in the request packet. Notice that this may involve
      multiple Write commands to the disk controller.

   10.After the transfer is complete, the device driver must report the
      status of the request to MS-DOS by setting the done bit in the status
      word (offset 3 in the request packet). It reports the number of sectors
      actually transferred in the sector count area of the request packet.

   11.If an error occurs, the driver sets the done bit and the error bit in
      the status word and fills in the error code in the lower half of the
      status word. The number of sectors actually transferred must be written
      in the request header. It is not sufficient just to set the error bit
      of the status word.

   12.The device driver does a FAR return to MS-DOS.

   The device drivers should preserve the state of MS-DOS. This means that
   all registers (including flags) should be preserved. The direction flag
   and interrupt enable bits are critical. When the interrupt entry point in
   the device driver is called, MS-DOS has room for about 40 to 50 bytes on
   its internal stack. Your device driver should switch to a local stack if
   it uses extensive stack operations.


 2.12  Two Sample Device Drivers

   The following two examples illustrate a block device driver program and a
   character device driver program. These examples are provided as guides for
   writing your own device drivers. However, since device drivers are
   hardware-dependent, your device drivers will differ.

   Block Device Driver



   ; ********************* A Block Device *******************

           Title   5.25-inch Disk Driver

   ; This driver is intended to drive up to four 5.25-inch
   ; drives hooked to a single disk controller. All standard
   ; IBM PC formats are supported.


   FALSE   EQU     0
   TRUE    EQU     NOT FALSE




   ; The I/O port address of the disk controller
   DISK    EQU     0E0H
   ; DISK+0
   ;        1793    Command/Status
   ; DISK+1
   ;        1793    Track
   ; DISK+2
   ;        1793    Sector
   ; DISK+3
   ;        1793    Data
   ; DISK+4
   ;        Aux Command/Status
   ; DISK+5
   ;        Wait Sync

   ; Back side select bit
   BACKBIT EQU     04H
   ; 5 1/4" select bit
   SMALBIT EQU     10H
   ; Double Density bit
   DDBIT   EQU     08H

   ; Done bit in status register
   DONEBIT EQU     01H

   ; Use table below to select head step speed.
   ; Step times for 5" drives
   ; are double that shown in the ; Step value    1771    1793
   ;
   ;     0          6ms     3ms
   ;     1          6ms     6ms
   ;     2         10ms    10ms
   ;     3         20ms    15ms
   ;
   STPSPD  EQU     1

   NUMERR  EQU     ERROUT-ERRIN

   CR      EQU     0DH
   LF      EQU     0AH

   CODE    SEGMENT
   ASSUME  CS:CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING
   ; -----------------------------------------------------
   ;
   ;        Device Header
   ;
   DRVDEV  LABEL   WORD
           DW      -1,-1
           DW      0000     ; IBM format-compatible, Block
           DW      STRATEGY
           DW      DRV$IN
   DRVMAX  DB      4

   DRVTBL  LABEL   WORD
           DW      DRV$INIT
           DW      MEDIA$CHK
           DW      GET$BPB
           DW      CMDERR
           DW      DRV$READ
           DW      EXIT
           DW      EXIT
           DW      EXIT
           DW      DRV$WRIT
           DW      DRV$WRIT
           DW      EXIT
           DW      EXIT
           DW      EXIT

   ; ------------------------------------
   ;
   ;        Strategy

   PTRSAV  DD      0

   STRATP  PROC    FAR
   STRATEGY:
           MOV     WORD PTR [PTRSAV],BX
           MOV     WORD PTR [PTRSAV+2],ES
           RET
   STRATP  ENDP

   ; --------------------------------------
   ;
   ;        Main Entry


   CMDLEN  =       0       ; Length of this command
   UNIT    =       1       ; Subunit specified
   CMDC    =       2       ; Command Code
   STATUS  =       3       ; Status
   MEDIA   =       13      ; Media Descriptor
   TRANS   =       14      ; Transfer Address
   COUNT   =       18      ; Count of blocks or characters
   START   =       20      ; First block to transfer

   DRV$IN:
           PUSH    SI
           PUSH    AX
           PUSH    CX
           PUSH    DX
           PUSH    DI
           PUSH    BP
           PUSH    DS
           PUSH    ES
           PUSH    BX

           LDS     BX,[PTRSAV]     ; Get pointer to I/O packet

           MOV     AL,BYTE PTR [BX].UNIT   ; AL = Unit Code
           MOV     AH,BYTE PTR [BX].MEDIA  ; AH = Media Descrip
           MOV     CX,WORD PTR [BX].COUNT  ; CX = Count
           MOV     DX,WORD PTR [BX].START  ; DX = Start Sector
           PUSH    AX
           MOV     AL,BYTE PTR [BX].CMDC   ; Command code
           CMP     AL,15
           JA      CMDERRP                 ; Bad command
           CBW
           SHL     AX,1                    ; 2 times command =
                                           ; word table index
           MOV     SI,OFFSET DRVTBL
           ADD     SI,AX                   ; Index into table
           POP     AX                      ; Get back media
                                           ; and unit

           LES     DI,DWORD PTR [BX].TRANS ; ES:DI = Transfer
                                           ; Address

           PUSH    CS
           POP     DS

   ASSUME  DS:CODE

           JMP     WORD PTR [SI]             ; GO DO COMMAND

   ; ----------------------------------------------------------
   ;
   ;        EXIT - All Routines return through this path
   ;
   ASSUME  DS:NOTHING
   CMDERRP:
           POP     AX                    ; Clean stack
   CMDERR:
           MOV     AL,3                  ; Unknown command error
           JMP     SHORT ERR$EXIT

   ERR$CNT:LDS     BX,[PTRSAV]
           SUB     WORD PTR [BX].COUNT,CX ; # OF SUCCESS. I/Os

   ERR$EXIT:
   ; AL has error code
           MOV     AH,10000001B            ; Mark error return
           JMP     SHORT ERR1

   EXITP   PROC    FAR

   EXIT:   MOV     AH,00000001B
   ERR1:   LDS     BX,[PTRSAV]
           MOV     WORD PTR [BX].STATUS,AX
                                       ; Mark Operation
   CompleteE

           POP     BX
           POP     ES
           POP     DS
           POP     BP
           POP     DI
           POP     DX
           POP     CX
           POP     AX
           POP     SI
           RET                         ; Restore REGS and return
   EXITP   ENDP

   CURDRV  DB      -1

   TRKTAB  DB      -1,-1,-1,-1

   SECCNT  DW      0

   DRVLIM  =       8       ; Number of sectors on device
   SECLIM  =       13      ; Maximum Sector
   HDLIM   =       15      ; Maximum Head

   ; WARNING - preserve order of drive and curhd!

   DRIVE   DB      0       ; Physical Drive Code
   CURHD   DB      0       ; Current Head
   CURSEC  DB      0       ; Current Sector
   CURTRK  DW      0       ; Current Track


   ;
   MEDIA$CHK:              ; Always indicates Don't know
   ASSUME  DS:CODE
           TEST    AH,00000100B       ; Test if Media Removable
           JZ      MEDIA$EXT
           XOR     DI,DI              ; Say I Don't know
   MEDIA$EXT:
           LDS     BX,[PTRSAV]
           MOV     WORD PTR [BX].TRANS,DI
           JMP     EXIT

   BUILD$BPB:
   ASSUME  DS:CODE
           MOV     AH,BYTE PTR ES:[DI]       ; Get FAT ID Byte
           CALL    BUILDBP                   ; Translate
   SETBPB: LDS     BX,[PTRSAV]
           MOV     [BX].MEDIA,AH
           MOV     [BX].COUNT,DI
           MOV     [BX].COUNT+2,CS
           JMP     EXIT

   BUILDBP:
   ASSUME  DS:NOTHING
   ; AH is media byte on entry
   ; DI points to correct BPB on return
           PUSH    AX
           PUSH    CX
           PUSH    DX
           PUSH    BX
           MOV     CL,AH       ; Save Media
           AND     CL,0F8H     ; Normalize
           CMP     CL,0F8H     ; Compare with Good Media Byte
           JZ      GOODID
           MOV     AH,0FEH     ; Default to 8-sector,
                               ; Single-sided
   GOODID:
           MOV     AL,1        ; Set number of FAT sectors
           MOV     BX,64*256+8 ; Set Dir Entries and Sector Max
           MOV     CX,40*8     ; Set Size of Drive
           MOV     DX,01*256+1 ; Set Head Limit & Sec/All Unit
           MOV     DI,OFFSET DRVBPB
           TEST    AH,00000010B ; Test for 8 OR 9 Sectors
           JNZ     HAS8        ; NZ = has 8 sectors
           INC     AL          ; Inc Number of FAT sectors
           INC     BL          ; Inc Sector Max
           ADD     CX,40       ; Increase Size
   HAS8:   TEST    AH,00000001B    ; Test for 1 or 2 Heads
           JZ      HAS1        ; Z = 1 Head
           ADD     CX,CX       ; Double Size of Disk
           MOV     BH,112      ; Increase # of Dir Entries
           INC     DH          ; Inc Sec/All Unit
           INC     DL          ; Inc Head Limit
   HAS1:   MOV     BYTE PTR [DI].2,DH
           MOV     BYTE PTR [DI].6,BH
           MOV     WORD PTR [DI].8,CX
           MOV     BYTE PTR [DI].10,AH
           MOV     BYTE PTR [DI].11,AL
           MOV     BYTE PTR [DI].13,BL
           MOV     BYTE PTR [DI].15,DL
           POP     BX
           POP     DX
           POP     CX
           POP     AX
           RET


   ; ----------------------------------------------------------
   ;
   ;        Disk I/O Handlers
   ;
   ; ENTRY:
   ;        AL = Drive Number (0-3)
   ;        AH = Media Descriptor
   ;        CX = Sector Count
   ;        DX = First Sector
   ;        DS = CS
   ;        ES:DI = Transfer Address
   ; EXIT:
   ;        IF Successful Carry Flag = 0
   ;          ELSE CF=1 AND AL contains (MS-DOS) Error Code,
             CX # sectors NOT transferred

   DRV$READ:
   ASSUME  DS:CODE
           JCXZ    DSKOK
           CALL    SETUP
           JC      DSK$IO
           CALL    DISKRD
           JMP     SHORT DSK$IO

   DRV$WRIT:
   ASSUME  DS:CODE
           JCXZ    DSKOK
           CALL    SETUP
           JC      DSK$IO
           CALL    DISKWRT
   ASSUME  DS:NOTHING
   DSK$IO: JNC     DSKOK
           JMP     ERR$CNT
   DSKOK:  JMP     EXIT


   SETUP:
   ASSUME  DS:CODE
   ; Input same as above
   ; On output
   ;  ES:DI = Trans addr
   ;  DS:BX Points to BPB
   ;  Carry set if error (AL is error code (MS-DOS))
   ;  else
   ;        [DRIVE] = Drive number (0-3)
   ;        [SECCNT] = Sectors to transfer
   ;        [CURSEC] = Sector number of start of I/O
   ;        [CURHD]  = Head number of start of I/O   ; Set
   ;        [CURTRK] = Track # of start of I/O ; Seek performed
   ;  All other registers destroyed

           XCHG   BX,DI              ; ES:BX = Transfer Address
           CALL   BUILDBP            ; DS:DI = PTR to B.P.B
           MOV    SI,CX
           ADD    SI,DX
           CMP    SI,WORD PTR [DI].DRVLIM
                                    ; Compare Against Drive Max
           JBE    INRANGE
           MOV    AL,8
           STC
           RET

   INRANGE:
           MOV    [DRIVE],AL
           MOV    [SECCNT],CX     ; Save Sector Count
           XCHG   AX,DX           ; Set Up Logical Sector
                                  ; For Divide
           XOR    DX,DX
           DIV    WORD PTR [DI].SECLIM ; Divide by Sec per Track
           INC    DL
           MOV    [CURSEC],DL          ; Save Current Sector
           MOV    CX,WORD PTR [DI].HDLIM ; Get Number of Heads
           XOR    DX,DX   ; Divide Tracks by Heads per Cylinder
           DIV    CX
           MOV    [CURHD],DL      ; Save Current Head
           MOV    [CURTRK],AX     ; Save Current Track
   SEEK:
           PUSH   BX              ; Xaddr
           PUSH   DI              ; BPB pointer
           CALL   CHKNEW          ; Unload head if change drives
           CALL   DRIVESEL
           MOV    BL,[DRIVE]
           XOR    BH,BH           ; BX drive index
           ADD    BX,OFFSET TRKTAB        ; Get current track
           MOV    AX,[CURTRK]
           MOV    DL,AL         ; Save desired track
           XCHG   AL,DS:[BX]    ; Make desired track current
           OUT    DISK+1,AL     ; Tell Controller current track
           CMP    AL,DL         ; At correct track?
           JZ     SEEKRET       ; Done if yes
           MOV    BH,2          ; Seek retry count
           CMP    AL,-1         ; Position Known?
           JNZ    NOHOME        ; If not home head
   TRYSK:
           CALL   HOME
           JC     SEEKERR
   NOHOME:
           MOV    AL,DL
           OUT    DISK+3,AL       ; Desired track
           MOV    AL,1CH+STPSPD   ; Seek
           CALL   DCOM
           AND    AL,98H    ; Accept not rdy, seek, & CRC errors
           JZ     SEEKRET
           JS     SEEKERR         ; No retries if not ready
           DEC    BH
           JNZ    TRYSK
   SEEKERR:
           MOV    BL,[DRIVE]
           XOR    BH,BH           ; BX drive index
           ADD    BX,OFFSET TRKTAB        ; Get current track
           MOV    BYTE PTR DS:[BX],-1     ; Make current track
                                          ; unknown
           CALL   GETERRCD
           MOV    CX,[SECCNT]     ; Nothing transferred
           POP    BX              ; BPB pointer
           POP    DI              ; Xaddr
           RET

   SEEKRET:
           POP    BX              ; BPB pointer
           POP    DI              ; Xaddr
           CLC
           RET

   ; ---------------------------------------------
   ;
   ;        Read
   ;

   DISKRD:
   ASSUME  DS:CODE
           MOV    CX,[SECCNT]
   RDLP:
           CALL   PRESET
           PUSH   BX
           MOV    BL,10              ; Retry count
           MOV    DX,DISK+3          ; Data port
   RDAGN:
           MOV    AL,80H             ; Read command
           CLI                       ; Disable for 1793
           OUT    DISK,AL            ; Output read command
           MOV    BP,DI              ; Save address for retry
           JMP    SHORT RLOOPENTRY
   RLOOP:
           STOSB
   RLOOPENTRY:
           IN     AL,DISK+5          ; Wait for DRQ or INTRQ
           SHR    AL,1
           IN     AL,DX              ; Read data
           JNC    RLOOP
           STI                       ; Ints OK now
           CALL   GETSTAT
           AND    AL,9CH
           JZ     RDPOP              ; Ok
           MOV    DI,BP              ; Get back transfer
           DEC    BL
           JNZ    RDAGN
           CMP    AL,10H             ; Record not found?
           JNZ    GOT_CODE           ; No
           MOV    AL,1               ; Map it
   GOT_CODE:
           CALL   GETERRCD
           POP    BX
           RET

   RDPOP:
           POP    BX
           LOOP   RDLP
           CLC
           RET


   ; ---------------------------------------------
   ;
   ;        Write
   ;

   DISKWRT:
   ASSUME  DS:CODE
           MOV     CX,[SECCNT]
           MOV     SI,DI
           PUSH    ES
           POP     DS
   ASSUME  DS:NOTHING
   WRLP:
           CALL    PRESET
           PUSH    BX
           MOV     BL,10                   ; Retry count
           MOV     DX,DISK+3               ; Data port
   WRAGN:
           MOV     AL,0A0H            ; Write command
           CLI                        ; Disable for 1793
           OUT     DISK,AL            ; Output write command
           MOV     BP,SI              ; Save address for retry
   WRLOOP:
           IN      AL,DISK+5
           SHR     AL,1
           LODSB                      ; Get data
           OUT     DX,AL              ; Write data
           JNC     WRLOOP
           STI                        ; Ints OK now
           DEC     SI
           CALL    GETSTAT
           AND     AL,0FCH
           JZ      WRPOP              ; Ok
           MOV     SI,BP              ; Get back transfer
           DEC     BL
           JNZ     WRAGN
           CALL    GETERRCD
           POP     BX
           RET

   WRPOP:
           POP     BX
           LOOP    WRLP
           CLC
           RET


   PRESET:
   ASSUME  DS:NOTHING
           MOV     AL,[CURSEC]
           CMP     AL,CS:[BX].SECLIM
           JBE     GOTSEC
           MOV     DH,[CURHD]
           INC     DH
           CMP     DH,CS:[BX].HDLIM
           JB      SETHEAD            ; Select new head
           CALL    STEP               ; Go on to next track
           XOR     DH,DH              ; Select head zero
   SETHEAD:
           MOV     [CURHD],DH
           CALL    DRIVESEL
           MOV     AL,1               ; First sector
           MOV     [CURSEC],AL        ; Reset CURSEC
   GOTSEC:
           OUT     DISK+2,AL     ; Tell controller which sector
           INC     [CURSEC]      ; We go on to next sector
           RET

   STEP:
   ASSUME  DS:NOTHING
           MOV     AL,58H+STPSPD  ; Step in w/ update, no verify
           CALL    DCOM
           PUSH    BX
           MOV     BL,[DRIVE]
           XOR     BH,BH           ; BX drive index
           ADD     BX,OFFSET TRKTAB        ; Get current track
           INC     BYTE PTR CS:[BX]        ; Next track
           POP     BX
           RET

   HOME:
   ASSUME  DS:NOTHING
           MOV     BL,3
   TRYHOM:
           MOV     AL,0CH+STPSPD   ; Restore with verify
           CALL    DCOM
           AND     AL,98H
           JZ      RET3
           JS      HOMERR          ; No retries if not ready
           PUSH    AX              ; Save real error code
           MOV     AL,58H+STPSPD   ; Step in w/ update no verify
           CALL    DCOM
           DEC     BL
           POP     AX              ; Get back real error code
           JNZ     TRYHOM
   HOMERR:
           STC
   RET3:   RET


   CHKNEW:
   ASSUME  DS:NOTHING
           MOV     AL,[DRIVE]      ; Get disk drive number
           MOV     AH,AL
           XCHG    AL,[CURDRV]     ; Make new drive current.
           CMP     AL,AH           ; Changing drives?
           JZ      RET1            ; No
   ;  If changing drives, unload head so the head load delay
   ; one-shot will fire again. Do it by seeking to the same
   ; track with the H bit reset.
   ;
           IN      AL,DISK+1       ; Get current track number
           OUT     DISK+3,AL       ; Make it the track to seek
           MOV     AL,10H          ; Seek and unload head

   DCOM:
   ASSUME  DS:NOTHING
           OUT     DISK,AL
           PUSH    AX
           AAM                     ; Delay 10 microseconds
           POP     AX
   GETSTAT:
           IN      AL,DISK+4
           TEST    AL,DONEBIT
           JZ      GETSTAT
           IN      AL,DISK
   RET1:   RET

   DRIVESEL:
   ASSUME  DS:NOTHING
   ; Select the drive based on current info
   ; Only AL altered
           MOV     AL,[DRIVE]
           OR      AL,SMALBIT + DDBIT      ; 5 1/4" IBM PC disks
           CMP     [CURHD],0
           JZ      GOTHEAD
           OR      AL,BACKBIT      ; Select side 1
   GOTHEAD:
           OUT     DISK+4,AL       ; Select drive and side
           RET

   GETERRCD:
   ASSUME  DS:NOTHING
           PUSH    CX
           PUSH    ES
           PUSH    DI
           PUSH    CS
           POP     ES              ; Make ES the local segment
           MOV     CS:[LSTERR],AL ; Terminate list w/ error code
           MOV     CX,NUMERR       ; Number of error conditions
           MOV     DI,OFFSET ERRIN ; Point to error conditions
           REPNE   SCASB
           MOV     AL,NUMERR-1[DI] ; Get translation
           STC                     ; Flag error condition
           POP     DI
           POP     ES
           POP     CX
           RET                     ; and return

   ; *********************************************************
   ;        BPB for an IBM floppy disk, Various parameters are
   ;        patched by BUILDBP to reflect the type of Media
   ;        inserted
   ;        This is a 9-sector, single-side BPB
   DRVBPB:
           DW      512          ; Physical sector size in bytes
           DB      1            ; Sectors/allocation unit
           DW      1            ; Reserved sectors for DOS
           DB      2            ; # of allocation tables
           DW      64           ; Number directory entries
           DW      9*40         ; Number 512-byte sectors
           DB      11111100B    ; Media descriptor
           DW      2            ; Number of FAT sectors
           DW      9            ; Sector limit
           DW      1            ; Head limit


   INITAB  DW      DRVBPB               ; Up to four units
           DW      DRVBPB
           DW      DRVBPB
           DW      DRVBPB

   ERRIN:  ; DISK ERRORS RETURNED FROM THE CONTROLLER
           DB      80H             ; No response
           DB      40H             ; Write protect
           DB      20H             ; Write Fault
           DB      10H             ; SEEK error
           DB      8               ; CRC error
           DB      1               ; Mapped from 10H
                                   ; (record not found) on Read
   LSTERR  DB      0               ; All other errors

   ERROUT: ; RETURNED ERROR CODES CORRESPONDING TO ABOVE
           DB      2               ; No response
           DB      0               ; Write Attempt
                                   ; On Write-protected disk
           DB      0AH             ; Write fault
           DB      6               ; SEEK Failure
           DB      4               ; Bad CRC
           DB      8               ; Sector not found
           DB      12              ; General error


   DRV$INIT:
   ;
   ;  Determine number of physical drives by reading config.sys
   ;
   ASSUME  DS:CODE
           PUSH    DS
           LDS     SI,[PTRSAV]
   ASSUME  DS:NOTHING
           LDS     SI,DWORD PTR [SI.COUNT] ; DS:SI points to
                                           ; config.sys
   SCAN_LOOP:
           CALL    SCAN_SWITCH
           MOV     AL,CL
           OR      AL,AL
           JZ      SCAN4
           CMP     AL,"s"
           JZ      SCAN4

   WERROR: POP     DS
   ASSUME  DS:CODE
           MOV     DX,OFFSET ERRMSG2
   WERROR2: MOV    AH,9
           INT     21H
           XOR     AX,AX
           PUSH    AX                      ; No units
           JMP     SHORT ABORT

   BADNDRV:
           POP     DS
           MOV     DX,OFFSET ERRMSG1
           JMP     WERROR2

   SCAN4:
   ASSUME  DS:NOTHING
   ; BX is number of floppies
           OR      BX,BX
           JZ      BADNDRV                 ; User error
           CMP     BX,4
           JA      BADNDRV                 ; User error
           POP     DS
   ASSUME  DS:CODE
           PUSH    BX                      ; Save unit count
   ABORT:  LDS     BX,[PTRSAV]
   ASSUME  DS:NOTHING
           POP     AX
           MOV     BYTE PTR [BX].MEDIA,AL           ; Unit count
           MOV     [DRVMAX],AL
           MOV     WORD PTR [BX].TRANS,OFFSET DRV$INIT ; SET
                                                 ; BREAK ADDRESS
           MOV     [BX].TRANS+2,CS
           MOV     WORD PTR [BX].COUNT,OFFSET INITAB
                                    ; SET POINTER TO BPB ARRAY
           MOV     [BX].ceOUNT+2,CS
           JMP     EXIT
   ;
   ;  Put switch in CL, value in BX
   ;
   SCAN_SWITCH:
           XOR     BX,BX
           MOV     CX,BX
           LODSB
           CMP     AL,10
           JZ      NUMRET
           CMP     AL,"-"
           JZ      GOT_SWITCH
           CMP     AL,"/"
           JNZ     SCAN_SWITCH
   GOT_SWITCH:
           CMP     BYTE PTR [SI+1],":"
           JNZ     TERROR
           LODSB
           OR      AL,20H          ;  Convert to lowercase
           MOV     CL,AL           ;  Get switch
           LODSB                   ;  Skip ":"
   ;
   ;   Get number pointed to by [SI]
   ;
   ;   Wipes out AX,DX only     BX returns number
   ;
   GETNUM1:LODSB
           SUB     AL,"0"
           JB      CHKRET
           CMP     AL,9
           JA      CHKRET
           CBW
           XCHG    AX,BX
           MOV     DX,10
           MUL     DX
           ADD     BX,AX
           JMP     GETNUM1

   CHKRET: ADD     AL,"0"
           CMP     AL," "
           JBE     NUMRET
           CMP     AL,"-"
           JZ      NUMRET
           CMP     AL,"/"
           JZ      NUMRET
   TERROR:
           POP     DS              ;  Get rid of return address
           JMP     WERROR
   NUMRET: DEC     SI
           RET

   ERRMSG1 DB      "SMLDRV: Bad number of drives",13,10,"$"
   ERRMSG2 DB      "SMLDRV: Invalid parameter",13,10,"$"
   CODE    ENDS
           END

   Character Device Driver

   The following program illustrates a character device driver program.


   ; ******************** A Character Device *******************

   Title   VT52 Console for 2.0    (IBM)

   ; ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
   ;
   ;        IBM Addresses for I/O
   ;
   ; ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

           CR=13              ; Carriage-Return
           BACKSP=8           ; BACKSPACE
           ESC=1BH
           BRKADR=6CH         ; 006C  Break vector address
           ASNMAX=200         ; Size of key assignment buffer

   CODE    SEGMENT BYTE

      ASSUME CS:CODE,DS:NOTHING,ES:NOTHING
   ; ----------------------------------------------------------
   ;
   ;        C O N - Console Device Driver
   ;
   CONDEV:                            ; Header for device "CON"
           DW      -1,-1
           DW      1000000000010011B  ; CON IN AND CON OUT
           DW      STRATEGY
           DW      ENTRY
           DB      'CON     '

   ; -----------------------------------------------------------
   ;
   ;        Command JUMP Tables
   CONTBL:
           DW      CON$INIT
           DW      EXIT
           DW      EXIT
           DW      CMDERR
           DW      CON$READ
           DW      CON$RDND
           DW      EXIT
           DW      CON$FLSH
           DW      CON$WRIT
           DW      CON$WRIT
           DW      EXIT
           DW      EXIT

   CMDTABL DB      'A'
           DW      CUU             ; cursor up
           DB      'B'
           DW      CUD             ; cursor down
           DB      'C'
           DW      CUF             ; cursor forward
           DB      'D'
           DW      CUB             ; cursor back
           DB      'H'
           DW      CUH             ; cursor position
           DB      'J'
           DW      ED              ; erase display
           DB      'K'
           DW      EL              ; erase line
           DB      'Y'
           DW      CUP             ; cursor position
           DB      'j'
           DW      PSCP            ; save cursor position
           DB      'k'
           DW      PRCP            ; restore cursor position
           DB      'y'
           DW      RM              ; reset mode
           DB      'x'
           DW      SM              ; set mode
           DB      00

   PAGE
   ; ---------------------------------------------------
   ;
   ;        Device entry point
   ;
   CMDLEN  =       0       ; Length of this command
   UNIT    =       1       ; Subunit Specified
   CMD     =       2       ; Command Code
   STATUS  =       3       ; Status
   MEDIA   =       13      ; Media Descriptor
   TRANS   =       14      ; Transfer Address
   COUNT   =       18      ; Count of blocks or characters
   START   =       20      ; First block to transfer

   PTRSAV  DD      0

   STRATP  PROC    FAR

   STRATEGY:
           MOV     WORD PTR CS:[PTRSAV],BX
           MOV     WORD PTR CS:[PTRSAV+2],ES
           RET

   STRATP  ENDP

   ENTRY:
           PUSH    SI
           PUSH    AX
           PUSH    CX
           PUSH    DX
           PUSH    DI
           PUSH    BP
           PUSH    DS
           PUSH    ES
           PUSH    BX

           LDS     BX,CS:[PTRSAV]  ; GET POINTER TO I/O PACKET

           MOV     CX,WORD PTR DS:[BX].COUNT    ; CX = COUNT

           MOV     AL,BYTE PTR DS:[BX].CMD
           CBW
           MOV     SI,OFFSET CONTBL
           ADD     SI,AX
           ADD     SI,AX
           CMP     AL,11
           JA      CMDERR

           LES     DI,DWORD PTR DS:[BX].TRANS

           PUSH    CS
           POP     DS

           ASSUME  DS:CODE

           JMP     WORD PTR [SI]              ; GO DO COMMAND

   PAGE
   ; =====================================================
   ; =
   ; =      Subroutines Shared by Multiple Devices
   ; =
   ; =====================================================
   ; -----------------------------------------------------
   ;
   ;        EXIT - All routines return through this path
   ;
   BUS$EXIT:                               ; Device Busy Exit
           MOV     AH,00000011B
           JMP     SHORT ERR1

   CMDERR:
           MOV     AL,3                ; Unknown command error

   ERR$EXIT:
           MOV     AH,10000001B            ; Mark error Return
           JMP     SHORT ERR1

   EXITP   PROC    FAR

   EXIT:   MOV     AH,00000001B
   ERR1:   LDS     BX,CS:[PTRSAV]
           MOV     WORD PTR [BX].STATUS,AX ; Mark
                                           ; Operation Complete

           POP     BX
           POP     ES
           POP     DS
           POP     BP
           POP     DI
           POP     DX
           POP     CX
           POP     AX
           POP     SI
           RET                        ; Restore REGS and Return
   EXITP   ENDP
   ; -----------------------------------------------
   ;
   ;        BREAK Key Handling
   ;
   BREAK:
           MOV     CS:ALTAH,3         ; Indicate BREAK key Set
   INTRET: IRET

   PAGE
   ;
   ;        WARNING - Variables are very order dependent,
                     so be careful when adding new ones!
   ;
   WRAP    DB      0               ;  0 = WRAP, 1 = NO WRAP
   STATE   DW      S1
   MODE    DB      3
   MAXCOL  DB      79
   COL     DB      0
   ROW     DB      0
   SAVCR   DW      0
   ALTAH   DB      0               ; Special key handling

   ; -------------------------------------------------------
   ;
   ;     CHROUT - Write out Char in AL using current attribute
   ;
   ATTRW   LABEL   WORD
   ATTR    DB      00000111B       ; Character Attribute
   BPAGE   DB      0               ; Base Page
   base    dw      0b800h

   chrout: cmp     al,13
           jnz     trylf
           mov     [col],0
           jmp     short setit

   trylf:  cmp     al,10
           jz      lf
           cmp     al,7
           jnz     tryback
   torom:
           mov     bx,[attrw]
           and     bl,7
           mov     ah,14
           int     10h
   ret5:   ret

   tryback:
           cmp     al,8
           jnz     outchr
           cmp     [col],0
           jz      ret5
           dec     [col]
           jmp     short setit

   outchr:
           mov     bx,[attrw]
           mov     cx,1
           mov     ah,9
           int     10h
           inc     [col]
           mov     al,[col]
           cmp     al,[maxcol]
           jbe     setit
           cmp     [wrap],0
           jz      outchr1
           dec     [col]
           ret
   outchr1:
           mov     [col],0
   lf:     inc     [row]
           cmp     [row],24
           jb      setit
           mov     [row],23
           call    scroll

   setit:  mov     dh,row
           mov     dl,col
           xor     bh,bh
           mov     ah,2
           int     10h
           ret

   scroll: call    getmod
           cmp     al,2
           jz      myscroll
           cmp     al,3
           jz      myscroll
           mov     al,10
           jmp     torom
   myscroll:
           mov     bh,[attr]
           mov     bl,' '
           mov     bp,80
           mov     ax,[base]
           mov     es,ax
           mov     ds,ax
           xor     di,di
           mov     si,160
           mov     cx,23*80
           cld
           cmp     ax,0b800h
           jz      colorcard

           rep     movsw
           mov     ax,bx
           mov     cx,bp
           rep     stosw
   sret:   push    cs
           pop     ds
           ret

   colorcard:
           mov     dx,3dah
   wait2:  in      al,dx
           test    al,8
           jz      wait2
           mov     al,25h
           mov     dx,3d8h
           out     dx,al           ; turn off video
           rep     movsw
           mov     ax,bx
           mov     cx,bp
           rep     stosw
           mov     al,29h
           mov     dx,3d8h
           out     dx,al           ; turn on video
           jmp     sret

   GETMOD: MOV     AH,15
           INT     16             ; get column information
           MOV     BPAGE,BH
           DEC     AH
           MOV     WORD PTR MODE,AX
           RET
   ; ------------------------------------------------------
   ;
   ;        Console Read Routine
   ;
   CON$READ:
           JCXZ    CON$EXIT
   CON$LOOP:
           PUSH    CX              ; Save Count
           CALL    CHRIN           ; Get Char in AL
           POP     CX
           STOSB                   ; Store Char at ES:DI
           LOOP    CON$LOOP
   CON$EXIT:
           JMP     EXIT
   ; ---------------------------------------------------------
   ;
   ;        Input Single Char into AL
   ;
   CHRIN:  XOR     AX,AX
           XCHG    AL,ALTAH     ; Get Character & Zero ALTAH
           OR      AL,AL
           JNZ     KEYRET

   INAGN:  XOR     AH,AH
           INT     22
   ALT10:
           OR      AX,AX       ; Check for non-key after BREAK
           JZ      INAGN
           OR      AL,AL       ; Special case?
           JNZ     KEYRET
           MOV     ALTAH,AH        ; Store special key
   KEYRET: RET
   ; ----------------------------------------------------------
   ;
   ;        Keyboard Non-destructive Read, No Wait
   ;
   CON$RDND:
           MOV     AL,[ALTAH]
           OR      AL,AL
           JNZ     RDEXIT

   RD1:    MOV     AH,1
           INT     22
           JZ      CONBUS
           OR      AX,AX
           JNZ     RDEXIT
           MOV     AH,0
           INT     22
           JMP     CON$RDND

   RDEXIT: LDS     BX,[PTRSAV]
           MOV     [BX].MEDIA,AL
   EXVEC:  JMP     EXIT
   CONBUS: JMP     BUS$EXIT
   ; ----------------------------------------------------------
   ;
   ;        Keyboard Flush Routine
   ;
   CON$FLSH:
           MOV     [ALTAH],0         ; Clear out holding buffer

           PUSH    DS
           XOR     BP,BP
           MOV     DS,BP                   ; Select segment 0
           MOV     DS:BYTE PTR 41AH,1EH    ; Reset KB queue head
                                           ; pointer
           MOV     DS:BYTE PTR 41CH,1EH    ; Reset tail pointer
           POP     DS
           JMP     EXVEC
   ; ----------------------------------------------------------
   ;
   ;        Console Write Routine
   ;
   CON$WRIT:
           JCXZ    EXVEC
           PUSH    CX
           MOV     AH,3            ; Set current cursor position
           XOR     BX,BX
           INT     16
           MOV     WORD PTR [COL],DX
           POP     CX

   CON$LP: MOV     AL,ES:[DI]      ; Get Char
           INC     DI
           CALL    OUTC            ; Output Char
           LOOP    CON$LP          ; Repeat until all through
           JMP     EXVEC

   COUT:   STI
           PUSH    DS
           PUSH    CS
           POP     DS
           CALL    OUTC
           POP     DS
           IRET

   OUTC:   PUSH    AX
           PUSH    CX
           PUSH    DX
           PUSH    SI
           PUSH    DI
           PUSH    ES
           PUSH    BP
           CALL    VIDEO
           POP     BP
           POP     ES
           POP     DI
           POP     SI
           POP     DX
           POP     CX
           POP     AX
           RET


   ; ----------------------------------------------------------
   ;
   ;        Output Single Char in AL to Video Device
   ;
   VIDEO:  MOV     SI,OFFSET STATE
           JMP     [SI]

   S1:     CMP     AL,ESC                 ; Escape sequence?
           JNZ     S1B
           MOV     WORD PTR [SI],OFFSET S2
           RET

   S1B:    CALL    CHROUT
   S1A:    MOV     WORD PTR [STATE],OFFSET S1
           RET


   S2:     PUSH    AX
           CALL    GETMOD
           POP     AX
           MOV     BX,OFFSET CMDTABL-3
   S7A:    ADD     BX,3
           CMP     BYTE PTR [BX],0
           JZ      S1A
           CMP     BYTE PTR [BX],AL
           JNZ     S7A
           JMP     WORD PTR [BX+1]


   MOVCUR: CMP     BYTE PTR [BX],AH
           JZ      SETCUR
           ADD     BYTE PTR [BX],AL
   SETCUR: MOV     DX,WORD PTR COL
           XOR     BX,BX
           MOV     AH,2
           INT     16
           JMP     S1A


   CUP:    MOV     WORD PTR [SI],OFFSET CUP1
           RET
   CUP1:   SUB     AL,32
           MOV     BYTE PTR [ROW],AL
           MOV     WORD PTR [SI],OFFSET CUP2
           RET
   CUP2:   SUB     AL,32
           MOV     BYTE PTR [COL],AL
           JMP     SETCUR

   SM:     MOV     WORD PTR [SI],OFFSET S1A
           RET


   CUH:    MOV     WORD PTR COL,0
           JMP     SETCUR

   CUF:    MOV     AH,MAXCOL
           MOV     AL,1
   CUF1:   MOV     BX,OFFSET COL
           JMP     MOVCUR

   CUB:    MOV     AX,00FFH
           JMP     CUF1

   CUU:    MOV     AX,00FFH
   CUU1:   MOV     BX,OFFSET ROW
           JMP     MOVCUR

   CUD:    MOV     AX,23*256+1
           JMP     CUU1

   PSCP:   MOV     AX,WORD PTR COL
           MOV     SAVCR,AX
           JMP     SETCUR

   PRCP:   MOV     AX,SAVCR
           MOV     WORD PTR COL,AX
           JMP     SETCUR

   ED:     CMP     BYTE PTR [ROW],24
           JAE     EL1

           MOV     CX,WORD PTR COL
           MOV     DH,24
           JMP     ERASE

   EL1:    MOV     BYTE PTR [COL],0
   EL:     MOV     CX,WORD PTR [COL]
   EL2:    MOV     DH,CH
   ERASE:  MOV     DL,MAXCOL
           MOV     BH,ATTR
           MOV     AX,0600H
           INT     16
   ED3:    JMP     SETCUR


   RM:     MOV     WORD PTR [SI],OFFSET RM1
           RET
   RM1:    XOR     CX,CX
           MOV     CH,24
           JMP     EL2

   CON$INIT:
           int     11h
           and     al,00110000b
           cmp     al,00110000b
           jnz     iscolor
           mov     [base],0b000h          ; look for bw card
   iscolor:
           cmp     al,00010000b           ; look for 40 col mode
           ja      setbrk
           mov     [mode],0
           mov     [maxcol],39

   setbrk:
           XOR     BX,BX
           MOV     DS,BX
           MOV     BX,BRKADR
           MOV     WORD PTR [BX],OFFSET BREAK
           MOV     WORD PTR [BX+2],CS

           MOV     BX,29H*4
           MOV     WORD PTR [BX],OFFSET COUT
           MOV     WORD PTR [BX+2],CS

           LDS     BX,CS:[PTRSAV]
           MOV     WORD PTR [BX].TRANS,OFFSET CON$INIT
                                 ; SET BREAK ADDRESS
           MOV     [BX].TRANS+2,CS
           JMP     EXIT

   CODE    ENDS
           END



 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Chapter 3  MS-DOS Technical Information

     3.1   Introduction
     3.2   MS-DOS Initialization
     3.3   The Command Processor
     3.4   MS-DOS Disk Allocation
     3.5   MS-DOS Disk Directory
     3.6   File Allocation Table (FAT)
           3.6.1   How to Use the FAT (12-Bit FAT Entries)
           3.6.2   How to Use the FAT (16-Bit FAT Entries)
     3.7   MS-DOS Standard Disk Formats


 3.1  Introduction

   This chapter describes how MS-DOS initializes and how it allocates disk
   space for the root directory, the File Allocation Tables (FAT), and the
   data area. For programmers writing installable device drivers, this
   chapter explains MS-DOS disk directory entries and File Allocation Tables.
   At the end of the chapter, Tables 3.1 and 3.2 describe MS-DOS standard
   formats for floppy disks.


 3.2  MS-DOS Initialization

   MS-DOS initialization consists of several steps. When you reset your
   computer or turn on its power, the ROM (Read Only Memory) BIOS is invoked
   and performs hardware checks and initialization. The ROM BIOS then
   examines drive A for the boot sector. If it locates a boot sector, the ROM
   BIOS reads it into low memory and gives it control. If it doesn't find the
   boot sector, the ROM BIOS then looks in the active partition of the hard
   disk. If it still doesn't find the boot sector, then the ROM BIOS invokes
   ROM BASIC.

   On a removable disk (3.5-inch, 5.25-inch, or 8-inch disk), the boot sector
   is always located on track 0, sector 1, side 0 of the disk. On a hard
   disk, the boot sector begins on the first sector of the MS-DOS partition.
   The hard disk boot sector also includes a partition table. This table
   identifies the active MS-DOS partition and any other partitions, such as
   an extended MS-DOS partition, on the hard disk. Notice that extended
   MS-DOS partitions are not bootable.

   The boot sector then reads the following files, in the order listed:

   io.sys
   msdos.sys


   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     Versions of MS-DOS prior to 3.3 required the io.sys file to be
     contiguous. This is no longer a requirement.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Next, the system initialization routine SYSINIT loads all of the resident
   device drivers. Then, it searches for a config.sys file on the boot disk.
   SYSINIT allocates memory for buffers and files, based on settings in the
   config.sys file or system default settings. If the config.sys file
   specifies any installable device drivers, these are installed next.

   Finally, SYSINIT executes the MS-DOS command processor, command.com.


 3.3  The Command Processor

   The command processor command.com consists of three parts:

   ž  A resident part resides in memory immediately following msdos.sys and
      its data area. This part contains routines to process Interrupts 22H
      (Terminate Process Exit Address), 23H (CONTROL+C Exit Address), and 24H
      (Critical-Error-Handler Address), as well as a routine to reload the
      transient part, if needed. All standard MS-DOS error handling is done
      within this part of command.com. This includes displaying error
      messages and processing the Abort, Retry, Fail, or Ignore messages.

   ž  An initialization part follows the resident part. During startup, the
      initialization part is given control; it contains the processor setup
      routine in the autoexec.bat file. The initialization part determines
      the segment address at which programs can be loaded, and because it is
      no longer needed, is overlaid by the first program that command.com
      loads.

   ž  A transient part is loaded at the high end of memory. This part
      contains all the internal command processors and the batch file
      processor.

      The transient part of the command processor produces the system prompt
      (A>, for example), reads commands from the keyboard (or from batch
      files), and causes them to be executed. For external commands, the
      transient part builds a command line and issues Function 4B00H (Load
      and Execute Program) to load and transfer control to the program.


 3.4  MS-DOS Disk Allocation

   The area on a disk partitioned for use by MS-DOS is formatted as follows:

   1. Reserved areaÄÄvariable size

   2. First copy of File Allocation TableÄÄvariable size

   3. Additional copies of File Allocation TableÄÄvariable size (optional)

   4. Root directoryÄÄvariable size

   5. File data area

   Space for a file in the data area is not preallocated. The space is
   allocated one cluster at a time. A cluster consists of one or more
   consecutive sectors (the number of sectors in a cluster must be a power of
   2); the cluster size is determined at format time. All the clusters for a
   file are "chained" together in the File Allocation Table, discussed in
   greater detail in Section 3.6, "File Allocation Table (FAT)." MS-DOS
   normally keeps a second copy of the FAT for consistency, except in the
   case of reliable storage such as a virtual RAM disk. Should the disk
   develop a bad sector in the middle of the first FAT, MS-DOS can use the
   second. This avoids loss of data due to an unreadable FAT.


 3.5  MS-DOS Disk Directory

   The format utility builds the root directory for all disks. This
   directory's location on the disk and the maximum number of entries are
   dependent on the media. Specifications for standard removable-disk formats
   are outlined later in this chapter. Notice, however, that MS-DOS regards
   directories, other than the root directory, as files, so there is no limit
   to the number of files that the subdirectories under the root directory
   may contain. All directory entries are 32 bytes in length and are in the
   following format (notice that byte offsets are in hexadecimal):

   Byte               Function
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0-7                Filename. Eight characters, left-aligned and padded, if
                      necessary, with blanks. The first byte of this field
                      indicates the file status as follows:

ÖŚÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ·
                      Byte              Status
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
                      00H               The directory entry has never been
                                        used. This is used to limit the
                                        length of directory searches, for
                                        performance reasons.

                      05H               The first character of the filename
                                        contains an E5H character.

                      2EH               The entry is for a directory. If the
                                        second byte is also 2EH, the cluster
                                        field contains the cluster number of
                                        this directory's parent directory
                                        (0000H if the parent directory is the
                                        root directory). Otherwise, bytes 01H
                      Byte              Status
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
                                       root directory). Otherwise, bytes 01H
                                        through 0AH are all spaces, and the
                                        cluster field contains the cluster
                                        number of this directory.

                      E5H               The file was used, but it has since
                                        been erased.
                      Any other character is the first character of a
                      filename.

   8-0A               Filename extension.

   0B                 File attribute. The attribute byte is mapped as follows
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


ÖŚÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ·
                      Byte              Contents
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
                      Byte              Contents
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
                      01H               File is marked read-only. An attempt
                                        to open the file for writing using
                                        Function 3DH (Open Handle) results
                                        in an error code being returned. This
                                        value can be used in programs along
                                        with the other attributes in this
                                        list. Attempts to delete the file
                                        with Function 13H (Delete File) or
                                        Function 41H (Delete Directory
                                        Entry) will also fail.

                      02H               Hidden file. The file is excluded
                                        from normal directory searches.

                      04H               System file. The file is excluded
                                        from normal directory searches.
                      08H               The entry contains the volume label
                                        in the first 11 bytes. The entry
                                        contains no other usable information
                      Byte              Contents
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
                                       contains no other usable information
                                        (except date and time of creation)
                                        and may exist only in the root
                                        directory.

                      10H               The entry defines a subdirectory and
                                        is excluded from normal directory
                                        searches.

                      20H               Archive bit. The bit is set to "on"
                                        whenever the file has been written to
                                        and closed.

                                        Note: The system files (io.sys and
                                        msdos.sys) are marked as read-only,
                                        hidden, and system files. Files can
                                        be marked hidden when they are
                                        created. Also, you may change the
                                        read-only, hidden, system, and
                      Byte              Contents
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
                                       read-only, hidden, system, and
                                        archive attributes through Function
                                        43H (Get/Set File Attributes).
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


ÖŚÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ·
   Byte               Function
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0C-15              Reserved.

   16-17              Time the file was created or last updated. The hour,
                      minutes, and seconds are mapped into two bytes as
                      follows (bit 7 on the left, 0 on the right):

                      Offset 17H
                      | H | H | H | H | H | M | M | M |

                      Offset 16H
   Byte               Function
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
                     Offset 16H
                      | M | M | M | S | S | S | S | S |

                      where:


                      H is the binary number of hours (0-23).
                      M is the binary number of minutes (0-59).
                      S is the binary number of two-second increments.


   18-19              Date the file was created or last updated. The year,
                      month, and day are mapped into two bytes as follows:

                      Offset 19H
                      | Y | Y | Y | Y | Y | Y | Y | M |

                      Offset 18H
                      | M | M | M | D | D | D | D | D |
   Byte               Function
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
                     | M | M | M | D | D | D | D | D |

                      where:


                      Y is the year, 0-119 (1980-2099).
                      M is the month (1-12).
                      D is the day of the month (1-31).
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


   Byte               Function
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   1A-1B              Starting cluster; the number of the first cluster in
                      the file.

                      ž Notice that the first cluster for data space on all
                      disks is cluster 002.

                      ž The cluster number is stored with the least
                      significant byte first.

                      ž For details about converting cluster numbers to
                      logical sector numbers, see Sections 3.6.1 and 3.6.2.

   1C-1F              File size in bytes. The first word of this four-byte
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


 3.6  File Allocation Table (FAT)

   This section explains how MS-DOS allocates disk space in the data area for
   a file by using the File Allocation Table to convert the clusters of a
   file to logical sector numbers. The device driver is then responsible for
   locating the logical sector on the disk. Programs should use the MS-DOS
   file management function calls for accessing files. Programs that access
   the FAT are not guaranteed to be upwardly-compatible with future releases
   of MS-DOS. The following information is useful to system programmers who
   wish to write installable device drivers.

   The File Allocation Table is an array of 12-bit entries (1.5 bytes) for
   each cluster on the disk. For disks containing more than 4085 clusters, a
   16-bit FAT entry is used.

   The first two FAT entries are reserved; however, the device driver may use
   the first byte as a FAT ID byte for determining media. For hard disks, the
   value of this byte is F8H. See Tables 3.1 and 3.2 for the media byte
   descriptors used for 8-inch, 5.25-inch, and 3.5-inch disks.

   The third FAT entry, which starts at byte offset 4, begins the mapping of
   the data area (cluster 002). The operating system does not always
   sequentially write (to the disk) files in the data area. Instead, the
   system allocates the data area one cluster at a time, skipping over
   clusters it has already allocated. The first free cluster following the
   last cluster allocated for that file is the next cluster allocated,
   regardless of its physical location on the disk. This permits the most
   efficient use of disk space, since if you erase old files, you can free
   clusters, which the operating system can then allocate for new files. Each
   FAT entry contains three or four hexadecimal characters, depending on
   whether it is a 12-bit or 16-bit entry:

   Entry              Contents
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   (0)000             If the cluster is unused and available.

   (F)FF7             The cluster has a bad sector in it if it is not part of
                      any cluster chain. MS-DOS will not allocate such a
                      cluster. So for its report, the chkdsk command counts
                      the number of bad clusters, which are not part of any
                      allocation chain.

   (F)FF8-FFF         The last cluster of a file.

   (X)XXX             Any other characters that are the cluster number of the
                      next cluster in the file. The number of the first
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   The File Allocation Table always begins on the first sector after the
   reserved sectors. If the FAT is larger than one sector, the sectors are
   contiguous. The operating system usually writes two copies of the FAT to
   preserve data integrity. MS-DOS reads the FAT into one of its buffers,
   whenever needed (open, read, write, etc.). The operating system also gives
   this buffer a high priority to keep it in memory as long as possible.

 3.6.1  How to Use the FAT (12-Bit FAT Entries)

   To get the starting cluster of a file, examine its directory entry (in the
   FAT). Then, to locate each subsequent cluster of the file, follow these
   steps:

   1. Multiply the cluster number just used by 1.5 (each FAT entry is 1.5
      bytes in length).

   2. The whole part of the product is an offset into the FAT, pointing to
      the entry that maps the cluster just used. That entry contains the
      cluster number of the next cluster of the file.

   3. Use a MOV instruction to move the word at the calculated FAT offset
      into a register.

   4. If the last cluster used was an even number, keep the low-order 12 bits
      of the register by using the AND operator with 0FFFH and the register.
      If the last cluster used was an odd number, keep the high-order 12 bits
      by using the SHR instruction to shift the register right four bits.

   5. If the resultant 12 bits are 0FF8H-0FFFH, the file contains no more
      clusters. Otherwise, the 12 bits contain the number of the next cluster
      in the file.

   To convert the cluster to a logical sector number (relative sector, such
   as that used by Interrupts 25H and 26H (Absolute Disk Read/Write) and by
   debug), follow these steps:

   1. Subtract two from the cluster number.

   2. Multiply the result by the number of sectors per cluster.

   3. To this result, add the logical sector number of the beginning of the
      data area.

 3.6.2  How to Use the FAT (16-Bit FAT Entries)

   To get the starting cluster of a file, examine its directory entry (in the
   FAT). Then, to find the next file cluster, follow these steps:

   1. Multiply the cluster number last used by 2 (each FAT entry is 2 bytes).

   2. Use a MOV WORD instruction to move the word at the calculated FAT
      offset into a register.

   3. If the resultant 16 bits are 0FFF8-0FFFH, no more clusters are in the
      file. Otherwise, the 16 bits contain the number of the next cluster in
      the file.


 3.7  MS-DOS Standard Disk Formats

   MS-DOS arranges data clusters on a disk to minimize head movement. MS-DOS
   then allocates all the space on one track (or cylinder) before moving to
   the next. It uses the sequential sectors on the lowest-numbered head, then
   all the sectors on the next head, and so on, until it has used all the
   sectors on all the heads of the track.

   The size of the MS-DOS partition on a hard disk determines the size of the
   FAT and root directory. Likewise, the type of floppy disk (tracks per
   side, sectors per track, etc.) determines how MS-DOS uses the disk. The
   removable disk formats listed in Tables 3.1 and 3.2 are standard and
   should be readable in the appropriate standard drive.

   Table 3.1
   MS-DOS Standard Removable-Disk Formats
   Disk Size in inches               5.25                         8
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   WORD no. heads                  1     1     2    2           1    2      1
   Tracks/side                    40    40    40   40          77   77     77
   WORD sectors/track              8     9     8    9          26   26      8
   WORD bytes/sector             512   512   512  512         128  128    024
   BYTE sectors/ cluster           1     1     2    2           4    4      1
   WORD reserved sectors           1     1     1    1           1    4      1
   Byte no. FATs                   2     2     2    2           2    2      2
   WORD root directory entries    64    64   112  112          68   68    192
   WORD no. sectors              320   360   640  720        2002 2002    616
   BYTE media descriptor          FE    FC    FF   FD         FE   FD    FE
   WORD sectors/FAT                1     2     1    2           6    6      2
   WORD no. hidden sectors         0     0     0    0           0    0      0
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Table 3.2
   MS-DOS Standard Removable-Disk Formats (High-Density)
   Disk Size in inches                  3.5 or 5.25            3.5      5.25
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   WORD no. heads                  1     2     2    2           2           2
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Tracks/side                    80    80    80   80          80          80
   WORD sectors/track              8     9     8    9          18          15
   WORD bytes/sector             512   512   512  512         512         512
   BYTE sectors/cluster            2     2     2    2           1           1
   WORD reserved sectors           1     1     1    1           1           1
   BYTE no. FATs                   2     2     2    2           2           2
   WORD root dir entries         112   112   112  112         224         224
   WORD no. sectors              640   720  1280 1440        2880        2400
   BYTE media descriptor         FA    FC    FB   F9          F0          F9
   WORD sectors/FAT                1     2     2    3           9           7
   WORD no. hidden sectors         0     0     0    0           0           0
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ



 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Chapter 4  MS-DOS Control Blocks and Work Areas

     4.1   Introduction
     4.2   Typical Contents of an MS-DOS Memory Map
     4.3   The MS-DOS Program Segment


 4.1  Introduction

   This chapter describes a typical MS-DOS memory map and explains how a
   program is loaded into memory. It also describes the structure of an
   MS-DOS program segment and the contents of segment registers for .exe and
   .com program files.


 4.2  Typical Contents of an MS-DOS Memory Map

   A typical MS-DOS memory map contains the following information:

     ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
     ³             ROM and Video Buffers                   ³
     ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
     ³          Transient Part of COMMAND.COM              ³
     ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
     ³                                                     ³
     ³                                                     ³
     ³                                                     ³
     ³                                                     ³
     ³              Transient Program Area                 ³
     ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
     ³                                                     ³
     ³                                                     ³
     ³                                                     ³
     ³                                                     ³
     ³          External Commands and Utilities            ³
     ³                                                     ³
     ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
     ³           Resident Part of COMMAND.COM              ³
     ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
     ³ MS-DOS buffers, control areas, & installed drivers  ³
     ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
     ³                                                     ³
     ³                MSDOS.SYS                            ³
     ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
     ³        IO.SYS and resident device drivers           ³
     ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
     ³                 Interrupt Vectors                   ³
   0 ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   During system initialization, MS-DOS loads the io.sys and msdos.sys files
   into low memory (Notice that in MS-DOS 4.0, the msdos.sys file is not
   required to be written contiguously to the disk). The io.sys system file
   is the MS-DOS interface to hardware. The msdos.sys system file includes
   MS-DOS interrupt handlers and service routines (Interrupt 21H functions).

   Next, the system initialization routine loads the resident and installable
   device drivers. Above the installable device drivers, MS-DOS writes the
   resident part of command.com. This part includes interrupt handlers for
   Interrupts 22H (Terminate Process Exit Address), 23H (CONTROL+C Handler
   Address), 24H (Critical-Error-Handler Address) and code to reload the
   transient part. The transient part of command.com is reloaded into high
   memory. It includes the command interpreter, the internal MS-DOS commands,
   and the batch processor.

   External command and utility (.com and .exe) files are loaded into the
   transient program area. MS-DOS also allocates 256 bytes of user stack used
   with .com files. User memory is allocated from the lowest end of available
   memory that fulfills the allocation request.


 4.3  The MS-DOS Program Segment

   When you type an external command or execute a program through Function
   4B00H or 4B03H (Load and Execute Program or Overlay, also called EXEC),
   MS-DOS determines the lowest available free memory address to use as the
   start of the program. The memory starting at this address is called the
   Program Segment.

   The EXEC system call sets up the first 256 bytes of the Program Segment
   for the program being loaded into memory. The program is then loaded
   following this block. A .exe file with minalloc and maxalloc both set to
   zero is loaded as high as possible.

   At offset 0 within the Program Segment, MS-DOS builds the Program Segment
   Prefix control block. The program returns from EXEC by one of five
   methods:

   ž  By issuing an Interrupt 21H with AH=4CH (End Process)

   ž  By issuing an Interrupt 21H with AH=31H (Keep Process)

   ž  By a long jump to offset 0 in the Program Segment Prefix

   ž  By issuing an Interrupt 20H (Progam Terminate) with CS:0 pointing at
      the PSP

   ž  By issuing an Interrupt 21H with register AH=0 and with CS:0 pointing
      at the PSP

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     The first two methods are preferred for functionality, compatibility,
     and efficiency in future versions of MS-DOS.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   All five methods transfer control to the program that issued the EXEC
   call. The first two methods return a completion code. They also restore
   the addresses of Interrupts 22H, 23H, and 24H (Terminate Process Exit
   Address, CONTROL+C Handler Address, and Critical-Error-Handler Address)
   from the values saved in the Program Segment Prefix of the terminating
   program. Control then passes to the terminate address.

   If a program returns to command.com, control transfers to the resident
   portion. If the program is a batch file (in process), it continues.
   Otherwise, command.com performs a checksum on the transient part, reloads
   it if necessary, issues the system prompt, and waits for you to type
   another command.

   When a program receives control, the following conditions are in effect:

   For All Programs:

   ž  The segment address of the passed environment is at offset 2CH in the
      Program Segment Prefix.

   ž  The environment is a series of ASCII strings (totaling less than 32K)
      in the form:

      NAME=parameter


   ž  A byte of zeros terminates each string, and another byte of zeros
      terminates the set of strings.

      Following the last byte of zeros is a set of initial arguments that the
      operating system passes to a program. This set of arguments contains a
      word count followed by an ASCII string. If the file is in the current
      directory, the ASCII string contains the drive and pathname of the
      executable program as passed to the EXEC function call. If the file is
      not in the current directory, EXEC concatenates the name of the file
      with the name of the path. Programs may use this area to determine
      where the program was loaded.

   ž  The environment built by the command processor contains at least a
      comspec=string (the parameters on comspec define the path that MS-DOS
      uses to locate command.com on the disk). The last path and prompt
      commands issued are also in the environment, along with any environment
      strings you have defined with the MS-DOS set command.

   ž  EXEC passes a copy of the invoking process environment. If your
      application uses a "keep process" concept, you should be aware that the
      copy of the environment passed to you is static. That is, it will not
      change even if you issue subsequent set, path, or prompt commands.
      Conversely, any modification of the passed environment by the
      application is not reflected in the parent process environment. For
      instance, a program cannot change the MS-DOS environment values as the
      set command does.

   ž  The Disk Transfer Address (DTA) is set to 80H (default DTA in the
      Program Segment Prefix). The Program Segment Prefix contains file
      control blocks at 5CH and 6CH. MS-DOS formats these blocks using the
      first two parameters that you typed when entering the command. If
      either parameter contained a pathname, then the corresponding FCB
      contains only the valid drive number. The filename field is not valid.

   ž  An unformatted parameter area at 81H contains all the characters typed
      after the command (including leading and embedded delimiters), with the
      byte at 80H set to the number of characters. If you type <, >, or
      parameters on the command line, they do not appear in this area (nor
      the filenames associated with them). Redirection of standard input and
      output is transparent to applications.

   ž  Register AX indicates whether the drive specifiers (entered with the
      first two parameters) are valid, as follows:

      AL=FF if the first parameter contained an invalid drive specifier
      (otherwise AL=00)

      AH=FF if the second parameter contained an invalid drive specifier
      (otherwise AH=00)

   ž  Offset 2 (one word) contains the segment address of the first byte of
      unavailable memory. Programs must not modify addresses beyond this
      point unless these addresses were obtained by allocating memory via
      Function 48H (Allocate Memory).

   For Executable (.exe) Programs:

   ž  DS and ES registers point to the Program Segment Prefix.

   ž  CS,IP,SS, and SP registers contain the values that Microsoft link sets
      in the .exe image.

   For Executable (.com) Programs:

   ž  All four segment registers contain the segment address of the initial
      allocation block that starts with the Program Segment Prefix control
      block.

   ž  .com programs allocate all of user memory. If the program invokes
      another program through Function 4B00H or 4B03H (EXEC), it must first
      free some memory through Function 4AH (Set Block) to provide space for
      the program being executed.

   ž  The Instruction Pointer (IP) is set to 100H.

   ž  The Stack Pointer register is set to the end of the program's segment.

   ž  A .com program places a word of zeros on top of the stack. Then, by
      doing a RET instruction last, your program can exit to command.com.
      This method assumes, however, that you have maintained your stack and
      code segments.

   Figure 4.1 illustrates the format of the Program Segment Prefix. All
   offsets are in hexadecimal.

                         (Offsets in Hex)
   0 ŚÄÄÄÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
     ³             ³ End of      ³                             ³
     ³   INT 20H   ³ alloc.      ³        Reserved             ³
     ³             ³ block       ³         04H                 ³
   8 ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
     ³             ³   Terminate address    ³   CONTROL+C exit ³
     ³  Reserved   ³       (IP, CS)         ³   address (IP)   ³
     ³             ³                        ³                  ³
   10ĆÄÄÄÄÄÄÄÄÄÄÄÄĀĮÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
     ³CONTROL+C   ³ Hard error exit address ³                  ³
     ³exit        ³       (IP, CS)          ³                  ³
     ³address (CS)³                         ³                  ³
     ĆÄÄÄÄÄÄÄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ                  ³
     ³                                                         ³
     ³                   Used by MS-DOS                        ³
     ³                                                         ³
     ³                         5CH                             ³
     ³                                                         ³
     ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
     ³                                                         ³
     ³    Formatted Parameter Area 1 formatted as standard     ³
     ³                    unopened FCB 6CH                     ³
     ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
     ³                                                         ³
     ³    Formatted Parameter Area 2 formatted as standard     ³
     ³     unopened FCB (overlaid if FCB at 5CH is opened)     ³
   80ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
     ³             Unformatted Parameter Area                  ³
     ³            (default Disk Transfer Area)                 ³
     ³       Initially contains command invocation line.       ³
     ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ
   100

   Figure 4.1  Program Segment Prefix

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Important
     Programs must not alter any part of the Program Segment Prefix below
     offset 5CH.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ



 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Chapter 5  National Language Support

     5.1   Introduction
     5.2   National Language Support Calls
     5.3   Font Files
           5.3.1   Font File Structure


 5.1  Introduction

   National language support for this version of MS-DOS 4.0 includes these
   major features:

   ž  Country-dependent information

   ž  Support for national keyboard layouts

   ž  Programming interfaces for national language support

   ž  Utility commands

   Country-dependent information is available on a per-country basis and
   includes the following:

   ž  Time, date, and currency

   ž  Lowercase-to-uppercase character-conversion tables

   ž  Collating sequence for character sorting

   ž  Valid single-byte characters used in filenames

   Selectable keyboard support for different keyboard layouts is provided.

   The MS-DOS 4.0 programming interfaces for national language support allow
   applications to use the country-dependent information just described. To
   access this information, applications do not need to change the current
   country code of the system.

   Utility commands allow the user to select the keyboard layout and system
   country code.

   This version of MS-DOS does not support right-to-left national languages.


 5.2  National Language Support Calls

   The following function calls allow an application to tailor its operation
   to the current country code and to accept or change the current code page.
   A country code defines the country in which you live or work. MS-DOS uses
   this code to prepare and assign default code pages for your system. A code
   page is a table that defines the character set you are using. A character
   set is a country-specific or language-specific group of characters that
   are translated from the code page table and displayed on your screen or
   printer. Each code page character set contains 256 characters. The
   following function calls are also used by MS-DOS 4.0 to support the
   National Language requirements:

   ž  Function 440CH (Generic IOCtl) ÄÄ supports code page switching on a
      per-device basis.

   ž  Function 65H (Get Extended Country Information) ÄÄ returns standard
      country information and points to related case-map or collating tables.

   ž  Function 66H (Get/Set Global Code Page) ÄÄ gets or sets the code page
      used by the kernel and by all devices.

   These functions support access to country-dependent information, all of
   which resides in one file named country.sys.


 5.3  Font Files

   Font files, also called code page information files, contain the images of
   code page character sets for use by display or printer devices. These font
   files are identified by a filename extension of .cpi. Four font files are
   included with MS-DOS 4.0:

   Font file          Supported device
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   ega.cpi            Color console used with an EGA card

   lcd.cpi            Liquid crystal display

   4201.cpi           IBM 4201 Proprinter family and IBM 4202 Proprinter
                      printers

   4208.cpi           IBM 4207 Proprinter X24 and IBM 4208 Proprinter XL24
                      printers

   5202.cpi           IBM 5202 Quietwriter III printer
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

 5.3.1  Font File Structure

   The contents of printer or display font files are structured as follows:

   ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³ 23-BYTE File Header                  ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ WORD Information Header              ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ 28-BYTE Code Page Entry Header(s)    ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ Variable size Font Data Block(s)     ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³ 150-BYTE Copyright Notice            ³
   ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ


   Figure 5.1  Font File Structure

   The first code page entry header immediately follows the information
   header. The copyright notice is always at the end of the file. Between
   these, the file consists of arbitrarily intermingled code page entry
   headers and font data blocks.

   The font file fields are described in the following sections.

   File Header

   Each file must begin with a file header. There is only one of these
   headers per file. This header identifies the file as a valid font file and
   has the following format:

   Length             Parameter
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   8 BYTES            File tag
   8 BYTES            Reserved
   WORD               Number of pointers
   BYTE               Type of pointer
   2 WORDS            Offset
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   where:

   File tag begins with the byte 0FFH and is followed by the seven-byte
   string "font."

   Reserved is eight bytes of zeros.

   Number of pointers is the number of information pointers in the header.
   For MS-DOS 4.0, the value of this word should be 1.

   Type of pointer is the type of information pointers in the header. For
   MS-DOS 4.0, the value of this word should be 1.

   Offset is the offset, in bytes, from the beginning of the file to the
   information header.

   Information Header

   The information header begins at the offset given in the file header. It
   describes how many code pages are contained in the font file. The format
   of this one-word information header is:

   Length             Parameter
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   WORD               Number of code pages
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   where:

   Number of code pages is the number of code page entries in the file.

   Code Page Entry Header

   The number of code page entries in a font file is defined in the preceding
   section, "Information Header." For each code page in the font file, there
   is a code page entry header that gives general information about that code
   page entry in the file. The header has the following format:

   Length             Parameter
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   WORD               Length
   2 WORDS            Pointer
   WORD               Device type
   8 BYTES            Device subtype
   WORD               Code page ID
   3 WORDS            Reserved
   2 WORDS            Offset
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   where:

   Length is the size of the code page entry header. Since this header is a
   fixed size, it can be used for testing if the font file has been read in
   correctly.

   Pointer is a two-word pointer to the next code page entry header. The last
   header will point to nothing and will have a value of 0,0.

   Device type is 1 if the device is a raster display, or 2 if the device is
   a printer.

   Device subtype names the type of display or printer. This field also
   determines the name of the font file. For example, if the subtype is
   "EGA," the font file name is ega.cpi

   Code page ID defines a valid three-digit code page identification number.
   Valid code page numbers are 437, 850, 860, 863, and 865.

   Reserved is three words of zeros.

   Offset is a double-word pointer to the font data block associated with
   this code page and described in the next section.

   Font Data Block

   The Font Data Block consists of the following fields:

   ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³   6-BYTE Font Data Header               ³
   ĆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³   Variable length Font Description(s)   ³
   ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   The code page of a font data block is specified by the code page entry
   header whose Offset field points to that font data block. The device type
   contained in this code page entry header determines whether the font
   description(s) should be interpreted as raster-style (display) fonts or
   escape code sequences for particular downloadable device (printer) fonts.

   The Font Data Header, the Display Font Description, and the Printer Font
   Description fields are described in the following sections.

   Font Data Header:

   The Font Data Header indicates how many font descriptions exist for the
   current code page. This header has the following fields:

   Length             Parameter
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   WORD               Reserved
   WORD               Number of fonts
   WORD               Length of font data
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   where:

   Reserved must be 1.

   Number of fonts specifies the number of fonts (font descriptions) that
   immediately follow this font data header. These font descriptions are all
   associated with the font data block's code page. For printer devices, the
   number of fonts must be equal to one.

   Length of font data is equal to the sum of the sizes (in bytes) of the
   font descriptions, as described in the next two sections.

   Display Font Description:

   Each font description for a display device begins with a header that
   specifies the raster dimensions of each character in the font and the
   number of characters in the font. This is followed by the raster bitmaps
   for each character. The actual fields are:

   Length             Parameter
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   BYTE               Height
   BYTE               Width
   BYTE               Relative height
   BYTE               Relative width
   WORD               Number of characters
   Variable           Bitmap
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   where:

   Height is the number of rows in pixels that this character occupies on the
   screen. Width is the number of columns in pixels that this character
   occupies on the screen.

   Relative height is part of the aspect ratio. This is currently unused
   (zero).

   Relative width is part of the aspect ratio. This is currently unused
   (zero).

   Number of characters is the number of characters that are defined in the
   bitmap immediately following this header. Normally, the entire ASCII
   character set is defined, so that this value is usually 256.

   Bitmap is a sequence of bitmaps, one for each character in the font. Each
   character bitmap is a packed array of bits organized in rows by columns,
   starting at the upper left corner of the character's image. Since all
   current display fonts are eight bits wide, the number of bytes needed to
   encode this packed array is simply equal to the square area of a character
   in the font divided by 8 (the number of bits per byte).

   The total length of the display font description is six bytes plus the
   product of the number of characters in the descriptions and the number of
   bytes needed to encode a character bitmap.

   Printer Font Description:

   There are two formats for printer font descriptions. These vary only in
   the number of control sequences present in the font description.

   Unlike the display font description, the number of bytes in the printer
   font description cannot be directly determined. Instead, the size of the
   printer font description must be calculated from the font header's length
   value. As a result, only one printer font description can be contained in
   a given font data block (otherwise, the point at which the first ended and
   the second printer font description began could not be determined).

   The format for the printer font desription is:

   Length             Parameter
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   WORD               Selection type
   WORD               Control sequence length
   Variable           Control sequence data
   Variable           Downloadable font data
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   where:

   Selection type is either 1 or 2. It identifies which of the two formats
   for the printer font description is being used. These existing printer
   files use the following selection types:

      Selection type    Printer font file
      ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
      1                 4201.cpi
      2                 4208.cpi
      2                 5202.cpi
      ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Control sequence length is the number of bytes the control sequence data
   field takes. This length must always be less than 31 (bytes).

   Control sequence data is used for initializing the printer with this code
   page. The size of this field is defined in the control sequence length
   field.

   If the selection type field is 2, this control sequence information
   consists of a single escape sequence that selects the font for this code
   page (this font may have been downloaded).

   If the selection type field is 1, this control sequence information is
   further divided into two escape sequences. In this case, the control
   sequence data field consists of:

      Length            Parameter
      ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
      BYTE              Hardware sequence length
      Variable          Hardware sequence
      BYTE              Downloadable sequence length
      Variable          Downloadable sequence
      ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

       where:

       Hardware sequence length is the number of bytes contained in the
       hardware sequence.

       Hardware sequence is the escape sequence that selects the hardware
       (default) font of the printer.

       Downloadable sequence length is the number of bytes contained in the
       downloadable sequence.

       Downloadable sequence is the escape sequence that selects the
       downloaded font currently resident in the printer.

       Notice that the total number of bytes in these subfields must be equal
       to the number of bytes given by the control sequence length field in
       the printer font description.

   Downloadable font data consists of the escape sequence required to
   download the font description. This escape sequence is highly printer
   specific. The number of bytes in it is determined by subtracting the size
   of the initial portion of the printer font description from the Length
   field of the font data block.

   Since the 4208 and 5202 printers have hardware support for code pages,
   they do not need any font data to be downloaded. Therefore, this field is
   nonexistent in those font files.



 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Chapter 6  .Exe File Structure and Loading

     6.1   Introduction
     6.2   Format of a File Header
     6.3   The Relocation Table


 6.1  Introduction

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     This chapter describes .exe file structure and loading procedures for
     systems that use a version of MS-DOS earlier than 2.0. For MS-DOS
     versions 2.0 and later, use Function B00H (Load and Execute Program) to
     load (or load and execute) a .exe file.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   The .exe files produced by link consist of two parts:

   ž  Control and relocation information

   ž  The load module

   The control and relocation information is at the beginning of the file in
   an area called the header. Immediately following this header is the load
   module.


 6.2  Format of a File Header

   The header is formatted as follows (notice that offsets are in
   hexadecimal):

ÖŚÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ·
   Offset             Contents
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0-1                Must contain 4DH, 5AH.

   2-3                Number of bytes contained in last page; useful for
                      reading overlays.

   4-5                Size of the file in 512-byte pages, including the
                      header.

   6-7                Number of relocation entries in table.

   8-9                Size of the header in 16-byte paragraphs. Used to
   Offset             Contents
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  8-9                Size of the header in 16-byte paragraphs. Used to
                      locate the beginning of the load module in the file.

   AH-BH              Minimum number of 16-byte paragraphs required above the
                      end of the loaded program.

   CH-DH              Maximum number of 16-byte paragraphs required above the
                      end of the loaded program. If both minalloc and
                      maxalloc are 0, the program is loaded as high as
                      possible.

   EH-FH              Initial value to be loaded into stack segment before
                      starting program execution. Must be adjusted by
                      relocation.

   10-11              Value to be loaded into the SP register before starting
                      program execution.

   12-13              Negative sum of all the words in the file.
   Offset             Contents
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  12-13              Negative sum of all the words in the file.

   14-15              Initial value to be loaded into the IP register before
                      starting program execution.

   16-17              Initial value to be loaded into the CS register before
                      starting program execution. Must be adjusted by
                      relocation.

   18-19              Relative byte offset from beginning of run file to
                      relocation table.

   1AH-1BH            The number of the overlay as generated by link.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ



 6.3  The Relocation Table

   The relocation table that follows the formatted area above consists of a
   variable number of relocation items. Each relocation item contains two
   fields: a two-byte offset value, followed by a two-byte segment value.
   These two fields contain the offset into a word's load module. This item
   requires modification before the module is given control. The following
   steps describe this process:

   1. The formatted part of the header is read into memory. Its size is 1BH.

   2. MS-DOS allocates a portion of memory depending on the size of the load
      module and the allocation numbers (AH-BH and CH-DH). MS-DOS then
      attempts to allocate 0FFFH paragraphs. This attempt always fails and
      returns the size of the largest free block. If this block is smaller
      than minalloc and loadsize, there is no memory error. But if this block
      is larger than maxalloc and loadsize, MS-DOS allocates (maxalloc +
      loadsize). Otherwise, it allocates the largest free block of memory.

   3. A Program Segment Prefix is built in the lowest part of the allocated
      memory.

   4. MS-DOS calculates the load module size (using offsets 4-5 and 8-9) by
      subtracting the header size from the file size. The actual size is
      adjusted down based on the contents of offsets 2-3. The operating
      system determines (based on the setting of the high/low load switch) an
      appropriate segment, called the start segment, where it loads the load
      module.

   5. The load module is read into memory beginning with the start segment.

   6. The items in the relocation table are read into a work area.

   7. MS-DOS adds the segment value of each relocation table item to the
      start segment value. This calculated segment, plus offset, points to
      the module to which the start segment value is added. The result is
      then placed back into the word in the load module.

   8. Once all relocation items have been processed, the operating system
      sets the SS and SP registers, using the values in the header. MS-DOS
      then adds the start segment value to SS and sets the ES and DS
      registers to the segment address of the Program Segment Prefix. The
      start segment value is then added to the header CS register value. The
      result, along with the header IP value, is the initial CS:IP to
      transfer to before starting execution of the program.



 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Chapter 7  Relocatable Object Module Formats

     7.1   Introduction
           7.1.1   Definition of Terms
     7.2   Module Identification and Attributes
           7.2.1   Segment Definition
           7.2.2   Addressing a Segment
           7.2.3   Symbol Definition
           7.2.4   Indices
     7.3   Conceptual Framework for Fixups
           7.3.1   Self-Relative Fixup
           7.3.2   Segment-Relative Fixup
     7.4   Record Sequence
     7.5   Introducing the Record Formats
           7.5.1   Sample Record Format (SAMREC)
           7.5.2   T-Module Header Record (THEADR)
           7.5.3   L-Module Header Record (LHEADR)
           7.5.4   List of Names Record (LNAMES)
           7.5.5   Segment Definition Record (SEGDEF)
           7.5.6   Group Definition Record (GRPDEF)
           7.5.7   Public Names Definition Record (PUBDEF)
           7.5.8   Communal Names Definition Record (COMDEF)
           7.5.9   Local Symbols Record (LOCSYM)
           7.5.10  External Names Definition Record (EXTDEF)
           7.5.11  Line Numbers Record (LINNUM)
           7.5.12  Logical Enumerated Data Record (LEDATA)
           7.5.13  Logical Iterated Data Record (LIDATA)
           7.5.14  Fixup Record (FIXUPP)
           7.5.15  Module End Record (MODEND)
           7.5.16  Comment Record (COMENT)
     7.6   Microsoft Type Representations for Communal Variables


 7.1  Introduction

   This chapter presents the object record formats that define the
   relocatable object language for the 8086, 80186, and 80286
   microprocessors. The 8086 object language is the output of all language
   translators that have an 8086 processor and that will be linked by the
   Microsoft linker. The 8086 object language is used for input and output
   for object language processors such as linkers and librarians, and in the
   XENIX, PC-DOS, and MS-DOS operating systems.

   The 8086 object module formats let you specify relocatable memory images
   that may be linked together. These formats also allow efficient use of the
   memory mapping facilities of the 8086 family of microprocessors.

   The following table lists the record formats that Microsoft supports.
   Their abbreviations appear in parentheses. Each is described in this
   chapter.

   Table 7.1
   Object Module Record Formats
   Symbol Definition Records
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Public Names Definition Record       (PUBDEF)
   Communal Names Definition Record     (COMDEF)
   Local Symbols Record                 (LOCSYM)
   External Names Definition Record     (EXTDEF)
   Line Numbers Record                  (LINNUM)

   Data Records
   Logical Enumerated Data Record       (LEDATA)
   Logical Iterated Data Record         (LIDATA)
   T-Module Header Record               (THEADR)
   L-Module Header Record               (LHEADR)
   List of Names Record                 (LNAMES)
   Segment Definition Record            (SEGDEF)
   Group Definition Record              (GRPDEF)

   Fixup Record                         (FIXUPP)
   Module End Record                    (MODEND)
   Comment Record                       (COMENT)
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     If an object module contains any undefined values, the behavior of the
     Microsoft linker is undefined. All undefined values should be considered
     reserved by Microsoft for future use.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

 7.1.1  Definition of Terms

   The following terms are fundamental to 8086 relocation and linkage:

   OMF - Object Module Formats

   MAS - Memory Address Space

   The 8086 MAS is one megabyte (1,048,576 bytes). Notice that the MAS is
   distinguished from actual memory, which may occupy only a portion of the
   MAS.

   Module

   A module is an "inseparable" collection of object code and other
   information produced by a translator.

   T-Module

   A T-module is a module created by a translator, such as Pascal or FORTRAN.

   The following restrictions apply to object modules:

   ž  Every module should have a name. Translators provide default names
      (possibly filenames or null names) for T-modules if neither the source
      code nor the user specifies otherwise.

   ž  Every T-module in a collection of linked modules should have a
      different name so that symbolic debugging systems can distinguish the
      various line numbers and local symbols. The Microsoft linker does not
      require or enforce this restriction.

   Frame

   A frame is a contiguous region of 64K of memory address space (MAS),
   beginning on a paragraph boundary (i.e., on a multiple of 16 bytes) or on
   a selector on the 80286 processor. This concept is useful because the
   contents of the four 8086 segment registers define four (possibly
   overlapping) frames; no 16-bit address in the 8086 code can access a
   memory location outside the current four frames.

   LSEG (Logical Segment)

   A logical segment (LSEG) is a contiguous region of memory whose contents
   are determined at translation time (except for address-binding). Neither
   the size nor the location in MAS are necessarily determined during
   translation: the size, although partially fixed, may not be final because
   the linker may combine the LSEG when linking with other LSEGs, forming a
   single LSEG. So that it can fit in a frame, an LSEG must not be larger
   than 64K. Thus, a 16-bit offset, from the base of a frame that covers the
   LSEG, may address any byte in that LSEG.

   PSEG (Physical Segment)

   This term is equivalent to frame. Some prefer "PSEG" to "frame" because
   the terms PSEG and LSEG reflect the "physical" and "logical" nature of the
   underlying segments.

   Frame Number

   Every frame begins on a paragraph boundary. The "paragraphs" in MAS can be
   numbered from 0 through 65,535. These numbers, each of which defines a
   frame, are called frame numbers.

   Group

   A group is a collection of LSEGs defined at translation time, whose final
   locations in MAS have been constrained so that at least one frame exists
   that covers (contains) every LSEG in the collection.

   The notation "Gr A(X,Y,Z,)" means that LSEGs X, Y, and Z form a group
   named A. That X, Y, and Z are all LSEGs in the same group does not imply
   any ordering of X, Y, and Z in MAS, nor does it imply any contiguity
   between X, Y, and Z.

   The Microsoft linker does not currently allow an LSEG to be a member of
   more than one group.

   Canonic

   On the 8086 processor, any location in MAS is contained in exactly 4096
   distinct frames, but one of these frames can be distinguished because it
   has a higher frame number. This frame is called the canonic frame of the
   location. In other words, the canonic frame of a given byte is the frame
   chosen so that the byte's offset from that frame lies in the range 0 to 15
   (decimal).

   For example, suppose FOO is a symbol defining a memory location. You would
   then refer to this frame as the "canonic frame of FOO." Similarly, if S is
   any set of memory locations, then a unique frame exists that has the
   lowest frame number in the set of canonic frames of the locations in S.
   This unique frame is called the canonic frame of the set S. You might
   refer similarly to the canonic frame of an LSEG or of a group of LSEGs.

   Segment Name

   LSEGs are assigned segment names at translation time. These names serve
   two purposes:

   ž  During linking, they play a role in determining which LSEGs are
      combined with other LSEGs.

   ž  They are used in assembly source code to specify membership in groups.

   Class Name

   The translator may optionally assign class names to LSEGs during
   translation. Classes define a partition on LSEGs: two LSEGs are in the
   same class if they have the same class name.

   The Microsoft linker applies the following semantics to class names: the
   class name "CODE", or any class name whose suffix is "CODE", implies that
   all segments of that class contain only code and may be considered
   read-only. Such segments may be overlaid if you specify the module
   containing the segment as part of an overlay.

   Overlay Name

   The linker may optionally assign an overlay name to LSEGs. The overlay
   name of an LSEG is ignored by Microsoft language linkers for version 3.0
   and later languages, but the standard MS-DOS linker supports it.

   Complete Name

   The complete name of an LSEG consists of the segment name, class name, and
   overlay name. The linker combines LSEGs from different modules if their
   complete names are identical.


 7.2  Module Identification and Attributes

   A module header record, which provides a module name, is always the first
   record in a module. In addition to having a name, a module may represent a
   main program and may have a specified starting address. When linking
   multiple modules together, you should give only one module which has the
   main attribute. If more than one main module appears, the first takes
   precedence.

   In summary, modules may or may not be main and may or may not have a
   starting address.

 7.2.1  Segment Definition

   A module is a collection of object code defined by a sequence of records
   that a translator produces. The object code represents contiguous regions
   of memory whose contents the linker determines during translation. These
   regions are LSEGs. A module defines the attributes of each LSEG. The
   segment definition record (SEGDEF) is responsible for maintaining all LSEG
   information (name, length, memory alignment, etc.). The linker requires
   the LSEG information when you combine multiple LSEGs and when it
   establishes segment addressability. The SEGDEF records must follow the
   first header record.

 7.2.2  Addressing a Segment

   The 8086 addressing mechanism provides segment base registers from which
   you may address a 64-kilobyte region of memory (a frame). There is one
   code segment base register (CS), two data segment base registers (DS, ES),
   and one stack segment base register (SS).

   The possible number of LSEGs that may make up a memory image far exceeds
   the number of available base registers. Thus, base registers may require
   frequent loading. This would be the case in a modular program with many
   small data and/or code LSEGs.

   Since such frequent loading of base registers is undesirable, it is a good
   strategy to collect many small LSEGs together into a single unit that will
   fit in one memory frame. Then all the LSEGs may be addressed using the
   same base register value. This addressable unit is a group (see the
   definition of a group in Section 7.1.1, "Definition of Terms").

   To establish addressability of objects within a group, you must explicitly
   define each group in the module. The group definition record (GRPDEF)
   lists constituent segments by their segment names.

   The GRPDEF records within a module must follow all SEGDEF records because
   GRPDEF records will reference SEGDEF records in defining a group. The
   GRPDEF records must also precede all other records except header records,
   which the linker must process first.

 7.2.3  Symbol Definition

   The Microsoft linker supports three different types of records belonging
   to the class of symbol definition records. The types are public names
   definition records (PUBDEFs), communal names definition records (COMDEFs),
   and external names definition records (EXTDEFs). You use these record
   types to define globally visible procedures and data items and to resolve
   external references.

 7.2.4  Indices

   "Index" fields appear throughout this chapter. An index is an integer that
   selects a particular item from a collection of items; for example: name
   index, segment index, group index, external index, type index, etc.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     An index is normally a positive number. The index value zero is
     reserved, and may carry a special meaning depending on the type of index
     (for example, a segment index of zero specifies the "Unnamed" absolute
     pseudo-segment; a type index of zero specifies the "Untyped type").
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   In general, indices must assume values that are quite large (that is, much
   larger than 255). Nevertheless, a great number of object files contain no
   indices with values greater than 50 or 100. Therefore, indices are encoded
   in one or two bytes, as required.

   The high-order (left-most) bit of the first (and possibly the only) byte
   determines whether the index occupies one byte or two. If the bit is 0,
   the index is a number between 0 and 127, occupying one byte. If the bit is
   1, the index is a number between 0 and 32K-1, occupying two bytes, and is
   determined as follows: the low-order eight bits are in the second byte,
   and the high-order seven bits are in the first byte.


 7.3  Conceptual Framework for Fixups

   A fixup is a modification to object code that achieves address binding
   that a translator requested and a linker performed.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     This is the linker's definition of fixup. Nevertheless, the linker can
     modify object code (make a "fixup") that does not conform to this
     definition. For example, binding code to either hardware or software
     floating-point subroutines is a modification to an operation code, which
     is treated as an address. The previous definition of fixup is not
     intended to disallow or discourage modifications to the object code.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   8086-family translators need four kinds of data to specify a fixup:

   ž  The place and type of a location to be fixed up.

   ž  One of two possible fixup modes.

   ž  A target, which is the memory address to which the location must refer.

   ž  A frame that defines a context in which the reference takes place.

   Location ÄÄ There are five types of locations: a pointer, a base, an
   offset, a hibyte, and a lobyte.

   The vertical alignment of Figure 7.1 illustrates four points (remember
   that the high-order byte of a word in 8086 memory is the byte with the
   higher address):

   ž  A base is the high-order word of a pointer (the linker doesn't care
      whether the low-order word of the pointer is present).

   ž  An offset is the low-order word of a pointer (the linker doesn't care
      whether the high-order word follows).

   ž  A hibyte is the high-order half of an offset (the linker doesn't care
      whether the low-order half precedes).

   ž  A lobyte is the low-order half of an offset (the linker doesn't care
      whether the high-order half follows).

             ŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   Pointer:  ³                   ³
             ĄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

                       ŚÄÄÄÄÄÄÄÄÄæ
   Base:               ³         ³
                       ĄÄÄÄÄÄÄÄÄÄŁ

             ŚÄÄÄÄÄÄÄÄÄæ
   Offset:   ³         ³
             ĄÄÄÄÄÄÄÄÄÄŁ

                  ŚÄÄÄÄæ
   Hibyte:        ³    ³
                  ĄÄÄÄÄŁ

             ŚÄÄÄÄæ
   Lobyte:   ³    ³
             ĄÄÄÄÄŁ

   Figure 7.1  Location Types

   A Location is specified by two kinds of data: the location type, and where
   it is located.

   The location type is specified by the LOC field in the FIXUPP record's
   LOCAT field; where it is located is specified by the Data Record Offset
   field in the same LOCAT field.

   Mode ÄÄ The Microsoft linker supports two kinds of fixups: self-relative
   and segment-relative.

   Self-relative fixups support the 8-bit and 16-bit offsets used in CALL,
   JUMP, and SHORT-JUMP instructions. Segment-relative fixups support all
   other addressing modes of the 8086.

   Target ÄÄ The target is the location in MAS that the linker references.
   (More explicitly, the linker considers the target the lowest byte in the
   object that it is referencing.) The linker specifies a target by one of
   five methods. There are three "primary" methods and three "secondary"
   ones. Each primary method of specifying a target uses two kinds of data:
   an index number X, and a displacement D.

   Method             Explanation
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   (T0)               X is a segment index. The target is the Dth byte in the
                      LSEG that the segment index identifies.

   (T1)               X is a group index. The target is the Dth byte in the
                      LSEG that the group index identifies.

   (T2)               X is an external index. The external index identifies
                      the external name that (eventually) gives the address
                      of a byte. The Dth byte following this byte is the
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Each secondary method of specifying a target uses only one item of data ÄÄ
   the index number X; this assumes an implicit displacement equal to zero.

   Method             Explanation
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   (T4)               X is a segment index. The target is the 0th (first)
                      byte in the LSEG that the segment index identifies.

   (T5)               X is a group index. The target is the 0th (first) byte
                      in the LSEG in the specified group located (eventually)
                      lowest in MAS.

   (T6)               X is an external index. The target is the byte whose
                      address is the external name that the external index
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   The following nomenclature describes a target:

   Nomenclature                                     Method
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Target: SI(segment name), displacement           [T0]
   Target: GI(group name), displacement             [T1]
   Target: EI(symbol name), displacement            [T2]
   Target: SI (segment name)                        [T4]
   Target: GI (group name)                          [T5]
   Target: EI (symbol name)                         [T6]
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   The following examples illustrate how this notation is used:

   Sample Nomenclature                  Explanation
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Target: SI(CODE), 1024               The 1025th byte in the segment CODE.

   Target: GI(DATAAREA)                 The location in MAS of a group called
                                        DATAAREA.

   Target: EI(SIN)                      The address of the external
                                        subroutine SIN.

   Target: EI(PAYSCHEDULE), 24          The 24th byte following the location
                                        of an external data structure called
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Frame ÄÄ Every 8086 memory reference is to a location contained within a
   frame. This frame is designated by the contents of a segment register. For
   the linker to form a correct, usable memory reference, it must know what
   the target is, and to which frame the reference is being made. Thus, every
   fixup specifies such a frame, in one of five methods. Some methods use
   data, X, which is in the index number. Other methods require no data.

   The five methods of specifying frames are as follows:

   Method             Explanation
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   (F0)               X is a segment index. The frame is the canonic frame of
                      the LSEG that the segment index defines.

   (F1)               X is a group index. The frame is the canonic frame
                      defined by the group (that is, the canonic frame
                      defined by the LSEG in the group located (eventually)
                      lowest in MAS).

   (F2)               X is an external index. The frame is determined when
                      the linker finds the external name's public definition.
                      There are two cases:

                      Case              Explanation
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
                      (F2a)             The linker defines the symbol
                                        relative to some LSEG, and there is
                                        no associated group. The linker also
                                        specifies the LSEG's canonic frame.

                      (F2c)             Regardless of how the linker defines
                                        the symbol, there is an associated
                                        group. And the linker specifies the
                                        canonic frame of the group. (The
                                        Group Index field of the PUBDEF
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Method             Explanation
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   (F4)               No X. The frame is the canonic frame of the LSEG that
                      contains the location.

   (F5)               No X. The target determines the frame. There are three
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

                      Case              Explanation
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
                      (F5a)             The target specifies a segment index:
                                        in this case, the frame is determined
                                        as in (F0).

                      (F5b)             The target specifies a group index:
                                        in this case, the frame is determined
                                        as in (F1).

                      (F5c)             The target specifies an external
                                        index: in this case, the frame is
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   The nomenclature that describes frames is similar to the above
   nomenclature for targets.

   Nomenclature                                     Method
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Frame: SI (segment name)                         [F0]
   Frame: GI (group name)                           [F1]
   Frame: EI (symbol name)                          [F2]
   Frame: Location                                  [F4]
   Frame: target                                    [F5]
   Frame: None                                      [F6]
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   For an 8086 memory reference, the frame specified by a self-relative
   reference is usually the canonic frame of the LSEG that contains the
   location. Also, the frame specified by a segment-relative reference is the
   canonic frame of the LSEG that contains the target.

 7.3.1  Self-Relative Fixup

   A self-relative fixup works as follows: the location implicitly defines a
   memory addressÄÄnamely, the address of the byte following the location
   (because at the time of a self-relative reference, the 8086 IP
   (Instruction Pointer) is pointing to the byte following the reference).

   For 8086 self-relative references, if either the location or the target is
   outside the specified frame, the linker gives a warning. Otherwise, there
   is a unique l6-bit displacement that, when added to the address implicitly
   defined by the location, yields the relative position of the target in the
   frame.

   ž  If the location is an offset, the linker adds the displacement to the
      location (modulo 65,536) and reports no errors.

   ž  If the location is a lobyte, the displacement must be within the range
      {-128:127}; otherwise, the linker gives a warning. The linker adds the
      displacement to the location (modulo 256).

   ž  If the location is a base, pointer, or hibyte, it is unclear what the
      translator intended, so the linker's action is undefined.

 7.3.2  Segment-Relative Fixup

   A segment-relative fixup operates as follows: a nonnegative 16-bit number,
   FBVAL, is defined as the frame number of the frame or selector value that
   the fixup specifies. A signed 20-bit number, FOVAL, is defined as the
   distance from the base of the frame to the target. If this signed 20-bit
   number is less than 0 or greater than 65,535, the linker reports an error.
   Otherwise, the linker uses FBVAL and FOVAL to fix up the location in the
   following fashion:

   ž  If the location is a pointer, the linker adds FBVAL (modulo 65,536) to
      the high-order word of the pointer, and adds FOVAL (modulo 65,536) to
      the low-order word of the pointer.

   ž  If the location is a base, the linker adds FBVAL (modulo 65,536) to the
      base and ignores FOVAL.

   ž  If the location is an offset, the linker adds FOVAL (modulo 65,536) to
      the offset and ignores FBVAL.

   ž  If the location is a hibyte, the linker adds (FOVAL/256) (modulo 256)
      to the hibyte and ignores FBVAL. (The division indicated is integer
      division; that is, the linker discards the remainder.)

   ž  If the location is a lobyte, the linker adds (FOVAL modulo 256) (modulo
      256) to the lobyte and ignores FBVAL.


 7.4  Record Sequence

   An object code file must contain a sequence of one or more modules, or a
   library containing zero or more modules. The following syntax shows the
   valid record ordering necessary to form a module. In addition, the given
   semantic rules provide information about how to interpret the record
   sequence.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     The description language used in the following syntax is defined in
     WIRTH: CACM, November 1977, vol. 20, no. 11, pp. 822-823. The character
     strings represented by capital letters are not literals but identifiers,
     and are further defined in the record format section.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ



   object file  = tmodule

   tmodule      = {THEADR | LHEADR} seg-grp {component} modtail

   seg_grp      = {LNAMES} {SEGDEF} {EXTDEF | GRPDEF}

   component    = data | debug_record

   data         = content_def | thread_def |
                       PUBDEF | EXTDEF | COMDEF | LOCSYM

   debug_record = LINNUM

   content_def  = data_record {FIXUPP}

   thread_def   = FIXUPP (containing only Thread fields)

   data_record  = LIDATA | LEDATA

   modtail      = MODEND

   The following rules apply:

   ž  A FIXUPP record always refers to the previous data record.

   ž  All LNAMES, SEGDEF, GRPDEF, and EXTDEF records must precede all records
      that refer to them.

   ž  Comment records may appear anywhere in a file, except as the first or
      last record in a file or module, or within a content_def.


 7.5  Introducing the Record Formats

   The following pages present diagrams of record formats in schematic form.
   Here is a sample record format that illustrates the various conventions:

 7.5.1  Sample Record Format (SAMREC)

   ŚÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄÄ///ÄÄÄÄĀÄÄÄÄ||||ÄÄÄÄĀÄÄÄÄÄæ
   ³     ³          ³            ³            ³     ³
   ³ REC ³  Record  ³    Name    ³   Number   ³ CHK ³
   ³ TYP ³  Length  ³            ³            ³ SUM ³
   ³ xxH ³          ³            ³            ³     ³
   ³     ³          ³            ³            ³     ³
   ĄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄ///ÄÄÄÄÄÅÄÄÄÄ||||ÄÄÄÄĮÄÄÄÄÄŁ
                    ³            ³
                    ĄÄÄÄÄrptÄÄÄÄÄŁ

   The Title and Official Abbreviation

   At the top of the figure is the name of the record format described, with
   its official abbreviation. To promote uniformity among various programs,
   including translators and debuggers, use the abbreviation in both code and
   documentation. The abbreviation of the record format is always six
   letters.

   The Boxes

   Each format is drawn with boxes of two sizes. A narrow box represents a
   single byte. A plain wide box represents two bytes. The wide boxes with
   three slashes in the top and bottom represent a variable number of bytes,
   one or more, depending upon the content. The wide boxes with four vertical
   bars in the top and bottom represent four-byte fields.

   RECTYP

   The first byte in each record contains a value between 0 and 255,
   indicating the record type.

   Record Length

   The second field in each record contains the number of bytes in the
   record, exclusive of the first two fields, where a field is a 16-bit
   numberÄÄa low byte followed by a high byte.

   Name

   Any field that indicates a name has the following internal structure: the
   first byte contains a number between 0 and 127, inclusive, indicating the
   number of remaining bytes in the field. The remaining bytes are
   interpreted as a byte string.

   Most translators constrain the character set to a subset of the ASCII
   character set.

   Number

   A four-byte number field represents a 32-bit unsigned integer, where the
   first eight bits (least-significant) are stored in the first byte (lowest
   address), the next eight bits are stored in the second byte, and so on.

   Repeated or Conditional Fields

   Some portions of a record format contain a field or series of fields that
   may be repeated one or more times. Such portions are indicated by the
   "repeated" or "rpt" brackets below the boxes.

   Similarly, some portions of a record format are present only if some given
   condition is true; these fields are indicated by similar "conditional" or
   "cond" brackets below the boxes.

   CHKSUM

   The last field in each record is a check sum, which contains the two's
   complement of the sum (modulo 256) of all other bytes in the record.
   Therefore, the sum (modulo 256) of all bytes in the record is zero.

   Bit Fields

   Sometimes descriptions of the contents of fields are at the bit level.
   Boxes with vertical lines drawn through them represent bytes or words; the
   vertical lines indicate bit boundaries. Thus, the following byte
   representation has three bit fields of three, one, and four bits,
   respectively.

   ŚÄÄÄÄÄÄÄÄÄÄÄĀÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³           ³   ³               ³
   ³           ³   ³               ³
   ³           ³   ³               ³
   ĄÄÄÄÄÄÄÄÄÄÄÄĮÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ
         3       1         4

 7.5.2  T-Module Header Record (THEADR)

   ŚÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄÄ///ÄÄÄÄĀÄÄÄÄÄæ
   ³     ³          ³            ³     ³
   ³ REC ³  Record  ³    T-      ³ CHK ³
   ³ TYP ³  Length  ³    Module  ³ SUM ³
   ³ 80H ³          ³    Name    ³     ³
   ³     ³          ³            ³     ³
   ĄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄĮÄÄÄÄ///ÄÄÄÄÄĮÄÄÄÄÄŁ

   T-Module Name

   The T-Module Name field contains the name for the T-module.

 7.5.3  L-Module Header Record (LHEADR)

   ŚÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄÄ///ÄÄÄÄĀÄÄÄÄÄæ
   ³     ³          ³            ³     ³
   ³ REC ³  Record  ³    L-      ³ CHK ³
   ³ TYP ³  Length  ³    Module  ³ SUM ³
   ³ 82H ³          ³    Name    ³     ³
   ³     ³          ³            ³     ³
   ĄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄĮÄÄÄÄ///ÄÄÄÄÄĮÄÄÄÄÄŁ

   L-Module Name

   The L-Module Name field contains the name for the L-module.

   Every module output from a translator must have a T-module or L-module
   header record. The linker requires a THEADR or LHEADR record to come first
   in the module and ignores any others. The LHEADR record is identical to
   the THEADR record, except it has a record type of 82H.

 7.5.4  List of Names Record (LNAMES)

   ŚÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄÄ///ÄÄÄÄĀÄÄÄÄÄæ
   ³     ³          ³            ³     ³
   ³ REC ³  Record  ³    Name    ³ CHK ³
   ³ TYP ³  Length  ³            ³ SUM ³
   ³ 96H ³          ³            ³     ³
   ³     ³          ³            ³     ³
   ĄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄ///ÄÄÄÄÄÅÄÄÄÄÄŁ
                    ³            ³
                    ĄÄÄÄÄrptÄÄÄÄÄŁ

   The LNAMES record contains a list of names that the following SEGDEF and
   GRPDEF records may use as the names of segments, classes, and/or groups.

   The order of LNAMES records in a module and the order of names within each
   LNAMES record imply a mapping of these names to numbers: 1, 2, 3, etc.
   These numbers are used as "Name Indices" in the Segment Name Index, Class
   Name Index, and Group Name Index fields of the SEGDEF and GRPDEF records.

   Name

   This repeatable field provides a name, which may have zero length.

 7.5.5  Segment Definition Record (SEGDEF)

   ŚÄÄÄĀÄÄÄÄÄÄÄÄĀÄÄÄ///ÄÄÄĀÄÄÄÄÄÄÄÄÄĀÄÄÄ///ÄÄÄĀÄ///ÄĀÄ///ÄĀÄÄÄæ
   ³   ³        ³         ³         ³         ³     ³     ³   ³
   ³REC³ Record ³ Segment ³ Segment ³ Segment ³Class³Over ³CHK³
   ³TYP³ Length ³   ATTR  ³ Length  ³   Name  ³Name ³Lay  ³SUM³
   ³98H³        ³         ³         ³  Index  ³Index³Name ³   ³
   ³   ³        ³         ³         ³         ³     ³Index³   ³
   ĄÄÄÄĮÄÄÄÄÄÄÄÄĮÄÄÄ///ÄÄÄĮÄÄÄÄÄÄÄÄÄĮÄÄÄ///ÄÄÄĮÄ///ÄĮÄ///ÄĮÄÄÄŁ

   Segment index values 1 through 32,767, which are used in other record
   types to refer to specific LSEGs, are defined implicitly by the sequence
   in which SEGDEF records appear in the object file.

   Segment ATTR

   The Segment ATTR field provides information on various attributes of a
   segment, and has the following format:

   ŚÄÄÄÄÄĀÄÄÄÄÄÄÄÄĀÄÄÄÄÄÄÄæ
   ³     ³        ³       ³
   ³ ACB ³ Frame  ³  Off- ³
   ³  P  ³ Number ³  Set  ³
   ³     ³        ³       ³
   ³     ³        ³       ³
   ĄÄÄÄÄÄÅÄÄÄÄÄÄÄÄĮÄÄÄÄÄÄÄ“
         ³                ³
         ĄÄÄÄconditionalÄÄŁ

   The ACBP byte contains four numbersÄÄthe A, C, B, and P attribute
   specifications. This byte has the following format:

   ŚÄÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄĀÄÄÄĀÄÄÄæ
   ³           ³           ³   ³   ³
   ³     A     ³     C     ³ B ³ P ³
   ³           ³           ³   ³   ³
   ĄÄÄÄÄÄÄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄĮÄÄÄĮÄÄÄŁ

   A (Alignment) is a 3-bit subfield that specifies the alignment attribute
   of the LSEG. The semantics are defined as follows:

   Attribute      Explanation
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   A=0            SEGDEF describes an absolute LSEG.
   A=1            SEGDEF describes a relocatable, byte-aligned LSEG.
   A=2            SEGDEF describes a relocatable, word-aligned LSEG.
   A=3            SEGDEF describes a relocatable, paragraph-aligned LSEG.
   A=4            SEGDEF describes a relocatable, page(256-byte)-aligned
                  LSEG.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   If A=0, the Frame Number and Offset fields are present. With the Microsoft
   linker, you may use absolute segments for addressing only; for example, to
   define the starting address of a ROM and to define symbolic names for
   addresses within the ROM. The linker ignores any data that belongs to an
   absolute LSEG and issues a warning if absolute segments are defined for a
   program that runs in protected mode. C (Combination) is a 3-bit subfield
   that specifies the combination attribute of the LSEG. Absolute segments
   (A=0) must have combination zero (C=0). For relocatable segments, the C
   field encodes a number (0,1,2,3,4,5,6, or 7) that indicates how the
   segment can be combined. One way to interpret this attribute is to
   consider how two LSEGs are combined.

   For example, suppose that X and Y are LSEGs, and that Z is the LSEG
   resulting from the combination of X and Y. Let LX and LY be the lengths of
   X and Y, and let MXY denote the maximum of LX, LY. Now, to accommodate the
   alignment attribute of Y, let G be the length of any gap required between
   the X and Y components of Z. Then, let LZ denote the length of the
   (combined) LSEG, Z; let dx (0(<=dx<LX) be the offset in X of a byte and,
   similarly, let dy be the offset (of a byte) in Y.

   The following table gives the length LZ of the combined LSEG, Z, and the
   offsets dx' and dy' in Z for the bytes corresponding to dx in X and to dy
   in Y.

   Table 7.2
   Combination Attribute Example
   C              LZ             dx'           dy'
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   2              LX+LY+G        dx            dy+LX+G        "Public"
   5              LX+LY+G        dx            dy+LX+G        "Stack"
   6              MXY            dx            dy             "Common"
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Table 7.2 has no lines for C=0, 1, 3, 4, or 7. C=0 indicates that the
   relocatable LSEG may not be combined. C=1 and C=3 are undefined. C=4 and
   C=7 are treated the same as C=2.

   B (Big) is a 1-bit subfield that, if set to 1, indicates that the segment
   length is exactly 64K (65,536 bytes). In this case, the Segment Length
   field must contain zero.

   The P field must always be zero.

   The Frame Number and Offset fields (present only for absolute segments,
   A=0) specify the placement in MAS of the absolute segment. Offset is in
   the range between 0 and 15, inclusive. If you want an offset value larger
   than 15, you should adjust the frame number.

   Segment Length

   The Segment Length field gives a segment's length in bytes. This length
   may be zero. If it is, the linker does not delete the segment from the
   module. The Segment Length field is only large enough to hold numbers from
   0 to 64K-1, inclusive. To give the segment a length of 64K, you must use
   the B attribute bit in the ACBP field (see Segment ATTR in this section).

   Segment Name Index

   The segment name is a name that a programmer or translator assigns to the
   segment; for example, CODE, DATA, MODULENAME_CODE, TAXDATA, or STACK. The
   Segment Name Index field provides the segment name by indexing into the
   list of names provided by the LNAMES record.

   Class Name Index

   The class name is a name that a programmer or translator assigns to a
   segment. If none is assigned, the name is null and has a length of zero.
   The purpose of a class name is to let the programmer define a "handle" to
   order the LSEGs in MAS; for example, RED, WHITE, BLUE; or ROM, FASTRAM,
   DISPLAYRAM. The Class Name Index field provides the class name by indexing
   into the list of names provided by the LNAMES record.

   Overlay Name Index

   The overlay name is a name that the translator and/or the linker, at the
   programmer's request, applies to a segment. The overlay name, like the
   class name, may be null. The Overlay Name Index field provides the overlay
   name by indexing into the list of names provided by the LNAMES record.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     Microsoft language linkers (versions 3.00 and later) ignore the Overlay
     Name Index field, but the standard MS-DOS linker supports it.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

 7.5.6  Group Definition Record (GRPDEF)

   ŚÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄÄ///ÄÄÄÄĀÄÄÄÄ///ÄÄÄÄÄĀÄÄÄÄÄæ
   ³     ³          ³            ³            ³     ³
   ³ REC ³  Record  ³    Group   ³   Group    ³ CHK ³
   ³ TYP ³  Length  ³    Name    ³  Component ³ SUM ³
   ³ 9AH ³          ³    Index   ³ Descriptor ³     ³
   ³     ³          ³            ³            ³     ³
   ĄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄĮÄÄ///ÄÄÄÄÄÄÄ“ÄÄ///ÄÄÄÄÄÄÄÅÄÄÄÄÄŁ
                                 ³            ³
                                 ĄÄÄrepeatedÄÄŁ

   Group Name Index

   The linker may reference a collection of LSEGs with the group name. Most
   importantly, when the LSEGs are eventually fixed in MAS, a frame must
   exist that "covers" every LSEG of the group.

   The Group Name Index field provides the group name by indexing into the
   list of names provided by the LNAMES record.

   Group Component Descriptor

   This repeatable field has the following format:

   ŚÄÄÄÄÄĀÄÄÄÄ///ÄÄÄÄæ
   ³     ³           ³
   ³ FFH ³  Segment  ³
   ³     ³   Index   ³
   ³     ³           ³
   ³     ³           ³
   ĄÄÄÄÄÄĮÄÄÄÄ///ÄÄÄÄŁ

   The first byte of the Group Component Descriptor field contains 0FFH; the
   descriptor contains one field, which is a segment index that selects the
   LSEG described by a preceding SEGDEF record.

 7.5.7  Public Names Definition Record (PUBDEF)

   ŚÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄ///ÄÄĀÄÄÄ///ÄÄÄĀÄÄÄÄÄÄÄĀÄÄ///ÄÄĀÄÄÄÄÄæ
   ³    ³          ³         ³         ³       ³       ³     ³
   ³ REC³  Record  ³  Public ³ Public  ³Public ³ Type  ³ CHK ³
   ³ TYP³  Length  ³   Base  ³  Name   ³Offset ³ Index ³ SUM ³
   ³ 90H³          ³         ³         ³       ³       ³     ³
   ³    ³          ³         ³         ³       ³       ³     ³
   ĄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄĮÄÄÄÄ///ÄÄÅÄÄ///ÄÄÄÄĮÄÄÄÄÄÄÄĮÄ///ÄÄÄÅÄÄÄÄÄŁ
                             ³                         ³
                             ĄÄÄÄÄÄÄÄÄÄrepeatedÄÄÄÄÄÄÄÄŁ

   The PUBDEF record provides a list of one or more public names. For each
   name, three kinds of data are provided: (1) a base value for the name, (2)
   the offset value of the name, and (3) the type of entity represented by
   the name.

   Public Base

   The Public Base field has the following format:

   ŚÄÄÄÄ///ÄÄÄÄĀÄÄÄÄ///ÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄæ
   ³           ³           ³           ³
   ³   Group   ³  Segment  ³   Frame   ³
   ³   Index   ³   Index   ³   Number  ³
   ³           ³           ³           ³
   ĄÄÄÄÄ///ÄÄÄÄĮÄÄÄÄ///ÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄ“
                           ³           ³
                           ĄconditionalŁ

   The Group Index field has a format, which was given earlier, and contains
   a number between 0 and 32,767, inclusive. A nonzero value in the Group
   Index field associates a group with the public symbol and is used as
   described in case (F2c) of Section 7.3, "Conceptual Framework for
   Fixups." A zero value in the Group Index field indicates that there is no
   associated group.

   The Segment Index field has a format, which was given earlier, and
   contains a number between 0 and 32,767, inclusive.

   A nonzero value in the Segment Index field selects an LSEG. In this case,
   the location of each public symbol defined in the record is taken as a
   nonnegative displacement (given by a Public Offset field) from the first
   byte of the selected LSEG. Also, the Frame Number field must be absent.

   A zero value in the Segment Index field means that the defined symbols are
   absolute, and that the absolute addresses of the symbols are the values in
   the Public Offset field. The Group Index field is ignored. The Frame
   Number field contains a frame number only if the value of the Segment
   Index field is zero. The linker ignores this field.

   A nonzero value in the Group Index field selects some group. This group is
   taken as the "frame of reference" for references to all public symbols
   defined in this record. That is, the linker performs the following
   actions:

   ž  The linker converts any fixup of the form:

      Target: EI(P)

      Frame: Target

      (where P is a public symbol in this PUBDEF record) to a fixup of the
      form:

      Target: SI(L),d

      Frame: GI(G)

      where SI(L) and d are provided by the Segment Index and Public Offset
      fields. (The "normal" action would have the frame specifier in the new
      fixup be the same as in the old fixup: Frame:Target.)

   ž  When the linker converts the value of a public symbol, as defined by
      the Segment Index, Public Offset, and (optionally) Frame Number fields,
      to a {base,offset} pair, the base part is the base of the indicated
      group.

   A zero value in the Group Index field selects no group. The linker does
   not alter the frame specification of fixups referencing the symbol, and
   takes, as the base part of the absolute value of the public symbol, the
   canonic frame of the segment (either LSEG or PSEG) determined by the
   Segment Index field.

   Public Name

   The Public Name field gives the name of the object whose location in MAS
   is made available to other modules by the linker. The name must contain
   one or more characters.

   Public Offset

   The Public Offset field is a 16-bit value. It is either the offset of the
   public symbol with respect to an LSEG (if the segment index is greater
   than zero), or the offset of the public symbol with respect to the
   specified frame (if the segment index is equal to zero).

   Type Index

   The Type Index field identifies a single preceding TYPDEF (Type Definition
   Record), which contains a descriptor for the type of entity represented by
   the public symbol. The linker ignores this field.

 7.5.8  Communal Names Definition Record (COMDEF)

   ŚÄÄÄÄÄĀÄÄÄÄÄĀÄÄÄÄ///ÄÄÄÄĀÄÄÄÄ///ÄÄÄÄĀÄÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄÄæ
   ³     ³     ³           ³           ³      ³          ³     ³
   ³ REC ³ REC ³ Communal  ³   Type    ³ Data ³ Communal ³ CHK ³
   ³ TYP ³ LEN ³   Name    ³   Index   ³ Seg  ³ Length   ³ SUM ³
   ³ B0H ³     ³           ³           ³ Type ³          ³     ³
   ³     ³     ³           ³           ³      ³          ³     ³
   ĄÄÄÄÄÄĮÄÄÄÄÄÅÄÄÄÄ///ÄÄÄÄĮÄÄÄÄ///ÄÄÄÄĮÄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄĮ
               ³                                         ³
               ĄÄÄÄÄÄÄÄrepeatedÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   The COMDEF record provides a list of one or more Communal Names, which
   define communal variables. A communal variable is an uninitialized public
   variable whose final size and location are not fixed during compiling.

   Communal variables are similar to FORTRAN common blocks in that if you are
   linking object modules that each declare a communal variable, then the
   size of that variable is the largest of the declared variables. In the C
   language, all uninitialized public variables are communal. The following
   example shows three different declarations of the same C communal
   variable:

   char    foo[4];          /* In file a.c */
   char    foo[1];          /* In file b.c */
   char    foo[1024];       /* In file c.c */

   If the objects produced from a.c, b.c, and c.c are linked together, the
   linker allocates 1024 bytes for the character array "foo."

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     This record requires that a COMENT record from the Microsoft Extensions
     class appear before it in the object module.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Communal Name

   The Communal Name field gives the communal variable name and must contain
   one or more characters.

   Communal names are treated as external names when an external name is
   requested elsewhere in the module. Communal names are ordered together
   with external names for the purpose of referring to an external name by
   its index. (See the description of the EXTDEF record later in this
   section for more details on external names.)

   Type Index

   The Type Index field is ignored by the Microsoft linker.

   Data Segment Type

   The Data Segment Type field is a single byte that describes the data
   segment in which the communal variable resides. It can contain the
   following values:

       62H (NEAR) = the communal variable is in the default data segment.
       61H (FAR) = the communal variable is not in the default data segment.


   Communal Length

   The Communal Length field describes the length of the communal variable
   according to its data segment type.

   If its value is NEAR (62H), the field represents the length in bytes.

   If its value is FAR (61H), the field represents:

   ŚÄÄÄÄÄ//ÄÄÄÄĀÄÄÄÄÄ///ÄÄÄÄÄÄæ
   ³ Number of ³ Element size ³
   ³ elements  ³ in bytes     ³
   ĄÄÄÄÄ///ÄÄÄÄĮÄÄÄÄÄ///ÄÄÄÄÄÄŁ


   The format of all the length fields is as follows:

   ŚÄÄÄÄÄæ
   ³     ³
   ³  0  ³
   ³ to  ³
   ³ 127 ³
   ³     ³
   ĄÄÄÄÄÄŁ

   ŚÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄæ
   ³     ³           ³
   ³     ³     0     ³
   ³ 129 ³    to     ³
   ³(81H)³   64K-1   ³
   ³     ³           ³
   ĄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄŁ

   ŚÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³     ³                 ³
   ³     ³        0        ³
   ³ 132 ³       to        ³
   ³(84H)³      16M-1      ³
   ³     ³                 ³
   ĄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   ŚÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³     ³                 ³
   ³     ³     -2G-1       ³
   ³ 136 ³       to        ³
   ³(88H)³      2G-1       ³
   ³     ³                 ³
   ĄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   The first format (single byte), containing a value between 0 and 127,
   represents the number given.

   The second format, with a leading byte containing 129, represents the
   number contained in the following two bytes.

   The third format, with a leading byte containing 132, represents the
   number contained in the following three bytes.

   The fourth format, with a leading byte containing 136, represents the
   number contained in the following four bytes with its sign extended if
   necessary.

   Link-Time Semantics

   A PUBDEF matching a communal variable definition overrides the communal
   variable definition. Two communal variable definitions match if the names
   in their definitions match. If two matching definitions disagree on
   whether a communal variable is NEAR or FAR, the linker assumes the
   variable is NEAR.

   If the variable is NEAR, then its size is the largest of the sizes
   specified for it. If the variable is FAR, the linker issues a warning if
   the array element sizes conflict. If these sizes don't conflict, the
   variable's size is the element size multiplied by the largest number of
   elements specified. In addition, the sum of the sizes of all NEAR
   variables must not exceed 64 kilobytes, and the sum of the sizes of all
   FAR variables must not exceed the size of the machine's addressable memory
   space.

   HUGE Communal Variables:

   A FAR communal variable that is larger than 64 kilobytes (a HUGE communal
   variable) resides in segments that are contiguous (on an 8086) or that
   have consecutive selectors (on an 80286). No other data items reside in
   the segments occupied by a HUGE communal variable.

   If the linker finds matching HUGE and NEAR communal variable definitions,
   it issues a warning message, since it is impossible for a NEAR variable to
   be larger than 64 kilobytes.

 7.5.9  Local Symbols Record (LOCSYM)

   ŚÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄ///ÄÄĀÄÄÄ///ÄÄÄĀÄÄÄÄÄÄÄĀÄÄ///ÄÄĀÄÄÄÄÄæ
   ³    ³          ³         ³         ³       ³       ³     ³
   ³ REC³  Record  ³  Local  ³ Local   ³ Local ³ Type  ³ CHK ³
   ³ TYP³  Length  ³   Base  ³  Name   ³Offset ³ Index ³ SUM ³
   ³ 92H³          ³         ³         ³       ³       ³     ³
   ³    ³          ³         ³         ³       ³       ³     ³
   ĄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄĮÄÄÄÄ///ÄÄÅÄÄ///ÄÄÄÄĮÄÄÄÄÄÄÄĮÄ///ÄÄÄÅÄÄÄÄÄŁ
                             ³                         ³
                             ĄÄÄÄÄÄÄÄÄÄrepeatedÄÄÄÄÄÄÄÄŁ

   The LOCSYM record provides information for the definition of a local
   symbol, one that is visible only within the module in which it is defined.

   The form and meaning of each of the fields is identical to those in the
   PUBDEF record.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     The LOCSYM record requires that a COMENT record from the Microsoft
     Extensions class appear before it in the object module. Also, it is only
     recognized by Microsoft language linkers later than version 3.07.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

 7.5.10  External Names Definition Record (EXTDEF)

   ŚÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄ///ÄÄÄÄĀÄÄÄÄ///ÄÄÄÄĀÄÄÄÄÄæ
   ³     ³           ³           ³           ³     ³
   ³ REC ³  Record   ³ External  ³   Type    ³ CHK ³
   ³ TYP ³  Length   ³   Name    ³   Index   ³ SUM ³
   ³ 8CH ³           ³           ³           ³     ³
   ³     ³           ³           ³           ³     ³
   ĄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄ///ÄÄÄÄĮÄÄÄÄ///ÄÄÄÄÅÄÄÄÄÄŁ
                     ³                       ³
                     ĄÄÄÄÄÄÄÄrepeatedÄÄÄÄÄÄÄÄŁ

   The EXTDEF record provides a list of external names and, for each name,
   the type of object it represents. The linker assigns to each external name
   the value provided by an identical public name or local name (if such a
   name is found).

   External Name

   The External Name field provides the external object name, which must have
   a nonzero length.

   Including a name in an EXTDEF record is an implicit request to link the
   object file to a module containing the same name declared as a public
   symbol, unless the name is defined as a local symbol within the same
   module as the EXTDEF. This request determines whether or not the external
   name is referenced within some FIXUPP record in the module.

   The order of EXTDEF records in a module and the order of external names
   within each EXTDEF record, together with COMDEF records and communal
   names, imply a mapping on the set of all external names requested by the
   module; for example: 1, 2, 3, etc. So to refer to a particular external
   name, the linker uses these numbers as "external indices" in the Target
   Datum and/or Frame Datum fields of FIXUPP records.

   External indices may not reference forward. For example, an EXTDEF
   defining the kth object must precede any record referring to that object
   with index k.

   Type Index

   The Type Index field is ignored by the Microsoft linker, except for linker
   versions earlier than 3.05, and for object modules lacking the COMENT
   record from the Microsoft Extensions class. For that case, refer to
   Section 7.6, "Microsoft Type Representations for Communal Variables."

 7.5.11  Line Numbers Record (LINNUM)

   ŚÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄÄ///ÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄÄæ
   ³     ³          ³           ³           ³           ³     ³
   ³ REC ³  Record  ³   Line    ³   Line    ³   Line    ³ CHK ³
   ³ TYP ³  Length  ³  Number   ³  Number   ³  Number   ³ SUM ³
   ³ 94H ³          ³   Base    ³           ³  Offset   ³     ³
   ³     ³          ³           ³           ³           ³     ³
   ĄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄĮÄÄÄÄ///ÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄŁ
                                ³                       ³
                                ĄÄÄÄÄÄÄÄÄrepeatedÄÄÄÄÄÄÄŁ

   The LINNUM record allows a translator to relate a line number in source
   code to the corresponding line in translated code.

   Line Number Base

   The Line Number Base field has the following format:

   ŚÄÄÄÄ///ÄÄÄÄĀÄÄÄÄ///ÄÄÄÄæ
   ³           ³           ³
   ³   Group   ³  Segment  ³
   ³   Index   ³   Index   ³
   ³           ³           ³
   ĄÄÄÄÄ///ÄÄÄÄĮÄÄÄÄ///ÄÄÄÄŁ

   The Group Index field is ignored by the Microsoft linker.

   The Segment Index field determines the location of the first byte of code
   corresponding to some source line number.

   Line Number

   The Line Number field provides a binary line number between 0 and 32,767,
   inclusive. If the high-order bit is not zero, the number is considered
   undefined.

   Line Number Offset

   The Line Number Offset field is a 16-bit value, which is the offset of the
   line number with respect to an LSEG (if the segment index is greater than
   zero).

 7.5.12  Logical Enumerated Data Record (LEDATA)

   ŚÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄ///ÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄÄĀÄÄÄÄÄæ
   ³     ³           ³           ³           ³     ³     ³
   ³ REC ³  Record   ³  Segment  ³ Enumerated³     ³ CHK ³
   ³ TYP ³  Length   ³   Index   ³   Data    ³ DAT ³ SUM ³
   ³ A0H ³           ³           ³  offset   ³     ³     ³
   ³     ³           ³           ³           ³     ³     ³
   ĄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄĮÄÄÄÄ///ÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄŁ
                                             ³     ³
                                             ĄÄrptÄŁ

   The LEDATA record provides contiguous data from which the linker may
   construct a portion of an 8086 memory image.

   Segment Index

   The Segment Index field, which must be nonzero, specifies an index
   relative to the SEGDEF records that precede the LEDATA record.

   Enumerated Data Offset

   The Enumerated Data Offset field specifies an offset that is relative to
   the base of the LSEG specified by the segment index. The field also
   defines the relative location of the first byte of the DAT field.
   Successive data bytes in the DAT field occupy successively higher
   locations of memory.

   DAT

   The DAT field provides up to 1024 consecutive bytes of relocatable or
   absolute data.

 7.5.13  Logical Iterated Data Record (LIDATA)

   ŚÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄ///ÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄ///ÄÄÄÄĀÄÄÄÄÄæ
   ³     ³          ³           ³           ³           ³     ³
   ³ REC ³  Record  ³  Segment  ³  Iterated ³  Iterated ³ CHK ³
   ³ TYP ³  Length  ³   Index   ³    Data   ³   Data    ³ SUM ³
   ³ A2H ³          ³           ³   Offset  ³   Block   ³     ³
   ³     ³          ³           ³           ³           ³     ³
   ĄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄĮÄÄÄÄ///ÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄ///ÄÄÄÄÅÄÄÄÄÄŁ
                                            ³           ³
                                            ĄÄrepeatedÄÄŁ

   The LIDATA record provides contiguous data from which the linker may
   construct a portion of an 8086 memory image.

   Segment Index

   The Segment Index field, which must be nonzero, specifies an index that is
   relative to the SEGDEF records that precede the LIDATA record.

   Iterated Data Offset

   The Iterated Data Offset field specifies an offset that is relative to the
   base of the LSEG specified by the segment index. It also defines the
   relative location of the first byte in the iterated data block. Successive
   data bytes in the iterated data block occupy successively higher locations
   of memory.

   Iterated Data Block

   This repeated field is a structure specifying the repeated data bytes. It
   has the following format:

   ŚÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄ///ÄÄÄÄæ
   ³          ³            ³           ³
   ³  Repeat  ³   Block    ³           ³
   ³   Count  ³   Count    ³  Content  ³
   ³          ³            ³           ³
   ³          ³            ³           ³
   ĄÄÄÄÄÄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄÄĮÄÄÄÄ///ÄÄÄÄŁ

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     The linker cannot handle LIDATA records whose iterated data blocks are
     larger than 512 bytes.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   Repeat Count:

   The Repeat Count field specifies the number of times to repeat the Content
   portion of this iterated data block. The value of the Repeat Count field
   must be nonzero.

   Block Count:

   The Block Count field specifies the number of iterated data blocks in the
   Content portion of this iterated data block. If the Block Count field has
   a value of zero, the Content portion of the iterated data block is
   interpreted as data bytes. If the field is nonzero, the Content portion is
   interpreted as that number of iterated data blocks.

   Content:

   The Content field may be interpreted in one of two ways, depending on the
   value of the previous Block Count field.

   If the Block Count field is zero, this field is a 1-byte count followed by
   the indicated number of data bytes. But if the Block Count field is
   nonzero, the Content field is interpreted as the first byte of another
   iterated data block.

 7.5.14  Fixup Record (FIXUPP)

   ŚÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄ///ÄÄÄÄĀÄÄÄÄÄæ
   ³     ³           ³           ³     ³
   ³ REC ³  Record   ³  Thread   ³ CHK ³
   ³ TYP ³  Length   ³    or     ³ SUM ³
   ³ 9CH ³           ³   Fixup   ³     ³
   ³     ³           ³           ³     ³
   ĄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄ///ÄÄÄÄÅÄÄÄÄÄŁ
                     ³           ³
                     ĄÄÄÄÄrptÄÄÄÄŁ

   The FIXUPP record specifies zero or more fixups. Each fixup requests a
   modification (fixup) to a location within the previous data record. A data
   record may be followed by more than one FIXUPP record that refers to it.
   Each fixup is specified by a Fixup field that specifies four kinds of
   data: a location, a mode, a target, and a frame. The frame and target may
   be specified completely within the Fixup field, or by reference to a
   preceding Thread field.

   A Thread field specifies a default target or frame that subsequently may
   be referred to. Eight threads are providedÄÄfour for frame specification
   and four for target specification. Once a thread has specified a target or
   frame, any Fixup fields that follow (in the same or following FIXUPP
   records) may refer to that target or frame until another Thread field with
   the same type (target or frame) and thread number (0-3) appears (in the
   same or in another FIXUPP record).

   Thread

   The Thread field has the following format:

   ŚÄÄÄÄÄĀÄÄÄÄ///ÄÄÄÄæ
   ³     ³           ³
   ³ TRD ³   Index   ³
   ³ DAT ³           ³
   ³     ³           ³
   ĄÄÄÄÄÄÅÄÄÄÄ///ÄÄÄÄ³
         ³           ³
         ĄcondiionalÄŁ

   The TRD DAT (Thread Data) field is a byte with the following internal
   structure:

   ŚÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄÄÄÄæ
   ³   ³   ³   ³           ³       ³
   ³ 0 ³ D ³ 0 ³  Method   ³ THRED ³
   ³   ³   ³   ³           ³       ³
   ĄÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄĮÄÄÄÄÄÄÄŁ

   The D field is one bit and defines the type of thread being used. If D=0,
   this bit defines a target thread, and if D=1, it defines a frame thread.

   Method is a 3-bit field containing a number between 0 and 3 (if D=0) or a
   number between 0 and 6 (if D=1).

   If D=0, then Method = (0, 1, 2, 4, 5, 6)mod 4, where 0, 1, 2, 4, 5, 6
   indicate methods T0, T1, T2, T4, T5, and T6 of specifying a target. Thus,
   Method indicates the kind of index or frame number required to specify the
   target, without indicating whether the target is specified by a primary or
   secondary method.

   If D=1, then Method = 0, 1, 2, 4, 5, corresponding to methods F0, F1, F2,
   F4, F5 of specifying a frame. Here, Method indicates the kind (if any) of
   index required to specify the frame.

   The THRED field contains a number between 0 and 3, inclusive, and
   associates a thread number to the frame or target defined by the Thread
   field.

   The Index field contains a segment index, group index, or external index
   depending on the specification in the Method field. If Method specifies F4
   or F5, this field will not be present.

   Fixup

   The Fixup field has the following format:

   ŚÄÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄÄĀÄÄÄÄ///ÄÄÄÄĀÄÄÄÄ///ÄÄÄÄĀÄÄÄÄ///ÄÄÄÄæ
   ³           ³     ³           ³           ³           ³
   ³   LOCAT   ³ FIX ³   Frame   ³  Target   ³  Target   ³
   ³           ³ DAT ³   Datum   ³   Datum   ³   Dis-    ³
   ³           ³     ³           ³           ³ Placement ³
   ³           ³     ³           ³           ³           ³
   ĄÄÄÄÄÄÄÄÄÄÄÄĮÄÄÄÄÄÅÄÄÄÄ///ÄÄÄÄÅÄÄÄÄ///ÄÄÄÄÅÄÄÄÄ///ÄÄÄÄ³
                     ³           ³           ³           ³
                     ĄÄÄÄÄÄÄÄÄÄÄÄÄconditionalÄÄÄÄÄÄÄÄÄÄÄÄŁ

   The LOCAT field is a byte pair with the following format:

   ŚÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³   ³   ³   ³           ³                                       ³
   ³ 1 ³ M ³ 0 ³    LOC    ³  D a t a   R e c o r d   O f f s e t  ³
   ³   ³   ³   ³           ³                                       ³
   ĆÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄĮÄÄÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ“
   ³                               ³                               ³
   ĄÄÄÄÄÄÄÄÄÄÄÄÄlo byteÄÄÄÄÄÄÄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄÄhi byteÄÄÄÄÄÄÄÄÄÄÄÄŁ

   M is a 1-bit field that specifies the mode of the fixups: self-relative
   (if M=0) or segment-relative (if M=1).

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     Self-relative fixups may not be applied to LIDATA records.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   LOC is a 3-bit field indicating that the byte(s) in the preceding data
   record to be fixed up are a lobyte (if LOC=0), an offset (if LOC=1), a
   base (if LOC=2), a pointer (if LOC=3), a hibyte (if LOC=4), or a
   "loader-resolved" offset (if LOC=5). Any other values in LOC are invalid.

   The Data Record Offset field contains a number between 0 and 1023,
   inclusive, that gives the relative position of the lowest order byte of
   location (the actual bytes being fixed up) within the preceding data
   record. The Data Record Offset value is relative to the first byte in the
   data fields in the data records.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     If the preceding data record is an LIDATA record, it is possible for the
     Data Record Offset value to designate a location within a Repeat Count
     field or a Block Count field of the Iterated Data Block field. Such a
     reference is an error. The linker's action on such a malformed record is
     undefined.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   The FIX DAT field is a byte with the following format:

   ŚÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄÄÄÄÄæ
   ³   ³           ³   ³   ³       ³
   ³ F ³   Frame   ³ T ³ P ³ TARGT ³
   ³   ³           ³   ³   ³       ³
   ĄÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄÄÄÄÄŁ

   F is a 1-bit subfield that specifies whether the frame for this fixup is
   specified by a thread (if F=1) or explicitly (if F=0).

   The Frame field contains a number that is interpreted in one of two ways,
   as indicated by the F bit. If F is zero, the Frame field contains a number
   between 0 and 5, inclusive, corresponding to methods F0,...,F5 for
   specifying a frame. If F=1, then the Frame field contains a thread number
   (0-3). It specifies the frame most recently defined by a Thread field that
   defined a frame thread with the same thread number. (Notice that the
   Thread field may appear in the same FIXUPP record, or in an earlier one.)

   T is a 1-bit field that specifies whether the target specified for this
   fixup is defined by reference to a thread (T=1), or is given explicitly in
   the Fixup field (T=0).

   P is a 1-bit field that indicates whether the Target is specified by a
   primary method (requires a target displacement, if P=0) or by a secondary
   method (requires no target displacement, if P=1). Since a target thread
   does not have a primary/secondary attribute, the P bit is the only field
   that contains the target specification attribute.

   TARGT is interpreted as a 2-bit field. When T=0, it provides a number
   between 0 and 3, inclusive, corresponding to methods T0, T1, T2 or T4, T5,
   T6, depending on the value of P (where P is interpreted as the high-order
   bit of T0, T1, T2, T4, T5, or T6). When a thread specifies the target (if
   T=1), then the TARGET field specifies a thread number (0-3).

   The Frame Datum field is the "referent" portion of a frame specification,
   and is a segment index, group index, or external index. The Frame Datum
   field is present only when the frame is not specified by a thread (if F=0)
   or explicitly by methods F4, F5, or F6.

   The Target Datum field is the "referent" portion of a target
   specification, and is a segment index, group index, or external index. The
   Target Datum field is present only when a thread does not specify the
   target (if T=0).

   The Target Displacement field is the 2-byte displacement required by
   primary methods of specifying targets. This field is present if P=0.

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     All these methods are described in Section 7.3, "Conceptual Framework
     for Fixups."
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

 7.5.15  Module End Record (MODEND)

   ŚÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄÄĀÄÄÄÄ///ÄÄÄÄĀÄÄÄÄÄæ
   ³     ³           ³     ³           ³     ³
   ³ REC ³  Record   ³ MOD ³   START   ³ CHK ³
   ³ TYP ³  Length   ³ TYP ³   ADDRS   ³ SUM ³
   ³ 8AH ³           ³     ³           ³     ³
   ³     ³           ³     ³           ³     ³
   ĄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄĮÄÄÄÄÄÅÄÄÄÄ///ÄÄÄÄÅÄÄÄÄÄŁ
                           ³           ³
                           ĄconditionalŁ

   The MODEND record serves two purposes. It denotes the end of a module and
   indicates whether or not the module that just ended specifies an entry
   point to begin execution. If it does not, the linker specifies the
   execution address.

   MOD TYP

   The MOD TYP field specifies the attributes of the module. The bit
   allocation and associated meanings are as follows:

   ŚÄÄÄÄÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄæ
   ³       ³   ³   ³   ³   ³   ³   ³
   ³ MATTR ³ 0 ³ 0 ³ 0 ³ 0 ³ 0 ³ 1 ³
   ³       ³   ³   ³   ³   ³   ³   ³
   ĄÄÄÄÄÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄŁ

   MATTR is a 2-bit field that specifies the following module attributes:

   MATTR              Module Attribute
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0                  Non-main module with no START ADDRS
   1                  Non-main module with START ADDRS
   2                  Main module with no START ADDRS
   3                  Main module with START ADDRS
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   The START ADDRS field (present only if MATTR is 1 or 3) has the following
   format:

   ŚÄÄÄÄÄĀÄÄÄÄ///ÄÄÄÄĀÄÄÄÄ///ÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄæ
   ³     ³           ³           ³           ³
   ³ END ³   Frame   ³  Target   ³  Target   ³
   ³ DAT ³   Datum   ³   Datum   ³   Dis-    ³
   ³     ³           ³           ³ Placement ³
   ³     ³           ³           ³           ³
   ĄÄÄÄÄÄÅÄÄÄÄ///ÄÄÄÄĮÄÄÄÄ///ÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄ³
         ³                                   ³
         ĄÄÄÄÄÄÄÄÄÄÄÄÄconditionalÄÄÄÄÄÄÄÄÄÄÄÄŁ

   The starting address of a module has all the attributes of any other
   logical reference found in a module. The mapping of a logical starting
   address to a physical starting address is done in the same manner as
   mapping any other logical address to a physical address, as specified in
   the discussion of fixups and the FIXUPP record. The fields of the START
   ADDRS field have the same semantics as the FIX DAT, Frame Datum, Target
   Datum, and Target Displacement fields in the FIXUPP record. Only primary
   fixup methods are allowed. Frame method F4 is not allowed.

 7.5.16  Comment Record (COMENT)

   ŚÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄĀÄÄÄÄ///ÄÄÄÄĀÄÄÄÄÄæ
   ³     ³           ³           ³           ³     ³
   ³ REC ³  Record   ³  Comment  ³           ³ CHK ³
   ³ TYP ³  Length   ³   Type    ³  Comment  ³ SUM ³
   ³ 88H ³           ³           ³           ³     ³
   ³     ³           ³           ³           ³     ³
   ĄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄĮÄÄÄÄ///ÄÄÄÄĮÄÄÄÄÄŁ

   The COMENT record allows translators to include comments in object text.

   Comment Type

   The Comment Type field indicates the type of comment that this record
   carries, allowing you to structure comments for processes that selectively
   act on comments.

   The format of the Comment Type field is as follows:

   ŚÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄĀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄæ
   ³ N ³ N ³   ³   ³   ³   ³   ³   ³          Comment     ³
   ³ P ³ L ³ 0 ³ 0 ³ 0 ³ 0 ³ 0 ³ 0 ³           Class      ³
   ĄÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄĮÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŁ

   The NP (NOPURGE) bit, if set to 1, indicates that this comment cannot be
   purged by object file utility programs that can delete Comment records.

   The NL (NOLIST) bit, if set to 1, indicates that the text in the Comment
   field should not appear in the listing file of object file utility
   programs that can list object Comment records.

   The Comment Class field is a byte defined as follows:

ÖŚÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ·
   Value              Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   0                  Language Translator Comment (obsolete)

                      If the Comment field contains one of the strings "MS
                      PASCAL" or "FORTRAN 77," then the Comment record
                      enables the dsallocation switch on the Microsoft
                      linker.
   Value              Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
                     linker.

   156(9CH)           DOS Version

                      The Comment field contains a 2-byte integer that
                      specifies the DOS level number.

   157(9DH)           Memory Model

                      Indicates the memory model of the object module. The
                      Comment field contains a single byte with the values S,
                      M, L, or H, for SMALL, MEDIUM, LARGE, or HUGE,
                      respectively. This Comment record is used only by the
                      Microsoft XENIX linker.

   158(9EH)           Force Segment Ordering

                      Causes the linker to use a special segment ordering for
                      executable files. This Comment record has the same
   Value              Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
                     executable files. This Comment record has the same
                      effect as giving the dosseg switch to Microsoft
                      language versions of the linker.

   159(9FH)           Library Specifier

   129(81H)           Library Specifier (obsolete)

                      Specifies a library to add to the Microsoft linker's
                      library search list. The Comment field contains the
                      name of the library. Notice that, unlike all other name
                      specifications, the library name is not prefixed with
                      its length but is determined by the record length. The
                      nodefaultlibrarysearch switch causes the linker to
                      ignore these Comment records. The 159(9FH) class record
                      is ignored by XENIX versions of the Microsoft linker.

   161(A1H)           Microsoft Extensions

   Value              Meaning
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

                      Indicates that the object module contains extensions to
                      the original Microsoft adaptation of the Intel
                      Relocatable Object Module Format, such as the COMDEF
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


   Comment

   The Comment field provides the commentary information.


 7.6  Microsoft Type Representations for Communal Variables

   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Note
     Object modules not containing the COMENT record from the Microsoft
     Extensions class can represent communal variable definitions only with
     the obsolete method described here. Also, Microsoft language linkers
     earlier than version 3.05 can recognize this method only. The newer
     method uses the Communal Variable Definitions (COMDEF) record.
   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   A communal variable is defined in the object text by an EXTDEF record and
   the TYPDEF record to which it refers.

   The TYPDEF record of a communal variable has the following format:

   ŚÄÄÄÄÄĀÄÄÄÄÄÄÄÄĀÄÄÄĀÄÄÄÄÄ///ÄÄÄÄĀÄÄÄÄÄæ
   ³ REC ³ Record ³   ³    Eight   ³ CHK ³
   ³ TYP ³ Length ³ 0 ³    Leaf    ³ SUM ³
   ³ 8EH ³        ³   ³ Descriptor ³     ³
   ĄÄÄÄÄÄĮÄÄÄÄÄÄÄÄĮÄÄÄĮÄÄÄÄÄ///ÄÄÄÄĮÄÄÄÄÄŁ

   The Eight Leaf Descriptor field has the following format:

   ŚÄÄÄĀÄÄÄÄ///ÄÄÄÄÄæ
   ³ E ³    Leaf    ³
   ³ N ³ Descriptor ³
   ĄÄÄÄĮÄÄÄÄ///ÄÄÄÄÄŁ

   The EN bitfield specifies whether the next eight leaves in the Leaf
   Descriptor field are EASY (if EN = 0) or NICE (if EN = l). This byte is
   always zero for TYPDEFs of communal variables. The Leaf Descriptor field
   has one of the following two formats. The format for communal variables in
   the default data segment (NEAR variables) is as follows:

   ŚÄÄÄÄÄÄĀÄÄÄÄÄĀÄÄÄÄ///ÄÄÄĀÄ///ÄÄÄÄæ
   ³ NEAR ³ VAR ³  Length  ³  VAR   ³
   ³ 62H  ³ TYP ³    In    ³ SUBTYP ³
   ³      ³     ³   Bits   ³        ³
   ĄÄÄÄÄÄÄĮÄÄÄÄÄĮÄÄÄÄ///ÄÄÄÅÄÄ///ÄÄÄ“
                           ³        ³
                           ĄÄÄÄÄÄÄÄÄŁ
                           (optional)

   The VARTYP (Variable Type) field may be either SCALAR (7BH), STRUCT (79H),
   or ARRAY (77H). The linker ignores the VAR SUBTYP field (if one exists).
   The format for communal variables not in the default data segment (FAR
   variables) is as follows:

   ŚÄÄÄÄÄĀÄÄÄÄÄĀÄÄÄÄ///ÄÄÄĀÄÄÄ///ÄÄÄæ
   ³ FAR ³ VAR ³  Number  ³ Element ³
   ³ 61H ³ TYP ³    of    ³  Type   ³
   ³     ³ 77H ³ Elements ³  Index  ³
   ĄÄÄÄÄÄĮÄÄÄÄÄĮÄÄÄÄ///ÄÄÄĮÄÄÄ///ÄÄÄŁ

   The VARTYP field must be ARRAY (77H). The Length in Bits field specifies
   the Number of Elements, and the Element Type Index is an index to a
   previously defined TYPDEF record whose format is that of a NEAR communal
   variable.

   The format for the Length in Bits or Number of Elements fields is the same
   as the format of the Communal Length field of the COMDEF record.

   Link-Time Semantics

   All EXTDEF records referencing a TYPDEF record of one of the previously
   described formats are treated as communal variables. All others are
   treated as externally defined symbols for which a matching PUBDEF record
   is expected.

   For more information, see "Link-Time Semantics" in Section 7.5.8,
   "Communal Names Definition Record (COMDEF)."



 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Chapter 8  Programming Hints

     8.1   Introduction
     8.2   Interrupts
     8.3   System Calls
     8.4   Device Management
     8.5   Memory Management
     8.6   Process Management
     8.7   File and Directory Management
           8.7.1   Locking Files
     8.8   Miscellaneous


 8.1  Introduction

   This chapter describes recommended MS-DOS 4.0 programming procedures. By
   using these programming hints, you can ensure compatibility with future
   versions of MS-DOS.

   The hints are organized in the following categories:

   ž  Interrupts

   ž  System Calls

   ž  Device Management

   ž  Memory Management

   ž  Process Management

   ž  File and Directory Management

   ž  Miscellaneous


 8.2  Interrupts

   ž  Never explicitly issue Interrupt 22H (Terminate Process Exit Address).

      Only the DOS should do this. To change the terminate address, use
      Function 35H (Get Interrupt Vector) to get the current address and
      save it, then use Function 25H (Set Interrupt Vector) to change the
      Interrupt 22H entry in the vector table to point to the new terminate
      address.

   ž  Use Interrupt 24H (Critical-Error-Handler Address) with care. The
      Interrupt 24H handler must preserve the ES register.

      An Interrupt 24H handler can issue only the system calls 01H-0CH.
      Making any other calls destroys the MS-DOS stack and prevents
      successful use of the Retry or Ignore options.

      When using the Retry or Ignore options, you must preserve the SS, SP,
      DS, BX, CX, and DX registers.

   ž  When an Interrupt 24H (Critical-Error-Handler Address) is received,
      always IRET back to MS-DOS with one of the standard responses.

      Programs that do not IRET from Interrupt 24H leave the system in an
      unpredictable state until a function call other than 01H-0CH is made.
      The Ignore option may leave incorrect or invalid data in internal
      system buffers.

   ž  Avoid trapping Interrupt 23H (CONTROL+C Handler Address) and Interrupt
      24H (Critical-Error-Handler Address). Don't rely on trapping errors
      via Interrupt 24H as part of a copy protection scheme.

      These methods might not be included in future releases of MS-DOS.

   ž  A user program must never issue Interrupt 23H (CONTROL+C Handler
      Address).

      Only MS-DOS may issue Interrupt 23H.

   ž  Save any registers that your program uses before issuing Interrupt
      25H (Absolute Disk Read) or Interrupt 26H (Absolute Disk Write).

      These interrupts destroy all registers except for the segment
      registers.

      Avoid writing or reading an interrupt vector directly to or from
      memory.

   ž  Use Functions 25H and 35H (Set Interrupt Vector and Get Interrupt
      Vector) to set and get values in the interrupt table.


 8.3  System Calls

   ž  Use new system calls.

      Avoid using system calls that have been superseded by new calls unless
      the program must maintain backward compatibility with MS-DOS versions
      before 2.0. See Section 1.9, "Old System Calls," for a list of these
      new calls.

   ž  Avoid using functions 01H-0CH and 26H (Create New PSP).

      Use the new "tools" approach for reading and writing on standard input
      and output. Use Function 4B00H or 4B03H (Load and Execute Program or
      Overlay) instead of 26H to execute a child process.

   ž  Use file-sharing calls if more than one process is in effect.

      For more information, see "File Sharing" in Section 1.5.2,
      "File-Related Function Requests."

   ž  Use networking calls where appropriate.

      Some forms of IOCtl can only be used with Microsoft Networks. For more
      information and a list of these calls, see Section 1.6, "Microsoft
      Networks."

   ž  When selecting a disk with Function 0EH (Select Disk), treat the value
      returned in AL with care.

      The value in AL specifies the maximum number of logical drives; it does
      not specify which drives are valid.


 8.4  Device Management

   ž  Use installable device drivers.

      MS-DOS provides a modular device driver structure for the BIOS,
      allowing you to configure and install device drivers at boot time.
      Block device drivers transmit a block of data at a time, while
      character device drivers transmit a byte of data at a time.

      Examples of both types of device drivers are given in Chapter 2,
      "MS-DOS Device Drivers."

   ž  Use buffered I/O.

      The device drivers can handle streams of data up to 64 kilobytes. To
      improve performance when sending a large amount of output to the
      screen, you can send it with one system call.

   ž  Programs that use direct console I/O via Function 06H and 07H (Direct
      Console I/O and Direct Console Input) and that want to read CONTROL+C
      as data should ensure that CONTROL+C checking is off.

      The program should ensure that CONTROL+C checking is off by using
      Function 33H (CONTROL+C Check).

   ž  Be compatible with international support.

      To provide support for international character sets, MS-DOS recognizes
      all possible byte values as significant characters in filenames and
      data streams. MS-DOS versions earlier than 2.0 ignored the high bit in
      the MS-DOS filename.


 8.5  Memory Management

   ž  Use memory management.

      MS-DOS keeps track of allocated memory by writing a memory control
      block at the beginning of each area of memory. Programs should use
      Functions 48H (Allocate Memory), 49H (Free Allocated Memory), and
      4AH (Set Block) to release unneeded memory.

      This allows for future compatibility. For more information, see Section
      1.3, "Memory Management."

   ž  Use only allocated memory.

      Don't directly access memory that was not provided as a result of a
      system call. Do not use fixed addressing, use only relative references.

      A program that uses memory that has not been allocated to it may
      destroy other memory control blocks or cause other applications to
      fail.


 8.6  Process Management

   ž  Use Function 4B00H or 4B03H (Load and Execute Program or Overlay,
      also known as EXEC) to load and execute programs.

      EXEC is the preferred call to use when loading programs and program
      overlays. Using the EXEC call instead of hard-coding information about
      how to load a .exe file (or always assuming that your file is a .com
      file) isolates your program from changes in .exe file formats and
      future releases of MS-DOS.

   ž  Use Function 31H (Keep Process), instead of Interrupt 27H (Terminate
      But Stay Resident).

      Function 31H allows programs that are greater than 64 kilobytes to
      terminate and stay resident.

   ž  Programs should terminate using Function 4CH (End Process).

      Programs that terminate by one of the following must ensure that the CS
      register contains the segment address of the PSP:

      ž  A long jump to offset 0 in the PSP

      ž  Issuing an Interrupt 20H with CS:0 pointing at the PSP

      ž  Issuing an Interrupt 21H with AH=0, CS:0 pointing at the PSP

      ž  A long call to location 50H in the PSP with AH=0


 8.7  File and Directory Management

   ž  Use the MS-DOS file management system.

      Using the MS-DOS file system ensures program compatibility with future
      MS-DOS versions through compatible disk formats and consistent internal
      storage.

   ž  Use file handles instead of FCBs.

      A handle is a 16-bit number that MS-DOS returns when a file is opened
      or created using Functions 3CH, 3DH, 5AH, or 5BH (Create Handle,
      Open Handle, Create Temporary File, or Create New File). The MS-DOS
      file-related function requests that use handles are listed in Table
      1.5 in Chapter 1, "System Calls."

      Although the default maximum number of open files is 20, this limit can
      be raised to 64K by Function 67H (Set Handle Count). For more
      information on this system call, see Chapter 1, "System Calls."

      You should use these calls instead of the old file-related functions
      that use FCBs (file control blocks). This is because a file operation
      can simply pass its handle rather than maintaining FCB information. If
      you must use FCBs, be sure the program closes them and does not move
      them around in memory.

   ž  Close files that have changed in length before issuing an Interrupt
      20H (Program Terminate), Function 00H (Terminate Program), Function
      4CH (End Process), or Function 0DH (Reset Disk).

      If you do not close a changed file, its length will not be recorded
      correctly in the directory.

   ž  Close files when they are no longer needed.

      Closing unneeded files increases efficiency in a networking
      environment.

   ž  If a program does use FCBs, that program should not close an FCB file
      and then continue writing to it. This practice will not work in a
      network environment and is not recommended under any circumstances.

   ž  Change disks only if all files on the disk are closed.

      If you don't close all the files, any information in internal system
      buffers may be written incorrectly to a changed disk.

 8.7.1  Locking Files

   ž  Programs should not rely on being denied access to a locked region.

      To determine the status of a region, first attempt to lock it, then
      examine its error code.

   ž  Programs should not close a file with a locked region or terminate with
      an open file that contains a locked region.

      The result of this procedure is undefined. Programs that might be
      terminated by an Interrupt 23H or Interrupt 24H (CONTROL+C Handler
      Address or Critical-Error-Handler Address) should trap these interrupts
      and unlock any locked regions before exiting.


 8.8  Miscellaneous

   ž  Avoid timing dependencies.

      Various machines use CPUs of different speeds. Also, programs that rely
      upon the speed of the clock for timing are not dependable in a
      networking environment.

   ž  Use the documented interface to the operating system. If either the
      hardware or media change, the operating system can use the features
      without modification.

      Don't use the ROM support provided by the OEM (Original Equipment
      Manufacturer).

      Don't directly address the video memory.

      Don't use undocumented function calls, interrupts, or features.

      These items may change or may not exist in future MS-DOS versions. If
      you do use these features, you will make your program highly
      non-portable.

   ž  Use the .exe format rather than the .com format.

      .Exe files are relocatable; .com files are direct memory images that
      load at a specific place and have no room for additional control
      information. .Exe files have headers that can be expanded for
      compatibility with future MS-DOS versions.

   ž  Use the environment to pass information to applications.

      The environment allows a parent process to pass information to a child
      process. The command.com file is usually the parent process to every
      application, so it can easily pass default drive and path information
      to the application.



 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Index

 Numbers

 80186 microprocessor
 80286 microprocessor
 8086 microprocessor
 8086 object language
 8086 object module format. See Object Module Formats (OMF)

 A

 Absolute Disk Read (Interrupt 25H)
 Absolute Disk Write (Interrupt 26H)
 Absolute segment, LSEG
 ACBP byte, SEG ATTR
 Address mode
 Alignment attribute
 Alignment subfield, SEG ATTR
 Allocate Memory (Function 48H)
 Application
   Frame Number, protected-mode
 Archive bit
 Array, character
 ASCII character set
 ASCIZ string
 Assign list
 Attribute
   primary
   secondary
   Target
 Attribute byte
 Attribute field
 Attribute, LSEG
   Alignment
   Combination
   SEG ATTR field, SEGDEF
 AUTOEXEC file
 Auxiliary Input (Function 03H)
 Auxiliary Output (Function 04H)

 B

 base, definition
 Big subfield, SEG ATTR
 BIN format file
 Binary line number
 BIOS Parameter ^Block (BPB)
 BIOS Parameter Block (BPB)
 Bit 8
 Bit 9
 Bitfield
 Block Count subfield, Iterated Data Block
 Block devices
   device drivers
   disk drives
   example
   installation
 Boot sector
 BPB pointer
 Buffered Keyboard Input (Function 0AH)
 BUILD BPB
 Build BPB
 Busy bit
 Byte, representation

 C

 C language
 CALL instruction
 Cancel Assign-List Entry (Function 5FH, Code 04H)
 Canonic Frame
 Canonic Frame, definition
 Carry flag
 Case-Mapping Call
 Change Current Directory (Function 3BH)
 Change Directory Entry (Function 56H)
 Character array
 Character device driver, example
 Character devices
 Character set
   definition
 Check Keyboard Status (Function 0BH)
 CHKSUM field, SAMREC
 Class Name, definition
 CLOCK device
 Close File (Function 10H)
 Close Handle (Function 3EH)
 Cluster
 Code page
   definition
 Code segment, CS
 Combination attribute
 Combination subfield, SEG ATTR
 COMDEF record
   field
     CHKSUM
     Communal Length, repeated
     Communal Name, repeated
     Data Segment Type, repeated
     Record Length
     RECTYP
     Type Index, repeated
   length fields, format
   order with respect to COMENT
   purpose
   schematic
 COMENT record
   field
     CHKSUM
     Comment
     Comment Type
     Record Length
     RECTYP
   order with respect to COMDEF
   order with respect to LOCSYM
   purpose
   schematic
   subfield of Comment Type
     Comment Class
 Command code field
 Command processor
 Command.com
 Commands, utility, NLS
 Comment class subfield, Comment Type
 Comment field, COMENT
 Comment record
 Comment Record (COMENT)
 Comment Type field, COMENT
   bit settings
   definition
   format
 Commit File (Function 68H)
 Common blocks, FORTRAN
 Communal Length field, COMDEF
 Communal Name field, COMDEF
 Communal Name, ordering with External Name
 Communal names definition record. See COMDEF record
 Communal Names Definition Record (COMDEF)
 Communal variable
   FAR
   HUGE
   NEAR
   similarity to FORTRAN common block
   uninitialized public variable
 Compatibility, ensuring
 Complete Name, definition
 Computer language
   C
   FORTRAN
 COMSPEC
 Con device
 config.sys
 config.sys file
 Content subfield, Iterated Data Block
 Control blocks
 Control information
 CONTROL+C Address (Interrupt 23H)
 CONTROL+C Check (Function 33H)
 CONTROL+C Handler Address (Interrupt 23H)
 Country code
   definition
 Country code, current
 Country-dependent information
   case conversion tables
   collating sequence, character sorting
   currency
   date
   DBCS environmental vector
   keyboard support
   time
   valid single-byte characters
 Country-dependent information, NLS
 Country.sys file
 Create Directory (Function 39H)
 Create File (Function 16H)
 Create Handle (Function 3CH)
 Create New File (Function 5BH)
 Create New PSP (Function 26H)
 Create Temporary File (Function 5AH)
 Critical Error Handler Address (Interrupt 24H)
 CS register

 D

 DAT field, LEDATA
 Data Record
 Data segment
   DS
   ES
   FAR
   NEAR
 Data Segment Type field, COMDEF
 Delete Directory Entry (Function 41H)
 Delete File (Function 13H)
 Descriptor, Group Component, GRPDEF
 Device control
 Device drivers
   block
   creating
   example
   installable
   installing
   non-resident
   preserving registers
   resident
 Device Handles
 Device header
 Device interrupt routine
 Device management, programming hints
 Device strategy routine
 Device-related function requests
 Direct Console Input (Function 07H)
 Direct Console I/O (Function 06H)
 Directory Entry
 Directory-Related Function Requests
 Directory-related function requests
 Disk allocation
 Disk Directory
 Disk formats
   IBM
   standard MS-DOS
 Disk Transfer Address (DTA)
 Dispatch table
 Display Character (Function 02H)
 Display String (Function 09H)
 Done bit
 DS register
 Duplicate File Handle (Function 45H)

 E

 Eight Leaf Descriptor field, TYPDEF
   format
   subfield
     EN
     Leaf Descriptor
 Element Type Index subfield, Leaf Descriptor
 EN subfield, Eight Leaf Descriptor
 End address
 End Process (Function 4CH)
 Enumerated Data Offset field, LEDATA
 Error bit
 Error codes
 Error Handling
 Error handling
 ES register
 EXE device drivers
 .exe files
 exe files
 EXE format file
 EXE loader
 EXTDEF record
   field
     CHKSUM
     External Name, repeated
     Record Length
     RECTYP
     Type Index, repeated
   purpose
   schematic
 Extended error codes
 Extended FCB
 Extensions class, Microsoft
 External Index
 External indices
 External Name
   mapping
   referenced in FIXUPP record
 External Name field, EXTDEF
 External names definition record. See EXTDEF record
 External Names Definition Record (EXTDEF)

 F

 FAR data segment
 FAR subfield, Leaf Descriptor
 FAR variable format, Leaf Descriptor
 FAT
 FAT ID byte
 FAT ID byte
 FBVAL, definition
 FCB
 File Allocation Table
 File and directory management, programming hints
 File attributes
 File Control Block
   definition
   extended
   fields
   format
   opened
   unopened
 File locking, programming hints
 Filename separators
 Filename terminators
 File-related function requests
 File-sharing function requests
 Find First File (Function 4EH)
 Find Next File (Function 4FH)
 FIX DAT subfield, Fixup
   internal structure
   schematic
 Fixup
   definition
   Frame
   Location
   segment-relative
   self-relative
   Target
 Fixup field, FIXUPP
   data type
     Frame
     Location
     Mode
     Target
   definition
   schematic
   subfield
     LOCAT
 Fixup mode
   segment-relative
   self-relative
 FIXUP record
 FIXUPP record
   External Name referenced in
   field
     CHKSUM
     Fixup, repeated
     Frame Datum, conditional
     Record Length
     RECTYP
     Target Datum, conditional
     Thread, repeated
   purpose
   schematic
   subfield of FIX DAT, Fixup
     F
     Frame
     P
     T
     TARGT
   subfield of Fixup
     Frame Datum, conditional
     Target Datum, conditional
     Target Displacement, conditional
   subfield of LOCAT, Fixup
     Data Record Offset
     LOC
     M (mode)
   subfield of Thread
     Index, conditional
     TRD DAT
   subfield of TRD DAT, Thread
     D
     Method
     THRED
 FIXUPP Record (FIXUPP)
 Flush
 Flush Buffer, Read Keyboard (Function 0CH)
 Force Duplicate File Handle (Function 46H)
 Format
 FORTRAN, common blocks
 FORTRAN language
 FOVAL, definition
 Frame
   definition
   Frame Number
   nomenclature
   specifying
   specifying, FIXUPP
 Frame Datum field, FIXUPP
 Frame Datum subfield, Fixup
   External Index
   Group Index
   Segment Index
 Frame Datum subfield, START ADDRS
 Frame Number
 Frame Number, conditional
 Frame Number, definition
 Frame Number subfield, Public Base
 Frame Number subfield, SEG ATTR
 Frames
   Thread Number, FIXUPP
 Free Allocated Memory (Function 49H)
 Function Requests
   alphabetic order
   calling
   definition
   device-related
   Directory-related
   directory-related
   file-related
   file-sharing
   Function 00H
   Function 01H
   Function 02H
   Function 03H
   Function 04H
   Function 05H
   Function 06H
   Function 07H
   Function 08H
   Function 09H
   Function 0AH
   Function 0BH
   Function 0CH
   Function 0DH
   Function 0EH
   Function 0FH
   Function 10H
   Function 11H
   Function 12H
   Function 13H
   Function 14H
   Function 15H
   Function 16H
   Function 17H
   Function 19H
   Function 1AH
   Function 1BH
   Function 1CH
   Function 21H
   Function 22H
   Function 23H
   Function 24H
   Function 25H
   Function 26H
   Function 27H
   Function 28H
   Function 29H
   Function 2AH
   Function 2BH
   Function 2CH
   Function 2DH
   Function 2EH
   Function 2FH
   Function 30H
   Function 31H
   Function 33H
   Function 35H
   Function 36H
   Function 38H
   Function 39H
   Function 3AH
   Function 3BH
   Function 3CH
   Function 3DH
   Function 3EH
   Function 3FH
   Function 40H
   Function 41H
   Function 42H
   Function 43H
   Function 44H, Code 08H
   Function 44H, Code 09H
   Function 44H, Code 0AH
   Function 44H, Code 0BH
   Function 44H, Code 0CH
   Function 44H, Code 0DH
   Function 44H, Codes 00H and 01H
   Function 44H, Codes 02H and 03H
   Function 44H, Codes 04H and 05H
   Function 44H, Codes 06H and 07H
   Function 44H, Codes 0EH and 0FH
   Function 45H
   Function 47H
   Function 48H
   Function 49H
   Function 4AH
   Function 4BH, Code 00H
   Function 4BH, Code 03H
   Function 4CH
   Function 4DH
   Function 4EH
   Function 4FH
   Function 54H
   Function 56H
   Function 57H
   Function 58H
   Function 59H
   Function 5AH
   Function 5BH
   Function 5CH, Code 00H
   Function 5CH, Code 01H
   Function 5EH, Code 00H
   Function 5EH, Code 02H
   Function 5FH, Code 02H
   Function 5FH, Code 03H
   Function 5FH, Code 04H
   Function 62H
   Function 65H
   Function 66H
   Function 67H
   Function 68H
   Handling errors
   memory management
   National Language Support
   Network-related
   network-related
   numeric order
   process management
   standard character I/O
   system-management
 Function requests
   definition
   Function 25H
   Function 35H
   Function 46H

 G

 Generic IOCtl for devices (Function 44H, Code 0DH)
 Generic IOCtl for handles (Function 44H, Code 0CH)
 Generic IOCtl Function
 Get Assign List Entry (Function 5FH, Code 02H)
 Get Country Data (Function 38H)
 Get Current Directory (Function 47H)
 Get Current Disk (Function 19H)
 Get Date (Function 2AH)
 Get Default Drive Data (Function 1BH)
 Get Disk Free Space (Function 36H)
 Get Disk Transfer Address (Function 2FH)
 Get Drive Data (Function 1CH)
 Get Extended Country Information (Function 65H)
 Get Extended Error (Function 59H)
 Get File Size (Function 23H)
 Get Interrupt Vector (Function 35H)
 Get Machine Name (Function 5EH, Code 00H)
 Get MS-DOS Version Number (Function 30H)
 Get PSP (Function 62H)
 Get Return Code Child Process (Function 4DH)
 Get Time (Function 2CH)
 Get Verify State (Function 54H)
 Get/Set Allocation Strategy (Function 58H)
 Get/Set Date/Time of File (Function 57H)
 Get/Set File Attributes (Function 43H)
 Get/Set Global Code Page (Function 66H)
 Get/Set IOCtl Drive Map (Function 44H, Codes 0EH and 0FH)
 Get/Set Logical Drive Map Function
 Group Component Descriptor field, GRPDEF
 Group, definition
 Group definition record. See GRPDEF record
 Group Definition Record (GRPDEF)
 Group Index
 Group Index subfield, Line Number Base
 Group Index subfield, Public Base
 Group Name Index field, GRPDEF
 GRPDEF record
   definition
   field
     CHKSUM
     Group Component Descriptor, repeated
     Group Name Index
     Record Length
     RECTYP
   schematic

 H

 Handles
   definition
   device
 Handling errors
 Header
 hibyte, definition
 Hidden files
 High-Level Language
 HUGE communal variable

 I

 IBM disk format
 Index
   definition
 Index fields
 Index Number
 Index subfield, Thread
   External Index
   Group Index
   Segment Index
 Indices
 Indices, external
 Init
 INIT code
 Installable device drivers
 Instruction
   CALL
   JUMP
   SHORT-JUMP
 Instruction Pointer (IP)
 Internal stack
 Interrupt entry point
 Interrupt handlers
 Interrupt routines
 Interrupt-handling routine
 Interrupts
   21H
   Address of handlers
   alphabetic order
   definition
   Interrupt 20H
   Interrupt 21H
   Interrupt 22H
   Interrupt 23H
   Interrupt 24H
   Interrupt 25H
   Interrupt 26H
   Interrupt 27H
   issuing
   numeric order
   programming hints
   Vector table
 I/O Control for Devices (Function 44H)
 IOCtl
 IOCtl bit
 IOCtl Block (Function 44H, Codes 4 and 5)
 IOCtl Character (Function 44H, Codes 2 and 3)
 IOCtl Data (Function 44H, Codes 0 and 1)
 IOCtl Is Changeable (Function 44H, Code 08H)
 IOCtl Is Redirected Block (Function 44H, Code 09H)
 IOCtl Is Redirected Handle (Function 44H, Code 0AH)
 IOCtl Retry (Function 44H, Code 0BH)
 IOCtl Status (Function 44H, Codes 6 and 7)
 io.sys file
 IP. See Instruction Pointer (IP)
 Iterated Data Block field, LIDATA
 Iterated Data Offset field, LIDATA

 J

 JUMP instruction

 K

 Keep Process (Function 31H)
 Keyboard layouts, national, NLS

 L

 Language
   C
   FORTRAN
 Leaf Descriptor subfield, Eight Leaf Descriptor
   format
     FAR variable
     NEAR variable
   subfield
     NEAR
     VARTYP
 LEDATA
   field
     CHKSUM
     Record Length
     RECTYP
   purpose
 LEDATA record
   field
     DAT, repeated
     Enumerated Data Offset
     Segment Index
   schematic
 Length fields, COMDEF, format
 Length in Bits subfield, Leaf Descriptor
 Length of Record Field
 LHEADR record
   field
     CHKSUM
     L-module Name
     Record Length
     RECTYP
   schematic
 LIDATA record
   field
     CHKSUM
     Iterated Data Block, repeated
     Iterated Data Offset
     Record Length
     RECTYP
     Segment Index
   purpose
   schematic
   subfield of Iterated Data Block
     Block Count
     Content
     Repeat Count
 Line Number Base field, LINNUM
 Line number, binary
 Line Number field, LINNUM
 Line Number Offset field, LINNUM
 Line Numbers Record (LINNUM)
 LINK
 Linker, Microsoft
 Linker, Microsoft
 Link-time semantics
 LINNUM record
   field
     CHKSUM
     Line Number Base
     Line Number Offset, repeated
     Line Number, repeated
     Record Length
     RECTYP
   purpose
   schematic
   subfield of Line Number Base
     Group Index
     Segment Index
 List of Names Record (LNAMES)
 L-module Header Record (LHEADR)
 L-module Name
 LNAMES record
   field
     CHKSUM
     Name, repeated
     Record Length
     RECTYP
   schematic
 Load and Execute Program (Function 4BH, Code 00H)
 Load module
 Load Overlay (Function 4BH, Code 03H)
 Loadsize
 lobyte, definition
 Local Base field, LOCSYM
 Local buffering
 Local Name field, LOCSYM
 Local Offset field, LOCSYM
 Local symbol
 Local Symbols Record (LOCSYM)
 LOCAT subfield, Fixup
   internal structure
   schematic
 Location
   types
     base
     hibyte
     lobyte
     offset
     pointer
 Lock (Function 5CH, Code 00H)
 LOCSYM record
   field
     CHKSUM
     Local Base
     Local Name, repeated
     Local Offset, repeated
     Record Length
     RECTYP
     Type Index, repeated
   order with respect to COMENT
   purpose
   schematic
 Logical Enumerated Data Record (LEDATA)
 Logical Iterated Data Record (LIDATA)
 Logical sector
 Logical sector numbers
 Logical Segment. See LSEG
 LSEG
   absolute
     Combination attribute
   Alignment attribute
     absolute segment
     relocatable segment
   canonic Frame
   Class name
   Combination attribute
     absolute segment
     relocatable segment
   combining
   Complete name
   definition
   Overlay Name
   relocatable
     byte-aligned
     Combination attribute
     page-aligned
     paragraph-aligned
     word-aligned
   Segment Name

 M

 Make Assign-List Entry (Function 5FH, Code 03H)
 Mapping
   logical to physical starting address
 MAS. See Memory Address Space (MAS)
 MATTR subfield, MOD TYP
 Maxalloc
 Media Check
 Media descriptor byte
 Media, determining
 Memory address
 Memory Address Space (MAS)
 Memory control block
 Memory image, 8086
 Memory image, LSEGs in
 Memory image, relocatable
 Memory management function requests
 Memory management, programming hints
 Memory model
   huge
   large
   medium
   small
 Microprocessor
   80186
   80286
   8086
 Microsoft Extensions class
 Microsoft linker
 Microsoft linker
 Microsoft Networks
 Microsoft Networks Manager's Guide
 Microsoft Networks User's Guide
 Minalloc
 MOD TYP field, MODEND
   MATTR subfield
   module attributes
 Mode
   fixup
     segment-relative
     self-relative
 Mode, address
 MODEND record
   field
     CHKSUM
     MOD TYP
     Record Length
     RECTYP
     START ADDRS, conditional
   purpose
   schematic
   subfield of START ADDRS
     Frame Datum, conditional
     Target Datum, conditional
     Target Displacement, conditional
 Module
   record ordering in
 Module, definition
 Module End Record (MODEND)
 Module header record, definition
 Move File Pointer (Function 42H)
 MS-DOS, 8086 object language
 MS-DOS initialization
 MS-DOS memory map
 MS-DOS User's Reference
 msdos.sys file
 Multitasking

 N

 Name field
 Name field, SAMREC
 Name Indices
 National keyboard layouts, NLS
 National Language Support Function Requests
 National Language Support (NLS)
   restrictions
   unsupported features
 National Language Support system calls
 NEAR data segment
 NEAR subfield, Leaf Descriptor
 NEAR variable format, Leaf Descriptor
 Network-related Function Requests
 Network-related function requests
 Non IBM format bit
 Non-destructive Read No Wait
 NUL device
 Number field, SAMREC
 Number of Elements subfield, Leaf Descriptor

 O

 Object language, 8086
 Object module
   restrictions
 Object Module Formats
 Object Module Formats (OMF)
 offset, definition
 Offset subfield, SEG ATTR
 Old system calls
 OMF. See Object Module Formats (OMF)
 Open File (Function 0FH)
 Open Handle (Function 3DH)
 Opened FCB
 Operating system
   MS-DOS
   PC-DOS
   XENIX
 Overlay Name, definition

 P

 Parameter block
 Parse File Name (Function 29H)
 Path command
 PC-DOS, 8086 object language
 Physical Segment. See PSEG
 Pointer to Next Device field
 Predefined device handles
 Print Character (Function 05H)
 Printer Setup (Function 5EH, Code 02H
 Process management function requests
 Process management, programming hints
 Processor. See Microprocessor
 Program End Process (Interrupt 20H)
 Program segment
 Program Segment Prefix
 Programming hints
   device management
   file and directory management
   file locking
   interrupts
   memory management
   miscellaneous
   process management
   recommendations
   system calls
 Programming interfaces, NLS
 Prompt command
 Protected-mode
   application Frame Number
 PSEG
   definition
 PUBDEF record
   field
     Public Base, repeated
     Public Name, repeated
     Public Offset, repeated
     Record Length
     RECTYP
     Type Index, repeated
   purpose
   schematic
   subfield of Public Base
     Frame Number, conditional
   subfield, Public Base
     Frame Number, conditional
     Group Index
     Segment Index
 Public Base field, PUBDEF
 Public Name field, PUBDEF
 Public names definition record. See PUBDEF record
 Public Names Definition Record (PUBDEF)
 Public Offset field, PUBDEF
 Public symbol
 Public variable

 R

 Random Block Read (Function 27H)
 Random Block Write (Function 28H)
 Random Read (Function 21H)
 Random Write (Function 22H)
 Read Handle (Function 3FH)
 Read Keyboard and Echo (Function 01H)
 Read Keyboard (Function 08H)
 Read Only Memory
 Read or Write
 Record
   COMDEF
   COMENT
   comment
   Data
   EXTDEF
   FIXUP
   FIXUPP
   GRPDEF
   LEDATA
   LHEADR
   LIDATA
   LINNUM
   LNAMES
   LOCSYM
   MODEND
   PUBDEF
   RECTYP(record type)
   SAMREC (sample record)
   SEGDEF
   symbol definition
     COMDEF
     EXTDEF
     PUBDEF
   THEADR
   TYPDEF
 Record format
   abbreviation
   bitfields
   conditional field
   repeated field
   sample (SAMREC)
   SAMREC (sample record)
     CHKSUM field
     Name field
     Number field
     Record Length field
   SAMREC(sample record)
     RECTYP field
   title
 Record formats
 Record Length field, SAMREC
 Record order
   definition
   semantic rules
   syntax
 Record Size
 RECTYP(record type)field
 Reference
   segment-relative
 Reference self-relative
 References
   WIRTH
     CACM, Nov. 1977)
 Register
   CS
   DS
   ES
   SS
 Registers, treatment of
 Relocatable memory image
 Relocatable segment, LSEG
 Relocation information
 Relocation item offset value to a word in the load
 Relocation table
 Remove Directory (Function 3AH)
 Rename File (Function 17H)
 Repeat Count subfield, Iterated Data Block
 request header
 Request packet
 Reset Disk (Function 0DH)
 Resident device drivers
 ROM
 Root directory

 S

 SAMREC (sample record)
   schematic
 Search for First Entry (Function 11H)
 Search for Next Entry (Function 12H)
 Sector count
 SEG ATTR field, SEGDEF
 SEGDEF record
   definition
   field
     CHKSUM
     Class Name Index
     Overlay Name Index
     Record Length
     RECTYP
     SEG ATTR
     Segment Name Index
   schematic
   subfield of SEG ATTR
     Alignment
     Big
     Combination
     Offset, conditional
 SEGDEF recrod
   field
     Segment Length
 Segment
   absolute, LSEG
   attribute
     Alignment
     Combination
   logical (LSEG)
   physical (PSEG)
   relocatable, LSEG
 Segment addressing
 Segment definition record. See SEGDEF record
 Segment Definition Record (SEGDEF)
 Segment Index
 Segment Index field, LEDATA
 Segment Index field, LIDATA
 Segment Index subfield, Group Component Descriptor
 Segment Index subfield, Line Number Base
 Segment Index subfield, Public Base
 Segment Length field, SEGDEF
 Segment Name, definition
 Segment Name Index field, SEGDEF
 Segment-relative fixup
 Segment-relative reference
 Select Disk (Function 0EH)
 Self-relative fixup
 Self-relative reference
 Semantic rules, record ordering
 Semantics, link-time
 Sequential Read (Function 14H)
 Sequential Write (Function 15H)
 Set Block (Function 4AH)
 Set command
 Set Country Data (Function 38H)
 Set Date (Function 2BH)
 Set Disk Transfer Address (Function 1AH)
 Set Handle Count(Function 67H)
 Set Interrupt Vector (Function 25H)
 Set Relative Record (Function 24H)
 Set Time (Function 2DH)
 Set/Reset Verify Flag (Function 2EH)
 SHORT-JUMP instruction
 SS register
 Stack segment, SS
 Standard character I/O function requests
 START ADDRS field, MODEND
   Format
 Start sector
 Start segment value the relocation item offset
 static request header
 Status
 Status field
 Strategy entry point
 Strategy routines
 Subfield
   Comment Type
     Comment Class
   Eight Leaf Descriptor
     EN
     Leaf Descriptor
   Fixup
     Frame Datum
     Target Datum
     Target Displacement
   Frame Number, conditional
   Group Component Descriptor
     Segment Index
   Iterated Data Block
     Block Count
     Content
     Repeat Count
   Leaf Descriptor
     Element Type Index
     FAR
     Length in Bits
     NEAR
     Number of Elements
     VAR SUBTYP
     VARTYP
   Line Number Base, LINNUM
     Group Index
     Segment Index
   MOD TYP
     MATTR
   Public Base
     Group INdex
   SEG ATTR
     Alignment
     Big
     Combination
   Segment Index
   START ADDRS
     Frame Datum
     Target Datum
     Target Displacement
   Thread
     Index
     TRD DAT
 Subfield OFFH
 Superseded system calls
 Symbol
   local
   public
 Symbol definition
 Symbol definition record
   COMDEF
   EXTDEF
   PUBDEF
 Syntax, record ordering
 Sysinit
 System call
   National Language Support:
 System Calls
   superseded calls
 System calls
   definition
   programming hints
   replacements for old
   types of
 System files
 System prompt
 System-management function requests

 T

 Target
   definition
   nomenclature
   specification attribute
   specifying
   specifying, FIXUPP
   Thread Number, FIXUPP
 Target Datum field, FIXUPP
 Target Datum subfield, Fixup
   External Index
   Group Index
   Segment Index
 Target Datum subfield, START ADDRS
 Target Displacement subfield, Fixup
 Target Displacment subfield, START ADDRS
 Terminate But Stay Resident (Interrupt 27H)
 Terminate Process Exit Address (Interrupt 22H)
 Terminate Program (Function 00H)
 THEADR record
   field
     CHKSUM
     Record Length
     RECTYP
     T-module Name
   schematic
 Thread Data subfield. See TRD DAT subfield, Thread
 Thread field, FIXUPP
   data type
     Frame
     Target
   definition
 Thread Number, THRED
 T-module, definition
 T-module Header Record (THEADR)
 T-Module Name
 Transfer address
 TRD DAT subfield, Thread
   D subfield
   internal structure
   Method subfield
   schematic
   THRED subfield
 TYPDEF record
   communal variable
   field
     CHKSUM
     Eight Leaf Descriptor
     Record Length
     RECTYP
   subfield of Eight Leaf Descriptor
     EN
   subfield of Leaf Descriptor
     Element Type Index
     FAR
     Length in Bits
     NEAR
     Number of Elements
     VAR SUBTYP, optional
     VARTYP
 Type Index field, COMDEF
 Type Index field, EXTDEF
 Type Index field, LOCSYM
 Type Index field, PUBDEF
 Type-ahead buffer

 U

 Unit code field
 Unlock (Function 5CH, Code 01H)
 Unopened FCB
 User Stack
 User stack
 Utility commands, NLS

 V

 VAR SUBTYP subfield, Leaf Descriptor
 Variable
   communal
     FAR
     HUGE"
     NEAR
   public
 VARTYP subfield, Leaf Descriptor
   ARRAY
   SCALAR
   STRUCT
 Vector table
 Volume ID
 Volume label

 W

 Wildcard characters
 Write Handle (Function 40H)

 X

 XENIX, 8086 object language
