(file) Return to cli_c.c.bkp CVS log (file) (dir) Up to [OMI] / omi / cli

File: [OMI] / omi / cli / cli_c.c.bkp (download)
Revision: 1.1, Mon Apr 20 17:19:50 2015 UTC (9 years ago) by krisbash
Branch: MAIN
CVS Tags: OMI_1_0_8_2, OMI_1_0_8_1, HEAD
OMI 1.0.8-1

#include <stdio.h>
#include <signal.h>
#include <MI.h>
#include <pal/file.h>
#include <pal/dir.h>
#include <pal/strings.h>
#include <pal/cpu.h>
#include <pal/format.h>
#include <pal/lock.h>
#include <pal/sleep.h>
#include <pal/strings.h>
#include <base/paths.h>
#include <wql/wql.h>
#include <base/conf.h>
#include <base/env.h>
#include <base/instance.h>
#include <base/log.h>
#include <base/result.h>
#include <base/strarr.h>
#include <base/ptrarray.h>

static MI_Boolean ArgsToInstance(
    const MI_Char*** _p, 
    const MI_Char** end, 
    MI_Uint32 metaType,
    MI_Boolean key,
    MI_Instance **instanceOut);

static FILE* sout;
static FILE* serr;
const MI_Char* arg0;
static MI_Operation gop = {0, 0, 0};

struct Options
{
    MI_Boolean help;
    MI_Boolean quiet;
    MI_Boolean summary;
    MI_Boolean suppressResults;
    MI_Boolean trace;
    MI_Boolean shallow;
    int repeat;
    const MI_Char *assocClass;
    const MI_Char *resultClass;
    const MI_Char *role;
    const MI_Char *resultRole;
    const MI_Char *user;
    const MI_Char *password;
    MI_Uint64 timeOut;
    unsigned int httpport;
    unsigned int httpsport;
    MI_Boolean nulls;
    const MI_Char *querylang;
    const MI_Char *queryexpr;
    MI_Boolean synchronous;
};

static struct Options opts =
{ MI_FALSE, MI_FALSE, MI_FALSE, MI_FALSE, MI_FALSE, MI_FALSE, 1, NULL, NULL, NULL, NULL, NULL, NULL, 90 * 1000 * 1000, CONFIG_HTTPPORT, CONFIG_HTTPSPORT, MI_FALSE, MI_T("wql"), NULL, MI_FALSE };

static void err(const ZChar* fmt, ...)
{
    va_list ap;

    Ftprintf(serr, PAL_T("%T: "), tcs(arg0));

    va_start(ap, fmt);
    Vftprintf(serr, fmt, ap);
    va_end(ap);

    Ftprintf(serr, PAL_T("\n"));
}

static MI_Uint64 s_numInstances = 0;
static ptrdiff_t s_startTime;
static MI_Result s_finalResult = MI_RESULT_FAILED;
static ptrdiff_t s_finished = 0;

static void PrintSummary()
{
    ptrdiff_t now = CPU_GetTimeStamp();
    MI_Uint64 msec = (now - s_startTime) / 1000;
    MI_Real64 seconds = (MI_Real64)msec / (MI_Real64)1000.0;

    Tprintf(PAL_T("number of instances: %u\n"), s_numInstances);
    Tprintf(PAL_T("seconds: %.3lf\n"), seconds);
    Tprintf(PAL_T("instances per second: %.3lf\n"), s_numInstances / seconds);
    Tprintf(PAL_T("\n"));
}

static MI_Result Encode(int argc, const MI_Char* argv[])
{
    MI_Instance *inst;
    if (argc < 3)
    {
        Ftprintf(serr, PAL_T("Usage: %s noop CLASSNAME KEYBINDING\n\n"), tcs(arg0));
        return MI_RESULT_INVALID_PARAMETER;
    }

    argc -= 2;
    argv += 2;

    if (!ArgsToInstance(&argv, argv + argc, MI_FLAG_CLASS, MI_FALSE, &inst))
    {
        err(PAL_T("invalid instance name specification"));
        return MI_RESULT_INVALID_PARAMETER;
    }

    if (!opts.quiet)
    {
        Instance_Print(inst, sout, 0, opts.nulls, MI_FALSE);
    }

    MI_Instance_Delete(inst);

    s_numInstances++;

    return MI_RESULT_OK;
}



// Find closing brach (assuming *p points to an opening brace).
static const MI_Char** FindClosingBrace(const MI_Char** p)
{
    int nesting = 1;

    if (Tcscmp(*p, MI_T("{")) != 0)
        return NULL;

    p++;

    while (*p)
    {
        if (Tcscmp(*p, MI_T("{")) == 0)
            nesting++;
        else if (Tcscmp(*p, MI_T("}")) == 0)
            nesting--;

        p++;

        if (nesting == 0)
            return p;
    }

    return NULL;
}

static void MI_MAIN_CALL _DeleteInstance(void* inst)
{
    MI_Instance_Delete((MI_Instance*)inst);
}

static MI_Boolean ArgsToInstance(
    const MI_Char*** _p, 
    const MI_Char** end, 
    MI_Uint32 metaType,
    MI_Boolean key,
    MI_Instance **instanceOut)
{
    MI_Instance *instance;
    MI_Uint32 keyFlag = 0;
    const MI_Char **p = *_p;

    if (key)
        keyFlag = MI_FLAG_KEY;

    if (p == end)
        return MI_FALSE;

    // Consume opening brace:
    if (Tcscmp(*p++, MI_T("{")) != 0)
        return MI_FALSE;

    if (p == end)
        return MI_FALSE;


    if (metaType == MI_FLAG_METHOD)
    {
        if (Instance_NewDynamic(&instance, MI_T("Parameters"), MI_FLAG_METHOD, NULL) != MI_RESULT_OK)
            return MI_FALSE;
    }
    else
    {
        if (Instance_NewDynamic(&instance, *p++, MI_FLAG_CLASS, NULL) != MI_RESULT_OK)
            return MI_FALSE;

        if (p == end)
        {
            MI_Instance_Delete(instance);
            return MI_FALSE;
        }
    }

    // Consume name/value pairs:
    for (;;)
    {
        const MI_Char *name;
        if (Tcscmp(*p, MI_T("}")) == 0)
        {
            p++;
            break;
        }

        // Get name:
        name = *p++;

        if (p == end)
        {
            MI_Instance_Delete(instance);
            return MI_FALSE;
        }

        // Get value:
        if (Tcscmp(*p, MI_T("{")) == 0)
        {
            const MI_Char** q = FindClosingBrace(p);
            MI_Instance *tmpInst;
            MI_Value value;

            if (!q || q == end)
            {
                MI_Instance_Delete(instance);
                return MI_FALSE;
            }

            // Recursively call to obtain reference or embedded instance.

            if (!ArgsToInstance(&p, q, MI_FLAG_CLASS, key, &tmpInst))
            {
                MI_Instance_Delete(instance);
                return MI_FALSE;
            }

            value.instance = tmpInst;
            if (MI_Instance_AddElement(instance, name, &value, MI_INSTANCE, keyFlag | MI_FLAG_ADOPT) != MI_RESULT_OK)
                //!instance.AddInstance(name, tmpInst, MI_FALSE, key))
            {
                MI_Instance_Delete(tmpInst);
                MI_Instance_Delete(instance);
                return MI_FALSE;
            }
        }
        else if (Tcscmp(*p, MI_T("[")) == 0)
        {
            MI_Char** strArray = ZArr();
            PtrArray instanceArray;

            if (strArray == NULL)
            {
                MI_Instance_Delete(instance);
                return MI_FALSE;
            }
            if (PtrArray_Construct(&instanceArray, 5, _DeleteInstance) != 0)
            {
                ZArrFree(strArray);
                MI_Instance_Delete(instance);
                return MI_FALSE;
            }

            p++;

            // Find closing brace:
            while (*p && Tcscmp(*p, MI_T("]")) != 0)
            {
                if (Tcscmp(*p, MI_T("{")) == 0)
                {
                    const MI_Char** q = FindClosingBrace(p);
                    MI_Instance *tmpInst = NULL;

                    if (!q || q == end)
                    {
                        if (strArray)
                        {
#ifdef _PREFAST_
    #pragma prefast(push)
    #pragma prefast(disable:26018) 
#endif
                            ZArrFree(strArray);
#ifdef _PREFAST_
    #pragma prefast(pop)
#endif
                        }
                        PtrArray_Destruct(&instanceArray);
                        MI_Instance_Delete(instance);
                        return MI_FALSE;
                    }

                    if (!ArgsToInstance(&p, q, MI_FLAG_CLASS, key, &tmpInst))
                    {
                        if (strArray)
                        {
#ifdef _PREFAST_
    #pragma prefast(push)
    #pragma prefast(disable:26018) 
#endif
                            ZArrFree(strArray);
#ifdef _PREFAST_
    #pragma prefast(pop)
#endif
                        }
                        PtrArray_Destruct(&instanceArray);
                        MI_Instance_Delete(instance);
                        return MI_FALSE;
                    }
                    if (PtrArray_Append(&instanceArray, tmpInst) != 0)
                    {
                        if (strArray)
                        {
#ifdef _PREFAST_
    #pragma prefast(push)
    #pragma prefast(disable:26018) 
#endif
                            ZArrFree(strArray);
#ifdef _PREFAST_
    #pragma prefast(pop)
#endif
                        }
                        PtrArray_Destruct(&instanceArray);
                        MI_Instance_Delete(instance);
                        MI_Instance_Delete(tmpInst);
                        return MI_FALSE;
                    }
                }
                else
                {
                    MI_Char **_strArray = strArray;
                    ZArrCat(&_strArray, *p++);
                    if (_strArray == NULL)
                    {
                        /* Failed */
                        if (strArray)
                        {
#ifdef _PREFAST_
    #pragma prefast(push)
    #pragma prefast(disable:26018) 
#endif
                            ZArrFree(strArray);
#ifdef _PREFAST_
    #pragma prefast(pop)
#endif
                        }
                        PtrArray_Destruct(&instanceArray);
                        MI_Instance_Delete(instance);
                        return MI_FALSE;
                    }
                    strArray = _strArray;
                }
            }

            // Handle missing closing brace:
            if (p == end)
            {
                if (strArray)
                {
#ifdef _PREFAST_
    #pragma prefast(push)
    #pragma prefast(disable:26018) 
#endif
                    ZArrFree(strArray);
#ifdef _PREFAST_
    #pragma prefast(pop)
#endif
                }
                PtrArray_Destruct(&instanceArray);
                MI_Instance_Delete(instance);
                return MI_FALSE;
            }

            if (instanceArray.size)
            {
                MI_Value value;
                MI_Uint32 flags = 0;
                value.instancea.data = (MI_Instance**) instanceArray.data;
                value.instancea.size = instanceArray.size;
                if (key)
                    flags = MI_FLAG_KEY;

                if (MI_Instance_AddElement(instance, name, &value, MI_INSTANCEA, flags) != MI_RESULT_OK)
                {
                    if (strArray)
                    {
#ifdef _PREFAST_
    #pragma prefast(push)
    #pragma prefast(disable:26018) 
#endif
                        ZArrFree(strArray);
#ifdef _PREFAST_
    #pragma prefast(pop)
#endif
                    }
                    PtrArray_Destruct(&instanceArray);
                    MI_Instance_Delete(instance);
                    return MI_FALSE;
                }
            }
            else
            {
                MI_Uint32 arrLength = ZArrLen(strArray);
                if (arrLength)
                {
                    MI_Value value;
                    MI_Uint32 flags = 0;
                    value.stringa.data = strArray;
                    value.stringa.size = arrLength;
                    if (key)
                        flags = MI_FLAG_KEY;

                    if (MI_Instance_AddElement(instance, name, &value, MI_STRINGA, flags) != MI_RESULT_OK)
                    {
                        if (strArray)
                        {
#ifdef _PREFAST_
    #pragma prefast(push)
    #pragma prefast(disable:26018) 
#endif
                            ZArrFree(strArray);
#ifdef _PREFAST_
    #pragma prefast(pop)
#endif
                        }
                        PtrArray_Destruct(&instanceArray);
                        MI_Instance_Delete(instance);
                        return MI_FALSE;
                    }
                }
            }

            if (strArray)
            {
#ifdef _PREFAST_
    #pragma prefast(push)
    #pragma prefast(disable:26018) 
#endif
                ZArrFree(strArray);
#ifdef _PREFAST_
    #pragma prefast(pop)
#endif
            }
            PtrArray_Destruct(&instanceArray);
            p++;
        }
        else
        {
            MI_Value value;

            value.string = (MI_Char *)*p++;

            // Add property:
            if (MI_Instance_AddElement(instance, name, &value, MI_STRING, keyFlag | MI_FLAG_BORROW) != MI_RESULT_OK)
            {
                MI_Instance_Delete(instance);
                return MI_FALSE;
            }

            if (p == end)
                break;
        }
    }

    *_p = p;
    *instanceOut = instance;
    return MI_TRUE;
}

