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