int
main(
    int argc,
    char * argv[]
    )
{
    gctBOOL         dumpLog      = gcvFALSE;
    gctSTRING       fileName[2]  = { gcvNULL, gcvNULL };
    gcSHADER        shaders[2]   = { gcvNULL, gcvNULL };
    gctINT          i;
    gcoOS           os           = gcvNULL;
    gcoHAL          hal          = gcvNULL;
    gceSTATUS       result;
    gctUINT         option       = 1;   /* no optimization */
    char            outFile[128] = { '\0' };
    char            logVSFile[128] = { '\0' };
    char            logFSFile[128] = { '\0' };

    printf("vCompile version 0.8, Copyright (c) 2005-2011, Vivante Corporation\n\n");

#ifdef _WIN32
    _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) /*| _CRTDBG_CHECK_ALWAYS_DF*/ | _CRTDBG_DELAY_FREE_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
    _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
    _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
    /* _CrtSetBreakAlloc(79); */
#endif

#if gcdDEBUG
    gcoOS_SetDebugLevel(gcvLEVEL_VERBOSE);
    gcoOS_SetDebugZone(gcvZONE_COMPILER);
#endif

    for (i = 1; i < argc; i++)
    {
        if (gcmIS_SUCCESS(gcoOS_StrCmp(argv[i], "-l")))
        {
            dumpLog = gcvTRUE;
        }
        else if (gcmIS_SUCCESS(gcoOS_StrCmp(argv[i], "-O0")))
        {
            /* Currently, optimization level is either FULL or NONE */
            option = 0;     /* no optimization */
        }
        else if (gcmIS_SUCCESS(gcoOS_StrCmp(argv[i], "-O")))
        {
            option = 1;     /* full optimization */
        }
        else if (gcmIS_SUCCESS(gcoOS_StrCmp(argv[i], "-OT")))
        {
            /* For optimization unit test */
            if (i++ == argc)
            {
                printf("*ERROR* Optimization testing pattern not provided.\n");
                return 1;
            }
            else
            {
                gctINT testPattern;

                gcmVERIFY_OK(gcoOS_StrToInt(argv[i], (gctINT *)&testPattern));
                if (testPattern < 0)
                {
                    printf("*ERROR* Unknown optimization testing pattern.\n");
                    return 1;
                }
                option = testPattern;
            }
        }
        else
        {
            if (fileName[0] == gcvNULL) fileName[0] = argv[i];
            else if (fileName[1] == gcvNULL) fileName[1] = argv[i];
            else
            {
                printf("*ERROR* Too many shaders.\n");
                return 1;
            }
        }
    }

    if (fileName[0] == gcvNULL)
    {
        printf("Usage: %s [-l] [-O0] shaderFileName [shaderFileName]\n", argv[0]);
        printf("  -l   Generate log file.\n"
               "  -O0  Disable optimizations.\n"
               "\n"
               "If only one shader is specified, that shader will be compiled into a .gcSL\n"
               "file.  If two shaders are specified, those shaders will be compiled and\n"
               "linked into a .gcPGM file. With two shaders, the vertex shader file needs\n"
               "to be the first.\n");
        return 0;
    }

    result = gcoOS_Construct(gcvNULL, &os);
    if (result != gcvSTATUS_OK)
    {
        printf("*ERROR* Failed to construct a new gcoOS object\n");
        return 1;
    }

    result = gcoHAL_Construct(gcvNULL, os, &hal);
    if (result != gcvSTATUS_OK)
    {
        printf("*ERROR* Failed to construct a new gcoHAL object\n");
        goto ErrorExit;
    }

    /* Dump compile log only when one shader is present */
    shaders[0] = CompileFile(os, fileName[0], hal, option, dumpLog && (fileName[1] == gcvNULL), fileName[1] == gcvNULL );

    if (shaders[0] == gcvNULL)
    {
        goto ErrorExit;
    }

    if (fileName[1] != gcvNULL)
    {
        gctSIZE_T programBufferSize = 0;
        gctPOINTER programBuffer = gcvNULL;
        gcsHINT_PTR hints = gcvNULL;
        gceSTATUS status;
        gctPOINTER binary = gcvNULL;
        gctSIZE_T binarySize = 0;
        FILE * f;
        gctSTRING p;

        gcoOS_StrCopySafe(outFile, gcmSIZEOF(outFile), fileName[0]);
        p = strrchr(outFile, '.');
        gcoOS_StrCopySafe(p, gcmSIZEOF(outFile) - (p - outFile), ".gcPGM");

        gcoOS_StrCopySafe(logVSFile, gcmSIZEOF(logVSFile), fileName[0]);
        gcoOS_StrCatSafe(logVSFile, gcmSIZEOF(logVSFile), ".log");

        gcoOS_StrCopySafe(logFSFile, gcmSIZEOF(logFSFile), fileName[1]);
        gcoOS_StrCatSafe(logFSFile, gcmSIZEOF(logFSFile), ".log");

        shaders[1] = CompileFile(os, fileName[1], hal, option, gcvFALSE, gcvFALSE);
        if (shaders[1] == gcvNULL)
        {
            goto ErrorExit;
        }

        if ( dumpLog)
        {
            gcoOS_SetDebugShaderFiles(logVSFile, logFSFile);
        }
        status = gcLinkShaders(shaders[0],
                               shaders[1],
                               gcvSHADER_DEAD_CODE
                               | gcvSHADER_RESOURCE_USAGE
                               | gcvSHADER_OPTIMIZER
                               | gcvSHADER_USE_GL_Z
                               | gcvSHADER_USE_GL_POSITION
                               | gcvSHADER_USE_GL_FACE,
                               &programBufferSize,
                               &programBuffer,
                               &hints);
        if ( dumpLog)
        {
            gcoOS_SetDebugShaderFiles(gcvNULL, gcvNULL);
        }

        if (gcmIS_ERROR(status))
        {
            printf("*ERROR* gcLinkShaders returned errror %d\n", status);
        }
        else
        {
            int ret;
            status = gcSaveProgram(shaders[0],
                                   shaders[1],
                                   programBufferSize,
                                   programBuffer,
                                   hints,
                                   &binary,
                                   &binarySize);

            if (gcmIS_ERROR(status))
            {
                printf("*ERROR* gcSaveShaders returned errror %d\n", status);
            }

            f = fopen(outFile, "wb");
            ret = fwrite(binary, binarySize, 1, f);
            if (ret);
            fclose(f);
        }

        if (programBuffer != gcvNULL) gcoOS_Free(os, programBuffer);
        if (hints         != gcvNULL) gcoOS_Free(os, hints);
        if (binary        != gcvNULL) gcoOS_Free(os, binary);
    }

    gcSHADER_Destroy(shaders[0]);
    if (shaders[1] != gcvNULL) gcSHADER_Destroy(shaders[1]);
    gcoHAL_Destroy(hal);
    gcoOS_Destroy(os);
    return 0;

