blob: dcb117091df82740700b39ca5cb3b0a5a0823d5b [file] [log] [blame]
/*
* R : A Computer Language for Statistical Data Analysis
* Copyright (C) 1995, 1996, 1997, Robert Gentleman and Ross Ihaka
* 2007-2014 The R 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, a copy is available at
* https://www.R-project.org/Licenses/
*
*
* I/O Support Code
*
* This is a general IO support package to provide R with a uniform
* interface to reading data from the console, files and internal
* text strings.
*
* This is probably overkill, but it works much better than the
* previous anarchy.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "IOStuff.h"
/* Move the iob->write_buf pointer to the next */
/* BufferListItem in the chain. If there no next */
/* buffer item, then one is added. */
static int NextWriteBufferListItem(IoBuffer *iob)
{
if (iob->write_buf->next) {
iob->write_buf = iob->write_buf->next;
}
else {
BufferListItem *_new;
if (!(_new = (BufferListItem*)malloc(sizeof(BufferListItem))))
return 0;
_new->next = NULL;
iob->write_buf->next = _new;
iob->write_buf = iob->write_buf->next;
}
iob->write_ptr = iob->write_buf->buf;
iob->write_offset = 0;
return 1;
}
/* Move the iob->read_buf pointer to the next */
/* BufferListItem in the chain. */
static int NextReadBufferListItem(IoBuffer *iob)
{
iob->read_buf = iob->read_buf->next;
iob->read_ptr = iob->read_buf->buf;
iob->read_offset = 0;
return 1;
}
/* Reset the read/write pointers of an IoBuffer */
int attribute_hidden R_IoBufferWriteReset(IoBuffer *iob)
{
if (iob == NULL || iob->start_buf == NULL)
return 0;
iob->write_buf = iob->start_buf;
iob->write_ptr = iob->write_buf->buf;
iob->write_offset = 0;
iob->read_buf = iob->start_buf;
iob->read_ptr = iob->read_buf->buf;
iob->read_offset = 0;
return 1;
}
/* Reset the read pointer of an IoBuffer */
int attribute_hidden R_IoBufferReadReset(IoBuffer *iob)
{
if (iob == NULL || iob->start_buf == NULL)
return 0;
iob->read_buf = iob->start_buf;
iob->read_ptr = iob->read_buf->buf;
iob->read_offset = 0;
return 1;
}
/* Allocate an initial BufferListItem for IoBuffer */
/* Initialize the counts and pointers. */
int attribute_hidden R_IoBufferInit(IoBuffer *iob)
{
if (iob == NULL) return 0;
iob->start_buf = (BufferListItem*)malloc(sizeof(BufferListItem));
if (iob->start_buf == NULL) return 0;
iob->start_buf->next = NULL;
return R_IoBufferWriteReset(iob);
}
/* Free any BufferListItem's associated with an IoBuffer */
/* This resets pointers to NULL, which could be detected */
/* in other calls. */
int attribute_hidden R_IoBufferFree(IoBuffer *iob)
{
BufferListItem *thisItem, *nextItem;
if (iob == NULL || iob->start_buf == NULL)
return 0;
thisItem = iob->start_buf;
while (thisItem) {
nextItem = thisItem->next;
free(thisItem);
thisItem = nextItem;
}
return 1;
}
/* Add a character to an IoBuffer */
int attribute_hidden R_IoBufferPutc(int c, IoBuffer *iob)
{
if (iob->write_offset == IOBSIZE)
NextWriteBufferListItem(iob);
*(iob->write_ptr)++ = (char) c;
iob->write_offset++;
return 0;/*not used*/
}
/* Add a (null terminated) string to an IoBuffer */
int attribute_hidden R_IoBufferPuts(char *s, IoBuffer *iob)
{
char *p;
int n = 0;
for (p = s; *p; p++) {
R_IoBufferPutc(*p, iob);
n++;
}
return n;
}
/* Read a character from an IoBuffer */
int attribute_hidden R_IoBufferGetc(IoBuffer *iob)
{
if (iob->read_buf == iob->write_buf &&
iob->read_offset >= iob->write_offset)
return EOF;
if (iob->read_offset == IOBSIZE) NextReadBufferListItem(iob);
iob->read_offset++;
return *(iob->read_ptr)++;
}
/* What is our current offset, taking all blocks into account? */
int attribute_hidden R_IoBufferReadOffset(IoBuffer *iob)
{
int result = iob->read_offset;
BufferListItem* buf = iob->start_buf;
while(buf && buf != iob->read_buf) {
result += IOBSIZE;
buf = buf->next;
}
return result;
}
/* Initialization code for text buffers */
static void transferChars(unsigned char *p, const char *q)
{
while (*q) *p++ = *q++;
*p++ = '\n';
*p++ = '\0';
}
int attribute_hidden R_TextBufferInit(TextBuffer *txtb, SEXP text)
{
int i, k, l, n;
if (isString(text)) {
// translateChar might allocate
void *vmax = vmaxget();
n = length(text);
l = 0;
for (i = 0; i < n; i++) {
if (STRING_ELT(text, i) != R_NilValue) {
k = (int) strlen(translateChar(STRING_ELT(text, i)));
if (k > l)
l = k;
}
}
vmaxset(vmax);
txtb->vmax = vmax;
txtb->buf = (unsigned char *)R_alloc(l+2, sizeof(char)); /* '\n' and '\0' */
txtb->bufp = txtb->buf;
txtb->text = text;
txtb->ntext = n;
txtb->offset = 0;
transferChars(txtb->buf,
translateChar(STRING_ELT(txtb->text, txtb->offset)));
txtb->offset++;
return 1;
}
else {
txtb->vmax = vmaxget();
txtb->buf = NULL;
txtb->bufp = NULL;
txtb->text = R_NilValue;
txtb->ntext = 0;
txtb->offset = 1;
return 0;
}
}
/* Finalization code for text buffers */
int attribute_hidden R_TextBufferFree(TextBuffer *txtb)
{
vmaxset(txtb->vmax);
return 0;/* not used */
}
/* Getc for text buffers */
int attribute_hidden R_TextBufferGetc(TextBuffer *txtb)
{
if (txtb->buf == NULL)
return EOF;
if (*(txtb->bufp) == '\0') {
if (txtb->offset == txtb->ntext) {
txtb->buf = NULL;
return EOF;
} else {
const void *vmax = vmaxget();
transferChars(txtb->buf,
translateChar(STRING_ELT(txtb->text, txtb->offset)));
txtb->bufp = txtb->buf;
txtb->offset++;
vmaxset(vmax);
}
}
return *txtb->bufp++;
}