Index: src/include/R_ext/Makefile.in =================================================================== --- src/include/R_ext/Makefile.in (revision 39795) +++ src/include/R_ext/Makefile.in (working copy) @@ -19,7 +19,7 @@ Error.h GetX11Image.h \ GraphicsDevice.h GraphicsEngine.h GraphicsBase.h \ Lapack.h Linpack.h Memory.h \ - Parse.h Print.h PrtUtil.h R-ftp-http.h RS.h Random.h RConverters.h \ + Parse.h Print.h PrtUtil.h R-ftp-http.h RConn.h RS.h Random.h RConverters.h \ Rdynload.h Riconv.h RStartup.h Utils.h eventloop.h libextern.h rlocale.h DISTFILES = Makefile.in $(R_EXT_HEADERS) Index: src/include/R_ext/RConn.h =================================================================== --- src/include/R_ext/RConn.h (revision 0) +++ src/include/R_ext/RConn.h (revision 0) @@ -0,0 +1,78 @@ +/* + * R : A Computer Language for Statistical Data Analysis + * Copyright (C) 2000-2006 The R Development Core Team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef R_CONN_H_ +#define R_CONN_H_ +#include + +#ifndef HAVE_RCONNECTION_TYPEDEF +typedef struct Rconn *Rconnection; +#define HAVE_RCONNECTION_TYPEDEF +#endif + +struct Rconn { + char* class; + char* description; + char mode[5]; + Rboolean text, isopen, incomplete, canread, canwrite, canseek, blocking, + isGzcon; + Rboolean (*open)(struct Rconn *); + void (*close)(struct Rconn *); /* routine closing after auto open */ + void (*destroy)(struct Rconn *); /* when closing connection */ + int (*vfprintf)(struct Rconn *, const char *, va_list); + int (*fgetc)(struct Rconn *); + int (*fgetc_internal)(struct Rconn *); +/* int (*ungetc)(int c, struct Rconn *); */ + double (*seek)(struct Rconn *, double, int, int); + void (*truncate)(struct Rconn *); + int (*fflush)(struct Rconn *); + size_t (*read)(void *, size_t, size_t, struct Rconn *); + size_t (*write)(const void *, size_t, size_t, struct Rconn *); +/* void (*onerror)(struct Rconn *); */ + int nPushBack, posPushBack; /* number of lines, position on top line */ + char **PushBack; + int save, save2; + /* unsigned char encoding[256];*/ + char encname[101]; + /* will be iconv_t, which is a pointer. NULL if not in use */ + void *inconv, *outconv; + /* The idea here is that no MBCS char will ever not fit */ + char iconvbuff[25], oconvbuff[50], *next, init_out[25]; + short navail, inavail; + Rboolean EOF_signalled; + void *private; +}; + +/* Public functions availabe to package writers */ +int R_RegisterStdinConnection(SEXP scon); +int R_RegisterStdoutConnection(SEXP scon); +int R_RegisterStderrConnection(SEXP scon); +SEXP R_NewConnection(char *class, char *description, char *mode, + Rconnection *con); +Rconnection R_GetConnection(Rconnection ucon, int idx); +void R_CloseConnection(int idx); +int R_VfprintfConnection(int idx, const char *format, va_list ap); +int R_FgetcConnection(int idx); +double R_SeekConnection(int idx, double where, int origin, int rw); +void R_TruncateConnection(int idx); +int R_FlushConnection(int idx); +size_t R_ReadConnection(int idx, void *buf, size_t size, size_t n); +size_t R_WriteConnection(int idx, const void *buf, size_t size, size_t n); +size_t R_WriteRConnection(Rconnection con, void *buf, size_t n); +#endif Index: src/include/Rconnections.h =================================================================== --- src/include/Rconnections.h (revision 39795) +++ src/include/Rconnections.h (working copy) @@ -19,46 +19,8 @@ #ifndef R_CONNECTIONS_H_ #define R_CONNECTIONS_H_ -#include +#include -/* until we make connections more public this allows the opaque - pointer definition to be made available in Rinternals.h */ -#ifndef HAVE_RCONNECTION_TYPEDEF -typedef struct Rconn *Rconnection; -#endif -struct Rconn { - char* class; - char* description; - char mode[5]; - Rboolean text, isopen, incomplete, canread, canwrite, canseek, blocking, - isGzcon; - Rboolean (*open)(struct Rconn *); - void (*close)(struct Rconn *); /* routine closing after auto open */ - void (*destroy)(struct Rconn *); /* when closing connection */ - int (*vfprintf)(struct Rconn *, const char *, va_list); - int (*fgetc)(struct Rconn *); - int (*fgetc_internal)(struct Rconn *); -/* int (*ungetc)(int c, struct Rconn *); */ - double (*seek)(struct Rconn *, double, int, int); - void (*truncate)(struct Rconn *); - int (*fflush)(struct Rconn *); - size_t (*read)(void *, size_t, size_t, struct Rconn *); - size_t (*write)(const void *, size_t, size_t, struct Rconn *); -/* void (*onerror)(struct Rconn *); */ - int nPushBack, posPushBack; /* number of lines, position on top line */ - char **PushBack; - int save, save2; - /* unsigned char encoding[256];*/ - char encname[101]; - /* will be iconv_t, which is a pointer. NULL if not in use */ - void *inconv, *outconv; - /* The idea here is that no MBCS char will ever not fit */ - char iconvbuff[25], oconvbuff[50], *next, init_out[25]; - short navail, inavail; - Rboolean EOF_signalled; - void *private; -}; - typedef struct fileconn { FILE *fp; #if defined(HAVE_OFF_T) && defined(HAVE_SEEKO) Index: src/main/connections.c =================================================================== --- src/main/connections.c (revision 39795) +++ src/main/connections.c (working copy) @@ -3696,7 +3696,7 @@ connection. It is mainly intended as a means for C code to do a buffered write to sockets, but could be the start of a more extensive C-level connection API. LT */ -size_t R_WriteConnection(Rconnection con, void *buf, size_t n) +size_t R_WriteRConnection(Rconnection con, void *buf, size_t n) { if(!con->isopen) error(_("connection is not open")); if(!con->canwrite) error(_("cannot write to this connection")); @@ -3704,6 +3704,197 @@ return con->write(buf, 1, n, con); } +int R_RegisterStdinConnection(SEXP scon) +{ + int icon = asInteger(scon); + Rconnection con=NULL; + con = getConnection(icon); + if (!con) return -1; + if(!con->canread) { + error(_("cannot read from this connection")); + return -1; + } + + con_close(0); + Connections[0] = con; + Connections[icon] = NULL; + return 0; +} + +int R_RegisterStdoutConnection(SEXP scon) +{ + int icon = asInteger(scon); + Rconnection con=NULL; + con = getConnection(icon); + if (!con) return -1; + if(!con->canwrite) { + error(_("cannot read from this connection")); + return -1; + } + + con_close(1); + Connections[1] = con; + Connections[icon] = NULL; + return 0; +} + +int R_RegisterStderrConnection(SEXP scon) +{ + int icon = asInteger(scon); + Rconnection con=NULL; + con = getConnection(icon); + if (!con) return -1; + if(!con->canwrite) { + error(_("cannot read from this connection")); + return -1; + } + + con_close(2); + Connections[2] = con; + Connections[icon] = NULL; + return 0; +} +/* Alternative to allow C code access to connection API. */ +SEXP R_NewConnection(char *class, char *description, char *mode, + Rconnection *con) +{ + SEXP sclass, ans; + Rconnection new = NULL; + int ncon; + + /* Get index before we allocate memory */ + ncon = NextConnection(); + + new = (Rconnection) malloc(sizeof(struct Rconn)); + if(!new) error(_("allocation of new connection failed")); + new->class = (char *) malloc(strlen(class) + 1); + if(!new->class) { + free(new); + error(_("allocation of new connection failed")); + } + strcpy(new->class, class); + new->description = (char *) malloc(strlen(description) + 1); + if(!new->description) { + free(new->class); free(new); + error(_("allocation of new connection failed")); + } + init_con(new, description, mode); + new->isopen = TRUE; + new->canread = (strcmp(mode, "r") == 0); + new->canwrite = (strcmp(mode, "w") == 0); + new->destroy = &null_close; + new->private = NULL; + + /* Add to Connections, and also + * allow users to assign function + * pointer members + */ + *con = Connections[ncon] = new; + + /* Create something to pass to R code */ + PROTECT(ans = allocVector(INTSXP, 1)); + INTEGER(ans)[0] = ncon; + PROTECT(sclass = allocVector(STRSXP, 2)); + SET_STRING_ELT(sclass, 0, mkChar(class)); + SET_STRING_ELT(sclass, 1, mkChar("connection")); + classgets(ans, sclass); + UNPROTECT(2); + + return ans; +} + + +Rconnection R_GetConnection(Rconnection ucon, int idx){ + Rconnection rcon; + + /* Valid connection? */ + if ((rcon = getConnection(idx)) == NULL) + return NULL; + + memcpy(ucon,rcon,sizeof(struct Rconn)); + + /* Don't reveal private data */ + ucon->private = NULL; + + return ucon; +} + +void R_CloseConnection(int idx){ + Rconnection con = getConnection(idx); + + if (con) con->close(con); +} + + +int R_VfprintfConnection(int idx, const char *format, va_list ap){ + Rconnection con = getConnection(idx); + + if (!con) return -1; /* just like fprintf(3)? */ + + if(!con->isopen) error(_("connection is not open")); + if(!con->canwrite) error(_("cannot write to this connection")); + + return con->vfprintf(con,format,ap); +} + +int R_FgetcConnection(int idx){ + Rconnection con = getConnection(idx); + + if (!con) return EOF; /* just like fgetc(3)? */ + + if(!con->isopen) error(_("connection is not open")); + if(!con->canread) error(_("cannot read from this connection")); + + return con->fgetc(con); +} + +double R_SeekConnection(int idx, double where, int origin, int rw){ + Rconnection con = getConnection(idx); + + if (!con) return -1; /* just like fseek(3)? */ + if(!con->isopen) error(_("connection is not open")); + if(!con->canseek) error(_("cannot seek on this connection")); + + return con->seek(con,where,origin,rw); +} + +void R_TruncateConnection(int idx){ + Rconnection con = getConnection(idx); + + if (con) con->truncate(con); +} + +int R_FlushConnection(int idx){ + Rconnection con = getConnection(idx); + + if (!con) return EOF; /* like fflush(3) */ + + return con->fflush(con); +} + +size_t R_ReadConnection(int idx, void *buf, size_t size, size_t n){ + Rconnection con = getConnection(idx); + + if (!con) return 0; + + if(!con->isopen) error(_("connection is not open")); + if(!con->canread) error(_("cannot read from this connection")); + + return con->read(buf,size,n,con); +} + +size_t R_WriteConnection(int idx, const void *buf, size_t size, size_t n) +{ + Rconnection con = getConnection(idx); + + if (!con) return -1; /* just like write(2)? */ + + if(!con->isopen) error(_("connection is not open")); + if(!con->canwrite) error(_("cannot write to this connection")); + + return con->write(buf, size, n, con); +} + /* ------------------- (de)compression functions --------------------- */ static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ Index: src/main/serialize.c =================================================================== --- src/main/serialize.c (revision 39795) +++ src/main/serialize.c (working copy) @@ -1788,7 +1788,7 @@ */ /**** should eventually come from a public header file */ -size_t R_WriteConnection(Rconnection con, void *buf, size_t n); +/* size_t R_WriteConnection(Rconnection con, void *buf, size_t n); */ #define BCONBUFSIZ 4096 @@ -1800,7 +1800,7 @@ static void flush_bcon_buffer(bconbuf_t bb) { - if (R_WriteConnection(bb->con, bb->buf, bb->count) != bb->count) + if (R_WriteRConnection(bb->con, bb->buf, bb->count) != bb->count) error(_("error writing to connection")); bb->count = 0; } @@ -1822,7 +1822,7 @@ memcpy(bb->buf + bb->count, buf, length); bb->count += length; } - else if (R_WriteConnection(bb->con, buf, length) != length) + else if (R_WriteRConnection(bb->con, buf, length) != length) error(_("error writing to connection")); }