Add optional configuration file for specifying (existing) limits.  Details explained by usage statement.  More limits to be added in the future.


git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@23105 e7fa87d3-cd2b-0410-9028-fcbf551c1848
diff --git a/StandAlone/StandAlone.cpp b/StandAlone/StandAlone.cpp
index 8203ad5..bd04bea 100644
--- a/StandAlone/StandAlone.cpp
+++ b/StandAlone/StandAlone.cpp
@@ -33,6 +33,10 @@
 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 //POSSIBILITY OF SUCH DAMAGE.
 //
+
+// this only applies to the standalone wrapper, not the front end in general
+#define _CRT_SECURE_NO_WARNINGS
+
 #include "Worklist.h"
 #include "./../glslang/Include/ShHandle.h"
 #include "./../glslang/Public/ShaderLang.h"
@@ -56,6 +60,7 @@
     EOptionGiveWarnings       = 0x010,
     EOptionsLinkProgram       = 0x020,
     EOptionMultiThreaded      = 0x040,
+    EOptionDumpConfig         = 0x080,
 };
 
 //
@@ -85,39 +90,122 @@
 ShBindingTable FixedAttributeTable = { 3, FixedAttributeBindings };
 
 EShLanguage FindLanguage(const std::string& name);
-bool CompileFile(const char *fileName, ShHandle, int options, const TBuiltInResource*);
+bool CompileFile(const char *fileName, ShHandle, int options);
 void usage();
 void FreeFileData(char **data);
 char** ReadFileData(const char *fileName);
 void InfoLogMsg(const char* msg, const char* name, const int num);
 
-// Use to test breaking a single shader file into multiple strings.
+// Use to test breaking up a single shader file into multiple strings.
 int NumShaderStrings = 1;
 
+TBuiltInResource Resources;
+std::string ConfigFile;
+
 //
-// Set up the per compile resources
+// These are the default resources for TBuiltInResources, used for both
+//  - parsing this string for the case where the user didn't supply one
+//  - dumping out a template for user construction of a config file
 //
