Rev 77730 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/** R : A Computer Language for Statistical Data Analysis* Copyright (C) 1995, 1996, 1997, Robert Gentleman and Ross Ihaka* 2007-2025 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 */attribute_hidden int 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 */attribute_hidden int 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. */attribute_hidden int 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. */attribute_hidden int 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 */attribute_hidden int 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 */attribute_hidden int 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 */attribute_hidden int 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? */attribute_hidden int 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';}/* respect encoding override from parser invocation - do_parse */static const char *translateCharWithOverride(SEXP x){if (!IS_LATIN1(x) && !mbcslocale && known_to_be_utf8)/* A hack to allow UTF-8 string literals, comments whenparsing on Windows. Note that the parser cannot handleinvalid characters when running in UTF-8 locale. */return CHAR(x);elsereturn translateChar(x);}attribute_hidden int R_TextBufferInit(TextBuffer *txtb, SEXP text){int i, k, l, n;if (isString(text)) {// translateChar might allocatevoid *vmax = vmaxget();n = length(text);l = 0;for (i = 0; i < n; i++) {if (STRING_ELT(text, i) != R_NilValue) {k = (int) strlen(translateCharWithOverride(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,translateCharWithOverride(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 */attribute_hidden int R_TextBufferFree(TextBuffer *txtb){vmaxset(txtb->vmax);return 0;/* not used */}/* Getc for text buffers */attribute_hidden int 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,translateCharWithOverride(STRING_ELT(txtb->text,txtb->offset)));txtb->bufp = txtb->buf;txtb->offset++;vmaxset(vmax);}}return *txtb->bufp++;}