/*
 * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/dyn.c,v 1.18 2004/04/30 13:41:56 aleigh Exp $ 
 */

/*
 * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved
 * 
 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright
 * notice above does not evidence any actual or intended publication of such
 * source code.
 * 
 * Disclosure, copying, distribution, or transmission of this code without
 * express permission is prohibited.
 */


#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <pthread.h>

#define DYN_CHUNK_SZ 1024

#include "mecha.h"
#include "dyn.h"

void dynFreset(dynTstring * ds)
{
    assert(ds != NULL);
    ds->strlen = 0;
}

void dynFfree(dynTstring * ds)
{
    assert(ds);

    if (ds->str != NULL)
        free(ds->str);
    free(ds);
}

dynTstring *dynFinit(void)
{
    dynTstring *p;

    p = (dynTstring *) malloc(sizeof(dynTstring));

    p->str = NULL;
    p->len = 0;
    p->strlen = 0;

    return p;
}

static int dynFalloc(dynTstring * ds, int size)
{
    char *p;

    assert(ds != NULL);

    if (ds->str != NULL) {
        p = (char *) realloc(ds->str, ds->len + size);
        if (p == NULL)
            return -1;

        ds->str = p;
        ds->len += size;
    } else {
        ds->str = (char *) malloc(size);
        if (ds->str == NULL)
            return -1;

        ds->len = size;

        /* make the first byte empty */
        ds->str[0] = 0;
    }
    return 0;
}

size_t dynFappend(dynTstring * ds, const char *str, size_t len)
{
    assert(ds != NULL);
    assert(str != NULL);

    /* we want to be able to put a NULL at the end */
    if (ds->strlen + len + 1 > ds->len) {
        size_t required = len - (ds->len - ds->strlen);
        required += DYN_CHUNK_SZ;
        dynFalloc(ds, ds->len + required);
    }
    memcpy(ds->str + ds->strlen, str, len);
    ds->strlen += len;

    /* make the end of the string empty */
    ds->str[ds->strlen] = 0;

    return len;
}

size_t dynFappend_string(dynTstring * ds, const dynTstring * src)
{
    assert(ds != NULL);
    assert(src != NULL);

    return (dynFappend(ds, src->str, src->strlen));
}

size_t dynFsappend(dynTstring * ds, const char *str)
{
    assert(ds != NULL);
    assert(str != NULL);
    return dynFappend(ds, str, strlen(str));
}

size_t dynFappend_print(dynTstring * ds, const char *fmt, ...)
{
    va_list ap;
    char *buf;
    size_t size = 1024;
    char stack_buf[1024];
    int nchars;

    assert(ds != NULL);
    assert(fmt != NULL);

    buf = stack_buf;
    size = sizeof(stack_buf);

    assert(buf != NULL);

    va_start(ap, fmt);

    while (1) {
        nchars = vsnprintf(buf, size, fmt, ap);

        if (nchars > -1 && nchars < (int) size)
            break;
        if (nchars > -1)
            size = nchars + 1;
        else
            size *= 2;

        if (buf == stack_buf) {
            buf = (char *) malloc(size);
        } else {
            buf = (char *) realloc(buf, size);
        }
    }

    va_end(ap);

    dynFappend(ds, buf, nchars);

    if (buf != stack_buf) {
        free(buf);
    }
    return (0);
}

const char *dynFgetstr(const dynTstring * ds)
{
    assert(ds != NULL);
    return ds->str;
}

size_t dynFgetlen(const dynTstring * ds)
{
    assert(ds != NULL);
    return ds->strlen;
}
