Recent

Author Topic: capture apl_exec stdout  (Read 7127 times)

Thaddy

  • Hero Member
  • *****
  • Posts: 14198
  • Probably until I exterminate Putin.
Re: capture apl_exec stdout
« Reply #45 on: January 19, 2023, 06:47:44 pm »
Did you try my reply at #41? Affter that, all the chatter came nicely in Output/stdOut.
It simply makes sure that stdErr goes to stdOut.

Set WriteErrorsToStdErr to False  // this is from unit system
« Last Edit: January 19, 2023, 06:51:47 pm by Thaddy »
Specialize a type, not a var.

TRon

  • Hero Member
  • *****
  • Posts: 2434
Re: capture apl_exec stdout
« Reply #46 on: January 20, 2023, 11:16:28 am »
Thaddy:
Yes, I have seen your reply #41

Thank you for that as I also was not aware of the existence of that variable

Unfortunately it did not had the required effect for me (of redirecting the output on handle 2 from terminal if even to oblivion). The library will continue to emit to the terminal for me.

But a second point (not important right now) is that we actually wish for this to be outputted to the error-handle because it seems the way the library communicates.

For some reason FPC fails (refuses ?) to pick things up on the standard error handle.

I have tried multiple approaches now and I seem to fail to replicate what a filestream create does (as shown by Fred vS) differently when compared to duplicating the handle and feed that with a customized textrec to Assignstream. It should behave the same but it seems it does not.

I have to delve deeper into FPC internals and/or brush up my knowledge on what a Filestream and AssignStream actually does (to a handle) in order to spot the difference.

toby

  • Sr. Member
  • ****
  • Posts: 251
Re: capture apl_exec stdout
« Reply #47 on: January 26, 2023, 11:07:32 pm »
thaddy and tron : looks like you weren't able to figure it out and just left it hanging

isn't this doable from fpc itself by some combo of thandlestream/fpdup/tmemorystream/tstringstream/loadfromstream/tstream.write programming methods?

surely some hero fpc programmer here who knows this stuff can do it :)

toby

  • Sr. Member
  • ****
  • Posts: 251
Re: capture apl_exec stdout
« Reply #48 on: January 27, 2023, 12:23:08 am »
this is my attempt to convert the fpdup proigran that writes apl_exec output to file to a stream (and then to tstringlist)

anyone can help get it working properly?

Code: Pascal  [Select][+][-]
  1.  
  2.  
  3. program stdouty;
  4.  
  5. //{$mode objfpc}{$H+}
  6.  
  7. {$linklib apl}
  8.  
  9. uses sysutils, classes, baseunix, libaplu;
  10.  
  11. //var fs : tfilestream;
  12. var fs : thandlestream;
  13.     oldoutputhandle : thandle;
  14.     olderrorhandle : thandle;
  15.     i, j : longint;
  16.     e : array[1..4] of longint;
  17.  
  18. begin
  19.  
  20. for i := 1 to 4 do e[i] := 2;
  21.  
  22. // save original handles
  23. oldoutputhandle := fpdup(textrec(stdout).handle);
  24. olderrorhandle  := fpdup(textrec(stderr).handle);
  25.  
  26. //fs := tfilestream.create('stdout.tmp', fmopenreadwrite or fmcreate);
  27. fs := thandlestream.create(stdoutputhandle);
  28.  
  29. // assign output and error handles to a single file
  30. fpdup2(fs.handle, stderrorhandle);
  31. fpdup2(fs.handle, stdoutputhandle);
  32.  
  33. init_libapl(paramstr(0), 0);
  34. apl_exec('"⍳4"');
  35. j := apl_exec('⍳4');
  36. writeln('j : ', j);
  37.  
  38. writeln('fs.position : ', fs.position);
  39. fs.position := 0;
  40. writeln('fs.position : ', fs.position);
  41. /fpc/current/tstream/tstream.html
  42. writeln('fs.size : ', fs.size);
  43.  
  44. writeln(fs.write(e, 4));
  45.  
  46. for i := 1 to 4 do writeln('i : ', i, '  e[', e[i], ']');
  47.  
  48. fs.free;
  49.  
  50. // restore original handles
  51. fpdup2(oldoutputhandle, textrec(stdout).handle);
  52. fpdup2(olderrorhandle , textrec(stderr).handle);
  53.  
  54. //fpunlink('stdout.tmp');
  55.  
  56. end.
  57.  
