1-- GHDL Run Time (GRT) - VHDL files subprograms. 2-- Copyright (C) 2002 - 2014 Tristan Gingold 3-- 4-- This program is free software: you can redistribute it and/or modify 5-- it under the terms of the GNU General Public License as published by 6-- the Free Software Foundation, either version 2 of the License, or 7-- (at your option) any later version. 8-- 9-- This program is distributed in the hope that it will be useful, 10-- but WITHOUT ANY WARRANTY; without even the implied warranty of 11-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12-- GNU General Public License for more details. 13-- 14-- You should have received a copy of the GNU General Public License 15-- along with this program. If not, see <gnu.org/licenses>. 16-- 17-- As a special exception, if other files instantiate generics from this 18-- unit, or you link this unit with other files to produce an executable, 19-- this unit does not by itself cause the resulting executable to be 20-- covered by the GNU General Public License. This exception does not 21-- however invalidate any other reasons why the executable file might be 22-- covered by the GNU Public License. 23with Grt.Stdio; use Grt.Stdio; 24with Grt.C; use Grt.C; 25with Grt.Table; 26with System; use System; 27pragma Elaborate_All (Grt.Table); 28 29package body Grt.Files_Operations is 30 subtype C_Files is Grt.Stdio.FILEs; 31 32 -- The end of lines 33 C_LF : constant int := 10; -- \n 34 C_CR : constant int := 13; -- \r 35 36 Auto_Flush : constant Boolean := False; 37 38 type File_Entry_Type is record 39 -- The corresponding C stream. 40 Stream : C_Files; 41 42 Signature : Ghdl_C_String; 43 44 -- Open kind: r, a or w. 45 Kind : Character; 46 47 Is_Text : Boolean; 48 49 -- True if the file entry is used. 50 Is_Alive : Boolean; 51 end record; 52 53 package Files_Table is new Grt.Table 54 (Table_Component_Type => File_Entry_Type, 55 Table_Index_Type => Ghdl_File_Index, 56 Table_Low_Bound => 1, 57 Table_Initial => 2); 58 59 -- Get the C stream for INDEX. 60 procedure Get_File 61 (Index : Ghdl_File_Index; Res : out C_Files; Status : out Op_Status) is 62 begin 63 if Index not in Files_Table.First .. Files_Table.Last then 64 Status := Op_Bad_Index; 65 else 66 Status := Op_Ok; 67 Res := Files_Table.Table (Index).Stream; 68 end if; 69 end Get_File; 70 71 -- Assume INDEX is correct. 72 function Is_Open (Index : Ghdl_File_Index) return Boolean is 73 begin 74 return Files_Table.Table (Index).Stream /= NULL_Stream; 75 end Is_Open; 76 77 -- Assume INDEX is correct. 78 function Get_Kind (Index : Ghdl_File_Index) return Character is 79 begin 80 return Files_Table.Table (Index).Kind; 81 end Get_Kind; 82 83 procedure Check_File_Mode 84 (Index : Ghdl_File_Index; Is_Text : Boolean; Status : out Op_Status) is 85 begin 86 if Files_Table.Table (Index).Is_Text /= Is_Text then 87 Status := Op_Bad_Mode; 88 else 89 Status := Op_Ok; 90 end if; 91 end Check_File_Mode; 92 93 procedure Check_Read 94 (Index : Ghdl_File_Index; Is_Text : Boolean; Status : out Op_Status) is 95 begin 96 Check_File_Mode (Index, Is_Text, Status); 97 if Status /= Op_Ok then 98 return; 99 end if; 100 101 -- LRM08 5.5.2 File operations 102 -- It is an error if the access mode of the file object is write-only 103 -- or if the file object is not open. 104 if not Is_Open (Index) then 105 Status := Op_Not_Open; 106 return; 107 end if; 108 if Get_Kind (Index) /= 'r' then 109 Status := Op_Read_Write_File; 110 return; 111 end if; 112 113 Status := Op_Ok; 114 end Check_Read; 115 116 procedure Check_Write 117 (Index : Ghdl_File_Index; Is_Text : Boolean; Status : out Op_Status) is 118 begin 119 Check_File_Mode (Index, Is_Text, Status); 120 if Status /= Op_Ok then 121 return; 122 end if; 123 124 -- LRM08 5.5.2 File operations 125 -- It is an error if the access mode of the file object is read-only 126 -- or if the file object is not open. 127 if not Is_Open (Index) then 128 Status := Op_Not_Open; 129 return; 130 end if; 131 if Get_Kind (Index) = 'r' then 132 Status := Op_Write_Read_File; 133 return; 134 end if; 135 136 Status := Op_Ok; 137 end Check_Write; 138 139 function Create_File 140 (Is_Text : Boolean; Kind : Character; Sig : Ghdl_C_String) 141 return Ghdl_File_Index is 142 begin 143 Files_Table.Append ((Stream => NULL_Stream, 144 Signature => Sig, 145 Kind => Kind, 146 Is_Text => Is_Text, 147 Is_Alive => True)); 148 return Files_Table.Last; 149 end Create_File; 150 151 procedure Destroy_File 152 (Is_Text : Boolean; Index : Ghdl_File_Index; Status : out Op_Status) 153 is 154 Cstream : C_Files; 155 begin 156 Get_File (Index, Cstream, Status); 157 if Status /= Op_Ok then 158 return; 159 end if; 160 if Cstream /= NULL_Stream then 161 Status := Op_Not_Closed; 162 return; 163 end if; 164 Check_File_Mode (Index, Is_Text, Status); 165 if Status /= Op_Ok then 166 return; 167 end if; 168 169 -- Cleanup. 170 Files_Table.Table (Index).Is_Alive := False; 171 if Index = Files_Table.Last then 172 while Files_Table.Last >= Files_Table.First 173 and then Files_Table.Table (Files_Table.Last).Is_Alive = False 174 loop 175 Files_Table.Decrement_Last; 176 end loop; 177 end if; 178 end Destroy_File; 179 180 function Ghdl_Text_File_Elaborate return Ghdl_File_Index is 181 begin 182 return Create_File (True, ' ', null); 183 end Ghdl_Text_File_Elaborate; 184 185 function Ghdl_File_Elaborate (Sig : Ghdl_C_String) return Ghdl_File_Index 186 is 187 begin 188 return Create_File (False, ' ', Sig); 189 end Ghdl_File_Elaborate; 190 191 procedure Ghdl_Text_File_Finalize 192 (File : Ghdl_File_Index; Status : out Op_Status) is 193 begin 194 Destroy_File (True, File, Status); 195 end Ghdl_Text_File_Finalize; 196 197 procedure Ghdl_File_Finalize 198 (File : Ghdl_File_Index; Status : out Op_Status) is 199 begin 200 Destroy_File (False, File, Status); 201 end Ghdl_File_Finalize; 202 203 procedure Ghdl_File_Endfile 204 (File : Ghdl_File_Index; Status : out Op_Status) 205 is 206 Stream : C_Files; 207 C : int; 208 begin 209 Get_File (File, Stream, Status); 210 if Status /= Op_Ok then 211 return; 212 end if; 213 214 -- LRM93 3.4.1 File Operations 215 -- LRM08 5.5.2 File Operations 216 -- It is an error if ENDFILE is called on a file object that is not 217 -- open. 218 if Stream = NULL_Stream then 219 Status := Op_Not_Open; 220 return; 221 end if; 222 223 -- Default: returns True. 224 Status := Op_End_Of_File; 225 226 -- LRM93 3.4.1 File Operations 227 -- LRM08 5.5.2 File Operations 228 -- Function ENDFILE always returns TRUE for an open file object whose 229 -- access mode is write-only. 230 if Get_Kind (File) /= 'r' then 231 return; 232 end if; 233 234 if feof (Stream) /= 0 then 235 return; 236 end if; 237 C := fgetc (Stream); 238 if C < 0 then 239 return; 240 end if; 241 if ungetc (C, Stream) /= C then 242 Status := Op_Ungetc_Error; 243 return; 244 end if; 245 246 Status := Op_Ok; 247 return; 248 end Ghdl_File_Endfile; 249 250 function Simple_Open (Name : Ghdl_C_String; Mode : Ghdl_C_String) 251 return C_Files is 252 begin 253 return fopen (To_Address (Name), To_Address (Mode)); 254 end Simple_Open; 255 256 Sig_Header : constant String := "#GHDL-BINARY-FILE-0.0" & Nl; 257 258 Std_Output_Name : constant String := "STD_OUTPUT" & NUL; 259 Std_Input_Name : constant String := "STD_INPUT" & NUL; 260 261 procedure File_Open (File : Ghdl_File_Index; 262 Mode : Ghdl_I32; 263 Name : Ghdl_C_String; 264 Status : out Op_Status) 265 is 266 Str_Mode : String (1 .. 3); 267 F : C_Files; 268 Sig : Ghdl_C_String; 269 Sig_Len : Natural; 270 Kind : Character; 271 begin 272 Get_File (File, F, Status); 273 if Status /= Op_Ok then 274 return; 275 end if; 276 277 if F /= NULL_Stream then 278 -- File was already open. 279 Status := Op_Not_Closed; 280 return; 281 end if; 282 283 case Mode is 284 when Read_Mode => 285 Kind := 'r'; 286 when Write_Mode => 287 Kind := 'w'; 288 when Append_Mode => 289 Kind := 'a'; 290 when others => 291 -- Bad mode, cannot happen. 292 Status := Op_Bad_Mode; 293 return; 294 end case; 295 296 if Strcmp (Name, To_Ghdl_C_String (Std_Input_Name'Address)) = 0 then 297 if Mode /= Read_Mode then 298 Status := Op_Mode_Error; 299 return; 300 end if; 301 F := stdin; 302 elsif Strcmp (Name, To_Ghdl_C_String (Std_Output_Name'Address)) = 0 then 303 if Mode /= Write_Mode then 304 Status := Op_Mode_Error; 305 return; 306 end if; 307 F := stdout; 308 else 309 Str_Mode (1) := Kind; 310 if Files_Table.Table (File).Is_Text then 311 Str_Mode (2) := NUL; 312 else 313 Str_Mode (2) := 'b'; 314 Str_Mode (3) := NUL; 315 end if; 316 F := Open_Handler (Name, To_Ghdl_C_String (Str_Mode'Address)); 317 if F = NULL_Stream then 318 Status := Op_Name_Error; 319 return; 320 end if; 321 -- if Grt.Options.Unbuffered_Writes and Mode /= Read_Mode then 322 -- setbuf (F, NULL_voids); 323 -- end if; 324 end if; 325 326 Sig := Files_Table.Table (File).Signature; 327 if Sig /= null then 328 Sig_Len := strlen (Sig); 329 case Mode is 330 when Write_Mode => 331 if fwrite (Sig_Header'Address, 1, Sig_Header'Length, F) 332 /= Sig_Header'Length 333 then 334 Status := Op_Write_Error; 335 return; 336 end if; 337 if fwrite (Sig (1)'Address, 1, size_t (Sig_Len), F) 338 /= size_t (Sig_Len) 339 then 340 Status := Op_Write_Error; 341 return; 342 end if; 343 when Read_Mode => 344 declare 345 Hdr : String (1 .. Sig_Header'Length); 346 Sig_Buf : String (1 .. Sig_Len); 347 begin 348 if fread (Hdr'Address, 1, Hdr'Length, F) /= Hdr'Length then 349 Status := Op_Read_Error; 350 return; 351 end if; 352 if Hdr /= Sig_Header then 353 Status := Op_Signature_Error; 354 return; 355 end if; 356 if fread (Sig_Buf'Address, 1, Sig_Buf'Length, F) 357 /= Sig_Buf'Length 358 then 359 Status := Op_Read_Error; 360 return; 361 end if; 362 if Sig_Buf /= Sig (1 .. Sig_Len) then 363 Status := Op_Signature_Error; 364 return; 365 end if; 366 end; 367 when Append_Mode => 368 null; 369 when others => 370 null; 371 end case; 372 end if; 373 374 Files_Table.Table (File).Stream := F; 375 Files_Table.Table (File).Kind := Kind; 376 377 Status := Op_Ok; 378 end File_Open; 379 380 procedure Ghdl_Text_File_Open (File : Ghdl_File_Index; 381 Mode : Ghdl_I32; 382 Name : Ghdl_C_String; 383 Status : out Op_Status) is 384 begin 385 Check_File_Mode (File, True, Status); 386 if Status /= Op_Ok then 387 return; 388 end if; 389 390 File_Open (File, Mode, Name, Status); 391 end Ghdl_Text_File_Open; 392 393 procedure Ghdl_File_Open (File : Ghdl_File_Index; 394 Mode : Ghdl_I32; 395 Name : Ghdl_C_String; 396 Status : out Op_Status) is 397 begin 398 Check_File_Mode (File, False, Status); 399 if Status /= Op_Ok then 400 return; 401 end if; 402 403 File_Open (File, Mode, Name, Status); 404 end Ghdl_File_Open; 405 406 procedure Ghdl_Text_Write (File : Ghdl_File_Index; Str : Std_String_Ptr; 407 Status : out Op_Status) 408 is 409 Res : C_Files; 410 Len : size_t; 411 R : size_t; 412 begin 413 Get_File (File, Res, Status); 414 if Status /= Op_Ok then 415 return; 416 end if; 417 Check_Write (File, True, Status); 418 if Status /= Op_Ok then 419 return; 420 end if; 421 422 Len := size_t (Str.Bounds.Dim_1.Length); 423 if Len = 0 then 424 Status := Op_Ok; 425 return; 426 end if; 427 428 R := fwrite (Str.Base (0)'Address, Len, 1, Res); 429 if R /= 1 then 430 Status := Op_Write_Error; 431 return; 432 end if; 433 434 if Auto_Flush then 435 fflush (Res); 436 end if; 437 438 Status := Op_Ok; 439 end Ghdl_Text_Write; 440 441 procedure Ghdl_Write_Scalar (File : Ghdl_File_Index; 442 Ptr : Ghdl_Ptr; 443 Length : Ghdl_Index_Type; 444 Status : out Op_Status) 445 is 446 Res : C_Files; 447 R : size_t; 448 begin 449 Get_File (File, Res, Status); 450 if Status /= Op_Ok then 451 return; 452 end if; 453 Check_Write (File, False, Status); 454 if Status /= Op_Ok then 455 return; 456 end if; 457 458 R := fwrite (System.Address (Ptr), size_t (Length), 1, Res); 459 if R /= 1 then 460 Status := Op_Write_Error; 461 return; 462 end if; 463 if Auto_Flush then 464 fflush (Res); 465 end if; 466 467 Status := Op_Ok; 468 end Ghdl_Write_Scalar; 469 470 procedure Ghdl_Read_Scalar (File : Ghdl_File_Index; 471 Ptr : Ghdl_Ptr; 472 Length : Ghdl_Index_Type; 473 Status : out Op_Status) 474 is 475 Res : C_Files; 476 R : size_t; 477 begin 478 Get_File (File, Res, Status); 479 if Status /= Op_Ok then 480 return; 481 end if; 482 Check_Read (File, False, Status); 483 if Status /= Op_Ok then 484 return; 485 end if; 486 487 R := fread (System.Address (Ptr), size_t (Length), 1, Res); 488 if R /= 1 then 489 Status := Op_Read_Error; 490 return; 491 end if; 492 493 Status := Op_Ok; 494 end Ghdl_Read_Scalar; 495 496 procedure Ghdl_Text_Read_Length (File : Ghdl_File_Index; 497 Str : Std_String_Ptr; 498 Status : out Op_Status; 499 Length : out Std_Integer) 500 is 501 Stream : C_Files; 502 C : int; 503 Len : Ghdl_Index_Type; 504 begin 505 Length := 0; 506 Get_File (File, Stream, Status); 507 if Status /= Op_Ok then 508 return; 509 end if; 510 Check_Read (File, True, Status); 511 if Status /= Op_Ok then 512 return; 513 end if; 514 515 Len := Str.Bounds.Dim_1.Length; 516 -- Read until EOL (or EOF). 517 -- Store as much as possible. 518 for I in Ghdl_Index_Type loop 519 C := fgetc (Stream); 520 if C < 0 then 521 Length := Std_Integer (I); 522 Status := Op_End_Of_File; 523 return; 524 end if; 525 if I < Len then 526 Str.Base (I) := Character'Val (C); 527 end if; 528 -- End of line is '\n' or LF or character # 10. 529 if C = C_LF then 530 Length := Std_Integer (I + 1); 531 Status := Op_Ok; 532 return; 533 end if; 534 end loop; 535 Length := 0; 536 Status := Op_Ok; 537 end Ghdl_Text_Read_Length; 538 539 procedure Ghdl_Untruncated_Text_Read (File : Ghdl_File_Index; 540 Buf : Ghdl_C_String; 541 Len : in out Std_Integer; 542 Status : out Op_Status) 543 is 544 Stream : C_Files; 545 L : Natural; 546 C : int; 547 begin 548 Get_File (File, Stream, Status); 549 if Status /= Op_Ok then 550 return; 551 end if; 552 Check_Read (File, True, Status); 553 if Status /= Op_Ok then 554 return; 555 end if; 556 557 -- Default status. 558 Status := Op_Ok; 559 560 -- Read at most LEN characters, stop at EOL. 561 L := 0; 562 for I in 1 .. Len loop 563 C := fgetc (Stream); 564 if C < 0 then 565 Status := Op_End_Of_File; 566 exit; 567 end if; 568 -- Be nice with DOS files: handle CR/CR+LF/LF. 569 -- Note: LF+CR is not handled, so that on unix we don't need 570 -- to read the next line. 571 -- Always return LF as end of line. 572 if C = C_CR then 573 C := fgetc (Stream); 574 if C > 0 and C /= C_LF then 575 C := ungetc (C, Stream); 576 pragma Assert (C >= 0); 577 end if; 578 C := C_LF; 579 end if; 580 L := L + 1; 581 Buf (L) := Character'Val (C); 582 exit when C = C_LF; 583 end loop; 584 585 Len := Std_Integer (L); 586 end Ghdl_Untruncated_Text_Read; 587 588 procedure File_Close 589 (File : Ghdl_File_Index; Is_Text : Boolean; Status : out Op_Status) 590 is 591 Stream : C_Files; 592 begin 593 Get_File (File, Stream, Status); 594 if Status /= Op_Ok then 595 return; 596 end if; 597 Check_File_Mode (File, Is_Text, Status); 598 if Status /= Op_Ok then 599 return; 600 end if; 601 602 -- LRM 3.4.1 File Operations 603 -- If F is not associated with an external file, then FILE_CLOSE has 604 -- no effect. 605 if Stream = NULL_Stream then 606 Status := Op_Ok; 607 return; 608 end if; 609 610 if fclose (Stream) /= 0 then 611 Status := Op_Close_Error; 612 return; 613 end if; 614 Files_Table.Table (File).Stream := NULL_Stream; 615 Status := Op_Ok; 616 end File_Close; 617 618 procedure Ghdl_Text_File_Close 619 (File : Ghdl_File_Index; Status : out Op_Status) is 620 begin 621 File_Close (File, True, Status); 622 end Ghdl_Text_File_Close; 623 624 procedure Ghdl_File_Close 625 (File : Ghdl_File_Index; Status : out Op_Status) is 626 begin 627 File_Close (File, False, Status); 628 end Ghdl_File_Close; 629 630 procedure Ghdl_File_Flush (File : Ghdl_File_Index; Status : out Op_Status) 631 is 632 Stream : C_Files; 633 begin 634 Get_File (File, Stream, Status); 635 if Status /= Op_Ok then 636 return; 637 end if; 638 639 -- LRM08 5.5.2 File Operations 640 -- For the WRITE and FLUSH procedures, it is an error if the access 641 -- mode of the file object is read-only or if the file is not open. 642 if Stream = NULL_Stream then 643 Status := Op_Not_Open; 644 return; 645 end if; 646 if Get_Kind (File) = 'r' then 647 Status := Op_Write_Read_File; 648 return; 649 end if; 650 651 fflush (Stream); 652 Status := Op_Ok; 653 end Ghdl_File_Flush; 654end Grt.Files_Operations; 655