MI_Result CreateOperationOptions(_Inout_ MI_Session *session, _Out_ MI_OperationOptions *options)
{
    MI_Application application;
    MI_Result miResult;
    MI_Interval timeoutInterval;
    MI_Uint64 currentTimeout = opts.timeOut;


    miResult = MI_Session_GetApplication(session, &application);
    if (miResult != MI_RESULT_OK)
        return miResult;

    miResult = MI_Application_NewOperationOptions(&application, MI_FALSE, options);
    if (miResult != MI_RESULT_OK)
        return miResult;

    memset(&timeoutInterval, 0, sizeof(timeoutInterval));

    timeoutInterval.microseconds = currentTimeout%1000000;
    currentTimeout /= 1000000;
    
    timeoutInterval.seconds = currentTimeout % 60;
    currentTimeout /= 60;
    
    timeoutInterval.minutes = currentTimeout % 60;
    currentTimeout /= 60;
    
    timeoutInterval.hours = currentTimeout % 24;
    currentTimeout /= 24;
    
    timeoutInterval.days = (MI_Uint32) currentTimeout;

    miResult = MI_OperationOptions_SetTimeout(options, &timeoutInterval);
    if (miResult != MI_RESULT_OK)
    {
        goto cleanup;
    }

    return miResult;

cleanup:
    MI_OperationOptions_Delete(options);
    memset(options, 0, sizeof(*options));
    return miResult;
}

void MI_CALL InstanceResults(
    _In_opt_     MI_Operation *operation,
    _In_     void *callbackContext, 
    _In_opt_ const MI_Instance *instance,
             MI_Boolean moreResults,
    _In_     MI_Result resultCode,
    _In_opt_z_ const MI_Char *errorString,
    _In_opt_ const MI_Instance *errorDetails,
    _In_opt_ MI_Result (MI_CALL * resultAcknowledgement)(_In_ MI_Operation *operation))
{
    if (instance)
    {
        s_numInstances++;

        if (!opts.quiet)
        {
            Instance_Print(instance, sout, 0, opts.nulls, MI_FALSE);
        }
    }

    if (moreResults == MI_FALSE)
    {
        if (resultCode != MI_RESULT_OK)
        {
            if (!opts.suppressResults)
            {
                DEBUG_ASSERT(PAL_FALSE);
                err(PAL_T("result: %T"), tcs(Result_ToString(resultCode)));
                if (errorString)
                {
                    err(PAL_T("result: %T"), tcs(errorString));
                }
                if (errorDetails)
                {
                    Instance_Print(errorDetails, sout, 0, opts.nulls, MI_FALSE);
                }
            }
        }
        s_finalResult = resultCode;
        s_finished = 1;
        CondLock_Broadcast((ptrdiff_t)callbackContext);
    }
}

void MI_CALL IndicationResult(
    _In_opt_     MI_Operation *operation,
    _In_     void *callbackContext, 
    _In_opt_ const MI_Instance *instance,
    _In_opt_z_ const MI_Char *bookmark,
    _In_opt_z_ const MI_Char *machineID,
             MI_Boolean moreResults,
    _In_     MI_Result resultCode,
    _In_opt_z_ const MI_Char *errorString,
    _In_opt_ const MI_Instance *errorDetails,
    _In_opt_ MI_Result (MI_CALL * resultAcknowledgement)(_In_ MI_Operation *operation))
{
    if (instance)
    {
        s_numInstances++;

        if (!opts.quiet)
        {
            Ftprintf(sout, PAL_T("Async suscribe. Bookmark: %T; MachineID: %T\n"), tcs(bookmark), tcs(machineID));
            Instance_Print(instance, sout, 0, opts.nulls, MI_FALSE);
        }
    }

    if (moreResults == MI_FALSE)
    {
        if (resultCode != MI_RESULT_OK)
        {
            if (!opts.suppressResults)
            {
                err(PAL_T("result: %T"), tcs(Result_ToString(resultCode)));
                if (errorString)
                {
                    err(PAL_T("result: %T"), tcs(errorString));
                }
                if (errorDetails)
                {
                    Instance_Print(errorDetails, sout, 0, opts.nulls, MI_FALSE);
                }
            }
        }
        s_finalResult = resultCode;
        s_finished = 1;
        CondLock_Broadcast((ptrdiff_t)callbackContext);
    }
}

static MI_Result ConsumeInstanceResults(MI_Operation *miOperation)
{
    MI_Result miResult;

    if (opts.synchronous == MI_TRUE)
    {
        MI_Boolean moreResults = MI_FALSE;
        do
        {
            const MI_Instance *miInstanceResult = NULL;
            MI_Result _miResult;
            const MI_Char *errorString = NULL;
            const MI_Instance *errorDetails = NULL;

            _miResult = MI_Operation_GetInstance(miOperation, &miInstanceResult, &moreResults, &miResult, &errorString, &errorDetails);
            if (_miResult != MI_RESULT_OK)
            {
                miResult = _miResult;
            }
            if (miInstanceResult)
            {
                s_numInstances++;

                if (!opts.quiet)
                {
                    Instance_Print(miInstanceResult, sout, 0, opts.nulls, MI_FALSE);
                }
            }

            if (moreResults == MI_FALSE)
            {
                if (miResult != MI_RESULT_OK)
                {
                    if (!opts.suppressResults)
                    {
                        DEBUG_ASSERT(PAL_FALSE);
                        err(PAL_T("result: %T"), tcs(Result_ToString(miResult)));
                        if (errorString)
                        {
                            err(PAL_T("result: %T"), tcs(errorString));
                        }
                        if (errorDetails)
                        {
                            Instance_Print(errorDetails, sout, 0, opts.nulls, MI_FALSE);
                        }
                    }
                }
                s_finalResult = miResult;
                s_finished = 1;
            }

        } while ((miResult == MI_RESULT_OK) && (moreResults == MI_TRUE));
    }
    else
    {
        ptrdiff_t finished;
        finished = s_finished;
        while (!finished)
        {
            CondLock_Wait((ptrdiff_t)&s_finished, &s_finished, finished, CONDLOCK_DEFAULT_SPINCOUNT);
            finished = s_finished;
        }
        miResult = s_finalResult;
    }

    return miResult;
}


