github.com/hbdrawn/golang@v0.0.0-20141214014649-6b835209aba2/src/syscall/mksyscall_windows.go (about)

     1  // Copyright 2013 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build ignore
     6  
     7  /*
     8  mksyscall_windows generates windows system call bodies
     9  
    10  It parses all files specified on command line containing function
    11  prototypes (like syscall_windows.go) and prints system call bodies
    12  to standard output.
    13  
    14  The prototypes are marked by lines beginning with "//sys" and read
    15  like func declarations if //sys is replaced by func, but:
    16  
    17  * The parameter lists must give a name for each argument. This
    18    includes return parameters.
    19  
    20  * The parameter lists must give a type for each argument:
    21    the (x, y, z int) shorthand is not allowed.
    22  
    23  * If the return parameter is an error number, it must be named err.
    24  
    25  * If go func name needs to be different from it's winapi dll name,
    26    the winapi name could be specified at the end, after "=" sign, like
    27    //sys LoadLibrary(libname string) (handle uint32, err error) = LoadLibraryA
    28  
    29  * Each function that returns err needs to supply a condition, that
    30    return value of winapi will be tested against to detect failure.
    31    This would set err to windows "last-error", otherwise it will be nil.
    32    The value can be provided at end of //sys declaration, like
    33    //sys LoadLibrary(libname string) (handle uint32, err error) [failretval==-1] = LoadLibraryA
    34    and is [failretval==0] by default.
    35  
    36  Usage:
    37  	mksyscall_windows [flags] [path ...]
    38  
    39  The flags are:
    40  	-trace
    41  		Generate print statement after every syscall.
    42  */
    43  package main
    44  
    45  import (
    46  	"bufio"
    47  	"errors"
    48  	"flag"
    49  	"fmt"
    50  	"go/parser"
    51  	"go/token"
    52  	"io"
    53  	"log"
    54  	"os"
    55  	"strconv"
    56  	"strings"
    57  	"text/template"
    58  )
    59  
    60  var PrintTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall")
    61  
    62  func trim(s string) string {
    63  	return strings.Trim(s, " \t")
    64  }
    65  
    66  var packageName string
    67  
    68  func packagename() string {
    69  	return packageName
    70  }
    71  
    72  func syscalldot() string {
    73  	if packageName == "syscall" {
    74  		return ""
    75  	}
    76  	return "syscall."
    77  }
    78  
    79  // Param is function parameter
    80  type Param struct {
    81  	Name      string
    82  	Type      string
    83  	fn        *Fn
    84  	tmpVarIdx int
    85  }
    86  
    87  // tmpVar returns temp variable name that will be used to represent p during syscall.
    88  func (p *Param) tmpVar() string {
    89  	if p.tmpVarIdx < 0 {
    90  		p.tmpVarIdx = p.fn.curTmpVarIdx
    91  		p.fn.curTmpVarIdx++
    92  	}
    93  	return fmt.Sprintf("_p%d", p.tmpVarIdx)
    94  }
    95  
    96  // BoolTmpVarCode returns source code for bool temp variable.
    97  func (p *Param) BoolTmpVarCode() string {
    98  	const code = `var %s uint32
    99  	if %s {
   100  		%s = 1
   101  	} else {
   102  		%s = 0
   103  	}`
   104  	tmp := p.tmpVar()
   105  	return fmt.Sprintf(code, tmp, p.Name, tmp, tmp)
   106  }
   107  
   108  // SliceTmpVarCode returns source code for slice temp variable.
   109  func (p *Param) SliceTmpVarCode() string {
   110  	const code = `var %s *%s
   111  	if len(%s) > 0 {
   112  		%s = &%s[0]
   113  	}`
   114  	tmp := p.tmpVar()
   115  	return fmt.Sprintf(code, tmp, p.Type[2:], p.Name, tmp, p.Name)
   116  }
   117  
   118  // StringTmpVarCode returns source code for string temp variable.
   119  func (p *Param) StringTmpVarCode() string {
   120  	errvar := p.fn.Rets.ErrorVarName()
   121  	if errvar == "" {
   122  		errvar = "_"
   123  	}
   124  	tmp := p.tmpVar()
   125  	const code = `var %s %s
   126  	%s, %s = %s(%s)`
   127  	s := fmt.Sprintf(code, tmp, p.fn.StrconvType(), tmp, errvar, p.fn.StrconvFunc(), p.Name)
   128  	if errvar == "-" {
   129  		return s
   130  	}
   131  	const morecode = `
   132  	if %s != nil {
   133  		return
   134  	}`
   135  	return s + fmt.Sprintf(morecode, errvar)
   136  }
   137  
   138  // TmpVarCode returns source code for temp variable.
   139  func (p *Param) TmpVarCode() string {
   140  	switch {
   141  	case p.Type == "bool":
   142  		return p.BoolTmpVarCode()
   143  	case strings.HasPrefix(p.Type, "[]"):
   144  		return p.SliceTmpVarCode()
   145  	default:
   146  		return ""
   147  	}
   148  }
   149  
   150  // TmpVarHelperCode returns source code for helper's temp variable.
   151  func (p *Param) TmpVarHelperCode() string {
   152  	if p.Type != "string" {
   153  		return ""
   154  	}
   155  	return p.StringTmpVarCode()
   156  }
   157  
   158  // SyscallArgList returns source code fragments representing p parameter
   159  // in syscall. Slices are translated into 2 syscall parameters: pointer to
   160  // the first element and length.
   161  func (p *Param) SyscallArgList() []string {
   162  	t := p.HelperType()
   163  	var s string
   164  	switch {
   165  	case t[0] == '*':
   166  		s = fmt.Sprintf("unsafe.Pointer(%s)", p.Name)
   167  	case t == "bool":
   168  		s = p.tmpVar()
   169  	case strings.HasPrefix(t, "[]"):
   170  		return []string{
   171  			fmt.Sprintf("uintptr(unsafe.Pointer(%s))", p.tmpVar()),
   172  			fmt.Sprintf("uintptr(len(%s))", p.Name),
   173  		}
   174  	default:
   175  		s = p.Name
   176  	}
   177  	return []string{fmt.Sprintf("uintptr(%s)", s)}
   178  }
   179  
   180  // IsError determines if p parameter is used to return error.
   181  func (p *Param) IsError() bool {
   182  	return p.Name == "err" && p.Type == "error"
   183  }
   184  
   185  // HelperType returns type of parameter p used in helper function.
   186  func (p *Param) HelperType() string {
   187  	if p.Type == "string" {
   188  		return p.fn.StrconvType()
   189  	}
   190  	return p.Type
   191  }
   192  
   193  // join concatenates parameters ps into a string with sep separator.
   194  // Each parameter is converted into string by applying fn to it
   195  // before conversion.
   196  func join(ps []*Param, fn func(*Param) string, sep string) string {
   197  	if len(ps) == 0 {
   198  		return ""
   199  	}
   200  	a := make([]string, 0)
   201  	for _, p := range ps {
   202  		a = append(a, fn(p))
   203  	}
   204  	return strings.Join(a, sep)
   205  }
   206  
   207  // Rets describes function return parameters.
   208  type Rets struct {
   209  	Name         string
   210  	Type         string
   211  	ReturnsError bool
   212  	FailCond     string
   213  }
   214  
   215  // ErrorVarName returns error variable name for r.
   216  func (r *Rets) ErrorVarName() string {
   217  	if r.ReturnsError {
   218  		return "err"
   219  	}
   220  	if r.Type == "error" {
   221  		return r.Name
   222  	}
   223  	return ""
   224  }
   225  
   226  // ToParams converts r into slice of *Param.
   227  func (r *Rets) ToParams() []*Param {
   228  	ps := make([]*Param, 0)
   229  	if len(r.Name) > 0 {
   230  		ps = append(ps, &Param{Name: r.Name, Type: r.Type})
   231  	}
   232  	if r.ReturnsError {
   233  		ps = append(ps, &Param{Name: "err", Type: "error"})
   234  	}
   235  	return ps
   236  }
   237  
   238  // List returns source code of syscall return parameters.
   239  func (r *Rets) List() string {
   240  	s := join(r.ToParams(), func(p *Param) string { return p.Name + " " + p.Type }, ", ")
   241  	if len(s) > 0 {
   242  		s = "(" + s + ")"
   243  	}
   244  	return s
   245  }
   246  
   247  // PrintList returns source code of trace printing part correspondent
   248  // to syscall return values.
   249  func (r *Rets) PrintList() string {
   250  	return join(r.ToParams(), func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
   251  }
   252  
   253  // SetReturnValuesCode returns source code that accepts syscall return values.
   254  func (r *Rets) SetReturnValuesCode() string {
   255  	if r.Name == "" && !r.ReturnsError {
   256  		return ""
   257  	}
   258  	retvar := "r0"
   259  	if r.Name == "" {
   260  		retvar = "r1"
   261  	}
   262  	errvar := "_"
   263  	if r.ReturnsError {
   264  		errvar = "e1"
   265  	}
   266  	return fmt.Sprintf("%s, _, %s := ", retvar, errvar)
   267  }
   268  
   269  func (r *Rets) useLongHandleErrorCode(retvar string) string {
   270  	const code = `if %s {
   271  		if e1 != 0 {
   272  			err = error(e1)
   273  		} else {
   274  			err = %sEINVAL
   275  		}
   276  	}`
   277  	cond := retvar + " == 0"
   278  	if r.FailCond != "" {
   279  		cond = strings.Replace(r.FailCond, "failretval", retvar, 1)
   280  	}
   281  	return fmt.Sprintf(code, cond, syscalldot())
   282  }
   283  
   284  // SetErrorCode returns source code that sets return parameters.
   285  func (r *Rets) SetErrorCode() string {
   286  	const code = `if r0 != 0 {
   287  		%s = %sErrno(r0)
   288  	}`
   289  	if r.Name == "" && !r.ReturnsError {
   290  		return ""
   291  	}
   292  	if r.Name == "" {
   293  		return r.useLongHandleErrorCode("r1")
   294  	}
   295  	if r.Type == "error" {
   296  		return fmt.Sprintf(code, r.Name, syscalldot())
   297  	}
   298  	s := ""
   299  	switch {
   300  	case r.Type[0] == '*':
   301  		s = fmt.Sprintf("%s = (%s)(unsafe.Pointer(r0))", r.Name, r.Type)
   302  	case r.Type == "bool":
   303  		s = fmt.Sprintf("%s = r0 != 0", r.Name)
   304  	default:
   305  		s = fmt.Sprintf("%s = %s(r0)", r.Name, r.Type)
   306  	}
   307  	if !r.ReturnsError {
   308  		return s
   309  	}
   310  	return s + "\n\t" + r.useLongHandleErrorCode(r.Name)
   311  }
   312  
   313  // Fn describes syscall function.
   314  type Fn struct {
   315  	Name        string
   316  	Params      []*Param
   317  	Rets        *Rets
   318  	PrintTrace  bool
   319  	dllname     string
   320  	dllfuncname string
   321  	src         string
   322  	// TODO: get rid of this field and just use parameter index instead
   323  	curTmpVarIdx int // insure tmp variables have uniq names
   324  }
   325  
   326  // extractParams parses s to extract function parameters.
   327  func extractParams(s string, f *Fn) ([]*Param, error) {
   328  	s = trim(s)
   329  	if s == "" {
   330  		return nil, nil
   331  	}
   332  	a := strings.Split(s, ",")
   333  	ps := make([]*Param, len(a))
   334  	for i := range ps {
   335  		s2 := trim(a[i])
   336  		b := strings.Split(s2, " ")
   337  		if len(b) != 2 {
   338  			b = strings.Split(s2, "\t")
   339  			if len(b) != 2 {
   340  				return nil, errors.New("Could not extract function parameter from \"" + s2 + "\"")
   341  			}
   342  		}
   343  		ps[i] = &Param{
   344  			Name:      trim(b[0]),
   345  			Type:      trim(b[1]),
   346  			fn:        f,
   347  			tmpVarIdx: -1,
   348  		}
   349  	}
   350  	return ps, nil
   351  }
   352  
   353  // extractSection extracts text out of string s starting after start
   354  // and ending just before end. found return value will indicate success,
   355  // and prefix, body and suffix will contain correspondent parts of string s.
   356  func extractSection(s string, start, end rune) (prefix, body, suffix string, found bool) {
   357  	s = trim(s)
   358  	if strings.HasPrefix(s, string(start)) {
   359  		// no prefix
   360  		body = s[1:]
   361  	} else {
   362  		a := strings.SplitN(s, string(start), 2)
   363  		if len(a) != 2 {
   364  			return "", "", s, false
   365  		}
   366  		prefix = a[0]
   367  		body = a[1]
   368  	}
   369  	a := strings.SplitN(body, string(end), 2)
   370  	if len(a) != 2 {
   371  		return "", "", "", false
   372  	}
   373  	return prefix, a[0], a[1], true
   374  }
   375  
   376  // newFn parses string s and return created function Fn.
   377  func newFn(s string) (*Fn, error) {
   378  	s = trim(s)
   379  	f := &Fn{
   380  		Rets:       &Rets{},
   381  		src:        s,
   382  		PrintTrace: *PrintTraceFlag,
   383  	}
   384  	// function name and args
   385  	prefix, body, s, found := extractSection(s, '(', ')')
   386  	if !found || prefix == "" {
   387  		return nil, errors.New("Could not extract function name and parameters from \"" + f.src + "\"")
   388  	}
   389  	f.Name = prefix
   390  	var err error
   391  	f.Params, err = extractParams(body, f)
   392  	if err != nil {
   393  		return nil, err
   394  	}
   395  	// return values
   396  	_, body, s, found = extractSection(s, '(', ')')
   397  	if found {
   398  		r, err := extractParams(body, f)
   399  		if err != nil {
   400  			return nil, err
   401  		}
   402  		switch len(r) {
   403  		case 0:
   404  		case 1:
   405  			if r[0].IsError() {
   406  				f.Rets.ReturnsError = true
   407  			} else {
   408  				f.Rets.Name = r[0].Name
   409  				f.Rets.Type = r[0].Type
   410  			}
   411  		case 2:
   412  			if !r[1].IsError() {
   413  				return nil, errors.New("Only last windows error is allowed as second return value in \"" + f.src + "\"")
   414  			}
   415  			f.Rets.ReturnsError = true
   416  			f.Rets.Name = r[0].Name
   417  			f.Rets.Type = r[0].Type
   418  		default:
   419  			return nil, errors.New("Too many return values in \"" + f.src + "\"")
   420  		}
   421  	}
   422  	// fail condition
   423  	_, body, s, found = extractSection(s, '[', ']')
   424  	if found {
   425  		f.Rets.FailCond = body
   426  	}
   427  	// dll and dll function names
   428  	s = trim(s)
   429  	if s == "" {
   430  		return f, nil
   431  	}
   432  	if !strings.HasPrefix(s, "=") {
   433  		return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
   434  	}
   435  	s = trim(s[1:])
   436  	a := strings.Split(s, ".")
   437  	switch len(a) {
   438  	case 1:
   439  		f.dllfuncname = a[0]
   440  	case 2:
   441  		f.dllname = a[0]
   442  		f.dllfuncname = a[1]
   443  	default:
   444  		return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
   445  	}
   446  	return f, nil
   447  }
   448  
   449  // DLLName returns DLL name for function f.
   450  func (f *Fn) DLLName() string {
   451  	if f.dllname == "" {
   452  		return "kernel32"
   453  	}
   454  	return f.dllname
   455  }
   456  
   457  // DLLName returns DLL function name for function f.
   458  func (f *Fn) DLLFuncName() string {
   459  	if f.dllfuncname == "" {
   460  		return f.Name
   461  	}
   462  	return f.dllfuncname
   463  }
   464  
   465  // ParamList returns source code for function f parameters.
   466  func (f *Fn) ParamList() string {
   467  	return join(f.Params, func(p *Param) string { return p.Name + " " + p.Type }, ", ")
   468  }
   469  
   470  // HelperParamList returns source code for helper function f parameters.
   471  func (f *Fn) HelperParamList() string {
   472  	return join(f.Params, func(p *Param) string { return p.Name + " " + p.HelperType() }, ", ")
   473  }
   474  
   475  // ParamPrintList returns source code of trace printing part correspondent
   476  // to syscall input parameters.
   477  func (f *Fn) ParamPrintList() string {
   478  	return join(f.Params, func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
   479  }
   480  
   481  // ParamCount return number of syscall parameters for function f.
   482  func (f *Fn) ParamCount() int {
   483  	n := 0
   484  	for _, p := range f.Params {
   485  		n += len(p.SyscallArgList())
   486  	}
   487  	return n
   488  }
   489  
   490  // SyscallParamCount determines which version of Syscall/Syscall6/Syscall9/...
   491  // to use. It returns parameter count for correspondent SyscallX function.
   492  func (f *Fn) SyscallParamCount() int {
   493  	n := f.ParamCount()
   494  	switch {
   495  	case n <= 3:
   496  		return 3
   497  	case n <= 6:
   498  		return 6
   499  	case n <= 9:
   500  		return 9
   501  	case n <= 12:
   502  		return 12
   503  	case n <= 15:
   504  		return 15
   505  	default:
   506  		panic("too many arguments to system call")
   507  	}
   508  }
   509  
   510  // Syscall determines which SyscallX function to use for function f.
   511  func (f *Fn) Syscall() string {
   512  	c := f.SyscallParamCount()
   513  	if c == 3 {
   514  		return syscalldot() + "Syscall"
   515  	}
   516  	return syscalldot() + "Syscall" + strconv.Itoa(c)
   517  }
   518  
   519  // SyscallParamList returns source code for SyscallX parameters for function f.
   520  func (f *Fn) SyscallParamList() string {
   521  	a := make([]string, 0)
   522  	for _, p := range f.Params {
   523  		a = append(a, p.SyscallArgList()...)
   524  	}
   525  	for len(a) < f.SyscallParamCount() {
   526  		a = append(a, "0")
   527  	}
   528  	return strings.Join(a, ", ")
   529  }
   530  
   531  // HelperCallParamList returns source code of call into function f helper.
   532  func (f *Fn) HelperCallParamList() string {
   533  	a := make([]string, 0, len(f.Params))
   534  	for _, p := range f.Params {
   535  		s := p.Name
   536  		if p.Type == "string" {
   537  			s = p.tmpVar()
   538  		}
   539  		a = append(a, s)
   540  	}
   541  	return strings.Join(a, ", ")
   542  }
   543  
   544  // IsUTF16 is true, if f is W (utf16) function. It is false
   545  // for all A (ascii) functions.
   546  func (f *Fn) IsUTF16() bool {
   547  	s := f.DLLFuncName()
   548  	return s[len(s)-1] == 'W'
   549  }
   550  
   551  // StrconvFunc returns name of Go string to OS string function for f.
   552  func (f *Fn) StrconvFunc() string {
   553  	if f.IsUTF16() {
   554  		return syscalldot() + "UTF16PtrFromString"
   555  	}
   556  	return syscalldot() + "BytePtrFromString"
   557  }
   558  
   559  // StrconvType returns Go type name used for OS string for f.
   560  func (f *Fn) StrconvType() string {
   561  	if f.IsUTF16() {
   562  		return "*uint16"
   563  	}
   564  	return "*byte"
   565  }
   566  
   567  // HasStringParam is true, if f has at least one string parameter.
   568  // Otherwise it is false.
   569  func (f *Fn) HasStringParam() bool {
   570  	for _, p := range f.Params {
   571  		if p.Type == "string" {
   572  			return true
   573  		}
   574  	}
   575  	return false
   576  }
   577  
   578  // HelperName returns name of function f helper.
   579  func (f *Fn) HelperName() string {
   580  	if !f.HasStringParam() {
   581  		return f.Name
   582  	}
   583  	return "_" + f.Name
   584  }
   585  
   586  // Source files and functions.
   587  type Source struct {
   588  	Funcs []*Fn
   589  	Files []string
   590  }
   591  
   592  // ParseFiles parses files listed in fs and extracts all syscall
   593  // functions listed in  sys comments. It returns source files
   594  // and functions collection *Source if successful.
   595  func ParseFiles(fs []string) (*Source, error) {
   596  	src := &Source{
   597  		Funcs: make([]*Fn, 0),
   598  		Files: make([]string, 0),
   599  	}
   600  	for _, file := range fs {
   601  		if err := src.ParseFile(file); err != nil {
   602  			return nil, err
   603  		}
   604  	}
   605  	return src, nil
   606  }
   607  
   608  // DLLs return dll names for a source set src.
   609  func (src *Source) DLLs() []string {
   610  	uniq := make(map[string]bool)
   611  	r := make([]string, 0)
   612  	for _, f := range src.Funcs {
   613  		name := f.DLLName()
   614  		if _, found := uniq[name]; !found {
   615  			uniq[name] = true
   616  			r = append(r, name)
   617  		}
   618  	}
   619  	return r
   620  }
   621  
   622  // ParseFile adds adition file path to a source set src.
   623  func (src *Source) ParseFile(path string) error {
   624  	file, err := os.Open(path)
   625  	if err != nil {
   626  		return err
   627  	}
   628  	defer file.Close()
   629  
   630  	s := bufio.NewScanner(file)
   631  	for s.Scan() {
   632  		t := trim(s.Text())
   633  		if len(t) < 7 {
   634  			continue
   635  		}
   636  		if !strings.HasPrefix(t, "//sys") {
   637  			continue
   638  		}
   639  		t = t[5:]
   640  		if !(t[0] == ' ' || t[0] == '\t') {
   641  			continue
   642  		}
   643  		f, err := newFn(t[1:])
   644  		if err != nil {
   645  			return err
   646  		}
   647  		src.Funcs = append(src.Funcs, f)
   648  	}
   649  	if err := s.Err(); err != nil {
   650  		return err
   651  	}
   652  	src.Files = append(src.Files, path)
   653  
   654  	// get package name
   655  	fset := token.NewFileSet()
   656  	_, err = file.Seek(0, 0)
   657  	if err != nil {
   658  		return err
   659  	}
   660  	pkg, err := parser.ParseFile(fset, "", file, parser.PackageClauseOnly)
   661  	if err != nil {
   662  		return err
   663  	}
   664  	packageName = pkg.Name.Name
   665  
   666  	return nil
   667  }
   668  
   669  // Generate output source file from a source set src.
   670  func (src *Source) Generate(w io.Writer) error {
   671  	funcMap := template.FuncMap{
   672  		"syscalldot":  syscalldot,
   673  		"packagename": packagename,
   674  	}
   675  	t := template.Must(template.New("main").Funcs(funcMap).Parse(srcTemplate))
   676  	err := t.Execute(w, src)
   677  	if err != nil {
   678  		return errors.New("Failed to execute template: " + err.Error())
   679  	}
   680  	return nil
   681  }
   682  
   683  func usage() {
   684  	fmt.Fprintf(os.Stderr, "usage: mksyscall_windows [flags] [path ...]\n")
   685  	flag.PrintDefaults()
   686  	os.Exit(1)
   687  }
   688  
   689  func main() {
   690  	flag.Usage = usage
   691  	flag.Parse()
   692  	if len(os.Args) <= 1 {
   693  		fmt.Fprintf(os.Stderr, "no files to parse provided\n")
   694  		usage()
   695  	}
   696  	src, err := ParseFiles(os.Args[1:])
   697  	if err != nil {
   698  		log.Fatal(err)
   699  	}
   700  	if err := src.Generate(os.Stdout); err != nil {
   701  		log.Fatal(err)
   702  	}
   703  }
   704  
   705  // TODO: use println instead to print in the following template
   706  const srcTemplate = `
   707  
   708  {{define "main"}}// go build mksyscall_windows.go && ./mksyscall_windows{{range .Files}} {{.}}{{end}}
   709  // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
   710  
   711  package {{packagename}}
   712  
   713  import "unsafe"{{if syscalldot}}
   714  import "syscall"{{end}}
   715  
   716  var (
   717  {{template "dlls" .}}
   718  {{template "funcnames" .}})
   719  {{range .Funcs}}{{if .HasStringParam}}{{template "helperbody" .}}{{end}}{{template "funcbody" .}}{{end}}
   720  {{end}}
   721  
   722  {{/* help functions */}}
   723  
   724  {{define "dlls"}}{{range .DLLs}}	mod{{.}} = {{syscalldot}}NewLazyDLL("{{.}}.dll")
   725  {{end}}{{end}}
   726  
   727  {{define "funcnames"}}{{range .Funcs}}	proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}")
   728  {{end}}{{end}}
   729  
   730  {{define "helperbody"}}
   731  func {{.Name}}({{.ParamList}}) {{template "results" .}}{
   732  {{template "helpertmpvars" .}}	return {{.HelperName}}({{.HelperCallParamList}})
   733  }
   734  {{end}}
   735  
   736  {{define "funcbody"}}
   737  func {{.HelperName}}({{.HelperParamList}}) {{template "results" .}}{
   738  {{template "tmpvars" .}}	{{template "syscall" .}}
   739  {{template "seterror" .}}{{template "printtrace" .}}	return
   740  }
   741  {{end}}
   742  
   743  {{define "helpertmpvars"}}{{range .Params}}{{if .TmpVarHelperCode}}	{{.TmpVarHelperCode}}
   744  {{end}}{{end}}{{end}}
   745  
   746  {{define "tmpvars"}}{{range .Params}}{{if .TmpVarCode}}	{{.TmpVarCode}}
   747  {{end}}{{end}}{{end}}
   748  
   749  {{define "results"}}{{if .Rets.List}}{{.Rets.List}} {{end}}{{end}}
   750  
   751  {{define "syscall"}}{{.Rets.SetReturnValuesCode}}{{.Syscall}}(proc{{.DLLFuncName}}.Addr(), {{.ParamCount}}, {{.SyscallParamList}}){{end}}
   752  
   753  {{define "seterror"}}{{if .Rets.SetErrorCode}}	{{.Rets.SetErrorCode}}
   754  {{end}}{{end}}
   755  
   756  {{define "printtrace"}}{{if .PrintTrace}}	print("SYSCALL: {{.Name}}(", {{.ParamPrintList}}") (", {{.Rets.PrintList}}")\n")
   757  {{end}}{{end}}
   758  
   759  `