| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325 |
- package main
- import (
- "bufio"
- "flag"
- "fmt"
- "io"
- "os"
- "regexp"
- "strings"
- )
- // Current Version
- const (
- PROGNAME = "glapi2go"
- VMAJOR = 0
- VMINOR = 1
- )
- // Command line options
- var (
- oGLVersion = flag.String("glversion", "GL_VERSION_3_3", "OpenGL version to use")
- )
- const (
- fileGLAPIC = "glapi.c"
- fileGLAPIH = "glapi.h"
- fileGLPARAMH = "glparam.h"
- fileCONSTS = "consts.go"
- )
- // Maps OpenGL types to Go
- var mapCType2Go = map[string]string{
- "GLenum": "uint",
- "GLfloat": "float32",
- "GLchar": "byte",
- "GLbyte": "byte",
- "GLboolean": "bool",
- "GLshort": "int16",
- "GLushort": "uint16",
- "GLint": "int",
- "GLint64": "int64",
- "GLsizei": "int",
- "GLbitfield": "uint",
- "GLdouble": "float64",
- "GLuint": "uint",
- "GLuint64": "uint64",
- "GLubyte": "byte",
- "GLintptr": "uintptr",
- "GLsizeiptr": "uintptr",
- "GLsync": "unsafe.Pointer",
- }
- func main() {
- // Parse command line parameters
- flag.Usage = usage
- flag.Parse()
- // Checks for input header file
- if len(flag.Args()) == 0 {
- usage()
- return
- }
- fname := flag.Args()[0]
- // Open input header file
- fin, err := os.Open(fname)
- if err != nil {
- abort(err)
- }
- // Parses the header and builds GLHeader struct
- // with all the information necessary to expand all templates.
- var glh GLHeader
- err = parser(fin, &glh)
- if err != nil {
- abort(err)
- }
- // Generates glapi.c
- err = genFile(templGLAPIC, &glh, fileGLAPIC, false)
- if err != nil {
- abort(err)
- }
- // Generates glapi.h
- err = genFile(templGLAPIH, &glh, fileGLAPIH, false)
- if err != nil {
- abort(err)
- }
- // Generates consts.go
- err = genFile(templCONSTS, &glh, fileCONSTS, true)
- if err != nil {
- abort(err)
- }
- }
- // parser parses the header file and builds the Template structure
- func parser(fheader io.Reader, h *GLHeader) error {
- // Regex to parser #endif line to detect end of definitions for
- // specific OpenGL version: ex:"#endif /* GL_VERSION_3_3 */"
- rexEndif := regexp.MustCompile(`#endif\s+/\*\s+(\w+)\s+\*/`)
- // Regex to parse define line, capturing name (1) and value (2)
- rexDefine := regexp.MustCompile(`#define\s+(\w+)\s+(\w+)`)
- // Regex to parse function definition line,
- // capturing return value (1), function name (2) and parameters (3)
- rexApi := regexp.MustCompile(`GLAPI\s+(.*)APIENTRY\s+(\w+)\s+\((.*)\)`)
- h.Defines = make([]GLDefine, 0)
- h.Funcs = make([]GLFunc, 0)
- bufin := bufio.NewReader(fheader)
- maxLength := 0
- for {
- // Reads next line and abort on error (not EOF)
- line, err := bufin.ReadString('\n')
- if err != nil && err != io.EOF {
- return err
- }
- // Checks for "#endif" identifying end of definitions for specified
- // OpenGL version
- res := rexEndif.FindStringSubmatch(line)
- if len(res) > 0 {
- if res[1] == *oGLVersion {
- break
- }
- }
- // Checks for "#define" of GL constants
- res = rexDefine.FindStringSubmatch(line)
- if len(res) >= 3 {
- dname := res[1]
- if strings.HasPrefix(dname, "GL_") {
- h.Defines = append(h.Defines, GLDefine{
- Name: gldef2go(res[1]),
- Value: glval2go(res[2]),
- })
- }
- }
- // Checks for function declaration
- res = rexApi.FindStringSubmatch(line)
- if len(res) >= 2 {
- var f GLFunc
- f.Rtype = strings.Trim(res[1], " ")
- f.Ptype = "PFN" + strings.ToUpper(res[2]) + "PROC"
- f.Fname = res[2]
- f.FnameGo = glfname2go(res[2])
- f.Pname = "p" + f.Fname
- f.CParams = res[3]
- err := parseParams(res[3], &f)
- if err != nil {
- return err
- }
- h.Funcs = append(h.Funcs, f)
- if len(f.Ptype) > maxLength {
- maxLength = len(f.Ptype)
- }
- }
- // If EOF ends of parsing.
- if err == io.EOF {
- break
- }
- }
- // Sets spacer string
- for i := 0; i < len(h.Funcs); i++ {
- h.Funcs[i].Spacer = strings.Repeat(" ", maxLength-len(h.Funcs[i].Ptype)+1)
- }
- return nil
- }
- // parseParams receives a string with the declaration of the parameters of a C function
- // and parses it into an array of GLParam types with are then saved in the specified
- // GLfunc object.
- func parseParams(gparams string, f *GLFunc) error {
- params := strings.Split(gparams, ",")
- res := make([]GLParam, 0)
- args := make([]string, 0)
- goParams := make([]string, 0)
- for _, tn := range params {
- parts := strings.Split(strings.TrimSpace(tn), " ")
- var qualif string
- var name string
- var ctype string
- switch len(parts) {
- case 1:
- ctype = parts[0]
- if ctype != "void" {
- panic("Should be void but is:" + ctype)
- }
- continue
- case 2:
- ctype = parts[0]
- name = parts[1]
- case 3:
- qualif = parts[0]
- ctype = parts[1]
- name = parts[2]
- default:
- return fmt.Errorf("Invalid parameter:[%s]", tn)
- }
- arg := getArgName(name)
- args = append(args, arg)
- res = append(res, GLParam{Qualif: qualif, CType: ctype, Arg: arg, Name: name})
- // Go parameter
- goarg, gotype := gltypearg2go(ctype, name)
- goParams = append(goParams, goarg+" "+gotype)
- }
- f.Args = strings.Join(args, ", ")
- f.Params = res
- f.GoParams = strings.Join(goParams, ", ")
- return nil
- }
- // getArgName remove qualifiers and array brackets from the argument
- // returning only the argument name. Ex: *const*indices -> indices
- func getArgName(arg string) string {
- if strings.HasPrefix(arg, "*const*") {
- return strings.TrimPrefix(arg, "*const*")
- }
- if strings.HasPrefix(arg, "**") {
- return strings.TrimPrefix(arg, "**")
- }
- if strings.HasPrefix(arg, "*") {
- return strings.TrimPrefix(arg, "*")
- }
- // Checks for array index: [?]
- aidx := strings.Index(arg, "[")
- if aidx > 0 {
- return arg[:aidx]
- }
- return arg
- }
- // glfname2go converts the name of an OpenGL C function to Go
- func glfname2go(glfname string) string {
- if strings.HasPrefix(glfname, "gl") {
- return strings.TrimPrefix(glfname, "gl")
- }
- return glfname
- }
- // gldef2go converts a name such as GL_LINE_LOOP to LINE_LOOP
- func gldef2go(gldef string) string {
- return strings.TrimPrefix(gldef, "GL_")
- }
- // glval2go converts a C OpenGL value to a Go value
- func glval2go(glval string) string {
- val := glval
- if strings.HasSuffix(val, "u") {
- val = strings.TrimSuffix(val, "u")
- }
- if strings.HasSuffix(val, "ull") {
- val = strings.TrimSuffix(val, "ull")
- }
- return val
- }
- // gltypearg2go converts a C OpenGL function type/argument to a Go argument/type
- // GLfloat *param -> param *float32
- // GLuint type -> ptype uint
- // void *pixels -> pixels unsafe.Pointer
- // void **params -> params *unsafe.Pointer
- func gltypearg2go(gltype, glarg string) (goarg string, gotype string) {
- // Replace parameter names using Go keywords
- gokeys := []string{"type", "func"}
- for _, k := range gokeys {
- if strings.HasSuffix(glarg, k) {
- glarg = strings.TrimSuffix(glarg, k) + "p" + k
- break
- }
- }
- if gltype == "void" {
- gotype = "unsafe.Pointer"
- if strings.HasPrefix(glarg, "**") {
- goarg = strings.TrimPrefix(glarg, "**")
- gotype = "*" + gotype
- return goarg, gotype
- }
- if strings.HasPrefix(glarg, "*") {
- goarg = strings.TrimPrefix(glarg, "*")
- return goarg, gotype
- }
- return "???", "???"
- }
- goarg = glarg
- gotype = mapCType2Go[gltype]
- if strings.HasPrefix(glarg, "*") {
- gotype = "*" + gotype
- goarg = strings.TrimPrefix(goarg, "*")
- }
- return goarg, gotype
- }
- //
- // Shows application usage
- //
- func usage() {
- fmt.Fprintf(os.Stderr, "%s v%d.%d\n", PROGNAME, VMAJOR, VMINOR)
- fmt.Fprintf(os.Stderr, "usage:%s [options] <glheader>\n", strings.ToLower(PROGNAME))
- flag.PrintDefaults()
- os.Exit(2)
- }
- func abort(err error) {
- fmt.Fprintf(os.Stderr, "%s\n", err)
- os.Exit(1)
- }
|