The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

/* ====================================================================
* Copyright 1999 Web Juice, LLC. All rights reserved.
*
* context.c
*
* Functions for manipulating the context structure in the template
* library.
*
* ==================================================================== */
#include <stdlib.h>
#include <context.h>
#include <varlist.h>
#include <nclist.h>
/* ====================================================================
* NAME: context_init
*
* DESCRIPTION: Initializes and returns a pointer to a new context
* structure.
*
* RETURN VALUES: Returns NULL if the memory allocation fails; otherwise
* returns a pointer to a varlist structure.
*
* BUGS: Hopefully none.
* ==================================================================== */
context_p
context_init(void)
{
context_p ctx;
ctx = (context_p)calloc(1, sizeof(context));
if (ctx == NULL)
{
return NULL;
}
ctx->variables = varlist_init();
if (ctx->variables == NULL)
{
free(ctx);
return NULL;
}
ctx->named_child_contexts = nclist_init();
if (ctx->named_child_contexts == NULL)
{
varlist_destroy(ctx->variables);
free(ctx);
return NULL;
}
ctx->parent_context = NULL;
ctx->next_context = NULL;
ctx->output_contents = 1;
ctx->anonymous = 0;
return(ctx);
}
/* ====================================================================
* NAME: context_destroy
*
* DESCRIPTION: Frees up all memory associated with a context.
*
* 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
context_destroy(context_p ctx)
{
context_p next;
if (ctx == NULL)
{
return;
}
next = ctx->next_context;
if (ctx->named_child_contexts != NULL)
{
nclist_destroy(ctx->named_child_contexts);
}
if (ctx->variables != NULL)
{
varlist_destroy(ctx->variables);
}
ctx->named_child_contexts = NULL;
ctx->variables = NULL;
ctx->next_context = NULL;
ctx->parent_context = NULL;
free(ctx);
context_destroy(next);
}
/* ====================================================================
* NAME: context_get_value
*
* DESCRIPTION: Returns the value of the variable stored under the given
* name in the current context or any parents' variable list.
*
* RETURN VALUES: This function will return NULL if there are any problems
* or if there is no value. It returns a string containing
* the value on success.
*
* BUGS: Hopefully none.
* ==================================================================== */
char *
context_get_value(context_p ctx, char *name)
{
char *result;
if (ctx == NULL)
{
return NULL;
}
result = varlist_get_value(ctx->variables, name);
if (result != NULL)
{
return(result);
}
if (ctx->parent_context == NULL)
{
return NULL;
}
return(context_get_value(ctx->parent_context, name));
}
/* ====================================================================
* NAME: context_set_value
*
* DESCRIPTION: Set a variable in the context's variable list.
*
* RETURN VALUES: Returns 0 if there's any trouble. Returns 1 if the
* variable was successfully set.
*
* BUGS: Hopefully none.
* ==================================================================== */
int
context_set_value(context_p ctx, char *name, char *value)
{
if (ctx == NULL)
{
return 0;
}
return(varlist_set_value(ctx->variables, name, value));
}
/* ====================================================================
* NAME: context_get_anonymous_child
*
* DESCRIPTION: Creates and returns an unnamed context with the parent
* set to the current context (i.e. a new context within
* the scope of the current context).
*
* RETURN VALUES: Returns NULL if there's a problem; returns a pointer to
* the new context otherwise.
*
* BUGS: Hopefully none.
* ==================================================================== */
context_p
context_get_anonymous_child(context_p ctx)
{
context_p anonymous_ctx;
if (ctx == NULL)
{
return NULL;
}
anonymous_ctx = context_init();
if (anonymous_ctx == NULL)
{
return NULL;
}
anonymous_ctx->parent_context = ctx;
anonymous_ctx->anonymous = 1;
return(anonymous_ctx);
}
/* ====================================================================
* NAME: context_get_named_child
*
* DESCRIPTION: This function returns a named context within the scope
* of the current context, if it exists.
*
* RETURN VALUES: Returns NULL if there is any problem, or if the context
* doesn't exist; else returns a pointer to the context.
*
* BUGS: Hopefully none.
* ==================================================================== */
context_p
context_get_named_child(context_p ctx, char *name)
{
context_p result;
if (ctx == NULL)
{
return NULL;
}
result = nclist_get_context(ctx->named_child_contexts, name);
if (result != NULL)
{
return(result);
}
if (ctx->parent_context == NULL)
{
return NULL;
}
return(context_get_named_child(ctx->parent_context, name));
}
/* ====================================================================
* NAME: context_set_named_child
*
* DESCRIPTION: This function creates a new named context within the
* scope of the current context.
*
* RETURN VALUES: Returns 0 if there is any trouble; returns 1 on success.
*
* BUGS: Hopefully none.
* ==================================================================== */
int
context_set_named_child(context_p ctx, char *name)
{
context_p named_ctx;
if (ctx == NULL)
{
return 0;
}
if (! nclist_new_context(ctx->named_child_contexts, name))
{
return 0;
}
named_ctx = context_get_named_child(ctx, name);
if (named_ctx == NULL)
{
return 0;
}
named_ctx->parent_context = ctx;
return 1;
}
/* ====================================================================
* NAME: context_add_peer
*
* DESCRIPTION: This function adds a peer context (a.k.a. loop iteration)
* to the context passed in, and initializes it.
*
* RETURN VALUES: Returns NULL if there is any trouble; returns a pointer to
* the new peer context otherwise.
*
* BUGS: Hopefully none.
* ==================================================================== */
context_p
context_add_peer(context_p ctx)
{
context_p peer_ctx;
context_p current = ctx;
if (ctx == NULL)
{
return NULL;
}
peer_ctx = context_init();
if (peer_ctx == NULL)
{
return NULL;
}
peer_ctx->parent_context = ctx->parent_context;
while (current->next_context != NULL)
{
current = current->next_context;
}
current->next_context = peer_ctx;
return(peer_ctx);
}
/* ====================================================================
* NAME: context_output_contents
*
* DESCRIPTION: This function adds a peer context (a.k.a. loop iteration)
*
* RETURN VALUES: None.
*
* BUGS: Hopefully none.
* ==================================================================== */
void
context_output_contents(context_p ctx, char output_contents)
{
if (ctx == NULL)
{
return;
}
ctx->output_contents = output_contents;
return;
}