-void GenerateResources(TBuiltInResource& resources)
+const char* DefaultConfig = 
+"MaxLights 32\n"
+"MaxClipPlanes 6\n"
+"MaxTextureUnits 32\n"
+"MaxTextureCoords 32\n"
+"MaxVertexAttribs 64\n"
+"MaxVertexUniformComponents 4096\n"
+"MaxVaryingFloats 64\n"
+"MaxVertexTextureImageUnits 32\n"
+"MaxCombinedTextureImageUnits 32\n"
+"MaxTextureImageUnits 32\n"
+"MaxFragmentUniformComponents 4096\n"
+"MaxDrawBuffers 32\n"
+"MaxVertexUniformVectors 128\n"
+"MaxVaryingVectors 8\n"
+"MaxFragmentUniformVectors 16\n"
+"MaxVertexOutputVectors 16\n"
+"MaxFragmentInputVectors 15\n"
+"MinProgramTexelOffset -8\n"
+"MaxProgramTexelOffset 7\n"
+;
+
+//
+// Parse either a .conf file provided by the user or the default string above.
+//
+void ProcessConfigFile()
 {
-    resources.maxLights = 32;
-    resources.maxClipPlanes = 6;
-    resources.maxTextureUnits = 32;
-    resources.maxTextureCoords = 32;
-    resources.maxVertexAttribs = 64;
-    resources.maxVertexUniformComponents = 4096;
-    resources.maxVaryingFloats = 64;
-    resources.maxVertexTextureImageUnits = 32;
-    resources.maxCombinedTextureImageUnits = 32;
-    resources.maxTextureImageUnits = 32;
-    resources.maxFragmentUniformComponents = 4096;
-    resources.maxDrawBuffers = 32;
-    resources.maxVertexUniformVectors = 128;
-    resources.maxVaryingVectors = 8;
-    resources.maxFragmentUniformVectors = 16;
-    resources.maxVertexOutputVectors = 16;
-    resources.maxFragmentInputVectors = 15;
-    resources.minProgramTexelOffset = -8;
-    resources.maxProgramTexelOffset = 7;
+    char** configStrings = 0;
+    char *config = 0;
+    if (ConfigFile.size() > 0) {
+        char** configStrings = ReadFileData(ConfigFile.c_str());
+        if (configStrings)
+            config = *configStrings;
+        else {
+            printf("Error opening configuration file; will instead use the default configuration\n");
+            usage();
+        }
+    }
+
+    if (config == 0) {
+        config = new char[strlen(DefaultConfig)];
+        strcpy(config, DefaultConfig);
+    }
+
+    const char* delims = " \t\n\r";
+    const char* token = strtok(config, delims);
+    while (token) {
+        const char* valueStr = strtok(0, delims);
+        if (valueStr == 0 || ! (valueStr[0] == '-' || (valueStr[0] >= '0' && valueStr[0] <= '9'))) {
+            printf("Error: '%s' bad .conf file.  Each name must be followed by one number.\n", valueStr ? valueStr : "");
+            return;
+        }
+        int value = atoi(valueStr);
+
+        if (strcmp(token, "MaxLights") == 0)
+            Resources.maxLights = value;
+        else if (strcmp(token, "MaxClipPlanes") == 0)
+            Resources.maxClipPlanes = value;
+        else if (strcmp(token, "MaxTextureUnits") == 0)
+            Resources.maxTextureUnits = value;
+        else if (strcmp(token, "MaxTextureCoords") == 0)
+            Resources.maxTextureCoords = value;
+        else if (strcmp(token, "MaxVertexAttribs") == 0)
+            Resources.maxVertexAttribs = value;
+        else if (strcmp(token, "MaxVertexUniformComponents") == 0)
+            Resources.maxVertexUniformComponents = value;
+        else if (strcmp(token, "MaxVaryingFloats") == 0)
+            Resources.maxVaryingFloats = value;
+        else if (strcmp(token, "MaxVertexTextureImageUnits") == 0)
+            Resources.maxVertexTextureImageUnits = value;
+        else if (strcmp(token, "MaxCombinedTextureImageUnits") == 0)
+            Resources.maxCombinedTextureImageUnits = value;
+        else if (strcmp(token, "MaxTextureImageUnits") == 0)
+            Resources.maxTextureImageUnits = value;
+        else if (strcmp(token, "MaxFragmentUniformComponents") == 0)
+            Resources.maxFragmentUniformComponents = value;
+        else if (strcmp(token, "MaxDrawBuffers") == 0)
+            Resources.maxDrawBuffers = value;
+        else if (strcmp(token, "MaxVertexUniformVectors") == 0)
+            Resources.maxVertexUniformVectors = value;
+        else if (strcmp(token, "MaxVaryingVectors") == 0)
+            Resources.maxVaryingVectors = value;
+        else if (strcmp(token, "MaxFragmentUniformVectors") == 0)
+            Resources.maxFragmentUniformVectors = value;
+        else if (strcmp(token, "MaxVertexOutputVectors") == 0)
+            Resources.maxVertexOutputVectors = value;
+        else if (strcmp(token, "MaxFragmentInputVectors") == 0)
+            Resources.maxFragmentInputVectors = value;
+        else if (strcmp(token, "MinProgramTexelOffset") == 0)
+            Resources.minProgramTexelOffset = value;
+        else if (strcmp(token, "MaxProgramTexelOffset") == 0)
+            Resources.maxProgramTexelOffset = value;
+        else
+            printf("Warning: unrecognized limit (%s) in configuration file.\n", token);
+
+        token = strtok(0, delims);
+    }
+    if (configStrings)
+        FreeFileData(configStrings);
 }
 
 // thread-safe list of shaders to asynchronously grab and compile
@@ -131,6 +219,22 @@
 bool Delay = false;
 const char* ExecutableName;
 
+//
+// *.conf => this is a config file that can set limits/resources
+//
+bool SetConfigFile(const std::string& name)
+{
+    if (name.size() < 5)
+        return false;
+
+    if (name.substr(name.size() - 5, std::string::npos) == ".conf") {
+        ConfigFile = name;
+        return true;
+    }
+
+    return false;
+}
+
 bool ProcessArguments(int argc, char* argv[])
 {
     ExecutableName = argv[0];
@@ -141,13 +245,16 @@
     argc--;
     argv++;    
     for (; argc >= 1; argc--, argv++) {
+        Work[argc] = 0;
         if (argv[0][0] == '-') {
-            Work[argc] = 0;
             switch (argv[0][1]) {
+            case 'c':
+                Options |= EOptionDumpConfig;
+                break;
             case 'd':
                 Delay = true;                        
                 break;
-            case 'i': 
+            case 'i':
                 Options |= EOptionIntermediate;
                 break;
             case 'l':
@@ -171,14 +278,14 @@
                 return false;
             }
         } else {
-            Work[argc] = new glslang::TWorkItem(std::string(argv[0]));
-            Worklist.add(Work[argc]);
+            std::string name(argv[0]);
+            if (! SetConfigFile(name)) {
+                Work[argc] = new glslang::TWorkItem(name);
+                Worklist.add(Work[argc]);
+            }
         }
     }
 
-    if (Worklist.empty())
-        return false;
-
     return true;
 }
 
