From ripley at stats.ox.ac.uk  Sun Jun  5 09:34:09 2005
From: ripley at stats.ox.ac.uk (Prof Brian Ripley)
Date: Sun Jun  5 09:34:18 2005
Subject: [Rd] Characters in lists.
In-Reply-To: <42A20871.7050509@berkeley.edu>
References: <42A20871.7050509@berkeley.edu>
Message-ID: <Pine.LNX.4.61.0506050824230.26525@gannet.stats>

On Sat, 4 Jun 2005, James Bullard wrote:

> Hi all, this should be a relatively straightforward question. I am 
> constructing an R list in C which will contain both Integers and Strings (by 
> string I mean in C I have const char* whose values I want passed through to 
> R) The Integers are easy. I do something like this:
>
> PROTECT(tmp = NEW_INTEGER(1));
> INTEGER(tmp)[0] = header.GetCols();
> SET_STRING_ELT(names, i, mkChar("cols"));
> SET_VECTOR_ELT(vals, i++, tmp);
> UNPROTECT(1);
>
> This works just fine. So, when I wanted to set a string element of the list 
> (please correct my nomenclature if I am refering to things incorrectly) I 
> used the following bit of code:
>
> SET_STRING_ELT(names, i, mkChar("header"));
> SET_VECTOR_ELT(vals, i++, mkChar(header.GetHeader().c_str()));
>
> I did this based on the fact that this is how I have created named attributes 
> for lists in the past and it seemed to work fine, however in R when I call 
> the function I get the following results (sorry for the output, but I think 
> the important thing is the <CHARSXP: ...>).
>
> $header
> <CHARSXP: 
> "Cols=712\rRows=712\rTotalX=712\rTotalY=712\rOffsetX=0\rOffsetY=0\rGridCornerUL=162 
> 119\rGridCornerUR=5286 153\rGridCornerLR=5253 5270\rGridCornerLL=130 
> 5237\rAxis-invertX=0\rAxisInvertY=0\rswapXY=0\rDatHeader=[0..65528] 
> T1:CLS=5412 RWS=5412 XIN=2  YIN=2  VE=30        2.0 07/09/04 13:38:45 
> 50101350  M10   \024  \024 Doe16s.1sq \024  \024  \024  \024  \024  \024 
> \024  \024  \024 
> 6\rAlgorithm=Percentile\rAlgorithmParameters=Percentile:75;CellMargin:2;OutlierHigh:1.500;OutlierLow:1.004;AlgVersion:6.0;FixedCellSize:FALSE;IgnoreOutliersInShiftRows:FALSE;FeatureExtraction:FALSE;UseSubgrids:FALSE;RandomizePixels:FALSE;ErrorBasis:StdvMean;StdMult:1.000000\r">

A character vector is a STRSXP, so mkChar is not the right function.

> Ok, so then I thought to try something a little closer to how I did the 
> INTEGER. So I used the following code:
>
> PROTECT(tmp = NEW_CHARACTER(1));
> CHAR(tmp)[0] = *header.GetHeader().c_str();
> SET_STRING_ELT(names, i, mkChar("header"));
> SET_VECTOR_ELT(vals, i++, tmp);
> UNPROTECT(1);
>
> Which in R returns the following:
>
> $header
> [1] ""
>
> So that is not working.

As STRSXPs are not structured identically to INTSXPs.

> So the question is: given a function in C/C++ which 
> returns a const char* how do I correctly create an R character string/vector 
> (terminology?) to set as a list element. Thanks for any advice or any 
> particular parts of the R source tree which might be illuminating. Also, if 
> anyone knows some shorter code for the above code which sets the INTEGER 
> elements of the list that would be nice as well.

You want mkString, e.g.

SET_STRING_ELT(names, i, mkChar("header"));
SET_VECTOR_ELT(vals, i++, mkString(*header.GetHeader().c_str()));

I would have written

> PROTECT(tmp = NEW_INTEGER(1));
> INTEGER(tmp)[0] = header.GetCols();
> SET_STRING_ELT(names, i, mkChar("cols"));
> SET_VECTOR_ELT(vals, i++, tmp);
> UNPROTECT(1);

as

SET_STRING_ELT(names, i, mkChar("cols"));
tmp = allocVector(INTSXP, 1)
INTEGER(tmp)[0] = header.GetCols();
SET_VECTOR_ELT(vals, i++, tmp);

as no further allocation and hence no PROTECTion is required.  You could 
encapsulate it as a function (mkInt?) if you prefer.

-- 
Brian D. Ripley,                  ripley@stats.ox.ac.uk
Professor of Applied Statistics,  http://www.stats.ox.ac.uk/~ripley/
University of Oxford,             Tel:  +44 1865 272861 (self)
1 South Parks Road,                     +44 1865 272866 (PA)
Oxford OX1 3TG, UK                Fax:  +44 1865 272595


[Rd] Characters in lists.
Prof Brian Ripley