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