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