/* * 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 #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++; }