static MI_Result ConsumeIndicationsResults(MI_Operation *miOperation)
{
    MI_Result miResult;

    if (opts.synchronous == MI_TRUE)
    {
        MI_Boolean moreResults = MI_FALSE;
        do
        {
            const MI_Instance *miInstanceResult = NULL;
            MI_Result _miResult;
            const MI_Char *errorString = NULL;
            const MI_Instance *errorDetails = NULL;
            const MI_Char *bookmark;
            const MI_Char *machineid;

            _miResult = MI_Operation_GetIndication(miOperation, &miInstanceResult, &bookmark, &machineid, &moreResults, &miResult, &errorString, &errorDetails);
            if (_miResult != MI_RESULT_OK)
            {
                miResult = _miResult;
            }

            if (miInstanceResult)
            {
                s_numInstances++;

                if (!opts.quiet)
                {
                    Ftprintf(sout, PAL_T("Sync subscribe. Bookmark: %T; MachineID: %T\n"), tcs(bookmark), tcs(machineid));
                    Instance_Print(miInstanceResult, sout, 0, opts.nulls, MI_FALSE);
                }
            }

            if (moreResults == MI_FALSE)
            {
                if (miResult != MI_RESULT_OK)
                {
                    if (!opts.suppressResults)
                    {
                        err(PAL_T("result: %T"), tcs(Result_ToString(miResult)));
                        if (errorString)
                        {
                            err(PAL_T("result: %T"), tcs(errorString));
                        }
                        if (errorDetails)
                        {
                            Instance_Print(errorDetails, sout, 0, opts.nulls, MI_FALSE);
                        }
                    }
                }
                s_finalResult = miResult;
                s_finished = 1;
            }

        } while ((miResult == MI_RESULT_OK) && (moreResults == MI_TRUE));
    }
    else
    {
        ptrdiff_t finished;
        finished = s_finished;
        while (!finished)
        {
            CondLock_Wait((ptrdiff_t)&s_finished, &s_finished, finished, CONDLOCK_DEFAULT_SPINCOUNT);
            finished = s_finished;
        }
        miResult = s_finalResult;
    }

    return miResult;
}

void MI_CALL ClassResults(
    _In_opt_     MI_Operation *operation,
    _In_     void *callbackContext, 
    _In_opt_ const MI_Class *classObject,
             MI_Boolean moreResults,
    _In_     MI_Result resultCode,
    _In_opt_z_ const MI_Char *errorString,
    _In_opt_ const MI_Instance *errorDetails,
    _In_opt_ MI_Result (MI_CALL * resultAcknowledgement)(_In_ MI_Operation *operation))
{
    if (classObject)
    {
        s_numInstances++;

        if (!opts.quiet)
        {
            MI_Instance *instance;
            if (Instance_New(&instance, classObject->classDecl, NULL) == MI_RESULT_OK)
            {
                Instance_Print(instance, sout, 0, MI_TRUE, MI_TRUE);

                MI_Instance_Delete(instance);
            }
        }
    }

    if (moreResults == MI_FALSE)
    {
        if (resultCode != MI_RESULT_OK)
        {
            if (!opts.suppressResults)
            {
                err(PAL_T("result: %T"), tcs(Result_ToString(resultCode)));
                if (errorString)
                {
                    err(PAL_T("result: %T"), tcs(errorString));
                }
                if (errorDetails)
                {
                    Instance_Print(errorDetails, sout, 0, opts.nulls, MI_FALSE);
                }
            }
        }
        s_finalResult = resultCode;
        s_finished = 1;
        CondLock_Broadcast((ptrdiff_t)callbackContext);
    }
}

static MI_Result ConsumeClassResults(MI_Operation *miOperation)
{
    MI_Result miResult;

    if (opts.synchronous == MI_TRUE)
    {
        MI_Boolean moreResults = MI_FALSE;
        do
        {
            const MI_Class *miClassResult = NULL;
            MI_Result _miResult;
            const MI_Char *errorString = NULL;
            const MI_Instance *errorDetails = NULL;

            _miResult = MI_Operation_GetClass(miOperation, &miClassResult, &moreResults, &miResult, &errorString, &errorDetails);
            if (_miResult != MI_RESULT_OK)
            {
                miResult = _miResult;
            }
            if (miClassResult)
            {
                s_numInstances++;

                if (!opts.quiet)
                {
                    MI_Instance *instance;
                    if (Instance_New(&instance, miClassResult->classDecl, NULL) == MI_RESULT_OK)
                    {
                        Instance_Print(instance, sout, 0, MI_TRUE, MI_TRUE);

                        MI_Instance_Delete(instance);
                    }
                }
            }

            if (moreResults == MI_FALSE)
            {
                if (miResult != MI_RESULT_OK)
                {
                    if (!opts.suppressResults)
                    {
                        err(PAL_T("result: %T"), tcs(Result_ToString(miResult)));
                        if (errorString)
                        {
                            err(PAL_T("result: %T"), tcs(errorString));
                        }
                        if (errorDetails)
                        {
                            Instance_Print(errorDetails, sout, 0, opts.nulls, MI_FALSE);
                        }
                    }
                }
                s_finalResult = miResult;
                s_finished = 1;
            }

        } while ((miResult == MI_RESULT_OK) && (moreResults == MI_TRUE));
    }
    else
    {
        ptrdiff_t finished;
        finished = s_finished;
        while (!finished)
        {
            CondLock_Wait((ptrdiff_t)&s_finished, &s_finished, finished, CONDLOCK_DEFAULT_SPINCOUNT);
            finished = s_finished;
        }
        miResult = s_finalResult;
    }

    return miResult;
}


void MI_CALL NoOpResults(
    _In_opt_     MI_Operation *operation,
    _In_     void *callbackContext, 
    _In_opt_ const MI_Instance *instance,
             MI_Boolean moreResults,
    _In_     MI_Result resultCode,
    _In_opt_z_ const MI_Char *errorString,
    _In_opt_ const MI_Instance *errorDetails,
    _In_opt_ MI_Result (MI_CALL * resultAcknowledgement)(_In_ MI_Operation *operation))
{
    if (instance)
    {
        s_numInstances++;

        if (!opts.quiet)
        {
            Instance_Print(instance, sout, 0, opts.nulls, MI_FALSE);
        }
    }

    if (moreResults == MI_FALSE)
    {
        if (resultCode != MI_RESULT_OK)
        {
            if (!opts.suppressResults)
            {
                err(PAL_T("result: %T"), tcs(Result_ToString(resultCode)));
                if (errorString)
                {
                    err(PAL_T("result: %T"), tcs(errorString));
                }
                if (errorDetails)
                {
                    Instance_Print(errorDetails, sout, 0, opts.nulls, MI_FALSE);
                }
            }
        }
        else
        {
            Ftprintf(sout, PAL_T("got noop response\n"));

        }
        s_finalResult = resultCode;
        s_finished = 1;
        CondLock_Broadcast((ptrdiff_t)callbackContext);
    }
}


static MI_Result NoOp(MI_Session *miSession, int argc, const MI_Char* argv [])
{
    MI_Result miResult;
    MI_Operation miOperation = MI_OPERATION_NULL;
    MI_OperationCallbacks _callbacks = MI_OPERATIONCALLBACKS_NULL;
    MI_OperationCallbacks *callbacks = NULL;
    MI_Uint32 flags = 0;

    MI_UNUSED(argv);

    if (argc != 2)
    {
        Ftprintf(serr, MI_T("Usage: %s noop\n\n"), tcs(arg0));
        return MI_RESULT_INVALID_PARAMETER;
    }

    if (opts.synchronous == MI_FALSE)
    {
        _callbacks.callbackContext = &s_finished;
        _callbacks.instanceResult = NoOpResults;
        callbacks = &_callbacks;
        s_finished = 0;
    }


    MI_Session_TestConnection(miSession, flags, callbacks, &miOperation);

    miResult = ConsumeInstanceResults(&miOperation);

    MI_Operation_Close(&miOperation);

    return miResult;
}

static MI_Result EnumerateInstances(MI_Session *miSession, int argc, const MI_Char* argv[])
{
    MI_Result miResult;
    MI_OperationOptions miOperationOptions;
    MI_Operation miOperation = MI_OPERATION_NULL;
    MI_OperationCallbacks _callbacks = MI_OPERATIONCALLBACKS_NULL;
    MI_OperationCallbacks *callbacks = NULL;
    MI_Uint32 flags = 0;

    if (argc != 4)
    {
        Ftprintf(serr, MI_T("Usage: %s ei NAMESPACE CLASSNAME\n\n"), tcs(arg0));
        return MI_RESULT_INVALID_PARAMETER;
    }

    if (opts.shallow)
    {
        flags = MI_OPERATIONFLAGS_POLYMORPHISM_SHALLOW;
    }

    if (opts.synchronous == MI_FALSE)
    {
        _callbacks.callbackContext = &s_finished;
        _callbacks.instanceResult = InstanceResults;
        callbacks = &_callbacks;
        s_finished = 0;
    }


    miResult = CreateOperationOptions(miSession, &miOperationOptions);
    if (miResult != MI_RESULT_OK)
        return miResult;

    MI_Session_EnumerateInstances(miSession, flags, &miOperationOptions, argv[2], argv[3], MI_FALSE, callbacks, &miOperation);

    miResult = ConsumeInstanceResults(&miOperation);

    MI_Operation_Close(&miOperation);

    MI_OperationOptions_Delete(&miOperationOptions);

    return miResult;
}

static MI_Result QueryInstances(MI_Session *miSession, int argc, const MI_Char* argv[])
{
    MI_Result miResult;
    MI_OperationOptions miOperationOptions;
    MI_Operation miOperation = MI_OPERATION_NULL;
    MI_OperationCallbacks _callbacks = MI_OPERATIONCALLBACKS_NULL;
    MI_OperationCallbacks *callbacks = NULL;

    if (argc != 4)
    {
        Ftprintf(serr, MI_T("Usage: %s ei NAMESPACE CLASSNAME\n\n"), tcs(arg0));
        return MI_RESULT_INVALID_PARAMETER;
    }

    if (opts.synchronous == MI_FALSE)
    {
        _callbacks.callbackContext = &s_finished;
        _callbacks.instanceResult = InstanceResults;
        callbacks = &_callbacks;
        s_finished = 0;
    }

    miResult = CreateOperationOptions(miSession, &miOperationOptions);
    if (miResult != MI_RESULT_OK)
        return miResult;

    MI_Session_QueryInstances(miSession, 0, &miOperationOptions, argv[2], opts.querylang, opts.queryexpr, callbacks, &miOperation);

    miResult = ConsumeInstanceResults(&miOperation);
    
    MI_Operation_Close(&miOperation);

    MI_OperationOptions_Delete(&miOperationOptions);

    return miResult;
}

