OSSP CVS Repository

ossp - ossp-pkg/var/expression.c
Not logged in
[Honeypot]  [Browse]  [Directory]  [Home]  [Login
[Reports]  [Search]  [Ticket]  [Timeline
  [Raw

ossp-pkg/var/expression.c
#include "internal.h"

int expression(const char* begin, const char* end, const var_config_t* config,
               const char nameclass[256], var_cb_t lookup, void* lookup_context,
               int force_expand, tokenbuf* result)
    {
    const char* p = begin;
    const char* data;
    size_t len, buffer_size;
    int failed = 0;
    int rc;
    tokenbuf name;
    tokenbuf tmp;

    /* Clear the tokenbufs to make sure we have a defined state. */

    init_tokenbuf(&name);
    init_tokenbuf(&tmp);
    init_tokenbuf(result);

    /* Expect STARTDELIM. */

    if (p == end || *p != config->startdelim)
        return 0;

    if (++p == end)
        return VAR_INCOMPLETE_VARIABLE_SPEC;

    /* Get the name of the variable to expand. The name may consist of
       an arbitrary number of VARNAMEs and VARIABLEs. */

    do
        {
        rc = varname(p, end, nameclass);
        if (rc < 0)
            goto error_return;
        else if (rc > 0)
            {
            if (!append_to_tokenbuf(&name, p, rc))
                {
                rc = VAR_OUT_OF_MEMORY;
                goto error_return;
                }
            else
                p += rc;
            }

        rc = variable(p, end, config, nameclass, lookup, lookup_context, force_expand, &tmp);
        if (rc < 0)
            goto error_return;
        else if (rc > 0)
            {
            if (!append_to_tokenbuf(&name, tmp.begin, tmp.end - tmp.begin))
                {
                rc = VAR_OUT_OF_MEMORY;
                goto error_return;
                }
            else
                p += rc;
            }
        }
    while (rc > 0);

    /* We must have the complete variable name now, so make sure we
       do. */

    if (name.begin == name.end)
        {
        rc = VAR_INCOMPLETE_VARIABLE_SPEC;
        goto error_return;
        }

    /* Now we have the name of the variable stored in "name". We
       expect an ENDDELIM here. */

    if (p == end || (*p != config->enddelim && *p != ':'))
        {
        rc = VAR_INCOMPLETE_VARIABLE_SPEC;
        goto error_return;
        }
    else
        ++p;

    /* Use the lookup callback to get the variable's contents. */

    rc = (*lookup)(lookup_context, name.begin, name.end - name.begin, &data, &len, &buffer_size);
    if (rc < 0)
        goto error_return;
    else if (rc == 0)
        {
        /* The variable is undefined. What we'll do now depends on the
           force_expand flag. */

        if (force_expand)
            {
            rc = VAR_UNDEFINED_VARIABLE;
            goto error_return;
            }
        else
            {
            /* Initialize result to point back to the original text in
               the buffer. */

            result->begin       = begin-1;
            result->end         = p;
            result->buffer_size = 0;
            failed              = 1;
            }
        }
    else
        {
        /* The preliminary result is the contents of the variable.
           This may be modified by the commands that may follow. */

        result->begin       = data;
        result->end         = data + len;
        result->buffer_size = buffer_size;
        }

    if (p[-1] == ':')
        {
        /* Parse and execute commands. */

        free_tokenbuf(&tmp);
        --p;
        while (p != end && *p == ':')
            {
            ++p;
            if (!failed)
                rc = command(p, end, config, nameclass, lookup, lookup_context, force_expand, result);
            else
                rc = command(p, end, config, nameclass, lookup, lookup_context, force_expand, &tmp);
            if (rc < 0)
                goto error_return;
            p += rc;
            if (failed)
                result->end += rc;
            }

        if (p == end || *p != config->enddelim)
            {
            rc = VAR_INCOMPLETE_VARIABLE_SPEC;
            goto error_return;
            }
        ++p;
        if (failed)
            ++result->end;
        }

    /* Exit gracefully. */

    free_tokenbuf(&name);
    free_tokenbuf(&tmp);
    return p - begin;

    /* Exit in case of an error. */

  error_return:
    free_tokenbuf(&name);
    free_tokenbuf(&tmp);
    free_tokenbuf(result);
    return rc;
    }

CVSTrac 2.0.1