]> git.cworth.org Git - vogl/blob - src/voglgen/voglgen.cpp
Make voglgen accept specdir as option
[vogl] / src / voglgen / voglgen.cpp
1 /**************************************************************************
2  *
3  * Copyright 2013-2014 RAD Game Tools and Valve Software
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26 // File: voglgen.cpp
27 // Important: If compiling with gcc, be sure strict aliasing is disabled: -fno-strict-aliasing
28
29 #include "vogl_core.h"
30 #include "vogl_console.h"
31 #include "vogl_colorized_console.h"
32 #include "vogl_find_files.h"
33 #include "vogl_file_utils.h"
34 #include "vogl_command_line_params.h"
35 #include "vogl_cfile_stream.h"
36 #include "vogl_vector2d.h"
37 #include "vogl_json.h"
38 #include "vogl_vec_interval.h"
39 #include "vogl_radix_sort.h"
40 #include "vogl_regex.h"
41 #include "vogl_hash_map.h"
42 #include <set>
43
44 #include "tinyxml/tinyxml.h"
45
46 #define VOGL_NAMESPACES_HEADER
47 #define VOGL_NAMESPACES_IMPLEMENTATION
48 #include "../voglcommon/vogl_namespaces.h"
49
50 using namespace vogl;
51
52 //-------------------------------------------------------------------------------------------------------------------------------
53 // Command line options
54 //-------------------------------------------------------------------------------------------------------------------------------
55 static command_line_param_desc g_command_line_param_descs[] =
56     {
57         { "debug", 0, false, NULL },
58         { "verbose", 0, false, NULL },
59         { "find", 0, false, NULL },
60         { "func_regex", 1, false, NULL },
61         { "param_regex", 1, false, NULL },
62         { "category_regex", 1, false, NULL },
63         { "ctype_regex", 1, false, NULL },
64         { "namespace_regex", 1, false, NULL },
65         { "srcdir", 1, false, NULL },
66         { "specdir", 1, false, NULL },
67     };
68
69 //-----------------------------------------------------------------------------------------------------------------------
70 // Function prefixes
71 //-------------------------------------------------------------------------------------------------------------------------------
72 enum gl_lib_t
73 {
74     cGL,
75     cGLX,
76     cWGL,
77     cGLU
78 };
79
80 static const char *g_lib_api_prefixes[] =
81     {
82         "gl",
83         "glX",
84         "wgl",
85         "glu"
86     };
87
88 //-------------------------------------------------------------------------------------------------------------------------------
89 // Vendor suffixes
90 //-------------------------------------------------------------------------------------------------------------------------------
91 static const char *g_gl_vendor_suffixes[] =
92     {
93         "NV", "INTEL", "SGIS", "SGIX", "SUN", "NVX", "OES", "AMD", "ATI", "OES", "3DFX", "PGI", "INGR", "IBM"
94     };
95
96 //-------------------------------------------------------------------------------------------------------------------------------
97 // GL/GLX/WGL/etc. function specs
98 //-------------------------------------------------------------------------------------------------------------------------------
99 struct gl_function_param
100 {
101     dynamic_string m_name;
102     dynamic_string m_type;
103     dynamic_string m_ctype;
104     dynamic_string m_ctype_enum;
105     dynamic_string m_direction;
106     dynamic_string m_semantic; // array, reference, value
107     dynamic_string m_array_size;
108     bool m_retained;
109
110     gl_function_param()
111         : m_retained(false)
112     {
113     }
114
115     void clear()
116     {
117         m_name.clear();
118         m_type.clear();
119         m_ctype.clear();
120         m_ctype_enum.clear();
121         m_direction.clear();
122         m_semantic.clear();
123         m_array_size.clear();
124         m_retained = false;
125     }
126
127     void print(FILE *pFile) const
128     {
129         vogl_fprintf(pFile, "Name: \"%s\", Type: \"%s\", Direction: \"%s\", Semantic: \"%s\", ArraySize: \"%s\", Retained: %u\n", m_name.get_ptr(), m_type.get_ptr(), m_direction.get_ptr(), m_semantic.get_ptr(), m_array_size.get_ptr(), m_retained);
130     }
131 };
132
133 //-----------------------------------------------------------------------------------------------------------------------
134 // struct gl_function_def
135 //-----------------------------------------------------------------------------------------------------------------------
136 struct gl_function_def
137 {
138     dynamic_string m_name;      // func name from spec file, without the gl/glx/wgl/etc. prefix
139     dynamic_string m_full_name; // full func name, with prefix
140     vogl::vector<dynamic_string> m_param_names;
141
142     dynamic_string m_return;
143     dynamic_string m_return_ctype;
144     dynamic_string m_return_ctype_enum;
145
146     vogl::vector<gl_function_param> m_params;
147     dynamic_string m_category;
148     dynamic_string m_version;
149     dynamic_string m_profile;
150     dynamic_string m_deprecated;
151     gl_lib_t m_lib;
152     bool m_notlistable;
153
154     gl_function_def()
155     {
156         clear();
157     }
158
159     void clear()
160     {
161         m_name.clear();
162         m_param_names.clear();
163         m_return.clear();
164         m_return_ctype.clear();
165         m_return_ctype_enum.clear();
166         m_params.clear();
167         m_category.clear();
168         m_version.clear();
169         m_profile.clear();
170         m_deprecated.clear();
171         m_lib = cGL;
172         m_notlistable = false;
173     }
174
175     void print(FILE *pFile) const
176     {
177         vogl_fprintf(pFile, "Name: \"%s\", ParamNames: %u, Params: %u, Return: \"%s\", Category: \"%s\", Version: \"%s\", Profile: \"%s\", Deprecated: \"%s\", Lib: \"%s\" notlistable: %u\n",
178                     m_name.get_ptr(),
179                     m_param_names.size(),
180                     m_params.size(),
181                     m_return.get_ptr(),
182                     m_category.get_ptr(),
183                     m_version.get_ptr(),
184                     m_profile.get_ptr(),
185                     m_deprecated.get_ptr(),
186                     g_lib_api_prefixes[m_lib],
187                     m_notlistable);
188
189         if (m_params.size())
190         {
191             for (uint i = 0; i < m_params.size(); i++)
192             {
193                 vogl_fprintf(pFile, "  ");
194                 m_params[i].print(pFile);
195             }
196             vogl_fprintf(pFile, "\n");
197         }
198     }
199
200     dynamic_string get_param_proto() const
201     {
202         dynamic_string proto;
203         for (uint param_index = 0; param_index < m_params.size(); param_index++)
204         {
205             const gl_function_param &param = m_params[param_index];
206
207             proto.format_append("%s%s%s", param.m_ctype.get_ptr(), param.m_ctype.ends_with("*") ? "" : " ", param.m_name.get_ptr());
208             if (param_index != m_params.size() - 1)
209                 proto.format_append(", ");
210         }
211         return proto;
212     }
213
214     dynamic_string get_param_args() const
215     {
216         dynamic_string proto;
217         for (uint param_index = 0; param_index < m_params.size(); param_index++)
218         {
219             proto.format_append("%s", m_params[param_index].m_name.get_ptr());
220             if (param_index != m_params.size() - 1)
221                 proto.format_append(", ");
222         }
223         return proto;
224     }
225
226     const char *get_lib_name() const
227     {
228         return g_lib_api_prefixes[m_lib];
229     }
230 };
231
232 typedef vogl::vector<gl_function_def> gl_function_def_vec;
233
234 //-----------------------------------------------------------------------------------------------------------------------
235 // struct gl_string_key_comparer
236 //-----------------------------------------------------------------------------------------------------------------------
237 struct gl_string_key_comparer
238 {
239     bool operator()(const dynamic_string &lhs, const dynamic_string &rhs) const
240     {
241         return lhs.compare(rhs, true) < 0;
242     }
243 };
244
245 typedef std::map<dynamic_string, dynamic_string, gl_string_key_comparer> gl_string_map;
246 typedef std::set<dynamic_string, gl_string_key_comparer> gl_string_set;
247
248 //-----------------------------------------------------------------------------------------------------------------------
249 // class gl_function_specs
250 //-----------------------------------------------------------------------------------------------------------------------
251 class gl_function_specs
252 {
253 public:
254     gl_function_specs()
255     {
256     }
257
258     void clear()
259     {
260         m_funcs.clear();
261     }
262
263     gl_function_specs &operator+=(const gl_function_specs &other)
264     {
265         m_funcs.append(other.m_funcs);
266         return *this;
267     }
268
269     uint size() const
270     {
271         return m_funcs.size();
272     }
273
274     const gl_function_def &operator[](uint i) const
275     {
276         return m_funcs[i];
277     }
278
279     gl_function_def &operator[](uint i)
280     {
281         return m_funcs[i];
282     }
283
284     const gl_function_def_vec &get_funcs_vec() const
285     {
286         return m_funcs;
287     }
288
289     gl_function_def_vec &get_funcs_vec()
290     {
291         return m_funcs;
292     }
293
294     int find_index(const char *pName) const
295     {
296         for (uint i = 0; i < m_funcs.size(); i++)
297             if (m_funcs[i].m_name.compare(pName, true) == 0)
298                 return i;
299
300         return -1;
301     }
302
303     const gl_function_def *find(const char *pName) const
304     {
305         for (uint i = 0; i < m_funcs.size(); i++)
306             if (m_funcs[i].m_name.compare(pName, true) == 0)
307                 return &m_funcs[i];
308
309         return NULL;
310     }
311
312     bool exists(const char *pName) const
313     {
314         return find(pName) != NULL;
315     }
316
317     void dump_to_file(const char *pFilename) const
318     {
319         FILE *pFile = vogl_fopen(pFilename, "w");
320         if (pFile)
321         {
322             console::info("--- Dumping %u GL function specs to file \"%s\"\n", m_funcs.size(), pFilename);
323
324             vogl_fprintf(pFile, "Functions:\n");
325             for (uint i = 0; i < m_funcs.size(); i++)
326             {
327                 m_funcs[i].print(pFile);
328             }
329
330             vogl_fprintf(pFile, "Categories:\n");
331
332             gl_string_set categories;
333             for (uint i = 0; i < m_funcs.size(); i++)
334                 categories.insert(m_funcs[i].m_category);
335
336             for (gl_string_set::const_iterator it = categories.begin(); it != categories.end(); ++it)
337                 vogl_fprintf(pFile, "\"%s\"\n", it->get_ptr());
338
339             vogl_fclose(pFile);
340         }
341     }
342
343     bool parse_spec_file(const char *pSpec_filename, gl_lib_t default_gl_lib_type)
344     {
345         cfile_stream spec_file(pSpec_filename, cDataStreamReadable);
346         if (!spec_file.is_opened())
347         {
348             console::error("Unable to open file \"%s\"!\n", pSpec_filename);
349             return false;
350         }
351
352         dynamic_string cur_function_def;
353         vogl::vector<dynamic_string> cur_function_param_names;
354         gl_function_def *pCur_func_def = NULL;
355
356         uint max_num_params = 0;
357         uint total_functions = 0;
358
359         dynamic_string line_str;
360         while (spec_file.get_remaining())
361         {
362             if (!spec_file.read_line(line_str))
363                 break;
364
365             line_str.trim_end();
366
367             int comment_ofs = line_str.find_left('#');
368             if (comment_ofs >= 0)
369             {
370                 line_str.truncate(comment_ofs);
371                 line_str.trim_end();
372             }
373
374             if (line_str.is_empty())
375                 continue;
376
377             if (line_str.find_left(':') >= 0)
378             {
379                 cur_function_def.clear();
380                 pCur_func_def = NULL;
381                 cur_function_param_names.clear();
382
383                 continue;
384             }
385
386             //printf("%s\n", line_str.get_ptr());
387
388             int paren_start = line_str.find_left('(');
389             int paren_end = line_str.find_right(')');
390             bool is_func_def = !vogl_isspace(line_str[0]) && ((paren_start >= 0) && (paren_end >= 0) && (paren_end > paren_start));
391
392             if (is_func_def)
393             {
394                 cur_function_def.set(line_str).left(paren_start).trim();
395                 if (cur_function_def.is_empty())
396                 {
397                     console::error("Skipping unrecognized line: %s\n", line_str.get_ptr());
398                     continue;
399                 }
400                 cur_function_def = cur_function_def;
401
402                 dynamic_string param_names(line_str);
403                 param_names.mid(paren_start + 1, paren_end - paren_start - 1).trim();
404
405                 cur_function_param_names.resize(0);
406
407                 int cur_ofs = 0;
408                 while (cur_ofs < (int)param_names.get_len())
409                 {
410                     int next_comma_ofs = param_names.find_left(',', cur_ofs);
411
412                     dynamic_string cur_param_name(param_names);
413                     if (next_comma_ofs < 0)
414                     {
415                         cur_param_name.right(cur_ofs).trim();
416                         cur_ofs = param_names.get_len();
417                     }
418                     else
419                     {
420                         cur_param_name.mid(cur_ofs, next_comma_ofs - cur_ofs).trim();
421                         cur_ofs = next_comma_ofs + 1;
422                     }
423
424                     if (!cur_param_name.is_empty())
425                     {
426                         cur_function_param_names.push_back(cur_param_name);
427                     }
428                     else
429                     {
430                         console::error("Empty parameter name: %s\n", line_str.get_ptr());
431                     }
432                 }
433
434 #if 0
435                                 printf("Function: \"%s\", Params %u:\n", cur_function_def.get_ptr(), cur_function_param_names.size());
436                                 for (uint i = 0; i < cur_function_param_names.size(); i++)
437                                 {
438                                         printf("  %s\n", cur_function_param_names[i].get_ptr());
439                                 }
440                                 printf("\n");
441 #endif
442
443                 max_num_params = math::maximum(max_num_params, cur_function_param_names.size());
444                 total_functions++;
445
446                 pCur_func_def = m_funcs.enlarge(1);
447                 pCur_func_def->m_name = cur_function_def;
448                 pCur_func_def->m_param_names = cur_function_param_names;
449                 pCur_func_def->m_lib = default_gl_lib_type;
450             }
451             else if ((!cur_function_def.is_empty()) && pCur_func_def && vogl_isspace(line_str[0]))
452             {
453                 vogl::vector<dynamic_string> func_attribute_tokens;
454                 line_str.tokenize(" \t", func_attribute_tokens);
455
456                 if (func_attribute_tokens.is_empty())
457                 {
458                     console::error("Skipping unrecognized line: %s\n", line_str.get_ptr());
459                 }
460                 else
461                 {
462                     if (func_attribute_tokens[0] == "return")
463                     {
464                         if (func_attribute_tokens.size() != 2)
465                         {
466                             console::error("Expected return type on line: %s\n", line_str.get_ptr());
467                             return false;
468                         }
469                         pCur_func_def->m_return = func_attribute_tokens[1];
470                     }
471                     else if (func_attribute_tokens[0] == "param")
472                     {
473                         if ((func_attribute_tokens.size() < 5) || (func_attribute_tokens.size() > 7))
474                         {
475                             console::error("Unexpected number of param tokens on line: %s\n", line_str.get_ptr());
476                             return false;
477                         }
478
479                         if ((func_attribute_tokens[3] != "in") && (func_attribute_tokens[3] != "out"))
480                         {
481                             console::error("Unexpected param direction on line: %s\n", line_str.get_ptr());
482                             return false;
483                         }
484
485                         if (func_attribute_tokens[4].find_left("array[") == 0)
486                         {
487                             // special case for glx.spec
488                             int open_bracket = func_attribute_tokens[4].find_left('[');
489                             int close_bracket = func_attribute_tokens[4].find_left(']');
490                             if (open_bracket < close_bracket)
491                             {
492                                 func_attribute_tokens.push_back(dynamic_string(func_attribute_tokens[4]));
493                                 func_attribute_tokens.back().right(open_bracket);
494                                 func_attribute_tokens[4].truncate(open_bracket);
495                             }
496                         }
497
498                         if ((func_attribute_tokens[4] != "value") && (func_attribute_tokens[4] != "array") && (func_attribute_tokens[4] != "reference"))
499                         {
500                             console::error("Unexpected param semantic on line: %s\n", line_str.get_ptr());
501                             return false;
502                         }
503
504                         gl_function_param *pParam = pCur_func_def->m_params.enlarge(1);
505
506                         if (func_attribute_tokens.back() == "retained")
507                         {
508                             pParam->m_retained = true;
509                             func_attribute_tokens.resize(func_attribute_tokens.size() - 1);
510                         }
511
512                         //param         pname           GetTextureParameter in value
513                         //param         params          Float32 out array [COMPSIZE(pname)]
514                         pParam->m_name = func_attribute_tokens[1];
515                         pParam->m_type = func_attribute_tokens[2];
516                         pParam->m_direction = func_attribute_tokens[3];
517                         pParam->m_semantic = func_attribute_tokens[4];
518                         if (pParam->m_semantic == "array")
519                         {
520                             if ((func_attribute_tokens[5][0] != '[') || (func_attribute_tokens[5].back() != ']'))
521                             {
522                                 console::error("Unexpected array size on line: %s\n", line_str.get_ptr());
523                                 return false;
524                             }
525
526                             pParam->m_array_size = func_attribute_tokens[5];
527                             for (;;)
528                             {
529                                 int slash_ofs = pParam->m_array_size.find_left('/');
530                                 if (slash_ofs < 0)
531                                     break;
532                                 pParam->m_array_size.set_char(slash_ofs, ',');
533                             }
534                         }
535                         else if (func_attribute_tokens.size() != 5)
536                         {
537                             console::error("Unexpected number of tokens on line: %s\n", line_str.get_ptr());
538                             return false;
539                         }
540                     }
541                     else if (func_attribute_tokens[0] == "category")
542                     {
543                         pCur_func_def->m_category = func_attribute_tokens[1];
544
545                         if (pCur_func_def->m_category == "gl")
546                             pCur_func_def->m_lib = cGL;
547                         else if (pCur_func_def->m_category == "glX")
548                             pCur_func_def->m_lib = cGLX;
549                         else if (pCur_func_def->m_category == "wgl")
550                             pCur_func_def->m_lib = cWGL;
551                         else if (pCur_func_def->m_category == "glu")
552                             pCur_func_def->m_lib = cGLU;
553                         else
554                         {
555                             // lib is default_gl_lib_type
556                         }
557                     }
558                     else if (func_attribute_tokens[0] == "version")
559                     {
560                         if (func_attribute_tokens.size() != 2)
561                         {
562                             console::error("Invalid version param on line: %s\n", line_str.get_ptr());
563                             return false;
564                         }
565
566                         pCur_func_def->m_version = func_attribute_tokens[1];
567                     }
568                     else if (func_attribute_tokens[0] == "profile")
569                     {
570                         if (func_attribute_tokens.size() != 2)
571                         {
572                             console::error("Invalid profile param on line: %s\n", line_str.get_ptr());
573                             return false;
574                         }
575
576                         pCur_func_def->m_profile = func_attribute_tokens[1];
577                     }
578                     else if (func_attribute_tokens[0] == "deprecated")
579                     {
580                         if (func_attribute_tokens.size() != 2)
581                         {
582                             console::error("Invalid deprecated param on line: %s\n", line_str.get_ptr());
583                             return false;
584                         }
585
586                         pCur_func_def->m_deprecated = func_attribute_tokens[1];
587                     }
588                     else if (func_attribute_tokens[0] == "dlflags")
589                     {
590                         if (func_attribute_tokens.size() != 2)
591                         {
592                             console::error("Invalid dlflags on line: %s\n", line_str.get_ptr());
593                             return false;
594                         }
595
596                         if ((func_attribute_tokens[1] != "notlistable") && (func_attribute_tokens[1] != "handcode") && (func_attribute_tokens[1] != "prepad"))
597                         {
598                             console::error("Unrecognized dlflags on line: %s\n", line_str.get_ptr());
599                             return false;
600                         }
601
602                         pCur_func_def->m_notlistable = (func_attribute_tokens[1] == "notlistable");
603                     }
604                 }
605             }
606             else
607             {
608                 console::error("Skipping unrecognized line: %s\n", line_str.get_ptr());
609             }
610         }
611
612         for (uint i = 0; i < m_funcs.size(); i++)
613         {
614             m_funcs[i].m_full_name.format("%s%s", g_lib_api_prefixes[m_funcs[i].m_lib], m_funcs[i].m_name.get_ptr());
615         }
616
617         return true;
618     }
619
620     bool parse_gl_xml_file(const char *pFilename)
621     {
622         TiXmlDocument gl_xml;
623         if (!gl_xml.LoadFile(pFilename))
624         {
625             console::error("Failed loading %s!\n", pFilename);
626             return false;
627         }
628
629         const TiXmlElement *pRoot = gl_xml.RootElement();
630         const char *pName = pRoot->Attribute("name");
631         if ((!pName) || (strcmp(pName, "gl")))
632         {
633             console::error("Invalid root element in %s!\n", pFilename);
634             return false;
635         }
636
637         const TiXmlElement *pLibraries = pRoot->FirstChildElement("libraries");
638         const TiXmlElement *pExtensions = pRoot->FirstChildElement("extensions");
639         if ((!pLibraries) || (!pExtensions))
640         {
641             console::error("Couldn't find libraries and/or extensions elements in %s!\n", pFilename);
642             return false;
643         }
644
645         const TiXmlElement *pLibrary = pLibraries->FirstChildElement();
646         while (pLibrary)
647         {
648             const char *pName = pLibrary->Attribute("name");
649             if (pName)
650             {
651                 if (!parse_gl_xml_function_defs(pFilename, pName, pLibrary->FirstChildElement()))
652                     return false;
653             }
654
655             pLibrary = pLibrary->NextSiblingElement();
656         }
657
658         const TiXmlElement *pCur_extension = pExtensions->FirstChildElement();
659         while (pCur_extension)
660         {
661             const char *pExt_name = pCur_extension->Attribute("name");
662             if (!pExt_name)
663             {
664                 console::error("Couldn't find extension name attribute in %s!\n", pFilename);
665                 return false;
666             }
667
668             if (!parse_gl_xml_function_defs(pFilename, pExt_name, pCur_extension->FirstChildElement()))
669                 return false;
670
671             pCur_extension = pCur_extension->NextSiblingElement();
672         }
673
674         return true;
675     }
676
677 protected:
678     gl_function_def_vec m_funcs;
679
680     bool parse_gl_xml_function_defs(const char *pFilename, const char *pCategory, const TiXmlElement *pFunctions)
681     {
682         while (pFunctions)
683         {
684             if ((pFunctions->Value()) && (strcmp(pFunctions->Value(), "functions") == 0))
685             {
686                 const TiXmlElement *pFunction = pFunctions->FirstChildElement();
687                 while (pFunction)
688                 {
689                     if ((pFunction->Value()) && (strcmp(pFunction->Value(), "function") == 0))
690                     {
691                         const char *pType = pFunction->Attribute("type");
692                         const char *pName = pFunction->Attribute("name");
693                         if ((!pType) || (!pName))
694                         {
695                             console::error("Expected function name and type in file %s\n", pFilename);
696                             return false;
697                         }
698
699                         gl_function_def gl_func;
700
701                         gl_func.clear();
702                         gl_func.m_full_name = pName;
703                         gl_func.m_name = pName;
704
705                         if (gl_func.m_name.begins_with("glX", true))
706                         {
707                             gl_func.m_name.right(3);
708                             gl_func.m_lib = cGLX;
709                         }
710                         else if (gl_func.m_name.begins_with("glu", true))
711                         {
712                             gl_func.m_name.right(3);
713                             gl_func.m_lib = cGLU;
714                         }
715                         else if (gl_func.m_name.begins_with("wgl", true))
716                         {
717                             gl_func.m_name.right(3);
718                             gl_func.m_lib = cWGL;
719                         }
720                         else if (gl_func.m_name.begins_with("gl", true))
721                         {
722                             gl_func.m_name.right(2);
723                             gl_func.m_lib = cGL;
724                         }
725                         else
726                         {
727                             //console::warning("Unknown function prefix from XML, assuming \"gl\": %s\n", gl_func.m_name.get_ptr());
728                             gl_func.m_lib = cGL;
729                             gl_func.m_full_name.format("%s%s", "gl", pName);
730                         }
731
732                         gl_func.m_category = pCategory;
733                         gl_func.m_return = pType;
734
735                         const TiXmlElement *pParams = pFunction->FirstChildElement();
736                         while (pParams)
737                         {
738                             if (strcmp(pParams->Value(), "param") == 0)
739                             {
740                                 const char *pParam_type = pParams->Attribute("type");
741                                 const char *pParam_name = pParams->Attribute("name");
742                                 if ((!pParam_type) || (!pParam_name))
743                                 {
744                                     console::error("Expected parameter type and name in file %s\n", pFilename);
745                                     return false;
746                                 }
747
748                                 gl_function_param param;
749                                 param.clear();
750                                 param.m_name = pParam_name;
751                                 param.m_type = pParam_type;
752                                 gl_func.m_params.push_back(param);
753                             }
754                             pParams = pParams->NextSiblingElement();
755                         }
756
757                         if ((gl_func.m_params.size() == 1) && (gl_func.m_params[0].m_type == "") && (gl_func.m_params[0].m_name == "void"))
758                             gl_func.m_params.resize(0);
759
760                         m_funcs.push_back(gl_func);
761                     }
762
763                     pFunction = pFunction->NextSiblingElement();
764                 }
765             }
766
767             pFunctions = pFunctions->NextSiblingElement();
768         }
769
770         return true;
771     }
772 };
773
774 //-----------------------------------------------------------------------------------------------------------------------
775 // apitrace glapi.py parsing
776 //-----------------------------------------------------------------------------------------------------------------------
777 static const struct
778 {
779     const char *m_pSpec_return_type;
780     const char *m_pApitrace_return_type;
781     vogl_namespace_t m_namespace;
782 } g_apitrace_return_type_aliases[] =
783       {
784           { "void", "Void", VOGL_NAMESPACE_INVALID },
785           { "GLenum", "GLenum_error", VOGL_NAMESPACE_INVALID },
786           { "const GLubyte *", "String(Const(GLubyte))", VOGL_NAMESPACE_INVALID },
787           { "GLuint", "Handle(\"list\", GLuint, \"range\")", VOGL_NAMESPACE_LISTS },
788           { "GLint", "Alias(\"GLint\", GLenum)", VOGL_NAMESPACE_INVALID },
789           { "GLvoid*", "GLmap", VOGL_NAMESPACE_INVALID },
790           { "GLuint", "GLprogram", VOGL_NAMESPACE_PROGRAMS },
791           { "GLuint", "GLshader", VOGL_NAMESPACE_SHADERS },
792           { "GLint", "GLlocation", VOGL_NAMESPACE_LOCATIONS },
793           { "GLubyte *", "String(Const(GLubyte))", VOGL_NAMESPACE_INVALID },
794           { "GLint", "GLlocationARB", VOGL_NAMESPACE_LOCATIONS },
795           { "GLuint", "Handle(\"fragmentShaderATI\", GLuint, \"range\")", VOGL_NAMESPACE_FRAGMENT_SHADER_ATI }
796       };
797
798 const uint APITRACE_RETURN_TYPE_ALIASES_ARRAY_SIZE = sizeof(g_apitrace_return_type_aliases) / sizeof(g_apitrace_return_type_aliases[0]);
799
800 //-----------------------------------------------------------------------------------------------------------------------
801 // g_apitrace_param_type_aliases array
802 //-----------------------------------------------------------------------------------------------------------------------
803
804 static const struct
805 {
806     const char *m_pSpec_type;
807     const char *m_pApitrace_type;
808 } g_apitrace_param_type_aliases[] =
809       {
810           { "GLbitfield", "GLbitfield_access" },
811           { "GLbitfield", "GLbitfield_attrib" },
812           { "GLbitfield", "GLbitfield_barrier" },
813           { "GLbitfield", "GLbitfield_client_attrib" },
814           { "GLbitfield", "GLbitfield_shader" },
815           { "GLbitfield", "GLbitfield_sync_flush" },
816           { "GLuint", "GLpipeline" },
817           { "GLuint", "GLarray" },
818           { "GLuint", "GLarrayAPPLE" },
819           { "GLuint", "GLbuffer" },
820           { "GLuint", "GLfeedback" },
821           { "GLuint", "GLfence" },
822           { "GLuint", "GLframebuffer" },
823           { "GLuint", "GLpipeline" },
824           { "GLuint", "GLprogramARB" },
825           { "GLuint", "GLquery" },
826           { "GLuint", "GLrenderbuffer" },
827           { "GLuint", "GLsampler" },
828           { "GLuint", "GLtexture" },
829           { "GLuint", "GLarray" },
830           { "GLuint", "GLarrayAPPLE" },
831           { "GLuint", "GLbuffer" },
832           { "GLuint", "GLfeedback" },
833           { "GLuint", "GLfence" },
834           { "GLuint", "GLfragmentShaderATI" },
835           { "GLuint", "GLframebuffer" },
836           { "GLuint", "GLlist" },
837           { "GLuint", "GLpipeline" },
838           { "GLuint", "GLprogram" },
839           { "GLuint", "GLprogramARB" },
840           { "GLuint", "GLquery" },
841           { "GLuint", "GLrenderbuffer" },
842           { "GLuint", "GLsampler" },
843           { "GLuint", "GLshader" },
844           { "GLuint", "GLtexture" },
845           { "GLvoid *", "GLpointer" },
846           { "GLvoid", "GLIndexBuffer" },
847           { "GLchar *", "GLstring" },
848           { "const GLvoid *", "GLpointerConst" },
849           { "GLhalf", "GLhalfNV" },
850           { "const GLchar *", "GLstringConst" },
851           { "const GLchar *", "GLstringConstARB" },
852           { "GLchar *", "GLstringARB" },
853           { "GLchar", "GLcharARB" },
854           { "GLint", "GLlocation" },
855           { "GLint", "GLlocationARB" },
856           { "GLenum", "GLenum_int" },
857           { "GLint", "size_bgra" },
858           { "GLenum", "GLenum_mode" },
859       };
860
861 static const uint APITRACE_PARAM_TYPE_ALIASES_ARRAY_SIZE = sizeof(g_apitrace_param_type_aliases) / sizeof(g_apitrace_param_type_aliases[0]);
862
863 //-----------------------------------------------------------------------------------------------------------------------
864 // struct apitrace_gl_func_param_def
865 //-----------------------------------------------------------------------------------------------------------------------
866 struct apitrace_gl_func_param_def
867 {
868     apitrace_gl_func_param_def()
869     {
870         clear();
871     }
872
873     void clear()
874     {
875         m_name.clear();
876         m_type.clear();
877         m_gl_type.clear();
878
879         m_array_count_str.clear();
880         m_index_count_str.clear();
881         m_string_count_str.clear();
882         m_index_type_str.clear();
883
884         m_is_out = false;
885         m_is_pointer = false;
886         m_is_const = false;
887         m_is_opaque = false;
888         m_is_array = false;
889         m_is_blob = false;
890         m_is_index_buffer = false;
891         m_is_string = false;
892         m_is_opaque_ctype = false;
893     }
894
895     dynamic_string m_name;
896     dynamic_string m_type;
897     dynamic_string m_gl_type; // actual C type (but without const stuff)
898     vogl_namespace_t m_namespace;
899
900     dynamic_string m_array_count_str;
901     dynamic_string m_index_count_str;
902     dynamic_string m_string_count_str;
903     dynamic_string m_index_type_str;
904
905     bool m_is_out;
906     bool m_is_pointer;
907     bool m_is_const;
908     bool m_is_opaque;
909     bool m_is_array;
910     bool m_is_blob;
911     bool m_is_index_buffer;
912     bool m_is_string;
913     bool m_is_opaque_ctype;
914 };
915
916 typedef vogl::vector<apitrace_gl_func_param_def> apitrace_gl_func_param_def_array;
917
918 //-----------------------------------------------------------------------------------------------------------------------
919 // struct apitrace_gl_func_def
920 //-----------------------------------------------------------------------------------------------------------------------
921 struct apitrace_gl_func_def
922 {
923     apitrace_gl_func_def()
924     {
925         clear();
926     }
927
928     void clear()
929     {
930         m_name.clear();
931         m_return_type.clear();
932         m_return_gl_type.clear();
933         m_has_side_effects = false;
934         m_params.clear();
935     }
936
937     dynamic_string m_name;
938     dynamic_string m_return_type;
939     dynamic_string m_return_gl_type; // actual C type (but without const stuff)
940     vogl_namespace_t m_return_namespace;
941
942     bool m_has_side_effects;
943     apitrace_gl_func_param_def_array m_params;
944 };
945
946 typedef vogl::vector<apitrace_gl_func_def> apitrace_gl_func_def_array;
947
948 //-----------------------------------------------------------------------------------------------------------------------
949 // class apitrace_func_specs
950 //-----------------------------------------------------------------------------------------------------------------------
951
952 //#define APITRACE_FUNC_SPECS_DEBUG
953
954 class apitrace_func_specs
955 {
956 public:
957     apitrace_func_specs()
958     {
959     }
960
961     void clear()
962     {
963         m_funcs.clear();
964     }
965
966     uint size() const
967     {
968         return m_funcs.size();
969     }
970
971     const apitrace_gl_func_def &operator[](uint i) const
972     {
973         return m_funcs[i];
974     }
975
976     apitrace_gl_func_def &operator[](uint i)
977     {
978         return m_funcs[i];
979     }
980
981     const apitrace_gl_func_def_array &get_funcs_vec() const
982     {
983         return m_funcs;
984     }
985
986     apitrace_gl_func_def_array &get_funcs_vec()
987     {
988         return m_funcs;
989     }
990
991     int find_index(const char *pName) const
992     {
993         for (uint i = 0; i < m_funcs.size(); i++)
994             if (m_funcs[i].m_name.compare(pName, true) == 0)
995                 return i;
996
997         return -1;
998     }
999
1000     const apitrace_gl_func_def *find(const char *pName) const
1001     {
1002         for (uint i = 0; i < m_funcs.size(); i++)
1003             if (m_funcs[i].m_name.compare(pName, true) == 0)
1004                 return &m_funcs[i];
1005
1006         return NULL;
1007     }
1008
1009     bool exists(const char *pName) const
1010     {
1011         return find(pName) != NULL;
1012     }
1013
1014     // Yes this guy is ugly, but it's simple and works on the unmodified Python source glapi.py from apitrace.
1015     // glapi.py was automatically generated, then hand edited. It contains a lot of useful type and array size info, but is still
1016     // incomplete (see glReadPixels() for example, which is missing its array size).
1017     bool parse(const char *pFilename = "apitrace_gl_param_info.txt")
1018     {
1019         clear();
1020
1021         dynamic_string_array param_info_file;
1022         if (!file_utils::read_text_file(pFilename, param_info_file, file_utils::cRTFTrim | file_utils::cRTFIgnoreEmptyLines | file_utils::cRTFIgnoreCommentedLines | file_utils::cRTFPrintErrorMessages))
1023             return false;
1024
1025         dynamic_string_array unique_types;
1026         dynamic_string_array unique_array_counts;
1027
1028         for (uint line_index = 0; line_index < param_info_file.size(); line_index++)
1029         {
1030             const dynamic_string &orig_line(param_info_file[line_index]);
1031             dynamic_string line(orig_line);
1032
1033             if (line.begins_with("#"))
1034                 continue;
1035
1036             int comment_ofs = line.find_right('#');
1037             if (comment_ofs >= 0)
1038                 line.left(comment_ofs).trim();
1039
1040             if (!line.begins_with("GlFunction("))
1041                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1042
1043             line.replace("GlFunction(", "", true, NULL, 1);
1044
1045             if (line.ends_with(","))
1046                 line.shorten(1);
1047
1048             if (!line.ends_with(")"))
1049                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1050
1051             dynamic_string return_type;
1052
1053             int first_comma = line.find_left(',');
1054             if (first_comma < 0)
1055                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1056
1057             int first_paren = line.find_left('(');
1058             if ((first_paren >= 0) && (first_paren < first_comma))
1059             {
1060                 int matching_paren = find_matching_paren(line, first_paren);
1061                 if (matching_paren < 0)
1062                     return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1063
1064                 return_type = dynamic_string(line).left(matching_paren + 1);
1065                 line.right(matching_paren + 1).trim();
1066                 if (!line.begins_with(","))
1067                     return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1068
1069                 line.right(1).trim();
1070             }
1071             else
1072             {
1073                 return_type = dynamic_string(line).left(first_comma);
1074                 line.right(first_comma + 1).trim();
1075             }
1076
1077             if (!line.begins_with("\""))
1078                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1079
1080             int end_quote_ofs = line.find_left('\"', 1);
1081             if (end_quote_ofs < 0)
1082                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1083
1084             dynamic_string func_name(line);
1085             func_name.substring(1, end_quote_ofs);
1086
1087             line.right(end_quote_ofs + 1).trim();
1088             if (!line.begins_with(","))
1089                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1090             line.right(1).trim();
1091
1092             if (!line.begins_with("["))
1093                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1094
1095             int params_end = find_matching_paren(line, 0, '[', ']');
1096             if (params_end < 0)
1097                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1098
1099             dynamic_string params(line);
1100             params.substring(1, params_end);
1101
1102             line.right(params_end + 1).trim();
1103
1104             if ((!line.begins_with(",") && !line.begins_with(")")) || !line.ends_with(")"))
1105                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1106
1107             bool func_has_side_effects = true;
1108             if (line.contains("sideeffects=False"))
1109                 func_has_side_effects = false;
1110
1111             apitrace_gl_func_def func_def;
1112             func_def.m_name = func_name;
1113             func_def.m_has_side_effects = func_has_side_effects;
1114             func_def.m_return_type = return_type;
1115
1116             func_def.m_return_gl_type = return_type;
1117
1118             uint a;
1119             for (a = 0; a < APITRACE_RETURN_TYPE_ALIASES_ARRAY_SIZE; a++)
1120             {
1121                 if (func_def.m_return_gl_type == g_apitrace_return_type_aliases[a].m_pApitrace_return_type)
1122                 {
1123                     func_def.m_return_gl_type = g_apitrace_return_type_aliases[a].m_pSpec_return_type;
1124                     func_def.m_return_namespace = g_apitrace_return_type_aliases[a].m_namespace;
1125                     break;
1126                 }
1127             }
1128             if (a == APITRACE_RETURN_TYPE_ALIASES_ARRAY_SIZE)
1129             {
1130                 func_def.m_return_namespace = vogl_find_namespace_from_gl_type(func_def.m_return_gl_type.get_ptr());
1131                 if (func_def.m_return_namespace == VOGL_NAMESPACE_INVALID)
1132                 {
1133 // TODO: Here's the list of return/param types that can't be mapped right now - make exception list?
1134 #if 0
1135                                         size_bgra
1136                                         const GLboolean *
1137                                         Void
1138                                         GLvoid
1139                                         GLushort
1140                                         GLuint64EXT
1141                                         GLuint64
1142                                         GLuint
1143                                         GLubyte
1144                                         GLstringConstARB
1145                                         GLstringConst
1146                                         GLstringARB
1147                                         GLstring
1148                                         GLsizeiptrARB
1149                                         GLsizeiptr
1150                                         GLsizei
1151                                         GLshort
1152                                         GLregion
1153                                         GLpointerConst
1154                                         GLpointer
1155                                         GLintptrARB
1156                                         GLintptr
1157                                         GLint64EXT
1158                                         GLint64
1159                                         GLint
1160                                         GLhalfNV
1161                                         GLfloat
1162                                         GLenum_mode
1163                                         GLenum_int
1164                                         GLenum
1165                                         GLdouble
1166                                         GLclampf
1167                                         GLclampd
1168                                         GLcharARB
1169                                         GLchar
1170                                         GLbyte
1171                                         GLboolean
1172                                         GLbitfield_sync_flush
1173                                         GLbitfield_shader
1174                                         GLbitfield_client_attrib
1175                                         GLbitfield_barrier
1176                                         GLbitfield_attrib
1177                                         GLbitfield_access
1178                                         GLbitfield
1179                                         GLIndexBuffer
1180                                         GLDEBUGPROCARB
1181                                         GLDEBUGPROCAMD
1182                                         GLDEBUGPROC
1183 #endif
1184
1185                     //console::warning("%s: Couldn't map namespace %s\n", VOGL_METHOD_NAME, func_def.m_return_gl_type.get_ptr());
1186                 }
1187             }
1188
1189 #ifdef APITRACE_FUNC_SPECS_DEBUG
1190             printf("--- Func: %s\nReturn Type: %s, HasSideEffects: %u, Namespace: %s\n", func_name.get_ptr(), return_type.get_ptr(), func_has_side_effects, vogl_get_namespace_name(func_def.m_return_namespace));
1191 #endif
1192
1193             for (;;)
1194             {
1195                 bool is_out = false;
1196                 bool is_pointer = false;
1197                 bool is_const = false;
1198                 bool is_opaque = false;
1199                 bool is_array = false;
1200                 bool is_blob = false;
1201                 bool is_index_buffer = false;
1202                 bool is_string = false;
1203                 bool is_opaque_ctype = false;
1204                 dynamic_string array_count_str;
1205                 dynamic_string index_count_str;
1206                 dynamic_string string_count_str;
1207                 dynamic_string index_type_str;
1208
1209                 if (params.is_empty())
1210                     break;
1211
1212                 if (params.begins_with("Out("))
1213                     is_out = true;
1214                 else if (!params.begins_with("("))
1215                     return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1216
1217                 int first_paren = params.find_left("(");
1218                 if (first_paren < 0)
1219                     return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1220
1221                 int param_end_ofs = find_matching_paren(params, first_paren);
1222                 if (param_end_ofs < 0)
1223                     return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1224
1225                 dynamic_string cur_param;
1226                 cur_param = params;
1227                 cur_param.substring(first_paren + 1, param_end_ofs);
1228
1229                 params.right(param_end_ofs + 1).trim();
1230                 if (params.begins_with(","))
1231                     params.right(1).trim();
1232
1233                 int right_comma = cur_param.find_right(",");
1234                 if (right_comma < 0)
1235                     return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1236
1237                 dynamic_string param_name(cur_param);
1238                 param_name.right(right_comma + 1).trim();
1239                 cur_param.left(right_comma).trim();
1240
1241                 int paren_ofs;
1242                 while ((paren_ofs = cur_param.find_left('(')) >= 0)
1243                 {
1244                     bool get_count_string = false;
1245                     bool count_string_is_optional = false;
1246                     dynamic_string *pCount_str = &array_count_str;
1247
1248                     if (cur_param.begins_with("Out("))
1249                         is_out = true;
1250                     else if (cur_param.begins_with("Pointer("))
1251                         is_pointer = true;
1252                     else if (cur_param.begins_with("OpaquePointer("))
1253                     {
1254                         is_opaque = true;
1255                         is_pointer = true;
1256                     }
1257                     else if (cur_param.begins_with("Const("))
1258                         is_const = true;
1259                     else if (cur_param.begins_with("OpaqueBlob("))
1260                     {
1261                         is_opaque = true;
1262                         is_blob = true;
1263                         get_count_string = true;
1264                     }
1265                     else if (cur_param.begins_with("Blob("))
1266                     {
1267                         is_blob = true;
1268                         get_count_string = true;
1269                     }
1270                     else if (cur_param.begins_with("GLIndexBuffer("))
1271                     {
1272                         is_index_buffer = true;
1273                         get_count_string = true;
1274                         pCount_str = &index_count_str;
1275                     }
1276                     else if (cur_param.begins_with("OpaqueArray("))
1277                     {
1278                         is_opaque = true;
1279                         is_array = true;
1280                         get_count_string = true;
1281                     }
1282                     else if (cur_param.begins_with("Array("))
1283                     {
1284                         is_array = true;
1285                         get_count_string = true;
1286                     }
1287                     else if (cur_param.begins_with("String("))
1288                     {
1289                         is_string = true;
1290                         get_count_string = true;
1291                         count_string_is_optional = true;
1292                         pCount_str = &string_count_str;
1293                     }
1294                     else if (cur_param.begins_with("Opaque("))
1295                     {
1296                         is_opaque_ctype = true;
1297                     }
1298                     else
1299                         return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1300
1301                     int end_paren_ofs = find_matching_paren(cur_param, paren_ofs);
1302                     if (end_paren_ofs < 0)
1303                         return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1304
1305                     cur_param.substring(paren_ofs + 1, end_paren_ofs);
1306
1307                     if (get_count_string)
1308                     {
1309                         if (cur_param.ends_with("\""))
1310                         {
1311                             int start_of_count = cur_param.find_right('\"', cur_param.get_len() - 2);
1312                             if (start_of_count < 0)
1313                                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1314
1315                             if (!pCount_str->is_empty())
1316                                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1317
1318                             *pCount_str = cur_param;
1319                             pCount_str->right(start_of_count).trim();
1320
1321                             cur_param.left(start_of_count).trim();
1322                             if (!cur_param.ends_with(","))
1323                                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1324
1325                             cur_param.shorten(1).trim();
1326                         }
1327                         else
1328                         {
1329                             int comma_ofs = cur_param.find_right(',');
1330                             if ((comma_ofs < 0) && (!count_string_is_optional))
1331                                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1332
1333                             if (comma_ofs >= 0)
1334                             {
1335                                 if (!pCount_str->is_empty())
1336                                     return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1337                                 *pCount_str = cur_param;
1338                                 pCount_str->right(comma_ofs + 1).trim();
1339
1340                                 cur_param.left(comma_ofs).trim();
1341                             }
1342                         }
1343                     }
1344
1345                     if (is_index_buffer)
1346                     {
1347                         index_type_str = *pCount_str;
1348                         *pCount_str = cur_param;
1349                         cur_param.truncate(0);
1350                         if (index_type_str.contains('(') || index_type_str.contains(','))
1351                             return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1352                         break;
1353                     }
1354                 }
1355
1356                 if (is_index_buffer)
1357                     cur_param = "GLIndexBuffer";
1358
1359                 if (cur_param.is_empty())
1360                     return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1361
1362                 if (unique_types.find(cur_param) < 0)
1363                     unique_types.push_back(cur_param);
1364
1365                 if (unique_array_counts.find(array_count_str) < 0)
1366                     unique_array_counts.push_back(array_count_str);
1367
1368                 apitrace_gl_func_param_def param_def;
1369                 param_def.m_name = param_name;
1370                 param_def.m_type = cur_param;
1371                 param_def.m_array_count_str = array_count_str;
1372                 param_def.m_index_count_str = index_count_str;
1373                 param_def.m_string_count_str = string_count_str;
1374                 param_def.m_index_type_str = index_type_str;
1375                 param_def.m_is_out = is_out;
1376                 param_def.m_is_pointer = is_pointer;
1377                 param_def.m_is_const = is_const;
1378                 param_def.m_is_opaque = is_opaque;
1379                 param_def.m_is_array = is_array;
1380                 param_def.m_is_blob = is_blob;
1381                 param_def.m_is_index_buffer = is_index_buffer;
1382                 param_def.m_is_string = is_string;
1383                 param_def.m_is_opaque_ctype = is_opaque_ctype;
1384
1385                 dynamic_string gl_param_type(param_def.m_type);
1386
1387                 if (param_def.m_is_opaque_ctype)
1388                     gl_param_type.unquote();
1389
1390                 param_def.m_namespace = vogl_find_namespace_from_gl_type(gl_param_type.get_ptr());
1391                 if (param_def.m_namespace == VOGL_NAMESPACE_INVALID)
1392                 {
1393                     //console::warning("%s: Couldn't map namespace %s\n", VOGL_METHOD_NAME, gl_param_type.get_ptr());
1394                 }
1395
1396                 for (uint k = 0; k < APITRACE_PARAM_TYPE_ALIASES_ARRAY_SIZE; k++)
1397                 {
1398                     if (gl_param_type == g_apitrace_param_type_aliases[k].m_pApitrace_type)
1399                     {
1400                         gl_param_type = g_apitrace_param_type_aliases[k].m_pSpec_type;
1401                         break;
1402                     }
1403                 }
1404
1405                 if ((param_def.m_is_string) || (param_def.m_is_index_buffer))
1406                     gl_param_type.append(" *");
1407
1408                 if ((param_def.m_is_array) || (param_def.m_is_blob) || (param_def.m_is_pointer))
1409                 {
1410                     gl_param_type.append(" *");
1411                 }
1412
1413                 param_def.m_gl_type = gl_param_type;
1414
1415 #ifdef APITRACE_FUNC_SPECS_DEBUG
1416                 printf("Name: %s, Type: %s, Out: %u, Pointer: %u, Const: %u, IsOpaque: %u, Array: %u, Blob: %u, IndexBuf: %u, String: %u, OpaqueCType: %u, Namespace: %s\n",
1417                        param_name.get_ptr(),
1418                        cur_param.get_ptr(),
1419                        is_out, is_pointer, is_const, is_opaque, is_array, is_blob, is_index_buffer, is_string, is_opaque_ctype, vogl_get_namespace_name(param_def.m_namespace));
1420                 if (array_count_str.get_len())
1421                     printf("   ArrayCountStr: %s\n", array_count_str.get_ptr());
1422                 if (index_count_str.get_len())
1423                     printf("   IndexCountStr: %s\n", index_count_str.get_ptr());
1424                 if (string_count_str.get_len())
1425                     printf("   StringCountStr: %s\n", string_count_str.get_ptr());
1426                 if (index_type_str.get_len())
1427                     printf("   IndexTypeStr: %s\n", index_type_str.get_ptr());
1428 #endif
1429
1430                 func_def.m_params.push_back(param_def);
1431             }
1432
1433             m_funcs.push_back(func_def);
1434
1435 #ifdef APITRACE_FUNC_SPECS_DEBUG
1436             printf("\n\n");
1437 #endif
1438         }
1439
1440 #ifdef APITRACE_FUNC_SPECS_DEBUG
1441         printf("Unique types:\n");
1442         unique_types.sort();
1443         for (uint i = 0; i < unique_types.size(); i++)
1444             printf("%s\n", unique_types[i].get_ptr());
1445
1446         printf("\n");
1447
1448         printf("Unique array counts:\n");
1449         unique_array_counts.sort();
1450         for (uint i = 0; i < unique_array_counts.size(); i++)
1451             printf("%s\n", unique_array_counts[i].get_ptr());
1452 #endif
1453
1454         return true;
1455     }
1456
1457 private:
1458     apitrace_gl_func_def_array m_funcs;
1459
1460     bool parse_apitrace_gl_param_info_error(const dynamic_string_array &param_info_file, uint line_index)
1461     {
1462         console::error("Unrecognized line: %s\n", param_info_file[line_index].get_ptr());
1463         return false;
1464     }
1465
1466     static int find_matching_paren(const dynamic_string &str, uint ofs, uint open_char = '(', uint close_char = ')')
1467     {
1468         bool in_quoted_string = false;
1469         uint param_count = 0;
1470
1471         while (ofs < str.get_len())
1472         {
1473             uint c = str[ofs];
1474
1475             if (in_quoted_string)
1476             {
1477                 if (c == '"')
1478                 {
1479                     in_quoted_string = false;
1480                 }
1481             }
1482             else if (c == '"')
1483             {
1484                 in_quoted_string = true;
1485             }
1486             else if (c == open_char)
1487                 param_count++;
1488             else if (c == close_char)
1489             {
1490                 param_count--;
1491                 if (!param_count)
1492                     return ofs;
1493             }
1494
1495             ofs++;
1496         }
1497
1498         return -1;
1499     }
1500 };
1501
1502 //-----------------------------------------------------------------------------------------------------------------------
1503 // class gl_types
1504 //-----------------------------------------------------------------------------------------------------------------------
1505 class gl_types
1506 {
1507 public:
1508     gl_types()
1509     {
1510     }
1511
1512     void clear()
1513     {
1514         m_tm.clear();
1515     }
1516
1517     const gl_string_map &get_type_map() const
1518     {
1519         return m_tm;
1520     }
1521     gl_string_map &get_type_map()
1522     {
1523         return m_tm;
1524     }
1525
1526     uint size() const
1527     {
1528         return static_cast<uint>(m_tm.size());
1529     }
1530
1531     bool is_present(const dynamic_string &type_str) const
1532     {
1533         return m_tm.find(type_str) != m_tm.end();
1534         //return false;
1535     }
1536
1537     const dynamic_string *find(const dynamic_string &type_str) const
1538     {
1539         gl_string_map::const_iterator it(m_tm.find(type_str));
1540         if (it == m_tm.end())
1541             return NULL;
1542         return &it->second;
1543     }
1544
1545     bool parse_file(const char *pFilename)
1546     {
1547         cfile_stream tm_file(pFilename, cDataStreamReadable);
1548         if (!tm_file.is_opened())
1549         {
1550             console::error("Unable to open file \"%s\"!\n", pFilename);
1551             return false;
1552         }
1553
1554         dynamic_string line_str;
1555         while (tm_file.get_remaining())
1556         {
1557             if (!tm_file.read_line(line_str))
1558                 break;
1559
1560             line_str.trim_end();
1561
1562             int comment_ofs = line_str.find_left('#');
1563             if (comment_ofs >= 0)
1564             {
1565                 line_str.truncate(comment_ofs);
1566                 line_str.trim_end();
1567             }
1568
1569             if (line_str.is_empty())
1570                 continue;
1571
1572             // AccumOp,*,*,                         GLenum,*,*
1573
1574             dynamic_string_array tokens;
1575             line_str.tokenize(",", tokens);
1576             if (tokens.size() != 6)
1577             {
1578                 console::error("Unexpected number of tokens on line: %s\n", line_str.get_ptr());
1579                 return false;
1580             }
1581
1582             for (uint i = 0; i < tokens.size(); i++)
1583                 tokens[i].trim();
1584
1585             if ((tokens[0].is_empty()) || (tokens[1] != "*") || (tokens[2] != "*") ||
1586                 (tokens[3].is_empty()) || (tokens[4] != "*") || (tokens[5] != "*"))
1587             {
1588                 console::error("Unexpected token on line: %s\n", line_str.get_ptr());
1589                 return false;
1590             }
1591
1592             if (m_tm.find(tokens[0]) != m_tm.end())
1593             {
1594                 console::error("Duplicate spec type on line: %s\n", line_str.get_ptr());
1595                 return false;
1596             }
1597
1598             m_tm.insert(std::make_pair(tokens[0], tokens[3]));
1599         }
1600
1601         return true;
1602     }
1603
1604     //-----------------------------------------------------------------------------------------------------------------------
1605
1606     void dump_to_file(const char *pFilename) const
1607     {
1608         FILE *pFile = vogl_fopen(pFilename, "w");
1609         if (pFile)
1610         {
1611             console::info("--- Dumping %u GL types to text file \"%s\"\n", static_cast<uint>(m_tm.size()), pFilename);
1612
1613             for (gl_string_map::const_iterator it = m_tm.begin(); it != m_tm.end(); ++it)
1614                 vogl_fprintf(pFile, "\"%s\" = \"%s\"\n", it->first.get_ptr(), it->second.get_ptr());
1615
1616             vogl_fclose(pFile);
1617         }
1618         else
1619         {
1620             console::error("Failed writing GL types to file \"%s\"!\n", pFilename);
1621         }
1622     }
1623
1624 protected:
1625     gl_string_map m_tm;
1626 };
1627
1628 //-----------------------------------------------------------------------------------------------------------------------
1629 // class gl_enums
1630 //-----------------------------------------------------------------------------------------------------------------------
1631 struct gl_enum_def
1632 {
1633     dynamic_string m_name;
1634     dynamic_string m_def;
1635     bool m_alias_flag;
1636     bool m_define_flag;
1637 };
1638
1639 typedef vogl::vector<gl_enum_def> gl_enum_def_vec;
1640
1641 typedef std::map<dynamic_string, gl_enum_def_vec, gl_string_key_comparer> gl_enum_def_vec_map;
1642
1643 class gl_enums
1644 {
1645 public:
1646     gl_enums()
1647     {
1648     }
1649
1650     bool parse_file(const char *pFilename)
1651     {
1652         cfile_stream enum_file(pFilename, cDataStreamReadable);
1653         if (!enum_file.is_opened())
1654         {
1655             console::error("Unable to open file \"%s\"!\n", pFilename);
1656             return false;
1657         }
1658
1659         vogl::vector<gl_enum_def_vec_map::iterator> cur_enums;
1660         bool is_define = false;
1661         bool seen_at_least_one_define = false;
1662
1663         dynamic_string line_str;
1664         while (enum_file.get_remaining())
1665         {
1666             if (!enum_file.read_line(line_str))
1667                 break;
1668
1669             line_str.trim_end();
1670
1671             int comment_ofs = line_str.find_left('#');
1672             if (comment_ofs >= 0)
1673             {
1674                 line_str.truncate(comment_ofs);
1675                 line_str.trim_end();
1676             }
1677
1678             if (line_str.is_empty())
1679                 continue;
1680
1681             int colon_ofs = line_str.find_left(':');
1682             if (colon_ofs >= 0)
1683                 line_str.left(colon_ofs + 1);
1684
1685             dynamic_string_array tokens;
1686             line_str.tokenize(", \t", tokens);
1687
1688             if ((tokens[0] == "passthru:") || (tokens[0] == "profile:") || (tokens[0].find_left("future_use:") >= 0))
1689                 continue;
1690
1691             if ((colon_ofs >= 0) && (tokens.size()) &&
1692                 ((tokens.back() == "enum:") || (tokens.back() == "define:")))
1693             {
1694                 if (seen_at_least_one_define)
1695                     cur_enums.resize(0);
1696
1697                 is_define = (tokens.back() == "define:");
1698
1699                 for (uint i = 0; i < (tokens.size() - 1); i++)
1700                 {
1701                     gl_enum_def_vec_map::iterator cur_enum(m_enums.find(tokens[i]));
1702                     if (cur_enum == m_enums.end())
1703                     {
1704                         cur_enum = m_enums.insert(std::make_pair(tokens[i], gl_enum_def_vec())).first;
1705                     }
1706
1707                     cur_enums.push_back(cur_enum);
1708                 }
1709             }
1710             else if (tokens.size())
1711             {
1712                 if (line_str.find_left('=') >= 0)
1713                 {
1714                     seen_at_least_one_define = true;
1715
1716                     if ((tokens.size() != 3) || (tokens[1] != "="))
1717                     {
1718                         console::error("Unrecognized line: %s\n", line_str.get_ptr());
1719                         return false;
1720                     }
1721
1722                     if ((tokens[0].is_empty()) || (tokens[1].is_empty()))
1723                     {
1724                         console::error("Unrecognized line: %s\n", line_str.get_ptr());
1725                         return false;
1726                     }
1727
1728                     if (!cur_enums.size())
1729                     {
1730                         console::error("Enum defined outside of enum block: %s\n", line_str.get_ptr());
1731                         return false;
1732                     }
1733
1734                     gl_enum_def def;
1735                     def.m_name = tokens[0];
1736                     def.m_def = tokens[2];
1737                     def.m_alias_flag = false;
1738                     def.m_define_flag = is_define;
1739
1740                     for (uint i = 0; i < cur_enums.size(); i++)
1741                         cur_enums[i]->second.push_back(def);
1742                 }
1743                 else if (tokens[0] == "use")
1744                 {
1745                     seen_at_least_one_define = true;
1746
1747                     if (!cur_enums.size())
1748                     {
1749                         console::error("Enum defined outside of enum block: %s\n", line_str.get_ptr());
1750                         return false;
1751                     }
1752
1753                     gl_enum_def def;
1754                     def.m_name = tokens[2];
1755                     def.m_def = tokens[1];
1756                     def.m_alias_flag = true;
1757                     def.m_define_flag = is_define;
1758
1759                     for (uint i = 0; i < cur_enums.size(); i++)
1760                         cur_enums[i]->second.push_back(def);
1761                 }
1762                 else
1763                 {
1764                     console::error("Unrecognized line: %s\n", line_str.get_ptr());
1765                     return false;
1766                 }
1767             }
1768             else
1769             {
1770                 console::error("Unrecognized line: %s\n", line_str.get_ptr());
1771                 return false;
1772             }
1773         }
1774
1775         for (gl_enum_def_vec_map::iterator enum_it = m_enums.begin(); enum_it != m_enums.end(); ++enum_it)
1776         {
1777             //printf("%s\n", enum_it->first.get_ptr());
1778             gl_enum_def_vec_map::const_iterator alias_it(m_enums.find(enum_it->first));
1779             VOGL_ASSERT(alias_it != m_enums.end());
1780         }
1781
1782         uint num_unresolved_aliases;
1783         uint pass_num = 0;
1784         do
1785         {
1786             if (++pass_num == 100)
1787             {
1788                 console::error("Typemap alias depth is too deep, or there are circular aliases\n");
1789                 return false;
1790             }
1791
1792             num_unresolved_aliases = 0;
1793
1794             for (gl_enum_def_vec_map::iterator enum_it = m_enums.begin(); enum_it != m_enums.end(); ++enum_it)
1795             {
1796                 gl_enum_def_vec &def_vec = enum_it->second;
1797                 for (uint i = 0; i < def_vec.size(); i++)
1798                 {
1799                     if (!def_vec[i].m_alias_flag)
1800                         continue;
1801
1802                     gl_enum_def_vec_map::const_iterator alias_it(m_enums.find(def_vec[i].m_def));
1803                     if (alias_it == m_enums.end())
1804                     {
1805                         console::error("Bad alias enum: %s %s\n", def_vec[i].m_def.get_ptr(), def_vec[i].m_name.get_ptr());
1806                         return false;
1807                     }
1808
1809                     const gl_enum_def_vec &alias_def_vec = alias_it->second;
1810
1811                     uint j;
1812                     for (j = 0; j < alias_def_vec.size(); j++)
1813                     {
1814                         if (alias_def_vec[j].m_name == def_vec[i].m_name)
1815                             break;
1816                     }
1817
1818                     if (j == alias_def_vec.size())
1819                     {
1820                         console::error("Bad alias enum: %s %s\n", def_vec[i].m_def.get_ptr(), def_vec[i].m_name.get_ptr());
1821                         return false;
1822                     }
1823                     if (alias_def_vec[j].m_alias_flag)
1824                     {
1825                         num_unresolved_aliases++;
1826                         continue;
1827                     }
1828
1829                     def_vec[i].m_def = alias_def_vec[j].m_def;
1830                     def_vec[i].m_alias_flag = false;
1831                 }
1832             }
1833             //printf(".");
1834         } while (num_unresolved_aliases);
1835         //printf("\n");
1836
1837         return true;
1838     }
1839
1840     void dump_to_text_file(const char *pFilename) const
1841     {
1842         FILE *pFile = vogl_fopen(pFilename, "w");
1843         if (pFile)
1844         {
1845             console::info("--- Dumping %u GL enums to file %s\n", static_cast<uint>(m_enums.size()), pFilename);
1846
1847             for (gl_enum_def_vec_map::const_iterator enum_it = m_enums.begin(); enum_it != m_enums.end(); ++enum_it)
1848             {
1849                 vogl_fprintf(pFile, "enum \"%s\"\n", enum_it->first.get_ptr());
1850                 for (uint i = 0; i < enum_it->second.size(); i++)
1851                     vogl_fprintf(pFile, "  \"%s\" = \"%s\"\n", enum_it->second[i].m_name.get_ptr(), enum_it->second[i].m_def.get_ptr());
1852             }
1853
1854             vogl_fclose(pFile);
1855         }
1856         else
1857         {
1858             console::error("Failed writing GL enums to file %s\n", pFilename);
1859         }
1860     }
1861
1862     bool dump_to_definition_macro_file(const char *pFilename, const char *pPrefix) const
1863     {
1864         gl_string_map unique_enums;
1865         for (gl_enum_def_vec_map::const_iterator enum_it = m_enums.begin(); enum_it != m_enums.end(); ++enum_it)
1866         {
1867             for (uint i = 0; i < enum_it->second.size(); i++)
1868                 unique_enums.insert(std::make_pair(enum_it->second[i].m_name, enum_it->second[i].m_def));
1869         }
1870
1871         console::info("--- Generating \"%s\":\n", pFilename);
1872
1873         FILE *pFile = vogl_fopen(pFilename, "w");
1874         if (!pFile)
1875         {
1876             console::error("%s: Failed creating file \"%s\"!\n", VOGL_METHOD_NAME, pFilename);
1877             return false;
1878         }
1879
1880         for (gl_string_map::const_iterator it = unique_enums.begin(); it != unique_enums.end(); ++it)
1881             vogl_fprintf(pFile, "#define %s_%s %s\n", pPrefix, it->first.get_ptr(), it->second.get_ptr());
1882
1883         vogl_fclose(pFile);
1884         return true;
1885     }
1886
1887     bool dump_to_description_macro_file(const char *pFilename, const char *pPrefix, const gl_types &gl_typemap, const gl_types &alt_gl_typemap) const
1888     {
1889         console::info("--- Generating \"%s\":\n", pFilename);
1890
1891         FILE *pFile = vogl_fopen(pFilename, "w");
1892         if (!pFile)
1893         {
1894             console::error("%s: Failed creating file \"%s\"!\n", VOGL_METHOD_NAME, pFilename);
1895             return false;
1896         }
1897
1898         for (gl_enum_def_vec_map::const_iterator enum_it = m_enums.begin(); enum_it != m_enums.end(); ++enum_it)
1899         {
1900             vogl_fprintf(pFile, "DEFINE_GL_ENUM_CATEGORY_BEGIN(%s)\n", enum_it->first.get_ptr());
1901
1902             for (uint i = 0; i < enum_it->second.size(); i++)
1903             {
1904                 const dynamic_string *pGLType = NULL;
1905                 pGLType = gl_typemap.find(enum_it->first.get_ptr());
1906                 if (!pGLType)
1907                     pGLType = alt_gl_typemap.find(enum_it->first.get_ptr());
1908
1909                 if (enum_it->second[i].m_define_flag)
1910                 {
1911                     vogl_fprintf(pFile, "DEFINE_GL_DEFINE_MEMBER(%s, %s, %s_%s)\n",
1912                                 pPrefix,
1913                                 enum_it->first.get_ptr(),
1914                                 pPrefix, enum_it->second[i].m_name.get_ptr());
1915                 }
1916                 else
1917                 {
1918                     vogl_fprintf(pFile, "DEFINE_GL_ENUM_MEMBER(%s, %s, \"%s\", \"%s_%s\", %s)\n",
1919                                 pPrefix,
1920                                 enum_it->first.get_ptr(),
1921                                 pGLType ? pGLType->get_ptr() : "",
1922                                 pPrefix, enum_it->second[i].m_name.get_ptr(), enum_it->second[i].m_def.get_ptr());
1923                 }
1924             }
1925
1926             vogl_fprintf(pFile, "DEFINE_GL_ENUM_CATEGORY_END(%s)\n", enum_it->first.get_ptr());
1927         }
1928
1929         vogl_fclose(pFile);
1930
1931         return true;
1932     }
1933
1934 private:
1935     gl_enum_def_vec_map m_enums;
1936 };
1937
1938 //-----------------------------------------------------------------------------------------------------------------------
1939 // class vogl_gen
1940 //-----------------------------------------------------------------------------------------------------------------------
1941 #define DEF_FUNCTION_PROTO_PARAM_STR "(a,b,c,d,e,f,g,h)"
1942
1943 class vogl_gen
1944 {
1945     apitrace_func_specs m_apitrace_gl_func_specs;
1946     gl_function_specs m_gl_xml_functions;
1947     gl_enums m_gl_enumerations;
1948     gl_enums m_glx_enumerations;
1949     gl_enums m_glx_ext_enumerations;
1950
1951     gl_function_specs m_gl_funcs;
1952     gl_function_specs m_glx_funcs;
1953     gl_function_specs m_glxext_funcs;
1954
1955     gl_function_specs m_all_gl_funcs;
1956
1957     dynamic_string_array m_unique_categories;
1958
1959     gl_string_map m_unique_ctype_enums;
1960
1961     gl_types m_gl_typemap;
1962     gl_types m_glx_typemap;
1963
1964     dynamic_string_array m_gl_so_function_exports;
1965
1966     gl_string_set m_all_gl_ctypes;
1967     gl_string_set m_all_gl_categories;
1968     gl_string_set m_all_array_sizes;
1969
1970     gl_string_map m_pointee_types;
1971
1972     dynamic_string_array m_whitelisted_funcs;
1973     dynamic_string_array m_whitelisted_displaylist_funcs;
1974     dynamic_string_array m_nullable_funcs;
1975
1976     dynamic_string_array m_simple_replay_funcs;
1977
1978     dynamic_string_array funcs_with_custom_array_size_macros;
1979     dynamic_string_array custom_return_param_array_size_macros;
1980     dynamic_string_array funcs_with_return_param_array_size_macros;
1981
1982     gl_string_set custom_array_size_macros;
1983     vogl::vector<uint> custom_array_size_macro_indices;
1984     dynamic_string_array custom_array_size_macro_names;
1985
1986     struct gl_get
1987     {
1988         gl_get()
1989             : m_min_vers(0xFFFF), m_max_vers(0)
1990         {
1991         }
1992
1993         dynamic_string m_name;
1994         uint m_min_vers;
1995         uint m_max_vers;
1996
1997         inline bool operator<(const gl_get &rhs) const
1998         {
1999             if (m_min_vers < rhs.m_min_vers)
2000                 return true;
2001             else if (m_min_vers == rhs.m_min_vers)
2002             {
2003                 if (m_max_vers < rhs.m_max_vers)
2004                     return true;
2005                 else if (m_max_vers == rhs.m_max_vers)
2006                     return m_name < rhs.m_name;
2007             }
2008             return false;
2009         }
2010     };
2011
2012     typedef vogl::hash_map<dynamic_string, gl_get> gl_get_hash_map;
2013     gl_get_hash_map m_gl_gets;
2014
2015 public:
2016     vogl_gen()
2017     {
2018     }
2019
2020     bool init()
2021     {
2022         // TODO: I'm going to move the "glspec" dir from under bin to raddebugger/glspec (or whatever)
2023         dynamic_string specdir;
2024
2025         if (g_command_line_params.get_value_as_string(specdir, "specdir"))
2026         {
2027             file_utils::change_directory(specdir.c_str());
2028             console::warning("Changing current directory to %s\n", specdir.c_str());
2029         }
2030         else if (!file_utils::does_file_exist("gl.spec"))
2031         {
2032             if (file_utils::does_file_exist("glspec/gl.spec"))
2033             {
2034                 file_utils::change_directory("glspec");
2035                 console::warning("Changing current directory to glspec\n");
2036             }
2037             else if (file_utils::does_file_exist("../bin/glspec/gl.spec"))
2038             {
2039                 file_utils::change_directory("../bin/glspec");
2040                 console::warning("Changing current directory to ../bin/glspec\n");
2041             }
2042         }
2043
2044         if (!file_utils::does_file_exist("gl.spec"))
2045         {
2046             console::error("Can't find find gl.spec, which must be in the current directory!\n");
2047             return false;
2048         }
2049
2050         // -- Load apitrace's GL function defintions, which was auto generated then hand-edited by the apitrace team - we ONLY use this for parameter namespace info and cross referencing (verification)
2051         if (!m_apitrace_gl_func_specs.parse())
2052         {
2053             console::error("Failed parsing apitrace param info file!\n");
2054             return false;
2055         }
2056
2057         // -- Load gl.xml, auto-generated from various web pages using several Python scripts
2058         if (!m_gl_xml_functions.parse_gl_xml_file("gl.xml"))
2059             return false;
2060
2061         // -- Load the various GL/GLX/GLXEXT enum spec files
2062         m_gl_enumerations.parse_file("enum.spec");
2063         m_glx_enumerations.parse_file("glxenum.spec");
2064         m_glx_ext_enumerations.parse_file("glxenumext.spec");
2065
2066         // -- Load the various GL/GLX/GLXEXT func spec files
2067         bool success = m_gl_funcs.parse_spec_file("gl.spec", cGL);
2068         if (!success)
2069         {
2070             console::error("Failed parsing gl.spec!\n");
2071             return false;
2072         }
2073         success = m_glx_funcs.parse_spec_file("glx.spec", cGLX);
2074         if (!success)
2075         {
2076             console::error("Failed parsing glx.spec!\n");
2077             return false;
2078         }
2079
2080         success = m_glxext_funcs.parse_spec_file("glxext.spec", cGLX);
2081         if (!success)
2082         {
2083             console::error("Failed parsing glxext.spec!\n");
2084             return false;
2085         }
2086
2087         // -- Clean up the GLX func definitions
2088         for (uint i = 0; i < m_glxext_funcs.size(); i++)
2089         {
2090             int glx_index = m_glx_funcs.find_index(m_glxext_funcs[i].m_name.get_ptr());
2091             if (glx_index >= 0)
2092             {
2093                 console::warning("glxext func %s overriding glx definition\n", m_glxext_funcs[i].m_name.get_ptr());
2094                 m_glx_funcs.get_funcs_vec().erase_unordered(glx_index);
2095             }
2096
2097             int gl_index = m_gl_funcs.find_index(m_glxext_funcs[i].m_name.get_ptr());
2098             if (gl_index >= 0)
2099             {
2100                 console::warning("glxext func %s overriding definition\n", m_glxext_funcs[i].m_name.get_ptr());
2101                 m_gl_funcs.get_funcs_vec().erase_unordered(gl_index);
2102             }
2103         }
2104
2105         for (uint j = 0; j < m_glxext_funcs.size(); j++)
2106         {
2107             if (m_glxext_funcs[j].m_name.ends_with("SGIX"))
2108             {
2109                 console::message("deleting glxext func %s\n", m_glxext_funcs[j].m_name.get_ptr());
2110
2111                 m_glxext_funcs.get_funcs_vec().erase_unordered(j);
2112                 j--;
2113             }
2114         }
2115
2116         // -- Parse the various spec typemap files
2117         success = m_gl_typemap.parse_file("gl.tm");
2118         if (!success)
2119         {
2120             console::error("Failed parsing gl.tm!\n");
2121             return false;
2122         }
2123
2124         success = m_glx_typemap.parse_file("glx.tm");
2125         if (!success)
2126         {
2127             console::error("Failed parsing glx.tm!\n");
2128             return false;
2129         }
2130
2131         // -- Determine the ctypes used by all the GL/GLX functions
2132         if (!determine_ctypes("gl", m_gl_funcs, m_gl_typemap, m_glx_typemap))
2133         {
2134             console::error("Failed determined gl c types!\n");
2135             return false;
2136         }
2137
2138         if (!determine_ctypes("glX", m_glx_funcs, m_glx_typemap, m_gl_typemap))
2139         {
2140             console::error("Failed determined glX c types!\n");
2141             return false;
2142         }
2143
2144         if (!determine_ctypes("glX", m_glxext_funcs, m_glx_typemap, m_gl_typemap))
2145         {
2146             console::error("Failed determined glX c types!\n");
2147             return false;
2148         }
2149
2150         // -- Create master list of all GL/GLX/GLXEXT functions
2151         m_all_gl_funcs = m_gl_funcs;
2152         m_all_gl_funcs += m_glx_funcs;
2153         m_all_gl_funcs += m_glxext_funcs;
2154
2155         // -- Determine the unique list of function API categories
2156         for (uint i = 0; i < m_all_gl_funcs.size(); i++)
2157         {
2158             if (m_unique_categories.find(m_all_gl_funcs[i].m_category) < 0)
2159                 m_unique_categories.push_back(m_all_gl_funcs[i].m_category);
2160         }
2161
2162         m_unique_categories.sort();
2163
2164         // -- Load the GL/GLX function export table, generated by dumping the headers of various drivers
2165         if (!load_gl_so_function_export_list("gl_glx_so_export_list.txt", m_gl_so_function_exports))
2166         {
2167             console::error("Failed parsing glx.tm!\n");
2168             return false;
2169         }
2170
2171         process_func_protos("gl", m_gl_funcs, m_gl_typemap, m_glx_typemap, m_gl_so_function_exports, m_all_gl_ctypes, m_all_gl_categories, m_all_array_sizes);
2172         process_func_protos("glX", m_glx_funcs, m_glx_typemap, m_gl_typemap, m_gl_so_function_exports, m_all_gl_ctypes, m_all_gl_categories, m_all_array_sizes);
2173         process_func_protos("glX", m_glxext_funcs, m_glx_typemap, m_gl_typemap, m_gl_so_function_exports, m_all_gl_ctypes, m_all_gl_categories, m_all_array_sizes);
2174
2175         // -- Create the m_unique_ctype_enums table
2176         for (uint i = 0; i < m_all_gl_funcs.size(); i++)
2177         {
2178             const gl_function_def &func = m_all_gl_funcs[i];
2179
2180             m_unique_ctype_enums.insert(std::make_pair(func.m_return_ctype_enum, func.m_return_ctype));
2181             for (uint p = 0; p < func.m_params.size(); p++)
2182                 m_unique_ctype_enums.insert(std::make_pair(func.m_params[p].m_ctype_enum, func.m_params[p].m_ctype));
2183         }
2184
2185 // -- Create the m_pointee_types table
2186 #if 0
2187                 printf("---\n");
2188                 for (uint i = 0; i < whitelisted_funcs.size(); i++)
2189                 {
2190                         int j = simple_replay_funcs.find(whitelisted_funcs[i]);
2191                         if (j < 0)
2192                                 printf("%s\n", whitelisted_funcs[i].get_ptr());
2193                 }
2194                 printf("---\n");
2195 #endif
2196
2197         for (gl_string_map::const_iterator it = m_unique_ctype_enums.begin(); it != m_unique_ctype_enums.end(); ++it)
2198         {
2199             dynamic_string ctype(it->first.get_ptr());
2200             if (!ctype.ends_with("_PTR"))
2201                 continue;
2202
2203             ctype.shorten(4);
2204
2205             if (ctype.ends_with("_CONST"))
2206                 ctype.shorten(6);
2207
2208             if (m_unique_ctype_enums.find(ctype) != m_unique_ctype_enums.end())
2209             {
2210                 m_pointee_types.insert(std::make_pair(it->first.get_ptr(), ctype));
2211             }
2212             else
2213             {
2214                 dynamic_string ctype_without_const(ctype);
2215                 int ofs = ctype_without_const.find_left("_CONST_");
2216                 if (ofs >= 0)
2217                 {
2218                     ctype_without_const.remove(ofs, 6);
2219                 }
2220                 if (m_unique_ctype_enums.find(ctype_without_const) != m_unique_ctype_enums.end())
2221                 {
2222                     m_pointee_types.insert(std::make_pair(it->first.get_ptr(), ctype_without_const));
2223                 }
2224                 else
2225                 {
2226                     dynamic_string ctype_without_const_definition(it->second);
2227
2228                     int ptr_ofs = ctype_without_const_definition.find_right('*');
2229                     if (ptr_ofs >= 0)
2230                         ctype_without_const_definition.remove(ptr_ofs, 1);
2231                     int const_ofs = ctype_without_const_definition.find_left("const");
2232                     if (const_ofs >= 0)
2233                         ctype_without_const_definition.remove(const_ofs, 5);
2234                     ctype_without_const_definition.trim();
2235
2236                     printf("Introducing new ctype from ptr to pointee: %s %s\n", ctype_without_const.get_ptr(), ctype_without_const_definition.get_ptr());
2237
2238                     m_unique_ctype_enums.insert(std::make_pair(ctype_without_const, ctype_without_const_definition));
2239                 }
2240                 m_pointee_types.insert(std::make_pair(it->first.get_ptr(), ctype_without_const));
2241             }
2242         }
2243
2244         // these are NOT actually pointers, they are just big enough to hold pointers (like intptr_t)
2245         //m_pointee_types.insert(std::make_pair("VOGL_GLINTPTR", "VOGL_GLINT"));
2246         //m_pointee_types.insert(std::make_pair("VOGL_GLINTPTRARB", "VOGL_GLINT"));
2247         //m_pointee_types.insert(std::make_pair("VOGL_GLSIZEIPTR", "VOGL_GLSIZEI"));
2248
2249         // -- Read the GL/GLX whitelisted and nullable funcs file
2250         //file_utils::read_text_file("gl_glx_whitelisted_funcs.txt", m_whitelisted_funcs, file_utils::cRTFTrim | file_utils::cRTFIgnoreEmptyLines | file_utils::cRTFIgnoreCommentedLines | file_utils::cRTFPrintWarningMessages);
2251         if (!read_regex_function_array("gl_glx_whitelisted_funcs.txt", m_whitelisted_funcs))
2252             return false;
2253
2254         // -- Read the display list whitelist
2255         //file_utils::read_text_file("gl_glx_displaylist_whitelist.txt", m_whitelisted_displaylist_funcs, file_utils::cRTFTrim | file_utils::cRTFIgnoreEmptyLines | file_utils::cRTFIgnoreCommentedLines | file_utils::cRTFPrintWarningMessages);
2256         if (!read_regex_function_array("gl_glx_displaylist_whitelist.txt", m_whitelisted_displaylist_funcs))
2257             return false;
2258
2259         //file_utils::read_text_file("gl_glx_nullable_funcs.txt", m_nullable_funcs, file_utils::cRTFTrim | file_utils::cRTFIgnoreEmptyLines | file_utils::cRTFIgnoreCommentedLines | file_utils::cRTFPrintWarningMessages);
2260         if (!read_regex_function_array("gl_glx_nullable_funcs.txt", m_nullable_funcs))
2261             return false;
2262
2263         if (!read_regex_function_array("gl_glx_simple_replay_funcs.txt", m_simple_replay_funcs))
2264             return false;
2265
2266         update_whitelisted_funcs(m_gl_funcs, m_unique_ctype_enums, m_pointee_types, m_whitelisted_funcs);
2267
2268         m_whitelisted_funcs.sort();
2269
2270         process_func_defs("gl", m_gl_funcs, m_gl_typemap, m_glx_typemap, m_gl_so_function_exports, m_whitelisted_funcs, m_nullable_funcs, funcs_with_custom_array_size_macros, custom_return_param_array_size_macros, funcs_with_return_param_array_size_macros);
2271         process_func_defs("glX", m_glx_funcs, m_glx_typemap, m_gl_typemap, m_gl_so_function_exports, m_whitelisted_funcs, m_nullable_funcs, funcs_with_custom_array_size_macros, custom_return_param_array_size_macros, funcs_with_return_param_array_size_macros);
2272         process_func_defs("glX", m_glxext_funcs, m_glx_typemap, m_gl_typemap, m_gl_so_function_exports, m_whitelisted_funcs, m_nullable_funcs, funcs_with_custom_array_size_macros, custom_return_param_array_size_macros, funcs_with_return_param_array_size_macros);
2273
2274         uint cur_func_id = 0;
2275         create_array_size_macros("gl", m_gl_funcs, m_gl_typemap, m_glx_typemap, m_gl_so_function_exports, custom_array_size_macros, custom_array_size_macro_indices, custom_array_size_macro_names, cur_func_id);
2276         create_array_size_macros("glX", m_glx_funcs, m_glx_typemap, m_gl_typemap, m_gl_so_function_exports, custom_array_size_macros, custom_array_size_macro_indices, custom_array_size_macro_names, cur_func_id);
2277         create_array_size_macros("glX", m_glxext_funcs, m_glx_typemap, m_gl_typemap, m_gl_so_function_exports, custom_array_size_macros, custom_array_size_macro_indices, custom_array_size_macro_names, cur_func_id);
2278
2279         // -- Cross reference the GL spec vs. XML files, for validation
2280         if (!validate_functions(m_gl_xml_functions, m_all_gl_funcs, m_apitrace_gl_func_specs, m_gl_typemap, m_glx_typemap))
2281         {
2282             console::error("Failed validating functions!\n");
2283             return false;
2284         }
2285
2286         if (!init_gl_gets())
2287             return false;
2288
2289         return true;
2290     }
2291
2292     bool func_regex(const char *pPattern) const
2293     {
2294         regexp r;
2295         if (!r.init(pPattern))
2296         {
2297             console::error("Bad regular expression: \"%s\", reason: \"%s\"\n", pPattern, r.get_error().get_ptr());
2298             return false;
2299         }
2300
2301         uint t = 0;
2302         for (uint func_index = 0; func_index < m_all_gl_funcs.size(); func_index++)
2303         {
2304             if (r.full_match(m_all_gl_funcs[func_index].m_full_name.get_ptr()))
2305             {
2306                 const gl_function_def &func = m_all_gl_funcs[func_index];
2307
2308                 printf("%s ", func.m_return_ctype.get_ptr());
2309                 printf("%s(", func.m_full_name.get_ptr());
2310                 for (uint j = 0; j < func.m_params.size(); j++)
2311                 {
2312                     printf("%s %s", func.m_params[j].m_ctype.get_ptr(), func.m_params[j].m_name.get_ptr());
2313                     if (j != func.m_params.size() - 1)
2314                         printf(", ");
2315                 }
2316                 printf(");\n");
2317                 t++;
2318             }
2319         }
2320         printf("Found %u results\n", t);
2321
2322         return true;
2323     }
2324
2325     bool param_regex(const char *pPattern) const
2326     {
2327         regexp r;
2328         if (!r.init(pPattern))
2329         {
2330             console::error("Bad regular expression: \"%s\", reason: \"%s\"\n", pPattern, r.get_error().get_ptr());
2331             return false;
2332         }
2333
2334         uint t = 0;
2335         for (uint func_index = 0; func_index < m_all_gl_funcs.size(); func_index++)
2336         {
2337             const gl_function_def &func_def = m_all_gl_funcs[func_index];
2338
2339             for (uint param_index = 0; param_index < func_def.m_params.size(); param_index++)
2340             {
2341                 if (r.full_match(func_def.m_params[param_index].m_name.get_ptr()))
2342                 {
2343                     printf("%s %u %s\n", func_def.m_full_name.get_ptr(), param_index, func_def.m_params[param_index].m_name.get_ptr());
2344                     t++;
2345                 }
2346             }
2347         }
2348         printf("Found %u results\n", t);
2349
2350         return true;
2351     }
2352
2353     bool category_regex(const char *pPattern) const
2354     {
2355         regexp r;
2356         if (!r.init(pPattern))
2357         {
2358             console::error("Bad regular expression: \"%s\", reason: \"%s\"\n", pPattern, r.get_error().get_ptr());
2359             return false;
2360         }
2361
2362         uint t = 0;
2363         for (uint func_index = 0; func_index < m_all_gl_funcs.size(); func_index++)
2364         {
2365             const gl_function_def &func_def = m_all_gl_funcs[func_index];
2366
2367             if (r.full_match(func_def.m_category.get_ptr()))
2368             {
2369                 printf("%s %s\n", func_def.m_full_name.get_ptr(), func_def.m_category.get_ptr());
2370                 t++;
2371             }
2372         }
2373         printf("Found %u results\n", t);
2374
2375         return true;
2376     }
2377
2378     bool ctype_regex(const char *pPattern) const
2379     {
2380         regexp r;
2381         if (!r.init(pPattern))
2382         {
2383             console::error("Bad regular expression: \"%s\", reason: \"%s\"\n", pPattern, r.get_error().get_ptr());
2384             return false;
2385         }
2386
2387         uint t = 0;
2388         for (uint func_index = 0; func_index < m_all_gl_funcs.size(); func_index++)
2389         {
2390             const gl_function_def &func_def = m_all_gl_funcs[func_index];
2391
2392             if (r.full_match(func_def.m_return_ctype.get_ptr()))
2393             {
2394                 printf("%s return %s\n", func_def.m_full_name.get_ptr(), func_def.m_return_ctype.get_ptr());
2395                 t++;
2396             }
2397
2398             for (uint param_index = 0; param_index < func_def.m_params.size(); param_index++)
2399             {
2400                 if (r.full_match(func_def.m_params[param_index].m_ctype.get_ptr()))
2401                 {
2402                     printf("%s %u %s %s\n", func_def.m_full_name.get_ptr(), param_index, func_def.m_params[param_index].m_name.get_ptr(), func_def.m_params[param_index].m_ctype.get_ptr());
2403                     t++;
2404                 }
2405             }
2406         }
2407         printf("Found %u results\n", t);
2408
2409         return true;
2410     }
2411
2412     bool namespace_regex(const char *pPattern) const
2413     {
2414         regexp r;
2415         if (!r.init(pPattern))
2416         {
2417             console::error("Bad regular expression: \"%s\", reason: \"%s\"\n", pPattern, r.get_error().get_ptr());
2418             return false;
2419         }
2420
2421         uint t = 0;
2422         for (uint func_index = 0; func_index < m_apitrace_gl_func_specs.size(); func_index++)
2423         {
2424             const apitrace_gl_func_def &func_def = m_apitrace_gl_func_specs[func_index];
2425
2426             if (r.full_match(vogl_get_namespace_name(func_def.m_return_namespace)))
2427             {
2428                 printf("%s return %s\n", func_def.m_name.get_ptr(), vogl_get_namespace_name(func_def.m_return_namespace));
2429                 t++;
2430             }
2431
2432             for (uint param_index = 0; param_index < func_def.m_params.size(); param_index++)
2433             {
2434                 const apitrace_gl_func_param_def &param = func_def.m_params[param_index];
2435
2436                 if (r.full_match(vogl_get_namespace_name(param.m_namespace)))
2437                 {
2438                     printf("%s %u %s\n", func_def.m_name.get_ptr(), param_index, vogl_get_namespace_name(param.m_namespace));
2439                     t++;
2440                 }
2441             }
2442         }
2443         printf("Found %u results\n", t);
2444
2445         return true;
2446     }
2447
2448     bool dump_debug_files() const
2449     {
2450         m_gl_enumerations.dump_to_text_file("dbg_enums.txt");
2451         m_glx_enumerations.dump_to_text_file("dbg_glx_enums.txt");
2452         m_glx_ext_enumerations.dump_to_text_file("dbg_glx_ext_enums.txt");
2453
2454         // -- Dump the definitions for debugging
2455         m_gl_xml_functions.dump_to_file("dbg_gl_xml_funcs.txt");
2456         m_gl_funcs.dump_to_file("dbg_gl_funcs.txt");
2457         m_glx_funcs.dump_to_file("dbg_glx_funcs.txt");
2458         m_glxext_funcs.dump_to_file("dbg_glxext_funcs.txt");
2459
2460         // -- Dump the spec typemap files, for debugging
2461         m_gl_typemap.dump_to_file("dbg_gl_typemap.txt");
2462         m_glx_typemap.dump_to_file("dbg_glx_typemap.txt");
2463
2464         m_all_gl_funcs.dump_to_file("dbg_gl_all_funcs.txt");
2465
2466         FILE *pFile;
2467
2468         // Write a simple macro file line this:
2469         //GL_FUNC(OpenGL,true,GLenum,glGetError,(void),())
2470         //GL_FUNC_VOID(OpenGL,true,glActiveTexture,(GLenum a),(a))
2471         pFile = fopen_and_log("dbg_gl_glx_simple_func_macros.txt", "w");
2472         for (uint i = 0; i < m_all_gl_funcs.size(); i++)
2473         {
2474             const gl_function_def &def = m_all_gl_funcs[i];
2475             if (def.m_return == "void")
2476                 fprintf(pFile, "GL_FUNC_VOID(%s,%s,(%s),(%s))\n", def.get_lib_name(), def.m_full_name.get_ptr(), def.get_param_proto().get_ptr(), def.get_param_args().get_ptr());
2477             else
2478                 fprintf(pFile, "GL_FUNC(%s,%s,%s,(%s),(%s))\n", def.get_lib_name(), def.m_return_ctype.get_ptr(), def.m_full_name.get_ptr(), def.get_param_proto().get_ptr(), def.get_param_args().get_ptr());
2479         }
2480         fclose(pFile);
2481
2482         pFile = fopen_and_log("dbg_gl_glx_types.txt", "w");
2483         for (gl_string_set::const_iterator it = m_all_gl_ctypes.begin(); it != m_all_gl_ctypes.end(); ++it)
2484             vogl_fprintf(pFile, "%s\n", it->get_ptr());
2485         vogl_fclose(pFile);
2486
2487         pFile = fopen_and_log("dbg_gl_glx_array_sizes.txt", "w");
2488         for (gl_string_set::const_iterator it = m_all_array_sizes.begin(); it != m_all_array_sizes.end(); ++it)
2489             vogl_fprintf(pFile, "%s\n", it->get_ptr());
2490         vogl_fclose(pFile);
2491
2492         printf("\n");
2493         printf("--- Functions with custom array size macros:\n");
2494         for (uint i = 0; i < funcs_with_custom_array_size_macros.size(); i++)
2495             printf("%s\n", funcs_with_custom_array_size_macros[i].get_ptr());
2496         printf("---\n");
2497
2498         printf("--- Whitelisted functions with custom array size macros:\n");
2499         for (uint i = 0; i < funcs_with_custom_array_size_macros.size(); i++)
2500         {
2501             if (scan_dynamic_string_array_for_string(m_whitelisted_funcs, funcs_with_custom_array_size_macros[i].get_ptr(), true) < 0)
2502                 continue;
2503             printf("%s\n", funcs_with_custom_array_size_macros[i].get_ptr());
2504         }
2505         printf("---\n");
2506
2507         printf("--- All categories:\n");
2508         for (uint i = 0; i < m_unique_categories.size(); i++)
2509             printf("%s\n", m_unique_categories[i].get_ptr());
2510         printf("---\n");
2511
2512         // -- Write the final whitelist to a file for debugging
2513         file_utils::write_text_file("dbg_final_gl_glx_whitelisted_funcs.txt", m_whitelisted_funcs, true);
2514
2515         VOGL_ASSERT(m_whitelisted_funcs.is_sorted());
2516
2517         for (uint i = 0; i < m_unique_categories.size(); i++)
2518         {
2519             dynamic_string_array missing_funcs;
2520
2521             bool are_any_whitelisted = false;
2522             for (uint j = 0; j < m_all_gl_funcs.size(); j++)
2523             {
2524                 const gl_function_def &func = m_all_gl_funcs[j];
2525                 if (func.m_category != m_unique_categories[i])
2526                     continue;
2527
2528                 bool is_whitelisted = m_whitelisted_funcs.find_sorted(func.m_full_name) >= 0;
2529
2530                 if (!is_whitelisted)
2531                     missing_funcs.push_back(func.m_full_name);
2532                 else
2533                     are_any_whitelisted = true;
2534             }
2535
2536             if (missing_funcs.size())
2537             {
2538                 printf("--- Non-whitelisted funcs for %s category %s:\n", are_any_whitelisted ? "partially supported" : "unsupported", m_unique_categories[i].get_ptr());
2539                 for (uint j = 0; j < missing_funcs.size(); j++)
2540                     printf("%s\n", missing_funcs[j].get_ptr());
2541                 printf("---\n");
2542             }
2543             else
2544             {
2545                 printf("--- Full support for category: %s\n", m_unique_categories[i].get_ptr());
2546             }
2547         }
2548
2549         return true;
2550     }
2551
2552     static FILE *fopen_and_log(const char *pFilename, const char *pMode)
2553     {
2554         FILE *pFile = vogl_fopen(pFilename, pMode);
2555         if (!pFile)
2556         {
2557             console::error("Failed opening file \"%s\" for mode %s\n", pFilename, pMode);
2558             return NULL;
2559         }
2560
2561         console::info("--- Generating \"%s\":\n", pFilename);
2562         return pFile;
2563     }
2564
2565     bool generate() const
2566     {
2567         if (!m_gl_enumerations.dump_to_definition_macro_file("gl_enums.inc", "GL"))
2568             return false;
2569         if (!m_glx_enumerations.dump_to_definition_macro_file("glx_enums.inc", "GLX"))
2570             return false;
2571         if (!m_glx_ext_enumerations.dump_to_definition_macro_file("glx_ext_enums.inc", "GLX"))
2572             return false;
2573
2574         if (!m_gl_enumerations.dump_to_description_macro_file("gl_enum_desc.inc", "GL", m_gl_typemap, m_glx_typemap))
2575             return false;
2576         if (!m_glx_enumerations.dump_to_description_macro_file("glx_enum_desc.inc", "GLX", m_glx_typemap, m_gl_typemap))
2577             return false;
2578         if (!m_glx_ext_enumerations.dump_to_description_macro_file("glx_ext_desc.inc", "GLX", m_glx_typemap, m_gl_typemap))
2579             return false;
2580
2581         // -- Generate the gl_glx_protos.inc include file
2582         FILE *pFile = fopen_and_log("gl_glx_protos.inc", "w");
2583         if (!pFile)
2584         {
2585             console::error("Failed creating file gl_glx_protos.inc!\n");
2586             return false;
2587         }
2588         dump_func_proto_macros(pFile, "gl", m_gl_funcs, m_gl_typemap, m_glx_typemap, m_gl_so_function_exports);
2589         dump_func_proto_macros(pFile, "glX", m_glx_funcs, m_glx_typemap, m_gl_typemap, m_gl_so_function_exports);
2590         dump_func_proto_macros(pFile, "glX", m_glxext_funcs, m_glx_typemap, m_gl_typemap, m_gl_so_function_exports);
2591         vogl_fprintf(pFile, "#undef DEF_PROTO_EXPORTED\n");
2592         vogl_fprintf(pFile, "#undef DEF_PROTO_EXPORTED_VOID\n");
2593         vogl_fprintf(pFile, "#undef DEF_PROTO_INTERNAL\n");
2594         vogl_fprintf(pFile, "#undef DEF_PROTO_INTERNAL_VOID\n");
2595         vogl_fprintf(pFile, "#undef DEF_PROTO\n");
2596         vogl_fprintf(pFile, "#undef DEF_PROTO_VOID\n");
2597         vogl_fclose(pFile);
2598
2599         // -- Generate the gl_glx_ctypes.inc include file
2600         pFile = fopen_and_log("gl_glx_ctypes.inc", "w");
2601         vogl_fprintf(pFile, "DEF_TYPE(VOGL_INVALID_CTYPE, int)\n");
2602         for (gl_string_map::const_iterator it = m_unique_ctype_enums.begin(); it != m_unique_ctype_enums.end(); ++it)
2603             vogl_fprintf(pFile, "DEF_TYPE(%s, %s)\n", it->first.get_ptr(), it->second.get_ptr());
2604         vogl_fclose(pFile);
2605
2606         // -- Generate the gl_glx_ctypes_ptr_to_pointee.inc include file
2607         pFile = fopen_and_log("gl_glx_ctypes_ptr_to_pointee.inc", "w");
2608         for (gl_string_map::const_iterator it = m_pointee_types.begin(); it != m_pointee_types.end(); ++it)
2609             vogl_fprintf(pFile, "DEF_PTR_TO_POINTEE_TYPE(%s, %s)\n", it->first.get_ptr(), it->second.get_ptr());
2610         vogl_fclose(pFile);
2611
2612         // -- Generate the gl_glx_simple_replay_funcs.inc simple replay funcs file, and update the whitelist
2613         generate_simple_replay_funcs(m_all_gl_funcs, m_unique_ctype_enums, m_pointee_types, m_whitelisted_funcs);
2614
2615         // -- Generate replayer helper macros
2616         generate_replay_func_load_macros(m_all_gl_funcs, m_unique_ctype_enums, m_pointee_types, m_whitelisted_funcs);
2617
2618         // -- Generate the gl_glx_func_defs.inc include file
2619         pFile = fopen_and_log("gl_glx_func_defs.inc", "w");
2620         if (!pFile)
2621         {
2622             console::error("Failed creating file gl_glx_func_defs.inc!\n");
2623             return false;
2624         }
2625         dump_inc_file_header(pFile);
2626         dump_func_def_macros(pFile, "gl", m_gl_funcs, m_gl_typemap, m_glx_typemap, m_gl_so_function_exports, m_whitelisted_funcs, m_nullable_funcs);
2627         dump_func_def_macros(pFile, "glX", m_glx_funcs, m_glx_typemap, m_gl_typemap, m_gl_so_function_exports, m_whitelisted_funcs, m_nullable_funcs);
2628         dump_func_def_macros(pFile, "glX", m_glxext_funcs, m_glx_typemap, m_gl_typemap, m_gl_so_function_exports, m_whitelisted_funcs, m_nullable_funcs);
2629         dump_function_def_undef_macros(pFile);
2630         vogl_fclose(pFile);
2631
2632         // -- Generate the gl_glx_func_return_param_array_size_macros.inc include file
2633         pFile = fopen_and_log("gl_glx_func_return_param_array_size_macros.inc", "w");
2634         if (!pFile)
2635         {
2636             console::error("Failed creating file gl_glx_func_return_param_array_size_macros.inc!\n");
2637             return false;
2638         }
2639         for (uint i = 0; i < custom_return_param_array_size_macros.size(); i++)
2640         {
2641             dynamic_string macro_name(custom_return_param_array_size_macros[i]);
2642             int n = macro_name.find_left('(');
2643             if (n >= 0)
2644                 macro_name.truncate(n);
2645
2646             int num_params = custom_return_param_array_size_macros[i].count_char(',') + 1;
2647
2648             dynamic_string params("(");
2649             for (int j = 0; j < num_params; j++)
2650             {
2651                 if (j)
2652                     params.append_char(',');
2653                 params.append_char((char)('a' + j));
2654             }
2655             params += ")";
2656
2657             vogl_fprintf(pFile, "#ifndef %s\n", macro_name.get_ptr());
2658             vogl_fprintf(pFile, "   #define %s%s -1\n", macro_name.get_ptr(), params.get_ptr());
2659             vogl_fprintf(pFile, "#endif\n");
2660         }
2661         vogl_fclose(pFile);
2662
2663         // -- Generate the gl_glx_func_descs.inc include file
2664         pFile = fopen_and_log("gl_glx_func_descs.inc", "w");
2665         dump_inc_file_header(pFile);
2666         dump_func_desc_macros(pFile, "gl", m_gl_funcs, m_gl_typemap, m_glx_typemap, m_apitrace_gl_func_specs, m_gl_so_function_exports, m_whitelisted_funcs, m_nullable_funcs, m_whitelisted_displaylist_funcs);
2667         dump_func_desc_macros(pFile, "glX", m_glx_funcs, m_glx_typemap, m_gl_typemap, m_apitrace_gl_func_specs, m_gl_so_function_exports, m_whitelisted_funcs, m_nullable_funcs, m_whitelisted_displaylist_funcs);
2668         dump_func_desc_macros(pFile, "glX", m_glxext_funcs, m_glx_typemap, m_gl_typemap, m_apitrace_gl_func_specs, m_gl_so_function_exports, m_whitelisted_funcs, m_nullable_funcs, m_whitelisted_displaylist_funcs);
2669         dump_function_def_undef_macros(pFile);
2670         vogl_fclose(pFile);
2671
2672         pFile = fopen_and_log("gl_glx_categories.inc", "w");
2673         for (gl_string_set::const_iterator it = m_all_gl_categories.begin(); it != m_all_gl_categories.end(); ++it)
2674             vogl_fprintf(pFile, "DEF_CATEGORY(%s)\n", it->get_ptr());
2675         vogl_fclose(pFile);
2676
2677         // -- Generate the gl_glx_array_size_macros.inc include file
2678         pFile = fopen_and_log("gl_glx_array_size_macros.inc", "w");
2679         for (gl_string_set::const_iterator it = custom_array_size_macros.begin(); it != custom_array_size_macros.end(); ++it)
2680         {
2681             dynamic_string macro_name(it->get_ptr());
2682             macro_name.truncate(macro_name.find_left('('));
2683             vogl_fprintf(pFile, "#ifndef %s\n", macro_name.get_ptr());
2684             vogl_fprintf(pFile, "   #define %s%s -1\n", macro_name.get_ptr(), DEF_FUNCTION_PROTO_PARAM_STR);
2685             vogl_fprintf(pFile, "#endif\n");
2686         }
2687         vogl_fclose(pFile);
2688
2689         // -- Generate the gl_glx_array_size_macros_validator.inc include file
2690         pFile = fopen_and_log("gl_glx_array_size_macros_validator.inc", "w");
2691         for (uint i = 0; i < custom_array_size_macro_indices.size(); i++)
2692         {
2693             uint j = custom_array_size_macro_indices[i];
2694             uint func_index = j >> 16;
2695             uint param_index = j & 0xFFFF;
2696             VOGL_NOTE_UNUSED(param_index);
2697
2698             const dynamic_string &macro_name = custom_array_size_macro_names[i];
2699
2700             vogl_fprintf(pFile, "#ifndef DEF_FUNCTION_CUSTOM_HANDLER_%s%s\n", g_lib_api_prefixes[m_all_gl_funcs[func_index].m_lib], m_all_gl_funcs[func_index].m_name.get_ptr());
2701             vogl_fprintf(pFile, "   #ifdef %s\n", macro_name.get_ptr());
2702             vogl_fprintf(pFile, "      VALIDATE_ARRAY_SIZE_MACRO_DEFINED(%s, 0x%08X)\n", macro_name.get_ptr(), custom_array_size_macro_indices[i]);
2703             vogl_fprintf(pFile, "   #else\n");
2704             vogl_fprintf(pFile, "      VALIDATE_ARRAY_SIZE_MACRO_NOT_DEFINED(%s, 0x%08X)\n", macro_name.get_ptr(), custom_array_size_macro_indices[i]);
2705             vogl_fprintf(pFile, "   #endif\n");
2706             vogl_fprintf(pFile, "#endif\n");
2707         }
2708         vogl_fclose(pFile);
2709
2710         // -- Generate the gl_glx_custom_return_param_array_size_macro_validator.inc include file
2711         pFile = fopen_and_log("gl_glx_custom_return_param_array_size_macro_validator.inc", "w");
2712         for (uint i = 0; i < custom_return_param_array_size_macros.size(); i++)
2713         {
2714             dynamic_string macro_name(custom_return_param_array_size_macros[i]);
2715             int n = macro_name.find_left('(');
2716             if (n >= 0)
2717                 macro_name.truncate(n);
2718
2719             vogl_fprintf(pFile, "#ifdef %s\n", macro_name.get_ptr());
2720             vogl_fprintf(pFile, "   CUSTOM_FUNC_RETURN_PARAM_ARRAY_SIZE_HANDLER_DEFINED(%s, %s)\n", macro_name.get_ptr(), funcs_with_return_param_array_size_macros[i].get_ptr());
2721             vogl_fprintf(pFile, "#else\n");
2722             vogl_fprintf(pFile, "   CUSTOM_FUNC_RETURN_PARAM_ARRAY_SIZE_HANDLER_NOT_DEFINED(%s, %s)\n", macro_name.get_ptr(), funcs_with_return_param_array_size_macros[i].get_ptr());
2723             vogl_fprintf(pFile, "#endif\n");
2724         }
2725         vogl_fclose(pFile);
2726
2727         // -- Generate the gl_glx_custom_func_handler_validator.inc include file
2728         pFile = fopen_and_log("gl_glx_custom_func_handler_validator.inc", "w");
2729         for (uint i = 0; i < m_all_gl_funcs.size(); i++)
2730         {
2731             vogl_fprintf(pFile, "#ifdef DEF_FUNCTION_CUSTOM_HANDLER_%s%s\n", g_lib_api_prefixes[m_all_gl_funcs[i].m_lib], m_all_gl_funcs[i].m_name.get_ptr());
2732             vogl_fprintf(pFile, "   CUSTOM_FUNC_HANDLER_DEFINED(%u)\n", i);
2733             vogl_fprintf(pFile, "#else\n");
2734             vogl_fprintf(pFile, "   CUSTOM_FUNC_HANDLER_NOT_DEFINED(%u)\n", i);
2735             vogl_fprintf(pFile, "#endif\n");
2736         }
2737         vogl_fclose(pFile);
2738
2739         // -- Generate the gl_glx_array_size_macro_func_param_indices.inc include file
2740         pFile = fopen_and_log("gl_glx_array_size_macro_func_param_indices.inc", "w");
2741         for (uint i = 0; i < custom_array_size_macro_indices.size(); i++)
2742         {
2743             if (i)
2744                 vogl_fprintf(pFile, ",");
2745             vogl_fprintf(pFile, "0x%08X", custom_array_size_macro_indices[i]);
2746             if ((i & 31) == 31)
2747                 vogl_fprintf(pFile, "\n");
2748         }
2749         vogl_fprintf(pFile, "\n");
2750         vogl_fclose(pFile);
2751
2752         if (!generate_gl_gets_inc_file())
2753             return false;
2754
2755         if (!generate_libvogltrace_export_script())
2756             return false;
2757
2758         return true;
2759     }
2760
2761 private:
2762     //-----------------------------------------------------------------------------------------------------------------------
2763     // init_gl_gets
2764     //-----------------------------------------------------------------------------------------------------------------------
2765     bool init_gl_gets()
2766     {
2767         static const struct gl_get_files
2768         {
2769             const char *m_pFilename;
2770             uint m_vers;
2771         } s_gl_get_files[] =
2772               {
2773                   { "gl10_gets.txt", 0x10 },
2774                   { "gl15_gets.txt", 0x15 },
2775                   { "gl21_gets.txt", 0x21 },
2776                   { "gl33_gets.txt", 0x33 },
2777                   { "gl40_gets.txt", 0x40 },
2778                   { "gl41_gets.txt", 0x41 },
2779                   { "gl42_gets.txt", 0x42 },
2780                   { "gl43_gets.txt", 0x43 }
2781               };
2782
2783         for (uint file_iter = 0; file_iter < sizeof(s_gl_get_files) / sizeof(s_gl_get_files[0]); file_iter++)
2784         {
2785             const char *pFilename = s_gl_get_files[file_iter].m_pFilename;
2786
2787             //         typedef vogl::hash_map<dynamic_string, gl_get> gl_get_hash_map;
2788             //         gl_get_hash_map m_gl_gets;
2789
2790             dynamic_string_array get_names;
2791
2792             if (!file_utils::read_text_file(pFilename, get_names, file_utils::cRTFTrim | file_utils::cRTFIgnoreEmptyLines | file_utils::cRTFIgnoreCommentedLines | file_utils::cRTFPrintErrorMessages))
2793                 return false;
2794
2795             for (uint i = 0; i < get_names.size(); i++)
2796             {
2797                 if ((get_names[i].toupper().compare(get_names[i], true) != 0) || (get_names[i].contains(' ')))
2798                 {
2799                     console::error("In file %s, enum name is invalid: \"%s\"\n", pFilename, get_names[i].get_ptr());
2800                     return false;
2801                 }
2802
2803                 gl_get_hash_map::insert_result ins_res(m_gl_gets.insert(get_names[i], gl_get()));
2804                 gl_get &gl_get_obj = ins_res.first->second;
2805                 gl_get_obj.m_name = get_names[i];
2806                 gl_get_obj.m_min_vers = vogl::math::minimum(gl_get_obj.m_min_vers, s_gl_get_files[file_iter].m_vers);
2807                 gl_get_obj.m_max_vers = vogl::math::maximum(gl_get_obj.m_max_vers, s_gl_get_files[file_iter].m_vers);
2808             }
2809         }
2810
2811         //for (gl_get_hash_map::const_iterator it = m_gl_gets.begin(); it != m_gl_gets.end(); ++it)
2812         //   printf("%s 0x%04X 0x%04X\n", it->first.get_ptr(), it->second.m_min_vers, it->second.m_max_vers);
2813
2814         return true;
2815     }
2816
2817     bool generate_libvogltrace_export_script() const
2818     {
2819 #if 0
2820                 // We're writing an anonymous version map on purpose, otherwise bad shit happens in some apps!
2821                 {
2822 global:
2823                         OpenDebugManager;
2824                         OpenDebugSession;
2825 local:
2826                         *;
2827                 };
2828 #endif
2829
2830         const char *pFilename = "libvogltrace_linker_script.txt";
2831         cfile_stream export_script(pFilename, cDataStreamWritable);
2832
2833         console::info("--- Generating \"%s\":\n", pFilename);
2834
2835         export_script.puts("{\n");
2836         export_script.puts("  global:\n");
2837
2838         for (uint i = 0; i < m_gl_so_function_exports.size(); i++)
2839             export_script.printf("    %s;\n", m_gl_so_function_exports[i].get_ptr());
2840
2841         dynamic_string_array nongenerated_exports;
2842         file_utils::read_text_file("gl_glx_nongenerated_so_export_list.txt", nongenerated_exports, file_utils::cRTFPrintWarningMessages);
2843
2844         for (uint i = 0; i < nongenerated_exports.size(); i++)
2845             export_script.printf("    %s;\n", nongenerated_exports[i].get_ptr());
2846
2847         export_script.puts("  local:\n");
2848         export_script.puts("    *;\n");
2849         export_script.puts("};\n");
2850
2851         return true;
2852     }
2853
2854     //-----------------------------------------------------------------------------------------------------------------------
2855     // generate_gl_gets_inc_file
2856     //-----------------------------------------------------------------------------------------------------------------------
2857     bool generate_gl_gets_inc_file() const
2858     {
2859         // Note: I used this to generate our first gl_gets.inc file, which then had to be hand edited.
2860         const char *pFilename = "gl_gets_approx.inc";
2861         cfile_stream gl_gets_inc(pFilename, cDataStreamWritable);
2862
2863         if (!gl_gets_inc.is_opened())
2864         {
2865             console::error("Failed creating file %s!\n", pFilename);
2866             return false;
2867         }
2868
2869         console::info("--- Generating \"%s\":\n", pFilename);
2870
2871         vogl::vector<gl_get> sorted_gets;
2872         for (gl_get_hash_map::const_iterator it = m_gl_gets.begin(); it != m_gl_gets.end(); ++it)
2873             sorted_gets.push_back(it->second);
2874         sorted_gets.sort();
2875
2876         int prev_min_vers = -1;
2877         int prev_max_vers = -1;
2878         for (uint i = 0; i < sorted_gets.size(); i++)
2879         {
2880             if ((prev_min_vers != static_cast<int>(sorted_gets[i].m_min_vers)) || (prev_max_vers != static_cast<int>(sorted_gets[i].m_max_vers)))
2881             {
2882                 gl_gets_inc.printf("// Start of version %u.%u - %u.%u\n", sorted_gets[i].m_min_vers >> 4, sorted_gets[i].m_min_vers & 0xF, sorted_gets[i].m_max_vers >> 4, sorted_gets[i].m_max_vers & 0xF);
2883                 prev_min_vers = sorted_gets[i].m_min_vers;
2884                 prev_max_vers = sorted_gets[i].m_max_vers;
2885             }
2886             gl_gets_inc.printf("DEFINE_GL_GET(%s, 0x%04X, 0x%04X)\n", sorted_gets[i].m_name.get_ptr(), sorted_gets[i].m_min_vers, sorted_gets[i].m_max_vers);
2887         }
2888
2889         return true;
2890     }
2891
2892     //-----------------------------------------------------------------------------------------------------------------------
2893     // ensure_gl_exports_are_defined
2894     //-----------------------------------------------------------------------------------------------------------------------
2895     bool ensure_gl_exports_are_defined(gl_function_specs &gl_funcs, const gl_function_specs &glx_funcs, const gl_function_specs &glxext_funcs)
2896     {
2897         cfile_stream list_file("gl_glx_so_export_list.txt", cDataStreamReadable);
2898         if (!list_file.is_opened())
2899             return false;
2900
2901         dynamic_string line_str;
2902         while (list_file.get_remaining())
2903         {
2904             if (!list_file.read_line(line_str))
2905                 break;
2906
2907             line_str.trim();
2908             if (line_str.is_empty())
2909                 continue;
2910
2911             dynamic_string func;
2912             const gl_function_specs *pSpecs = NULL;
2913             if (line_str.find_left("glX") == 0)
2914             {
2915                 func.set(line_str).right(3);
2916                 pSpecs = &glx_funcs;
2917             }
2918             else if (line_str.find_left("gl") == 0)
2919             {
2920                 func.set(line_str).right(2);
2921                 pSpecs = &gl_funcs;
2922             }
2923
2924             if (!pSpecs)
2925             {
2926                 console::warning("Unrecognized SO export: %s\n", line_str.get_ptr());
2927                 continue;
2928             }
2929
2930             const gl_function_def *pFunc = pSpecs->find(func.get_ptr());
2931             if ((!pFunc) && (pSpecs == &glx_funcs))
2932             {
2933                 pSpecs = &glxext_funcs;
2934                 pFunc = pSpecs->find(func.get_ptr());
2935             }
2936
2937             if (!pFunc)
2938             {
2939                 if (func.ends_with("OES", true) || func.ends_with("x", true) || func.ends_with("NV", true) || func.ends_with("NVX") ||
2940                     func.ends_with("SGI") || func.ends_with("EXT") || func.ends_with("X") || func.ends_with("xv") || func.ends_with("Autodesk") ||
2941                     func.ends_with("WIN"))
2942                 {
2943                     //console::warning("Skipping missing SO export: %s\n", line_str.get_ptr());
2944                     continue;
2945                 }
2946
2947                 console::warning("Can't find SO export in spec files: %s\n", line_str.get_ptr());
2948                 continue;
2949             }
2950
2951             //printf("Found %s\n", pFunc->m_name.get_ptr());
2952         }
2953
2954         return true;
2955     }
2956
2957     //-----------------------------------------------------------------------------------------------------------------------
2958     // load_gl_so_function_export_list
2959     //-----------------------------------------------------------------------------------------------------------------------
2960     bool load_gl_so_function_export_list(const char *pFilename, dynamic_string_array &gl_so_function_exports)
2961     {
2962         cfile_stream list_file(pFilename, cDataStreamReadable);
2963         if (!list_file.is_opened())
2964             return false;
2965
2966         dynamic_string line_str;
2967         while (list_file.get_remaining())
2968         {
2969             if (!list_file.read_line(line_str))
2970                 break;
2971
2972             line_str.trim();
2973             if (line_str.is_empty())
2974                 continue;
2975
2976             gl_so_function_exports.push_back(line_str);
2977         }
2978
2979         gl_so_function_exports.sort();
2980
2981         return true;
2982     }
2983
2984     //-----------------------------------------------------------------------------------------------------------------------
2985     // translate_ctype_to_ctype_enum
2986     //-----------------------------------------------------------------------------------------------------------------------
2987     dynamic_string translate_ctype_to_ctype_enum(dynamic_string ctype)
2988     {
2989         ctype.trim().toupper().replace("_", "");
2990
2991         uint num_found;
2992         do
2993         {
2994             ctype.replace(" *", "*", true, &num_found);
2995         } while (num_found);
2996
2997         do
2998         {
2999             ctype.replace("  ", " ", true, &num_found);
3000         } while (num_found);
3001
3002         ctype.replace(" ", "_");
3003         ctype.replace("*", "_PTR");
3004
3005         return "VOGL_" + ctype;
3006     }
3007
3008     //-----------------------------------------------------------------------------------------------------------------------
3009     // determine_ctypes
3010     //-----------------------------------------------------------------------------------------------------------------------
3011     bool determine_ctypes(const char *pFunc_prefix, gl_function_specs &gl_funcs, const gl_types &typemap, const gl_types &alt_typemap)
3012     {
3013         for (uint func_index = 0; func_index < gl_funcs.size(); func_index++)
3014         {
3015             gl_function_def &func = gl_funcs[func_index];
3016
3017             dynamic_string full_func_name(cVarArg, "%s%s", pFunc_prefix, func.m_name.get_ptr());
3018
3019             if (func.m_return == "void")
3020                 func.m_return_ctype = "void";
3021             else
3022             {
3023                 const dynamic_string *pCType = typemap.find(func.m_return);
3024                 if (!pCType)
3025                     pCType = alt_typemap.find(func.m_return);
3026                 if (!pCType)
3027                 {
3028                     console::warning("Unable to map spec type %s\n", func.m_return.get_ptr());
3029                     return false;
3030                 }
3031
3032                 func.m_return_ctype = *pCType;
3033             }
3034             func.m_return_ctype_enum = translate_ctype_to_ctype_enum(func.m_return_ctype);
3035
3036             for (uint param_index = 0; param_index < func.m_params.size(); param_index++)
3037             {
3038                 gl_function_param &param = func.m_params[param_index];
3039
3040                 const dynamic_string *pCType = typemap.find(param.m_type);
3041                 if (!pCType)
3042                     pCType = alt_typemap.find(param.m_type);
3043                 if (!pCType)
3044                 {
3045                     console::warning("Unable to map spec type %s\n", param.m_type.get_ptr());
3046                     return false;
3047                 }
3048
3049                 dynamic_string type_prefix;
3050
3051                 dynamic_string type_suffix("");
3052                 if ((param.m_semantic == "array") || (param.m_semantic == "reference"))
3053                 {
3054                     type_suffix = " *";
3055
3056                     if (param.m_direction == "in")
3057                     {
3058                         if (!pCType->ends_with("const"))
3059                             type_prefix = "const ";
3060                     }
3061                 }
3062
3063                 dynamic_string full_ctype(cVarArg, "%s%s%s", type_prefix.get_ptr(), pCType->get_ptr(), type_suffix.get_ptr());
3064
3065                 param.m_ctype = full_ctype;
3066                 param.m_ctype_enum = translate_ctype_to_ctype_enum(full_ctype);
3067             }
3068         }
3069
3070         return true;
3071     }
3072
3073     //-----------------------------------------------------------------------------------------------------------------------
3074     // get_func_proto_macro
3075     //-----------------------------------------------------------------------------------------------------------------------
3076     dynamic_string get_func_proto_macro(const char *pFunc_prefix, const gl_function_def &func, const dynamic_string_array &sorted_gl_so_function_exports) const
3077     {
3078         dynamic_string proto;
3079
3080         dynamic_string full_func_name(cVarArg, "%s%s", pFunc_prefix, func.m_name.get_ptr());
3081
3082         dynamic_string exported_param((func.m_return == "void") ? "DEF_PROTO_INTERNAL_VOID" : "DEF_PROTO_INTERNAL");
3083         int export_index = sorted_gl_so_function_exports.find_sorted(full_func_name);
3084         if (export_index >= 0)
3085             exported_param = (func.m_return == "void") ? "DEF_PROTO_EXPORTED_VOID" : "DEF_PROTO_EXPORTED";
3086
3087         dynamic_string category(func.m_category.get_len() ? func.m_category.get_ptr() : "UNDEFINED");
3088
3089         proto.format_append("( %s, %s, %s, %s, %u, ", exported_param.get_ptr(), category.get_ptr(), func.m_return_ctype.get_ptr(), func.m_return_ctype_enum.get_ptr(), func.m_params.size());
3090
3091         proto.format_append("%s, ", full_func_name.get_ptr());
3092
3093         proto.format_append("(");
3094         for (uint param_index = 0; param_index < func.m_params.size(); param_index++)
3095         {
3096             const gl_function_param &param = func.m_params[param_index];
3097
3098             proto.format_append("%s%s%s", param.m_ctype.get_ptr(), param.m_ctype.ends_with("*") ? "" : " ", param.m_name.get_ptr());
3099             if (param_index != func.m_params.size() - 1)
3100                 proto.format_append(", ");
3101         }
3102
3103         proto.format_append("), ");
3104
3105         proto.format_append("(");
3106         for (uint param_index = 0; param_index < func.m_params.size(); param_index++)
3107         {
3108             proto.format_append("%s", func.m_params[param_index].m_name.get_ptr());
3109             if (param_index != func.m_params.size() - 1)
3110                 proto.format_append(", ");
3111         }
3112
3113         proto.format_append(") )");
3114
3115         return proto;
3116     }
3117
3118     //-----------------------------------------------------------------------------------------------------------------------
3119     // process_func_protos
3120     //-----------------------------------------------------------------------------------------------------------------------
3121     bool process_func_protos(
3122         const char *pFunc_prefix, const gl_function_specs &gl_funcs, const gl_types &typemap, const gl_types &alt_typemap, const dynamic_string_array &sorted_gl_so_function_exports,
3123         gl_string_set &all_gl_ctypes, gl_string_set &all_gl_categories, gl_string_set &array_sizes)
3124     {
3125         VOGL_NOTE_UNUSED(pFunc_prefix);
3126         VOGL_NOTE_UNUSED(typemap);
3127         VOGL_NOTE_UNUSED(alt_typemap);
3128         VOGL_NOTE_UNUSED(sorted_gl_so_function_exports);
3129
3130         for (uint func_index = 0; func_index < gl_funcs.size(); func_index++)
3131         {
3132             const gl_function_def &func = gl_funcs[func_index];
3133
3134             all_gl_categories.insert(func.m_category);
3135             for (uint param_index = 0; param_index < func.m_params.size(); param_index++)
3136             {
3137                 const gl_function_param &param = func.m_params[param_index];
3138
3139                 all_gl_ctypes.insert(param.m_ctype);
3140                 array_sizes.insert(param.m_array_size);
3141             }
3142         }
3143
3144         return true;
3145     }
3146
3147     //-----------------------------------------------------------------------------------------------------------------------
3148     // dump_func_proto_macros
3149     //-----------------------------------------------------------------------------------------------------------------------
3150     bool dump_func_proto_macros(FILE *pFile, const char *pFunc_prefix, const gl_function_specs &gl_funcs, const gl_types &typemap, const gl_types &alt_typemap, const dynamic_string_array &sorted_gl_so_function_exports) const
3151     {
3152         VOGL_NOTE_UNUSED(typemap);
3153         VOGL_NOTE_UNUSED(alt_typemap);
3154
3155         for (uint func_index = 0; func_index < gl_funcs.size(); func_index++)
3156         {
3157             const gl_function_def &func = gl_funcs[func_index];
3158
3159             dynamic_string func_proto(get_func_proto_macro(pFunc_prefix, func, sorted_gl_so_function_exports));
3160
3161             vogl_fprintf(pFile, "%s%s\n", (func.m_return_ctype == "void") ? "DEF_PROTO_VOID" : "DEF_PROTO", func_proto.get_ptr());
3162         }
3163
3164         return true;
3165     }
3166
3167     //-----------------------------------------------------------------------------------------------------------------------
3168     // func_param_translate_array_size
3169     //-----------------------------------------------------------------------------------------------------------------------
3170     dynamic_string func_param_translate_array_size(const char *pFunc_prefix, const gl_function_def &func, const gl_function_param &param, const dynamic_string &func_proto, bool *pCustom_macro_flag = NULL) const
3171     {
3172         if (pCustom_macro_flag)
3173             *pCustom_macro_flag = false;
3174
3175         if (param.m_array_size.begins_with("[") && param.m_array_size.ends_with("]"))
3176         {
3177             dynamic_string array_size_param(param.m_array_size);
3178             array_size_param.mid(1, array_size_param.get_len() - 2);
3179
3180             for (uint i = 0; i < func.m_params.size(); i++)
3181                 if ((func.m_params[i].m_name == array_size_param) ||
3182                     ((func.m_params[i].m_name + "*1") == array_size_param) ||
3183                     ((func.m_params[i].m_name + "*2") == array_size_param) ||
3184                     ((func.m_params[i].m_name + "*3") == array_size_param) ||
3185                     ((func.m_params[i].m_name + "*4") == array_size_param) ||
3186                     ((func.m_params[i].m_name + "*5") == array_size_param) ||
3187                     ((func.m_params[i].m_name + "*6") == array_size_param) ||
3188                     ((func.m_params[i].m_name + "*7") == array_size_param) ||
3189                     ((func.m_params[i].m_name + "*8") == array_size_param) ||
3190                     ((func.m_params[i].m_name + "*9") == array_size_param) ||
3191                     ((func.m_params[i].m_name + "*10") == array_size_param) ||
3192                     ((func.m_params[i].m_name + "*11") == array_size_param) ||
3193                     ((func.m_params[i].m_name + "*12") == array_size_param) ||
3194                     ((func.m_params[i].m_name + "*13") == array_size_param) ||
3195                     ((func.m_params[i].m_name + "*14") == array_size_param) ||
3196                     ((func.m_params[i].m_name + "*15") == array_size_param) ||
3197                     ((func.m_params[i].m_name + "*16") == array_size_param))
3198                 {
3199                     if (func.m_params[i].m_semantic == "value")
3200                         return array_size_param;
3201                     //else if (func.m_params[i].m_semantic == "reference")
3202                     //   return dynamic_string(cVarArg, "%s ? *%s : -2", array_size_param.get_ptr(), array_size_param.get_ptr());
3203                     //else if ((func.m_params[i].m_semantic == "array") && (func.m_params[i].m_array_size == "[1]"))
3204                     //   return dynamic_string(cVarArg, "%s ? *%s : -2", array_size_param.get_ptr(), array_size_param.get_ptr());
3205                 }
3206
3207             if (array_size_param == "0" || array_size_param == "1" || array_size_param == "2" ||
3208                 array_size_param == "3" || array_size_param == "4" || array_size_param == "5" ||
3209                 array_size_param == "6" || array_size_param == "7" || array_size_param == "8" ||
3210                 array_size_param == "9" || array_size_param == "12" || array_size_param == "16")
3211             {
3212                 return array_size_param;
3213             }
3214
3215             if (array_size_param.begins_with("COMPSIZE(") && array_size_param.ends_with(")"))
3216             {
3217                 dynamic_string comp_size_param(array_size_param);
3218                 comp_size_param.mid(9, comp_size_param.get_len() - 10);
3219
3220                 // each of these are assumed to be a GL enum
3221                 if ((comp_size_param == "pname") || (comp_size_param == "attribute") ||
3222                     (comp_size_param == "id") ||  //(comp_size_param == "buffer") ||
3223                     (comp_size_param == "map") || //(comp_size_param == "name") ||
3224                     (comp_size_param == "path") || (comp_size_param == "query") ||
3225                     (comp_size_param == "target") || (comp_size_param == "type") ||
3226                     (comp_size_param == "value"))
3227                     return dynamic_string(cVarArg, "DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_GL_ENUM(%s)", comp_size_param.get_ptr());
3228
3229                 // these might be wrong
3230                 for (uint i = 0; i < func.m_params.size(); i++)
3231                     if (((func.m_params[i].m_name + "*2") == comp_size_param) ||
3232                         ((func.m_params[i].m_name + "*3") == comp_size_param) ||
3233                         ((func.m_params[i].m_name + "*4") == comp_size_param))
3234                     {
3235                         return dynamic_string(cVarArg, "DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_GL_ENUM(%s)", comp_size_param.get_ptr());
3236                     }
3237             }
3238         }
3239
3240         if (pCustom_macro_flag)
3241             *pCustom_macro_flag = true;
3242
3243         dynamic_string custom_array_size(cVarArg, "DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_%s%s_%s%s", pFunc_prefix, func.m_name.get_ptr(), param.m_name.get_ptr(), func_proto.get_ptr());
3244         return custom_array_size;
3245     }
3246
3247     //-----------------------------------------------------------------------------------------------------------------------
3248     // create_array_size_macros
3249     // TODO: use funcs_with_custom_array_size_macros[] vs. scanning for DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_
3250     //-----------------------------------------------------------------------------------------------------------------------
3251     void create_array_size_macros(const char *pFunc_prefix, const gl_function_specs &gl_funcs, const gl_types &typemap, const gl_types &alt_typemap, const dynamic_string_array &sorted_gl_so_function_exports,
3252                                   gl_string_set &custom_array_size_macros, vogl::vector<uint> &custom_array_size_macro_indices, dynamic_string_array &custom_array_size_macro_names, uint &cur_func_id) const
3253     {
3254         VOGL_NOTE_UNUSED(typemap);
3255         VOGL_NOTE_UNUSED(alt_typemap);
3256
3257         for (uint func_index = 0; func_index < gl_funcs.size(); func_index++)
3258         {
3259             const gl_function_def &func = gl_funcs[func_index];
3260
3261             dynamic_string func_proto(get_func_proto_macro(pFunc_prefix, func, sorted_gl_so_function_exports));
3262
3263             for (uint param_index = 0; param_index < func.m_params.size(); param_index++)
3264             {
3265                 const gl_function_param &param = func.m_params[param_index];
3266
3267                 if (param.m_semantic == "array")
3268                 {
3269                     dynamic_string array_size_macro(func_param_translate_array_size(pFunc_prefix, func, param, func_proto));
3270                     if (array_size_macro.begins_with("DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_"))
3271                     {
3272                         custom_array_size_macros.insert(array_size_macro);
3273
3274                         // oh god this is ugly
3275                         dynamic_string macro_name(array_size_macro);
3276                         int n = macro_name.find_left('(');
3277                         if (n >= 0)
3278                             macro_name.truncate(n);
3279
3280                         custom_array_size_macro_indices.push_back((cur_func_id << 16) | param_index);
3281                         custom_array_size_macro_names.push_back(macro_name);
3282                     }
3283                 }
3284             }
3285
3286             cur_func_id++;
3287         }
3288     }
3289
3290     //-----------------------------------------------------------------------------------------------------------------------
3291     // process_func_defs
3292     //-----------------------------------------------------------------------------------------------------------------------
3293     bool process_func_defs(const char *pFunc_prefix, const gl_function_specs &gl_funcs, const gl_types &typemap, const gl_types &alt_typemap, const dynamic_string_array &sorted_gl_so_function_exports,
3294                            const dynamic_string_array &whitelisted_funcs,
3295                            const dynamic_string_array &nullable_funcs,
3296                            dynamic_string_array &funcs_with_custom_array_size_macros,
3297                            dynamic_string_array &custom_return_param_array_size_macros,
3298                            dynamic_string_array &funcs_with_return_param_array_size_macros)
3299     {
3300         VOGL_NOTE_UNUSED(typemap);
3301         VOGL_NOTE_UNUSED(alt_typemap);
3302         VOGL_NOTE_UNUSED(nullable_funcs);
3303
3304         for (uint func_index = 0; func_index < gl_funcs.size(); func_index++)
3305         {
3306             const gl_function_def &func = gl_funcs[func_index];
3307
3308             dynamic_string full_func_name(func.m_full_name); //cVarArg, "%s%s", pFunc_prefix, func.m_name.get_ptr());
3309
3310             bool is_in_whitelist = false;
3311             VOGL_NOTE_UNUSED(is_in_whitelist);
3312             for (uint i = 0; i < whitelisted_funcs.size(); i++)
3313             {
3314                 if (whitelisted_funcs[i] == full_func_name)
3315                 {
3316                     is_in_whitelist = true;
3317                     break;
3318                 }
3319             }
3320
3321             dynamic_string func_proto(get_func_proto_macro(pFunc_prefix, func, sorted_gl_so_function_exports));
3322
3323             // TODO: This (func_has_custom_array_size_macros) is dead code
3324             bool func_has_custom_array_size_macros = false;
3325
3326             dynamic_string func_params;
3327
3328             for (uint param_index = 0; param_index < func.m_params.size(); param_index++)
3329             {
3330                 const gl_function_param &param = func.m_params[param_index];
3331
3332                 func_params.append(param.m_name);
3333                 if (param_index != (func.m_params.size() - 1))
3334                     func_params.append(", ");
3335             }
3336
3337             if (func.m_return != "void")
3338             {
3339                 dynamic_string return_param_compute_array_size_macro_name(cVarArg, "DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_%s(%s)", full_func_name.get_ptr(), func_params.get_ptr());
3340
3341                 custom_return_param_array_size_macros.push_back(return_param_compute_array_size_macro_name);
3342                 funcs_with_return_param_array_size_macros.push_back(full_func_name);
3343             }
3344
3345             if (func_has_custom_array_size_macros)
3346             {
3347                 funcs_with_custom_array_size_macros.push_back(full_func_name);
3348             }
3349         }
3350
3351         return true;
3352     }
3353
3354     //-----------------------------------------------------------------------------------------------------------------------
3355     // dump_func_def_macros
3356     //-----------------------------------------------------------------------------------------------------------------------
3357     bool dump_func_def_macros(FILE *pFile, const char *pFunc_prefix, const gl_function_specs &gl_funcs, const gl_types &typemap, const gl_types &alt_typemap, const dynamic_string_array &sorted_gl_so_function_exports,
3358                               const dynamic_string_array &whitelisted_funcs,
3359                               const dynamic_string_array &nullable_funcs) const
3360     {
3361         VOGL_NOTE_UNUSED(typemap);
3362         VOGL_NOTE_UNUSED(alt_typemap);
3363         VOGL_NOTE_UNUSED(nullable_funcs);
3364
3365         for (uint func_index = 0; func_index < gl_funcs.size(); func_index++)
3366         {
3367             const gl_function_def &func = gl_funcs[func_index];
3368
3369             dynamic_string full_func_name(cVarArg, "%s%s", pFunc_prefix, func.m_name.get_ptr());
3370
3371             bool is_in_whitelist = false;
3372             VOGL_NOTE_UNUSED(is_in_whitelist);
3373             for (uint i = 0; i < whitelisted_funcs.size(); i++)
3374             {
3375                 if (whitelisted_funcs[i] == full_func_name)
3376                 {
3377                     is_in_whitelist = true;
3378                     break;
3379                 }
3380             }
3381
3382             dynamic_string func_proto(get_func_proto_macro(pFunc_prefix, func, sorted_gl_so_function_exports));
3383
3384             vogl_fprintf(pFile, "// %s Category: %s Vers: \"%s\" Deprecated: \"%s\" Profile: \"%s\"\n", full_func_name.get_ptr(), func.m_category.get_ptr(), func.m_version.get_ptr(), func.m_deprecated.get_ptr(), func.m_profile.get_ptr());
3385
3386             vogl_fprintf(pFile, "#ifdef DEF_FUNCTION_CUSTOM_HANDLER_%s\n", full_func_name.get_ptr());
3387
3388             vogl_fprintf(pFile, "   DEF_FUNCTION_CUSTOM_HANDLER_%s%s\n", full_func_name.get_ptr(), func_proto.get_ptr());
3389             vogl_fprintf(pFile, "   #undef DEF_FUNCTION_CUSTOM_HANDLER_%s\n", full_func_name.get_ptr());
3390
3391             vogl_fprintf(pFile, "#else\n");
3392
3393             vogl_fprintf(pFile, "   DEF_FUNCTION_BEGIN%s%s\n", func.m_return == "void" ? "_VOID" : "", func_proto.get_ptr());
3394
3395             vogl_fprintf(pFile, "   #ifdef DEF_FUNCTION_CUSTOM_FUNC_PROLOG_%s\n", full_func_name.get_ptr());
3396             vogl_fprintf(pFile, "      DEF_FUNCTION_CUSTOM_FUNC_PROLOG_%s%s\n", full_func_name.get_ptr(), func_proto.get_ptr());
3397             vogl_fprintf(pFile, "      #undef DEF_FUNCTION_CUSTOM_FUNC_PROLOG_%s\n", full_func_name.get_ptr());
3398             vogl_fprintf(pFile, "   #endif\n");
3399
3400             vogl_fprintf(pFile, "   DEF_FUNCTION_INIT%s%s\n", func.m_return == "void" ? "_VOID" : "", func_proto.get_ptr());
3401
3402             bool func_has_custom_array_size_macros = false;
3403
3404             dynamic_string func_params;
3405
3406             for (uint param_index = 0; param_index < func.m_params.size(); param_index++)
3407             {
3408                 const gl_function_param &param = func.m_params[param_index];
3409
3410                 func_params.append(param.m_name);
3411                 if (param_index != (func.m_params.size() - 1))
3412                     func_params.append(", ");
3413
3414                 if (param.m_direction != "in")
3415                     continue;
3416
3417                 if (param.m_semantic == "value")
3418                 {
3419                     vogl_fprintf(pFile, "   DEF_FUNCTION_INPUT_VALUE_PARAM( %u, %s, %s, %s, %s )\n", param_index, param.m_type.get_ptr(), param.m_ctype.get_ptr(), param.m_ctype_enum.get_ptr(), param.m_name.get_ptr());
3420                 }
3421                 else if (param.m_semantic == "array")
3422                 {
3423                     vogl_fprintf(pFile, "   // %s ArraySize=%s\n", param.m_name.get_ptr(), param.m_array_size.get_ptr());
3424                     vogl_fprintf(pFile, "   DEF_FUNCTION_INPUT_ARRAY_PARAM( %u, %s, %s, %s, %s, %s )\n", param_index, param.m_type.get_ptr(), param.m_ctype.get_ptr(), param.m_ctype_enum.get_ptr(), param.m_name.get_ptr(), func_param_translate_array_size(pFunc_prefix, func, param, func_proto, &func_has_custom_array_size_macros).get_ptr());
3425                 }
3426                 else if (param.m_semantic == "reference")
3427                 {
3428                     vogl_fprintf(pFile, "   DEF_FUNCTION_INPUT_REFERENCE_PARAM( %u, %s, %s, %s, %s )\n", param_index, param.m_type.get_ptr(), param.m_ctype.get_ptr(), param.m_ctype_enum.get_ptr(), param.m_name.get_ptr());
3429                 }
3430             }
3431
3432             vogl_fprintf(pFile, "   #ifdef DEF_FUNCTION_CUSTOM_GL_CALLER_%s\n", full_func_name.get_ptr());
3433             vogl_fprintf(pFile, "      DEF_FUNCTION_CUSTOM_GL_CALLER_%s%s\n", full_func_name.get_ptr(), func_proto.get_ptr());
3434             vogl_fprintf(pFile, "      #undef DEF_FUNCTION_CUSTOM_GL_CALLER_%s\n", full_func_name.get_ptr());
3435
3436             vogl_fprintf(pFile, "   #else\n");
3437
3438             vogl_fprintf(pFile, "      #ifdef DEF_FUNCTION_CUSTOM_GL_PROLOG_%s\n", full_func_name.get_ptr());
3439             vogl_fprintf(pFile, "         DEF_FUNCTION_CUSTOM_GL_PROLOG_%s%s\n", full_func_name.get_ptr(), func_proto.get_ptr());
3440             vogl_fprintf(pFile, "         #undef DEF_FUNCTION_CUSTOM_GL_PROLOG_%s\n", full_func_name.get_ptr());
3441             vogl_fprintf(pFile, "      #endif\n");
3442
3443             vogl_fprintf(pFile, "      DEF_FUNCTION_CALL_GL%s%s\n", func.m_return == "void" ? "_VOID" : "", func_proto.get_ptr());
3444
3445             vogl_fprintf(pFile, "      #ifdef DEF_FUNCTION_CUSTOM_GL_EPILOG_%s\n", full_func_name.get_ptr());
3446             vogl_fprintf(pFile, "         DEF_FUNCTION_CUSTOM_GL_EPILOG_%s%s\n", full_func_name.get_ptr(), func_proto.get_ptr());
3447             vogl_fprintf(pFile, "         #undef DEF_FUNCTION_CUSTOM_GL_EPILOG_%s\n", full_func_name.get_ptr());
3448             vogl_fprintf(pFile, "      #endif\n");
3449
3450             vogl_fprintf(pFile, "   #endif\n");
3451
3452             for (uint param_index = 0; param_index < func.m_params.size(); param_index++)
3453             {
3454                 const gl_function_param &param = func.m_params[param_index];
3455                 if (param.m_direction != "out")
3456                     continue;
3457
3458                 if (param.m_semantic == "value")
3459                 {
3460                     vogl_fprintf(pFile, "   DEF_FUNCTION_OUTPUT_VALUE_PARAM( %u, %s, %s, %s, %s )\n", param_index, param.m_type.get_ptr(), param.m_ctype.get_ptr(), param.m_ctype_enum.get_ptr(), param.m_name.get_ptr());
3461                 }
3462                 else if (param.m_semantic == "array")
3463                 {
3464                     vogl_fprintf(pFile, "   // %s ArraySize=%s\n", param.m_name.get_ptr(), param.m_array_size.get_ptr());
3465                     vogl_fprintf(pFile, "   DEF_FUNCTION_OUTPUT_ARRAY_PARAM( %u, %s, %s, %s, %s, %s )\n", param_index, param.m_type.get_ptr(), param.m_ctype.get_ptr(), param.m_ctype_enum.get_ptr(), param.m_name.get_ptr(), func_param_translate_array_size(pFunc_prefix, func, param, func_proto, &func_has_custom_array_size_macros).get_ptr());
3466                 }
3467                 else if (param.m_semantic == "reference")
3468                 {
3469                     vogl_fprintf(pFile, "   DEF_FUNCTION_OUTPUT_REFERENCE_PARAM( %u, %s, %s, %s, %s )\n", param_index, param.m_type.get_ptr(), param.m_ctype.get_ptr(), param.m_ctype_enum.get_ptr(), param.m_name.get_ptr());
3470                 }
3471             }
3472
3473             vogl_fprintf(pFile, "   #ifdef DEF_FUNCTION_CUSTOM_FUNC_EPILOG_%s\n", full_func_name.get_ptr());
3474             vogl_fprintf(pFile, "      DEF_FUNCTION_CUSTOM_FUNC_EPILOG_%s%s\n", full_func_name.get_ptr(), func_proto.get_ptr());
3475             vogl_fprintf(pFile, "      #undef DEF_FUNCTION_CUSTOM_FUNC_EPILOG_%s\n", full_func_name.get_ptr());
3476             vogl_fprintf(pFile, "   #endif\n");
3477
3478             if (func.m_return != "void")
3479             {
3480                 //vogl_fprintf(pFile, "   DEF_FUNCTION_RETURN_PARAM( %s, %s, %s, )\n", func.m_return.get_ptr(), func.m_return_ctype.get_ptr(), func.m_return_ctype_enum.get_ptr());
3481                 dynamic_string return_param_compute_array_size_macro_name(cVarArg, "DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_%s(%s)", full_func_name.get_ptr(), func_params.get_ptr());
3482
3483                 vogl_fprintf(pFile, "   DEF_FUNCTION_RETURN_PARAM( %s, %s, %s, %s )\n", func.m_return.get_ptr(), func.m_return_ctype.get_ptr(), func.m_return_ctype_enum.get_ptr(), return_param_compute_array_size_macro_name.get_ptr());
3484             }
3485
3486             vogl_fprintf(pFile, "   DEF_FUNCTION_END%s%s\n", func.m_return == "void" ? "_VOID" : "", func_proto.get_ptr());
3487
3488             vogl_fprintf(pFile, "#endif\n");
3489             vogl_fprintf(pFile, "\n");
3490         }
3491
3492         return true;
3493     }
3494
3495     //-----------------------------------------------------------------------------------------------------------------------
3496     // dump_func_desc_macros
3497     //-----------------------------------------------------------------------------------------------------------------------
3498     bool dump_func_desc_macros(
3499         FILE *pFile, const char *pFunc_prefix,
3500         const gl_function_specs &gl_funcs, const gl_types &typemap, const gl_types &alt_typemap, const apitrace_func_specs &apitrace_gl_func_specs,
3501         const dynamic_string_array &sorted_gl_so_function_exports, const dynamic_string_array &whitelisted_funcs, const dynamic_string_array &nullable_funcs, const dynamic_string_array &whitelisted_displaylists_funcs) const
3502     {
3503         VOGL_NOTE_UNUSED(typemap);
3504         VOGL_NOTE_UNUSED(alt_typemap);
3505
3506         for (uint func_index = 0; func_index < gl_funcs.size(); func_index++)
3507         {
3508             const gl_function_def &func = gl_funcs[func_index];
3509
3510             dynamic_string full_func_name(cVarArg, "%s%s", pFunc_prefix, func.m_name.get_ptr());
3511             VOGL_ASSERT(full_func_name.compare(func.m_full_name, true) == 0);
3512
3513             const apitrace_gl_func_def *pApitrace_func_def = apitrace_gl_func_specs.find(full_func_name.get_ptr());
3514
3515             bool is_in_whitelist = whitelisted_funcs.find(full_func_name) != cInvalidIndex;
3516             bool is_nullable = nullable_funcs.find(full_func_name) != cInvalidIndex;
3517
3518             bool is_whitelisted_for_displaylists = false;
3519             for (uint i = 0; i < whitelisted_displaylists_funcs.size(); i++)
3520             {
3521                 if (regexp_full_match(func.m_full_name.get_ptr(), whitelisted_displaylists_funcs[i].get_ptr()))
3522                 {
3523                     is_whitelisted_for_displaylists = true;
3524                     break;
3525                 }
3526             }
3527
3528             if (is_whitelisted_for_displaylists)
3529             {
3530                 if (func.m_notlistable)
3531                 {
3532                     console::error("%s: Func's %s m_notlistable and is_whitelisted_for_displaylists flags are not compatible!\n", VOGL_METHOD_NAME, full_func_name.get_ptr());
3533                 }
3534             }
3535
3536             dynamic_string func_proto(get_func_proto_macro(pFunc_prefix, func, sorted_gl_so_function_exports));
3537
3538             vogl_fprintf(pFile, "// %s Category: %s Vers: \"%s\" Deprecated: \"%s\" Profile: \"%s\"\n", full_func_name.get_ptr(), func.m_category.get_ptr(), func.m_version.get_ptr(), func.m_deprecated.get_ptr(), func.m_profile.get_ptr());
3539
3540             vogl_fprintf(pFile, "DEF_FUNCTION_BEGIN%s\n", func_proto.get_ptr());
3541
3542             vogl_namespace_t return_namespace = VOGL_NAMESPACE_UNKNOWN;
3543             if (pApitrace_func_def)
3544                 return_namespace = pApitrace_func_def->m_return_namespace;
3545
3546             vogl_fprintf(pFile, "   DEF_FUNCTION_INFO( %i, %s, \"%s\", \"%s\", \"%s\", \"%s\", %s, %s, %s, %s )\n", (int)return_namespace, func.m_return.get_ptr(), func.m_category.get_ptr(), func.m_version.get_ptr(),
3547                         func.m_profile.get_ptr(), func.m_deprecated.get_ptr(), is_in_whitelist ? "true" : "false", is_nullable ? "true" : "false", is_whitelisted_for_displaylists ? "true" : "false", !func.m_notlistable ? "true" : "false");
3548
3549             if (func.m_params.size())
3550             {
3551                 vogl_fprintf(pFile, "   DEF_FUNCTION_BEGIN_PARAMS\n");
3552                 for (uint param_index = 0; param_index < func.m_params.size(); param_index++)
3553                 {
3554                     const gl_function_param &param = func.m_params[param_index];
3555
3556                     vogl_namespace_t param_namespace = VOGL_NAMESPACE_UNKNOWN;
3557                     if (pApitrace_func_def)
3558                     {
3559                         VOGL_ASSERT(param_index < pApitrace_func_def->m_params.size());
3560                         if (param_index < pApitrace_func_def->m_params.size())
3561                             param_namespace = pApitrace_func_def->m_params[param_index].m_namespace;
3562                     }
3563
3564                     dynamic_string dir(param.m_direction);
3565                     dir.toupper();
3566
3567                     if (param.m_semantic == "value")
3568                     {
3569                         vogl_fprintf(pFile, "   DEF_FUNCTION_%s_VALUE_PARAM( %i, %s, %s, %s, %s )\n", dir.get_ptr(), (int)param_namespace, param.m_type.get_ptr(), param.m_ctype.get_ptr(), param.m_ctype_enum.get_ptr(), param.m_name.get_ptr());
3570                     }
3571                     else if (param.m_semantic == "array")
3572                     {
3573                         vogl_fprintf(pFile, "   // %s ArraySize=%s\n", param.m_name.get_ptr(), param.m_array_size.get_ptr());
3574                         vogl_fprintf(pFile, "   DEF_FUNCTION_%s_ARRAY_PARAM( %i, %s, %s, %s, %s, %s )\n", dir.get_ptr(), (int)param_namespace, param.m_type.get_ptr(), param.m_ctype.get_ptr(), param.m_ctype_enum.get_ptr(), param.m_name.get_ptr(), func_param_translate_array_size(pFunc_prefix, func, param, func_proto).get_ptr());
3575                     }
3576                     else if (param.m_semantic == "reference")
3577                     {
3578                         vogl_fprintf(pFile, "   DEF_FUNCTION_%s_REFERENCE_PARAM( %i, %s, %s, %s, %s )\n", dir.get_ptr(), (int)param_namespace, param.m_type.get_ptr(), param.m_ctype.get_ptr(), param.m_ctype_enum.get_ptr(), param.m_name.get_ptr());
3579                     }
3580                 }
3581                 vogl_fprintf(pFile, "   DEF_FUNCTION_END_PARAMS\n");
3582             }
3583
3584             vogl_fprintf(pFile, "   DEF_FUNCTION_RETURN( %s, %s, %s )\n", func.m_return.get_ptr(), func.m_return_ctype.get_ptr(), func.m_return_ctype_enum.get_ptr());
3585
3586             vogl_fprintf(pFile, "DEF_FUNCTION_END%s\n", func_proto.get_ptr());
3587
3588             vogl_fprintf(pFile, "\n");
3589         }
3590
3591         return true;
3592     }
3593
3594     //-----------------------------------------------------------------------------------------------------------------------
3595     // dump_inc_file_header
3596     //-----------------------------------------------------------------------------------------------------------------------
3597     void dump_inc_file_header(FILE *pFile) const
3598     {
3599         vogl_fprintf(pFile, "// Auto-generated by voglgen. Don't hand modify!\n\n");
3600     }
3601
3602     //-----------------------------------------------------------------------------------------------------------------------
3603     // dump_function_def_undef_macros
3604     //-----------------------------------------------------------------------------------------------------------------------
3605     void dump_function_def_undef_macros(FILE *pFile) const
3606     {
3607         vogl_fprintf(pFile, "#undef DEF_PROTO_EXPORTED\n");
3608         vogl_fprintf(pFile, "#undef DEF_PROTO_EXPORTED_VOID\n");
3609         vogl_fprintf(pFile, "#undef DEF_PROTO_INTERNAL\n");
3610         vogl_fprintf(pFile, "#undef DEF_PROTO_INTERNAL_VOID\n");
3611         vogl_fprintf(pFile, "#undef DEF_FUNCTION_BEGIN_PARAMS\n");
3612         vogl_fprintf(pFile, "#undef DEF_FUNCTION_REFERENCE_PARAM\n");
3613         vogl_fprintf(pFile, "#undef DEF_FUNCTION_IN_VALUE_PARAM\n");
3614         vogl_fprintf(pFile, "#undef DEF_FUNCTION_IN_ARRAY_PARAM\n");
3615         vogl_fprintf(pFile, "#undef DEF_FUNCTION_IN_REFERENCE_PARAM\n");
3616         vogl_fprintf(pFile, "#undef DEF_FUNCTION_OUT_REFERENCE_PARAM\n");
3617         vogl_fprintf(pFile, "#undef DEF_FUNCTION_OUT_ARRAY_PARAM\n");
3618         vogl_fprintf(pFile, "#undef DEF_FUNCTION_END_PARAMS\n");
3619         vogl_fprintf(pFile, "#undef DEF_FUNCTION_BEGIN\n");
3620         vogl_fprintf(pFile, "#undef DEF_FUNCTION_BEGIN_VOID\n");
3621         vogl_fprintf(pFile, "#undef DEF_FUNCTION_INIT\n");
3622         vogl_fprintf(pFile, "#undef DEF_FUNCTION_INIT_VOID\n");
3623         vogl_fprintf(pFile, "#undef DEF_FUNCTION_INPUT_VALUE_PARAM\n");
3624         vogl_fprintf(pFile, "#undef DEF_FUNCTION_INPUT_REFERENCE_PARAM\n");
3625         vogl_fprintf(pFile, "#undef DEF_FUNCTION_INPUT_ARRAY_PARAM\n");
3626         vogl_fprintf(pFile, "#undef DEF_FUNCTION_OUTPUT_REFERENCE_PARAM\n");
3627         vogl_fprintf(pFile, "#undef DEF_FUNCTION_OUTPUT_ARRAY_PARAM\n");
3628         vogl_fprintf(pFile, "#undef DEF_FUNCTION_CALL_GL\n");
3629         vogl_fprintf(pFile, "#undef DEF_FUNCTION_CALL_GL_VOID\n");
3630         vogl_fprintf(pFile, "#undef DEF_FUNCTION_END\n");
3631         vogl_fprintf(pFile, "#undef DEF_FUNCTION_END_VOID\n");
3632         vogl_fprintf(pFile, "#undef DEF_FUNCTION_RETURN_PARAM\n");
3633         vogl_fprintf(pFile, "#undef DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_GL_ENUM\n");
3634         vogl_fprintf(pFile, "#undef DEF_FUNCTION_INFO\n");
3635     }
3636
3637     struct gl_type_alias_t
3638     {
3639         const char *m_pName;
3640         const char *m_pAlias;
3641     };
3642
3643     //-----------------------------------------------------------------------------------------------------------------------
3644     // purify_gl_type
3645     //-----------------------------------------------------------------------------------------------------------------------
3646     static dynamic_string_array purify_gl_type(dynamic_string str)
3647     {
3648         static const gl_type_alias_t g_gl_type_comparison_exception_table[] =
3649             {
3650                 { "__GLXextFuncPtr", "void *" },
3651                 { "GLfunction", "void *" },
3652                 { "GLuint*", "unsigned int *" },
3653                 { "GLuint *", "unsigned int *" },
3654                 { "GLuint", "unsigned int" },
3655                 { "Bool", "bool" },
3656                 { "GLboolean", "bool" },
3657                 { "GLvoid", "void" },
3658                 { "int64_t", "int64_t" },
3659                 { "GLint64", "int64_t" },
3660                 { "GLvoid*", "void*" },
3661                 { "handleARB", "GLhandleARB" },
3662                 { "GLint", "int" },
3663                 { "const GLubyte *", "const char *" },
3664                 { "GLubyte *", "char *" },
3665                 { "GLubyte*", "char *" },
3666                 { "GLchar*", "char *" },
3667                 { "GLchar* const", "char *" },
3668                 { "const char *", "char *" },
3669                 { "GLchar", "char" },
3670                 { "void function()", "void *" },
3671                 { "int32_t", "int" },
3672                 { "GLclampf", "float" },
3673                 { "GLfloat", "float" },
3674                 { "GLclampd", "double" },
3675                 { "GLdouble", "double" },
3676                 { "GLsizei", "int" },
3677                 { "int32_t *", "int *" },
3678                 { "int64_t *", "int64_t *" },
3679                 { "GLint64*", "int64_t *" },
3680                 { "GLint32*", "int *" },
3681                 { "GLint32 *", "int *" },
3682                 { "const GLuint*", "const unsigned int *" },
3683                 { "const GLuint *", "const unsigned int *" },
3684                 { "GLuint32*", "unsigned int *" },
3685                 { "GLuint32 *", "unsigned int *" },
3686                 { "GLulong*", "unsigned long *" },
3687                 { "GLint*", "int *" },
3688                 { "GLint *", "int *" },
3689                 { "const GLint *", "const int *" },
3690                 { "const GLvoid *", "const void *" },
3691                 { "const GLvoid*", "const void *" },
3692                 { "GLvoid *", "void *" },
3693                 { "GLvoid*", "void *" },
3694                 { "GLchar *", "char *" },
3695                 { "GLchar*", "char *" },
3696                 { "const GLchar *", "const char *" },
3697                 { "const GLchar*", "const char *" },
3698                 { "GLcharARB *", "char *" },
3699                 { "GLcharARB*", "char *" },
3700                 { "const GLcharARB *", "const char *" },
3701                 { "const GLcharARB*", "const char *" },
3702                 { "uint *", "unsigned int *" },
3703                 { "ulong", "unsigned long" },
3704                 { "ulong *", "unsigned long *" },
3705                 { "GLuint64", "unsigned int64_t" },
3706                 { "GLuint64*", "unsigned int64_t *" },
3707                 { "const GLuint64*", "const unsigned int64_t *" },
3708                 { "GLuint64EXT", "unsigned int64_t" },
3709                 { "const GLuint64EXT *", "const unsigned int64_t *" },
3710                 { "GLuint64EXT *", "unsigned int64_t *" },
3711                 { "GLint64", "int64_t" },
3712                 { "GLint64*", "int64_t *" },
3713                 { "const GLint64*", "const int64_t *" },
3714                 { "GLint64EXT", "int64_t" },
3715                 { "const GLint64EXT *", "const int64_t *" },
3716                 { "GLint64EXT *", "int64_t *" },
3717                 { "GLintptr", "int *" },
3718                 { "GLintptrARB", "int *" },
3719                 { "GLenum", "int" }, // Mapping GLenum->int is pushing it, but there are some extensions that don't agree on whether the param is GLenum or int.
3720                 { "GLhalfNV", "GLhalf" },
3721                 { "const GLhalfNV *", "const GLhalf *" },
3722                 { "GLchar* const *", "char * const *" },
3723                 { "GLchar **", "char **" },
3724                 { "const GLfloat *", "const float *" },
3725                 { "const GLdouble *", "const double *" },
3726                 { "GLfloat *", "float *" },
3727                 { "const GLfloat *", "const float *" },
3728                 { "GLfloat*", "float *" },
3729                 { "const GLfloat *", "const float *" },
3730                 { "const GLfloat*", "const float *" },
3731                 { "GLclampf *", "float *" },
3732                 { "const GLclampf *", "const float *" },
3733                 { "GLclampf*", "float *" },
3734                 { "GLdouble *", "double *" },
3735                 { "GLdouble*", "double *" },
3736                 { "GLclampd *", "double *" },
3737                 { "GLclampd*", "double *" },
3738                 { "GLsizeiptrARB", "GLsizeiptr" },
3739                 { "handleARB*", "GLhandleARB *" },
3740                 { "const GLcharARB* *", "const char **" },
3741                 { "GLchar * *", "const char **" },
3742                 { "GLchar**", "const char **" },
3743                 { "const GLchar* *", "const char **" },
3744                 { "GLoint", "unsigned int" }, // Bad in scraped XML
3745                 { "const GLchar * *", "const char **" },
3746                 { "cl_context", "struct _cl_context *" }, // Correct in spec, bad in scraped XML.
3747                 { "cl_event", "struct _cl_event *" },     // Correct in spec, bad in scraped XML.
3748             };
3749
3750         // See if the ctype can be aliased to a simpler, hopefully equivalent ctype.
3751         for (uint i = 0; i < VOGL_ARRAY_SIZE(g_gl_type_comparison_exception_table); i++)
3752         {
3753             if (str == g_gl_type_comparison_exception_table[i].m_pName)
3754             {
3755                 str = g_gl_type_comparison_exception_table[i].m_pAlias;
3756                 break;
3757             }
3758         }
3759
3760         // Tokenize type string
3761         dynamic_string_array tokens;
3762         str.tokenize(" \t", tokens, true);
3763
3764         // Kill all const crap, nobody seems to agree on it so screw it.
3765         for (int i = 0; i < static_cast<int>(tokens.size()); i++)
3766         {
3767             if (tokens[i] == "const")
3768             {
3769                 tokens.erase(i);
3770                 i--;
3771             }
3772         }
3773
3774         // Seperate out trailing "*" chars into multiple tokens.
3775         dynamic_string ptr_str("*");
3776
3777         for (int i = 0; i < static_cast<int>(tokens.size()); i++)
3778         {
3779             for (;;)
3780             {
3781                 if (tokens[i].get_len() == 1)
3782                     break;
3783
3784                 int pointer_ofs = tokens[i].find_right('*');
3785                 if (pointer_ofs < 0)
3786                     break;
3787
3788                 tokens[i].truncate(pointer_ofs);
3789                 tokens.insert(i + 1, ptr_str);
3790             }
3791         }
3792
3793         return tokens;
3794     }
3795
3796     //-----------------------------------------------------------------------------------------------------------------------
3797     // validate_functions
3798     //-----------------------------------------------------------------------------------------------------------------------
3799     bool validate_functions(const gl_function_specs &gl_xml_funcs, const gl_function_specs &gl_funcs, const apitrace_func_specs &apitrace_gl_funcs,
3800                             const gl_types &primary_typemap, const gl_types &alt_typemap) const
3801     {
3802         dynamic_string_array missing_funcs;
3803
3804         uint total_skipped = 0;
3805         uint total_validated = 0;
3806         uint total_failures = 0;
3807         uint total_not_found = 0;
3808
3809         for (uint func_index = 0; func_index < gl_funcs.size(); func_index++)
3810         {
3811             const gl_function_def &func = gl_funcs[func_index];
3812
3813             // Let's skip these guys, they are either bad in the XML and not worth fixing up the individual params in code, or they are totally uninteresting (SUN, OES),
3814             // or they have been manually validated to be correct in the .spec files.
3815             if ((func.m_name == "Uniform2ui") || (func.m_name == "Uniform3ui") || (func.m_name == "Uniform4ui") ||
3816                 (func.m_name == "ProgramUniform2ui") || (func.m_name == "ProgramUniform3ui") || (func.m_name == "ProgramUniform4ui") ||
3817                 (func.m_name == "ReplacementCodePointerSUN") || (func.m_name == "ClearDepthfOES") || (func.m_name == "QueryMatrixxOES") ||
3818                 (func.m_name == "QueryMatrixxOES") || (func.m_name == "SendPbufferToVideoNV") || (func.m_name == "ReleaseVideoImageNV") ||
3819                 (func.m_name == "BindVideoImageNV") || (func.m_name == "GetTransparentIndexSUN") ||
3820                 (func.m_name == "GetIntegerui64i_vNV"))
3821             {
3822                 total_skipped++;
3823                 continue;
3824             }
3825
3826             const gl_types *pPrimary_typemap = &primary_typemap;
3827             const gl_types *pAlt_typemap = &alt_typemap;
3828             if ((func.m_lib == cGLX) || (func.m_lib == cWGL))
3829                 std::swap(pPrimary_typemap, pAlt_typemap);
3830
3831             dynamic_string return_type;
3832             if (func.m_return == "void")
3833             {
3834                 return_type = "void";
3835             }
3836             else
3837             {
3838                 const dynamic_string *pCType = pPrimary_typemap->find(func.m_return);
3839                 if (!pCType)
3840                     pCType = pAlt_typemap->find(func.m_return);
3841                 if (!pCType)
3842                 {
3843                     console::warning("Unable to map spec type %s\n", func.m_return.get_ptr());
3844                     return false;
3845                 }
3846
3847                 return_type = *pCType;
3848             }
3849
3850             dynamic_string_array func_param_ctypes;
3851
3852             for (uint param_index = 0; param_index < func.m_params.size(); param_index++)
3853             {
3854                 const gl_function_param &param = func.m_params[param_index];
3855
3856                 const dynamic_string *pCType = pPrimary_typemap->find(param.m_type);
3857                 if (!pCType)
3858                     pCType = pAlt_typemap->find(param.m_type);
3859                 if (!pCType)
3860                 {
3861                     console::warning("Unable to map spec type %s\n", param.m_type.get_ptr());
3862                     return false;
3863                 }
3864
3865                 dynamic_string type_prefix;
3866
3867                 dynamic_string type_suffix("");
3868                 if ((param.m_semantic == "array") || (param.m_semantic == "reference"))
3869                 {
3870                     type_suffix = " *";
3871
3872                     if (param.m_direction == "in")
3873                     {
3874                         if (!pCType->ends_with("const"))
3875                             type_prefix = "const ";
3876                     }
3877                 }
3878
3879                 dynamic_string full_ctype(cVarArg, "%s%s%s", type_prefix.get_ptr(), pCType->get_ptr(), type_suffix.get_ptr());
3880
3881                 func_param_ctypes.push_back(full_ctype);
3882             }
3883
3884             const apitrace_gl_func_def *pApitrace_func_def = apitrace_gl_funcs.find(func.m_full_name.get_ptr());
3885             if (pApitrace_func_def)
3886             {
3887                 if (pApitrace_func_def->m_return_gl_type != return_type)
3888                 {
3889                     console::warning("Function %s return type mismatch vs. apitrace specs: spec: %s, apitrace: %s\n", func.m_full_name.get_ptr(), return_type.get_ptr(), pApitrace_func_def->m_return_gl_type.get_ptr());
3890                     total_failures++;
3891                 }
3892
3893                 if (pApitrace_func_def->m_params.size() != func_param_ctypes.size())
3894                 {
3895                     console::warning("Function %s has a different number of params vs. apitrace specs: spec: %u, apitrace: %u\n", func.m_full_name.get_ptr(), func_param_ctypes.size(), pApitrace_func_def->m_params.size());
3896                     total_failures++;
3897                 }
3898                 else
3899                 {
3900                     for (uint i = 0; i < func_param_ctypes.size(); i++)
3901                     {
3902                         const apitrace_gl_func_param_def &param_def = pApitrace_func_def->m_params[i];
3903
3904                         dynamic_string apitrace_param_type(param_def.m_gl_type);
3905
3906                         dynamic_string_array purified_spec_ctype(purify_gl_type(func_param_ctypes[i]));
3907                         dynamic_string_array purified_apitrace_ctype(purify_gl_type(apitrace_param_type));
3908
3909                         bool type_mismatch = purified_spec_ctype.size() != purified_apitrace_ctype.size();
3910                         if (!type_mismatch)
3911                         {
3912                             for (uint j = 0; j < purified_spec_ctype.size(); j++)
3913                             {
3914                                 if (purified_spec_ctype[j] != purified_apitrace_ctype[j])
3915                                 {
3916                                     type_mismatch = true;
3917                                     break;
3918                                 }
3919                             }
3920                         }
3921
3922                         if (type_mismatch)
3923                         {
3924                             console::warning("Function %s param %u, spec vs. apitrace type difference: spec: %s apitrace: %s\n", func.m_full_name.get_ptr(), i, func_param_ctypes[i].get_ptr(), apitrace_param_type.get_ptr());
3925                             total_failures++;
3926
3927                             //printf("   { \"%s\", \"%s\" },\n", func_param_ctypes[i].get_ptr(), apitrace_param_type.get_ptr());
3928                         }
3929                     }
3930                 }
3931             }
3932             else
3933             {
3934                 //printf("Func not found in apitrace specs: %s\n", func.m_full_name.get_ptr());
3935             }
3936
3937             uint gl_xml_func_index;
3938             for (gl_xml_func_index = 0; gl_xml_func_index < gl_xml_funcs.size(); gl_xml_func_index++)
3939             {
3940                 if (gl_xml_funcs[gl_xml_func_index].m_lib != func.m_lib)
3941                     continue;
3942
3943                 dynamic_string gl_xml_func_name(gl_xml_funcs[gl_xml_func_index].m_name);
3944
3945                 if (gl_xml_func_name == func.m_name)
3946                     break;
3947             }
3948
3949             if (gl_xml_func_index == gl_xml_funcs.size())
3950             {
3951                 dynamic_string suffix;
3952                 if (func.m_name.ends_with("ARB", true) || func.m_name.ends_with("EXT", true))
3953                     suffix.set(func.m_name).right(func.m_name.get_len() - 3);
3954                 else if (func.m_name.ends_with("NV", true))
3955                     suffix.set(func.m_name).right(func.m_name.get_len() - 2);
3956
3957                 if (suffix.get_len())
3958                 {
3959                     for (gl_xml_func_index = 0; gl_xml_func_index < gl_xml_funcs.size(); gl_xml_func_index++)
3960                     {
3961                         if (gl_xml_funcs[gl_xml_func_index].m_lib != func.m_lib)
3962                             continue;
3963
3964                         dynamic_string gl_xml_func_name(gl_xml_funcs[gl_xml_func_index].m_name);
3965                         gl_xml_func_name += suffix;
3966
3967                         if (gl_xml_func_name == func.m_name)
3968                             break;
3969                     }
3970                 }
3971
3972                 if (gl_xml_func_index == gl_xml_funcs.size())
3973                 {
3974                     missing_funcs.push_back(func.m_name);
3975                     total_not_found++;
3976                     continue;
3977                 }
3978             }
3979
3980             const gl_function_def &xml_func = gl_xml_funcs[gl_xml_func_index];
3981             if (xml_func.m_params.size() != func.m_params.size())
3982             {
3983                 console::error("Function %s param number mismatch\n", func.m_name.get_ptr());
3984                 total_failures++;
3985                 continue;
3986             }
3987
3988             dynamic_string_array purified_func_return(purify_gl_type(return_type));
3989
3990             dynamic_string xml_func_return(xml_func.m_return);
3991
3992             // XML exceptions (they where incorrect on the web, GLsync here makes no sense)
3993             if ((func.m_name == "FramebufferRenderbuffer") || (func.m_name == "FlushMappedBufferRange"))
3994             {
3995                 xml_func_return = "void";
3996             }
3997
3998             dynamic_string_array purified_xml_func_return(purify_gl_type(xml_func_return));
3999
4000             if (purified_func_return.size() != purified_xml_func_return.size())
4001             {
4002                 console::warning("Function %s return type mismatch: \"%s\" != \"%s\"\n", func.m_name.get_ptr(), return_type.get_ptr(), xml_func_return.get_ptr());
4003                 total_failures++;
4004             }
4005             else
4006             {
4007                 for (uint i = 0; i < purified_func_return.size(); i++)
4008                 {
4009                     if (purified_func_return[i] != purified_xml_func_return[i])
4010                     {
4011                         console::warning("Function %s return type mismatch: \"%s\" != \"%s\", param \"%s\" != \"%s\"\n", func.m_name.get_ptr(), return_type.get_ptr(), xml_func_return.get_ptr(), purified_func_return[i].get_ptr(), purified_xml_func_return[i].get_ptr());
4012                         total_failures++;
4013                     }
4014                 }
4015             }
4016
4017             uint param_index;
4018             for (param_index = 0; param_index < func.m_params.size(); param_index++)
4019             {
4020                 dynamic_string param_type(func_param_ctypes[param_index]);
4021                 dynamic_string xml_param_type(xml_func.m_params[param_index].m_type);
4022
4023                 // manual XML exceptions (incorrect on the web)
4024                 if ((param_index == 4) && (func.m_name == "GetTransformFeedbackVarying"))
4025                 {
4026                     xml_param_type = "GLsizei *";
4027                 }
4028                 if ((param_index == 3) && (func.m_name == "GetActiveUniformBlockiv"))
4029                 {
4030                     xml_param_type = "GLint *";
4031                 }
4032                 if ((param_index == 1) && (func.m_name == "CreateContextAttribsARB"))
4033                 {
4034                     xml_param_type = "GLXFBConfig";
4035                 }
4036                 if ((param_index == 3) && (func.m_name == "ProgramNamedParameter4fvNV"))
4037                 {
4038                     xml_param_type = "GLfloat *";
4039                 }
4040                 if ((param_index == 3) && (func.m_name == "ProgramNamedParameter4dvNV"))
4041                 {
4042                     xml_param_type = "GLdouble *";
4043                 }
4044
4045                 dynamic_string_array purified_param_type(purify_gl_type(param_type));
4046                 dynamic_string_array purified_xml_param_type(purify_gl_type(xml_param_type));
4047
4048                 if (purified_param_type.size() != purified_xml_param_type.size())
4049                 {
4050                     console::warning("Function %s param type mismatch: \"%s\" != \"%s\"\n", func.m_name.get_ptr(), param_type.get_ptr(), xml_param_type.get_ptr());
4051                     total_failures++;
4052                 }
4053                 else
4054                 {
4055                     for (uint j = 0; j < purified_param_type.size(); j++)
4056                     {
4057                         if (purified_param_type[j] != purified_xml_param_type[j])
4058                         {
4059                             console::warning("Function %s param type mismatch: \"%s\" != \"%s\", param \"%s\" != \"%s\"\n", func.m_name.get_ptr(),
4060                                              param_type.get_ptr(),
4061                                              xml_param_type.get_ptr(),
4062                                              purified_param_type[j].get_ptr(),
4063                                              purified_xml_param_type[j].get_ptr());
4064                             total_failures++;
4065                         }
4066                     }
4067                 }
4068             }
4069
4070             total_validated++;
4071         }
4072
4073         printf("\n");
4074         printf("Results of spec vs. XML function validation:\n");
4075         printf("Total passed: %u\n", total_validated);
4076         printf("Total failures: %u\n", total_failures);
4077         printf("Total skipped: %u\n", total_skipped);
4078         printf("Total functions present in spec but missing in XML: %u\n", total_not_found);
4079
4080         if (g_command_line_params.get_value_as_bool("verbose"))
4081         {
4082             printf("\nMissing function list:\n");
4083             for (uint i = 0; i < missing_funcs.size(); i++)
4084                 printf("%s\n", missing_funcs[i].get_ptr());
4085
4086             printf("\nMissing function list excluding OES and vendor suffixes:\n");
4087             for (uint i = 0; i < missing_funcs.size(); i++)
4088             {
4089                 const dynamic_string &func = missing_funcs[i];
4090
4091                 uint j;
4092                 for (j = 0; j < VOGL_ARRAY_SIZE(g_gl_vendor_suffixes); j++)
4093                     if (func.ends_with(g_gl_vendor_suffixes[j], true))
4094                         break;
4095
4096                 if (j < VOGL_ARRAY_SIZE(g_gl_vendor_suffixes))
4097                     continue;
4098
4099                 printf("%s\n", func.get_ptr());
4100             }
4101         }
4102
4103         return true;
4104     }
4105
4106     //-----------------------------------------------------------------------------------------------------------------------
4107     // update_whitelisted_funcs
4108     //-----------------------------------------------------------------------------------------------------------------------
4109     bool update_whitelisted_funcs(const gl_function_specs &gl_funcs, const gl_string_map &unique_ctype_enums, const gl_string_map &pointee_types, dynamic_string_array &whitelisted_funcs)
4110     {
4111         VOGL_NOTE_UNUSED(unique_ctype_enums);
4112         VOGL_NOTE_UNUSED(pointee_types);
4113
4114         dynamic_string_array new_whitelisted_funcs(whitelisted_funcs);
4115
4116         vogl::vector<bool> used_flags(m_simple_replay_funcs.size());
4117
4118         for (uint func_index = 0; func_index < gl_funcs.size(); func_index++)
4119         {
4120             const gl_function_def &func_def = gl_funcs[func_index];
4121             dynamic_string full_func_name(func_def.m_full_name); //cVarArg, "%s%s", g_lib_api_prefixes[gl_funcs[func_index].m_lib], gl_funcs[func_index].m_name.get_ptr());
4122
4123             uint i;
4124             for (i = 0; i < m_simple_replay_funcs.size(); i++)
4125             {
4126                 if (m_simple_replay_funcs[i].ends_with("*"))
4127                 {
4128                     dynamic_string prefix(m_simple_replay_funcs[i]);
4129                     prefix.left(prefix.get_len() - 1);
4130                     if (full_func_name.begins_with(prefix.get_ptr()))
4131                         break;
4132                 }
4133                 else
4134                 {
4135                     if (full_func_name == m_simple_replay_funcs[i])
4136                         break;
4137                 }
4138             }
4139
4140             if (i == m_simple_replay_funcs.size())
4141                 continue;
4142
4143             VOGL_ASSERT(!used_flags[i]);
4144             used_flags[i] = true;
4145
4146             if (whitelisted_funcs.find(full_func_name) < 0)
4147             {
4148                 console::printf("Adding simple GL replay func %s to func whitelist\n", full_func_name.get_ptr());
4149                 whitelisted_funcs.push_back(full_func_name);
4150             }
4151             else
4152             {
4153                 console::warning("Simple GL replay func %s was already in the func whitelist\n", full_func_name.get_ptr());
4154             }
4155         }
4156
4157         for (uint i = 0; i < m_simple_replay_funcs.size(); i++)
4158         {
4159             if (!used_flags[i])
4160                 console::warning("Simple replay func %s was not found/used\n", m_simple_replay_funcs[i].get_ptr());
4161         }
4162
4163         return true;
4164     }
4165
4166     //-----------------------------------------------------------------------------------------------------------------------
4167     // generate_simple_replay_funcs
4168     //-----------------------------------------------------------------------------------------------------------------------
4169     bool generate_simple_replay_funcs(const gl_function_specs &gl_funcs, const gl_string_map &unique_ctype_enums, const gl_string_map &pointee_types, const dynamic_string_array &whitelisted_funcs) const
4170     {
4171         dynamic_string_array new_whitelisted_funcs(whitelisted_funcs);
4172
4173         console::info("--- Generating \"gl_glx_simple_replay_funcs.inc\":\n");
4174
4175         FILE *pFile = vogl_fopen("gl_glx_simple_replay_funcs.inc", "w");
4176         if (!pFile)
4177         {
4178             console::error("Failed creating file gl_glx_simple_replay_funcs.inc\n");
4179             return false;
4180         }
4181
4182         dump_inc_file_header(pFile);
4183
4184         vogl::vector<bool> used_flags(m_simple_replay_funcs.size());
4185
4186         for (uint func_index = 0; func_index < gl_funcs.size(); func_index++)
4187         {
4188             const gl_function_def &func_def = gl_funcs[func_index];
4189             dynamic_string full_func_name(func_def.m_full_name); //cVarArg, "%s%s", g_lib_api_prefixes[gl_funcs[func_index].m_lib], gl_funcs[func_index].m_name.get_ptr());
4190
4191             uint i;
4192             for (i = 0; i < m_simple_replay_funcs.size(); i++)
4193             {
4194                 if (m_simple_replay_funcs[i].ends_with("*"))
4195                 {
4196                     dynamic_string prefix(m_simple_replay_funcs[i]);
4197                     prefix.left(prefix.get_len() - 1);
4198                     if (full_func_name.begins_with(prefix.get_ptr()))
4199                         break;
4200                 }
4201                 else
4202                 {
4203                     if (full_func_name == m_simple_replay_funcs[i])
4204                         break;
4205                 }
4206             }
4207
4208             if (i == m_simple_replay_funcs.size())
4209                 continue;
4210
4211             VOGL_ASSERT(!used_flags[i]);
4212             used_flags[i] = true;
4213
4214             vogl_fprintf(pFile, "VOGL_SIMPLE_REPLAY_FUNC_BEGIN(%s, func_def.m_params.size())\n", full_func_name.get_ptr());
4215
4216             for (uint param_index = 0; param_index < func_def.m_params.size(); param_index++)
4217             {
4218                 const bool last_param = (param_index == (func_def.m_params.size() - 1));
4219
4220                 if (func_def.m_params[param_index].m_ctype_enum.ends_with("_PTR"))
4221                 {
4222                     gl_string_map::const_iterator it = pointee_types.find(func_def.m_params[param_index].m_ctype_enum);
4223                     if (it == pointee_types.end())
4224                     {
4225                         console::error("Failed finding pointee ctype for ctype %s\n", func_def.m_params[param_index].m_ctype.get_ptr());
4226                         vogl_fclose(pFile);
4227                         return false;
4228                     }
4229
4230                     it = unique_ctype_enums.find(it->second);
4231                     if (it == unique_ctype_enums.end())
4232                     {
4233                         console::error("Failed finding pointee ctype for ctype %s\n", func_def.m_params[param_index].m_ctype.get_ptr());
4234                         vogl_fclose(pFile);
4235                         return false;
4236                     }
4237
4238                     vogl_fprintf(pFile, "   VOGL_SIMPLE_REPLAY_FUNC_PARAM_CLIENT_MEMORY(%s, %u)\n", it->second.get_ptr(), param_index);
4239                 }
4240                 else
4241                 {
4242                     // TODO: Add expected size of buffer check
4243                     vogl_fprintf(pFile, "   VOGL_SIMPLE_REPLAY_FUNC_PARAM_VALUE(%s, %u)\n", func_def.m_params[param_index].m_ctype.get_ptr(), param_index);
4244                 }
4245
4246                 if (!last_param)
4247                     vogl_fprintf(pFile, "   VOGL_SIMPLE_REPLAY_FUNC_PARAM_SEPERATOR\n");
4248             }
4249
4250             vogl_fprintf(pFile, "VOGL_SIMPLE_REPLAY_FUNC_END(%s)\n\n", full_func_name.get_ptr());
4251         }
4252
4253         vogl_fclose(pFile);
4254
4255         return true;
4256     }
4257
4258     //-----------------------------------------------------------------------------------------------------------------------
4259     // generate_replay_func_load_macros
4260     //-----------------------------------------------------------------------------------------------------------------------
4261     bool generate_replay_func_load_macros(const gl_function_specs &gl_funcs, const gl_string_map &unique_ctype_enums, const gl_string_map &pointee_types, const dynamic_string_array &whitelisted_funcs) const
4262     {
4263         VOGL_NOTE_UNUSED(unique_ctype_enums);
4264         VOGL_NOTE_UNUSED(pointee_types);
4265
4266         dynamic_string_array new_whitelisted_funcs(whitelisted_funcs);
4267
4268         console::info("--- Generating \"gl_glx_replay_helper_macros.inc\":\n");
4269
4270         FILE *pFile = vogl_fopen("gl_glx_replay_helper_macros.inc", "w");
4271         if (!pFile)
4272         {
4273             console::error("Failed creating file gl_glx_replay_helper_macros\n");
4274             return false;
4275         }
4276
4277         dump_inc_file_header(pFile);
4278
4279         for (uint func_index = 0; func_index < gl_funcs.size(); func_index++)
4280         {
4281             const gl_function_def &func_def = gl_funcs[func_index];
4282             dynamic_string full_func_name(func_def.m_full_name); //cVarArg, "%s%s", g_lib_api_prefixes[gl_funcs[func_index].m_lib], gl_funcs[func_index].m_name.get_ptr());
4283
4284             vogl_fprintf(pFile, "#define VOGL_REPLAY_LOAD_PARAMS_HELPER_%s %c\n", full_func_name.get_ptr(), func_def.m_params.size() ? '\\' : ' ');
4285
4286             for (uint param_index = 0; param_index < func_def.m_params.size(); param_index++)
4287             {
4288                 const bool last_param = (param_index == (func_def.m_params.size() - 1));
4289
4290                 if (func_def.m_params[param_index].m_ctype_enum.ends_with("_PTR"))
4291                 {
4292 #if 0
4293                                         gl_string_map::const_iterator it = pointee_types.find(func_def.m_params[param_index].m_ctype_enum);
4294                                         if (it == pointee_types.end())
4295                                         {
4296                                                 console::error("Failed finding pointee ctype for ctype %s\n", func_def.m_params[param_index].m_ctype.get_ptr());
4297                                                 vogl_fclose(pFile);
4298                                                 return false;
4299                                         }
4300
4301                                         it = unique_ctype_enums.find(it->second);
4302                                         if (it == unique_ctype_enums.end())
4303                                         {
4304                                                 console::error("Failed finding pointee ctype for ctype %s\n", func_def.m_params[param_index].m_ctype.get_ptr());
4305                                                 vogl_fclose(pFile);
4306                                                 return false;
4307                                         }
4308 #endif
4309
4310                     dynamic_string const_str;
4311                     if (!func_def.m_params[param_index].m_ctype.begins_with("const "))
4312                         const_str = "const ";
4313
4314                     vogl_fprintf(pFile, "   %s%s pTrace_%s = reinterpret_cast<%s%s>(trace_packet.get_param_client_memory_ptr(%u));", const_str.get_ptr(), func_def.m_params[param_index].m_ctype.get_ptr(), func_def.m_params[param_index].m_name.get_ptr(), const_str.get_ptr(), func_def.m_params[param_index].m_ctype.get_ptr(), param_index);
4315                 }
4316                 else
4317                 {
4318                     vogl_fprintf(pFile, "   %s %s = trace_packet.get_param_value<%s>(%u);", func_def.m_params[param_index].m_ctype.get_ptr(), func_def.m_params[param_index].m_name.get_ptr(), func_def.m_params[param_index].m_ctype.get_ptr(), param_index);
4319                 }
4320
4321                 if (!last_param)
4322                     vogl_fprintf(pFile, " \\\n");
4323                 else
4324                     vogl_fprintf(pFile, "\n");
4325             }
4326
4327             vogl_fprintf(pFile, "\n");
4328
4329             vogl_fprintf(pFile, "#define VOGL_REPLAY_CALL_GL_HELPER_%s GL_ENTRYPOINT(%s)(", full_func_name.get_ptr(), full_func_name.get_ptr());
4330
4331             for (uint param_index = 0; param_index < func_def.m_params.size(); param_index++)
4332             {
4333                 const bool last_param = (param_index == (func_def.m_params.size() - 1));
4334
4335                 if (func_def.m_params[param_index].m_ctype_enum.ends_with("_PTR"))
4336                 {
4337                     if (func_def.m_params[param_index].m_ctype_enum.begins_with("VOGL_CONST_"))
4338                         vogl_fprintf(pFile, "pTrace_%s", func_def.m_params[param_index].m_name.get_ptr());
4339                     else
4340                         vogl_fprintf(pFile, "pReplay_%s", func_def.m_params[param_index].m_name.get_ptr());
4341                 }
4342                 else
4343                 {
4344                     vogl_fprintf(pFile, "%s", func_def.m_params[param_index].m_name.get_ptr());
4345                 }
4346
4347                 if (!last_param)
4348                     vogl_fprintf(pFile, ", ");
4349             }
4350
4351             vogl_fprintf(pFile, ")\n\n");
4352         }
4353
4354         vogl_fclose(pFile);
4355
4356         return true;
4357     }
4358
4359     //-----------------------------------------------------------------------------------------------------------------------
4360     // read_regex_function_array
4361     //-----------------------------------------------------------------------------------------------------------------------
4362     bool read_regex_function_array(const char *pFilename, dynamic_string_array &funcs)
4363     {
4364         dynamic_string_array regex_func_patterns;
4365
4366         if (!file_utils::read_text_file(pFilename, regex_func_patterns, file_utils::cRTFTrim | file_utils::cRTFIgnoreEmptyLines | file_utils::cRTFIgnoreCommentedLines | file_utils::cRTFPrintErrorMessages))
4367             return false;
4368
4369         regex_func_patterns.unique(dynamic_string_equal_to_case_sensitive());
4370
4371         vogl::vector<bool> used_flags(regex_func_patterns.size());
4372
4373         for (uint i = 0; i < m_all_gl_funcs.size(); i++)
4374         {
4375             uint j;
4376             for (j = 0; j < regex_func_patterns.size(); j++)
4377                 if (regexp_full_match(m_all_gl_funcs[i].m_full_name.get_ptr(), regex_func_patterns[j].get_ptr()))
4378                     break;
4379
4380             if (j < regex_func_patterns.size())
4381             {
4382                 funcs.push_back(m_all_gl_funcs[i].m_full_name);
4383                 used_flags[j] = true;
4384             }
4385         }
4386
4387         for (uint i = 0; i < used_flags.size(); i++)
4388             if (!used_flags[i])
4389                 console::warning("%s: Regex pattern \"%s\" from file \"%s\" did not match any function names!\n", VOGL_METHOD_NAME, regex_func_patterns[i].get_ptr(), pFilename);
4390
4391         return true;
4392     }
4393 };
4394
4395 //----------------------------------------------------------------------------------------------------------------------
4396 // init_command_line_params
4397 //----------------------------------------------------------------------------------------------------------------------
4398 static bool init_command_line_params(int argc, char *argv[])
4399 {
4400     command_line_params::parse_config parse_cfg;
4401     parse_cfg.m_single_minus_params = true;
4402     parse_cfg.m_double_minus_params = true;
4403
4404     if (!g_command_line_params.parse(get_command_line_params(argc, argv), VOGL_ARRAY_SIZE(g_command_line_param_descs), g_command_line_param_descs, parse_cfg))
4405     {
4406         console::error("%s: Failed parsing command line parameters!\n", VOGL_FUNCTION_NAME);
4407         return false;
4408     }
4409
4410     return true;
4411 }
4412
4413 //-----------------------------------------------------------------------------------------------------------------------
4414 // check_for_option
4415 //-----------------------------------------------------------------------------------------------------------------------
4416 static bool check_for_option(int argc, char *argv[], const char *pOption)
4417 {
4418     for (int i = 1; i < argc; i++)
4419     {
4420         if ((argv[i][0] == '/') || (argv[i][0] == '-'))
4421         {
4422             if (vogl_stricmp(&argv[i][1], pOption) == 0)
4423                 return true;
4424         }
4425     }
4426     return false;
4427 }
4428
4429 //-----------------------------------------------------------------------------------------------------------------------
4430 // print_title
4431 //-----------------------------------------------------------------------------------------------------------------------
4432 static void print_title()
4433 {
4434     console::printf("voglgen");
4435     console::printf(" %s Built %s, %s", vogl_is_x64() ? "x64" : "x86", __DATE__, __TIME__);
4436 #ifdef VOGL_BUILD_DEBUG
4437     console::printf(" DEBUG build");
4438 #endif
4439     console::printf("\n");
4440     console::printf("Debugger present: %u\n", vogl_is_debugger_present());
4441 }
4442
4443 //-------------------------------------------------------------------------------------------------------------------------------
4444 // main_internal
4445 //-------------------------------------------------------------------------------------------------------------------------------
4446 static int main_internal(int argc, char *argv[])
4447 {
4448     VOGL_NOTE_UNUSED(argc);
4449     VOGL_NOTE_UNUSED(argv);
4450     char cwd[1024];
4451
4452     cwd[0] = 0;
4453     colorized_console::init();
4454     colorized_console::set_exception_callback();
4455
4456     if (check_for_option(argc, argv, "quiet"))
4457         console::disable_output();
4458
4459     print_title();
4460
4461     bool status = false;
4462     if (init_command_line_params(argc, argv))
4463     {
4464         dynamic_string srcdir;
4465
4466         if (g_command_line_params.get_value_as_string(srcdir, "srcdir"))
4467         {
4468             printf("srcdir: '%s'\n", srcdir.get_ptr());
4469             chdir(srcdir.get_ptr());
4470         }
4471         // If we can't find this text file, try the vogl/glspec dir.
4472         if (access("apitrace_gl_param_info.txt", F_OK) != 0)
4473         {
4474             if (access("../../vogl/glspec/apitrace_gl_param_info.txt", F_OK) == 0)
4475                 chdir("../../vogl/glspec");
4476         }
4477         getcwd(cwd, sizeof(cwd));
4478         printf("Current working directory: %s\n\n", cwd);
4479
4480         vogl_gen generator;
4481
4482         console::printf("---------------- Begin Generator Init\n");
4483         status = generator.init();
4484         console::printf("---------------- End Generator Init\n");
4485
4486         if (status)
4487         {
4488             dynamic_string regex_pattern;
4489             if (g_command_line_params.get_value_as_string(regex_pattern, "func_regex"))
4490                 generator.func_regex(regex_pattern.get_ptr());
4491             else if (g_command_line_params.get_value_as_string(regex_pattern, "param_regex"))
4492                 generator.param_regex(regex_pattern.get_ptr());
4493             else if (g_command_line_params.get_value_as_string(regex_pattern, "category_regex"))
4494                 generator.category_regex(regex_pattern.get_ptr());
4495             else if (g_command_line_params.get_value_as_string(regex_pattern, "namespace_regex"))
4496                 generator.namespace_regex(regex_pattern.get_ptr());
4497             else if (g_command_line_params.get_value_as_string(regex_pattern, "ctype_regex"))
4498                 generator.ctype_regex(regex_pattern.get_ptr());
4499             else
4500             {
4501                 console::printf("---------------- Begin Generate\n");
4502                 status = generator.generate();
4503                 console::printf("---------------- End Generate\n");
4504
4505                 if (status && g_command_line_params.get_value_as_bool("debug"))
4506                 {
4507                     console::printf("---------------- Begin Debug Dump\n");
4508                     generator.dump_debug_files();
4509                     console::printf("---------------- End Debug Dump\n");
4510                 }
4511             }
4512         }
4513     }
4514
4515     if (!status)
4516         console::error("voglgen FAILED!\n");
4517     else
4518         console::printf("voglgen succeeded\n  (to %s)\n", cwd);
4519
4520     int exit_status = status ? EXIT_SUCCESS : EXIT_FAILURE;
4521
4522     console::printf("%u warning(s), %u error(s)\n", console::get_total_messages(cWarningConsoleMessage), console::get_total_messages(cErrorConsoleMessage));
4523
4524     console::printf("Exit status: %i\n", exit_status);
4525
4526     colorized_console::deinit();
4527
4528     vogl_print_heap_stats();
4529
4530     return status ? EXIT_SUCCESS : EXIT_FAILURE;
4531 }
4532
4533 //-----------------------------------------------------------------------------------------------------------------------
4534 // pause_and_wait
4535 //-----------------------------------------------------------------------------------------------------------------------
4536 static void pause_and_wait(void)
4537 {
4538     console::enable_output();
4539
4540     console::message("\nPress a key to continue.\n");
4541
4542     for (;;)
4543     {
4544         if (vogl_getch() != -1)
4545             break;
4546     }
4547 }
4548
4549 //-----------------------------------------------------------------------------------------------------------------------
4550 // main
4551 //-----------------------------------------------------------------------------------------------------------------------
4552 int main(int argc, char *argv[])
4553 {
4554     int status = EXIT_FAILURE;
4555
4556     if (vogl_is_debugger_present())
4557     {
4558         status = main_internal(argc, argv);
4559     }
4560     else
4561     {
4562 #ifdef _MSC_VER
4563         __try
4564         {
4565             status = main_internal(argc, argv);
4566         }
4567         __except(EXCEPTION_EXECUTE_HANDLER)
4568         {
4569             console::error("Uncached exception! voglgen command line tool failed!\n");
4570         }
4571 #else
4572         status = main_internal(argc, argv);
4573 #endif
4574     }
4575
4576     if (check_for_option(argc, argv, "pause"))
4577     {
4578         if ((status == EXIT_FAILURE) || (console::get_total_messages(cErrorConsoleMessage)))
4579             pause_and_wait();
4580     }
4581
4582     return status;
4583 }