Microsoft KB Archive/35513

From BetaArchive Wiki

How to Invoke DOS Interrupts with Call X“84” in COBOL 3.0

PSS ID Number: Q35513 Article last modified on 06-24-1993

3.00 | 3.00 MS-DOS | OS/2

The information in this article applies to:
- Microsoft COBOL for MS-DOS and OS/2, version 3.0

Summary: The DOS interrupt calls that use only the AX, BX, CX, and DX registers can be made using Call X“84” in Microsoft COBOL Version 3.0. The following example shows how to make an interrupt call that uses a block of data from within the COBOL program to serve as a buffer for the DOS interrupt call. Specifically, this example will pass the Disk Transfer Address through a DOS interrupt and then use this buffer area to read a disk directory.

More Information: Each of the registers (AX, BX, CX, and DX) are two 8-bit values. The Disk Transfer Address we pass is actually the address of a COBOL data block. In this example, the block is called MyBuff. The size of this block is prescribed by the requirements of the interrupt we are calling. The actual syntax of the call is as follows: CALL X“84” USING DOS-INT, FLAG, AX-VALUE, BX-VALUE, CX-VALUE, DX-VALUE. The DOS-INT in this case is 21 hex. The flag is a single 8-bit value that describes how each of the registers are to be used on input and output. The high nibble of the byte represents output and the low nibble is for input. Each bit of one nibble represents one register. If the bit is set, the values passed to the corresponding register are equal to the values in AX-VALUE, BX-VALUE, CX-VALUE, and DX-VALUE. However, if the bit is clear, the offset of the location of the value in memory is passed to the corresponding register. In this case, we want to pass AX by content; BX and CX are unused. Bit 0 (AX) then must be high; Bits 1 and 2 don’t matter. However, we want to pass the address of our data block (MyBuff) to the DOS interrupt in DS:DX. The DS register is automatically set to the segment address and by resetting Bit 3 in the flag, DX will be set equal to the offset of the address of MyBuff. The high nibble of the flag byte is used to specify which registers will be passed back to our local variables. If the bit is high, the register is copied to the variable on exit. Since we do not need any of the values passed back, we can reset all high bits. As shown in the following table, the flag value is hex 05. Any value that had bit 0 set to 1 and bit 3 reset to 0 would work in the following example:

        High Bits          Low Bits
        ---------          --------

Bit Number 7 6 5 4 3 2 1 0 Setting 0 0 0 0 0 1 0 1 Represents DX CX BX AX DX CX BX AX During OUT IN

