/*
 * (C) Copyright 1991 UCAR/Unidata
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose without fee is hereby granted, provided that
 * the above copyright notice appear in all copies, that both that copyright
 * notice and this permission notice appear in supporting documentation, and
 * that the name of UCAR/Unidata not be used in advertising or publicity
 * pertaining to distribution of the software without specific, written prior
 * permission.  UCAR makes no representations about the suitability of this
 * software for any purpose. It is provided "as is" without express or
 * implied warranty.  It is provided with no support and without obligation
 * on the part of UCAR or Unidata, to assist in its use, correction,
 * modification, or enhancement.
 * 
 * $Id: strvec.c,v 1.1 2000/08/07 23:15:04 emmerson Exp $
 */

/*
 * This file implements an arbitrarily extensible array of strings.
 */

/* LINTLIBRARY */

#include "udposix.h"	/* for a near-POSIX environment */
#include <stdio.h>	/* needed by <assert.h> */
#include <assert.h>	/* for assert() */
#include <stdlib.h>
#include <string.h>	/* for string functions */
#include "udalloc.h"	/* for Unidata memory-allocation routines */
#include "strvec.h"	/* for myself */

/*
 * Definition of otherwise opaque data-structure:
 */
struct Strvec {
    size_t          max;
    size_t          num;
    char          **string;
};

#undef	SV_SIZE
#define	SV_SIZE(num)	(sizeof(Strvec)+((num)-1)*sizeof(char*))


/*
 * Free the resources of a string-vector.
 */
    Strvec*
svfree(sv)
    Strvec         *sv;
{
    if (sv != NULL) {
	int             i;

	for (i = 0; i < sv->num; ++i)
	    /*
	     * lint(1) might warn about a possible pointer alignment problem
	     * in the following statement.  This may safely be ignored.
	     */
	    free((voidp)sv->string[i]);

	if (sv->string != NULL)
	    free((voidp)sv->string);

	free((voidp)sv);
    }

    return NULL;
}


/*
 * Return a new string-vector.
 */
    Strvec*
svnew(initial_size)
    size_t          initial_size;
{
    Strvec         *new;

    if (initial_size < 2)
	initial_size = 2;

    if ((new = UD_ALLOC(1, Strvec)) != NULL) {
	new->max = initial_size;
	new->num = 0;

	if ((new->string = UD_ALLOC(new->max, char*)) == NULL) {
	    (void) svfree(new);
	    new = NULL;
	}
    }
    return new;
}


/*
 * Add a string to a string-vector.
 */
    Strvec*
svadd(sv, string)
    Strvec         *sv;
    const char     *string;
{
    assert(sv != NULL);

    if (sv->num == sv->max) {
	size_t          newmax = (8 * sv->max) / 5;
	char          **newstring;

	assert(newmax > sv->max);

	if ((newstring = UD_REALLOC(sv, newmax, char*)) == NULL)
	    return NULL;

	sv->string = newstring;
	sv->max = newmax;
    }
    if ((sv->string[sv->num++] = udstrdup(string)) == NULL) {
	sv->num--;
	return NULL;
    }
    return sv;
}


/*
 * Return the number of strings in a string-vector.
 */
    int
svnumber(sv)
    const Strvec         *sv;
{
    assert(sv != NULL);

    return sv->num;
}


/*
 * Return the vector of strings in a string-vector.
 */
    char**
svvector(sv)
    const Strvec         *sv;
{
    assert(sv != NULL);

    return sv->string;
}


/*
 * Return a pointer to a particular string in a string-vector.
 */
    char*
svstring(sv, i)
    const Strvec   *sv;
    int             i;
{
    assert(sv != NULL);
    assert(i >= 0 && i < sv->num);

    return sv->string[i];
}