« Last Edit: January 27, 2023, 12:49:25 am by toby »

440bx

  • Hero Member
  • *****
  • Posts: 3944
Re: capture apl_exec stdout
« Reply #49 on: January 27, 2023, 12:28:28 am »
@toby,

you should put your code between tags, i.e, [ code = pascal ] <your code goes here> [ / code ]  (without the spaces between [ and ])

HTH.

ETA:

well done :)



« Last Edit: January 27, 2023, 07:49:03 am by 440bx »
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

TRon

  • Hero Member
  • *****
  • Posts: 2434
Re: capture apl_exec stdout
« Reply #50 on: January 27, 2023, 06:44:15 am »
thaddy and tron : looks like you weren't able to figure it out and just left it hanging
not leaving it hanging, just requires more in depth research to figure out exactly what is happening internally.

Quote
isn't this doable from fpc itself by some combo of thandlestream/fpdup/tmemorystream/tstringstream/loadfromstream/tstream.write programming methods?
As you have noticed yourself: no. That is not a problem of FPC perse.

Quote
surely some hero fpc programmer here who knows this stuff can do it :)
Things would have been much easier if the library was a proper shared library (and also not tied to the programming language) so that provision for a normal call-back mechanism would have been in place. We/you are trying to fix something that should not have to be fixed in the first place. You can already make use of a sort of callback mechanism with APL but it still will not catch /all/ output from the library.

TRon

  • Hero Member
  • *****
  • Posts: 2434
Re: capture apl_exec stdout
« Reply #51 on: January 27, 2023, 06:59:29 am »
anyone can help get it working properly?
Just for the record: combining output and error will not help you in communicating properly with the APL library. One channel is used for normal results, the other for indicating that there is an error and another channel that outputs additional information. And then you have your input channel. The latter can be fixed/circumvented with a call-back. Another callback also work for /one/ of the other used channels.

toby

  • Sr. Member
  • ****
  • Posts: 251
Re: capture apl_exec stdout
« Reply #52 on: January 27, 2023, 10:18:23 pm »

i don't understand your problem with the libapl.so library
please post your problem code so i have something to understand what is a problem

---

this is information i received from apl guys

from a c++ libapl programmer he uses the line
LIBAPL_error execerr = LAE_NO_ERROR;

from the apl dev
'not sure if this helps, but if I remember correctly (I may not) then the main GNU APL output
goes to *stderr* (fd 2) and not to *stdout* (fd 1). The reason is somewhat historic because *stdout* is
buffered by default while *stderr* is not (which caused some issues with *stdout* when used
interactively that did not occur with *stderr*).'

---

Thaddy

  • Hero Member
  • *****
  • Posts: 14198
  • Probably until I exterminate Putin.
Re: capture apl_exec stdout
« Reply #53 on: January 28, 2023, 09:13:47 am »
Hey, it is weekend. Back on it again.
Btw. I would not worry too much about the stdout vs stderr, that is easily solved as per one of my previous posts. I now ran into trouble with my library compile, but that is likely to be my fault. (setback, only on windows, Linux just fine)
But I got the windows keyboard layout working. (progress)
« Last Edit: January 28, 2023, 09:15:32 am by Thaddy »
Specialize a type, not a var.

TRon

  • Hero Member
  • *****
  • Posts: 2434
Re: capture apl_exec stdout
« Reply #54 on: January 28, 2023, 11:31:43 am »
i don't understand your problem with the libapl.so library
As a reminder: I do not have a problem with libapl.so, you did ask for help  ;D

Quote
please post your problem code so i have something to understand what is a problem
I don't like repeating myself: see post #42

.. and try to brush up on your knowledge concerning shared objects.


Quote
from a c++ libapl programmer he uses the line
LIBAPL_error execerr = LAE_NO_ERROR;
That has no bearings on the current issues.

Quote
from the apl dev
I am aware how the library works. You can also do so by using a simple trace.

