#include <sys/types.h>
#include <stdio.h>
#include <ctype.h>
#include "s_string.h"
#include <stdlib.h>
#define STRLEN 128UL
#define STRALLOC 128UL
#define MAXINCR 250000UL
typedef struct {
string s[STRALLOC];
size_t o;
} stralloc;
static stralloc *freep = NULL;
static string *freed = NULL;
static string *s_alloc(void);
static void s_simplegrow(string *, size_t);
void
s_free(string *sp)
{
if (sp != NULL) {
sp->ptr = (char *)freed;
freed = sp;
}
}
static string *
s_alloc(void)
{
if (freep == NULL || freep->o >= STRALLOC) {
freep = (stralloc *)malloc(sizeof (stralloc));
if (freep == NULL) {
perror("allocating string");
exit(1);
}
freep->o = (size_t)0;
}
return (&(freep->s[freep->o++]));
}
string *
s_new(void)
{
string *sp;
if (freed != NULL) {
sp = freed;
freed = (string *)(freed->ptr);
sp->ptr = sp->base;
return (sp);
}
sp = s_alloc();
sp->base = sp->ptr = malloc(STRLEN);
if (sp->base == NULL) {
perror("allocating string");
exit(1);
}
sp->end = sp->base + STRLEN;
s_terminate(sp);
return (sp);
}
static void
s_simplegrow(string *sp, size_t incr)
{
char *cp;
size_t size;
if (((sp->end - sp->base) < incr) && (MAXINCR < incr))
size = (sp->end - sp->base) + incr;
else if ((sp->end - sp->base) > MAXINCR)
size = (sp->end - sp->base) + MAXINCR;
else
size = (size_t)2 * (sp->end - sp->base);
cp = realloc(sp->base, size);
if (cp == NULL) {
perror("string:");
exit(1);
}
sp->ptr = (sp->ptr - sp->base) + cp;
sp->end = cp + size;
sp->base = cp;
}
int
s_grow(string *sp, int c)
{
s_simplegrow(sp, (size_t)2);
s_putc(sp, c);
return (c);
}
string *
s_array(char *cp, size_t len)
{
string *sp = s_alloc();
sp->base = sp->ptr = cp;
sp->end = sp->base + len;
return (sp);
}
string*
s_copy(char *cp)
{
string *sp;
size_t len;
sp = s_alloc();
len = strlen(cp)+1;
sp->base = malloc(len);
if (sp->base == NULL) {
perror("string:");
exit(1);
}
sp->end = sp->base + len;
(void) strcpy(sp->base, cp);
sp->ptr = sp->end - (size_t)1;
return (sp);
}
void
s_tolower(string *sp)
{
char *cp;
for (cp = sp->ptr; *cp; cp++)
*cp = tolower(*cp);
}
void
s_skipwhite(string *sp)
{
while (isspace(*sp->ptr))
s_skipc(sp);
}
string *
s_append(string *to, char *from)
{
if (to == NULL)
to = s_new();
if (from == NULL)
return (to);
for (; *from; from++)
s_putc(to, (int)(unsigned int)*from);
s_terminate(to);
return (to);
}
string *
s_seq_read(FILE *fp, string *to, int lineortoken)
{
int c;
int done = 0;
if (feof(fp))
return (NULL);
do {
c = getc(fp);
switch (c) {
case EOF:
if (to != NULL)
s_terminate(to);
return (NULL);
case '#':
while ((c = getc(fp)) != '\n' && c != EOF)
continue;
break;
case ' ':
case '\t':
case '\n':
case '\r':
case '\f':
break;
default:
done = 1;
break;
}
} while (!done);
if (to == NULL)
to = s_new();
for (;;) {
switch (c) {
case '\\':
c = getc(fp);
if (c != '\n') {
s_putc(to, (int)(unsigned int)'\\');
s_putc(to, c);
}
break;
case EOF:
case '\r':
case '\f':
case '\n':
s_terminate(to);
return (to);
case ' ':
case '\t':
if (lineortoken == TOKEN) {
s_terminate(to);
return (to);
}
default:
s_putc(to, c);
break;
}
c = getc(fp);
}
}
string *
s_tok(string *from, char *split)
{
char *splitend = strpbrk(from->ptr, split);
if (splitend) {
string *to = s_new();
for (; from->ptr < splitend; ) {
s_putc(to, (int)(unsigned int)*from->ptr);
from->ptr++;
}
s_terminate(to);
s_restart(to);
from->ptr += strspn(from->ptr, split);
return (to);
}
else if (from->ptr[0]) {
string *to = s_clone(from);
while (*from->ptr)
from->ptr++;
return (to);
}
else
return (NULL);
}
char *
s_read_line(FILE *fp, string *to)
{
int c;
size_t len = 0;
s_terminate(to);
if (feof(fp) || (c = getc(fp)) == EOF)
return (NULL);
for (; ; ) {
len++;
switch (c) {
case EOF:
s_terminate(to);
return (to->ptr - len);
case '\n':
s_putc(to, (int)(unsigned int)'\n');
s_terminate(to);
return (to->ptr - len);
default:
s_putc(to, c);
break;
}
c = getc(fp);
}
}
size_t
s_read_to_eof(FILE *fp, string *to)
{
size_t got;
size_t have;
s_terminate(to);
for (; ; ) {
if (feof(fp))
break;
have = to->end - to->ptr;
if (have < 4096UL)
s_simplegrow(to, (size_t)4096);
have = to->end - to->ptr;
got = fread(to->ptr, (size_t)1, have, fp);
if (got == (size_t)0)
break;
to->ptr += got;
}
s_terminate(to);
return (to->ptr - to->base);
}
string *
s_parse(string *from, string *to)
{
while (isspace(*from->ptr))
from->ptr++;
if (*from->ptr == '\0')
return (NULL);
if (to == NULL)
to = s_new();
if (*from->ptr == '\'') {
from->ptr++;
for (; *from->ptr != '\'' && *from->ptr != '\0'; from->ptr++)
s_putc(to, (int)(unsigned int)*from->ptr);
if (*from->ptr == '\'')
from->ptr++;
} else if (*from->ptr == '"') {
from->ptr++;
for (; *from->ptr != '"' && *from->ptr != '\0'; from->ptr++)
s_putc(to, (int)(unsigned int)*from->ptr);
if (*from->ptr == '"')
from->ptr++;
} else {
for (; !isspace(*from->ptr) && *from->ptr != '\0'; from->ptr++)
s_putc(to, (int)(unsigned int)*from->ptr);
}
s_terminate(to);
return (to);
}