/* buffer.c: Routines for C-- buffer manipulation. */ #define _POSIX_SOURCE #include <ctype.h> #include "x.tab.h" #include "buffer.h" #include "memory.h" #define BUFALLOC(len) (Buffer *)emalloc(sizeof(Buffer) + (len) - 1) #define BUFREALLOC(buf, len) (Buffer *)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 = (unsigned char *)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; d.u.str = 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(List *string_list, Buffer *sep) { Data *string_data; Buffer *buf; int num_strings, i, len, pos; unsigned char *s; string_data = list_first(string_list); num_strings = list_length(string_list); /* Find length of finished buffer. */ len = 0; for (i = 0; i < num_strings; i++) len += string_length(string_data[i].u.str) + ((sep) ? sep->len : 2); /* Make a buffer and copy the strings into it. */ buf = buffer_new(len); pos = 0; for (i = 0; i < num_strings; i++) { s = string_chars(string_data[i].u.str); len = string_length(string_data[i].u.str); MEMCPY(buf->s + pos, s, len); pos += len; 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 *cnew; if (buf->refs == 1) return buf; /* Make a new buffer with the same contents as the old one. */ buf->refs--; cnew = buffer_new(buf->len); MEMCPY(cnew->s, buf->s, buf->len); return cnew; }