/*
 * KAarray: string-addressable KA array, used for easy manipulation
 * of configuration files.
 *
 * Copyright (c) 1996 David L Parsons
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
 * to endorse or promote products derived from this software without
 * specific prior written permission.  THIS SOFTWARE IS PROVIDED
 * ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
 * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.
 */
static const char rcsid[] = "$Id: s.KAarray.cc 1.5 01/03/11 17:58:55-08:00 orc@downbelow.pell.portland.or.us $";

extern "C" {
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <ctype.h>
}
#include <string.h>

#include "KAarray.H"

/*
 * KAarray::~KAarray() - deletes the object in question
 */
KAarray::~KAarray()
{
    Erase();
    free((char*)_list);
} /* KAarray::~KAarray */


/*
 * operator[] (char *index)
 */
KA&
KAarray::operator[] (char *key)
{
    return valueof(key);
}

/*
 * valueof()
 */
KA&
KAarray::valueof(char *key)
{
    register int i;
    static KA null(0);

    if ((i = locate(key)) >= 0)
	return *(_list[i]._content);
    else if (autoappend())
	return create(key);
    return null;
} /* KAarray:valueof */


/*
 * locate() finds the slot for a given key
 */
int
KAarray::locate(char *key)
{
    register unsigned i;

    if (key == 0)
	return -1;
    for (i=0; i<count(); i++)
	if (strcasecmp(_list[i]._key, key) == 0)
	    return i;
    return -1;
} /* KAarray::locate */


/*
 * assign() sets an arg to a value (or adds a new arg with a given value)
 */
KA&
KAarray::create(char* key, char* value)
{
    int index;

    assert(key != (char*)0);

    if ((index=locate(key)) < 0) {
	for (index=0; index<(int)count(); index++)
	    if (!_list[index]._used)
		break;
	if (index == (int)count()) {
	    _list = (struct KAA*)realloc((char*)_list,
					(1+index) * sizeof(struct KA));
	    _nrlist++;
	}
	_list[index]._key = strdup(key);
	_list[index]._content = new KA(value);
	_list[index]._used = 1;
    }
    else {
	*(_list[index]._content) = value;
    }
    return *(_list[index]._content);
} /* KAarray::assign */


/*
 * foreach() - iterate across the thing array
 */
int
KAarray::foreach(int (*op)(char*,KA*))
{
    unsigned int i;
    int st;

    for (i=0; i<count(); i++)
	if (_list[i]._used && (st=(*op)(_list[i]._key, _list[i]._content)) != 0)
	    return st;
    return 0;
} /* KAarray::foreach */


/*
 * drop() deletes something by name
 */
int
KAarray::drop(char* key)
{
    int index = locate(key);

    if (index >= 0 && index < (int)count()) {
	free(_list[index]._key);
	delete _list[index]._content;
	_list[index]._used = 0;
    }
    _dirty = 1;
    return (int)count();
} /* KAarray::drop */


/*
 * changed() tells us if anything has changed
 */
int
KAarray::changed()
{
    unsigned int x;

    if (_dirty)
	return 1;
    for (x=0; x<count(); x++)
	if (_list[x]._used && _list[x]._content->changed())
	    return 1;
    return 0;
} /* KAarray::changed */


/*
 * changed(int) sets the changed flags
 */
int
KAarray::changed(int val)
{
    unsigned int x;

    _dirty = val;
    for (x=0; x<count(); x++)
	if (_list[x]._used)
	    _list[x]._content->changed(val);
    return val;
} /* KAarray::changed */


/*
 * print() does a debug print of the object.
 */
int
KAarray::print(FILE *out)
{
    unsigned int i;

    for (i=0; i<count(); i++) {
	fprintf(out, "%s=", _list[i]._key);
	_list[i]._content->print(out);
    }
    return ferror(out);
} /* KAarray::print */


/*
 * Erase() wipes the contents of the array out
 */
void
KAarray::Erase()
{
    unsigned int i;

    for (i=0; i< count(); i++) {
	if (_list[i]._used) {
	    delete _list[i]._content;
	    free(_list[i]._key);
	    _list[i]._used = 0;
	}
    }
    _dirty = 1;
    _nrlist = 0;
} /* KAarray::Erase */
