1#! /usr/bin/perl -w
2
3# This file generates three source files required to build sage
4# This first part of this file extracts the extension names, the #defines
5# and the function names. This process also creates a cutsom glext.h file
6# for use in sage The remaining parts of the file write the header and
7# code file.
8
9# Input Filenames
10$GLEXT_FILE="glext.h";
11# Output Filenames
12$GLEXT_SAGE_FILE="sage/sage_fptr.h";
13$SAGE_HEADER_FILE="sage/sage.h";
14$SAGE_CODE_FILE="sage/sage.c";
15$LICENSE_FILE="templates/license";
16
17#regular expressions
18$FUNCTION_REGEXP="([A-Za-z*]*) APIENTRY ([a-zA-Z0-9]*) (.*)";
19$DEFINE_REGEXP="\#define (GL_[A-Za-z0-9_]*) 1\$";
20$VERSION_REGEXP="\#ifndef (GL_[A-Za-z0-9_]*)";
21$TOKEN_REGEXP="\#define (GL_[A-Za-z0-9_]*)[ \t]*((0x[0-9A-F]*)\|(GL_.*))\$";
22$TYPES_REGEXP="typedef ([ A-Za-z0-9_*]*)[ \t]*(GL[A-Za-z0-9_]*);";
23
24#flag checking whether we need to add an endif or not
25$WAIT_FOR_ENDIF="false";
26
27# Open glext.h for input
28open (GLEXT, "<$GLEXT_FILE") or die "Cannot open $GLEXT_FILE\n";
29#loop through every line in glext.h
30while (<GLEXT>) {
31  if  ($_ =~ m|$VERSION_REGEXP|) {
32    push(@FUNCTION_HEADER_DEF, $_); # write into header
33    $WAIT_FOR_ENDIF="true"; # we now need to write a corresponding endif when its next found
34  } elsif  ($_ =~ m|$TYPES_REGEXP|) {
35    push(@FUNCTION_HEADER_DEF, $_); # write into header
36    $WAIT_FOR_ENDIF="true"; # we now need to write a corresponding endif when its next found
37  } elsif ($_ =~ m|$FUNCTION_REGEXP|) {
38    ($RET, $FUNCTION, $ARGS) = ($_ =~ m|$FUNCTION_REGEXP|); # Extract function name
39    $PFN_FUNCTION = "SAGE_PFN".uc($FUNCTION)."PROC"; # make the typedef name
40    push(@TYPEDEFS, "typedef $RET (APIENTRYP $PFN_FUNCTION) $ARGS\n");
41
42    push(@FUNCTION_HEADER_FPTR , "SAGEAPI $PFN_FUNCTION SAGE_$FUNCTION;\n"); # declare function for header
43    push(@FUNCTION_HEADER_DEF, "#ifndef $FUNCTION\n");
44    push(@FUNCTION_HEADER_DEF, "#define $FUNCTION SAGE_$FUNCTION\n");
45    push(@FUNCTION_HEADER_DEF, "#endif\n\n");
46#    push (@FUNCTION_CODE, "$PFN_FUNCTION SAGE_$FUNCTION = NULL;\n"); # declaraion of function in c file
47    push (@FUNCTION_CODE, "$PFN_FUNCTION SAGE_$FUNCTION = ($PFN_FUNCTION)&badfunc;\n"); # declaraion of function in c file
48#    push (@FUNCTION_INIT,"  SAGE_$FUNCTION = ($PFN_FUNCTION)SDL_GL_GetProcAddress(\"$FUNCTION\");\n"); # linkup function ptr
49    push (@FUNCTION_INIT,"  SAGE_$FUNCTION = ($PFN_FUNCTION)getPtr(\"$FUNCTION\");\n"); # linkup function ptr
50  # Grab #defines
51  } elsif  ($_ =~ m|$DEFINE_REGEXP|) {
52    ($DEF) = ($_ =~ m|$DEFINE_REGEXP|); # extract #define name
53    if ($DEF =~ m|GL_VERSION|) {
54      # ignore GL_VERSION for BOOLS def
55    } else  {
56      push (@BOOLS, $DEF);
57    }
58    push(@FUNCTION_HEADER_DEF, $_); # write into header
59  } elsif  ($_ =~ m|$TOKEN_REGEXP|) {
60    push(@FUNCTION_HEADER_DEF, $_); # write into header
61  # grab endif if required
62  } elsif ($_ =~ m|\#endif|) { # write the endif now we have it
63    if ($WAIT_FOR_ENDIF eq "true") {
64      $WAIT_FOR_ENDIF="false";
65      push(@FUNCTION_HEADER_DEF, "#endif\n\n");
66    }
67  }
68}
69#copy into two arrays - we use this twice (prob a better way to do this)
70for (@BOOLS) {
71  push(@BOOLS_DEF, $_);
72  push(@BOOLS_ENUM, $_);
73}
74
75
76## Begin writing output files
77
78
79## This header file just contains the function pointer prototypes.
80print "Writing $GLEXT_SAGE_FILE\n";
81# Open our glext.h for output
82open (GLEXT_SAGE, ">$GLEXT_SAGE_FILE") or die "Cannot open $GLEXT_SAGE_FILE\n";
83
84
85print GLEXT_SAGE "/* This file is autogenerated by build_sage.pl */\n";
86open (LICENSE, "<$LICENSE_FILE") or die "Can't open: $LICENSE_FILE\n";
87while(<LICENSE>) { print GLEXT_SAGE $_; }
88close LICENSE;
89
90print GLEXT_SAGE "\n";
91print GLEXT_SAGE "#ifndef GLEXT_SAGE_H\n";
92print GLEXT_SAGE "#define GLEXT_SAGE_H 1\n";
93print GLEXT_SAGE "\n";
94
95print GLEXT_SAGE "#ifndef APIENTRY\n";
96print GLEXT_SAGE "#define APIENTRY\n";
97print GLEXT_SAGE "#endif\n\n";
98
99print GLEXT_SAGE "#ifndef APIENTRYP\n";
100print GLEXT_SAGE "#define APIENTRYP APIENTRY *\n";
101print GLEXT_SAGE "#endif\n\n";
102
103for (@TYPEDEFS) {
104  print GLEXT_SAGE $_;
105}
106
107print GLEXT_SAGE "#endif\n";
108close GLEXT_SAGE;
109
110# This file contains all the definitions from glext.h
111# This file is reponsible for defining the numeric constants used by applications
112# to determine whether a particular extension has been found.
113# This file also transparently #defines normal function names as the functio npointer
114# if is not already defined. Some care needs to be taken to ensure that standard functions
115# are properly guarded against by version number rather than name.
116
117open (SAGE_HEADER, ">$SAGE_HEADER_FILE") or die "Can't open: $SAGE_HEADER_FILE\n";
118print "Writing $SAGE_HEADER_FILE\n";
119#Write autogen comment
120print SAGE_HEADER "/* This file is autogenerated by build_sage.pl */\n";
121
122#Write license header
123open (LICENSE, "<$LICENSE_FILE") or die "Can't open: $LICENSE_FILE\n";
124while(<LICENSE>) { print SAGE_HEADER $_; }
125close LICENSE;
126print SAGE_HEADER "\n";
127
128# Write header check
129print SAGE_HEADER "#ifndef SAGE_H\n";
130print SAGE_HEADER "#define SAGE_H 1\n";
131print SAGE_HEADER "\n";
132
133print SAGE_HEADER "#ifdef __glext_h_ \n";
134print SAGE_HEADER "#error glext.h has already been included.\n";
135print SAGE_HEADER "#endif\n\n";
136
137print SAGE_HEADER "#define __glext_h_ 1\n\n";
138
139# Write defines for use in extensions array
140$INDEX = 0; # Set counter to zero
141for (@BOOLS_ENUM) {
142  print SAGE_HEADER "#define ".uc($_)." $INDEX\n"; # write a #define
143  $INDEX = $INDEX + 1; # increment counter
144}
145# This allows use to determine the size of the extensions array
146print SAGE_HEADER "#define SAGE_LAST_EXTENSION ".$INDEX."\n\n";
147
148#include the SAGEAPI stuff
149print SAGE_HEADER "#include <sage/header.h>\n";
150print SAGE_HEADER "#include <sage/GL.h>\n";
151# This is required to define ptrdiff_t
152print SAGE_HEADER "#include <stddef.h>\n";
153#define the extensions array
154print SAGE_HEADER "SAGEAPI int sage_ext[SAGE_LAST_EXTENSION];\n\n";
155
156
157#print all the token definitions
158for (@FUNCTION_HEADER_DEF) {
159  print SAGE_HEADER $_;
160}
161
162## Include prototypes.
163## By now all the OpenGL types should have been defined.
164printf SAGE_HEADER "\n";
165print SAGE_HEADER "#include <$GLEXT_SAGE_FILE>\n\n";
166printf SAGE_HEADER "\n";
167
168#print the function declarations and #if's generated from glext.h
169for (@FUNCTION_HEADER_FPTR) {
170  print SAGE_HEADER $_;
171}
172
173#add the init function prototype
174print SAGE_HEADER "\nSAGEAPI int sage_init(void);\n\n";
175#endif for header check
176print SAGE_HEADER "#endif\n";
177#close file handle
178close SAGE_HEADER;
179
180# Write the code file
181
182#open code file for writing
183open (SAGE_CODE, ">$SAGE_CODE_FILE") or die "Can't open: $SAGE_CODE_FILE\n";
184print "Writing $SAGE_CODE_FILE\n";
185
186#Write autogen comment
187print SAGE_CODE "/* This file is autogenerated by build_sage.pl */\n";
188
189#Write license header
190open (LICENSE, "<$LICENSE_FILE") or die "Can't open: $LICENSE_FILE\n";
191while(<LICENSE>) { print SAGE_CODE $_; }
192close LICENSE;
193print SAGE_CODE "\n";
194
195#write the #includes
196print SAGE_CODE "#include <$SAGE_HEADER_FILE>\n";
197print SAGE_CODE "#include \"SDL.h\"\n";
198print SAGE_CODE "#include <sage/utility.h>\n";
199print SAGE_CODE "#include <stdlib.h>\n";
200print SAGE_CODE "\n";
201print SAGE_CODE "static void badfunc(void*v, ...) {\n";
202print SAGE_CODE "  fprintf(stderr, \"Error: You have tried to call a sage function pointer that is NULL.\\n\");\n";
203print SAGE_CODE "  fflush(stderr);\n";
204print SAGE_CODE "  abort();\n";
205print SAGE_CODE "}\n";
206print SAGE_CODE "\n";
207print SAGE_CODE "static void* getPtr(const char *func) {\n";
208print SAGE_CODE "  void *p = SDL_GL_GetProcAddress(func);\n";
209print SAGE_CODE "  if (p == NULL) p = &badfunc;\n";
210print SAGE_CODE "  return p;\n";
211print SAGE_CODE "}\n";
212print SAGE_CODE "\n";
213
214#start writing the function pointer declarations
215for (@FUNCTION_CODE) {
216  print SAGE_CODE $_;
217}
218print SAGE_CODE "\n";
219
220# declare the extension array
221print SAGE_CODE "int sage_ext[SAGE_LAST_EXTENSION];\n\n";
222
223#start writing the init function
224print SAGE_CODE "int sage_init(void) {\n";
225## Gets the glExtension string each time init is called.
226print SAGE_CODE "  GLubyte *ext_str = (GLubyte*)glGetString(GL_EXTENSIONS);\n";
227print SAGE_CODE "  if (ext_str == NULL) {\n";
228print SAGE_CODE "    fprintf(stderr, \"Sage Error: Could not get extension string\\n\");\n";
229print SAGE_CODE "    return 1;\n";
230print SAGE_CODE "  }\n";
231## Write the code to hook up the function pointers.
232for (@FUNCTION_INIT) {
233  print SAGE_CODE $_;
234}
235
236# start writing the extension check code
237for (@BOOLS_DEF) {
238  print SAGE_CODE "  sage_ext[".uc($_)."] = isExtensionSupported(\"$_\", ext_str);\n";
239}
240#write closing brace for function
241print SAGE_CODE "  return 0;\n";
242print SAGE_CODE "}\n";
243#close file handle
244close SAGE_CODE;
245
246