ErrorExit:
    if (shaders[0] != gcvNULL) gcSHADER_Destroy(shaders[0]);
    if (shaders[1] != gcvNULL) gcSHADER_Destroy(shaders[1]);
    if (gcvNULL != hal) gcoHAL_Destroy(hal);
    if (gcvNULL != os) gcoOS_Destroy(os);

    return 1;
}
/**
 *
 * @param driver - driver object to be destroyed
 * @return  - status of the destriuction
 */
static gctBOOL DestroyDriver
(
        IN Viv2DDriverPtr driver
        ) {
    gceSTATUS status = gcvSTATUS_OK;
    gcmASSERT(driver != gcvNULL);
    TRACE_ENTER();
    /*Committing what is left*/
    gcoHAL_Commit(driver->mHal, gcvTRUE);


    /*Unmapping the memory*/
    if (driver->g_Internal != gcvNULL) {
        /* Unmap the local internal memory. */
        status = gcoHAL_UnmapMemory(driver->mHal,
                driver->g_InternalPhysical,
                driver->g_InternalSize,
                driver->g_Internal
                );
        if (status < 0) {
            TRACE_ERROR("gcoHAL_UnMapMemory failed, status = %d\n", status);
            TRACE_EXIT(gcvFALSE);
        }
    }

    if (driver->g_External != gcvNULL) {
        /* Unmap the local external memory. */
        status = gcoHAL_UnmapMemory(driver->mHal,
                driver->g_ExternalPhysical,
                driver->g_ExternalSize,
                driver->g_External
                );
        if (status < 0) {
            TRACE_ERROR("gcoHAL_UnMapMemory failed, status = %d\n", status);
            TRACE_EXIT(gcvFALSE);
        }
    }
    if (driver->g_Contiguous != gcvNULL) {
        /* Unmap the contiguous memory. */
        status = gcoHAL_UnmapMemory(driver->mHal,
                driver->g_ContiguousPhysical,
                driver->g_ContiguousSize,
                driver->g_Contiguous
                );

        if (status < 0) {
            TRACE_ERROR("gcoHAL_UnMapMemory failed, status = %d\n", status);
            TRACE_EXIT(gcvFALSE);
        }
    }


    /* Shutdown */
    if (driver->mHal != gcvNULL) {
        status = gcoHAL_Destroy(driver->mHal);
        if (status != gcvSTATUS_OK) {
            TRACE_ERROR("Unable to destroy HAL object, status = %d\n", status);
            TRACE_EXIT(gcvFALSE);
        }
        driver->mHal = gcvNULL;
    }

    /*Os Destroy*/
    if (driver->mOs != gcvNULL) {
        status = gcoOS_Destroy(driver->mOs);
        if (status != gcvSTATUS_OK) {
            TRACE_ERROR("Unable to destroy Os object, status = %d\n", status);
            TRACE_EXIT(gcvFALSE);
        }
        driver->mOs = gcvNULL;
    }
    status = gcoOS_Free(gcvNULL, driver);
    if (status != gcvSTATUS_OK) {
        TRACE_ERROR("Unable to free driver structure, status = %d\n", status);
        TRACE_EXIT(gcvFALSE);
    }
    driver = gcvNULL;
    TRACE_EXIT(gcvTRUE);
}