I said that the communication the library uses is not how shared libraries are suppose to work (not on any platform) and that the library is tight to the programing language it was designed in (the story of any FPC programmer).

I refuse to write C startup/initialization code or write a wrapper in C. That's all  :)

TRon

  • Hero Member
  • *****
  • Posts: 2434
Re: capture apl_exec stdout
« Reply #55 on: January 31, 2023, 02:49:23 pm »
@toby:
fwiw: I read the same ML's that you use and you are currently confronted with answers that are the typical response and deliberate misinterpretation (apparently APL itself is written in APL and compiled with the APL compiler) of things that you quoted (which consisted of parts of my statements).

Usually one get such answers when you confront someone with their (broken) design philosophy (please don't get me wrong there as I get it, but I detest when someone tries to deflect the issue with providing bogus responses).

The provided answers did clear something up for me though and that is that you can not solve this problem with Free Pascal. the APL shared library is broken by design so you are forced to brush up on your C(++) knowledge. The provided answer that tells you/us to adjust the C source-code / makefile is exactly what I meant with my statement "the story of any FPC programmer"

The explanation from their ML about the call-back mechanism that /is/ in place is nice but I already knew that (apparently you yourself still do not, despite the fact that I had already expanded the library with that functionality and added two examples to show how to use them).

As said earlier in this post: it will still not solve the underlying problem (e.g. there is a reason (as explained) you are forced to use static linking).
« Last Edit: January 31, 2023, 03:16:14 pm by TRon »

TRon

  • Hero Member
  • *****
  • Posts: 2434
Re: capture apl_exec stdout
« Reply #56 on: February 04, 2023, 04:31:01 pm »
@toby:
With regards to your return value evaluation of exec call problem:
Code: Pascal  [Select][+][-]
  1. var
  2.   global_exec_callback_result : string;
  3.  
  4. function exec_callback(const value: TAPL_value; committed: cint): cint; cdecl;
  5. var temp:pchar;
  6. begin
  7.   global_exec_callback_result := '';
  8.  
  9.   temp := print_value_to_string(value);
  10.  
  11.   // if value has not been committed
  12.   if committed = 0
  13.     then setstring(global_exec_callback_result,temp,strlen(temp));
  14.  
  15.   // do not commit
  16.   result := 0;
  17. end;
  18.  
  19.  
  20. // wrapper function
  21. function apl_exec(apl_line: string; out ret_value: string): Tlibapl_error;
  22. begin
  23.   res_callback:=@exec_callback;
  24.   result:=ulibapl.apl_exec(apl_line);
  25.   ret_value:=global_exec_callback_result;
  26.   res_callback:=nil;
  27. end;
  28.  

edit: You can use it like:
Code: Pascal  [Select][+][-]
  1. var
  2.   err: Tlibapl_error;
  3.   exec_result: string;
  4.  
  5. const
  6.   example = '2*8';
  7.  
  8. begin
  9.   init_libapl(argv[0], 0);
  10.   err := apl_exec(example, exec_result);
  11.   if err = 0
  12.    then writeln('.APL code "', example, '" was interpreted successful: answer = ', exec_result)
  13.    else writeln('.APL code "', example, '" failed miserably');
  14. end.
  15.  

That is what the good Dr. is trying to tell you.
« Last Edit: February 04, 2023, 04:49:18 pm by TRon »

toby

  • Sr. Member
  • ****
  • Posts: 251
Re: capture apl_exec stdout
« Reply #57 on: February 07, 2023, 01:20:03 am »
with your code as :

i get following compile error

Compiling ulibapl.pas
cb.pas(15,47) Error: Identifier not found "TAPL_value"
cb.pas(15,64) Error: Identifier not found "cint"
cb.pas(15,71) Error: Identifier not found "cint"
cb.pas(19,9) Error: Identifier not found "print_value_to_string"
cb.pas(21,14) Error: Operator is not overloaded: "<erroneous type>" = "ShortInt"
cb.pas(30,1) Error: Identifier not found "res_callback"
cb.pas(33,1) Error: Identifier not found "res_callback"
cb.pas(44) Fatal: There were 7 errors compiling module, stopping

are you using a new ulibapl.pas that i do not have ??




Code: Pascal  [Select][+][-]
  1.  
  2.  
  3. program cb;
  4.  
  5. {$linklib apl}
  6.  
  7. //uses libaplu;
  8. uses ulibapl;
  9.  
  10. var
  11. global_exec_callback_result : string;
  12.  
  13. err: Tlibapl_error;
  14. exec_result: string;
  15. const example = '2*8';
  16.  
  17. function exec_callback(const value: TAPL_value; committed: cint): cint; cdecl;
  18. var temp:pchar;
  19. begin
  20. global_exec_callback_result := '';
  21. temp := print_value_to_string(value);
  22. // if value has not been committed
  23. if committed = 0
  24. then setstring(global_exec_callback_result,temp,strlen(temp));
  25. // do not commit
  26. result := 0;
  27. end;
  28.  
  29. // wrapper function
  30. function apl_exec(apl_line: string; out ret_value: string): Tlibapl_error;
  31. begin
  32. res_callback:=@exec_callback;
  33. result:=ulibapl.apl_exec(apl_line);
  34. ret_value:=global_exec_callback_result;
  35. res_callback:=nil;
  36. end;
  37.  
  38. begin
  39. init_libapl(argv[0], 0);
  40. err := apl_exec(example, exec_result);
  41. if err = 0
  42. then writeln('.APL code "', example, '" was interpreted successful: answer = ', exec_result)
  43. else writeln('.APL code "', example, '" failed miserably');
  44. end.
  45.  
  46.  

TRon

  • Hero Member
  • *****
  • Posts: 2434
Re: capture apl_exec stdout
« Reply #58 on: February 07, 2023, 05:18:33 am »
i get following compile error
ah yes, craps. Sorry for that.

Quote
are you using a new ulibapl.pas that i do not have ??
Yes, but it is no big change (although I have now almost all functions declared) . Only requires one additional function for the example to work.

Try the following instead, with the ulibapl from post #17.

Code: Pascal  [Select][+][-]
  1. program test;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   ulibapl, ctypes;
  7.  
  8.   // additional function declaration that should be declared inside ulibapl.pas
  9.   // print value into a string
  10.   function  print_value_to_string(const value: TAPL_Value): pchar; cdecl; external apllib;
  11.  
  12.  
  13.   // example code follows:
  14.  
  15. var
  16.   global_exec_callback_result : string;
  17.  
  18.  
  19. function exec_callback(const value: TAPL_value; committed: cint): cint; cdecl;
  20. var temp:pchar;
  21. begin
  22.   global_exec_callback_result := '';
  23.  
  24.   temp := print_value_to_string(value);
  25.  
  26.   // if value has not been committed
  27.   if committed = 0
  28.     then setstring(global_exec_callback_result,temp,strlen(temp));
  29.  
  30.   // do not commit
  31.   result := 0;
  32. end;
  33.  
  34.  
  35. // wrapper function
  36. function apl_exec(apl_line: string; out ret_value: string): Tlibapl_error;
  37. begin
  38.   res_callback:=@exec_callback;
  39.   result:=ulibapl.apl_exec(apl_line);
  40.   ret_value:=global_exec_callback_result;
  41.   res_callback:=nil;
  42. end;
  43.  
  44. var
  45.   err: Tlibapl_error;
  46.   exec_result: string;
  47.  
  48. const
  49.   example = '2*8';
  50.  
  51. begin
  52.   init_libapl(argv[0], 0);
  53.   err := apl_exec(example, exec_result);
  54.   if err = 0
  55.    then writeln('.APL code "', example, '" was interpreted successful: answer = ', exec_result)
  56.    else writeln('.APL code "', example, '" failed miserably');
  57. end.
  58.  
Hopefully that does the trick.

toby

  • Sr. Member
  • ****
  • Posts: 251
Re: capture apl_exec stdout
« Reply #59 on: February 07, 2023, 10:57:11 pm »
Tron

absolutely fantastic!!

I'm doing some speed testing and large data result testing and will report back

Thanks for this complicated understandng of what was going on



 

TinyPortal © 2005-2018