/* buffer.c: Routines for C-- buffer manipulation. */
#define _POSIX_SOURCE
#include <ctype.h>
#include "x.tab.h"
#include "data.h"
#include "memory.h"
#define BUFALLOC(len) emalloc(sizeof(Buffer) + (len) - 1)
#define BUFREALLOC(buf, len) erealloc(buf, sizeof(Buffer) + (len) - 1)
static Buffer *prepare_to_modify(Buffer *buf);
Buffer *buffer_new(int len)
{
Buffer *buf;
buf = BUFALLOC(len);
buf->len = len;
buf->refs = 1;
return buf;
}
Buffer *buffer_dup(Buffer *buf)
{
buf->refs++;
return buf;
}
void buffer_discard(Buffer *buf)
{
buf->refs--;
if (!buf->refs)
free(buf);
}
Buffer *buffer_append(Buffer *buf1, Buffer *buf2)
{
if (!buf2->len)
return buf1;
buf1 = prepare_to_modify(buf1);
buf1 = BUFREALLOC(buf1, buf1->len + buf2->len);
MEMCPY(buf1->s + buf1->len, buf2->s, buf2->len);
buf1->len += buf2->len;
return buf1;
}
int buffer_retrieve(Buffer *buf, int pos)
{
return buf->s[pos];
}
Buffer *buffer_replace(Buffer *buf, int pos, unsigned int c)
{
if (buf->s[pos] == c)
return buf;
buf = prepare_to_modify(buf);
buf->s[pos] = OCTET_VALUE(c);
return buf;
}
Buffer *buffer_add(Buffer *buf, unsigned int c)
{
buf = prepare_to_modify(buf);
buf = BUFREALLOC(buf, buf->len + 1);
buf->s[buf->len] = OCTET_VALUE(c);
buf->len++;
return buf;
}
int buffer_len(Buffer *buf)
{
return buf->len;
}
Buffer *buffer_truncate(Buffer *buf, int len)
{
if (len == buf->len)
return buf;
buf = prepare_to_modify(buf);
buf = BUFREALLOC(buf, len);
buf->len = len;
return buf;
}
/* If sep (separator buffer) is NULL, separate by newlines. */
List *buffer_to_strings(Buffer *buf, Buffer *sep)
{
Data d;
String *str;
List *result;
unsigned char sepchar, *string_start, *p, *q;
char *s;
int seplen;
Buffer *end;
sepchar = (sep) ? *sep->s : '\n';
seplen = (sep) ? sep->len : 1;
result = list_new(0);
string_start = p = buf->s;
while (p + seplen <= buf->s + buf->len) {
/* Look for sepchar staring from p. */
p = memchr(p, sepchar, (buf->s + buf->len) - (p + seplen - 1));
if (!p)
break;
/* Keep going if we don't match all of the separator. */
if (sep && MEMCMP(p + 1, sep->s + 1, seplen - 1) != 0) {
p++;
continue;
}
/* We found a separator. Copy the printable characters in the
* intervening text into a string. */
str = string_new(p - string_start);
s = str->s;
for (q = string_start; q < p; q++) {
if (isprint(*q))
*s++ = *q;
}
*s = 0;
str->len = s - str->s;
d.type = STRING;
substr_set_to_full_string(&d.u.substr, str);
result = list_add(result, &d);
string_discard(str);
string_start = p = p + seplen;
}
/* Add the remainder characters to the list as a buffer. */
end = buffer_new(buf->s + buf->len - string_start);
MEMCPY(end->s, string_start, buf->s + buf->len - string_start);
d.type = BUFFER;
d.u.buffer = end;
result = list_add(result, &d);
buffer_discard(end);
return result;
}
Buffer *buffer_from_strings(Data *d, int n, Buffer *sep)
{
Buffer *buf;
int i, len, pos;
unsigned char *s;
/* Find length of finished buffer. */
len = 0;
for (i = 0; i < n; i++)
len += d[i].u.substr.span + ((sep) ? sep->len : 2);
/* Make a buffer and copy the strings into it. */
buf = buffer_new(len);
pos = 0;
for (i = 0; i < n; i++) {
s = (unsigned char *) data_sptr(&d[i]);
MEMCPY(buf->s + pos, s, d->u.substr.span);
pos += d->u.substr.span;
if (sep) {
MEMCPY(buf->s + pos, sep->s, sep->len);
pos += sep->len;
} else {
buf->s[pos++] = '\r';
buf->s[pos++] = '\n';
}
}
return buf;
}
static Buffer *prepare_to_modify(Buffer *buf)
{
Buffer *new;
if (buf->refs == 1)
return buf;
/* Make a new buffer with the same contents as the old one. */
buf->refs--;
new = buffer_new(buf->len);
MEMCPY(new->s, buf->s, buf->len);
return new;
}