From mtmorgan at fhcrc.org  Fri Mar 16 01:48:30 2012
From: mtmorgan at fhcrc.org (Martin Morgan)
Date: Thu, 15 Mar 2012 17:48:30 -0700
Subject: [Rd] Dealing with printf() &c. in third-party library code
In-Reply-To: <CAM9CR=2493iX8V4-5WXSC4461WoSVkWY_USs+J=RAYTCS-gY0w@mail.gmail.com>
References: <CAM9CR=2iwS1E3TFnh5y-SRCh5p3KEtSD1ChO7bVpXgMsRV_PrQ@mail.gmail.com>	<4F61786B.6030200@fhcrc.org>
	<CAM9CR=2493iX8V4-5WXSC4461WoSVkWY_USs+J=RAYTCS-gY0w@mail.gmail.com>
Message-ID: <4F628DDE.9060808@fhcrc.org>

On 03/15/2012 02:24 PM, Jon Clayden wrote:
> Martin,
>
> Thanks for your reply. I wonder if you'd be willing to post your
> "my_fprintf" function, since I'm struggling to get around needing to
> use the "stdout" and "stderr" symbols completely. This function has
> the right effect...
>
> void rniftyreg_fprintf (FILE *stream, const char *format, ...)
> {
>     va_list args;
>     va_start(args, format);
>
>     if (stream == stdout)
>         Rvprintf(format, args);
>     else if (stream == stderr)
>         REvprintf(format, args);
>     else
>         vfprintf(stream, format, args);
>
>     va_end(args);
> }
>
> ... but the R CMD check info message still arises because stdout and
> stderr still appear. I'm struggling to see how to get around this
> without doing something really ugly, like casting integers to FILE*
> pointers.

Hi Jon --

My own implementation is like yours, where I still reference stderr / 
stdout. But it seems like the meaningful problem (writing to stderr / 
stdout, which R might have re-directed) has been addressed (except for 
the third branch, in your code above).

Martin
>
> All the best,
> Jon
>
>
> On 15 March 2012 05:04, Martin Morgan<mtmorgan at fhcrc.org>  wrote:
>> On 03/14/2012 05:15 AM, Jon Clayden wrote:
>>>
>>> Dear all,
>>>
>>> I recognise the reason for strongly discouraging use of printf() and
>>> similar C functions in R packages, but I wonder what people do in
>>> practice about third-party code which may be littered with such calls.
>>> I maintain a package (RNiftyReg) which provides an R interface to a
>>> third-party library which contains hundreds of calls to printf(...),
>>> fprintf(stderr,...) and similar. It seems to me that there are several
>>> possible approaches, but all have their issues:
>>>
>>> 1. Replace all such calls with equivalent Rprintf() calls, using
>>> compiler preprocessing directives to ensure the library does not
>>> become incompatible with other code. For example,
>>>
>>> #ifdef RNIFTYREG
>>> Rprintf(...);
>>> #else
>>> printf(...);
>>> #endif
>>>
>>> This will be very time-consuming if there are lots of calls, and also
>>> makes the code very untidy and much harder to update when a new
>>> version of the upstream library is released.
>>>
>>> 2. Remove all such calls from the code altogether, or comment them
>>> out. The problem here is that doing this safely is hard, because the
>>> call could be part of an "if" statement or similar. For example,
>>>
>>> if (test)
>>>   printf("Something");
>>> do_something_important;
>>>
>>> If the middle line here is removed, then the last line becomes
>>> (erroneously) conditioned on the test. Plus, once again, you are
>>> introducing a lot of small changes to the library itself.
>>>
>>> 3. Redefine printf to use Rprintf, viz.
>>>
>>> #ifdef RNIFTYREG
>>> #include<R.h>
>>> #define printf Rprintf
>>> #endif
>>>
>>> This will compile as long as the R function is a drop-in replacement
>>> for the original function, which I believe is true for Rprintf (vs.
>>> printf), but isn't true for Calloc (vs. calloc), for example. And I'm
>>> not sure whether this approach can be used to deal with cases of the
>>> form fprintf(stderr,...), where stderr would need to be redefined.
>>> This approach requires only modest changes to the library itself, but
>>> may be fragile to future changes in R.
>>>
>>> Are there any other (better?) alternatives? Any thoughts or advice
>>> would be appreciated.
>>
>>
>> In Makevars, I add -Dfprintf=my_fprintf to the pre-processor flags and then
>> implement my_fprintf in a separate source file. This means that the source
>> code of the 3rd party library is not touched, and there is some scope for
>> re-mapping or otherwise intercepting function arguments. For abort and
>> error, I throw an error that encourages the user to save and quit
>> immediately, though this is far from ideal. I too would be interested in
>> better practices for dealing with this, short of whole-sale modification of
>> the third-party library.
>>
>> Martin
>>
>>>
>>> All the best,
>>> Jon
>>>
>>> ______________________________________________
>>> R-devel at r-project.org mailing list
>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>>
>>
>> --
>> Computational Biology
>> Fred Hutchinson Cancer Research Center
>> 1100 Fairview Ave. N. PO Box 19024 Seattle, WA 98109
>>
>> Location: M1-B861
>> Telephone: 206 667-2793


-- 
Computational Biology
Fred Hutchinson Cancer Research Center
1100 Fairview Ave. N. PO Box 19024 Seattle, WA 98109

Location: M1-B861
Telephone: 206 667-2793



[Rd] Dealing with printf() &c. in third-party library code
Martin Morgan