@@ -195,9 +302,7 @@
         if (compiler == 0)
             return false;
 
-        TBuiltInResource resources;
-        GenerateResources(resources);
-        CompileFile(workItem->name.c_str(), compiler, Options, &resources);
+        CompileFile(workItem->name.c_str(), compiler, Options);
 
         if (! (Options & EOptionSuppressInfolog))
             workItem->results = ShGetInfoLog(compiler);
@@ -225,9 +330,6 @@
     if (Options & EOptionIntermediate)
         messages = (EShMessages)(messages | EShMsgAST);
 
-    TBuiltInResource resources;
-    GenerateResources(resources);
-
     //
     // Per-shader processing...
     //
@@ -247,7 +349,7 @@
 
         shader->setStrings(shaderStrings, 1);
 
-        shader->parse(&resources, 100, false, messages);
+        shader->parse(&Resources, 100, false, messages);
         
         program.addShader(shader);
 
@@ -295,6 +397,20 @@
         return EFailUsage;
     }
 
+    if (Options & EOptionDumpConfig) {
+        printf("%s", DefaultConfig);
+        if (Worklist.empty())
+            return ESuccess;
+    }
+
+    if (Worklist.empty()) {
+        usage();
+        return EFailUsage;
+    }
+
+    ProcessConfigFile();
+
+
     //
     // Two modes:
     // 1) linking all arguments together, single-threaded, new C++ interface
@@ -384,7 +500,7 @@
 // Read a file's data into a string, and compile it using the old interface ShCompile, 
 // for non-linkable results.
 //
-bool CompileFile(const char *fileName, ShHandle compiler, int Options, const TBuiltInResource* resources)
+bool CompileFile(const char *fileName, ShHandle compiler, int Options)
 {
     int ret;
     char** shaderStrings = ReadFileData(fileName);
@@ -410,11 +526,11 @@
     
     for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
         for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j) {
-            //ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, resources, Options, 100, false, messages);
-            ret = ShCompile(compiler, shaderStrings, NumShaderStrings, 0, EShOptNone, resources, Options, 100, false, messages);
+            //ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, &Resources, Options, 100, false, messages);
+            ret = ShCompile(compiler, shaderStrings, NumShaderStrings, 0, EShOptNone, &Resources, Options, 100, false, messages);
             //const char* multi[4] = { "# ve", "rsion", " 300 e", "s" };
             //const char* multi[7] = { "/", "/", "\\", "\n", "\n", "#", "version 300 es" };
-            //ret = ShCompile(compiler, multi, 4, 0, EShOptNone, resources, Options, 100, false, messages);
+            //ret = ShCompile(compiler, multi, 4, 0, EShOptNone, &Resources, Options, 100, false, messages);
         }
 
         if (Options & EOptionMemoryLeakMode)
@@ -434,6 +550,8 @@
 {
     printf("Usage: glslangValidator [ options ] filename\n"
            "Where: filename is a name ending in\n"
+           "    .conf provides an optional config file that replaces the default configuration\n"
+           "          (see -c option below for generating a template)\n"
            "    .vert for a vertex shader\n"
            "    .tesc for a tessellation control shader\n"
            "    .tese for a tessellation evaluation shader\n"
@@ -442,6 +560,7 @@
            "    .comp for a compute shader\n\n"
            "Compilation warnings and errors will be printed to stdout.\n"
            "To get other information, use one of the following options:\n"
+           "-c: configuration dump; use to create default configuration file (redirect to a .conf file)\n"
            "-i: intermediate tree (glslang AST) is printed out\n"
            "-d: delay exit\n"
            "-l: link validation of all input files\n"