/* ====================================================================
* Copyright 1999 Web Juice, LLC. All rights reserved.
*
* tagplist.c
*
* Functions for manipulating the tag pair list structure in the template
* library.
*
* ==================================================================== */
#include <stdlib.h>
#include <string.h>
#include <template.h>
/* ====================================================================
* NAME: tagplist_init
*
* DESCRIPTION: Initializes and returns a pointer to a new tag pair
* list structure.
*
* RETURN VALUES: Returns NULL if the memory allocation fails; otherwise
* returns a pointer to a tag pair list structure.
*
* BUGS: Hopefully none.
* ==================================================================== */
tagplist_p
tagplist_init()
{
tagplist_p tag_pair_list;
tag_pair_list = (tagplist_p)malloc(sizeof(tagplist));
if (tag_pair_list == NULL)
{
template_errno = TMPL_EMALLOC;
return NULL;
}
tag_pair_list->open_name = NULL;
tag_pair_list->close_name = NULL;
tag_pair_list->function = NULL;
tag_pair_list->next = NULL;
tag_pair_list->named_context = 0;
return(tag_pair_list);
}
/* ====================================================================
* NAME: tagplist_destroy
*
* DESCRIPTION: Frees up all memory associated with a tag pair 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
tagplist_destroy(tagplist_p tag_pair_list)
{
tagplist_p next;
if (tag_pair_list == NULL)
{
return;
}
next = tag_pair_list->next;
tag_pair_list->next = NULL;
if (tag_pair_list->open_name != NULL)
{
free(tag_pair_list->open_name);
}
if (tag_pair_list->close_name != NULL)
{
free(tag_pair_list->close_name);
}
free(tag_pair_list);
tagplist_destroy(next);
}
/* ====================================================================
* NAME: tagplist_alias
*
* DESCRIPTION: Copy an existing tag pair to a new tag pair name.
*
* RETURN VALUES: Returns 0 upon failure; 1 on success.
*
* BUGS: Hopefully none.
* ==================================================================== */
int
tagplist_alias(tagplist_p *tag_pair_list, char *old_open_name,
char *old_close_name, char *new_open_name, char *new_close_name)
{
tagplist_p current = *tag_pair_list;
/* Make sure the names are not NULL */
if ((old_open_name == NULL) || (old_close_name == NULL)
|| (new_open_name == NULL) || (new_close_name == NULL))
{
template_errno = TMPL_ENULLARG;
return 0;
}
/* Walk through the contexts to find the old tag */
while (current != NULL)
{
if ((current->open_name != NULL) && (current->close_name != NULL)
&& (strcmp(current->open_name, old_open_name) == 0)
&& (strcmp(current->close_name, old_close_name) == 0))
{
return tagplist_register(tag_pair_list, current->named_context,
new_open_name, new_close_name,
current->function);
}
current = current->next;
}
template_errno = TMPL_ENOTAGP;
return 0;
}
/* ====================================================================
* NAME: tagplist_remove
*
* DESCRIPTION: Remove a tag pair.
*
* RETURN VALUES: None.
*
* BUGS: Hopefully none.
* ==================================================================== */
void
tagplist_remove(tagplist_p *tag_pair_list, char *open_name)
{
tagplist_p current = *tag_pair_list;
tagplist_p previous = NULL;
/* Make sure the name isn't NULL */
if (open_name == NULL)
{
template_errno = TMPL_ENULLARG;
return;
}
/* Make sure the pointer passed in wasn't NULL */
if (*tag_pair_list == NULL)
{
template_errno = TMPL_ENULLARG;
return;
}
while (current != NULL)
{
if ((current->open_name != NULL)
&& (strcmp(current->open_name, open_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)
{
*tag_pair_list = current->next;
} else
{
previous->next = current->next;
}
/* Destroy the tag */
current->next = NULL;
if (current->open_name != NULL)
{
free(current->open_name);
}
if (current->close_name != NULL)
{
free(current->close_name);
}
free(current);
}
/* ====================================================================
* NAME: tagplist_register
*
* DESCRIPTION: Register a new tag pair and associated function to call.
*
* RETURN VALUES: Returns 0 upon failure; 1 on success.
*
* BUGS: Hopefully none.
* ==================================================================== */
int
tagplist_register(tagplist_p *tag_pair_list, char named_context,
char *open_name, char *close_name,
void (*function) (context_p, int, char**))
{
tagplist_p new = NULL;
int length;
/* Make sure the function isn't NULL */
if (function == NULL)
{
template_errno = TMPL_ENULLARG;
return 0;
}
if ((open_name == NULL) || (close_name == NULL))
{
template_errno = TMPL_ENULLARG;
return 0;
}
if (*tag_pair_list == NULL)
{
template_errno = TMPL_ENULLARG;
return 0;
}
new = tagplist_init();
new->function = function;
new->named_context = named_context;
length = strlen(open_name);
new->open_name = (char *)malloc(length + 1);
strncpy(new->open_name, open_name, length);
new->open_name[length] = '\0';
length = strlen(close_name);
new->close_name = (char *)malloc(length + 1);
strncpy(new->close_name, close_name, length);
new->close_name[length] = '\0';
new->next = *tag_pair_list;
*tag_pair_list = new;
return 1;
}
/* ====================================================================
* NAME: tagplist_is_opentag
*
* DESCRIPTION: Find out whether a particular tag is a legitimate
* opening tag.
*
* RETURN VALUES: Returns 0 if there's a problem or if the name is not
* a valid opening tag, or 1 if the name is a valid tag.
*
* BUGS: Hopefully none.
* ==================================================================== */
int
tagplist_is_opentag(tagplist_p tag_pair_list, char *open_name)
{
tagplist_p current = tag_pair_list;
while (current != NULL)
{
if ((current->open_name != NULL) && (current->function != NULL)
&& (strcmp(current->open_name, open_name) == 0))
{
return 1;
}
current = current->next;
}
template_errno = TMPL_ENOTAGP;
return 0;
}
/* ====================================================================
* NAME: tagplist_is_closetag
*
* DESCRIPTION: Find out whether a particular tag is a valid closing
* tag for another (i.e. whether you have a valid tag pair).
*
* RETURN VALUES: Returns 0 if there's a problem or if the names do not
* form a valid tag pair; otherwise returns 1.
*
* BUGS: Hopefully none.
* ==================================================================== */
int
tagplist_is_closetag(tagplist_p tag_pair_list, char *open_name,
char *close_name)
{
tagplist_p current = tag_pair_list;
while (current != NULL)
{
if ((current->open_name != NULL) && (current->close_name != NULL)
&& (strcmp(current->open_name, open_name) == 0)
&& (strcmp(current->close_name, close_name) == 0))
{
return 1;
}
current = current->next;
}
template_errno = TMPL_ENOTAGP;
return 0;
}
/* ====================================================================
* NAME: tagplist_exec
*
* DESCRIPTION: Executes the function associated with a given tag pair.
*
* RETURN VALUES: Returns NULL if there's a problem or the context
* modified by the function otherwise.
*
* BUGS: Hopefully none.
* ==================================================================== */
context_p
tagplist_exec(tagplist_p tag_pair_list, char *open_name, context_p ctx,
int argc, char **argv)
{
tagplist_p current = tag_pair_list;
while (current != NULL)
{
if ((current->open_name != NULL) && (current->function != NULL)
&& (strcmp(current->open_name, open_name) == 0))
{
if ((current->named_context) && (argc >= 0))
{
context_p named_context;
named_context = context_get_named_child(ctx, argv[1]);
if (named_context == NULL)
{
named_context = context_get_anonymous_child(ctx);
if (named_context == NULL)
{
return NULL;
}
ctx_unset_output(named_context);
return(named_context);
}
current->function(named_context, argc, argv);
return(named_context);
} else {
context_p anonymous_context;
anonymous_context = context_get_anonymous_child(ctx);
if (anonymous_context == NULL)
{
return NULL;
}
current->function(anonymous_context, argc, argv);
return(anonymous_context);
}
}
current = current->next;
}
template_errno = TMPL_ENOTAGP;
return NULL;
}