static MI_Result Query(MI_Session *miSession, int argc, const MI_Char* argv[])
{
    MI_Result miResult;
    MI_OperationOptions miOperationOptions;
    MI_Operation miOperation = MI_OPERATION_NULL;
    MI_OperationCallbacks _callbacks = MI_OPERATIONCALLBACKS_NULL;
    MI_OperationCallbacks *callbacks = NULL;
    const MI_Char* dialect = NULL;

    if (argc != 4)
    {
        Ftprintf(serr, PAL_T("Usage: %T %T NAMESPACE QUERY\n\n"), tcs(arg0),
            tcs(argv[1]));
        return MI_RESULT_INVALID_PARAMETER;
    }

    if (opts.synchronous == MI_FALSE)
    {
        _callbacks.callbackContext = &s_finished;
        _callbacks.instanceResult = InstanceResults;
        callbacks = &_callbacks;
        s_finished = 0;
    }

    // Determine query dialect:
    if (Tcscmp(argv[1], MI_T("wql")) == 0)
    {
        dialect = MI_T("WQL");
    }
    else if (Tcscmp(argv[1], MI_T("cql")) == 0)
    {
        dialect = MI_T("CQL");
    }
    else
    {
        err(MI_T("invalid query dialecdt: %T"), tcs(argv[1]));
    }

    // Extract query options.
    opts.queryexpr = argv[3];

    miResult = CreateOperationOptions(miSession, &miOperationOptions);
    if (miResult != MI_RESULT_OK)
        return miResult;

    MI_Session_QueryInstances(miSession, 0, &miOperationOptions, argv[2], dialect, argv[3], callbacks, &miOperation);

    miResult = ConsumeInstanceResults(&miOperation);
    
    MI_Operation_Close(&miOperation);

    MI_OperationOptions_Delete(&miOperationOptions);

    return miResult;
}

static MI_Result GetInstance(MI_Session *miSession, int argc, const MI_Char* argv[])
{
    MI_Result miResult;
    MI_OperationOptions miOperationOptions;
    MI_Operation miOperation = MI_OPERATION_NULL;
    MI_OperationCallbacks _callbacks = MI_OPERATIONCALLBACKS_NULL;
    MI_OperationCallbacks *callbacks = NULL;
    MI_Instance *instance;
    const MI_Char *nameSpace;
    const MI_Char** p;
    const MI_Char** end;

    if (argc < 4)
    {
        Ftprintf(serr, MI_T("Usage: %s gi NAMESPACE INSTANCENAME\n\n"), tcs(arg0));
        return MI_RESULT_INVALID_PARAMETER;
    }

    nameSpace = argv[2];
    argc -= 3;
    argv += 3;
    p = argv;
    end = p + argc;

    if (!ArgsToInstance(&p, end, MI_FLAG_CLASS, MI_TRUE, &instance))
    {
        err(MI_T("invalid instance name specification"));
        return MI_RESULT_FAILED;
    }

    if (p != end)
    {
        err(MI_T("extraneous arguments after instance name"));
        return MI_RESULT_INVALID_PARAMETER;
    }


    if (opts.synchronous == MI_FALSE)
    {
        _callbacks.callbackContext = &s_finished;
        _callbacks.instanceResult = InstanceResults;
        callbacks = &_callbacks;
        s_finished = 0;
    }

    miResult = CreateOperationOptions(miSession, &miOperationOptions);
    if (miResult != MI_RESULT_OK)
        return miResult;

    MI_Session_GetInstance(miSession, 0, &miOperationOptions, nameSpace, instance, callbacks, &miOperation);

    miResult = ConsumeInstanceResults(&miOperation);
    
    MI_Operation_Close(&miOperation);

    MI_Instance_Delete(instance);

    MI_OperationOptions_Delete(&miOperationOptions);

    return miResult;
}


static MI_Result CreateInstance(MI_Session *miSession, int argc, const MI_Char* argv[])
{
    MI_Result miResult;
    MI_OperationOptions miOperationOptions;
    MI_Operation miOperation = MI_OPERATION_NULL;
    MI_OperationCallbacks _callbacks = MI_OPERATIONCALLBACKS_NULL;
    MI_OperationCallbacks *callbacks = NULL;
    MI_Instance *instance;
    const MI_Char *nameSpace;
    const MI_Char** p;
    const MI_Char** end;

    if (argc < 4)
    {
        Ftprintf(serr, MI_T("Usage: %s ci NAMESPACE INSTANCE\n\n"), tcs(arg0));
        return MI_RESULT_INVALID_PARAMETER;
    }

    nameSpace = argv[2];
    argc -= 3;
    argv += 3;
    p = argv;
    end = p + argc;

    if (!ArgsToInstance(&p, end, MI_FLAG_CLASS, MI_TRUE, &instance))
    {
        err(PAL_T("invalid instance name specification"));
        return MI_RESULT_FAILED;
    }

    if (p != end)
    {
        err(PAL_T("extraneous arguments after instance name"));
        return MI_RESULT_INVALID_PARAMETER;
    }

    if (opts.synchronous == MI_FALSE)
    {
        _callbacks.callbackContext = &s_finished;
        _callbacks.instanceResult = InstanceResults;
        callbacks = &_callbacks;
        s_finished = 0;
    }

    miResult = CreateOperationOptions(miSession, &miOperationOptions);
    if (miResult != MI_RESULT_OK)
        return miResult;

    MI_Session_CreateInstance(miSession, 0, &miOperationOptions, nameSpace, instance, callbacks, &miOperation);

    miResult = ConsumeInstanceResults(&miOperation);
    
    MI_Operation_Close(&miOperation);

    MI_Instance_Delete(instance);

    MI_OperationOptions_Delete(&miOperationOptions);

    return miResult;

}

static MI_Result ModifyInstance(MI_Session *miSession, int argc, const MI_Char* argv[])
{
    MI_Result miResult;
    MI_OperationOptions miOperationOptions;
    MI_Operation miOperation = MI_OPERATION_NULL;
    MI_OperationCallbacks _callbacks = MI_OPERATIONCALLBACKS_NULL;
    MI_OperationCallbacks *callbacks = NULL;
    MI_Instance *instance;
    const MI_Char *nameSpace;
    const MI_Char** p;
    const MI_Char** end;

    if (argc < 4)
    {
        Ftprintf(serr, MI_T("Usage: %s mi NAMESPACE INSTANCE\n\n"), tcs(arg0));
        return MI_RESULT_INVALID_PARAMETER;
    }

    nameSpace = argv[2];
    argc -= 3;
    argv += 3;
    p = argv;
    end = p + argc;

    if (!ArgsToInstance(&p, end, MI_FLAG_CLASS, MI_TRUE, &instance))
    {
        err(PAL_T("invalid instance name specification"));
        return MI_RESULT_FAILED;
    }

    if (p != end)
    {
        err(PAL_T("extraneous arguments after instance name"));
        return MI_RESULT_INVALID_PARAMETER;
    }

    if (opts.synchronous == MI_FALSE)
    {
        _callbacks.callbackContext = &s_finished;
        _callbacks.instanceResult = InstanceResults;
        callbacks = &_callbacks;
        s_finished = 0;
    }


    miResult = CreateOperationOptions(miSession, &miOperationOptions);
    if (miResult != MI_RESULT_OK)
        return miResult;

    MI_Session_ModifyInstance(miSession, 0, &miOperationOptions, nameSpace, instance, callbacks, &miOperation);

    miResult = ConsumeInstanceResults(&miOperation);
    
    MI_Operation_Close(&miOperation);

    MI_Instance_Delete(instance);

    MI_OperationOptions_Delete(&miOperationOptions);

    return miResult;

}

static MI_Result DeleteInstance(MI_Session *miSession, int argc, const MI_Char* argv[])
{
    MI_Result miResult;
    MI_OperationOptions miOperationOptions;
    MI_Operation miOperation = MI_OPERATION_NULL;
    MI_OperationCallbacks _callbacks = MI_OPERATIONCALLBACKS_NULL;
    MI_OperationCallbacks *callbacks = NULL;
    MI_Instance *instance;
    const MI_Char *nameSpace;
    const MI_Char** p;
    const MI_Char** end;

    if (argc < 4)
    {
        Ftprintf(serr, MI_T("Usage: %s di NAMESPACE INSTANCE\n\n"), tcs(arg0));
        return MI_RESULT_INVALID_PARAMETER;
    }

    nameSpace = argv[2];
    argc -= 3;
    argv += 3;
    p = argv;
    end = p + argc;

    if (!ArgsToInstance(&p, end, MI_FLAG_CLASS, MI_TRUE, &instance))
    {
        err(PAL_T("invalid instance name specification"));
        return MI_RESULT_FAILED;
    }

    if (p != end)
    {
        err(PAL_T("extraneous arguments after instance name"));
        return MI_RESULT_INVALID_PARAMETER;
    }

    if (opts.synchronous == MI_FALSE)
    {
        _callbacks.callbackContext = &s_finished;
        _callbacks.instanceResult = InstanceResults;
        callbacks = &_callbacks;
        s_finished = 0;
    }


    miResult = CreateOperationOptions(miSession, &miOperationOptions);
    if (miResult != MI_RESULT_OK)
        return miResult;

    MI_Session_DeleteInstance(miSession, 0, &miOperationOptions, nameSpace, instance, callbacks, &miOperation);

    miResult = ConsumeInstanceResults(&miOperation);
    
    MI_Operation_Close(&miOperation);

    MI_Instance_Delete(instance);

    MI_OperationOptions_Delete(&miOperationOptions);

    return miResult;

}

