Files
remind/src/dynbuf.c
Dianne Skoll 05bc3af03d Use size_t rather than int to track dynamic buffer size.
This lets use create dynamic buffers larger than 2GB.
2022-01-22 18:40:27 -05:00

179 lines
5.0 KiB
C

/***************************************************************/
/* */
/* DYNBUF.C */
/* */
/* Implementation of functions for manipulating dynamic */
/* buffers. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
#include "config.h"
#include "dynbuf.h"
#include "err.h"
#include <string.h>
#include <stdlib.h>
/**********************************************************************
%FUNCTION: DBufMakeRoom
%ARGUMENTS:
dbuf -- pointer to a dynamic buffer
n -- size to expand to
%RETURNS:
OK if all went well; E_NO_MEM if out of memory
%DESCRIPTION:
Doubles the size of dynamic buffer until it has room for at least
'n' characters, not including trailing '\0'
**********************************************************************/
static int DBufMakeRoom(DynamicBuffer *dbuf, size_t n)
{
/* Double size until it's greater than n (strictly > to leave room
for trailing '\0' */
size_t size = dbuf->allocatedLen;
char *buf;
if (size > n) return OK;
while (size <= n) {
size *= 2;
}
/* Allocate memory */
buf = malloc(size);
if (!buf) return E_NO_MEM;
/* Copy contents */
strcpy(buf, dbuf->buffer);
/* Free contents if necessary */
if (dbuf->buffer != dbuf->staticBuf) free(dbuf->buffer);
dbuf->buffer = buf;
dbuf->allocatedLen = size;
return OK;
}
/**********************************************************************
%FUNCTION: DBufInit
%ARGUMENTS:
dbuf -- pointer to a dynamic buffer
%RETURNS:
Nothing
%DESCRIPTION:
Initializes a dynamic buffer
**********************************************************************/
void DBufInit(DynamicBuffer *dbuf)
{
dbuf->buffer = dbuf->staticBuf;
dbuf->len = 0;
dbuf->allocatedLen = DBUF_STATIC_SIZE;
dbuf->buffer[0] = 0;
}
/**********************************************************************
%FUNCTION: DBufPutcFN
%ARGUMENTS:
dbuf -- pointer to a dynamic buffer
c -- character to append to buffer
%RETURNS:
OK if all went well; E_NO_MEM if out of memory
%DESCRIPTION:
Appends a character to the buffer.
**********************************************************************/
int DBufPutcFN(DynamicBuffer *dbuf, char c)
{
if (dbuf->allocatedLen == dbuf->len+1) {
if (DBufMakeRoom(dbuf, dbuf->len+1) != OK) return E_NO_MEM;
}
dbuf->buffer[dbuf->len++] = c;
dbuf->buffer[dbuf->len] = 0;
return OK;
}
/**********************************************************************
%FUNCTION: DBufPuts
%ARGUMENTS:
dbuf -- pointer to a dynamic buffer
str -- string to append to buffer
%RETURNS:
OK if all went well; E_NO_MEM if out of memory
%DESCRIPTION:
Appends a string to the buffer.
**********************************************************************/
int DBufPuts(DynamicBuffer *dbuf, char const *str)
{
int l = strlen(str);
if (!l) return OK;
if (DBufMakeRoom(dbuf, dbuf->len+l) != OK) return E_NO_MEM;
strcpy((dbuf->buffer+dbuf->len), str);
dbuf->len += l;
return OK;
}
/**********************************************************************
%FUNCTION: DBufFree
%ARGUMENTS:
dbuf -- pointer to a dynamic buffer
%RETURNS:
Nothing
%DESCRIPTION:
Frees and reinitializes a dynamic buffer
**********************************************************************/
void DBufFree(DynamicBuffer *dbuf)
{
if (dbuf->buffer != dbuf->staticBuf) free(dbuf->buffer);
DBufInit(dbuf);
}
/**********************************************************************
%FUNCTION: DBufGets
%ARGUMENTS:
dbuf -- pointer to a dynamic buffer
fp -- file to read from
%RETURNS:
OK or E_NO_MEM
%DESCRIPTION:
Reads an entire line from a file and appends to dbuf. Does not include
trailing newline.
**********************************************************************/
int DBufGets(DynamicBuffer *dbuf, FILE *fp)
{
char tmp[256]; /* Safe to hard-code */
int busy = 1;
int l;
DBufFree(dbuf);
/* Try reading the first few bytes right into the buffer --
we can usually save some unnecessary copying */
*(dbuf->buffer) = 0;
if (fgets(dbuf->buffer, dbuf->allocatedLen, fp) == NULL) {
return OK;
}
if (!*(dbuf->buffer)) return OK;
dbuf->len = strlen(dbuf->buffer);
l = dbuf->len - 1;
if (dbuf->buffer[l] == '\n') {
dbuf->buffer[l] = 0;
dbuf->len = l;
return OK;
}
while(busy) {
*tmp = 0;
if (fgets(tmp, 256, fp) == NULL) return OK;
if (!*tmp) return OK;
l = strlen(tmp) - 1;
if (tmp[l] == '\n') {
tmp[l] = 0;
busy = 0;
}
if (DBufPuts(dbuf, tmp) != OK) return E_NO_MEM;
}
return OK;
}