summaryrefslogtreecommitdiff
path: root/auto/lib/OpenGL/Spec.pm
diff options
context:
space:
mode:
Diffstat (limited to 'auto/lib/OpenGL/Spec.pm')
-rw-r--r--auto/lib/OpenGL/Spec.pm202
1 files changed, 202 insertions, 0 deletions
diff --git a/auto/lib/OpenGL/Spec.pm b/auto/lib/OpenGL/Spec.pm
new file mode 100644
index 0000000..1311b39
--- /dev/null
+++ b/auto/lib/OpenGL/Spec.pm
@@ -0,0 +1,202 @@
+package OpenGL::Spec;
+
+# A very simple task further complicated by the fact that some people
+# can't read, others use legacy Operating Systems, and others don't give
+# a damn about using a halfway decent text editor.
+#
+# The code to parse the _template_ is so simple and straightforward...
+# yet the code to parse the real spec files is this mess.
+
+my %typemap = (
+ bitfield => "GLbitfield",
+ boolean => "GLboolean",
+ # fsck up in EXT_vertex_array
+ Boolean => "GLboolean",
+ byte => "GLbyte",
+ clampd => "GLclampd",
+ clampf => "GLclampf",
+ double => "GLdouble",
+ enum => "GLenum",
+ # Intel fsck up
+ Glenum => "GLenum",
+ float => "GLfloat",
+ half => "GLuint",
+ int => "GLint",
+ short => "GLshort",
+ sizei => "GLsizei",
+ ubyte => "GLubyte",
+ uint => "GLuint",
+ ushort => "GLushort",
+ DMbuffer => "void *",
+
+ # ARB VBO introduces these
+ sizeiptrARB => "GLsizeiptrARB",
+ intptrARB => "GLintptrARB",
+
+ # ARB shader objects introduces these, charARB is at least 8 bits,
+ # handleARB is at least 32 bits
+ charARB => "GLcharARB",
+ handleARB => "GLhandleARB",
+
+ # GLX 1.3 defines new types which might not be available at compile time
+ #GLXFBConfig => "void*",
+ #GLXFBConfigID => "XID",
+ #GLXContextID => "XID",
+ #GLXWindow => "XID",
+ #GLXPbuffer => "XID",
+
+ # Weird stuff for some SGIX extension
+ #GLXFBConfigSGIX => "void*",
+ #GLXFBConfigIDSGIX => "XID",
+);
+
+my %void_typemap = (
+ void => "GLvoid",
+);
+
+my $section_re = qr{^[A-Z]};
+my $function_re = qr{^(.+) ([a-z][a-z0-9_]*) \((.+)\)$}i;
+my $token_re = qr{^([A-Z0-9][A-Z0-9_]*):?\s+((?:0x)?[0-9A-F]+)(.*)$};
+my $prefix_re = qr{^(?:AGL | GLX | WGL)_}x;
+my $eofnc_re = qr{ \);?$ | ^$ }x;
+my $function_re = qr{^(.+) ([a-z][a-z0-9_]*) \((.+)\)$}i;
+my $prefix_re = qr{^(?:gl | agl | wgl | glX)}x;
+my $types_re = __compile_wordlist_cap(keys %typemap);
+my $voidtype_re = __compile_wordlist_cap(keys %void_typemap);
+
+sub new($)
+{
+ my $class = shift;
+ my $self = { section => {} };
+ $self->{filename} = shift;
+ local $/;
+ open(my $fh, "<$self->{filename}") or die "Can't open $self->{filename}";
+ my $content = <$fh>;
+ my $section;
+ my $s = $self->{section};
+
+ $content =~ s{[ \t]+$}{}mg;
+ # Join lines that end with a word-character and ones that *begin*
+ # with one
+ $content =~ s{(\w)\n(\w)}{$1 $2}sg;
+
+ foreach (split /\n/, $content)
+ {
+ if (/$section_re/)
+ {
+ chomp;
+ s/^Name String$/Name Strings/; # Fix common mistake
+ $section = $_;
+ $s->{$section} = "";
+ }
+ elsif (defined $section and exists $s->{$section})
+ {
+ s{^\s+}{}mg; # Remove leading whitespace
+ $s->{$section} .= $_ . "\n";
+ }
+ }
+
+ $s->{$_} =~ s{(?:^\n+|\n+$)}{}s foreach keys %$s;
+
+ bless $self, $class;
+}
+
+sub sections()
+{
+ my $self = shift;
+ keys %{$self->{section}};
+}
+
+sub name()
+{
+ my $self = shift;
+ $self->{section}->{Name};
+}
+
+sub name_strings()
+{
+ my $self = shift;
+ split("\n", $self->{section}->{"Name Strings"});
+}
+
+sub tokens()
+{
+ my $self = shift;
+ my %tokens = ();
+ foreach (split /\n/, $self->{section}->{"New Tokens"})
+ {
+ next unless /$token_re/;
+ my ($name, $value) = ($1, $2);
+ $name =~ s{^}{GL_} unless $name =~ /$prefix_re/;
+ $tokens{$name} = $value;
+ }
+
+ return %tokens;
+}
+
+sub functions()
+{
+ my $self = shift;
+ my %functions = ();
+ my @fnc = ();
+
+ foreach (split /\n/, $self->{section}->{"New Procedures and Functions"})
+ {
+ push @fnc, $_ unless ($_ eq "" or $_ eq "None");
+
+ next unless /$eofnc_re/;
+
+ if (__normalize_proto(@fnc) =~ /$function_re/)
+ {
+ my ($return, $name, $parms) = ($1, $2, $3);
+ if (!__ignore_function($name, $extname))
+ {
+ $name =~ s/^/gl/ unless $name =~ /$prefix_re/;
+ if ($name =~ /^gl/ && $name !~ /^glX/)
+ {
+ $return =~ s/$types_re/$typemap{$1}/g;
+ $return =~ s/$voidtype_re/$void_typemap{$1}/g;
+ $parms =~ s/$types_re/$typemap{$1}/g;
+ $parms =~ s/$voidtype_re/$void_typemap{$1}/g;
+ }
+ $functions{$name} = {
+ rtype => $return,
+ parms => $parms,
+ };
+ }
+ }
+ @fnc = ();
+ }
+
+ return %functions;
+}
+
+sub __normalize_proto
+{
+ local $_ = join(" ", @_);
+ s/\s+/ /g; # multiple whitespace -> single space
+ s/\s*\(\s*/ \(/; # exactly one space before ( and none after
+ s/\s*\)\s*/\)/; # no after before or after )
+ s/\s*\*([a-zA-Z])/\* $1/; # "* identifier" XXX: g missing?
+ s/\*wgl/\* wgl/; # "* wgl" XXX: why doesn't the
+ s/\*glX/\* glX/; # "* glX" previous re catch this?
+ s/\.\.\./void/; # ... -> void
+ s/;$//; # remove ; at the end of the line
+ return $_;
+}
+
+sub __ignore_function
+{
+ return 0;
+}
+
+sub __compile_regex
+{
+ my $regex = join('', @_);
+ return qr/$regex/
+}
+
+sub __compile_wordlist_cap
+{
+ __compile_regex('\b(', join('|', @_), ')\b');
+}