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// Hard-coding unicode mode for VHD library.
6
7// +build ignore
8
9/*
10mksyscall_windows generates windows system call bodies
11
12It parses all files specified on command line containing function
13prototypes (like syscall_windows.go) and prints system call bodies
14to standard output.
15
16The prototypes are marked by lines beginning with "//sys" and read
17like func declarations if //sys is replaced by func, but:
18
19* The parameter lists must give a name for each argument. This
20  includes return parameters.
21
22* The parameter lists must give a type for each argument:
23  the (x, y, z int) shorthand is not allowed.
24
25* If the return parameter is an error number, it must be named err.
26
27* If go func name needs to be different from its winapi dll name,
28  the winapi name could be specified at the end, after "=" sign, like
29  //sys LoadLibrary(libname string) (handle uint32, err error) = LoadLibraryA
30
31* Each function that returns err needs to supply a condition, that
32  return value of winapi will be tested against to detect failure.
33  This would set err to windows "last-error", otherwise it will be nil.
34  The value can be provided at end of //sys declaration, like
35  //sys LoadLibrary(libname string) (handle uint32, err error) [failretval==-1] = LoadLibraryA
36  and is [failretval==0] by default.
37
38* If the function name ends in a "?", then the function not existing is non-
39  fatal, and an error will be returned instead of panicking.
40
41Usage:
42	mksyscall_windows [flags] [path ...]
43
44The flags are:
45	-output
46		Specify output file name (outputs to console if blank).
47	-trace
48		Generate print statement after every syscall.
49*/
50package main
51
52import (
53	"bufio"
54	"bytes"
55	"errors"
56	"flag"
57	"fmt"
58	"go/format"
59	"go/parser"
60	"go/token"
61	"io"
62	"io/ioutil"
63	"log"
64	"os"
65	"path/filepath"
66	"runtime"
67	"sort"
68	"strconv"
69	"strings"
70	"text/template"
71)
72
73var (
74	filename       = flag.String("output", "", "output file name (standard output if omitted)")
75	printTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall")
76	systemDLL      = flag.Bool("systemdll", true, "whether all DLLs should be loaded from the Windows system directory")
77)
78
79func trim(s string) string {
80	return strings.Trim(s, " \t")
81}
82
83var packageName string
84
85func packagename() string {
86	return packageName
87}
88
89func syscalldot() string {
90	if packageName == "syscall" {
91		return ""
92	}
93	return "syscall."
94}
95
96// Param is function parameter
97type Param struct {
98	Name      string
99	Type      string
100	fn        *Fn
101	tmpVarIdx int
102}
103
104// tmpVar returns temp variable name that will be used to represent p during syscall.
105func (p *Param) tmpVar() string {
106	if p.tmpVarIdx < 0 {
107		p.tmpVarIdx = p.fn.curTmpVarIdx
108		p.fn.curTmpVarIdx++
109	}
110	return fmt.Sprintf("_p%d", p.tmpVarIdx)
111}
112
113// BoolTmpVarCode returns source code for bool temp variable.
114func (p *Param) BoolTmpVarCode() string {
115	const code = `var %[1]s uint32
116	if %[2]s {
117		%[1]s = 1
118	}`
119	return fmt.Sprintf(code, p.tmpVar(), p.Name)
120}
121
122// BoolPointerTmpVarCode returns source code for bool temp variable.
123func (p *Param) BoolPointerTmpVarCode() string {
124	const code = `var %[1]s uint32
125	if *%[2]s {
126		%[1]s = 1
127	}`
128	return fmt.Sprintf(code, p.tmpVar(), p.Name)
129}
130
131// SliceTmpVarCode returns source code for slice temp variable.
132func (p *Param) SliceTmpVarCode() string {
133	const code = `var %s *%s
134	if len(%s) > 0 {
135		%s = &%s[0]
136	}`
137	tmp := p.tmpVar()
138	return fmt.Sprintf(code, tmp, p.Type[2:], p.Name, tmp, p.Name)
139}
140
141// StringTmpVarCode returns source code for string temp variable.
142func (p *Param) StringTmpVarCode() string {
143	errvar := p.fn.Rets.ErrorVarName()
144	if errvar == "" {
145		errvar = "_"
146	}
147	tmp := p.tmpVar()
148	const code = `var %s %s
149	%s, %s = %s(%s)`
150	s := fmt.Sprintf(code, tmp, p.fn.StrconvType(), tmp, errvar, p.fn.StrconvFunc(), p.Name)
151	if errvar == "-" {
152		return s
153	}
154	const morecode = `
155	if %s != nil {
156		return
157	}`
158	return s + fmt.Sprintf(morecode, errvar)
159}
160
161// TmpVarCode returns source code for temp variable.
162func (p *Param) TmpVarCode() string {
163	switch {
164	case p.Type == "bool":
165		return p.BoolTmpVarCode()
166	case p.Type == "*bool":
167		return p.BoolPointerTmpVarCode()
168	case strings.HasPrefix(p.Type, "[]"):
169		return p.SliceTmpVarCode()
170	default:
171		return ""
172	}
173}
174
175// TmpVarReadbackCode returns source code for reading back the temp variable into the original variable.
176func (p *Param) TmpVarReadbackCode() string {
177	switch {
178	case p.Type == "*bool":
179		return fmt.Sprintf("*%s = %s != 0", p.Name, p.tmpVar())
180	default:
181		return ""
182	}
183}
184
185// TmpVarHelperCode returns source code for helper's temp variable.
186func (p *Param) TmpVarHelperCode() string {
187	if p.Type != "string" {
188		return ""
189	}
190	return p.StringTmpVarCode()
191}
192
193// SyscallArgList returns source code fragments representing p parameter
194// in syscall. Slices are translated into 2 syscall parameters: pointer to
195// the first element and length.
196func (p *Param) SyscallArgList() []string {
197	t := p.HelperType()
198	var s string
199	switch {
200	case t == "*bool":
201		s = fmt.Sprintf("unsafe.Pointer(&%s)", p.tmpVar())
202	case t[0] == '*':
203		s = fmt.Sprintf("unsafe.Pointer(%s)", p.Name)
204	case t == "bool":
205		s = p.tmpVar()
206	case strings.HasPrefix(t, "[]"):
207		return []string{
208			fmt.Sprintf("uintptr(unsafe.Pointer(%s))", p.tmpVar()),
209			fmt.Sprintf("uintptr(len(%s))", p.Name),
210		}
211	default:
212		s = p.Name
213	}
214	return []string{fmt.Sprintf("uintptr(%s)", s)}
215}
216
217// IsError determines if p parameter is used to return error.
218func (p *Param) IsError() bool {
219	return p.Name == "err" && p.Type == "error"
220}
221
222// HelperType returns type of parameter p used in helper function.
223func (p *Param) HelperType() string {
224	if p.Type == "string" {
225		return p.fn.StrconvType()
226	}
227	return p.Type
228}
229
230// join concatenates parameters ps into a string with sep separator.
231// Each parameter is converted into string by applying fn to it
232// before conversion.
233func join(ps []*Param, fn func(*Param) string, sep string) string {
234	if len(ps) == 0 {
235		return ""
236	}
237	a := make([]string, 0)
238	for _, p := range ps {
239		a = append(a, fn(p))
240	}
241	return strings.Join(a, sep)
242}
243
244// Rets describes function return parameters.
245type Rets struct {
246	Name          string
247	Type          string
248	ReturnsError  bool
249	FailCond      string
250	fnMaybeAbsent bool
251}
252
253// ErrorVarName returns error variable name for r.
254func (r *Rets) ErrorVarName() string {
255	if r.ReturnsError {
256		return "err"
257	}
258	if r.Type == "error" {
259		return r.Name
260	}
261	return ""
262}
263
264// ToParams converts r into slice of *Param.
265func (r *Rets) ToParams() []*Param {
266	ps := make([]*Param, 0)
267	if len(r.Name) > 0 {
268		ps = append(ps, &Param{Name: r.Name, Type: r.Type})
269	}
270	if r.ReturnsError {
271		ps = append(ps, &Param{Name: "err", Type: "error"})
272	}
273	return ps
274}
275
276// List returns source code of syscall return parameters.
277func (r *Rets) List() string {
278	s := join(r.ToParams(), func(p *Param) string { return p.Name + " " + p.Type }, ", ")
279	if len(s) > 0 {
280		s = "(" + s + ")"
281	} else if r.fnMaybeAbsent {
282		s = "(err error)"
283	}
284	return s
285}
286
287// PrintList returns source code of trace printing part correspondent
288// to syscall return values.
289func (r *Rets) PrintList() string {
290	return join(r.ToParams(), func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
291}
292
293// SetReturnValuesCode returns source code that accepts syscall return values.
294func (r *Rets) SetReturnValuesCode() string {
295	if r.Name == "" && !r.ReturnsError {
296		return ""
297	}
298	retvar := "r0"
299	if r.Name == "" {
300		retvar = "r1"
301	}
302	errvar := "_"
303	if r.ReturnsError {
304		errvar = "e1"
305	}
306	return fmt.Sprintf("%s, _, %s := ", retvar, errvar)
307}
308
309func (r *Rets) useLongHandleErrorCode(retvar string) string {
310	const code = `if %s {
311		err = errnoErr(e1)
312	}`
313	cond := retvar + " == 0"
314	if r.FailCond != "" {
315		cond = strings.Replace(r.FailCond, "failretval", retvar, 1)
316	}
317	return fmt.Sprintf(code, cond)
318}
319
320// SetErrorCode returns source code that sets return parameters.
321func (r *Rets) SetErrorCode() string {
322	const code = `if r0 != 0 {
323		%s = %sErrno(r0)
324	}`
325	if r.Name == "" && !r.ReturnsError {
326		return ""
327	}
328	if r.Name == "" {
329		return r.useLongHandleErrorCode("r1")
330	}
331	if r.Type == "error" {
332		return fmt.Sprintf(code, r.Name, syscalldot())
333	}
334	s := ""
335	switch {
336	case r.Type[0] == '*':
337		s = fmt.Sprintf("%s = (%s)(unsafe.Pointer(r0))", r.Name, r.Type)
338	case r.Type == "bool":
339		s = fmt.Sprintf("%s = r0 != 0", r.Name)
340	default:
341		s = fmt.Sprintf("%s = %s(r0)", r.Name, r.Type)
342	}
343	if !r.ReturnsError {
344		return s
345	}
346	return s + "\n\t" + r.useLongHandleErrorCode(r.Name)
347}
348
349// Fn describes syscall function.
350type Fn struct {
351	Name        string
352	Params      []*Param
353	Rets        *Rets
354	PrintTrace  bool
355	dllname     string
356	dllfuncname string
357	src         string
358	// TODO: get rid of this field and just use parameter index instead
359	curTmpVarIdx int // insure tmp variables have uniq names
360}
361
362// extractParams parses s to extract function parameters.
363func extractParams(s string, f *Fn) ([]*Param, error) {
364	s = trim(s)
365	if s == "" {
366		return nil, nil
367	}
368	a := strings.Split(s, ",")
369	ps := make([]*Param, len(a))
370	for i := range ps {
371		s2 := trim(a[i])
372		b := strings.Split(s2, " ")
373		if len(b) != 2 {
374			b = strings.Split(s2, "\t")
375			if len(b) != 2 {
376				return nil, errors.New("Could not extract function parameter from \"" + s2 + "\"")
377			}
378		}
379		ps[i] = &Param{
380			Name:      trim(b[0]),
381			Type:      trim(b[1]),
382			fn:        f,
383			tmpVarIdx: -1,
384		}
385	}
386	return ps, nil
387}
388
389// extractSection extracts text out of string s starting after start
390// and ending just before end. found return value will indicate success,
391// and prefix, body and suffix will contain correspondent parts of string s.
392func extractSection(s string, start, end rune) (prefix, body, suffix string, found bool) {
393	s = trim(s)
394	if strings.HasPrefix(s, string(start)) {
395		// no prefix
396		body = s[1:]
397	} else {
398		a := strings.SplitN(s, string(start), 2)
399		if len(a) != 2 {
400			return "", "", s, false
401		}
402		prefix = a[0]
403		body = a[1]
404	}
405	a := strings.SplitN(body, string(end), 2)
406	if len(a) != 2 {
407		return "", "", "", false
408	}
409	return prefix, a[0], a[1], true
410}
411
412// newFn parses string s and return created function Fn.
413func newFn(s string) (*Fn, error) {
414	s = trim(s)
415	f := &Fn{
416		Rets:       &Rets{},
417		src:        s,
418		PrintTrace: *printTraceFlag,
419	}
420	// function name and args
421	prefix, body, s, found := extractSection(s, '(', ')')
422	if !found || prefix == "" {
423		return nil, errors.New("Could not extract function name and parameters from \"" + f.src + "\"")
424	}
425	f.Name = prefix
426	var err error
427	f.Params, err = extractParams(body, f)
428	if err != nil {
429		return nil, err
430	}
431	// return values
432	_, body, s, found = extractSection(s, '(', ')')
433	if found {
434		r, err := extractParams(body, f)
435		if err != nil {
436			return nil, err
437		}
438		switch len(r) {
439		case 0:
440		case 1:
441			if r[0].IsError() {
442				f.Rets.ReturnsError = true
443			} else {
444				f.Rets.Name = r[0].Name
445				f.Rets.Type = r[0].Type
446			}
447		case 2:
448			if !r[1].IsError() {
449				return nil, errors.New("Only last windows error is allowed as second return value in \"" + f.src + "\"")
450			}
451			f.Rets.ReturnsError = true
452			f.Rets.Name = r[0].Name
453			f.Rets.Type = r[0].Type
454		default:
455			return nil, errors.New("Too many return values in \"" + f.src + "\"")
456		}
457	}
458	// fail condition
459	_, body, s, found = extractSection(s, '[', ']')
460	if found {
461		f.Rets.FailCond = body
462	}
463	// dll and dll function names
464	s = trim(s)
465	if s == "" {
466		return f, nil
467	}
468	if !strings.HasPrefix(s, "=") {
469		return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
470	}
471	s = trim(s[1:])
472	a := strings.Split(s, ".")
473	switch len(a) {
474	case 1:
475		f.dllfuncname = a[0]
476	case 2:
477		f.dllname = a[0]
478		f.dllfuncname = a[1]
479	default:
480		return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
481	}
482	if n := f.dllfuncname; strings.HasSuffix(n, "?") {
483		f.dllfuncname = n[:len(n)-1]
484		f.Rets.fnMaybeAbsent = true
485	}
486	return f, nil
487}
488
489// DLLName returns DLL name for function f.
490func (f *Fn) DLLName() string {
491	if f.dllname == "" {
492		return "kernel32"
493	}
494	return f.dllname
495}
496
497// DLLName returns DLL function name for function f.
498func (f *Fn) DLLFuncName() string {
499	if f.dllfuncname == "" {
500		return f.Name
501	}
502	return f.dllfuncname
503}
504
505// ParamList returns source code for function f parameters.
506func (f *Fn) ParamList() string {
507	return join(f.Params, func(p *Param) string { return p.Name + " " + p.Type }, ", ")
508}
509
510// HelperParamList returns source code for helper function f parameters.
511func (f *Fn) HelperParamList() string {
512	return join(f.Params, func(p *Param) string { return p.Name + " " + p.HelperType() }, ", ")
513}
514
515// ParamPrintList returns source code of trace printing part correspondent
516// to syscall input parameters.
517func (f *Fn) ParamPrintList() string {
518	return join(f.Params, func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
519}
520
521// ParamCount return number of syscall parameters for function f.
522func (f *Fn) ParamCount() int {
523	n := 0
524	for _, p := range f.Params {
525		n += len(p.SyscallArgList())
526	}
527	return n
528}
529
530// SyscallParamCount determines which version of Syscall/Syscall6/Syscall9/...
531// to use. It returns parameter count for correspondent SyscallX function.
532func (f *Fn) SyscallParamCount() int {
533	n := f.ParamCount()
534	switch {
535	case n <= 3:
536		return 3
537	case n <= 6:
538		return 6
539	case n <= 9:
540		return 9
541	case n <= 12:
542		return 12
543	case n <= 15:
544		return 15
545	default:
546		panic("too many arguments to system call")
547	}
548}
549
550// Syscall determines which SyscallX function to use for function f.
551func (f *Fn) Syscall() string {
552	c := f.SyscallParamCount()
553	if c == 3 {
554		return syscalldot() + "Syscall"
555	}
556	return syscalldot() + "Syscall" + strconv.Itoa(c)
557}
558
559// SyscallParamList returns source code for SyscallX parameters for function f.
560func (f *Fn) SyscallParamList() string {
561	a := make([]string, 0)
562	for _, p := range f.Params {
563		a = append(a, p.SyscallArgList()...)
564	}
565	for len(a) < f.SyscallParamCount() {
566		a = append(a, "0")
567	}
568	return strings.Join(a, ", ")
569}
570
571// HelperCallParamList returns source code of call into function f helper.
572func (f *Fn) HelperCallParamList() string {
573	a := make([]string, 0, len(f.Params))
574	for _, p := range f.Params {
575		s := p.Name
576		if p.Type == "string" {
577			s = p.tmpVar()
578		}
579		a = append(a, s)
580	}
581	return strings.Join(a, ", ")
582}
583
584// MaybeAbsent returns source code for handling functions that are possibly unavailable.
585func (p *Fn) MaybeAbsent() string {
586	if !p.Rets.fnMaybeAbsent {
587		return ""
588	}
589	const code = `%[1]s = proc%[2]s.Find()
590	if %[1]s != nil {
591		return
592	}`
593	errorVar := p.Rets.ErrorVarName()
594	if errorVar == "" {
595		errorVar = "err"
596	}
597	return fmt.Sprintf(code, errorVar, p.DLLFuncName())
598}
599
600// IsUTF16 is true, if f is W (utf16) function. It is false
601// for all A (ascii) functions.
602func (_ *Fn) IsUTF16() bool {
603	return true
604}
605
606// StrconvFunc returns name of Go string to OS string function for f.
607func (f *Fn) StrconvFunc() string {
608	if f.IsUTF16() {
609		return syscalldot() + "UTF16PtrFromString"
610	}
611	return syscalldot() + "BytePtrFromString"
612}
613
614// StrconvType returns Go type name used for OS string for f.
615func (f *Fn) StrconvType() string {
616	if f.IsUTF16() {
617		return "*uint16"
618	}
619	return "*byte"
620}
621
622// HasStringParam is true, if f has at least one string parameter.
623// Otherwise it is false.
624func (f *Fn) HasStringParam() bool {
625	for _, p := range f.Params {
626		if p.Type == "string" {
627			return true
628		}
629	}
630	return false
631}
632
633// HelperName returns name of function f helper.
634func (f *Fn) HelperName() string {
635	if !f.HasStringParam() {
636		return f.Name
637	}
638	return "_" + f.Name
639}
640
641// Source files and functions.
642type Source struct {
643	Funcs           []*Fn
644	Files           []string
645	StdLibImports   []string
646	ExternalImports []string
647}
648
649func (src *Source) Import(pkg string) {
650	src.StdLibImports = append(src.StdLibImports, pkg)
651	sort.Strings(src.StdLibImports)
652}
653
654func (src *Source) ExternalImport(pkg string) {
655	src.ExternalImports = append(src.ExternalImports, pkg)
656	sort.Strings(src.ExternalImports)
657}
658
659// ParseFiles parses files listed in fs and extracts all syscall
660// functions listed in sys comments. It returns source files
661// and functions collection *Source if successful.
662func ParseFiles(fs []string) (*Source, error) {
663	src := &Source{
664		Funcs: make([]*Fn, 0),
665		Files: make([]string, 0),
666		StdLibImports: []string{
667			"unsafe",
668		},
669		ExternalImports: make([]string, 0),
670	}
671	for _, file := range fs {
672		if err := src.ParseFile(file); err != nil {
673			return nil, err
674		}
675	}
676	return src, nil
677}
678
679// DLLs return dll names for a source set src.
680func (src *Source) DLLs() []string {
681	uniq := make(map[string]bool)
682	r := make([]string, 0)
683	for _, f := range src.Funcs {
684		name := f.DLLName()
685		if _, found := uniq[name]; !found {
686			uniq[name] = true
687			r = append(r, name)
688		}
689	}
690	sort.Strings(r)
691	return r
692}
693
694// ParseFile adds additional file path to a source set src.
695func (src *Source) ParseFile(path string) error {
696	file, err := os.Open(path)
697	if err != nil {
698		return err
699	}
700	defer file.Close()
701
702	s := bufio.NewScanner(file)
703	for s.Scan() {
704		t := trim(s.Text())
705		if len(t) < 7 {
706			continue
707		}
708		if !strings.HasPrefix(t, "//sys") {
709			continue
710		}
711		t = t[5:]
712		if !(t[0] == ' ' || t[0] == '\t') {
713			continue
714		}
715		f, err := newFn(t[1:])
716		if err != nil {
717			return err
718		}
719		src.Funcs = append(src.Funcs, f)
720	}
721	if err := s.Err(); err != nil {
722		return err
723	}
724	src.Files = append(src.Files, path)
725	sort.Slice(src.Funcs, func(i, j int) bool {
726		fi, fj := src.Funcs[i], src.Funcs[j]
727		if fi.DLLName() == fj.DLLName() {
728			return fi.DLLFuncName() < fj.DLLFuncName()
729		}
730		return fi.DLLName() < fj.DLLName()
731	})
732
733	// get package name
734	fset := token.NewFileSet()
735	_, err = file.Seek(0, 0)
736	if err != nil {
737		return err
738	}
739	pkg, err := parser.ParseFile(fset, "", file, parser.PackageClauseOnly)
740	if err != nil {
741		return err
742	}
743	packageName = pkg.Name.Name
744
745	return nil
746}
747
748// IsStdRepo reports whether src is part of standard library.
749func (src *Source) IsStdRepo() (bool, error) {
750	if len(src.Files) == 0 {
751		return false, errors.New("no input files provided")
752	}
753	abspath, err := filepath.Abs(src.Files[0])
754	if err != nil {
755		return false, err
756	}
757	goroot := runtime.GOROOT()
758	if runtime.GOOS == "windows" {
759		abspath = strings.ToLower(abspath)
760		goroot = strings.ToLower(goroot)
761	}
762	sep := string(os.PathSeparator)
763	if !strings.HasSuffix(goroot, sep) {
764		goroot += sep
765	}
766	return strings.HasPrefix(abspath, goroot), nil
767}
768
769// Generate output source file from a source set src.
770func (src *Source) Generate(w io.Writer) error {
771	const (
772		pkgStd         = iota // any package in std library
773		pkgXSysWindows        // x/sys/windows package
774		pkgOther
775	)
776	isStdRepo, err := src.IsStdRepo()
777	if err != nil {
778		return err
779	}
780	var pkgtype int
781	switch {
782	case isStdRepo:
783		pkgtype = pkgStd
784	case packageName == "windows":
785		// TODO: this needs better logic than just using package name
786		pkgtype = pkgXSysWindows
787	default:
788		pkgtype = pkgOther
789	}
790	if *systemDLL {
791		switch pkgtype {
792		case pkgStd:
793			src.Import("internal/syscall/windows/sysdll")
794		case pkgXSysWindows:
795		default:
796			src.ExternalImport("golang.org/x/sys/windows")
797		}
798	}
799	if packageName != "syscall" {
800		src.Import("syscall")
801	}
802	funcMap := template.FuncMap{
803		"packagename": packagename,
804		"syscalldot":  syscalldot,
805		"newlazydll": func(dll string) string {
806			arg := "\"" + dll + ".dll\""
807			if !*systemDLL {
808				return syscalldot() + "NewLazyDLL(" + arg + ")"
809			}
810			switch pkgtype {
811			case pkgStd:
812				return syscalldot() + "NewLazyDLL(sysdll.Add(" + arg + "))"
813			case pkgXSysWindows:
814				return "NewLazySystemDLL(" + arg + ")"
815			default:
816				return "windows.NewLazySystemDLL(" + arg + ")"
817			}
818		},
819	}
820	t := template.Must(template.New("main").Funcs(funcMap).Parse(srcTemplate))
821	err = t.Execute(w, src)
822	if err != nil {
823		return errors.New("Failed to execute template: " + err.Error())
824	}
825	return nil
826}
827
828func usage() {
829	fmt.Fprintf(os.Stderr, "usage: mksyscall_windows [flags] [path ...]\n")
830	flag.PrintDefaults()
831	os.Exit(1)
832}
833
834func main() {
835	flag.Usage = usage
836	flag.Parse()
837	if len(flag.Args()) <= 0 {
838		fmt.Fprintf(os.Stderr, "no files to parse provided\n")
839		usage()
840	}
841
842	src, err := ParseFiles(flag.Args())
843	if err != nil {
844		log.Fatal(err)
845	}
846
847	var buf bytes.Buffer
848	if err := src.Generate(&buf); err != nil {
849		log.Fatal(err)
850	}
851
852	data, err := format.Source(buf.Bytes())
853	if err != nil {
854		log.Fatal(err)
855	}
856	if *filename == "" {
857		_, err = os.Stdout.Write(data)
858	} else {
859		err = ioutil.WriteFile(*filename, data, 0644)
860	}
861	if err != nil {
862		log.Fatal(err)
863	}
864}
865
866// TODO: use println instead to print in the following template
867const srcTemplate = `
868
869{{define "main"}}// Code generated by 'go generate'; DO NOT EDIT.
870
871package {{packagename}}
872
873import (
874{{range .StdLibImports}}"{{.}}"
875{{end}}
876
877{{range .ExternalImports}}"{{.}}"
878{{end}}
879)
880
881var _ unsafe.Pointer
882
883// Do the interface allocations only once for common
884// Errno values.
885const (
886	errnoERROR_IO_PENDING = 997
887)
888
889var (
890	errERROR_IO_PENDING error = {{syscalldot}}Errno(errnoERROR_IO_PENDING)
891	errERROR_EINVAL error     = {{syscalldot}}EINVAL
892)
893
894// errnoErr returns common boxed Errno values, to prevent
895// allocations at runtime.
896func errnoErr(e {{syscalldot}}Errno) error {
897	switch e {
898	case 0:
899		return errERROR_EINVAL
900	case errnoERROR_IO_PENDING:
901		return errERROR_IO_PENDING
902	}
903	// TODO: add more here, after collecting data on the common
904	// error values see on Windows. (perhaps when running
905	// all.bat?)
906	return e
907}
908
909var (
910{{template "dlls" .}}
911{{template "funcnames" .}})
912{{range .Funcs}}{{if .HasStringParam}}{{template "helperbody" .}}{{end}}{{template "funcbody" .}}{{end}}
913{{end}}
914
915{{/* help functions */}}
916
917{{define "dlls"}}{{range .DLLs}}	mod{{.}} = {{newlazydll .}}
918{{end}}{{end}}
919
920{{define "funcnames"}}{{range .Funcs}}	proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}")
921{{end}}{{end}}
922
923{{define "helperbody"}}
924func {{.Name}}({{.ParamList}}) {{template "results" .}}{
925{{template "helpertmpvars" .}}	return {{.HelperName}}({{.HelperCallParamList}})
926}
927{{end}}
928
929{{define "funcbody"}}
930func {{.HelperName}}({{.HelperParamList}}) {{template "results" .}}{
931{{template "maybeabsent" .}}	{{template "tmpvars" .}}	{{template "syscall" .}}	{{template "tmpvarsreadback" .}}
932{{template "seterror" .}}{{template "printtrace" .}}	return
933}
934{{end}}
935
936{{define "helpertmpvars"}}{{range .Params}}{{if .TmpVarHelperCode}}	{{.TmpVarHelperCode}}
937{{end}}{{end}}{{end}}
938
939{{define "maybeabsent"}}{{if .MaybeAbsent}}{{.MaybeAbsent}}
940{{end}}{{end}}
941
942{{define "tmpvars"}}{{range .Params}}{{if .TmpVarCode}}	{{.TmpVarCode}}
943{{end}}{{end}}{{end}}
944
945{{define "results"}}{{if .Rets.List}}{{.Rets.List}} {{end}}{{end}}
946
947{{define "syscall"}}{{.Rets.SetReturnValuesCode}}{{.Syscall}}(proc{{.DLLFuncName}}.Addr(), {{.ParamCount}}, {{.SyscallParamList}}){{end}}
948
949{{define "tmpvarsreadback"}}{{range .Params}}{{if .TmpVarReadbackCode}}
950{{.TmpVarReadbackCode}}{{end}}{{end}}{{end}}
951
952{{define "seterror"}}{{if .Rets.SetErrorCode}}	{{.Rets.SetErrorCode}}
953{{end}}{{end}}
954
955{{define "printtrace"}}{{if .PrintTrace}}	print("SYSCALL: {{.Name}}(", {{.ParamPrintList}}") (", {{.Rets.PrintList}}")\n")
956{{end}}{{end}}
957
958`
959