static MI_Result Associators(MI_Session *miSession, int argc, const MI_Char* argv[])
{
    MI_Result miResult;
    MI_OperationOptions miOperationOptions;
    MI_Operation miOperation = MI_OPERATION_NULL;
    MI_OperationCallbacks _callbacks = MI_OPERATIONCALLBACKS_NULL;
    MI_OperationCallbacks *callbacks = NULL;
    MI_Instance *instance;
    const MI_Char *nameSpace;
    const MI_Char** p;
    const MI_Char** end;

    if (argc < 4)
    {
        Ftprintf(serr, MI_T("Usage: %s a NAMESPACE INSTANCE\n\n"), tcs(arg0));
        return MI_RESULT_INVALID_PARAMETER;
    }

    nameSpace = argv[2];
    argc -= 3;
    argv += 3;
    p = argv;
    end = p + argc;

    if (!ArgsToInstance(&p, end, MI_FLAG_CLASS, MI_TRUE, &instance))
    {
        err(PAL_T("invalid instance name specification"));
        return MI_RESULT_FAILED;
    }

    if (p != end)
    {
        err(PAL_T("extraneous arguments after instance name"));
        return MI_RESULT_INVALID_PARAMETER;
    }

    if (opts.synchronous == MI_FALSE)
    {
        _callbacks.callbackContext = &s_finished;
        _callbacks.instanceResult = InstanceResults;
        callbacks = &_callbacks;
        s_finished = 0;
    }


    miResult = CreateOperationOptions(miSession, &miOperationOptions);
    if (miResult != MI_RESULT_OK)
        return miResult;

    MI_Session_AssociatorInstances(miSession, 0, &miOperationOptions, nameSpace, instance, opts.assocClass, opts.resultClass, opts.role, opts.resultRole, MI_FALSE, callbacks, &miOperation);

    miResult = ConsumeInstanceResults(&miOperation);
    
    MI_Operation_Close(&miOperation);

    MI_Instance_Delete(instance);

    MI_OperationOptions_Delete(&miOperationOptions);

    return miResult;
}

static MI_Result References(MI_Session *miSession, int argc, const MI_Char* argv[])
{
    MI_Result miResult;
    MI_OperationOptions miOperationOptions;
    MI_Operation miOperation = MI_OPERATION_NULL;
    MI_OperationCallbacks _callbacks = MI_OPERATIONCALLBACKS_NULL;
    MI_OperationCallbacks *callbacks = NULL;
    MI_Instance *instance;
    const MI_Char *nameSpace;
    const MI_Char** p;
    const MI_Char** end;

    if (argc < 4)
    {
        Ftprintf(serr, MI_T("Usage: %T d NAMESPACE INSTANCE\n\n"), tcs(arg0));
        return MI_RESULT_INVALID_PARAMETER;
    }

    nameSpace = argv[2];
    argc -= 3;
    argv += 3;
    p = argv;
    end = p + argc;

    if (!ArgsToInstance(&p, end, MI_FLAG_CLASS, MI_TRUE, &instance))
    {
        err(PAL_T("invalid instance name specification"));
        return MI_RESULT_FAILED;
    }

    if (p != end)
    {
        err(PAL_T("extraneous arguments after instance name"));
        return MI_RESULT_INVALID_PARAMETER;
    }

    if (opts.synchronous == MI_FALSE)
    {
        _callbacks.callbackContext = &s_finished;
        _callbacks.instanceResult = InstanceResults;
        callbacks = &_callbacks;
        s_finished = 0;
    }


    miResult = CreateOperationOptions(miSession, &miOperationOptions);
    if (miResult != MI_RESULT_OK)
        return miResult;

    MI_Session_ReferenceInstances(miSession, 0, &miOperationOptions, nameSpace, instance, opts.assocClass, opts.role, MI_FALSE, callbacks, &miOperation);

    miResult = ConsumeInstanceResults(&miOperation);
    
    MI_Operation_Close(&miOperation);

    MI_Instance_Delete(instance);

    MI_OperationOptions_Delete(&miOperationOptions);

    return miResult;
}

static MI_Result Invoke(MI_Session *miSession, int argc, const MI_Char* argv[])
{
    MI_Result miResult;
    MI_OperationOptions miOperationOptions;
    MI_Operation miOperation = MI_OPERATION_NULL;
    MI_OperationCallbacks _callbacks = MI_OPERATIONCALLBACKS_NULL;
    MI_OperationCallbacks *callbacks = NULL;
    MI_Instance *instance;
    MI_Instance *inParams = NULL;
    const MI_Char *nameSpace;
    const MI_Char *methodName;
    const MI_Char** p;
    const MI_Char** end;
    MI_Uint32 elementCount = 0;

    if (argc < 5)
    {
        Ftprintf(serr, 
            PAL_T("Usage: %s iv NAMESPACE INSTANCENAME METHODNAME PARAMETERS\n\n"), 
            tcs(arg0));
        return MI_RESULT_INVALID_PARAMETER;
    }

    nameSpace = argv[2];
    argc -= 3;
    argv += 3;
    p = argv;
    end = p + argc;

    if (!ArgsToInstance(&p, end, MI_FLAG_CLASS, MI_TRUE, &instance))
    {
        err(PAL_T("invalid instance name specification"));
        return MI_RESULT_FAILED;
    }

    if (p == end)
    {
        err(PAL_T("expected method name"));
        return MI_RESULT_INVALID_PARAMETER;
    }

    methodName = *p;
    p++;

    if (p != end)
    {
        if (!ArgsToInstance(&p, end, MI_FLAG_METHOD, MI_TRUE, &inParams))
        {
            err(PAL_T("invalid instance name specification"));
            return MI_RESULT_FAILED;
        }
    }

    if (opts.synchronous == MI_FALSE)
    {
        _callbacks.callbackContext = &s_finished;
        _callbacks.instanceResult = InstanceResults;
        callbacks = &_callbacks;
        s_finished = 0;
    }

    if (MI_Instance_GetElementCount(instance, &elementCount) != MI_RESULT_OK)
    {
        err(PAL_T("Failed to get element count for instance"));
        return MI_RESULT_FAILED;
    }

    miResult = CreateOperationOptions(miSession, &miOperationOptions);
    if (miResult != MI_RESULT_OK)
        return miResult;

    if (elementCount)
    {
        MI_Session_Invoke(miSession, 0, NULL, nameSpace, instance->classDecl->name, methodName, instance, inParams, callbacks, &miOperation);
    }
    else
    {
        /* Static method */
        MI_Session_Invoke(miSession, 0, &miOperationOptions, nameSpace, instance->classDecl->name, methodName, NULL, inParams, callbacks, &miOperation);
    }

    miResult = ConsumeInstanceResults(&miOperation);
    
    MI_Operation_Close(&miOperation);

    MI_Instance_Delete(instance);

    MI_OperationOptions_Delete(&miOperationOptions);

    return miResult;
}

static MI_Result GetClass(MI_Session *miSession, int argc, const MI_Char* argv[])
{
    MI_Result miResult;
    MI_OperationOptions miOperationOptions;
    MI_Operation miOperation = MI_OPERATION_NULL;
    MI_OperationCallbacks _callbacks = MI_OPERATIONCALLBACKS_NULL;
    MI_OperationCallbacks *callbacks = NULL;
    const MI_Char *nameSpace;
    const MI_Char *className;

    if (argc != 4)
    {
        Ftprintf(serr, MI_T("Usage: %s gc NAMESPACE CLASSNAME\n\n"), tcs(arg0));
        return MI_RESULT_INVALID_PARAMETER;
    }

    nameSpace = argv[2];
    className = argv[3];

    if (opts.synchronous == MI_FALSE)
    {
        _callbacks.callbackContext = &s_finished;
        _callbacks.classResult = ClassResults;
        callbacks = &_callbacks;
        s_finished = 0;
    }


    miResult = CreateOperationOptions(miSession, &miOperationOptions);
    if (miResult != MI_RESULT_OK)
        return miResult;

    MI_Session_GetClass(miSession, 0, &miOperationOptions, nameSpace, className, callbacks, &miOperation);

    miResult = ConsumeClassResults(&miOperation);
    
    MI_Operation_Close(&miOperation);

    MI_OperationOptions_Delete(&miOperationOptions);

    return miResult;
}

static MI_Result Subscribe(MI_Session *miSession, int argc, const MI_Char* argv[])
{
    MI_Result miResult;
    MI_OperationOptions miOperationOptions;
    MI_Operation miOperation = MI_OPERATION_NULL;
    MI_OperationCallbacks _callbacks = MI_OPERATIONCALLBACKS_NULL;
    MI_OperationCallbacks *callbacks = NULL;
    const MI_Char *nameSpace;

    if (argc != 3 || opts.querylang == NULL || opts.queryexpr == NULL)
    {
        Ftprintf(serr, MI_T("Usage: %s [--querylang 'WQL/CQL'  --queryexpr ] sub NAMESPACE\n\n"), tcs(arg0));
        return MI_RESULT_INVALID_PARAMETER;
    }

    if (opts.synchronous == MI_FALSE)
    {
        _callbacks.callbackContext = &s_finished;
        _callbacks.indicationResult = IndicationResult;
        callbacks = &_callbacks;
        s_finished = 0;
    }

    nameSpace = argv[2];

    miResult = CreateOperationOptions(miSession, &miOperationOptions);
    if (miResult != MI_RESULT_OK)
    {
        Ftprintf(serr, MI_T("Failed to create MI_OperationOptions, error code(%d)\n\n"), miResult);
        return miResult;
    }

    MI_Session_Subscribe(miSession, 0, &miOperationOptions, nameSpace, opts.querylang, opts.queryexpr, NULL, callbacks, &miOperation);

    /* Duplicate operation */
    memcpy(&gop, &miOperation, sizeof(MI_Operation));

    miResult = ConsumeIndicationsResults(&miOperation);

    /* Cleanup global operation since it is done */
    memset(&gop, 0, sizeof(MI_Operation));

    MI_Operation_Close(&miOperation);

    MI_OperationOptions_Delete(&miOperationOptions);

    return miResult;
}

