/*
// Full copyright information is available in the file ../doc/CREDITS
//
// Routines for ColdC buffer manipulation.
*/
#include "defs.h"
#include <ctype.h>
#include "util.h"
#define BUFALLOC(len) (cBuf *)emalloc(sizeof(cBuf) + (len) - 1)
#define BUFREALLOC(buf, len) (cBuf *)erealloc(buf, sizeof(cBuf) + (len) - 1)
cBuf *buffer_new(Int len) {
cBuf *buf;
buf = BUFALLOC(len);
buf->len = len;
buf->refs = 1;
return buf;
}
cBuf *buffer_dup(cBuf *buf) {
buf->refs++;
return buf;
}
void buffer_discard(cBuf *buf) {
buf->refs--;
if (!buf->refs)
efree(buf);
}
cBuf *buffer_append(cBuf *buf1, cBuf *buf2) {
if (!buf2->len)
return buf1;
buf1 = buffer_prep(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(cBuf *buf, Int pos) {
return buf->s[pos];
}
cBuf *buffer_replace(cBuf *buf, Int pos, uInt c) {
if (buf->s[pos] == c)
return buf;
buf = buffer_prep(buf);
buf->s[pos] = OCTET_VALUE(c);
return buf;
}
cBuf *buffer_add(cBuf *buf, uInt c) {
buf = buffer_prep(buf);
buf = BUFREALLOC(buf, buf->len + 1);
buf->s[buf->len] = OCTET_VALUE(c);
buf->len++;
return buf;
}
cBuf *buffer_resize(cBuf *buf, Int len) {
if (len == buf->len)
return buf;
buf = buffer_prep(buf);
buf = BUFREALLOC(buf, len);
buf->len = len;
return buf;
}
/* REQUIRES char *s and unsigned char *q are defined */
#define SEPCHAR '\n'
#define SEPLEN 1
#define VERIFY_SIZE(_STR_) \
cStr * buf_to_string(cBuf * buf) {
cStr * str, * out;
unsigned char * string_start, *p, *q;
char * s;
size_t len;
#define SEPCHAR '\n'
#define SEPLEN 1
out = string_new(buf->len);
string_start = p = buf->s;
while (p + SEPLEN <= buf->s + buf->len) {
p = (unsigned char *) memchr(p, SEPCHAR, (buf->s + buf->len) - p);
if (!p)
break;
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;
out = string_add(out, str);
out = string_add_chars(out, "\\n", 2);
string_discard(str);
string_start = p = p + SEPLEN;
}
if ((len = (buf->s + buf->len) - string_start)) {
str = string_new(len);
s = str->s;
for (q = string_start; len--; q++) {
if (ISPRINT(*q))
*s++ = *q;
}
*s = (char) NULL;
str->len = s - str->s;
out = string_add(out, str);
string_discard(str);
}
#undef SEPCHAR
#undef SEPLEN
return out;
}
#undef SEPCHAR
#undef SEPLEN
/* If sep (separator buffer) is NULL, separate by newlines. */
cList *buf_to_strings(cBuf *buf, cBuf *sep)
{
cData d;
cStr *str;
cList *result;
unsigned char sepchar, *string_start;
register unsigned char *p, *q;
register char *s;
Int seplen;
cBuf *end;
sepchar = (sep) ? *sep->s : '\n';
seplen = (sep) ? sep->len : 1;
result = list_new(0);
string_start = p = buf->s;
d.type = STRING;
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 = (char) NULL;
str->len = s - str->s;
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;
}
cBuf *buffer_from_string(cStr * string) {
cBuf * buf;
Int new;
buf = buffer_new(string_length(string));
new = parse_strcpy((char *) buf->s,
string_chars(string),
string_length(string));
if (string_length(string) - new)
buf = buffer_resize(buf, new);
return buf;
}
cBuf *buffer_from_strings(cList * string_list, cBuf * sep) {
cData * string_data;
cBuf *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 = (unsigned char *) 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;
}
cBuf * buffer_subrange(cBuf * buf, Int start, Int len) {
cBuf * cnew = buffer_new(len);
MEMCPY(cnew->s, buf->s + start, (len > buf->len ? buf->len : len));
cnew->len = len;
buffer_discard(buf);
return cnew;
}
cBuf *buffer_prep(cBuf *buf) {
cBuf *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;
}
INTERNAL
int buf_rindexs(uChar * buf, int len, uChar * sub, int slen, int origin){
register uChar * s;
if (origin < slen)
origin = slen;
len -= origin;
if (len < 0)
return 0;
s = &buf[len];
while (len-- >= 0) {
if (*s == *sub) {
if (!MEMCMP(s, sub, slen))
return (s - buf) + 1;
}
s--;
}
return 0;
}
INTERNAL int buf_rindexc(uChar * buf, int len, uChar sub, int origin) {
register uChar * s;
len -= origin;
if (len < 0)
return 0;
s = &buf[len];
while (len-- >= 0) {
if (*s == sub)
return (s - buf) + 1;
s--;
}
return 0;
}
/*
// returns 1..$ if item is found, 0 if it is not or -1 if an error is thrown
*/
int buffer_index(cBuf * buf, uChar * ss, int slen, int origin) {
int len;
uChar * s,
* p,
* lastp;
Bool reverse = NO;
s = buf->s;
len = buf->len;
if (origin < 0) {
reverse = YES;
origin = -origin;
}
if (origin > len || !origin)
return F_FAILURE;
if (origin == len)
return 0;
if (reverse) {
if (slen == 1)
return buf_rindexc(s, len, *ss, origin);
return buf_rindexs(s, len, ss, slen, origin);
} else {
origin--;
len -= origin;
if (len < slen)
return 0;
p = s + origin;
p = (uChar *) memchr(p, *ss, len);
if (slen == 1) {
return p ? ((p - s) + 1) : 0;
} else {
slen--;
lastp = p - 1;
while (p) {
if (MEMCMP(p + 1, ss + 1, slen) == 0)
return (p - s) + 1;
len -= (p - lastp);
lastp = p;
p = (uChar *) memchr(p+1, *ss, len);
}
}
}
return 0;
}