#ifndef _plan9_
#include <string.h>
#include <stdlib.h>
#else
#include <u.h>
#include <libc.h>
#endif

#include <xio.h>
#include <misc-f.h>
struct fr
{
    char *string;
    int pos;
    int allocedsize;
    int stringsize;
};

char *
mystrdup (const char *c)
{
    int l = strlen (c);
    char *d = malloc (l + 1);
    if (!d)
        return NULL;
    memcpy (d, c, l + 1);
    return d;
}

static int
sputc (int c, xio_file s)
{
    struct fr *f = (struct fr *) s->data;
    if (f->pos >= f->allocedsize - 1) {
        char *c = (char *) realloc (f->string, f->allocedsize * 2);
        if (!c)
            return XIO_EOF;
        f->string = c;
        f->allocedsize *= 2;
    }
    f->string[f->pos++] = c;
    if (f->pos >= f->stringsize)
        f->string[f->pos] = 0, f->stringsize = f->pos;
    return 0;
}

static int
sputs (const char *c, xio_file s)
{
    int l = strlen (c);
    struct fr *f = (struct fr *) s->data;
    while (f->pos + l >= f->allocedsize - 1) {
        char *c = (char *) realloc (f->string, f->allocedsize * 2);
        if (!c)
            return XIO_EOF;
        f->string = c;
        f->allocedsize *= 2;
    }
    memcpy (f->string + f->pos, c, l);
    f->pos += l;
    if (f->pos >= f->stringsize)
        f->string[f->pos] = 0, f->stringsize = f->pos;
    return 0;
}

static int
sungetc (int c, xio_file s)
{
    struct fr *f = (struct fr *) s->data;
    f->pos--;
    /*f->string[f->pos]=c; */
    return 0;
}

static int
sgetc (xio_file s)
{
    struct fr *f = (struct fr *) s->data;
    if (f->pos == f->stringsize)
        return XIO_EOF;
    return f->string[f->pos++];
}

static int
sfeof (xio_file s)
{
    struct fr *f = (struct fr *) s->data;
    return (f->pos == f->stringsize);
}

static int
srclose (xio_file s)
{
    struct fr *f = (struct fr *) s->data;
    free (f->string);
    free (f);
    free (s);
    return 0;
}

static int
swclose (xio_file s)
{
    struct fr *f = (struct fr *) s->data;
    f->string = (char *) realloc (f->string, f->stringsize + 1);
    /*free(s);
       free(f); */
    return 0;
}

char *
xio_getstring (xio_file s)
{
    struct fr *f = (struct fr *) s->data;
    char *c = f->string;
    free (f);
    free (s);
    return c;
}

xio_file
xio_strropen (const char *string)
{
    xio_file s = (xio_file) calloc (1, sizeof (*s));
    struct fr *f = (struct fr *) calloc (1, sizeof (*f));
    s->data = f;
    f->pos = 0;
    f->string = (char *) string;
    f->stringsize = strlen (string);
    s->fclose = srclose;
    s->xeof = sfeof;
    s->fgetc = sgetc;
    s->fungetc = sungetc;
    return s;
}

#define PAGE 4096
xio_file
xio_strwopen (void)
{
    xio_file s = (xio_file) calloc (1, sizeof (*s));
    struct fr *f = (struct fr *) calloc (1, sizeof (*f));
    s->data = f;
    f->pos = 0;
    f->string = (char *) malloc (PAGE);
    f->allocedsize = PAGE;
    f->stringsize = 0;
    s->fputc = sputc;
    s->fputs = sputs;
    s->fclose = swclose;
    s->flush = NULL;
    return s;
}
