448 lines
12 KiB
Plaintext
448 lines
12 KiB
Plaintext
|
--
|
|||
|
-- D I R E C T I N P U T / O U T P U T
|
|||
|
--
|
|||
|
-- Body of the Package Direct_IO
|
|||
|
--
|
|||
|
-- According to ANSI/MIL-STD 1815A (1983)
|
|||
|
-- Implemented for Artek Ada
|
|||
|
--
|
|||
|
-- Copyright (C) 1986 Artek Corporation
|
|||
|
-- Author : O. Karlsson
|
|||
|
--
|
|||
|
--
|
|||
|
-- Version: 1.01
|
|||
|
-- Date last modified: 1986-05-01
|
|||
|
--
|
|||
|
|
|||
|
with DOS_INTERFACE, SYSTEM, LONG_OPERATIONS;
|
|||
|
|
|||
|
package body DIRECT_IO is
|
|||
|
|
|||
|
use DOS_INTERFACE, SYSTEM, ASCII, LONG_OPERATIONS;
|
|||
|
|
|||
|
-- Data types and objects
|
|||
|
|
|||
|
EOF : constant CHARACTER := CHARACTER (26);
|
|||
|
|
|||
|
R : REG_8086;
|
|||
|
|
|||
|
--
|
|||
|
-- Utility procedure to skip last character read from a file
|
|||
|
-- Same as " lseek (file, -1) " relative from the file position
|
|||
|
--
|
|||
|
|
|||
|
procedure UNGET (FILE : in FILE_TYPE) is
|
|||
|
|
|||
|
begin
|
|||
|
-- This procedure is only used internally and
|
|||
|
-- the file is always open
|
|||
|
R . AX := 16#4201#; -- DOS function 42, lseek
|
|||
|
R . BX := WORD (FILE . HANDLE);
|
|||
|
R . CX := -1; -- Desired location from current position
|
|||
|
R . DX := -1;
|
|||
|
CALL_DOS (R);
|
|||
|
if abs R . FLAGS mod 2 = 1 then -- Carry was set
|
|||
|
raise USE_ERROR; -- There should never be error here
|
|||
|
end if;
|
|||
|
end UNGET;
|
|||
|
|
|||
|
--
|
|||
|
-- File management
|
|||
|
--
|
|||
|
|
|||
|
procedure CREATE (
|
|||
|
FILE : in out FILE_TYPE;
|
|||
|
MODE : in FILE_MODE := INOUT_FILE;
|
|||
|
NAME : in STRING := "";
|
|||
|
FORM : in STRING := "") is
|
|||
|
|
|||
|
ASCIIZ_NAME : FILE_NAME_STRING;
|
|||
|
BLANK_NAME : FILE_NAME_STRING := (others => ' ');
|
|||
|
BLANK_FORM : FORM_NAME_STRING := (others => ' ');
|
|||
|
|
|||
|
-- See chapter 14.2.1
|
|||
|
|
|||
|
begin -- Concatenate a null character
|
|||
|
if FILE /= null then
|
|||
|
raise STATUS_ERROR;
|
|||
|
end if;
|
|||
|
ASCIIZ_NAME (1..NAME'LENGTH) := NAME;
|
|||
|
ASCIIZ_NAME (NAME'LENGTH + 1) := NUL;
|
|||
|
R . AX := 16#3C00#; -- Function 3C, Create a file
|
|||
|
R . DX := WORD (ASCIIZ_NAME'ADDRESS); -- Address of the filename
|
|||
|
R . CX := 16#0000#; -- No attributes
|
|||
|
CALL_DOS (R);
|
|||
|
if abs R . FLAGS mod 2 = 1 then -- Carry was set
|
|||
|
if R . AX > 3 then -- 4 = Too many open files, 5 = access denied
|
|||
|
raise USE_ERROR;
|
|||
|
else
|
|||
|
raise NAME_ERROR; -- 3 = Path not found
|
|||
|
end if;
|
|||
|
end if;
|
|||
|
FILE := new FILE_DESCR'
|
|||
|
(NAMELEN => NAME'LENGTH, NAME => BLANK_NAME,
|
|||
|
FORMLEN => FORM'LENGTH, FORM => BLANK_FORM,
|
|||
|
MODE => MODE, INDEX => 1,
|
|||
|
HANDLE => INTEGER (R . AX)); -- AX contains the file handle after call 3C
|
|||
|
FILE . NAME (1..NAME'LENGTH) := NAME;
|
|||
|
FILE . FORM (1..FORM'LENGTH) := FORM;
|
|||
|
end CREATE;
|
|||
|
|
|||
|
procedure OPEN (
|
|||
|
FILE : in out FILE_TYPE;
|
|||
|
MODE : in FILE_MODE;
|
|||
|
NAME : in STRING;
|
|||
|
FORM : in STRING := "") is
|
|||
|
|
|||
|
ASCIIZ_NAME : FILE_NAME_STRING;
|
|||
|
BLANK_NAME : FILE_NAME_STRING := (others => ' ');
|
|||
|
BLANK_FORM : FORM_NAME_STRING := (others => ' ');
|
|||
|
|
|||
|
-- See chapter 14.2.1
|
|||
|
|
|||
|
begin
|
|||
|
if FILE /= null then
|
|||
|
raise STATUS_ERROR;
|
|||
|
end if;
|
|||
|
ASCIIZ_NAME (1..NAME'LENGTH) := NAME;
|
|||
|
ASCIIZ_NAME (NAME'LENGTH + 1) := NUL;
|
|||
|
case MODE is
|
|||
|
when IN_FILE => R . AX := 16#3D00#; -- AH = 3D, Open a file
|
|||
|
when OUT_FILE => R . AX := 16#3D01#; -- AL = 00, Open for input
|
|||
|
when INOUT_FILE => R . AX := 16#3D02#; -- AL = 01, Open for output
|
|||
|
end case; -- AL = 02, Open for in- or out
|
|||
|
R . DX := WORD (ASCIIZ_NAME'ADDRESS);
|
|||
|
CALL_DOS (R);
|
|||
|
if abs R . FLAGS mod 2 = 1 then -- Carry was set
|
|||
|
if R . AX > 3 then
|
|||
|
raise USE_ERROR; -- Access denied and to many files open
|
|||
|
else
|
|||
|
raise NAME_ERROR; -- File not found
|
|||
|
end if;
|
|||
|
end if;
|
|||
|
FILE := new FILE_DESCR'
|
|||
|
(NAMELEN => NAME'LENGTH, NAME => BLANK_NAME,
|
|||
|
FORMLEN => FORM'LENGTH, FORM => BLANK_FORM,
|
|||
|
MODE => MODE, INDEX => 1,
|
|||
|
HANDLE => INTEGER (R . AX)); -- AX contains the file handle
|
|||
|
FILE . NAME (1..NAME'LENGTH) := NAME;
|
|||
|
FILE . FORM (1..FORM'LENGTH) := FORM;
|
|||
|
end OPEN;
|
|||
|
|
|||
|
procedure CLOSE (FILE : in out FILE_TYPE) is
|
|||
|
|
|||
|
-- See chapter 14.2.1
|
|||
|
|
|||
|
begin
|
|||
|
if FILE = null then
|
|||
|
raise STATUS_ERROR;
|
|||
|
end if;
|
|||
|
R . AX := 16#3E00#; -- DOS function 3E, Close a file handle
|
|||
|
R . BX := WORD (FILE . HANDLE);
|
|||
|
CALL_DOS (R);
|
|||
|
if abs R . FLAGS mod 2 = 1 then -- Carry was set
|
|||
|
raise USE_ERROR; -- Invalid handle. This error should never
|
|||
|
end if; -- occur. Something is wrong in the file system.
|
|||
|
FILE := null;
|
|||
|
end CLOSE;
|
|||
|
|
|||
|
procedure DELETE (FILE : in out FILE_TYPE) is
|
|||
|
|
|||
|
ASCIIZ_NAME : FILE_NAME_STRING;
|
|||
|
|
|||
|
-- See chapter 14.2.1
|
|||
|
|
|||
|
begin
|
|||
|
ASCIIZ_NAME (1..FILE . NAMELEN) := FILE . NAME (1..FILE . NAMELEN);
|
|||
|
ASCIIZ_NAME (FILE . NAMELEN + 1) := NUL;
|
|||
|
CLOSE (FILE);
|
|||
|
R . AX := 16#4100#; -- DOS function 41, delete a file
|
|||
|
R . DX := WORD (ASCIIZ_NAME'ADDRESS);
|
|||
|
CALL_DOS (R);
|
|||
|
if abs R . FLAGS mod 2 = 1 then -- Carry was set
|
|||
|
raise USE_ERROR; -- Access denied
|
|||
|
end if;
|
|||
|
end DELETE;
|
|||
|
|
|||
|
procedure RESET (FILE : in out FILE_TYPE; MODE : in FILE_MODE) is
|
|||
|
|
|||
|
-- See chapter 14.2.1
|
|||
|
|
|||
|
NAME : FILE_NAME_STRING;
|
|||
|
FORM : FORM_NAME_STRING;
|
|||
|
NAMELEN : NAME_INDEX;
|
|||
|
FORMLEN : FORM_INDEX;
|
|||
|
|
|||
|
begin
|
|||
|
if FILE = null then
|
|||
|
raise STATUS_ERROR;
|
|||
|
end if;
|
|||
|
if FILE . MODE = MODE then
|
|||
|
RESET (FILE);
|
|||
|
else
|
|||
|
NAME := FILE . NAME;
|
|||
|
FORM := FILE . FORM;
|
|||
|
NAMELEN := FILE . NAMELEN;
|
|||
|
FORMLEN := FILE . FORMLEN;
|
|||
|
CLOSE (FILE); -- Must close and reopen since MODE changes
|
|||
|
OPEN (FILE, MODE, NAME (1 .. NAMELEN), FORM (1..FORMLEN));
|
|||
|
end if;
|
|||
|
end RESET;
|
|||
|
|
|||
|
procedure RESET (FILE : in out FILE_TYPE) is
|
|||
|
|
|||
|
-- See chapter 14.2.1
|
|||
|
|
|||
|
begin
|
|||
|
if FILE = null then
|
|||
|
raise STATUS_ERROR;
|
|||
|
end if;
|
|||
|
-- Do an LSEEK (FILE, 0);
|
|||
|
R . AX := 16#4200#; -- DOS function 42, lseek
|
|||
|
R . BX := WORD (FILE . HANDLE);
|
|||
|
R . CX := 0; -- Desired location from BOF
|
|||
|
R . DX := 0;
|
|||
|
CALL_DOS (R);
|
|||
|
if abs R . FLAGS mod 2 = 1 then -- Carry was set
|
|||
|
raise USE_ERROR;
|
|||
|
end if;
|
|||
|
FILE . INDEX := 1;
|
|||
|
end RESET;
|
|||
|
|
|||
|
function MODE (FILE : in FILE_TYPE) return FILE_MODE is
|
|||
|
|
|||
|
-- See chapter 14.2.1
|
|||
|
|
|||
|
begin
|
|||
|
if FILE = null then
|
|||
|
raise STATUS_ERROR;
|
|||
|
end if;
|
|||
|
return FILE . MODE;
|
|||
|
end MODE;
|
|||
|
|
|||
|
function NAME (FILE : in FILE_TYPE) return STRING is
|
|||
|
|
|||
|
-- See chapter 14.2.1
|
|||
|
|
|||
|
|
|||
|
begin
|
|||
|
if FILE = null then
|
|||
|
raise STATUS_ERROR;
|
|||
|
end if;
|
|||
|
return FILE . NAME (1..FILE . NAMELEN);
|
|||
|
end NAME;
|
|||
|
|
|||
|
function FORM (FILE : in FILE_TYPE) return STRING is
|
|||
|
|
|||
|
-- See chapter 14.2.1
|
|||
|
|
|||
|
begin
|
|||
|
if FILE = null then
|
|||
|
raise STATUS_ERROR;
|
|||
|
end if;
|
|||
|
return FILE . FORM (1 .. FILE . FORMLEN);
|
|||
|
end FORM;
|
|||
|
|
|||
|
function IS_OPEN (FILE : in FILE_TYPE) return BOOLEAN is
|
|||
|
|
|||
|
-- See chapter 14.2.1
|
|||
|
|
|||
|
begin
|
|||
|
return FILE /= null;
|
|||
|
end IS_OPEN;
|
|||
|
|
|||
|
--
|
|||
|
-- Input and output operations
|
|||
|
--
|
|||
|
|
|||
|
procedure SET_INDEX (FILE : in FILE_TYPE; TO : in POSITIVE_COUNT) is
|
|||
|
|
|||
|
BYTE_INDEX : LONG_INTEGER;
|
|||
|
|
|||
|
-- See chapter 14.2.4
|
|||
|
|
|||
|
begin
|
|||
|
if FILE = null then
|
|||
|
raise STATUS_ERROR;
|
|||
|
end if;
|
|||
|
R . AX := 16#4200#; -- DOS function 42, lseek
|
|||
|
R . BX := WORD (FILE . HANDLE);
|
|||
|
BYTE_INDEX := INTEGER (TO - 1) *
|
|||
|
INTEGER (ELEMENT_TYPE'SIZE / STORAGE_UNIT);
|
|||
|
R . CX := WORD (BYTE_INDEX . HIGH); -- Desired location from BOF
|
|||
|
R . DX := WORD (BYTE_INDEX . LOW);
|
|||
|
CALL_DOS (R);
|
|||
|
FILE . INDEX := TO;
|
|||
|
if abs R . FLAGS mod 2 = 1 then -- Carry was set
|
|||
|
raise USE_ERROR; -- There should never be error here
|
|||
|
end if;
|
|||
|
exception
|
|||
|
when NUMERIC_ERROR =>
|
|||
|
raise USE_ERROR;
|
|||
|
end SET_INDEX;
|
|||
|
|
|||
|
procedure FREAD (FILE : in FILE_TYPE; ITEM : out ELEMENT_TYPE) is
|
|||
|
|
|||
|
MYITEM : ELEMENT_TYPE;
|
|||
|
|
|||
|
begin
|
|||
|
if FILE = null then
|
|||
|
raise STATUS_ERROR;
|
|||
|
elsif FILE . MODE = OUT_FILE then
|
|||
|
raise MODE_ERROR;
|
|||
|
end if;
|
|||
|
R . AX := 16#3F00#; -- DOS function 3F, read from a file or device
|
|||
|
R . BX := WORD (FILE . HANDLE);
|
|||
|
R . CX := WORD (ELEMENT_TYPE'SIZE / STORAGE_UNIT);
|
|||
|
R . DX := WORD (MYITEM'ADDRESS); -- Address of ITEM
|
|||
|
CALL_DOS (R);
|
|||
|
if R . AX = 0 then -- Read past EOF
|
|||
|
raise END_ERROR;
|
|||
|
end if;
|
|||
|
if abs R . FLAGS mod 2 = 1 then -- Carry set
|
|||
|
raise USE_ERROR; -- Access denied or invalid file handle
|
|||
|
end if;
|
|||
|
FILE . INDEX := FILE . INDEX + 1;
|
|||
|
ITEM := MYITEM;
|
|||
|
end FREAD;
|
|||
|
|
|||
|
procedure READ (FILE : in FILE_TYPE;
|
|||
|
ITEM : out ELEMENT_TYPE;
|
|||
|
FROM : in POSITIVE_COUNT) is
|
|||
|
|
|||
|
-- See chapter 14.2.4
|
|||
|
|
|||
|
begin
|
|||
|
SET_INDEX (FILE, FROM);
|
|||
|
FREAD (FILE, ITEM);
|
|||
|
end READ;
|
|||
|
|
|||
|
procedure READ (FILE : in FILE_TYPE; ITEM : out ELEMENT_TYPE) is
|
|||
|
|
|||
|
-- See chapter 14.2.4
|
|||
|
|
|||
|
begin
|
|||
|
FREAD (FILE, ITEM);
|
|||
|
end READ;
|
|||
|
|
|||
|
procedure FWRITE (FILE : in FILE_TYPE; ITEM : in ELEMENT_TYPE) is
|
|||
|
|
|||
|
begin
|
|||
|
if FILE = null then
|
|||
|
raise STATUS_ERROR;
|
|||
|
elsif FILE . MODE = IN_FILE then
|
|||
|
raise MODE_ERROR;
|
|||
|
end if;
|
|||
|
R . AX := 16#4000#; -- DOS function 40, write to a file or device
|
|||
|
R . BX := WORD (FILE . HANDLE);
|
|||
|
R . CX := WORD (ELEMENT_TYPE'SIZE / STORAGE_UNIT);
|
|||
|
R . DX := WORD (ITEM'ADDRESS); -- Address of ITEM
|
|||
|
CALL_DOS (R);
|
|||
|
if R . AX = 0 then -- No output made, probably disk full error
|
|||
|
raise USE_ERROR;
|
|||
|
end if;
|
|||
|
if abs R . FLAGS mod 2 = 1 then -- Carry set
|
|||
|
raise USE_ERROR; -- Access denied or invalid file handle
|
|||
|
end if;
|
|||
|
FILE . INDEX := FILE . INDEX + 1;
|
|||
|
end FWRITE;
|
|||
|
|
|||
|
procedure WRITE (FILE : in FILE_TYPE;
|
|||
|
ITEM : in ELEMENT_TYPE;
|
|||
|
TO : in POSITIVE_COUNT) is
|
|||
|
|
|||
|
-- See chapter 14.2.4
|
|||
|
|
|||
|
begin
|
|||
|
SET_INDEX (FILE, TO);
|
|||
|
FWRITE (FILE, ITEM);
|
|||
|
end WRITE;
|
|||
|
|
|||
|
procedure WRITE (FILE : in FILE_TYPE; ITEM : in ELEMENT_TYPE) is
|
|||
|
|
|||
|
-- See chapter 14.2.4
|
|||
|
|
|||
|
begin
|
|||
|
FWRITE (FILE, ITEM);
|
|||
|
end WRITE;
|
|||
|
|
|||
|
function INDEX (FILE : in FILE_TYPE) return POSITIVE_COUNT is
|
|||
|
|
|||
|
-- See chapter 14.2.4
|
|||
|
|
|||
|
begin
|
|||
|
if FILE = null then
|
|||
|
raise STATUS_ERROR;
|
|||
|
end if;
|
|||
|
return FILE . INDEX;
|
|||
|
end INDEX;
|
|||
|
|
|||
|
function SIZE (FILE : in FILE_TYPE) return COUNT is
|
|||
|
|
|||
|
BYTE_INDEX : LONG_INTEGER;
|
|||
|
C : COUNT;
|
|||
|
|
|||
|
-- See chapter 14.2.4
|
|||
|
|
|||
|
begin
|
|||
|
if FILE = null then
|
|||
|
raise STATUS_ERROR;
|
|||
|
end if;
|
|||
|
R . AX := 16#4202#; -- DOS function 42, lseek
|
|||
|
R . BX := WORD (FILE . HANDLE);
|
|||
|
R . CX := 0; -- Desired location from EOF
|
|||
|
R . DX := 0;
|
|||
|
CALL_DOS (R);
|
|||
|
if abs R . FLAGS mod 2 = 1 then -- Carry was set
|
|||
|
raise USE_ERROR; -- There should never be error here
|
|||
|
end if;
|
|||
|
BYTE_INDEX . HIGH := INTEGER (R . DX);
|
|||
|
BYTE_INDEX . LOW := INTEGER (R . AX);
|
|||
|
C := COUNT (BYTE_INDEX / (ELEMENT_TYPE'SIZE / STORAGE_UNIT)); -- Keep the size
|
|||
|
R . AX := 16#4200#; -- Return to the previous location
|
|||
|
R . BX := WORD (FILE . HANDLE);
|
|||
|
BYTE_INDEX := INTEGER (FILE . INDEX - 1) *
|
|||
|
INTEGER (ELEMENT_TYPE'SIZE / STORAGE_UNIT);
|
|||
|
R . CX := WORD (BYTE_INDEX . HIGH);
|
|||
|
R . DX := WORD (BYTE_INDEX . LOW);
|
|||
|
CALL_DOS (R);
|
|||
|
if abs R . FLAGS mod 2 = 1 then -- Carry was set
|
|||
|
raise USE_ERROR; -- There should never be error here
|
|||
|
end if;
|
|||
|
return C;
|
|||
|
exception
|
|||
|
when NUMERIC_ERROR =>
|
|||
|
raise USE_ERROR;
|
|||
|
end SIZE;
|
|||
|
|
|||
|
function END_OF_FILE (FILE : in FILE_TYPE) return BOOLEAN is
|
|||
|
|
|||
|
CH : CHARACTER;
|
|||
|
|
|||
|
-- See chapter 14.2.4
|
|||
|
|
|||
|
begin
|
|||
|
if FILE = null then
|
|||
|
raise STATUS_ERROR;
|
|||
|
elsif FILE . MODE = OUT_FILE then
|
|||
|
raise MODE_ERROR;
|
|||
|
end if;
|
|||
|
R . AX := 16#3F00#; -- DOS function 3F, read from a file or device
|
|||
|
R . BX := WORD (FILE . HANDLE);
|
|||
|
R . CX := 1; -- Read one byte
|
|||
|
R . DX := WORD (CH'ADDRESS);
|
|||
|
CALL_DOS (R);
|
|||
|
if R . AX = 0 then -- Read past EOF
|
|||
|
UNGET (FILE);
|
|||
|
return TRUE;
|
|||
|
end if;
|
|||
|
if abs R . FLAGS mod 2 = 1 then -- Carry set
|
|||
|
raise USE_ERROR; -- Access denied or invalid file handle
|
|||
|
end if;
|
|||
|
UNGET (FILE);
|
|||
|
return CH = EOF;
|
|||
|
end END_OF_FILE;
|
|||
|
|
|||
|
end DIRECT_IO;
|
|||
|
|
|||
|
|