static MI_Result FindConfigFile(_Pre_writable_size_(PAL_MAX_PATH_SIZE) char path[PAL_MAX_PATH_SIZE])
{
    char* home;
    /* Look in current directory */
    {
        Strlcpy(path, "./.omiclirc", PAL_MAX_PATH_SIZE);

        if (access(path, R_OK) == 0)
            return MI_RESULT_OK;
    }

    /* Look in HOME directory */
    home = Dupenv("HOME");
    if (home)
    {
        Strlcpy(path, home, PAL_MAX_PATH_SIZE);
        Strlcat(path, "/.omiclirc", PAL_MAX_PATH_SIZE);

        if (access(path, R_OK) == 0)
        {
            free(home);
            return MI_RESULT_OK;
        }
        free(home);
    }

    /* Look in system config directory */
    {
        Strlcpy(path, OMI_GetPath(ID_SYSCONFDIR), PAL_MAX_PATH_SIZE);
        Strlcat(path, "/omicli.conf", PAL_MAX_PATH_SIZE);

        if (access(path, R_OK) == 0)
            return MI_RESULT_OK;
    }

    /* Not found */
    return MI_RESULT_FAILED;
}

static MI_Result GetConfigFileOptions()
{
    char path[PAL_MAX_PATH_SIZE];
    Conf* conf;
    MI_Result miResult = MI_RESULT_OK;

    /* Form the configuration file path (silently ignore if not found) */
    if (FindConfigFile(path) != 0)
        return MI_RESULT_OK;

    /* Open the configuration file */
    conf = Conf_Open(path);
    if (!conf)
    {
        err(PAL_T("failed to open configuration file: %s"), scs(path));
        return MI_RESULT_FAILED;
    }

    /* For each key=value pair in configuration file */
    for (;;)
    {
        const char* key;
        const char* value;
        int r = Conf_Read(conf, &key, &value);

        if (r == -1)
        {
            err(PAL_T("%s: %s\n"), scs(path), scs(Conf_Error(conf)));
            miResult = MI_RESULT_FAILED;
            goto cleanup;
        }

        if (r == 1)
            break;

        if (strcmp(key, "httpport") == 0)
        {
            char* end;
            unsigned long x = Strtoul(value, &end, 10);

            if (*end != '\0' || x > USHRT_MAX)
            {
                err(PAL_T("%s(%u): invalid value for '%s': %s"), scs(path), 
                    Conf_Line(conf), scs(key), scs(value));
                miResult = MI_RESULT_FAILED;
                goto cleanup;
            }

            opts.httpport = (unsigned short)x;
        }
        else if (strcmp(key, "httpsport") == 0)
        {
            char* end;
            unsigned long x = Strtoul(value, &end, 10);

            if (*end != '\0' || x > USHRT_MAX)
            {
                err(PAL_T("%s(%u): invalid value for '%s': %s"), scs(path), 
                    Conf_Line(conf), scs(key), scs(value));
                miResult = MI_RESULT_FAILED;
                goto cleanup;
            }

            opts.httpsport = (unsigned short)x;
        }
        else if (strcmp(key, "trace") == 0)
        {
            if (Strcasecmp(value, "MI_TRUE") == 0)
            {
                opts.trace = MI_TRUE;
            }
            else if (Strcasecmp(value, "MI_FALSE") == 0)
            {
                opts.trace = MI_FALSE;
            }
            else
            {
                err(PAL_T("%s(%u): invalid value for '%s': %s"), scs(path), 
                    Conf_Line(conf), scs(key), scs(value));
                miResult = MI_RESULT_FAILED;
                goto cleanup;
            }
        }
        else if (strcmp(key, "protocolhandler") == 0)
        {
            /* This is used in the miapi itself */
        }
        if (strcmp(key, "loglevel") == 0)
        {
            if (Log_SetLevelFromString(value) != 0)
            {
                err(PAL_T("%s(%u): invalid value for '%s': %s"), scs(path), 
                    Conf_Line(conf), scs(key), scs(value));
                miResult = MI_RESULT_FAILED;
                goto cleanup;
            }
        }        
        else if (strcmp(key, "logpath") == 0)
        {
            /* TODO - this is just a test tool? */
        }
        else if (strcmp(key, "logfile") == 0)
        {
            /* TODO - this is just a test tool? */
        }
        else if (IsNickname(key))
        {
            if (SetPathFromNickname(key, value) != 0)
            {
                err(PAL_T("SetPathFromNickname() failed"));
                miResult = MI_RESULT_FAILED;
                goto cleanup;
            }
        }
        else
        {
            err(PAL_T("%s(%u): unknown key: %s"), scs(path), Conf_Line(conf),
                scs(key));
            miResult = MI_RESULT_FAILED;
            goto cleanup;
        }
    }

cleanup:
    /* Close configuration file */
    Conf_Close(conf);
    return miResult;
}

static MI_Result GetCommandLineDestDirOption(
    int* argc_,
    const MI_Char* argv[])
{
    int argc = *argc_;
    int i;
    const MI_Char* destdir = NULL;

    for (i = 1; i < argc; )
    {
        if (Tcscmp(argv[i], MI_T("--destdir")) == 0)
        {
            if (i + 1 == argc)
            {
                err(PAL_T("missing argument for --destdir option"));
                return MI_RESULT_INVALID_PARAMETER;
            }

            destdir = argv[i+1];
            memmove((char*)&argv[i], (char*)&argv[i+2], 
                sizeof(char*) * (argc-i-1));
            argc -= 2;
        }
        else if (Tcsncmp(argv[i], MI_T("--destdir="), 10) == 0)
        {
            destdir = argv[i] + 10;
            memmove((char*)&argv[i], (char*)&argv[i+1], 
                sizeof(char*) * (argc-i));

            argc -= 1;
        }
        else
            i++;
    }

    if (destdir)
    {
#if defined(CONFIG_ENABLE_WCHAR)
        char _destdir[PAL_MAX_PATH_SIZE];
        StrWcslcpy(_destdir, destdir, PAL_MAX_PATH_SIZE);
        if (SetPath(ID_DESTDIR, _destdir) != 0)
#else
        if (SetPath(ID_DESTDIR, destdir) != 0)
#endif
        {
            err(PAL_T("failed to set destdir"));
            return MI_RESULT_FAILED;
        }
    }

    *argc_ = argc;

    return MI_RESULT_OK;
}

#define GETOPTSTATE_INITIALIZER { 0, { '\0' }, NULL, { '\0' } }
#define GETOPT_OPT_SIZE 512
#define GETOPT_ERR_SIZE 512

typedef struct _GetOptState
{
    int index;
    MI_Char opt[GETOPT_OPT_SIZE];
    const MI_Char* arg;
    MI_Char err[GETOPT_ERR_SIZE];
}
GetOptState;

