/* ====================================================================
 * Copyright 1999 Web Juice, LLC. All rights reserved.
 *
 * staglist.c
 *
 * Functions for manipulating the simple tag list structure in the
 * template library.
 *
 * ==================================================================== */

#include <string.h>
#include <stdlib.h>

#include <template.h>

/* ====================================================================
 * NAME:          staglist_init
 *
 * DESCRIPTION:   Initializes and returns a pointer to a new simple tag
 *                structure.
 *
 * RETURN VALUES: Returns NULL if the memory allocation fails; otherwise
 *                returns a pointer to a simple tag structure.
 *
 * BUGS:          Hopefully none.
 * ==================================================================== */
staglist_p
staglist_init(void)
{
    staglist_p simple_tag_list;

    simple_tag_list = (staglist_p)malloc(sizeof(staglist));
    if (simple_tag_list == NULL)
    {
        template_errno = TMPL_EMALLOC;
        return NULL;
    }

    simple_tag_list->name     = NULL;
    simple_tag_list->function = NULL;
    simple_tag_list->next     = NULL;

    return(simple_tag_list);
}



/* ====================================================================
 * NAME:          staglist_destroy
 *
 * DESCRIPTION:   Frees up all memory associated with a simple tag list
 *
 * RETURN VALUES: None.
 *
 * BUGS:          Because a free()d pointer still *looks* valid, it is
 *                difficult to protect against the problems that arise
 *                if the user calls this function too early.
 * ==================================================================== */
void
staglist_destroy(staglist_p simple_tag_list)
{
    staglist_p next;

    if (simple_tag_list == NULL)
    {
        return;
    }

    next = simple_tag_list->next;

    simple_tag_list->next = NULL;
    if (simple_tag_list->name != NULL)
    {
        free(simple_tag_list->name);
    }
    free(simple_tag_list);

    staglist_destroy(next);
}



/* ====================================================================
 * NAME:          staglist_alias
 *
 * DESCRIPTION:   Copy an existing tag to a new name.
 *
 * RETURN VALUES: Returns 0 upon failure; 1 on success.
 *
 * BUGS:          Hopefully none.
 * ==================================================================== */
int
staglist_alias(staglist_p *simple_tag_list, char *old_name, char *new_name)
{
    staglist_p current  = *simple_tag_list;

    /* Make sure that neither name is NULL */
    if ((old_name == NULL) || (new_name == NULL))
    {
        template_errno = TMPL_ENULLARG;
        return 0;
    }

    /* Walk through the list to find old_name */
    while (current != NULL)
    {
        if ((current->name != NULL) && (strcmp(current->name, old_name) == 0))
        {
            return staglist_register(simple_tag_list, new_name,
                                     current->function);
        }
        current = current->next;
    }

    template_errno = TMPL_ENOSTAG;
    return 0;
}



/* ====================================================================
 * NAME:          staglist_remove
 *
 * DESCRIPTION:   Remove a tag.
 *
 * RETURN VALUES: None.
 *
 * BUGS:          Hopefully none.
 * ==================================================================== */
void
staglist_remove(staglist_p *simple_tag_list, char *name)
{
    staglist_p current  = *simple_tag_list;
    staglist_p previous = NULL;

    /* Make sure the name isn't NULL */
    if (name == NULL)
    {
        template_errno = TMPL_ENULLARG;
        return;
    }

    /* Make sure the pointer passed in wasn't NULL */
    if (*simple_tag_list == NULL)
    {
        template_errno = TMPL_ENULLARG;
        return;
    }

    while (current != NULL)
    {
        if ((current->name != NULL) && (strcmp(current->name, name) == 0))
        {
            break;
        }
        previous = current;
        current = current->next;
    }

    /* The tag wasn't found */
    if (current == NULL)
    {
        return;
    }

    /* Move a pointer to skip the found tag */
    if (previous == NULL)
    {
        *simple_tag_list = current->next;
    } else
    {
        previous->next = current->next;
    }

    /* Destroy the tag */
    current->next = NULL;
    if (current->name != NULL) 
    {
        free(current->name);
    }
    free(current);
}



/* ====================================================================
 * NAME:          staglist_register
 *
 * DESCRIPTION:   Register a new tag and associated function to call.
 *
 * RETURN VALUES: Returns 0 upon failure; 1 on success.
 *
 * BUGS:          Hopefully none.
 * ==================================================================== */
int
staglist_register(staglist_p *simple_tag_list, char *name,
                  void (*function)(context_p, char **, int, char**))
{
    staglist_p new = NULL;
    int length;

    /* Make sure the function isn't NULL */
    if (function == NULL)
    {
        template_errno = TMPL_ENULLARG;
        return 0;
    }

    /* Make sure the name isn't NULL */
    if (name == NULL)
    {
        template_errno = TMPL_ENULLARG;
        return 0;
    }

    /* Make sure the pointer passed in wasn't NULL */
    if (*simple_tag_list == NULL)
    {
        template_errno = TMPL_ENULLARG;
        return 0;
    }

    new = staglist_init();
    if (new == NULL)
    {
        return 0;
    }

    new->function = function;

    length = strlen(name);
    new->name = (char *)malloc(length + 1);
    strncpy(new->name, name, length);
    new->name[length] = '\0';

    new->next = *simple_tag_list;

    *simple_tag_list = new;

    return 1;
}



/* ====================================================================
 * NAME:          staglist_exists
 *      
 * DESCRIPTION:   Find out whether a particular tag is a legitimate
 *                simple tag.
 *   
 * RETURN VALUES: Returns 0 if there's a problem or if the name is not
 *                a valid simple tag, or 1 if the name is a valid tag.
 *  
 * BUGS:          Hopefully none.
 * ==================================================================== */
int
staglist_exists(staglist_p simple_tag_list, char *name)
{
    staglist_p current = simple_tag_list;

    while (current != NULL)
    {
        if ((current->name != NULL) && (current->function != NULL)
            && (strcmp(current->name, name) == 0))
        {
            return 1;
        }
        current = current->next;
    }

    template_errno = TMPL_ENOSTAG;
    return 0;
}



/* ====================================================================
 * NAME:          staglist_exec
 *      
 * DESCRIPTION:   Executes the function associated with a given tag.
 *   
 * RETURN VALUES: Returns NULL if there's a problem or the string result
 *                of the function on success.
 *  
 * BUGS:          Hopefully none.
 * ==================================================================== */
int
staglist_exec(staglist_p simple_tag_list, char *name, context_p ctx,
              char **output, int argc, char **argv)
{
    staglist_p current = simple_tag_list;

    while (current != NULL)
    {
        if ((current->name != NULL) && (current->function != NULL)
            && (strcmp(current->name, name) == 0))
        {
            current->function(ctx, output, argc, argv);
            return 1;
        }
        current = current->next;
    }

    template_errno = TMPL_ENOSTAG;
    return 0;
}