int main(int argc, char** argv)
{
    FILE* outputFile;
    GLSLShader result;
    GLLang language = LANG_DEFAULT;
	int returnValue = 0;//EXIT_SUCCESS
    Timer_t timer;
    int compiledOK = 0;
    double crossCompileTime = 0;
    double glslCompileTime = 0;

    printf("args: bytecode-file [output-file] [language override - es100 es300 120 130 etc.]\n");

    if(argc < 2 || !fileExists(argv[1]))
    {
        printf("Bad args. Supply a valid shader path, optionaly followed by the output path\n");
        return 1;//EXIT_FAILURE
    }

    if(argc > 3)
    {
        language = LanguageFromString(argv[3]);
    }

    InitTimer(&timer);

    ResetTimer(&timer);
    compiledOK = TranslateHLSLFromFile(argv[1], 0, language, NULL, &result);
    crossCompileTime = ReadTimer(&timer);

    if(compiledOK)
    {
        printf("cc time: %.2f us\n", crossCompileTime);

        if(argc > 2)
        {
            //Dump to file
            outputFile = fopen(argv[2], "w");
            fprintf(outputFile, result.sourceCode);
            fclose(outputFile);
        }

#if defined(VALIDATE_OUTPUT)
        compiledOK = TryCompileShader(result.shaderType, (argc > 2) ? argv[2] : "", result.sourceCode, &glslCompileTime);
        
        if(!compiledOK)
		{
			returnValue = 1;//EXIT_FAILURE
		}
        else
        {
            printf("glsl time: %.2f us\n", glslCompileTime);
        }
#endif

        bcstrfree(result.sourceCode);
    }

	return returnValue;
}
int GetOptions(int argc, char** argv, Options* psOptions)
{
	int i;
    int fullShaderChain = -1;
    int hashOut = 0;

	InitOptions(psOptions);

	for(i=1; i<argc; i++)
	{
		char *option;

		option = strstr(argv[i],"-help");
		if(option != NULL) 
		{
            PrintHelp();
            return 0;
		}

		option = strstr(argv[i],"-reflect=");
		if(option != NULL) 
        {
			psOptions->reflectPath = option + strlen("-reflect=");
		}

		option = strstr(argv[i],"-lang=");
		if(option != NULL)
		{
            psOptions->language = LanguageFromString((&option[strlen("-lang=")]));
		}

		option = strstr(argv[i],"-flags=");
		if(option != NULL)
		{
			psOptions->flags = atol(&option[strlen("-flags=")]);
		}

		option = strstr(argv[i],"-in=");
		if(option != NULL) 
        {
            fullShaderChain = 0;
			psOptions->shaderFile = option + strlen("-in=");
            if(!fileExists(psOptions->shaderFile))
            {
                printf("Invalid path: %s\n", psOptions->shaderFile);
                return 0;
            }
		}

		option = strstr(argv[i],"-out=");
		if(option != NULL) 
        {
            fullShaderChain = 0;
			psOptions->outputShaderFile = option + strlen("-out=");
		}

		option = strstr(argv[i],"-hashout");
		if(option != NULL) 
        {
            fullShaderChain = 0;
			psOptions->outputShaderFile = option + strlen("-hashout=");

            char* dir;
            int64_t length;

            uint64_t hash = hash64((const uint8_t*)psOptions->outputShaderFile, (uint32_t)strlen(psOptions->outputShaderFile), 0);

            uint32_t high = (uint32_t)( hash >> 32 );
            uint32_t low = (uint32_t)( hash & 0x00000000FFFFFFFF );

            dir = strrchr(psOptions->outputShaderFile, '\\');

            if(!dir)
            {
                dir = strrchr(psOptions->outputShaderFile, '//');
            }

            if(!dir)
            {
                length = 0;
            }
            else
            {
                length = (dir-psOptions->outputShaderFile) + 1;
            }

            for(i=0; i< length;++i)
            {
                psOptions->cacheKey[i] = psOptions->outputShaderFile[i];
            }

            //sprintf(psOptions->cacheKey, "%x%x", high, low);
            sprintf(&psOptions->cacheKey[i], "%010llX", hash);

            psOptions->outputShaderFile = psOptions->cacheKey;
        }

        //Semicolon-separated list of shader files to compile
        //Any dependencies between these shaders will be handled
        //so that they can be linked together into a monolithic program.
        //If using separate_shader_objects with GLSL 430 or later then -linkin
        //is only needed for hull and domain tessellation shaders - not doing
        //so risks incorrect layout qualifiers in domain shaders.
		option = strstr(argv[i],"-linkin=");
		if(option != NULL) 
        {
            const char* cter;
            int shaderIndex = 0;
            int writeIndex = 0;
            
			cter = option + strlen("-linkin=");

            while(cter[0] != '\0')
            {
                if(cter[0] == ';')
                {
                    psOptions->linkIn[shaderIndex][writeIndex] = '\0';
                    shaderIndex++;
                    writeIndex = 0;
                    cter++;
                }

                if(shaderIndex < 5 && writeIndex < MAX_PATH_CHARS)
                {
                    psOptions->linkIn[shaderIndex][writeIndex++] = cter[0];
                }

                cter++;
            }

            psOptions->linkIn[shaderIndex][writeIndex] = '\0';

            psOptions->numLinkShaders = shaderIndex+1;

            fullShaderChain = 1;
        }

		option = strstr(argv[i],"-linkout=");
		if(option != NULL) 
        {
            const char* cter;
            int shaderIndex = 0;
            int writeIndex = 0;
            
            cter = option + strlen("-linkout=");

            while(cter[0] != '\0')
            {
                if(cter[0] == ';')
                {
                    psOptions->linkOut[shaderIndex][writeIndex] = '\0';
                    shaderIndex++;
                    writeIndex = 0;
                    cter++;
                }

                if(shaderIndex < 5 && writeIndex < MAX_PATH_CHARS)
                {
                    psOptions->linkOut[shaderIndex][writeIndex++] = cter[0];
                }

                cter++;
            }

            psOptions->linkOut[shaderIndex][writeIndex] = '\0';
		}

		option = strstr(argv[i],"-hashlinkout=");
		if(option != NULL) 
        {
            const char* cter;
            const char* fullList;
            int shaderIndex = 0;
            int writeIndex = 0;

            char files[5][MAX_PATH_CHARS];

            fullList = option + strlen("-hashlinkout=");
            cter = fullList;

            while(cter[0] != '\0')
            {
                if(cter[0] == ';')
                {
                    files[shaderIndex][writeIndex] = '\0';
                    shaderIndex++;
                    writeIndex = 0;
                    cter++;
                }

                if(shaderIndex < 5 && writeIndex < MAX_PATH_CHARS)
                {
                    files[shaderIndex][writeIndex++] = cter[0];
                }

                cter++;
            }

            files[shaderIndex][writeIndex] = '\0';


            uint64_t hash = hash64((const uint8_t*)fullList, (uint32_t)strlen(fullList), 0);

            uint32_t high = (uint32_t)( hash >> 32 );
            uint32_t low = (uint32_t)( hash & 0x00000000FFFFFFFF );

            for(int i=0; i < shaderIndex+1; ++i)
            {
                char dir[MAX_PATH_CHARS];
                char fullDir[MAX_PATH_CHARS]; //includes hash

                char* separatorPtr = strrchr(&files[i][0], '\\');

                if(!separatorPtr)
                {
                    separatorPtr = strrchr(&files[i][0], '//');
                }

                char* file = separatorPtr + 1;

                size_t k = 0;
                const size_t  dirChars = (size_t)(separatorPtr-&files[i][0]);
                for(; k < dirChars; ++k)
                {
                    dir[k] = files[i][k];
                }
                
                dir[k] = '\0';

                sprintf(&fullDir[0], "%s//%010llX", dir, hash);

#if defined(_WIN32)
                _mkdir(fullDir);
#else 
                mkdir(fullDir, 0777);
#endif

                //outdir/hash/fileA...fileB
                sprintf(&psOptions->linkOut[i][0], "%s//%s", fullDir, file);
            }
		}
    }