/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
//
// set-proc.c
//
// specialized markup processors
//
// Copyright (c) 1995-96 Jim Nelson.  Permission to distribute
// granted by the author.  No warranties are made on the fitness of this
// source code.
//
*/

#include "set-proc.h"

#include "defs.h"
#include "snprintf.h"

uint SetProcessor(TASK *task, HTML_MARKUP *htmlMarkup, char **newPlaintext)
{
    char *name;
    char *value;
    uint flag;
    HTML_ATTRIBUTE *attrib;
    VARSTORE *varstore;

    UNREF_PARAM(newPlaintext);

    varstore = task->varstore;
    if (UnlinkBoolAttributeInMarkup(htmlMarkup, "GLOBAL")) {
        while (!varstore->isGlobal)
            varstore = varstore->parent;
    }

    /* have to declare at least one macro, but more are acceptable */
    if(htmlMarkup->attrib == NULL)
    {
        HtpMsg(MSG_ERROR, task->infile, "incomplete macro declaration");
        return MARKUP_ERROR;
    }

    /* walk the list and add each macro to the variable store */
    while ((attrib = htmlMarkup->attrib) != NULL)
    {
        name = attrib->name;
        value = attrib->value;

        flag = VAR_FLAG_DEALLOC_NAME | VAR_FLAG_DEALLOC_VALUE;
        if (!value) {
            value = "";
            flag &= ~VAR_FLAG_DEALLOC_VALUE;
        }

        /* put the new variable into the store */
        if(StoreVariable(varstore, name, value, 
                         VAR_TYPE_SET_MACRO, 
                         flag, NULL, NULL) == FALSE)
        {
            HtpMsg(MSG_ERROR, task->infile,
                   "unable to store macro \"%s\" (out of memory?)",
                   name);
            return MARKUP_ERROR;
        }

        HtpMsg(MSG_INFO, task->infile, "macro \"%s\" assigned value \"%s\"",
               name, value);

        if (attrib->whitespace)
            FreeMemory(attrib->whitespace);
        /* unlink attrib */
        htmlMarkup->attrib = attrib->next;
        FreeMemory(attrib);
    }

    return DISCARD_MARKUP;
}   

uint UnsetProcessor(TASK *task, HTML_MARKUP *htmlMarkup, char **newPlaintext)
{
    HTML_ATTRIBUTE *attrib;
    uint type;

    UNREF_PARAM(newPlaintext);

    attrib = htmlMarkup->attrib;

    /* need at least one attribute to undef */
    if(attrib == NULL)
    {
        HtpMsg(MSG_ERROR, task->infile, "UNDEF requires at least one name");
        return MARKUP_ERROR;
    }

    /* walk the list of attributes, deleting them as found */
    while (attrib != NULL)
    {
        /* is it in the store? */
        type = GetVariableType(task->varstore, attrib->name);
        if((type == VAR_TYPE_SET_MACRO) || (type == VAR_TYPE_BLOCK_MACRO))
        {
            RemoveVariable(task->varstore, attrib->name);
        }
        else
        {
            HtpMsg(MSG_ERROR, task->infile, "No macro \"%s\" to unset",
                   attrib->name);
            return MARKUP_ERROR;
        }

        HtpMsg(MSG_INFO, task->infile, "macro \"%s\" unset", attrib->name);
        attrib = attrib->next;
    }
    return DISCARD_MARKUP;
}


uint IncProcessor(TASK *task, HTML_MARKUP *htmlMarkup, char **newPlaintext)
{
    const char *expansion;
    char valueStr[MAX_INC_VALUE_LENGTH];
    int value;
    HTML_ATTRIBUTE *attrib;
    VARSTORE *varstore;

    varstore = task->varstore;
    if (UnlinkBoolAttributeInMarkup(htmlMarkup, "GLOBAL")) {
        while (!varstore->isGlobal)
            varstore = varstore->parent;
    }

    attrib = htmlMarkup->attrib;
    while (attrib != NULL)
    {
        /* make sure variable exists in store */
        if(VariableExists(task->varstore, attrib->name) != TRUE)
        {
            /* only a warning */
            HtpMsg(MSG_ERROR, task->infile, "unrecognized macro name \"%s\"",
                attrib->name);
            return MARKUP_ERROR;
        }

        /* block macros cannot be increased */
        if(GetVariableType(task->varstore, attrib->name) != VAR_TYPE_SET_MACRO)
        {
            HtpMsg(MSG_ERROR, task->infile, 
                   "\"%s\" is not a set macro.",
                   attrib->name);
            return MARKUP_ERROR;
        }

        /* get the macro value and replace the attribute value */
        expansion = GetVariableValue(varstore, attrib->name);

        if(expansion == NULL)
        {
            HtpMsg(MSG_WARNING, task->infile, "no value for macro \"%s\"",
                   attrib->name);
            return MARKUP_ERROR;
        }
        value = atoi(expansion);
        if (attrib->value != NULL) {
            value += atoi(attrib->value);
        } else {
            value++;
        }
        snprintf(valueStr, MAX_INC_VALUE_LENGTH, "%i", value);

        if(UpdateVariableValue(task->varstore, attrib->name, 
                               DuplicateString(valueStr)) == FALSE) {
            HtpMsg(MSG_WARNING, task->infile, 
                   "new value %s for macro \"%s\" could not be stored.",
                   valueStr, attrib->name);
            return MARKUP_ERROR;
        }
        HtpMsg(MSG_INFO, task->infile, "incrementing macro \"%s\" to %s",
               attrib->name, valueStr);
        attrib = attrib->next;
    }
    return DISCARD_MARKUP;
}   
