Request boilerplate / resusable code in Ada 95 for external file open, append, close

I scanned Predefined input and output in 66 pages of Cohen 2nd for an undergraduate lecture on file systems. I have Feldman, but learned not to trust it because of errors and no corrigenda.

What I want is reusable Ada 95 code to:

  1. Check external file name is not open, and if so then close it.
  2. Open external file name as output mode only.
  3. Write strings in ASCII character range of 0-127 sequentially in APPEND commands.
  4. Close external file name.

Thank you in advance.

Is Ada95 an absolute requirement?
The EVIL library has EVIL.Util.Files, which provides an auto-closing file-object; it’s in Ada2012, though.

Yes, I am afraid so, Ada 95 is an absolute requirement, but thanks for the link.

Check this: Ada - Source Treasury

I think most, if not all, examples are in Ada95.

Thanks for the link …

Is this a viable coding solution to the request?

WITH Ada.text_io ;   USE Ada.text_io ;

PROCEDURE Write_ASCII_characters IS
    File : File_type ;
BEGIN

    -- Step 1: Check if the external file is open and close it if necessary.
    BEGIN 
        Close( File) ; 
    EXCEPTION 
        WHEN Name_error => null ; 
        WHEN Others     => null ; 
    END;

    -- Step 2: Open external file as output mode only.
    Create( File, Out_file,    "filename.txt") ;

    -- Step 3: Write strings in ASCII character range of 0-127 sequentially.
    Open  ( File, Append_file, "filename.txt") ;
    
    FOR i IN 0 .. 127 LOOP 
        Put_line( File, Character'VAL( i)'Image); 
    END LOOP ;

    -- Step 4: Close external file name.
    Close( File) ;

END Write_ASCII_characters ;

I suggest you at least try to compile your code before posting. All of your questions are answered by the standard library documentation, which anyone using Ada should have read and understood.

The standard library documentation, as you know, is for vendors building Ada compilers, hence the name of standard ref. man. The response of “read the manual” really does not apply here because my question, per the subject line, refers to reusable code from practitioners. Compiling the instant code is not possible because the GNAT version obtained is broken (please see my other posts), and no replacement is suggested here.

May I also request not minimizing my question to dismiss it, as I am still an Ada 95 newbie.

Well, yes; but also it lets you see what is bundled in the standard library.
Checking it out is absolutely germane to the question; especially as it can show how difficult it would be to (e.g.) refactor a solution like I presented to use the older standard.

I think that all the main stuff EVIL uses was doable w/ Ada95; if so, then it’s just a matter of converting the Ada2005 dot-notation to subprogram-call notation.

Every time I hear about GNAT bootstrapping problems I wonder why it should be so problematic to bootstrap — I don’t necessarily think it is the complexity of the language, despite some others’ posts, but rather it seems to be GNAT/GCC’s own architecture getting in its own way.

The standard library is removed from confecting and/or reusing code which is a programming skill as supposedly taught by Ada 95 textbooks. For example in Feldman et al 3rd ed, file i/o is absent except in passing.

Converting EVIL in Ada2005 to Ada1995 from its acceptable dot notation is a good idea, but in light of the 17-lines of code fragment proffered such an exercise is unnecessary on at least ten-times that size in a PRAGMA library.

In my opinion, the historical enormity of gnat/gcc, as financed by the Gov’t hook-line-and-sinker and making millionaires in the process, traces its root cause back to the mistaken dictum of Richard Stallman not to build libraries but to build file structures. Welcome to the world of C.

Ah, yes.
The world where we throw away machine checkable constraints and “hope” that the programmer has the wherewithal, time, and energy to manually add them in.

Yay.
[/sarc]

You are on a good way.
Step 1 does nothing, since File is closed [1] and hasn’t even a name.
At step 3 you try to open again the file opened at step 2, so you always get an error. For instance with GNAT it looks like:
raised ADA.IO_EXCEPTIONS.STATUS_ERROR : System.File_IO.Open: file already open


[1] RM A.7 (5)
“Before input or output operations can be performed on a file, the file first has to be associated with an external file. While such an association is in effect, the file is said to be open, and otherwise the file is said to be closed.”


Step 1 does nothing, since File is closed [1] and hasn’t even a name.

Did you see the code fragment proffered in this thread?

No, Annex A is written for users of the standard library, and easy to understand.

Your subject line says nothing about “reusable code from practitioners”, nor does your initial post.

Anyone can easily obtain a recent version of FSF GNAT for common platforms and use it with the --gnat95 switch. I would suggest avoiding GNAT 13 < 13.3 and GNAT 14 < 14.1, as they had some significant errors, but 12.3 or 14.1 should work fine for you.

Thanks for comments.

Absolutely. My answer refers to that code fragment. You can track the parent post (if any) on the top right of each post (see the red arrow on the following screenshot).

grumpy

Step 1 derives from the early practice in Dartmouth BASIC (1965) of closing a channel before opening it to make sure the open does not raise an exception, because closing a closed channel raises no exception.
This in effect is mirrored in Cohen 2nd ed pg 746 with File named as file_type [assumed here]:
BEGIN
Open( File, Out_file, Name, Form) ;
EXCEPTION
WHEN Name_error => Create( File, Out_file, Name, Form) ;
END ;

The Step 3 I think is to comply with the Ada 95 order of open internal file then create external file to write the 'IMAGE in the loop (which apparently goes to the screen). The idea is to print to mutable screen and to immutable file.

If this code is mistaken, then how to fix it please, the implied purpose of the request.

Perhaps that’s the Dartmouth BASIC point of view, but in Ada, closing a file that’s not open raises an exception:

raised ADA.IO_EXCEPTIONS.STATUS_ERROR : System.File_IO.Check_File_Open: file not open
0x4035e1 Test_Close at test_close.adb:9

here’s the source file, for reference

with Ada.Text_IO;
procedure Test_Close is
   package IO renames Ada.Text_IO;
   File : IO.File_Type;
begin
   IO.Create (File, IO.Out_File, "test.txt");
   IO.Put_Line (File, "test");
   IO.Close (File);
   IO.Close (File);
end Test_Close;

In Ada, closing a file that’s not open raises an exception: that is correct.
Hence:
BEGIN
Close( File) ;
EXCEPTION
WHEN Name_error => null ;
WHEN Others => null ;
END;

Modifying @cantanima’s example a little bit:

with Ada.Text_IO;

procedure Test_Close is
   package IO renames Ada.Text_IO;
   File : IO.File_Type;
begin
   IO.Close (File);
exception
   when IO.Status_Error =>
      IO.Put ("Closing a file that's not open.");
      raise;
end Test_Close;

You get always:

Closing a file that's not open.

raised ADA.IO_EXCEPTIONS.STATUS_ERROR : System.File_IO.Check_File_Open: file not open

So you can basically (pun not intended :wink: ) remove the “Step 1” of your fragment:

    -- Step 1: Check if the external file is open and close it if necessary.
    BEGIN 
        Close( File) ; 
    EXCEPTION 
        WHEN Name_error => null ; 
        WHEN Others     => null ;  --  ***
    END;

because the point maked with *** is always reached.