static int GetOpt(
    int* argc, 
    const MI_Char* argv[], 
    const MI_Char* opts[],
    GetOptState* state)
{
    int i;
    int j;

    /* Clear state */
    state->opt[0] = '\0';
    state->arg = NULL;
    state->err[0] = '\0';

    for (i = state->index; i < *argc; i++)
    {
        if (argv[i][0] != '-')
        {
            state->index++;
            continue;
        }

        /* Find option argv[i] */
        for (j = 0; opts[j]; j++)
        {
            MI_Char opt[GETOPT_OPT_SIZE];
            size_t n;
            int hasArg;

            /* Copy option name */
            n = Tcslcpy(opt, opts[j], sizeof(opt)/sizeof(opt[0]));

            /* If option name too long */
            if (n >= sizeof(opt))
            {
                Tcslcpy(state->err, MI_T("bad parameter"), sizeof(state->err)/sizeof(state->err[0]));
                return -1;
            }

            /* If option name zero-length */
            if (n == 0)
            {
                Tcslcpy(state->err, MI_T("bad parameter"), sizeof(state->err)/sizeof(state->err[0]));
                return -1;
            }

            /* If option has argument */
    #ifdef _PREFAST_
     #pragma prefast(push)
     #pragma prefast(disable:26014) 
    #endif
            if (opt[n-1] == ':')
            {
                hasArg = 1;
                opt[n-1] = '\0';
            }
            else
                hasArg = 0;
    #ifdef _PREFAST_
     #pragma prefast(pop)
    #endif

            /* Does argv[i] match this option? */
            if (Tcscmp(argv[i], opt) == 0)
            {
                if (hasArg)
                {
                    if (i + 1 == *argc)
                    {
                        Tcslcpy(state->err, MI_T("missing option argument: "), 
                            sizeof(state->err)/sizeof(state->err[0]));
                        Tcslcat(state->err, opt, sizeof(state->err)/sizeof(state->err[0]));
                        return -1;
                    }

                    Tcslcpy(state->opt, argv[i], sizeof(state->opt)/sizeof(state->opt[0]));
                    state->arg =  argv[i+1];
                    memmove((void*)&argv[i], (void*)&argv[i+2],
                        sizeof(char*) * ((*argc) - i - 1));
                    *argc -= 2;
                    return 0;
                }
                else
                {
                    Tcslcpy(state->opt, argv[i], sizeof(state->opt)/sizeof(state->opt[0]));
                    memmove((void*)&argv[i], (void*)&argv[i+1], 
                        sizeof(char*) * ((*argc) - i));
                    *argc -= 1;
                    return 0;
                }
            }
            else if (hasArg && 
                Tcsncmp(argv[i], opt, n-1) == 0 && argv[i][n-1] == '=')
            {
                Tcslcpy(state->opt, argv[i], sizeof(state->opt)/sizeof(state->opt[0]));
                state->opt[n-1] = '\0';
                state->arg =  &argv[i][n];
                memmove((void*)&argv[i], (void*)&argv[i+1], 
                    sizeof(char*) * ((*argc) - i));
                *argc -= 1;
                return 0;
            }
        }

        /* Unknown option */
        Tcslcpy(state->err, MI_T("unknown option: "), sizeof(state->err)/sizeof(state->err[0]));
        Tcslcat(state->err, argv[i], sizeof(state->err)/sizeof(state->err[0]));
        return -1;
    }

    /* Done */
    return 1;
}
static MI_Result GetCommandLineOptions(
    int* argc,
    const MI_Char* argv[])
{
    GetOptState state = GETOPTSTATE_INITIALIZER;
    const MI_Char* supportedOptions[] =
    {
        MI_T("-h"),
        MI_T("-q"),
        MI_T("-t"),
        MI_T("-s"),
        MI_T("-shallow"),
        MI_T("-synchronous"),
        MI_T("-n"),
        MI_T("-R:"),
        MI_T("-ac:"),
        MI_T("-rc:"),
        MI_T("-r:"),
        MI_T("-rr:"),
        MI_T("-rc:"),
        MI_T("-u:"),
        MI_T("-p:"),
        MI_T("-S"),
        MI_T("--summary"),
        MI_T("--prefix:"),
        MI_T("--libdir:"),
        MI_T("--bindir:"),
        MI_T("--localstatedir:"),
        MI_T("--sysconfdir:"),
        MI_T("--providerdir:"),
        MI_T("--certsdir:"),
        MI_T("--rundir:"),
        MI_T("--logdir:"),
        MI_T("--pidfile:"),
        MI_T("--logfile:"),
        MI_T("--registerdir:"),
        MI_T("--socketfile:"),
        MI_T("--pemfile:"),
        MI_T("--keyfile:"),
        MI_T("--agentprogram:"),
        MI_T("--serverprogram:"),
        MI_T("--stdout:"),
        MI_T("--stderr:"),
        MI_T("--querylang:"),
        MI_T("--queryexpr:"),
        NULL,
    };

    for (;;)
    {
        int r = GetOpt(argc, argv, supportedOptions, &state);

        if (r == 1)
            break;

        if (r == -1)
        {
            Ftprintf(serr, PAL_T("error: %T\n"), tcs(state.err));
            Ftprintf(serr, PAL_T("Try -h for help\n"));
            return MI_RESULT_INVALID_PARAMETER;
        }

        if (Tcscmp(state.opt, PAL_T("-h")) == 0)
        {
            opts.help = MI_TRUE;
        }
        else if (Tcscmp(state.opt,  PAL_T("-q")) == 0)
        {
            opts.quiet = MI_TRUE;
        }
        else if (Tcscmp(state.opt,  PAL_T("-t")) == 0)
        {
            opts.trace = MI_TRUE;
        }
        else if (Tcscmp(state.opt,  PAL_T("-s")) == 0)
        {
            opts.suppressResults = MI_TRUE;
        }
        else if (Tcscmp(state.opt,  PAL_T("-shallow")) == 0)
        {
            opts.shallow = MI_TRUE;
        }
        else if (Tcscmp(state.opt,  PAL_T("-synchronous")) == 0)
        {
            opts.synchronous = MI_TRUE;
        }
        else if (Tcscmp(state.opt,  PAL_T("-n")) == 0)
        {
            opts.nulls = MI_TRUE;
        }
        else if (Tcscmp(state.opt,  PAL_T("-R")) == 0)
        {
            MI_Char *end;
            opts.repeat = Tcstol(state.arg, &end, 10);

            if (opts.repeat <= 0)
            {
                err(PAL_T("bad value for -R: %T"), tcs(state.arg));
                return MI_RESULT_INVALID_PARAMETER;
            }
        }
        else if (Tcscmp(state.opt,  PAL_T("-ac")) == 0)
        {
            opts.assocClass = state.arg;
        }
        else if (Tcscmp(state.opt,  PAL_T("-rc")) == 0)
        {
            opts.resultClass = state.arg;
        }
        else if (Tcscmp(state.opt,  PAL_T("-r")) == 0)
        {
            opts.role = state.arg;
        }
        else if (Tcscmp(state.opt,  PAL_T("-rr")) == 0)
        {
            opts.resultRole = state.arg;
        }
        else if (Tcscmp(state.opt,  PAL_T("-u")) == 0)
        {
            opts.user = state.arg;
        }
        else if (Tcscmp(state.opt,  PAL_T("-p")) == 0)
        {
            opts.password = state.arg;
        }
        else if (Tcscmp(state.opt,  PAL_T("--stdout")) == 0)
        {
            FILE* os;
#if defined(_MSC_VER)
            FILE* fp;
            os = (_wfopen_s(&fp, state.arg, PAL_T("wb")) == 0 ? fp : NULL);
#else
            {
#if defined(CONFIG_ENABLE_WCHAR)
                char tmp[50];
                StrWcslcpy(tmp, state.arg, sizeof(tmp));
                os = File_Open(tmp, "wb");
#else
                os = File_Open(state.arg, "wb");
#endif
            }
#endif

            if (!os)
                err(PAL_T("failed to open: %T"), tcs(state.arg));

            sout = os;
        }
        else if (Tcscmp(state.opt, PAL_T("--stderr")) == 0)
        {
            FILE* os;
#if defined(_MSC_VER)
            FILE* fp;
            os = (_wfopen_s(&fp, state.arg, PAL_T("wb")) == 0 ? fp : NULL);
#else
            {
#if defined(CONFIG_ENABLE_WCHAR)
                char tmp[50];
                StrWcslcpy(tmp, state.arg, sizeof(tmp));
                os = File_Open(tmp, "wb");
#else
                os = File_Open(state.arg, "wb");
#endif
            }
#endif

            if (!os)
                err(PAL_T("failed to open: %T"), tcs(state.arg));

            serr = os;
        }
        else if (Tcscmp(state.opt, PAL_T("--querylang")) == 0)
        {
            opts.querylang = state.arg;
        }
        else if (Tcscmp(state.opt, PAL_T("--queryexpr")) == 0)
        {
            opts.queryexpr = state.arg;
        }
        else if (Tcscmp(state.opt, PAL_T("--summary")) == 0 ||
                 Tcscmp(state.opt, PAL_T("-S")) == 0)
        {
            opts.summary = MI_TRUE;
        }
#if 0
        else if (Tcsncmp(state.opt, PAL_T("--"), 2) == 0 && IsNickname(state.opt+2))
        {
            if (SetPathFromNickname(state.opt+2, state.arg) != 0)
                err(PAL_T("SetPathFromNickname() failed"));
        }
#endif
    }

    return MI_RESULT_OK;
}

const MI_Char USAGE[] = MI_T("\
Usage: %T [OPTIONS] COMMAND ...\n\
\n\
This tool sends requests to the CIM server.\n\
\n\
OPTIONS:\n\
    -h                  Print this help message.\n\
    -q                  Operate quietly.\n\
    -t                  Enable diagnostic tracing.\n\
    -R N                Repeat command N times.\n\
    -shallow            Use shallow inheritance (see 'ei' command).\n\
    -synchronous        Executes command in synchronous mode.\n\
    -ac CLASSNAME       Association class (see 'a' and 'r' commands).\n\
    -rc CLASSNAME       Result class (see 'a' command).\n\
    -r ROLE             Role (see 'a' and 'r' commands).\n\
    -rr ROLE            Result role (see 'a' command).\n\
    -n                  Show null properties.\n\
    -u USERNAME         Username.\n\
    -p PASSWORD         User's password.\n\
    -id                 Send identify request.\n\
    --socketfile PATH   Talk to the server server whose socket file resides\n\
                        at the location given by the path argument.\n\
    --httpport          Connect on this port instead of default.\n\
    --httpsport         Connect on this secure port instead of default.\n\
    --querylang         Query language (for 'ei', 'sub' command).\n\
    --queryexpr         Query expression (for 'ei', 'sub' command).\n\
\n\
COMMANDS:\n\
    noop\n\
        Perform a no-op operation.\n\
    gi NAMESPACE INSTANCENAME\n\
        Peform a CIM [g]et [i]nstance operation.\n\
    ci NAMESPACE NEWINSTANCE\n\
        Peform a CIM [c]reate [i]nstance operation.\n\
    mi NAMESPACE MODIFIEDINSTANCE\n\
        Peform a CIM [m]odify [i]nstance operation.\n\
    di NAMESPACE INSTANCENAME\n\
        Peform a CIM [d]elete [i]nstance operation.\n\
    ei [-shallow] NAMESPACE CLASSNAME\n\
        Peform a CIM [e]numerate [i]nstances operation.\n\
    iv NAMESPACE INSTANCENAME METHODNAME PARAMETERS\n\
        Peform a CIM extrinisic method [i]nvocation operation.\n\
    a [-ac -rc -r -rr ] NAMESPACE INSTANCENAME\n\
        Perform a CIM [a]ssociator instances operation.\n\
    r [-ac -r] NAMESPACE INSTANCENAME (references)\n\
        Perform a CIM [r]eference instances operation.\n\
    gc NAMESPACE CLASSENAME\n\
        Peform a CIM [g]et [c]lass operation.\n\
    enc INSTANCE\n\
        Attempt to encode and print the given instance representation.\n\
    wql NAMESPACE WQLQUERY\n\
        Peform a WQL query operation.\n\
    cql NAMESPACE CQLQUERY\n\
        Peform a CQL query operation.\n\
    sub NAMESPACE\n\
        Peform a subscribe to indication operation.\n\
\n\
INSTANCENAME and PARAMETERS format:\n\
    { class_name property_name property_value property_name property_value }\n\
        property_value is either a string value, or can be an INSTANCENAME.\n\
        property_value can also be an array taking the form [ property_value property_value ].\n\
\n");

