123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927 |
- // Copyright 2013 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- /*
- mkwinsyscall generates windows system call bodies
- It parses all files specified on command line containing function
- prototypes (like syscall_windows.go) and prints system call bodies
- to standard output.
- The prototypes are marked by lines beginning with "//sys" and read
- like func declarations if //sys is replaced by func, but:
- * The parameter lists must give a name for each argument. This
- includes return parameters.
- * The parameter lists must give a type for each argument:
- the (x, y, z int) shorthand is not allowed.
- * If the return parameter is an error number, it must be named err.
- * If go func name needs to be different from its winapi dll name,
- the winapi name could be specified at the end, after "=" sign, like
- //sys LoadLibrary(libname string) (handle uint32, err error) = LoadLibraryA
- * Each function that returns err needs to supply a condition, that
- return value of winapi will be tested against to detect failure.
- This would set err to windows "last-error", otherwise it will be nil.
- The value can be provided at end of //sys declaration, like
- //sys LoadLibrary(libname string) (handle uint32, err error) [failretval==-1] = LoadLibraryA
- and is [failretval==0] by default.
- Usage:
- mkwinsyscall [flags] [path ...]
- The flags are:
- -output
- Specify output file name (outputs to console if blank).
- -trace
- Generate print statement after every syscall.
- */
- package main
- import (
- "bufio"
- "bytes"
- "errors"
- "flag"
- "fmt"
- "go/format"
- "go/parser"
- "go/token"
- "io"
- "io/ioutil"
- "log"
- "os"
- "path/filepath"
- "runtime"
- "sort"
- "strconv"
- "strings"
- "text/template"
- )
- var (
- filename = flag.String("output", "", "output file name (standard output if omitted)")
- printTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall")
- systemDLL = flag.Bool("systemdll", true, "whether all DLLs should be loaded from the Windows system directory")
- )
- func trim(s string) string {
- return strings.Trim(s, " \t")
- }
- var packageName string
- func packagename() string {
- return packageName
- }
- func syscalldot() string {
- if packageName == "syscall" {
- return ""
- }
- return "syscall."
- }
- // Param is function parameter
- type Param struct {
- Name string
- Type string
- fn *Fn
- tmpVarIdx int
- }
- // tmpVar returns temp variable name that will be used to represent p during syscall.
- func (p *Param) tmpVar() string {
- if p.tmpVarIdx < 0 {
- p.tmpVarIdx = p.fn.curTmpVarIdx
- p.fn.curTmpVarIdx++
- }
- return fmt.Sprintf("_p%d", p.tmpVarIdx)
- }
- // BoolTmpVarCode returns source code for bool temp variable.
- func (p *Param) BoolTmpVarCode() string {
- const code = `var %s uint32
- if %s {
- %s = 1
- } else {
- %s = 0
- }`
- tmp := p.tmpVar()
- return fmt.Sprintf(code, tmp, p.Name, tmp, tmp)
- }
- // BoolPointerTmpVarCode returns source code for bool temp variable.
- func (p *Param) BoolPointerTmpVarCode() string {
- const code = `var %s uint32
- if *%s {
- %s = 1
- } else {
- %s = 0
- }`
- tmp := p.tmpVar()
- return fmt.Sprintf(code, tmp, p.Name, tmp, tmp)
- }
- // SliceTmpVarCode returns source code for slice temp variable.
- func (p *Param) SliceTmpVarCode() string {
- const code = `var %s *%s
- if len(%s) > 0 {
- %s = &%s[0]
- }`
- tmp := p.tmpVar()
- return fmt.Sprintf(code, tmp, p.Type[2:], p.Name, tmp, p.Name)
- }
- // StringTmpVarCode returns source code for string temp variable.
- func (p *Param) StringTmpVarCode() string {
- errvar := p.fn.Rets.ErrorVarName()
- if errvar == "" {
- errvar = "_"
- }
- tmp := p.tmpVar()
- const code = `var %s %s
- %s, %s = %s(%s)`
- s := fmt.Sprintf(code, tmp, p.fn.StrconvType(), tmp, errvar, p.fn.StrconvFunc(), p.Name)
- if errvar == "-" {
- return s
- }
- const morecode = `
- if %s != nil {
- return
- }`
- return s + fmt.Sprintf(morecode, errvar)
- }
- // TmpVarCode returns source code for temp variable.
- func (p *Param) TmpVarCode() string {
- switch {
- case p.Type == "bool":
- return p.BoolTmpVarCode()
- case p.Type == "*bool":
- return p.BoolPointerTmpVarCode()
- case strings.HasPrefix(p.Type, "[]"):
- return p.SliceTmpVarCode()
- default:
- return ""
- }
- }
- // TmpVarReadbackCode returns source code for reading back the temp variable into the original variable.
- func (p *Param) TmpVarReadbackCode() string {
- switch {
- case p.Type == "*bool":
- return fmt.Sprintf("*%s = %s != 0", p.Name, p.tmpVar())
- default:
- return ""
- }
- }
- // TmpVarHelperCode returns source code for helper's temp variable.
- func (p *Param) TmpVarHelperCode() string {
- if p.Type != "string" {
- return ""
- }
- return p.StringTmpVarCode()
- }
- // SyscallArgList returns source code fragments representing p parameter
- // in syscall. Slices are translated into 2 syscall parameters: pointer to
- // the first element and length.
- func (p *Param) SyscallArgList() []string {
- t := p.HelperType()
- var s string
- switch {
- case t == "*bool":
- s = fmt.Sprintf("unsafe.Pointer(&%s)", p.tmpVar())
- case t[0] == '*':
- s = fmt.Sprintf("unsafe.Pointer(%s)", p.Name)
- case t == "bool":
- s = p.tmpVar()
- case strings.HasPrefix(t, "[]"):
- return []string{
- fmt.Sprintf("uintptr(unsafe.Pointer(%s))", p.tmpVar()),
- fmt.Sprintf("uintptr(len(%s))", p.Name),
- }
- default:
- s = p.Name
- }
- return []string{fmt.Sprintf("uintptr(%s)", s)}
- }
- // IsError determines if p parameter is used to return error.
- func (p *Param) IsError() bool {
- return p.Name == "err" && p.Type == "error"
- }
- // HelperType returns type of parameter p used in helper function.
- func (p *Param) HelperType() string {
- if p.Type == "string" {
- return p.fn.StrconvType()
- }
- return p.Type
- }
- // join concatenates parameters ps into a string with sep separator.
- // Each parameter is converted into string by applying fn to it
- // before conversion.
- func join(ps []*Param, fn func(*Param) string, sep string) string {
- if len(ps) == 0 {
- return ""
- }
- a := make([]string, 0)
- for _, p := range ps {
- a = append(a, fn(p))
- }
- return strings.Join(a, sep)
- }
- // Rets describes function return parameters.
- type Rets struct {
- Name string
- Type string
- ReturnsError bool
- FailCond string
- }
- // ErrorVarName returns error variable name for r.
- func (r *Rets) ErrorVarName() string {
- if r.ReturnsError {
- return "err"
- }
- if r.Type == "error" {
- return r.Name
- }
- return ""
- }
- // ToParams converts r into slice of *Param.
- func (r *Rets) ToParams() []*Param {
- ps := make([]*Param, 0)
- if len(r.Name) > 0 {
- ps = append(ps, &Param{Name: r.Name, Type: r.Type})
- }
- if r.ReturnsError {
- ps = append(ps, &Param{Name: "err", Type: "error"})
- }
- return ps
- }
- // List returns source code of syscall return parameters.
- func (r *Rets) List() string {
- s := join(r.ToParams(), func(p *Param) string { return p.Name + " " + p.Type }, ", ")
- if len(s) > 0 {
- s = "(" + s + ")"
- }
- return s
- }
- // PrintList returns source code of trace printing part correspondent
- // to syscall return values.
- func (r *Rets) PrintList() string {
- return join(r.ToParams(), func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
- }
- // SetReturnValuesCode returns source code that accepts syscall return values.
- func (r *Rets) SetReturnValuesCode() string {
- if r.Name == "" && !r.ReturnsError {
- return ""
- }
- retvar := "r0"
- if r.Name == "" {
- retvar = "r1"
- }
- errvar := "_"
- if r.ReturnsError {
- errvar = "e1"
- }
- return fmt.Sprintf("%s, _, %s := ", retvar, errvar)
- }
- func (r *Rets) useLongHandleErrorCode(retvar string) string {
- const code = `if %s {
- if e1 != 0 {
- err = errnoErr(e1)
- } else {
- err = %sEINVAL
- }
- }`
- cond := retvar + " == 0"
- if r.FailCond != "" {
- cond = strings.Replace(r.FailCond, "failretval", retvar, 1)
- }
- return fmt.Sprintf(code, cond, syscalldot())
- }
- // SetErrorCode returns source code that sets return parameters.
- func (r *Rets) SetErrorCode() string {
- const code = `if r0 != 0 {
- %s = %sErrno(r0)
- }`
- if r.Name == "" && !r.ReturnsError {
- return ""
- }
- if r.Name == "" {
- return r.useLongHandleErrorCode("r1")
- }
- if r.Type == "error" {
- return fmt.Sprintf(code, r.Name, syscalldot())
- }
- s := ""
- switch {
- case r.Type[0] == '*':
- s = fmt.Sprintf("%s = (%s)(unsafe.Pointer(r0))", r.Name, r.Type)
- case r.Type == "bool":
- s = fmt.Sprintf("%s = r0 != 0", r.Name)
- default:
- s = fmt.Sprintf("%s = %s(r0)", r.Name, r.Type)
- }
- if !r.ReturnsError {
- return s
- }
- return s + "\n\t" + r.useLongHandleErrorCode(r.Name)
- }
- // Fn describes syscall function.
- type Fn struct {
- Name string
- Params []*Param
- Rets *Rets
- PrintTrace bool
- dllname string
- dllfuncname string
- src string
- // TODO: get rid of this field and just use parameter index instead
- curTmpVarIdx int // insure tmp variables have uniq names
- }
- // extractParams parses s to extract function parameters.
- func extractParams(s string, f *Fn) ([]*Param, error) {
- s = trim(s)
- if s == "" {
- return nil, nil
- }
- a := strings.Split(s, ",")
- ps := make([]*Param, len(a))
- for i := range ps {
- s2 := trim(a[i])
- b := strings.Split(s2, " ")
- if len(b) != 2 {
- b = strings.Split(s2, "\t")
- if len(b) != 2 {
- return nil, errors.New("Could not extract function parameter from \"" + s2 + "\"")
- }
- }
- ps[i] = &Param{
- Name: trim(b[0]),
- Type: trim(b[1]),
- fn: f,
- tmpVarIdx: -1,
- }
- }
- return ps, nil
- }
- // extractSection extracts text out of string s starting after start
- // and ending just before end. found return value will indicate success,
- // and prefix, body and suffix will contain correspondent parts of string s.
- func extractSection(s string, start, end rune) (prefix, body, suffix string, found bool) {
- s = trim(s)
- if strings.HasPrefix(s, string(start)) {
- // no prefix
- body = s[1:]
- } else {
- a := strings.SplitN(s, string(start), 2)
- if len(a) != 2 {
- return "", "", s, false
- }
- prefix = a[0]
- body = a[1]
- }
- a := strings.SplitN(body, string(end), 2)
- if len(a) != 2 {
- return "", "", "", false
- }
- return prefix, a[0], a[1], true
- }
- // newFn parses string s and return created function Fn.
- func newFn(s string) (*Fn, error) {
- s = trim(s)
- f := &Fn{
- Rets: &Rets{},
- src: s,
- PrintTrace: *printTraceFlag,
- }
- // function name and args
- prefix, body, s, found := extractSection(s, '(', ')')
- if !found || prefix == "" {
- return nil, errors.New("Could not extract function name and parameters from \"" + f.src + "\"")
- }
- f.Name = prefix
- var err error
- f.Params, err = extractParams(body, f)
- if err != nil {
- return nil, err
- }
- // return values
- _, body, s, found = extractSection(s, '(', ')')
- if found {
- r, err := extractParams(body, f)
- if err != nil {
- return nil, err
- }
- switch len(r) {
- case 0:
- case 1:
- if r[0].IsError() {
- f.Rets.ReturnsError = true
- } else {
- f.Rets.Name = r[0].Name
- f.Rets.Type = r[0].Type
- }
- case 2:
- if !r[1].IsError() {
- return nil, errors.New("Only last windows error is allowed as second return value in \"" + f.src + "\"")
- }
- f.Rets.ReturnsError = true
- f.Rets.Name = r[0].Name
- f.Rets.Type = r[0].Type
- default:
- return nil, errors.New("Too many return values in \"" + f.src + "\"")
- }
- }
- // fail condition
- _, body, s, found = extractSection(s, '[', ']')
- if found {
- f.Rets.FailCond = body
- }
- // dll and dll function names
- s = trim(s)
- if s == "" {
- return f, nil
- }
- if !strings.HasPrefix(s, "=") {
- return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
- }
- s = trim(s[1:])
- a := strings.Split(s, ".")
- switch len(a) {
- case 1:
- f.dllfuncname = a[0]
- case 2:
- f.dllname = a[0]
- f.dllfuncname = a[1]
- default:
- return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
- }
- return f, nil
- }
- // DLLName returns DLL name for function f.
- func (f *Fn) DLLName() string {
- if f.dllname == "" {
- return "kernel32"
- }
- return f.dllname
- }
- // DLLName returns DLL function name for function f.
- func (f *Fn) DLLFuncName() string {
- if f.dllfuncname == "" {
- return f.Name
- }
- return f.dllfuncname
- }
- // ParamList returns source code for function f parameters.
- func (f *Fn) ParamList() string {
- return join(f.Params, func(p *Param) string { return p.Name + " " + p.Type }, ", ")
- }
- // HelperParamList returns source code for helper function f parameters.
- func (f *Fn) HelperParamList() string {
- return join(f.Params, func(p *Param) string { return p.Name + " " + p.HelperType() }, ", ")
- }
- // ParamPrintList returns source code of trace printing part correspondent
- // to syscall input parameters.
- func (f *Fn) ParamPrintList() string {
- return join(f.Params, func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
- }
- // ParamCount return number of syscall parameters for function f.
- func (f *Fn) ParamCount() int {
- n := 0
- for _, p := range f.Params {
- n += len(p.SyscallArgList())
- }
- return n
- }
- // SyscallParamCount determines which version of Syscall/Syscall6/Syscall9/...
- // to use. It returns parameter count for correspondent SyscallX function.
- func (f *Fn) SyscallParamCount() int {
- n := f.ParamCount()
- switch {
- case n <= 3:
- return 3
- case n <= 6:
- return 6
- case n <= 9:
- return 9
- case n <= 12:
- return 12
- case n <= 15:
- return 15
- default:
- panic("too many arguments to system call")
- }
- }
- // Syscall determines which SyscallX function to use for function f.
- func (f *Fn) Syscall() string {
- c := f.SyscallParamCount()
- if c == 3 {
- return syscalldot() + "Syscall"
- }
- return syscalldot() + "Syscall" + strconv.Itoa(c)
- }
- // SyscallParamList returns source code for SyscallX parameters for function f.
- func (f *Fn) SyscallParamList() string {
- a := make([]string, 0)
- for _, p := range f.Params {
- a = append(a, p.SyscallArgList()...)
- }
- for len(a) < f.SyscallParamCount() {
- a = append(a, "0")
- }
- return strings.Join(a, ", ")
- }
- // HelperCallParamList returns source code of call into function f helper.
- func (f *Fn) HelperCallParamList() string {
- a := make([]string, 0, len(f.Params))
- for _, p := range f.Params {
- s := p.Name
- if p.Type == "string" {
- s = p.tmpVar()
- }
- a = append(a, s)
- }
- return strings.Join(a, ", ")
- }
- // IsUTF16 is true, if f is W (utf16) function. It is false
- // for all A (ascii) functions.
- func (f *Fn) IsUTF16() bool {
- s := f.DLLFuncName()
- return s[len(s)-1] == 'W'
- }
- // StrconvFunc returns name of Go string to OS string function for f.
- func (f *Fn) StrconvFunc() string {
- if f.IsUTF16() {
- return syscalldot() + "UTF16PtrFromString"
- }
- return syscalldot() + "BytePtrFromString"
- }
- // StrconvType returns Go type name used for OS string for f.
- func (f *Fn) StrconvType() string {
- if f.IsUTF16() {
- return "*uint16"
- }
- return "*byte"
- }
- // HasStringParam is true, if f has at least one string parameter.
- // Otherwise it is false.
- func (f *Fn) HasStringParam() bool {
- for _, p := range f.Params {
- if p.Type == "string" {
- return true
- }
- }
- return false
- }
- // HelperName returns name of function f helper.
- func (f *Fn) HelperName() string {
- if !f.HasStringParam() {
- return f.Name
- }
- return "_" + f.Name
- }
- // Source files and functions.
- type Source struct {
- Funcs []*Fn
- Files []string
- StdLibImports []string
- ExternalImports []string
- }
- func (src *Source) Import(pkg string) {
- src.StdLibImports = append(src.StdLibImports, pkg)
- sort.Strings(src.StdLibImports)
- }
- func (src *Source) ExternalImport(pkg string) {
- src.ExternalImports = append(src.ExternalImports, pkg)
- sort.Strings(src.ExternalImports)
- }
- // ParseFiles parses files listed in fs and extracts all syscall
- // functions listed in sys comments. It returns source files
- // and functions collection *Source if successful.
- func ParseFiles(fs []string) (*Source, error) {
- src := &Source{
- Funcs: make([]*Fn, 0),
- Files: make([]string, 0),
- StdLibImports: []string{
- "unsafe",
- },
- ExternalImports: make([]string, 0),
- }
- for _, file := range fs {
- if err := src.ParseFile(file); err != nil {
- return nil, err
- }
- }
- return src, nil
- }
- // DLLs return dll names for a source set src.
- func (src *Source) DLLs() []string {
- uniq := make(map[string]bool)
- r := make([]string, 0)
- for _, f := range src.Funcs {
- name := f.DLLName()
- if _, found := uniq[name]; !found {
- uniq[name] = true
- r = append(r, name)
- }
- }
- return r
- }
- // ParseFile adds additional file path to a source set src.
- func (src *Source) ParseFile(path string) error {
- file, err := os.Open(path)
- if err != nil {
- return err
- }
- defer file.Close()
- s := bufio.NewScanner(file)
- for s.Scan() {
- t := trim(s.Text())
- if len(t) < 7 {
- continue
- }
- if !strings.HasPrefix(t, "//sys") {
- continue
- }
- t = t[5:]
- if !(t[0] == ' ' || t[0] == '\t') {
- continue
- }
- f, err := newFn(t[1:])
- if err != nil {
- return err
- }
- src.Funcs = append(src.Funcs, f)
- }
- if err := s.Err(); err != nil {
- return err
- }
- src.Files = append(src.Files, path)
- // get package name
- fset := token.NewFileSet()
- _, err = file.Seek(0, 0)
- if err != nil {
- return err
- }
- pkg, err := parser.ParseFile(fset, "", file, parser.PackageClauseOnly)
- if err != nil {
- return err
- }
- packageName = pkg.Name.Name
- return nil
- }
- // IsStdRepo reports whether src is part of standard library.
- func (src *Source) IsStdRepo() (bool, error) {
- if len(src.Files) == 0 {
- return false, errors.New("no input files provided")
- }
- abspath, err := filepath.Abs(src.Files[0])
- if err != nil {
- return false, err
- }
- goroot := runtime.GOROOT()
- if runtime.GOOS == "windows" {
- abspath = strings.ToLower(abspath)
- goroot = strings.ToLower(goroot)
- }
- sep := string(os.PathSeparator)
- if !strings.HasSuffix(goroot, sep) {
- goroot += sep
- }
- return strings.HasPrefix(abspath, goroot), nil
- }
- // Generate output source file from a source set src.
- func (src *Source) Generate(w io.Writer) error {
- const (
- pkgStd = iota // any package in std library
- pkgXSysWindows // x/sys/windows package
- pkgOther
- )
- isStdRepo, err := src.IsStdRepo()
- if err != nil {
- return err
- }
- var pkgtype int
- switch {
- case isStdRepo:
- pkgtype = pkgStd
- case packageName == "windows":
- // TODO: this needs better logic than just using package name
- pkgtype = pkgXSysWindows
- default:
- pkgtype = pkgOther
- }
- if *systemDLL {
- switch pkgtype {
- case pkgStd:
- src.Import("internal/syscall/windows/sysdll")
- case pkgXSysWindows:
- default:
- src.ExternalImport("golang.org/x/sys/windows")
- }
- }
- if packageName != "syscall" {
- src.Import("syscall")
- }
- funcMap := template.FuncMap{
- "packagename": packagename,
- "syscalldot": syscalldot,
- "newlazydll": func(dll string) string {
- arg := "\"" + dll + ".dll\""
- if !*systemDLL {
- return syscalldot() + "NewLazyDLL(" + arg + ")"
- }
- switch pkgtype {
- case pkgStd:
- return syscalldot() + "NewLazyDLL(sysdll.Add(" + arg + "))"
- case pkgXSysWindows:
- return "NewLazySystemDLL(" + arg + ")"
- default:
- return "windows.NewLazySystemDLL(" + arg + ")"
- }
- },
- }
- t := template.Must(template.New("main").Funcs(funcMap).Parse(srcTemplate))
- err = t.Execute(w, src)
- if err != nil {
- return errors.New("Failed to execute template: " + err.Error())
- }
- return nil
- }
- func usage() {
- fmt.Fprintf(os.Stderr, "usage: mkwinsyscall [flags] [path ...]\n")
- flag.PrintDefaults()
- os.Exit(1)
- }
- func main() {
- flag.Usage = usage
- flag.Parse()
- if len(flag.Args()) <= 0 {
- fmt.Fprintf(os.Stderr, "no files to parse provided\n")
- usage()
- }
- src, err := ParseFiles(flag.Args())
- if err != nil {
- log.Fatal(err)
- }
- var buf bytes.Buffer
- if err := src.Generate(&buf); err != nil {
- log.Fatal(err)
- }
- data, err := format.Source(buf.Bytes())
- if err != nil {
- log.Fatal(err)
- }
- if *filename == "" {
- _, err = os.Stdout.Write(data)
- } else {
- err = ioutil.WriteFile(*filename, data, 0644)
- }
- if err != nil {
- log.Fatal(err)
- }
- }
- // TODO: use println instead to print in the following template
- const srcTemplate = `
- {{define "main"}}// Code generated by 'go generate'; DO NOT EDIT.
- package {{packagename}}
- import (
- {{range .StdLibImports}}"{{.}}"
- {{end}}
- {{range .ExternalImports}}"{{.}}"
- {{end}}
- )
- var _ unsafe.Pointer
- // Do the interface allocations only once for common
- // Errno values.
- const (
- errnoERROR_IO_PENDING = 997
- )
- var (
- errERROR_IO_PENDING error = {{syscalldot}}Errno(errnoERROR_IO_PENDING)
- )
- // errnoErr returns common boxed Errno values, to prevent
- // allocations at runtime.
- func errnoErr(e {{syscalldot}}Errno) error {
- switch e {
- case 0:
- return nil
- case errnoERROR_IO_PENDING:
- return errERROR_IO_PENDING
- }
- // TODO: add more here, after collecting data on the common
- // error values see on Windows. (perhaps when running
- // all.bat?)
- return e
- }
- var (
- {{template "dlls" .}}
- {{template "funcnames" .}})
- {{range .Funcs}}{{if .HasStringParam}}{{template "helperbody" .}}{{end}}{{template "funcbody" .}}{{end}}
- {{end}}
- {{/* help functions */}}
- {{define "dlls"}}{{range .DLLs}} mod{{.}} = {{newlazydll .}}
- {{end}}{{end}}
- {{define "funcnames"}}{{range .Funcs}} proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}")
- {{end}}{{end}}
- {{define "helperbody"}}
- func {{.Name}}({{.ParamList}}) {{template "results" .}}{
- {{template "helpertmpvars" .}} return {{.HelperName}}({{.HelperCallParamList}})
- }
- {{end}}
- {{define "funcbody"}}
- func {{.HelperName}}({{.HelperParamList}}) {{template "results" .}}{
- {{template "tmpvars" .}} {{template "syscall" .}} {{template "tmpvarsreadback" .}}
- {{template "seterror" .}}{{template "printtrace" .}} return
- }
- {{end}}
- {{define "helpertmpvars"}}{{range .Params}}{{if .TmpVarHelperCode}} {{.TmpVarHelperCode}}
- {{end}}{{end}}{{end}}
- {{define "tmpvars"}}{{range .Params}}{{if .TmpVarCode}} {{.TmpVarCode}}
- {{end}}{{end}}{{end}}
- {{define "results"}}{{if .Rets.List}}{{.Rets.List}} {{end}}{{end}}
- {{define "syscall"}}{{.Rets.SetReturnValuesCode}}{{.Syscall}}(proc{{.DLLFuncName}}.Addr(), {{.ParamCount}}, {{.SyscallParamList}}){{end}}
- {{define "tmpvarsreadback"}}{{range .Params}}{{if .TmpVarReadbackCode}}
- {{.TmpVarReadbackCode}}{{end}}{{end}}{{end}}
- {{define "seterror"}}{{if .Rets.SetErrorCode}} {{.Rets.SetErrorCode}}
- {{end}}{{end}}
- {{define "printtrace"}}{{if .PrintTrace}} print("SYSCALL: {{.Name}}(", {{.ParamPrintList}}") (", {{.Rets.PrintList}}")\n")
- {{end}}{{end}}
- `
|