I waited until April 3 to post this, so it wouldn't be taken as an April Fool's joke! A recent R News item announces that we now have a bona fide mechanism to create custom connections in R! This makes it possible to implement a custom connection in an R package. Until now, the only feasible alternative was to write a patch (but see also this trick), as I had done to implement a tty connection! Of course, this was a suboptimal solution that required an update for each new version of R. In fact, my last update was for R v2.13.1. This new development will make it much easier to share this code. I will also need to update my first draft of R Connection Internals, which is now three years old. Perhaps the document is better suited as a package vignette. More to follow later...
So that we know who to thank:
matt@deb6box$ svn log -r 62016 http://svn.r-project.org/R/trunk/src/include/R_ext/Connections.h ------------------------------------------------------------------------ r62016 | urbaneks | 2013-02-21 14:29:44 -0500 (Thu, 21 Feb 2013) | 1 line add API to create custom connections ------------------------------------------------------------------------
Here is the header file itself, with credits. It looks like all of the Rconnection struct is made available. But, notice the warning!
matt@deb6box$ svn blame -r 62016 http://svn.r-project.org/R/trunk/src/include/R_ext/Connections.h 11656 ripley /* 11656 ripley * R : A Computer Language for Statistical Data Analysis 62016 urbaneks * Copyright (C) 2000-2013 The R Core Team. 11656 ripley * 11656 ripley * This program is free software; you can redistribute it and/or modify 11656 ripley * it under the terms of the GNU General Public License as published by 11656 ripley * the Free Software Foundation; either version 2 of the License, or 11656 ripley * (at your option) any later version. 11656 ripley * 11656 ripley * This program is distributed in the hope that it will be useful, 11656 ripley * but WITHOUT ANY WARRANTY; without even the implied warranty of 11656 ripley * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11656 ripley * GNU General Public License for more details. 11656 ripley * 11656 ripley * You should have received a copy of the GNU General Public License 42308 ripley * along with this program; if not, a copy is available at 42308 ripley * http://www.r-project.org/Licenses/ 11656 ripley */ 11656 ripley 62016 urbaneks #ifndef R_EXT_CONNECTIONS_H_ 62016 urbaneks #define R_EXT_CONNECTIONS_H_ 62016 urbaneks 11668 ripley #include11668 ripley 62016 urbaneks #ifndef NO_C_HEADERS 62016 urbaneks # include /* for size_t */ 62016 urbaneks # include /* for va_list */ 42677 urbaneks #endif 42677 urbaneks 62016 urbaneks /* IMPORTANT: we do not expect future connection APIs to be 62016 urbaneks backward-compatible so if you use this, you *must* check the version 62016 urbaneks and proceed only if it matches what you expect 62016 urbaneks 62016 urbaneks We explicitly reserve the right to change the connection 62016 urbaneks implementation without a compatibility layer. 62016 urbaneks */ 62016 urbaneks #define R_CONNECTIONS_VERSION 1 62016 urbaneks 45984 ripley /* this allows the opaque pointer definition to be made available 44013 ripley in Rinternals.h */ 16472 luke #ifndef HAVE_RCONNECTION_TYPEDEF 16472 luke typedef struct Rconn *Rconnection; 16472 luke #endif 16472 luke struct Rconn { 11656 ripley char* class; 11656 ripley char* description; 44013 ripley int enc; /* the encoding of 'description' */ 11656 ripley char mode[5]; 23228 ripley Rboolean text, isopen, incomplete, canread, canwrite, canseek, blocking, 23228 ripley isGzcon; 18583 ripley Rboolean (*open)(struct Rconn *); 11656 ripley void (*close)(struct Rconn *); /* routine closing after auto open */ 11656 ripley void (*destroy)(struct Rconn *); /* when closing connection */ 11656 ripley int (*vfprintf)(struct Rconn *, const char *, va_list); 11656 ripley int (*fgetc)(struct Rconn *); 32497 ripley int (*fgetc_internal)(struct Rconn *); 31166 ripley double (*seek)(struct Rconn *, double, int, int); 13305 ripley void (*truncate)(struct Rconn *); 11656 ripley int (*fflush)(struct Rconn *); 11656 ripley size_t (*read)(void *, size_t, size_t, struct Rconn *); 11656 ripley size_t (*write)(const void *, size_t, size_t, struct Rconn *); 59167 ripley int nPushBack, posPushBack; /* number of lines, position on top line */ 11656 ripley char **PushBack; 12256 pd int save, save2; 32492 ripley char encname[101]; 32492 ripley /* will be iconv_t, which is a pointer. NULL if not in use */ 32492 ripley void *inconv, *outconv; 32497 ripley /* The idea here is that no MBCS char will ever not fit */ 32497 ripley char iconvbuff[25], oconvbuff[50], *next, init_out[25]; 32497 ripley short navail, inavail; 32497 ripley Rboolean EOF_signalled; 44101 ripley Rboolean UTF8out; 41765 ripley void *id; 41765 ripley void *ex_ptr; 11656 ripley void *private; 61527 ripley int status; /* for pipes etc */ 16472 luke }; 11656 ripley 62016 urbaneks #ifdef __cplusplus 62016 urbaneks extern "C" { 62016 urbaneks #endif 11656 ripley 62016 urbaneks SEXP R_new_custom_connection(const char *description, const char *mode, const char *class_name, Rconnection *ptr); 62016 urbaneks size_t R_ReadConnection(Rconnection con, void *buf, size_t n); 62016 urbaneks size_t R_WriteConnection(Rconnection con, void *buf, size_t n); 13366 ripley 62016 urbaneks #ifdef __cplusplus 62016 urbaneks } 25961 ripley #endif 25961 ripley 62016 urbaneks #endif