File redirection in C? Or is there a better way?
Chris Mahoney (1684) 2165 posts |
Hi all, I’m trying to run a command-line app and grab its output for parsing. What’s the easiest way to do that? I’ve tried using file redirection, hoping to open the resulting file and parse that, but I can’t get it working consistently. For example, both of these work at the command line: cat { > <Wimp$ScrapDir>.MyFile } [Edit: fx0 does not! See the following two posts…] In both cases, “MyFile” ends up containing the output of the command. This also works in C: system(“cat { > <Wimp$ScrapDir>.MyFile }”); But this only generates an empty file: system(“fx0 { > <Wimp$ScrapDir>.MyFile }”); Is there an easier way for a C app to grab the output of a CLI app? If not, why is the call to fx0 giving an empty file? - A confused user :) |
David Pitt (102) 743 posts |
Here at the command line :- *fx0 { > fx0 } creates an empty file but reports its result unredirected at the command line :- *fx0 { > fx0 } RISC OS 5.23 (12 Jan 2017) *
|
Chris Mahoney (1684) 2165 posts |
Argh, I “simplified” my post (to remove a third-party dependency) and apparently didn’t test properly before posting. You’re right about fx0 creating an empty file and still outputting to the TaskWindow; I guess that’s because it’s presumably a very low-level command. The command that I’m actually having trouble with is the third-party “svn” app (available through PackMan as “Subversion”). This one works correctly from the command line but not from within C. |
Chris Mahoney (1684) 2165 posts |
Hah! I just figured it out… I changed from system() to a direct call to OS_CLI and was greeted with “No writable memory at this address”. It turns out that my !Run file (which I’d copied from another app) was setting the WimpSlot to 64k, which isn’t enough to run SVN. It’s all working now :) With that said, I’d still be interested in knowing whether there’s a “cleaner” way of getting at the output. |
Jeffrey Lee (213) 6048 posts |
FX 0 behaves like that because it returns the version string as an error (although I don’t know why it returns it as an error – maybe it’s a hack so that programs can parse the string if they want?)
You should be able to check the return code of system() to see if the command failed or returned an error.
If you get -2 you can then check _kernel_last_oserror() to see what the error was (Disclaimer: -2 will also be returned if you call system() from a non-USR mode, but it won’t record anything with _kernel_last_oserror)
I think you can use PipeFS instead of a temporary file on disc, but it isn’t really something I’m familiar with. |
Rick Murray (539) 13840 posts |
The problem RISC OS throws up is that it doesn’t really understand other tasks when we’re talking command line stuff. system() attempts to cheat by shifting the original program up in memory, but if the program being run messes with memory allocations, things can get messy. I have exactly this issue with a program I wrote yesterday. I am scanning the lookups for the DDNS of my IP camera. The addresses begin with the sequence ###xxxx where ‘#’ is a digit and ‘x’ is a lower case letter. I look for the next one in series every five seconds. It’s been running about 24h and has made it as far as “000axgy”, so it’s gonna take a while… To save a lot of bother writing socket code, I just call wget, throw away the result, and save the headers to a file for examination. Using OSCLI was a failure (wget would overwrite the program!), so I cheated. Since I’m a Wimp task, I simply call Wimp_StartTask and it does it as a separate task, to return to me when the task quits (or first calls Wimp_Poll, but that won’t happen for a CLI program!). Something of note, perhaps, is that within a C program, stdout and stderr are considered two different things. In the case of a C program, you could read the error messages by suffixing As Jeffrey says, you may be able to use PipeFS to push data from one app to another without using temp, though I’m not sure if there are size/other restrictions to worry about. I’ve never used PipeFS. You could, maybe, register yourself with TaskWindow and instead of opening and displaying a window, use TaskWindow_Input to issue commands, and receive TaskWindow_Output to receive replies back. |
Chris Mahoney (1684) 2165 posts |
Thanks to both of you. After reading that wall of text1 I think I’m going to take the easy way out and just redirect to a text file like I am now. I’ll tidy it up a little, such as using tmpnam() instead of hardcoding a filename, but it looks like I can make it work. I’ll do some testing and find out whether I need to parse any error text; in my limited experimentation the svn app was returning errors as ordinary stdout text, but I’ll need to make sure that that’s always the case. For what it’s worth, the PipeFS documentation seems to be extremely sparse. 1 I promise that I did read it in its entirety! |
Stuart Swales (1481) 351 posts |
fx 0,0 generates an error ‘cos that’s what the BBC micro did! If you want to collect all the output of svn regardless of stdout or stderr, execute svn arguments >outfile 2>&1 |
Rick Murray (539) 13840 posts |
? That’s more like a minor hedgerow. A picket fence at best.
|
Chris Mahoney (1684) 2165 posts |
It’s a wall on the phone. Less so on the desktop :) |
Rick Murray (539) 13840 posts |
Had to give this up – the Pi would simply freeze up after around 14-16 hours. No video output, and the network connection dead (no yellow light at either end). I guess scanning an address range continually is more than the network stack can handle. Hmm….. |
Steve Pampling (1551) 8170 posts |
I was looking at the EtherTH check-in with respect to the frame size vs typical MTU on access switches etc . With that in mind I did wonder whether modifying the drivers to produce a smaller frame might improve throughput. |