kusano 7d535a
#!/usr/bin/perl
kusano 7d535a
##
kusano 7d535a
## Copyright (C) 2002-2008, Marcelo E. Magallon <mmagallo[]debian org=""></mmagallo[]debian>
kusano 7d535a
## Copyright (C) 2002-2008, Milan Ikits <milan ikits[]ieee="" org=""></milan>
kusano 7d535a
##
kusano 7d535a
## This program is distributed under the terms and conditions of the GNU
kusano 7d535a
## General Public License Version 2 as published by the Free Software
kusano 7d535a
## Foundation or, at your option, any later version.
kusano 7d535a
kusano 7d535a
use strict;
kusano 7d535a
use warnings;
kusano 7d535a
kusano 7d535a
sub compile_regex
kusano 7d535a
{
kusano 7d535a
    my $regex = join('', @_);
kusano 7d535a
    return qr/$regex/
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
my @sections = (
kusano 7d535a
    "Name",
kusano 7d535a
    "Name Strings?",
kusano 7d535a
    "New Procedures and Functions",
kusano 7d535a
    "New Tokens",
kusano 7d535a
    "Additions to Chapter.*",
kusano 7d535a
);
kusano 7d535a
kusano 7d535a
my %typemap = (
kusano 7d535a
    bitfield => "GLbitfield",
kusano 7d535a
    boolean  => "GLboolean",
kusano 7d535a
    # fsck up in EXT_vertex_array
kusano 7d535a
    Boolean  => "GLboolean",
kusano 7d535a
    byte     => "GLbyte",
kusano 7d535a
    clampd   => "GLclampd",
kusano 7d535a
    clampf   => "GLclampf",
kusano 7d535a
    double   => "GLdouble",
kusano 7d535a
    enum     => "GLenum",
kusano 7d535a
    # Intel fsck up
kusano 7d535a
    Glenum   => "GLenum",
kusano 7d535a
    float    => "GLfloat",
kusano 7d535a
    half     => "GLhalf",
kusano 7d535a
    int      => "GLint",
kusano 7d535a
    short    => "GLshort",
kusano 7d535a
    sizei    => "GLsizei",
kusano 7d535a
    ubyte    => "GLubyte",
kusano 7d535a
    uint     => "GLuint",
kusano 7d535a
    ushort   => "GLushort",
kusano 7d535a
    DMbuffer => "void *",
kusano 7d535a
    # Nvidia video output fsck up
kusano 7d535a
    int64EXT => "GLint64EXT",
kusano 7d535a
    uint64EXT=> "GLuint64EXT",
kusano 7d535a
kusano 7d535a
    # ARB VBO introduces these.
kusano 7d535a
kusano 7d535a
    sizeiptr => "GLsizeiptr",
kusano 7d535a
    intptr   => "GLintptr",
kusano 7d535a
    sizeiptrARB => "GLsizeiptrARB",
kusano 7d535a
    intptrARB   => "GLintptrARB",
kusano 7d535a
kusano 7d535a
    # ARB shader objects introduces these, charARB is at least 8 bits,
kusano 7d535a
    # handleARB is at least 32 bits
kusano 7d535a
    charARB => "GLcharARB",
kusano 7d535a
    handleARB => "GLhandleARB",
kusano 7d535a
kusano 7d535a
    char => "GLchar",
kusano 7d535a
kusano 7d535a
    # OpenGL 3.2 and GL_ARB_sync
kusano 7d535a
kusano 7d535a
    int64  => "GLint64",
kusano 7d535a
    uint64 => "GLuint64",
kusano 7d535a
    sync   => "GLsync",
kusano 7d535a
kusano 7d535a
    # AMD_debug_output
kusano 7d535a
kusano 7d535a
    DEBUGPROCAMD => "GLDEBUGPROCAMD",
kusano 7d535a
kusano 7d535a
    # ARB_debug_output
kusano 7d535a
kusano 7d535a
    DEBUGPROCARB => "GLDEBUGPROCARB",
kusano 7d535a
kusano 7d535a
    # KHR_debug
kusano 7d535a
kusano 7d535a
    DEBUGPROC => "GLDEBUGPROC",
kusano 7d535a
kusano 7d535a
    vdpauSurfaceNV => "GLvdpauSurfaceNV",
kusano 7d535a
    
kusano 7d535a
    # GLX 1.3 defines new types which might not be available at compile time
kusano 7d535a
kusano 7d535a
    #GLXFBConfig   => "void*",
kusano 7d535a
    #GLXFBConfigID => "XID",
kusano 7d535a
    #GLXContextID  => "XID",
kusano 7d535a
    #GLXWindow     => "XID",
kusano 7d535a
    #GLXPbuffer    => "XID",
kusano 7d535a
kusano 7d535a
    # Weird stuff to some SGIX extension
kusano 7d535a
kusano 7d535a
    #GLXFBConfigSGIX   => "void*",
kusano 7d535a
    #GLXFBConfigIDSGIX => "XID",
kusano 7d535a
kusano 7d535a
);
kusano 7d535a
kusano 7d535a
my %voidtypemap = (
kusano 7d535a
    void    => "GLvoid",
kusano 7d535a
);
kusano 7d535a
kusano 7d535a
my %taboo_tokens = (
kusano 7d535a
    GL_ZERO => 1,
kusano 7d535a
);
kusano 7d535a
kusano 7d535a
# list of function definitions to be ignored, unless they are being defined in
kusano 7d535a
# the given spec.  This is an ugly hack arround the fact that people writing
kusano 7d535a
# spec files seem to shut down all brain activity while they are at this task.
kusano 7d535a
#
kusano 7d535a
# This will be moved to its own file eventually.
kusano 7d535a
#
kusano 7d535a
# (mem, 2003-03-19)
kusano 7d535a
kusano 7d535a
my %fnc_ignore_list = (
kusano 7d535a
    "BindProgramARB"                => "ARB_vertex_program",
kusano 7d535a
    "ColorSubTableEXT"              => "EXT_color_subtable",
kusano 7d535a
    "DeleteProgramsARB"             => "ARB_vertex_program",
kusano 7d535a
    "GenProgramsARB"                => "ARB_vertex_program",
kusano 7d535a
    "GetProgramEnvParameterdvARB"   => "ARB_vertex_program",
kusano 7d535a
    "GetProgramEnvParameterfvARB"   => "ARB_vertex_program",
kusano 7d535a
    "GetProgramLocalParameterdvARB" => "ARB_vertex_program",
kusano 7d535a
    "GetProgramLocalParameterfvARB" => "ARB_vertex_program",
kusano 7d535a
    "GetProgramStringARB"           => "ARB_vertex_program",
kusano 7d535a
    "GetProgramivARB"               => "ARB_vertex_program",
kusano 7d535a
    "IsProgramARB"                  => "ARB_vertex_program",
kusano 7d535a
    "ProgramEnvParameter4dARB"      => "ARB_vertex_program",
kusano 7d535a
    "ProgramEnvParameter4dvARB"     => "ARB_vertex_program",
kusano 7d535a
    "ProgramEnvParameter4fARB"      => "ARB_vertex_program",
kusano 7d535a
    "ProgramEnvParameter4fvARB"     => "ARB_vertex_program",
kusano 7d535a
    "ProgramLocalParameter4dARB"    => "ARB_vertex_program",
kusano 7d535a
    "ProgramLocalParameter4dvARB"   => "ARB_vertex_program",
kusano 7d535a
    "ProgramLocalParameter4fARB"    => "ARB_vertex_program",
kusano 7d535a
    "ProgramLocalParameter4fvARB"   => "ARB_vertex_program",
kusano 7d535a
    "ProgramStringARB"              => "ARB_vertex_program",
kusano 7d535a
    "glXCreateContextAttribsARB"    => "ARB_create_context_profile",
kusano 7d535a
    "wglCreateContextAttribsARB"    => "WGL_ARB_create_context_profile",
kusano 7d535a
);
kusano 7d535a
kusano 7d535a
my %regex = (
kusano 7d535a
    eofnc    => qr/(?:\);?$|^$)/, # )$ | );$ | ^$
kusano 7d535a
    extname  => qr/^[A-Z][A-Za-z0-9_]+$/,
kusano 7d535a
    none     => qr/^\(none\)$/,
kusano 7d535a
    function => qr/^(.+) ([a-z][a-z0-9_]*) \((.+)\)$/i,
kusano 7d535a
    prefix   => qr/^(?:[aw]?gl|glX)/, # gl | agl | wgl | glX
kusano 7d535a
    tprefix  => qr/^(?:[AW]?GL|GLX)_/, # GL_ | AGL_ | WGL_ | GLX_
kusano 7d535a
    section  => compile_regex('^(', join('|', @sections), ')$'), # sections in spec
kusano 7d535a
    token    => qr/^([A-Z0-9][A-Z0-9_x]*):?\s+((?:0x)?[0-9A-F]+)(.*)$/, # define tokens
kusano 7d535a
    types    => compile_regex('\b(', join('|', keys %typemap), ')\b'), # var types
kusano 7d535a
    voidtype => compile_regex('\b(', keys %voidtypemap, ')\b '), # void type
kusano 7d535a
);
kusano 7d535a
kusano 7d535a
# reshapes the the function declaration from multiline to single line form
kusano 7d535a
sub normalize_prototype
kusano 7d535a
{
kusano 7d535a
    local $_ = join(" ", @_);
kusano 7d535a
    s/\s+/ /g;                # multiple whitespace -> single space
kusano 7d535a
    s/\<.*\>//g;              # remove <comments> from direct state access extension</comments>
kusano 7d535a
    s/\<.*$//g;               # remove incomplete <comments> from direct state access extension</comments>
kusano 7d535a
    s/\s*\(\s*/ \(/;          # exactly one space before ( and none after
kusano 7d535a
    s/\s*\)\s*/\)/;           # no space before or after )
kusano 7d535a
    s/\s*\*([a-zA-Z])/\* $1/; # "* identifier"
kusano 7d535a
    s/\*wgl/\* wgl/;          # "* wgl"
kusano 7d535a
    s/\*glX/\* glX/;          # "* glX"
kusano 7d535a
    s/\.\.\./void/;           # ... -> void
kusano 7d535a
    s/;$//;                   # remove ; at the end of the line
kusano 7d535a
    return $_;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
# Ugly hack to work arround the fact that functions are declared in more
kusano 7d535a
# than one spec file.
kusano 7d535a
sub ignore_function($$)
kusano 7d535a
{
kusano 7d535a
    return exists($fnc_ignore_list{$_[0]}) && $fnc_ignore_list{$_[0]} ne $_[1]
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
sub parse_spec($)
kusano 7d535a
{
kusano 7d535a
    my $filename = shift;
kusano 7d535a
    my $extname = "";
kusano 7d535a
    my $vendortag = "";
kusano 7d535a
    my @extnames = ();
kusano 7d535a
    my %functions = ();
kusano 7d535a
    my %tokens = ();
kusano 7d535a
kusano 7d535a
    my $section = "";
kusano 7d535a
    my @fnc = ();
kusano 7d535a
kusano 7d535a
    my %proc = (
kusano 7d535a
        "Name" => sub {
kusano 7d535a
            if (/^([a-z0-9]+)_([a-z0-9_]+)/i)
kusano 7d535a
            {
kusano 7d535a
                $extname = "$1_$2";
kusano 7d535a
                $vendortag = $1;
kusano 7d535a
            }
kusano 7d535a
        },
kusano 7d535a
kusano 7d535a
        "Name Strings" => sub {
kusano 7d535a
            # Add extension name to extension list
kusano 7d535a
        
kusano 7d535a
           # Initially use $extname if (none) specified
kusano 7d535a
            if (/$regex{none}/)
kusano 7d535a
            {
kusano 7d535a
                $_ = $extname;
kusano 7d535a
            }
kusano 7d535a
kusano 7d535a
            if (/$regex{extname}/)
kusano 7d535a
            {
kusano 7d535a
                # prefix with "GL_" if prefix not present
kusano 7d535a
                s/^/GL_/ unless /$regex{tprefix}/o;
kusano 7d535a
                # Add extension name to extension list
kusano 7d535a
                push @extnames, $_;
kusano 7d535a
            }
kusano 7d535a
        },
kusano 7d535a
kusano 7d535a
        "New Procedures and Functions" => sub {
kusano 7d535a
            # if line matches end of function
kusano 7d535a
            if (/$regex{eofnc}/)
kusano 7d535a
            {
kusano 7d535a
                # add line to function declaration
kusano 7d535a
                push @fnc, $_;
kusano 7d535a
kusano 7d535a
                # if normalized version of function looks like a function
kusano 7d535a
                if (normalize_prototype(@fnc) =~ /$regex{function}/)
kusano 7d535a
                {
kusano 7d535a
                    # get return type, name, and arguments from regex
kusano 7d535a
                    my ($return, $name, $parms) = ($1, $2, $3);
kusano 7d535a
                    if (!ignore_function($name, $extname))
kusano 7d535a
                    {
kusano 7d535a
                        # prefix with "gl" if prefix not present
kusano 7d535a
                        $name =~ s/^/gl/ unless $name =~ /$regex{prefix}/;
kusano 7d535a
                        # is this a pure GL function?
kusano 7d535a
                        if ($name =~ /^gl/ && $name !~ /^glX/)
kusano 7d535a
                        {
kusano 7d535a
                            # apply typemaps
kusano 7d535a
                            $return =~ s/$regex{types}/$typemap{$1}/og;
kusano 7d535a
                            $return =~ s/void\*/GLvoid */og;
kusano 7d535a
                            $parms =~ s/$regex{types}/$typemap{$1}/og;
kusano 7d535a
                            $parms =~ s/$regex{voidtype}/$voidtypemap{$1}/og;
kusano 7d535a
                        }
kusano 7d535a
                        # add to functions hash
kusano 7d535a
                        $functions{$name} = {
kusano 7d535a
                            rtype => $return,
kusano 7d535a
                            parms => $parms,
kusano 7d535a
                        };
kusano 7d535a
                    }
kusano 7d535a
                }
kusano 7d535a
                # reset function declaration
kusano 7d535a
                @fnc = ();
kusano 7d535a
            } elsif ($_ ne "" and $_ ne "None") {
kusano 7d535a
                # if not eof, add line to function declaration
kusano 7d535a
                push @fnc, $_
kusano 7d535a
            }
kusano 7d535a
        },
kusano 7d535a
kusano 7d535a
        "New Tokens" => sub {
kusano 7d535a
            if (/$regex{token}/)
kusano 7d535a
            {
kusano 7d535a
                my ($name, $value) = ($1, $2);
kusano 7d535a
                # prefix with "GL_" if prefix not present
kusano 7d535a
                $name =~ s/^/GL_/ unless $name =~ /$regex{tprefix}/;
kusano 7d535a
                # Add (name, value) pair to tokens hash, unless it's taboo
kusano 7d535a
                $tokens{$name} = $value unless exists $taboo_tokens{$name};
kusano 7d535a
            }
kusano 7d535a
        },
kusano 7d535a
    );
kusano 7d535a
kusano 7d535a
    # Some people can't read, the template clearly says "Name String_s_"
kusano 7d535a
    $proc{"Name String"} = $proc{"Name Strings"};
kusano 7d535a
kusano 7d535a
    # Open spec file
kusano 7d535a
    open SPEC, "<$filename" or return;
kusano 7d535a
kusano 7d535a
    # For each line of SPEC
kusano 7d535a
    while(<spec>)</spec>
kusano 7d535a
    {
kusano 7d535a
        # Delete trailing newline character
kusano 7d535a
        chomp;
kusano 7d535a
        # Remove trailing white spaces
kusano 7d535a
        s/\s+$//;
kusano 7d535a
        # If starts with a capital letter, it must be a new section
kusano 7d535a
        if (/^[A-Z]/)
kusano 7d535a
        {
kusano 7d535a
            # Match section name with one of the predefined names 
kusano 7d535a
            $section = /$regex{section}/o ? $1 : "default";
kusano 7d535a
        } else {
kusano 7d535a
            # Line is internal to a section
kusano 7d535a
            # Remove leading whitespace
kusano 7d535a
            s/^\s+//;
kusano 7d535a
            # Call appropriate section processing function if it exists
kusano 7d535a
            &{$proc{$section}} if exists $proc{$section};
kusano 7d535a
        }
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    close SPEC;
kusano 7d535a
kusano 7d535a
    return ($extname, \@extnames, \%tokens, \%functions);
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
#----------------------------------------------------------------------------------------
kusano 7d535a
kusano 7d535a
my @speclist = ();
kusano 7d535a
my %extensions = ();
kusano 7d535a
kusano 7d535a
my $ext_dir = shift;
kusano 7d535a
my $reg_http = "http://www.opengl.org/registry/specs/";
kusano 7d535a
#my $reg_http = "http://oss.sgi.com/projects/ogl-sample/";
kusano 7d535a
kusano 7d535a
# Take command line arguments or read list from file
kusano 7d535a
if (@ARGV)
kusano 7d535a
{
kusano 7d535a
    @speclist = @ARGV;
kusano 7d535a
} else {
kusano 7d535a
    local $/; #???
kusano 7d535a
    @speclist = split "\n", (<>);
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
foreach my $spec (sort @speclist)
kusano 7d535a
{
kusano 7d535a
    my ($extname, $extnames, $tokens, $functions) = parse_spec($spec);
kusano 7d535a
kusano 7d535a
    foreach my $ext (@{$extnames})
kusano 7d535a
    {
kusano 7d535a
        my $info = "$ext_dir/" . $ext;
kusano 7d535a
        open EXT, ">$info";
kusano 7d535a
        print EXT $ext . "\n";                       # Extension name
kusano 7d535a
        my $specname = $spec;
kusano 7d535a
        $specname =~ s/registry\///;
kusano 7d535a
        print EXT $reg_http . $specname . "\n";      # Extension info URL
kusano 7d535a
        print EXT $ext . "\n";                       # Extension string
kusano 7d535a
kusano 7d535a
        my $prefix = $ext;
kusano 7d535a
        $prefix =~ s/^(.+?)(_.+)$/$1/;
kusano 7d535a
        foreach my $token (sort { hex ${$tokens}{$a} <=> hex ${$tokens}{$b} } keys %{$tokens})
kusano 7d535a
        {
kusano 7d535a
            if ($token =~ /^$prefix\_.*/i)
kusano 7d535a
            {
kusano 7d535a
                print EXT "\t" . $token . " " . ${\%{$tokens}}{$token} . "\n";
kusano 7d535a
            }
kusano 7d535a
        }
kusano 7d535a
        foreach my $function (sort keys %{$functions})
kusano 7d535a
        {
kusano 7d535a
            if ($function =~ /^$prefix.*/i)
kusano 7d535a
            {
kusano 7d535a
                print EXT "\t" . ${$functions}{$function}{rtype} . " " . $function . " (" . ${$functions}{$function}{parms} . ")" . "\n";
kusano 7d535a
            }
kusano 7d535a
        }
kusano 7d535a
        close EXT;
kusano 7d535a
    }
kusano 7d535a
}