aboutsummaryrefslogtreecommitdiffstats
path: root/src/grt
diff options
context:
space:
mode:
Diffstat (limited to 'src/grt')
-rw-r--r--src/grt/grt-files.adb496
-rw-r--r--src/grt/grt-files.ads87
-rw-r--r--src/grt/grt-files_lib.adb502
-rw-r--r--src/grt/grt-files_lib.ads101
-rw-r--r--src/grt/grt-main.adb2
5 files changed, 653 insertions, 535 deletions
diff --git a/src/grt/grt-files.adb b/src/grt/grt-files.adb
index 3b52ac587..0b0430ace 100644
--- a/src/grt/grt-files.adb
+++ b/src/grt/grt-files.adb
@@ -23,21 +23,11 @@
with Grt.Errors; use Grt.Errors;
with Grt.Errors_Exec; use Grt.Errors_Exec;
with Grt.Stdio; use Grt.Stdio;
-with Grt.C; use Grt.C;
with Grt.Table;
-with Grt.Options;
with System; use System;
pragma Elaborate_All (Grt.Table);
package body Grt.Files is
- subtype C_Files is Grt.Stdio.FILEs;
-
- -- The end of lines
- C_LF : constant int := 10; -- \n
- C_CR : constant int := 13; -- \r
-
- Auto_Flush : constant Boolean := False;
-
type File_Entry_Type is record
-- The corresponding C stream.
Stream : C_Files;
@@ -59,13 +49,28 @@ package body Grt.Files is
Table_Low_Bound => 1,
Table_Initial => 2);
- function Get_File (Index : Ghdl_File_Index) return C_Files is
+ function Check_File_Index (Index : Ghdl_File_Index) return Boolean is
+ begin
+ return Index in Files_Table.First .. Files_Table.Last;
+ end Check_File_Index;
+
+ function Get_File_Stream (Index : Ghdl_File_Index) return C_Files is
begin
- if Index not in Files_Table.First .. Files_Table.Last then
- Internal_Error ("get_file: bad file index");
- end if;
return Files_Table.Table (Index).Stream;
- end Get_File;
+ end Get_File_Stream;
+
+ procedure Set_File_Stream (Index : Ghdl_File_Index;
+ Stream : C_Files; Kind : Character) is
+ begin
+ Files_Table.Table (Index).Stream := Stream;
+ Files_Table.Table (Index).Kind := Kind;
+ end Set_File_Stream;
+
+ function Get_File_Signature (Index : Ghdl_File_Index)
+ return Ghdl_C_String is
+ begin
+ return Files_Table.Table (Index).Signature;
+ end Get_File_Signature;
function Is_Open (Index : Ghdl_File_Index) return Boolean is
begin
@@ -77,46 +82,14 @@ package body Grt.Files is
return Files_Table.Table (Index).Kind;
end Get_Kind;
- procedure Check_File_Mode (Index : Ghdl_File_Index; Is_Text : Boolean) is
- begin
- if Files_Table.Table (Index).Is_Text /= Is_Text then
- Internal_Error ("check_file_mode: bad file mode");
- end if;
- end Check_File_Mode;
-
- procedure Check_Read (Index : Ghdl_File_Index; Is_Text : Boolean) is
- begin
- Check_File_Mode (Index, Is_Text);
-
- -- LRM08 5.5.2 File operations
- -- It is an error if the access mode of the file object is write-only
- -- or if the file object is not open.
- if not Is_Open (Index) then
- Error_Call_Stack ("read called on a non-open file", 2);
- end if;
- if Get_Kind (Index) /= 'r' then
- Error_Call_Stack ("read called on a write-only file", 2);
- end if;
- end Check_Read;
-
- procedure Check_Write (Index : Ghdl_File_Index; Is_Text : Boolean) is
+ function Is_Text_File (Index : Ghdl_File_Index) return Boolean is
begin
- Check_File_Mode (Index, Is_Text);
-
- -- LRM08 5.5.2 File operations
- -- It is an error if the access mode of the file object is read-only
- -- or if the file object is not open.
- if not Is_Open (Index) then
- Error_Call_Stack ("write called on a non-open file", 2);
- end if;
- if Get_Kind (Index) = 'r' then
- Error_Call_Stack ("write called on a read-only file", 2);
- end if;
- end Check_Write;
+ return Files_Table.Table (Index).Is_Text;
+ end Is_Text_File;
- function Create_File
- (Is_Text : Boolean; Kind : Character; Sig : Ghdl_C_String)
- return Ghdl_File_Index is
+ function Create_File (Is_Text : Boolean;
+ Kind : Character;
+ Sig : Ghdl_C_String) return Ghdl_File_Index is
begin
Files_Table.Append ((Stream => NULL_Stream,
Signature => Sig,
@@ -126,12 +99,8 @@ package body Grt.Files is
return Files_Table.Last;
end Create_File;
- procedure Destroy_File (Is_Text : Boolean; Index : Ghdl_File_Index) is
+ procedure Destroy_File (Index : Ghdl_File_Index) is
begin
- if Get_File (Index) /= NULL_Stream then
- Internal_Error ("destroy_file");
- end if;
- Check_File_Mode (Index, Is_Text);
Files_Table.Table (Index).Is_Alive := False;
if Index = Files_Table.Last then
while Files_Table.Last >= Files_Table.First
@@ -142,415 +111,4 @@ package body Grt.Files is
end if;
end Destroy_File;
- procedure File_Error (File : Ghdl_File_Index)
- is
- pragma Unreferenced (File);
- begin
- Internal_Error ("file: IO error");
- end File_Error;
-
- function Ghdl_Text_File_Elaborate return Ghdl_File_Index is
- begin
- return Create_File (True, ' ', null);
- end Ghdl_Text_File_Elaborate;
-
- function Ghdl_File_Elaborate (Sig : Ghdl_C_String) return Ghdl_File_Index
- is
- begin
- return Create_File (False, ' ', Sig);
- end Ghdl_File_Elaborate;
-
- procedure Ghdl_Text_File_Finalize (File : Ghdl_File_Index) is
- begin
- Destroy_File (True, File);
- end Ghdl_Text_File_Finalize;
-
- procedure Ghdl_File_Finalize (File : Ghdl_File_Index) is
- begin
- Destroy_File (False, File);
- end Ghdl_File_Finalize;
-
- function Ghdl_File_Endfile (File : Ghdl_File_Index) return Boolean
- is
- Stream : C_Files;
- C : int;
- begin
- Stream := Get_File (File);
-
- -- LRM93 3.4.1 File Operations
- -- LRM08 5.5.2 File Operations
- -- It is an error if ENDFILE is called on a file object that is not
- -- open.
- if Stream = NULL_Stream then
- Error_Call_Stack ("endfile with a non-opened file", 1);
- end if;
-
- -- LRM93 3.4.1 File Operations
- -- LRM08 5.5.2 File Operations
- -- Function ENDFILE always returns TRUE for an open file object whose
- -- access mode is write-only.
- if Get_Kind (File) /= 'r' then
- return True;
- end if;
-
- if feof (Stream) /= 0 then
- return True;
- end if;
- C := fgetc (Stream);
- if C < 0 then
- return True;
- end if;
- if ungetc (C, Stream) /= C then
- Error ("internal error: ungetc");
- end if;
- return False;
- end Ghdl_File_Endfile;
-
- Sig_Header : constant String := "#GHDL-BINARY-FILE-0.0" & Nl;
-
- function File_Open (File : Ghdl_File_Index;
- Mode : Ghdl_I32;
- Str : Std_String_Ptr)
- return Ghdl_I32
- is
- Name : String (1 .. Integer (Str.Bounds.Dim_1.Length) + 1);
- Str_Mode : String (1 .. 3);
- F : C_Files;
- Sig : Ghdl_C_String;
- Sig_Len : Natural;
- Kind : Character;
- begin
- F := Get_File (File);
-
- if F /= NULL_Stream then
- -- File was already open.
- return Status_Error;
- end if;
-
- -- Copy file name and convert it to a C string (NUL terminated).
- for I in 1 .. Str.Bounds.Dim_1.Length loop
- Name (Natural (I)) := Str.Base (I - 1);
- end loop;
- Name (Name'Last) := NUL;
-
- case Mode is
- when Read_Mode =>
- Kind := 'r';
- when Write_Mode =>
- Kind := 'w';
- when Append_Mode =>
- Kind := 'a';
- when others =>
- -- Bad mode, cannot happen.
- Internal_Error ("file_open: bad open mode");
- end case;
-
- if Name = "STD_INPUT" & NUL then
- if Mode /= Read_Mode then
- return Mode_Error;
- end if;
- F := stdin;
- elsif Name = "STD_OUTPUT" & NUL then
- if Mode /= Write_Mode then
- return Mode_Error;
- end if;
- F := stdout;
- else
- Str_Mode (1) := Kind;
- if Files_Table.Table (File).Is_Text then
- Str_Mode (2) := NUL;
- else
- Str_Mode (2) := 'b';
- Str_Mode (3) := NUL;
- end if;
- F := fopen (Name'Address, Str_Mode'Address);
- if F = NULL_Stream then
- return Name_Error;
- end if;
- if Grt.Options.Unbuffered_Writes and Mode /= Read_Mode then
- setbuf (F, NULL_voids);
- end if;
- end if;
-
- Sig := Files_Table.Table (File).Signature;
- if Sig /= null then
- Sig_Len := strlen (Sig);
- case Mode is
- when Write_Mode =>
- if fwrite (Sig_Header'Address, 1, Sig_Header'Length, F)
- /= Sig_Header'Length
- then
- File_Error (File);
- end if;
- if fwrite (Sig (1)'Address, 1, size_t (Sig_Len), F)
- /= size_t (Sig_Len)
- then
- File_Error (File);
- end if;
- when Read_Mode =>
- declare
- Hdr : String (1 .. Sig_Header'Length);
- Sig_Buf : String (1 .. Sig_Len);
- begin
- if fread (Hdr'Address, 1, Hdr'Length, F) /= Hdr'Length then
- File_Error (File);
- end if;
- if Hdr /= Sig_Header then
- File_Error (File);
- end if;
- if fread (Sig_Buf'Address, 1, Sig_Buf'Length, F)
- /= Sig_Buf'Length
- then
- File_Error (File);
- end if;
- if Sig_Buf /= Sig (1 .. Sig_Len) then
- File_Error (File);
- end if;
- end;
- when Append_Mode =>
- null;
- when others =>
- null;
- end case;
- end if;
-
- Files_Table.Table (File).Stream := F;
- Files_Table.Table (File).Kind := Kind;
-
- return Open_Ok;
- end File_Open;
-
- procedure Error_Open (Str : Std_String_Ptr)
- is
- Bt : Backtrace_Addrs;
- begin
- Save_Backtrace (Bt, 2);
- Error_S ("cannot open file """);
- Diag_C_Std (Str.Base (0 .. Str.Bounds.Dim_1.Length - 1));
- Diag_C ('"');
- Error_E_Call_Stack (Bt);
- end Error_Open;
-
- procedure Ghdl_Text_File_Open
- (File : Ghdl_File_Index; Mode : Ghdl_I32; Str : Std_String_Ptr)
- is
- Res : Ghdl_I32;
- begin
- Check_File_Mode (File, True);
-
- Res := File_Open (File, Mode, Str);
-
- if Res /= Open_Ok then
- Error_Open (Str);
- end if;
- end Ghdl_Text_File_Open;
-
- procedure Ghdl_File_Open
- (File : Ghdl_File_Index; Mode : Ghdl_I32; Str : Std_String_Ptr)
- is
- Res : Ghdl_I32;
- begin
- Check_File_Mode (File, False);
-
- Res := File_Open (File, Mode, Str);
-
- if Res /= Open_Ok then
- Error_Open (Str);
- end if;
- end Ghdl_File_Open;
-
- function Ghdl_Text_File_Open_Status
- (File : Ghdl_File_Index; Mode : Ghdl_I32; Str : Std_String_Ptr)
- return Ghdl_I32
- is
- begin
- Check_File_Mode (File, True);
- return File_Open (File, Mode, Str);
- end Ghdl_Text_File_Open_Status;
-
- function Ghdl_File_Open_Status
- (File : Ghdl_File_Index; Mode : Ghdl_I32; Str : Std_String_Ptr)
- return Ghdl_I32
- is
- begin
- Check_File_Mode (File, False);
- return File_Open (File, Mode, Str);
- end Ghdl_File_Open_Status;
-
- procedure Ghdl_Text_Write (File : Ghdl_File_Index; Str : Std_String_Ptr)
- is
- Res : C_Files;
- Len : size_t;
- R : size_t;
- begin
- Res := Get_File (File);
- Check_Write (File, True);
-
- Len := size_t (Str.Bounds.Dim_1.Length);
- if Len = 0 then
- return;
- end if;
-
- R := fwrite (Str.Base (0)'Address, Len, 1, Res);
- if R /= 1 then
- Error ("text_write failed");
- end if;
-
- if Auto_Flush then
- fflush (Res);
- end if;
- end Ghdl_Text_Write;
-
- procedure Ghdl_Write_Scalar (File : Ghdl_File_Index;
- Ptr : Ghdl_Ptr;
- Length : Ghdl_Index_Type)
- is
- Res : C_Files;
- R : size_t;
- begin
- Res := Get_File (File);
- Check_Write (File, False);
-
- R := fwrite (System.Address (Ptr), size_t (Length), 1, Res);
- if R /= 1 then
- Error ("write_scalar failed");
- end if;
- if Auto_Flush then
- fflush (Res);
- end if;
- end Ghdl_Write_Scalar;
-
- procedure Ghdl_Read_Scalar (File : Ghdl_File_Index;
- Ptr : Ghdl_Ptr;
- Length : Ghdl_Index_Type)
- is
- Res : C_Files;
- R : size_t;
- begin
- Res := Get_File (File);
- Check_Read (File, False);
-
- R := fread (System.Address (Ptr), size_t (Length), 1, Res);
- if R /= 1 then
- Error ("read_scalar failed");
- end if;
- end Ghdl_Read_Scalar;
-
- function Ghdl_Text_Read_Length (File : Ghdl_File_Index;
- Str : Std_String_Ptr)
- return Std_Integer
- is
- Stream : C_Files;
- C : int;
- Len : Ghdl_Index_Type;
- begin
- Stream := Get_File (File);
- Check_Read (File, True);
-
- Len := Str.Bounds.Dim_1.Length;
- -- Read until EOL (or EOF).
- -- Store as much as possible.
- for I in Ghdl_Index_Type loop
- C := fgetc (Stream);
- if C < 0 then
- Error_Call_Stack ("read: end of file reached", 1);
- return Std_Integer (I);
- end if;
- if I < Len then
- Str.Base (I) := Character'Val (C);
- end if;
- -- End of line is '\n' or LF or character # 10.
- if C = 10 then
- return Std_Integer (I + 1);
- end if;
- end loop;
- return 0;
- end Ghdl_Text_Read_Length;
-
- procedure Ghdl_Untruncated_Text_Read
- (File : Ghdl_File_Index; Str : Std_String_Ptr; Len : Std_Integer_Acc)
- is
- Stream : C_Files;
- Max_Len : int;
- C : int;
- L : Ghdl_Index_Type;
- begin
- Stream := Get_File (File);
- Check_Read (File, True);
-
- Max_Len := int (Str.Bounds.Dim_1.Length);
-
- -- Read at most LEN characters, stop at EOL.
- L := 0;
- for I in 1 .. Max_Len loop
- C := fgetc (Stream);
- exit when C < 0;
- -- Be nice with DOS files: handle CR/CR+LF/LF.
- -- Note: LF+CR is not handled, so that on unix we don't need
- -- to read the next line.
- -- Always return LF as end of line.
- if C = C_CR then
- C := fgetc (Stream);
- if C > 0 and C /= C_LF then
- C := ungetc (C, Stream);
- pragma Assert (C >= 0);
- end if;
- C := C_LF;
- end if;
- Str.Base (L) := Character'Val (C);
- L := L + 1;
- exit when C = C_LF;
- end loop;
-
- Len.all := Std_Integer (L);
- end Ghdl_Untruncated_Text_Read;
-
- procedure File_Close (File : Ghdl_File_Index; Is_Text : Boolean)
- is
- Stream : C_Files;
- begin
- Stream := Get_File (File);
- Check_File_Mode (File, Is_Text);
-
- -- LRM 3.4.1 File Operations
- -- If F is not associated with an external file, then FILE_CLOSE has
- -- no effect.
- if Stream = NULL_Stream then
- return;
- end if;
-
- if fclose (Stream) /= 0 then
- Internal_Error ("file_close: fclose error");
- end if;
- Files_Table.Table (File).Stream := NULL_Stream;
- end File_Close;
-
- procedure Ghdl_Text_File_Close (File : Ghdl_File_Index) is
- begin
- File_Close (File, True);
- end Ghdl_Text_File_Close;
-
- procedure Ghdl_File_Close (File : Ghdl_File_Index) is
- begin
- File_Close (File, False);
- end Ghdl_File_Close;
-
- procedure Ghdl_File_Flush (File : Ghdl_File_Index)
- is
- Stream : C_Files;
- begin
- Stream := Get_File (File);
-
- -- LRM08 5.5.2 File Operations
- -- For the WRITE and FLUSH procedures, it is an error if the access
- -- mode of the file object is read-only or if the file is not open.
- if Stream = NULL_Stream then
- Error_Call_Stack ("flush called on a non-open file", 1);
- end if;
- if Get_Kind (File) = 'r' then
- Error_Call_Stack ("flush called on a read-only file", 1);
- end if;
-
- fflush (Stream);
- end Ghdl_File_Flush;
end Grt.Files;
diff --git a/src/grt/grt-files.ads b/src/grt/grt-files.ads
index da22f0c1d..2aba8ad1e 100644
--- a/src/grt/grt-files.ads
+++ b/src/grt/grt-files.ads
@@ -20,10 +20,11 @@
-- covered by the GNU General Public License. This exception does not
-- however invalidate any other reasons why the executable file might be
-- covered by the GNU Public License.
-with Grt.Types; use Grt.Types;
-with Grt.Vhdl_Types; use Grt.Vhdl_Types;
with Interfaces;
+with Grt.Types; use Grt.Types;
+with Grt.Stdio;
+
package Grt.Files is
type Ghdl_File_Index is new Interfaces.Integer_32;
@@ -38,76 +39,32 @@ package Grt.Files is
Name_Error : constant Ghdl_I32 := 2;
Mode_Error : constant Ghdl_I32 := 3;
- -- General files.
- function Ghdl_File_Endfile (File : Ghdl_File_Index) return Boolean;
-
- -- Elaboration.
- function Ghdl_Text_File_Elaborate return Ghdl_File_Index;
- function Ghdl_File_Elaborate (Sig : Ghdl_C_String) return Ghdl_File_Index;
-
- -- Finalization.
- procedure Ghdl_Text_File_Finalize (File : Ghdl_File_Index);
- procedure Ghdl_File_Finalize (File : Ghdl_File_Index);
-
- -- Subprograms.
- procedure Ghdl_Text_File_Open
- (File : Ghdl_File_Index; Mode : Ghdl_I32; Str : Std_String_Ptr);
- function Ghdl_Text_File_Open_Status
- (File : Ghdl_File_Index; Mode : Ghdl_I32; Str : Std_String_Ptr)
- return Ghdl_I32;
-
- procedure Ghdl_File_Open
- (File : Ghdl_File_Index; Mode : Ghdl_I32; Str : Std_String_Ptr);
- function Ghdl_File_Open_Status
- (File : Ghdl_File_Index; Mode : Ghdl_I32; Str : Std_String_Ptr)
- return Ghdl_I32;
-
- procedure Ghdl_Text_Write (File : Ghdl_File_Index; Str : Std_String_Ptr);
- procedure Ghdl_Write_Scalar (File : Ghdl_File_Index;
- Ptr : Ghdl_Ptr;
- Length : Ghdl_Index_Type);
-
- procedure Ghdl_Read_Scalar (File : Ghdl_File_Index;
- Ptr : Ghdl_Ptr;
- Length : Ghdl_Index_Type);
-
- function Ghdl_Text_Read_Length
- (File : Ghdl_File_Index; Str : Std_String_Ptr) return Std_Integer;
-
- procedure Ghdl_Untruncated_Text_Read
- (File : Ghdl_File_Index; Str : Std_String_Ptr; Len : Std_Integer_Acc);
-
- procedure Ghdl_Text_File_Close (File : Ghdl_File_Index);
- procedure Ghdl_File_Close (File : Ghdl_File_Index);
-
- procedure Ghdl_File_Flush (File : Ghdl_File_Index);
-private
- pragma Export (Ada, Ghdl_File_Endfile, "__ghdl_file_endfile");
+ subtype C_Files is Grt.Stdio.FILEs;
- pragma Export (C, Ghdl_Text_File_Elaborate, "__ghdl_text_file_elaborate");
- pragma Export (C, Ghdl_File_Elaborate, "__ghdl_file_elaborate");
+ -- Create a file entry (add an entry to the table).
+ -- The file is not named and not opened.
+ function Create_File (Is_Text : Boolean;
+ Kind : Character;
+ Sig : Ghdl_C_String) return Ghdl_File_Index;
- pragma Export (C, Ghdl_Text_File_Finalize, "__ghdl_text_file_finalize");
- pragma Export (C, Ghdl_File_Finalize, "__ghdl_file_finalize");
- pragma Export (C, Ghdl_Text_File_Open, "__ghdl_text_file_open");
- pragma Export (C, Ghdl_Text_File_Open_Status,
- "__ghdl_text_file_open_status");
+ -- Check INDEX is a valid index.
+ function Check_File_Index (Index : Ghdl_File_Index) return Boolean;
- pragma Export (C, Ghdl_File_Open, "__ghdl_file_open");
- pragma Export (C, Ghdl_File_Open_Status, "__ghdl_file_open_status");
+ -- Return the file for INDEX.
+ function Get_File_Stream (Index : Ghdl_File_Index) return C_Files;
+ procedure Set_File_Stream (Index : Ghdl_File_Index;
+ Stream : C_Files; Kind : Character);
- pragma Export (C, Ghdl_Text_Write, "__ghdl_text_write");
- pragma Export (C, Ghdl_Write_Scalar, "__ghdl_write_scalar");
+ -- Get the file signature.
+ function Get_File_Signature (Index : Ghdl_File_Index) return Ghdl_C_String;
- pragma Export (C, Ghdl_Read_Scalar, "__ghdl_read_scalar");
+ -- Return True iff file for INDEX is open.
+ function Is_Open (Index : Ghdl_File_Index) return Boolean;
- pragma Export (C, Ghdl_Text_Read_Length, "__ghdl_text_read_length");
- pragma Export (C, Ghdl_Untruncated_Text_Read,
- "std__textio__untruncated_text_read");
+ function Get_Kind (Index : Ghdl_File_Index) return Character;
- pragma Export (C, Ghdl_Text_File_Close, "__ghdl_text_file_close");
- pragma Export (C, Ghdl_File_Close, "__ghdl_file_close");
+ function Is_Text_File (Index : Ghdl_File_Index) return Boolean;
- pragma Export (C, Ghdl_File_Flush, "__ghdl_file_flush");
+ procedure Destroy_File (Index : Ghdl_File_Index);
end Grt.Files;
diff --git a/src/grt/grt-files_lib.adb b/src/grt/grt-files_lib.adb
new file mode 100644
index 000000000..02a472bd1
--- /dev/null
+++ b/src/grt/grt-files_lib.adb
@@ -0,0 +1,502 @@
+-- GHDL Run Time (GRT) - VHDL files subprograms.
+-- Copyright (C) 2002 - 2014 Tristan Gingold
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 2 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see <gnu.org/licenses>.
+--
+-- As a special exception, if other files instantiate generics from this
+-- unit, or you link this unit with other files to produce an executable,
+-- this unit does not by itself cause the resulting executable to be
+-- covered by the GNU General Public License. This exception does not
+-- however invalidate any other reasons why the executable file might be
+-- covered by the GNU Public License.
+with System; use System;
+
+with Grt.Errors; use Grt.Errors;
+with Grt.Errors_Exec; use Grt.Errors_Exec;
+with Grt.Stdio; use Grt.Stdio;
+with Grt.C; use Grt.C;
+with Grt.Options;
+
+package body Grt.Files_Lib is
+ -- The end of lines
+ C_LF : constant int := 10; -- \n
+ C_CR : constant int := 13; -- \r
+
+ Auto_Flush : constant Boolean := False;
+
+ function Get_File (Index : Ghdl_File_Index) return C_Files is
+ begin
+ if not Check_File_Index (Index) then
+ Internal_Error ("get_file: bad file index");
+ end if;
+ return Grt.Files.Get_File_Stream (Index);
+ end Get_File;
+
+ procedure Check_File_Mode (Index : Ghdl_File_Index; Is_Text : Boolean) is
+ begin
+ if Is_Text_File (Index) /= Is_Text then
+ Internal_Error ("check_file_mode: bad file mode");
+ end if;
+ end Check_File_Mode;
+
+ procedure Check_Read (Index : Ghdl_File_Index; Is_Text : Boolean) is
+ begin
+ Check_File_Mode (Index, Is_Text);
+
+ -- LRM08 5.5.2 File operations
+ -- It is an error if the access mode of the file object is write-only
+ -- or if the file object is not open.
+ if not Is_Open (Index) then
+ Error_Call_Stack ("read called on a non-open file", 2);
+ end if;
+ if Get_Kind (Index) /= 'r' then
+ Error_Call_Stack ("read called on a write-only file", 2);
+ end if;
+ end Check_Read;
+
+ procedure Check_Write (Index : Ghdl_File_Index; Is_Text : Boolean) is
+ begin
+ Check_File_Mode (Index, Is_Text);
+
+ -- LRM08 5.5.2 File operations
+ -- It is an error if the access mode of the file object is read-only
+ -- or if the file object is not open.
+ if not Is_Open (Index) then
+ Error_Call_Stack ("write called on a non-open file", 2);
+ end if;
+ if Get_Kind (Index) = 'r' then
+ Error_Call_Stack ("write called on a read-only file", 2);
+ end if;
+ end Check_Write;
+
+ procedure Destroy_File (Is_Text : Boolean; Index : Ghdl_File_Index) is
+ begin
+ if Get_File (Index) /= NULL_Stream then
+ Internal_Error ("destroy_file");
+ end if;
+ Check_File_Mode (Index, Is_Text);
+ Destroy_File (Index);
+ end Destroy_File;
+
+ procedure File_Error (File : Ghdl_File_Index)
+ is
+ pragma Unreferenced (File);
+ begin
+ Internal_Error ("file: IO error");
+ end File_Error;
+
+ function Ghdl_Text_File_Elaborate return Ghdl_File_Index is
+ begin
+ return Create_File (True, ' ', null);
+ end Ghdl_Text_File_Elaborate;
+
+ function Ghdl_File_Elaborate (Sig : Ghdl_C_String) return Ghdl_File_Index
+ is
+ begin
+ return Create_File (False, ' ', Sig);
+ end Ghdl_File_Elaborate;
+
+ procedure Ghdl_Text_File_Finalize (File : Ghdl_File_Index) is
+ begin
+ Destroy_File (True, File);
+ end Ghdl_Text_File_Finalize;
+
+ procedure Ghdl_File_Finalize (File : Ghdl_File_Index) is
+ begin
+ Destroy_File (False, File);
+ end Ghdl_File_Finalize;
+
+ function Ghdl_File_Endfile (File : Ghdl_File_Index) return Boolean
+ is
+ Stream : C_Files;
+ C : int;
+ begin
+ Stream := Get_File (File);
+
+ -- LRM93 3.4.1 File Operations
+ -- LRM08 5.5.2 File Operations
+ -- It is an error if ENDFILE is called on a file object that is not
+ -- open.
+ if Stream = NULL_Stream then
+ Error_Call_Stack ("endfile with a non-opened file", 1);
+ end if;
+
+ -- LRM93 3.4.1 File Operations
+ -- LRM08 5.5.2 File Operations
+ -- Function ENDFILE always returns TRUE for an open file object whose
+ -- access mode is write-only.
+ if Get_Kind (File) /= 'r' then
+ return True;
+ end if;
+
+ if feof (Stream) /= 0 then
+ return True;
+ end if;
+ C := fgetc (Stream);
+ if C < 0 then
+ return True;
+ end if;
+ if ungetc (C, Stream) /= C then
+ Error ("internal error: ungetc");
+ end if;
+ return False;
+ end Ghdl_File_Endfile;
+
+ Sig_Header : constant String := "#GHDL-BINARY-FILE-0.0" & Nl;
+
+ function File_Open (File : Ghdl_File_Index;
+ Mode : Ghdl_I32;
+ Str : Std_String_Ptr)
+ return Ghdl_I32
+ is
+ Name : String (1 .. Integer (Str.Bounds.Dim_1.Length) + 1);
+ Str_Mode : String (1 .. 3);
+ F : C_Files;
+ Sig : Ghdl_C_String;
+ Sig_Len : Natural;
+ Kind : Character;
+ begin
+ F := Get_File (File);
+
+ if F /= NULL_Stream then
+ -- File was already open.
+ return Status_Error;
+ end if;
+
+ -- Copy file name and convert it to a C string (NUL terminated).
+ for I in 1 .. Str.Bounds.Dim_1.Length loop
+ Name (Natural (I)) := Str.Base (I - 1);
+ end loop;
+ Name (Name'Last) := NUL;
+
+ case Mode is
+ when Read_Mode =>
+ Kind := 'r';
+ when Write_Mode =>
+ Kind := 'w';
+ when Append_Mode =>
+ Kind := 'a';
+ when others =>
+ -- Bad mode, cannot happen.
+ Internal_Error ("file_open: bad open mode");
+ end case;
+
+ if Name = "STD_INPUT" & NUL then
+ if Mode /= Read_Mode then
+ return Mode_Error;
+ end if;
+ F := stdin;
+ elsif Name = "STD_OUTPUT" & NUL then
+ if Mode /= Write_Mode then
+ return Mode_Error;
+ end if;
+ F := stdout;
+ else
+ Str_Mode (1) := Kind;
+ if Is_Text_File (File) then
+ Str_Mode (2) := NUL;
+ else
+ Str_Mode (2) := 'b';
+ Str_Mode (3) := NUL;
+ end if;
+ F := fopen (Name'Address, Str_Mode'Address);
+ if F = NULL_Stream then
+ return Name_Error;
+ end if;
+ if Grt.Options.Unbuffered_Writes and Mode /= Read_Mode then
+ setbuf (F, NULL_voids);
+ end if;
+ end if;
+
+ Sig := Get_File_Signature (File);
+ if Sig /= null then
+ Sig_Len := strlen (Sig);
+ case Mode is
+ when Write_Mode =>
+ if fwrite (Sig_Header'Address, 1, Sig_Header'Length, F)
+ /= Sig_Header'Length
+ then
+ File_Error (File);
+ end if;
+ if fwrite (Sig (1)'Address, 1, size_t (Sig_Len), F)
+ /= size_t (Sig_Len)
+ then
+ File_Error (File);
+ end if;
+ when Read_Mode =>
+ declare
+ Hdr : String (1 .. Sig_Header'Length);
+ Sig_Buf : String (1 .. Sig_Len);
+ begin
+ if fread (Hdr'Address, 1, Hdr'Length, F) /= Hdr'Length then
+ File_Error (File);
+ end if;
+ if Hdr /= Sig_Header then
+ File_Error (File);
+ end if;
+ if fread (Sig_Buf'Address, 1, Sig_Buf'Length, F)
+ /= Sig_Buf'Length
+ then
+ File_Error (File);
+ end if;
+ if Sig_Buf /= Sig (1 .. Sig_Len) then
+ File_Error (File);
+ end if;
+ end;
+ when Append_Mode =>
+ null;
+ when others =>
+ null;
+ end case;
+ end if;
+
+ Set_File_Stream (File, F, Kind);
+
+ return Open_Ok;
+ end File_Open;
+
+ procedure Error_Open (Str : Std_String_Ptr)
+ is
+ Bt : Backtrace_Addrs;
+ begin
+ Save_Backtrace (Bt, 2);
+ Error_S ("cannot open file """);
+ Diag_C_Std (Str.Base (0 .. Str.Bounds.Dim_1.Length - 1));
+ Diag_C ('"');
+ Error_E_Call_Stack (Bt);
+ end Error_Open;
+
+ procedure Ghdl_Text_File_Open
+ (File : Ghdl_File_Index; Mode : Ghdl_I32; Str : Std_String_Ptr)
+ is
+ Res : Ghdl_I32;
+ begin
+ Check_File_Mode (File, True);
+
+ Res := File_Open (File, Mode, Str);
+
+ if Res /= Open_Ok then
+ Error_Open (Str);
+ end if;
+ end Ghdl_Text_File_Open;
+
+ procedure Ghdl_File_Open
+ (File : Ghdl_File_Index; Mode : Ghdl_I32; Str : Std_String_Ptr)
+ is
+ Res : Ghdl_I32;
+ begin
+ Check_File_Mode (File, False);
+
+ Res := File_Open (File, Mode, Str);
+
+ if Res /= Open_Ok then
+ Error_Open (Str);
+ end if;
+ end Ghdl_File_Open;
+
+ function Ghdl_Text_File_Open_Status
+ (File : Ghdl_File_Index; Mode : Ghdl_I32; Str : Std_String_Ptr)
+ return Ghdl_I32
+ is
+ begin
+ Check_File_Mode (File, True);
+ return File_Open (File, Mode, Str);
+ end Ghdl_Text_File_Open_Status;
+
+ function Ghdl_File_Open_Status
+ (File : Ghdl_File_Index; Mode : Ghdl_I32; Str : Std_String_Ptr)
+ return Ghdl_I32
+ is
+ begin
+ Check_File_Mode (File, False);
+ return File_Open (File, Mode, Str);
+ end Ghdl_File_Open_Status;
+
+ procedure Ghdl_Text_Write (File : Ghdl_File_Index; Str : Std_String_Ptr)
+ is
+ Res : C_Files;
+ Len : size_t;
+ R : size_t;
+ begin
+ Res := Get_File (File);
+ Check_Write (File, True);
+
+ Len := size_t (Str.Bounds.Dim_1.Length);
+ if Len = 0 then
+ return;
+ end if;
+
+ R := fwrite (Str.Base (0)'Address, Len, 1, Res);
+ if R /= 1 then
+ Error ("text_write failed");
+ end if;
+
+ if Auto_Flush then
+ fflush (Res);
+ end if;
+ end Ghdl_Text_Write;
+
+ procedure Ghdl_Write_Scalar (File : Ghdl_File_Index;
+ Ptr : Ghdl_Ptr;
+ Length : Ghdl_Index_Type)
+ is
+ Res : C_Files;
+ R : size_t;
+ begin
+ Res := Get_File (File);
+ Check_Write (File, False);
+
+ R := fwrite (System.Address (Ptr), size_t (Length), 1, Res);
+ if R /= 1 then
+ Error ("write_scalar failed");
+ end if;
+ if Auto_Flush then
+ fflush (Res);
+ end if;
+ end Ghdl_Write_Scalar;
+
+ procedure Ghdl_Read_Scalar (File : Ghdl_File_Index;
+ Ptr : Ghdl_Ptr;
+ Length : Ghdl_Index_Type)
+ is
+ Res : C_Files;
+ R : size_t;
+ begin
+ Res := Get_File (File);
+ Check_Read (File, False);
+
+ R := fread (System.Address (Ptr), size_t (Length), 1, Res);
+ if R /= 1 then
+ Error ("read_scalar failed");
+ end if;
+ end Ghdl_Read_Scalar;
+
+ function Ghdl_Text_Read_Length (File : Ghdl_File_Index;
+ Str : Std_String_Ptr)
+ return Std_Integer
+ is
+ Stream : C_Files;
+ C : int;
+ Len : Ghdl_Index_Type;
+ begin
+ Stream := Get_File (File);
+ Check_Read (File, True);
+
+ Len := Str.Bounds.Dim_1.Length;
+ -- Read until EOL (or EOF).
+ -- Store as much as possible.
+ for I in Ghdl_Index_Type loop
+ C := fgetc (Stream);
+ if C < 0 then
+ Error_Call_Stack ("read: end of file reached", 1);
+ return Std_Integer (I);
+ end if;
+ if I < Len then
+ Str.Base (I) := Character'Val (C);
+ end if;
+ -- End of line is '\n' or LF or character # 10.
+ if C = 10 then
+ return Std_Integer (I + 1);
+ end if;
+ end loop;
+ return 0;
+ end Ghdl_Text_Read_Length;
+
+ procedure Ghdl_Untruncated_Text_Read
+ (File : Ghdl_File_Index; Str : Std_String_Ptr; Len : Std_Integer_Acc)
+ is
+ Stream : C_Files;
+ Max_Len : int;
+ C : int;
+ L : Ghdl_Index_Type;
+ begin
+ Stream := Get_File (File);
+ Check_Read (File, True);
+
+ Max_Len := int (Str.Bounds.Dim_1.Length);
+
+ -- Read at most LEN characters, stop at EOL.
+ L := 0;
+ for I in 1 .. Max_Len loop
+ C := fgetc (Stream);
+ exit when C < 0;
+ -- Be nice with DOS files: handle CR/CR+LF/LF.
+ -- Note: LF+CR is not handled, so that on unix we don't need
+ -- to read the next line.
+ -- Always return LF as end of line.
+ if C = C_CR then
+ C := fgetc (Stream);
+ if C > 0 and C /= C_LF then
+ C := ungetc (C, Stream);
+ pragma Assert (C >= 0);
+ end if;
+ C := C_LF;
+ end if;
+ Str.Base (L) := Character'Val (C);
+ L := L + 1;
+ exit when C = C_LF;
+ end loop;
+
+ Len.all := Std_Integer (L);
+ end Ghdl_Untruncated_Text_Read;
+
+ procedure File_Close (File : Ghdl_File_Index; Is_Text : Boolean)
+ is
+ Stream : C_Files;
+ begin
+ Stream := Get_File (File);
+ Check_File_Mode (File, Is_Text);
+
+ -- LRM 3.4.1 File Operations
+ -- If F is not associated with an external file, then FILE_CLOSE has
+ -- no effect.
+ if Stream = NULL_Stream then
+ return;
+ end if;
+
+ if fclose (Stream) /= 0 then
+ Internal_Error ("file_close: fclose error");
+ end if;
+ Set_File_Stream (File, NULL_Stream, ' ');
+ end File_Close;
+
+ procedure Ghdl_Text_File_Close (File : Ghdl_File_Index) is
+ begin
+ File_Close (File, True);
+ end Ghdl_Text_File_Close;
+
+ procedure Ghdl_File_Close (File : Ghdl_File_Index) is
+ begin
+ File_Close (File, False);
+ end Ghdl_File_Close;
+
+ procedure Ghdl_File_Flush (File : Ghdl_File_Index)
+ is
+ Stream : C_Files;
+ begin
+ Stream := Get_File (File);
+
+ -- LRM08 5.5.2 File Operations
+ -- For the WRITE and FLUSH procedures, it is an error if the access
+ -- mode of the file object is read-only or if the file is not open.
+ if Stream = NULL_Stream then
+ Error_Call_Stack ("flush called on a non-open file", 1);
+ end if;
+ if Get_Kind (File) = 'r' then
+ Error_Call_Stack ("flush called on a read-only file", 1);
+ end if;
+
+ fflush (Stream);
+ end Ghdl_File_Flush;
+end Grt.Files_Lib;
diff --git a/src/grt/grt-files_lib.ads b/src/grt/grt-files_lib.ads
new file mode 100644
index 000000000..6925d07e3
--- /dev/null
+++ b/src/grt/grt-files_lib.ads
@@ -0,0 +1,101 @@
+-- GHDL Run Time (GRT) - VHDL files subprograms.
+-- Copyright (C) 2002 - 2023 Tristan Gingold
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 2 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see <gnu.org/licenses>.
+--
+-- As a special exception, if other files instantiate generics from this
+-- unit, or you link this unit with other files to produce an executable,
+-- this unit does not by itself cause the resulting executable to be
+-- covered by the GNU General Public License. This exception does not
+-- however invalidate any other reasons why the executable file might be
+-- covered by the GNU Public License.
+
+with Grt.Types; use Grt.Types;
+with Grt.Vhdl_Types; use Grt.Vhdl_Types;
+with Grt.Files; use Grt.Files;
+
+package Grt.Files_Lib is
+ -- General files.
+ function Ghdl_File_Endfile (File : Ghdl_File_Index) return Boolean;
+
+ -- Elaboration.
+ function Ghdl_Text_File_Elaborate return Ghdl_File_Index;
+ function Ghdl_File_Elaborate (Sig : Ghdl_C_String) return Ghdl_File_Index;
+
+ -- Finalization.
+ procedure Ghdl_Text_File_Finalize (File : Ghdl_File_Index);
+ procedure Ghdl_File_Finalize (File : Ghdl_File_Index);
+
+ -- Subprograms.
+ procedure Ghdl_Text_File_Open
+ (File : Ghdl_File_Index; Mode : Ghdl_I32; Str : Std_String_Ptr);
+ function Ghdl_Text_File_Open_Status
+ (File : Ghdl_File_Index; Mode : Ghdl_I32; Str : Std_String_Ptr)
+ return Ghdl_I32;
+
+ procedure Ghdl_File_Open
+ (File : Ghdl_File_Index; Mode : Ghdl_I32; Str : Std_String_Ptr);
+ function Ghdl_File_Open_Status
+ (File : Ghdl_File_Index; Mode : Ghdl_I32; Str : Std_String_Ptr)
+ return Ghdl_I32;
+
+ procedure Ghdl_Text_Write (File : Ghdl_File_Index; Str : Std_String_Ptr);
+ procedure Ghdl_Write_Scalar (File : Ghdl_File_Index;
+ Ptr : Ghdl_Ptr;
+ Length : Ghdl_Index_Type);
+
+ procedure Ghdl_Read_Scalar (File : Ghdl_File_Index;
+ Ptr : Ghdl_Ptr;
+ Length : Ghdl_Index_Type);
+
+ function Ghdl_Text_Read_Length
+ (File : Ghdl_File_Index; Str : Std_String_Ptr) return Std_Integer;
+
+ procedure Ghdl_Untruncated_Text_Read
+ (File : Ghdl_File_Index; Str : Std_String_Ptr; Len : Std_Integer_Acc);
+
+ procedure Ghdl_Text_File_Close (File : Ghdl_File_Index);
+ procedure Ghdl_File_Close (File : Ghdl_File_Index);
+
+ procedure Ghdl_File_Flush (File : Ghdl_File_Index);
+private
+ pragma Export (Ada, Ghdl_File_Endfile, "__ghdl_file_endfile");
+
+ pragma Export (C, Ghdl_Text_File_Elaborate, "__ghdl_text_file_elaborate");
+ pragma Export (C, Ghdl_File_Elaborate, "__ghdl_file_elaborate");
+
+ pragma Export (C, Ghdl_Text_File_Finalize, "__ghdl_text_file_finalize");
+ pragma Export (C, Ghdl_File_Finalize, "__ghdl_file_finalize");
+
+ pragma Export (C, Ghdl_Text_File_Open, "__ghdl_text_file_open");
+ pragma Export (C, Ghdl_Text_File_Open_Status,
+ "__ghdl_text_file_open_status");
+
+ pragma Export (C, Ghdl_File_Open, "__ghdl_file_open");
+ pragma Export (C, Ghdl_File_Open_Status, "__ghdl_file_open_status");
+
+ pragma Export (C, Ghdl_Text_Write, "__ghdl_text_write");
+ pragma Export (C, Ghdl_Write_Scalar, "__ghdl_write_scalar");
+
+ pragma Export (C, Ghdl_Read_Scalar, "__ghdl_read_scalar");
+
+ pragma Export (C, Ghdl_Text_Read_Length, "__ghdl_text_read_length");
+ pragma Export (C, Ghdl_Untruncated_Text_Read,
+ "std__textio__untruncated_text_read");
+
+ pragma Export (C, Ghdl_Text_File_Close, "__ghdl_text_file_close");
+ pragma Export (C, Ghdl_File_Close, "__ghdl_file_close");
+
+ pragma Export (C, Ghdl_File_Flush, "__ghdl_file_flush");
+end Grt.Files_Lib;
diff --git a/src/grt/grt-main.adb b/src/grt/grt-main.adb
index 35161f686..d9cc5d1b4 100644
--- a/src/grt/grt-main.adb
+++ b/src/grt/grt-main.adb
@@ -34,7 +34,7 @@ with Grt.Change_Generics;
-- These are subprograms called only from GHDL generated code.
-- They are with'ed in order to be present in the binary.
pragma Warnings (Off);
-with Grt.Files;
+with Grt.Files_Lib;
with Grt.Types;
with Grt.Lib;
with Grt.Shadow_Ieee;