Hi all, I'm working on a GUI frontend for R, and I'm looking for a good way to catch all warning- and error-output. The reason for this is mostly, that I would like to know, which sections of the output are "normal" output, warnings, and errors. This would allow for some nice features, such as highlighting warnings and errors in a different color, or popping up a message like e.g. "There were these warnings, while doing this-or-that:". Maybe a good solution for this already exists, but I have not been able to find it. Therefore, I'll outline what I have tried/considered so far, and what I think might be ways to add a corresonding API. Of course, I'm not very familiar with R, so these suggestions are probably not "the right way to do it".
What I've tried so far: 1) Directing stderr-output to a file (using sink ()): This solution splits warnings, and errors from "regular" output. Using options (error=quote (myhandler ()) I can additionally tell warnings and errors apart after the fact. However, this solution is problematic, in that then the output is handled asynchronously, and I can not tell, at which position in the output a warning should have been printed. Further, if the user runs one "sink ()" too many (the user has a sort of console for direct interaction with R), the output-handling will be broken in my GUI. 2) Use options (warning.expression=...), and options (error=...): Unfortunately, it turned out, that when setting warning.expression to something non-NULL, the warning is discarded completely. There is no way to get at the warning that would have been generated. 3) Use condition handlers: 3a) Wrap each call inside withCallingHandlers (...): This would probably work, but add quite a bit of overhead for string manipulation, and parsing. The GUI runs a lot of small commands during normal operation. There are additional hazzles, such as error messages would then all look like "Error in withCallingHandlers(...", and I'd have to use yet more string operations to make them look normal. Also: Can I be sure, that all warnings (i.e. even from C-code) are signalled as conditions? I'm afraid I do not fully understand the internal going-ons, here. If all else fails, I'll have to use this, but I'm not very happy with this. 3b) Use ".Internal (.addCondHands (...))" once to set up persistent handlers: This worked fine, when testing it in the R-console. However, in my GUI, calls are actually handled using R_tryEval (..., R_GlobalEnv, ...). It seems the condition handlers do not carry over between two successive calls of R_tryEval. So effectively, I'd once again be back at 3a. What I would like to have: Of course there would be many different ways to accomplish this. Here are some solutions I can think of: 1) In my programmers' dream, there'd simply be three callbacks that I can override: R_WriteConsole (exists), R_WriteWarning, and R_WriteError. R_WriteWarning, and R_WriteError would be called from vwarningcall_dflt, and verrorcall_dflt, respectively, instead of REprintf. The default implementation of those, would of course simply call REprintf. Drawbacks: a) REprintf is available for use in R_ext/Print.h. I'd miss out on any direct calls of REprintf, while those should probably still be recorded as a warning/error. b) I'd have to add a fairly elaborate implementation in order to honor any sinks the user has (purposefully) created. If I can even access all necessary data/functions from my code (I have not investigated that, yet). 2) Similar, but add the hook a little later, in REvprintf. There, instead of directly calling R_WriteConsole, a new callback R_WriteError would be used (which defaults to R_WriteConsole). Using this callback I would get a stream of both warnings, and errors, separate from "regular" output. I could tell warnings and errors apart, using options (error=...). 3) Yet a little less intrusive: Somehow use a fake R_ErrorCon: There I'd simply add my own callback for con->vprintf, and con->fflush. Then proceed as in 2. However, it seems Rconnection and the related functions are too tightly guarded against this approach. I simply don't see a way, how I could fake this connection (but maybe there is one?). Maybe a public API could be added to allow this. Ok, so much on my helpless attempts. Could you help me with this? Thanks! Thomas ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel