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