Once all the values are set, the first Call X“84” sets the disk transfer address, then the values are reset to read the first directory listing. The AX-VALUE must be set to 4E00 hex, which is the function number, BX-VALUE is of no importance, CX-VALUE is set to the file attribute, FF hex will match all files, and the DS:DS register is the pointer to the full name (including the path) of the directory listings to be read. The flag byte may be any value that has bits 0 and 2 set with bit 3 reset. Therefore, the same flag value works in both cases. When the second call is made, the first directory listing is read into the data block named MyBuff. This information may be displayed without modification, except for the time and date. The modifications are required because of the coding used within DOS to store this information. The remainder of the directory listings can be read using the DOS interrupt call hex 4F00 until no more listings remain. Note that this technique is not supported by versions of Microsoft COBOL earlier than Version 3.0. The following is a code example:

  $SET ANS85 NOOSVS
   SPECIAL-NAMES.
       CONSOLE IS CRT.
   WORKING-STORAGE SECTION.
   01 DOS-INT          PIC X VALUE X"21".
   01 REGS.
      02 FLAG          PIC X.
      02 AX-VALUE      PIC XX.
      02 BX-VALUE      PIC XX.
      02 CX-VALUE      PIC XX.
      02 DX-VALUE      PIC XX.
  * THE DISK TRANSFER ADDRESS IS SET TO THIS BUFFER.
   01 MYBUFF.
      02 MY-RES1     PIC X(21).
      02 MY-ATT      PIC 9(2) COMP-5.
      02 MY-TIME     PIC 9(4) COMP-5.
      02 MY-DATE     PIC 9(4) COMP-5.
      02 MY-SIZE     PIC 9(8) COMP-5.
      02 MY-NAME     PIC X(12).
      02 FILLER      PIC X(22).
  * THIS RECORD HOLDS THE CONVERTED DATA VALUES FOR
  * THE DIRECTORY ENTRY.
   01 DIRLIST.
      02 SHOW-TIME.
         03 SHOW-HR    PIC 99.
         03 SHOW-D0    PIC X VALUE ":".
         03 SHOW-MIN   PIC 99.
      02 SHOW-DATE.
         03 SHOW-YR    PIC 9999.
         03 SHOW-D1    PIC X VALUE "-".
         03 SHOW-MO    PIC 99.
         03 SHOW-D2    PIC X VALUE "-".
         03 SHOW-DAY   PIC 99.
  * THE FOLLOWING VALUES ARE MOVED INTO THE REGS RECORD
  * TO SET EACH OF THE REGISTERS PRIOR TO THE DOS INTERRUPT
  * CALL TO SET THE DISK TRANSFER ADDRESS
   01 V-TO-SET-DTA.
      02 DTA-FLAG PIC X VALUE X"05".
      02 DTA-AX   PIC XX VALUE X"1A00".
  * THESE VALUES ARE NEED TO SET THE REGS RECORD PRIOR TO
  * THE DOS INTERRUPT CALL TO READ THE DIRECTORY.
   01 V-TO-GET-FIRST.
      02 FIRST-FLG  PIC X VALUE X"05".
      02 FIRST-AX   PIC XX VALUE X"4E00".
      02 FIRST-BX   PIC XX VALUE X"0000".
      02 FIRST-CX   PIC XX VALUE X"00FF".
   01 FULLNAME PIC X(80).
   01 TEMP-VAR1 PIC 9999.
   01 TEMP-VAR2 PIC 9999.
   01 TEMP-VAR3 PIC 9999.
   01 INKEY     PIC X.
   PROCEDURE DIVISION.
   MAIN.
       DISPLAY SPACES UPON CRT.
       DISPLAY "SEARCH PATH NAME EXAMPLE: C:\*.BAT " AT 0405.
       DISPLAY "ENTER THE FULL NAME OF THE SEARCH PATH " AT 0505.
       ACCEPT FULLNAME AT 0605.
       DISPLAY SPACES UPON CRT.
       DISPLAY "NAME     :" AT 1001.
       DISPLAY "ATTRIBUTE:" AT 1101.
       DISPLAY "SIZE     :" AT 1201.
       DISPLAY "TIME     :" AT 1301.
       DISPLAY "DATE     :" AT 1401.
  * FIRST SET THE DISK TRANSFER ADDRESS
       MOVE V-TO-SET-DTA TO REGS.
       CALL X"84" USING DOS-INT, FLAG, AX-VALUE, BX-VALUE, CX-VALUE,
                       MYBUFF.
  * READ THE FIRST ENTRY
       PERFORM NEXT-LISTING.
  * SET AX REGISTER TO DO NEXT OPTION
       MOVE X"4F00" TO FIRST-AX.
  * CONTINUE SEARCHING
       PERFORM NEXT-LISTING UNTIL INKEY ="Q".
  * THAT'S ALL
       STOP RUN.
   NEXT-LISTING.
       MOVE "?" TO MY-NAME.
       MOVE V-TO-GET-FIRST TO REGS.
       CALL X"84" USING DOS-INT, FLAG, AX-VALUE,
                  BX-VALUE, CX-VALUE, FULLNAME.
       IF MY-NAME(1:1) = "?" THEN
          MOVE "Q" TO INKEY
       ELSE
          PERFORM DISPLAY-LISTING
       END-IF.
   DISPLAY-LISTING.
       DISPLAY MY-NAME AT 1015.
       DISPLAY MY-ATT AT 1115.
       DISPLAY MY-SIZE AT 1215.
       COMPUTE TEMP-VAR1
               = MY-TIME / 2048.
       COMPUTE TEMP-VAR2
               = (MY-TIME - TEMP-VAR1 * 2048) / 32.
       MOVE TEMP-VAR1 TO SHOW-HR.
       MOVE TEMP-VAR2 TO SHOW-MIN.
       DISPLAY SHOW-TIME AT 1315.
       COMPUTE TEMP-VAR1
                = MY-DATE / 512.
       COMPUTE TEMP-VAR2
                = (MY-DATE - TEMP-VAR1 * 512) / 32.
       COMPUTE TEMP-VAR3
                = (MY-DATE - TEMP-VAR1 * 512
                           - TEMP-VAR2 * 32).
       COMPUTE TEMP-VAR1
                = TEMP-VAR1 + 1980
       MOVE TEMP-VAR1 TO SHOW-YR.
       MOVE TEMP-VAR2 TO SHOW-MO.
       MOVE TEMP-VAR3 TO SHOW-DAY.
       DISPLAY SHOW-DATE AT 1415.
       DISPLAY "Q RETURN TO QUIT OR " AT 1910.
       DISPLAY "PRESS RETURN TO CONTINUE " AT 2010.
       ACCEPT INKEY AT 2040.

Additional reference words: 3.00 Copyright Microsoft Corporation 1993.