Using Ada.Text_IO.Put_Line inside Ada function owned by C function?

I have a function in C. This function imports an Ada function. Inside my Ada function I want to do Put_Line, and have it displayed in my console. So this means that I have to open a C_Stream inside of my Ada function?

-- PUT_LINE PROBLEM, the parent function is in C.
-- Therefore I need to open a stream?
-- method 1, writing directly to stdout.
C_Out_File : Ada.Text_IO.File_Type;
Ada.Text_IO.C_Streams.Open
  (File     => C_Out_File,
   Mode     => Ada.Text_IO.Out_File,
   C_Stream => Interfaces.C_Streams.stdout);
Put_Line (C_Out_File, "Hello!");
-- method 2, use Set_Output so I don't have to define the file in Put_Line.
Ada.Text_IO.Set_Output(C_Out_File);
Put_Line("Hello without specifying file!");
-- will have to Set_Output back to Ada.Text_IO.Standard_Output to get the regular back.

Both of these methods do work and properly display, though I do not know if this is the optimal way.

You should just be able to call Ada.Text_IO.Put_Line from your Ada function. There should be no need to use C streams in this case.

Then what is the problem?

What, exactly, do you mean by ā€˜optimal’?
What do you want to optimize?

Hm, you know what works well for context-capture? Generics.
And you can combine that with scoping to automatically take care of resetting things, or if you need the generic-instantiation at library level use code similar to the ā€œlast chance handlerā€ example. Another option would be using a Task, having one entry handle the writing/procedure internals, and another entry for shutting down and cleaning up.

It really is dependent upon the design of your mixed-language system.

1 Like

C streams is a necessity because the main function is C. Calling Put_Line without opening a c stream leads to raised ADA.IO_EXCEPTIONS.STATUS_ERROR : System.File_IO.Check_Write_Status: file not open
Several hours of wisdom later: I initially thought this was an incorrect response to my question, but it seems that I wasn’t elaborating (right word?) the Ada runtime so that Standard_Output would correspond to the stdout of C. My blunder was not recognizing that the main loop was not owned by Ada, so all I needed to do was pass -n (no main loop implemented in Ada, gives me adainit() and adafinal()), import the said external functions in C, and then call it once right before my C main loop calls my ada functions, now Put_Line outputs to the console the same as it always should, without having to do my c_stream setup. Thanks. This explanation is for anyone else coming across this in the future, gave me a headache.

-n // to the gnat binder to tell it to generate adainit() and adafinal()
// Then in the C/CPP code :
extern "C"
{
  void adainit ();
  void adafinal ();
};
// pseudo example:
int main () {
   adainit(); // properly elaborate Ada.Text_IO etc...
   Call_Ada_Entry_Point();
   adafinal();

return 0;
}
-- Now any Ada code that does Put_Line will automatically write to the console owned by the C loop.

I have no actual problem with functionality or performance. I’m probably after a unicorn solution that does not exist. [ 6 hours later… ] As I was writing this response to you I think I may have found the ā€˜unicorn’ solution, see above code. It’s optimal to me because it’s ā€˜smaller’ and a one time solution, that may also solve the true underlying problem. I think it’s the most correct way to do it. The C_Stream setup that I had going solved the problem of the console not displaying Put_Line. But, the underlying problem was me not implementing/elaborating/bindinghellmyheadhurts correctly.

I will also take your generics into account for next time, as I have already invested too much time into my way! My poor comedy aside, thank you for the tip.