/*
 *  SETLOCAL.C - setlocal and endlocal internal batch commands.
 *
 *  History:
 *
 *    1 Feb 2008 (Christoph von Wittich)
 *        started.
*/

#include "precomp.h"

typedef struct _SETLOCAL
{
    struct _SETLOCAL *Prev;
    BOOL EnableExtensions;
    BOOL DelayedExpansion;
    LPTSTR Environment;
} SETLOCAL;

/* Create a copy of the current environment */
LPTSTR
DuplicateEnvironment(VOID)
{
    LPTSTR Environ = GetEnvironmentStrings();
    LPTSTR End, EnvironCopy;

    if (!Environ) return NULL;

    for (End = Environ; *End; End += _tcslen(End) + 1) ;
    EnvironCopy = cmd_alloc((End + 1 - Environ) * sizeof(TCHAR));

    if (EnvironCopy)
        memcpy(EnvironCopy, Environ, (End + 1 - Environ) * sizeof(TCHAR));

    FreeEnvironmentStrings(Environ);
    return EnvironCopy;
}

INT cmd_setlocal(LPTSTR param)
{
    SETLOCAL *Saved;
    LPTSTR *arg;
    INT argc, i;

    /* SETLOCAL only works inside a batch file */
    if (!bc)
        return 0;

    Saved = cmd_alloc(sizeof(SETLOCAL));
    if (!Saved)
    {
        WARN("Cannot allocate memory for Saved!\n");
        error_out_of_memory();
        return 1;
    }
    Saved->Prev = bc->setlocal;
    Saved->EnableExtensions = bEnableExtensions;
    Saved->DelayedExpansion = bDelayedExpansion;
    Saved->Environment = DuplicateEnvironment();
    if (!Saved->Environment)
    {
        error_out_of_memory();
        cmd_free(Saved);
        return 1;
    }
    bc->setlocal = Saved;

    nErrorLevel = 0;

    arg = splitspace(param, &argc);
    for (i = 0; i < argc; i++)
    {
        if (!_tcsicmp(arg[i], _T("enableextensions")))
            /* FIXME: not implemented! */
            bEnableExtensions = TRUE;
        else if (!_tcsicmp(arg[i], _T("disableextensions")))
            /* FIXME: not implemented! */
            bEnableExtensions = FALSE;
        else if (!_tcsicmp(arg[i], _T("enabledelayedexpansion")))
            bDelayedExpansion = TRUE;
        else if (!_tcsicmp(arg[i], _T("disabledelayedexpansion")))
            bDelayedExpansion = FALSE;
        else
        {
            error_invalid_parameter_format(arg[i]);
            break;
        }
    }
    freep(arg);

    return nErrorLevel;
}

/* endlocal doesn't take any params */
INT cmd_endlocal(LPTSTR param)
{
    LPTSTR Environ, Name, Value;
    SETLOCAL *Saved;

    /* Pop a SETLOCAL struct off of this batch file's stack */
    if (!bc || !(Saved = bc->setlocal))
        return 0;
    bc->setlocal = Saved->Prev;

    bEnableExtensions = Saved->EnableExtensions;
    bDelayedExpansion = Saved->DelayedExpansion;

    /* First, clear out the environment. Since making any changes to the
     * environment invalidates pointers obtained from GetEnvironmentStrings(),
     * we must make a copy of it and get the variable names from that */
    Environ = DuplicateEnvironment();
    if (Environ)
    {
        for (Name = Environ; *Name; Name += _tcslen(Name) + 1)
        {
            if (!(Value = _tcschr(Name + 1, _T('='))))
                continue;
            *Value++ = _T('\0');
            SetEnvironmentVariable(Name, NULL);
            Name = Value;
        }
        cmd_free(Environ);
    }

    /* Now, restore variables from the copy saved by cmd_setlocal */
    for (Name = Saved->Environment; *Name; Name += _tcslen(Name) + 1)
    {
        if (!(Value = _tcschr(Name + 1, _T('='))))
            continue;
        *Value++ = _T('\0');
        SetEnvironmentVariable(Name, Value);
        Name = Value;
    }

    cmd_free(Saved->Environment);
    cmd_free(Saved);
    return 0;
}