/*
 * Signal handler that catch SIGINT signal, the signal
 * is triggered by CTRL+C from console; In case of
 * SIGINT signal, need to cancel the active operation
 * and exit
 *
 */
void MI_MAIN_CALL SignalHandler(int signo)
{
    err(PAL_T("Quit program upon receiving ctrl+c"), signo);
    if (gop.ft)
    {
        if (s_finished == 0)
        {
            s_finished = 1;
            CondLock_Broadcast((ptrdiff_t)(&s_finished));
        }

        Ftprintf(sout, MI_T("Cancel the operation"));
        MI_Operation_Cancel(&gop, MI_REASON_SHUTDOWN);
        /* Close opeartion will be hung due to */
        /* the operation is not get final result yet */
        /* need to enable this code after end to end cancel was completed */
        /* MI_Operation_Close(&gop); */
        /* Ftprintf(sout, MI_T("Closed the operation")); */
        Sleep_Milliseconds(200);
    }
    exit(1);
}

/*
 * Set up signal handler to catch SIGINT signal
 *
 */
void CatchCtrlC()
{
    if (signal(SIGINT, SignalHandler) == SIG_ERR)
        err(PAL_T("cannot catch signal: SIGINT\n"));
}

MI_Result climain(int argc, const MI_Char* argv[])
{
    MI_Application miApplication = MI_APPLICATION_NULL;
    MI_Session miSession = MI_SESSION_NULL;
    MI_Result miResult;
    MI_DestinationOptions _miDestinationOptions = MI_DESTINATIONOPTIONS_NULL;
    MI_DestinationOptions *miDestinationOptions = NULL;
    MI_UserCredentials miUserCredentials = {0};

    /*Log_OpenStdErr();
    Log_SetLevel(LOG_VERBOSE);*/
    CatchCtrlC();

    // Setup default stderr and stdout streams:
    serr = stderr;
    sout = stdout;

    arg0 = argv[0];

    // const MI_Uint64 CONNECT_TIMEOUT_USEC = 10 * 1000 * 1000;

    // Get the options:
    miResult = GetCommandLineDestDirOption(&argc, argv);
    if (miResult != MI_RESULT_OK)
    {
        return miResult;
    }

    // Get configuration file options:
    miResult = GetConfigFileOptions();
    if (miResult != MI_RESULT_OK)
    {
        return miResult;
    }

    // Get the options:
    miResult = GetCommandLineOptions(&argc, argv);
    if (miResult != MI_RESULT_OK)
    {
        return miResult;
    }
    // There must be at least 1 argument left:
    if (argc < 2)
    {
        if (argc >= 1)
        {
            Ftprintf(sout, USAGE, tcs(argv[0]));
            if (opts.help)
                miResult = MI_RESULT_OK;
            else
                miResult = MI_RESULT_INVALID_PARAMETER;
        }
        else
        {
            Ftprintf(sout, USAGE, tcs(MI_T("omicli")));
            miResult = MI_RESULT_INVALID_PARAMETER;
        }
        return miResult;
    }

    if (Tcscmp(argv[1], MI_T("enc")) != 0)
    {
        miResult = MI_Application_Initialize(0, NULL, NULL, &miApplication);
        if (miResult != MI_RESULT_OK)
            return miResult;
        if (opts.user)
        {
            miDestinationOptions = &_miDestinationOptions;
            miResult = MI_Application_NewDestinationOptions(&miApplication, miDestinationOptions);
            if (miResult != MI_RESULT_OK)
                goto CleanupApplication;

            miUserCredentials.authenticationType = MI_AUTH_TYPE_BASIC;
            miUserCredentials.credentials.usernamePassword.domain = MI_T("localhost");
            miUserCredentials.credentials.usernamePassword.username = opts.user;
            miUserCredentials.credentials.usernamePassword.password = opts.password;

            miResult = MI_DestinationOptions_AddDestinationCredentials(miDestinationOptions, &miUserCredentials);
            if (miResult != MI_RESULT_OK)
                goto CleanupApplication;
        }

        miResult = MI_Application_NewSession(&miApplication, NULL, NULL, miDestinationOptions, NULL, NULL, &miSession);
        if (miResult != MI_RESULT_OK)
            goto CleanupApplication;

        // Remember start time (will calculate total time in PrintSummary()
        s_startTime = CPU_GetTimeStamp();
    }

    if (Tcscmp(argv[1], MI_T("ei")) == 0)
    {
        int i;
        for (i = 0; i < opts.repeat; i++)
        {
            if (opts.queryexpr)
            {
                miResult = QueryInstances(&miSession, argc, argv);
                if (miResult != MI_RESULT_OK)
                    goto CleanupSession;
            }
            else
            {
                miResult = EnumerateInstances(&miSession, argc, argv);
                if (miResult != MI_RESULT_OK)
                    goto CleanupSession;
            }
        }
    }
    else if (Tcscmp(argv[1], MI_T("id")) == 0)
    {
        const MI_Char* args[5];
        int i;

        if (argc != 2)
        {
            Ftprintf(serr, PAL_T("Usage: %T id\n\n"), tcs(arg0));
            miResult = MI_RESULT_INVALID_PARAMETER;
            goto CleanupSession;
        }

        args[0]= argv[0];
        args[1]= MI_T("ei");
        args[2]= MI_T("root/omi");
        args[3]= MI_T("OMI_Identify");
        args[4]= NULL;

        for (i = 0; i < opts.repeat; i++)
        {
            miResult = EnumerateInstances(&miSession, 4, args);
            if (miResult != MI_RESULT_OK)
                goto CleanupSession;
        }
    }
    else if (Tcscmp(argv[1], MI_T("wql")) == 0 ||
             Tcscmp(argv[1], MI_T("cql")) == 0)
    {
        int i;
        for (i = 0; i < opts.repeat; i++)
        {
            miResult = Query(&miSession, argc, argv);
            if (miResult != MI_RESULT_OK)
                goto CleanupSession;
        }
    }
    else if (Tcscmp(argv[1], MI_T("noop")) == 0)
    {
        int i;
        for (i = 0; i < opts.repeat; i++)
        {
            miResult = NoOp(&miSession, argc, argv);
            if (miResult != MI_RESULT_OK)
                goto CleanupSession;
        }
    }
    else if (Tcscmp(argv[1], MI_T("enc")) == 0)
    {
        miResult = Encode(argc, argv);
        goto CleanupApplication;
    }
    else if (Tcscmp(argv[1], MI_T("gi")) == 0)
    {
        int i;
        for (i = 0; i < opts.repeat; i++)
        {
            miResult = GetInstance(&miSession, argc, argv);
            if (miResult != MI_RESULT_OK)
                goto CleanupSession;
        }
    }
    else if (Tcscmp(argv[1], MI_T("ci")) == 0)
    {
        int i;
        for (i = 0; i < opts.repeat; i++)
        {
            miResult = CreateInstance(&miSession, argc, argv);
            if (miResult != MI_RESULT_OK)
                goto CleanupSession;
        }
    }
    else if (Tcscmp(argv[1], MI_T("mi")) == 0)
    {
        int i;
        for (i = 0; i < opts.repeat; i++)
        {
            miResult = ModifyInstance(&miSession, argc, argv);
            if (miResult != MI_RESULT_OK)
                goto CleanupSession;
        }
    }
    else if (Tcscmp(argv[1], MI_T("di")) == 0)
    {
        int i;
        for (i = 0; i < opts.repeat; i++)
        {
            miResult = DeleteInstance(&miSession, argc, argv);
            if (miResult != MI_RESULT_OK)
                goto CleanupSession;
        }
    }
    else if (Tcscmp(argv[1], MI_T("iv")) == 0)
    {
        int i;
        for (i = 0; i < opts.repeat; i++)
        {
            miResult = Invoke(&miSession, argc, argv);
            if (miResult != MI_RESULT_OK)
                goto CleanupSession;
        }
    }
    else if (Tcscmp(argv[1], MI_T("a")) == 0)
    {
        int i;
        for (i = 0; i < opts.repeat; i++)
        {
            miResult = Associators(&miSession, argc, argv);
            if (miResult != MI_RESULT_OK)
                goto CleanupSession;
        }
    }
    else if (Tcscmp(argv[1], MI_T("r")) == 0)
    {
        int i;
        for (i = 0; i < opts.repeat; i++)
        {
            miResult = References(&miSession, argc, argv);
            if (miResult != MI_RESULT_OK)
                goto CleanupSession;
        }
    }
    else if (Tcscmp(argv[1], MI_T("gc")) == 0)
    {
        int i;
        for (i = 0; i < opts.repeat; i++)
        {
            miResult = GetClass(&miSession, argc, argv);
            if (miResult != MI_RESULT_OK)
                goto CleanupSession;
        }
    }
    else if (Tcscmp(argv[1], MI_T("sub")) == 0)
    {
        int i;
        for (i = 0; i < opts.repeat; i++)
        {
            miResult = Subscribe(&miSession, argc, argv);
            if (miResult != MI_RESULT_OK)
                goto CleanupSession;
        }
    }
    else
    {
        err(PAL_T("unknown command: %T"), tcs(argv[1]));
        miResult = MI_RESULT_INVALID_PARAMETER;
        goto CleanupSession;
    }

    if (opts.summary)
        PrintSummary();

CleanupSession:
    MI_Session_Close(&miSession, NULL, NULL);

CleanupApplication:
    if (miDestinationOptions)
        MI_DestinationOptions_Delete(miDestinationOptions);

    MI_Application_Close(&miApplication);

    if (sout != stdout)
        fclose(sout);

    if (serr != stdout)
        fclose(serr);

    return miResult;
}

ViewCVS 0.9.2