windows/mkwinsyscall: account for non-"err" return values when processing "?"

The "?" code assumed that the error value was always called "err", when
in reality it might be called something different (like "ret") or even
entirely absent. This commit makes the templating robust to that. At the
same time, we move a lot of the complexity out of the actual templates
and into helper functions, so that this remains easy to read.

Change-Id: I939d56413a24f0e3e1bbf13da5adf13e9401747a
Reviewed-on: https://go-review.googlesource.com/c/sys/+/275472
Trust: Jason A. Donenfeld <Jason@zx2c4.com>
Trust: Alex Brainman <alex.brainman@gmail.com>
Run-TryBot: Jason A. Donenfeld <Jason@zx2c4.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
diff --git a/windows/mkwinsyscall/mkwinsyscall.go b/windows/mkwinsyscall/mkwinsyscall.go
index 0f2f645..22f844e 100644
--- a/windows/mkwinsyscall/mkwinsyscall.go
+++ b/windows/mkwinsyscall/mkwinsyscall.go
@@ -239,10 +239,11 @@
 
 // Rets describes function return parameters.
 type Rets struct {
-	Name         string
-	Type         string
-	ReturnsError bool
-	FailCond     string
+	Name          string
+	Type          string
+	ReturnsError  bool
+	FailCond      string
+	fnMaybeAbsent bool
 }
 
 // ErrorVarName returns error variable name for r.
@@ -273,6 +274,8 @@
 	s := join(r.ToParams(), func(p *Param) string { return p.Name + " " + p.Type }, ", ")
 	if len(s) > 0 {
 		s = "(" + s + ")"
+	} else if r.fnMaybeAbsent {
+		s = "(err error)"
 	}
 	return s
 }
@@ -345,7 +348,6 @@
 	Params      []*Param
 	Rets        *Rets
 	PrintTrace  bool
-	MaybeAbsent bool
 	dllname     string
 	dllfuncname string
 	src         string
@@ -475,7 +477,7 @@
 	}
 	if n := f.dllfuncname; strings.HasSuffix(n, "?") {
 		f.dllfuncname = n[:len(n)-1]
-		f.MaybeAbsent = true
+		f.Rets.fnMaybeAbsent = true
 	}
 	return f, nil
 }
@@ -575,6 +577,22 @@
 	return strings.Join(a, ", ")
 }
 
+// MaybeAbsent returns source code for handling functions that are possibly unavailable.
+func (p *Fn) MaybeAbsent() string {
+	if !p.Rets.fnMaybeAbsent {
+		return ""
+	}
+	const code = `%[1]s = proc%[2]s.Find()
+	if %[1]s != nil {
+		return
+	}`
+	errorVar := p.Rets.ErrorVarName()
+	if errorVar == "" {
+		errorVar = "err"
+	}
+	return fmt.Sprintf(code, errorVar, p.DLLFuncName())
+}
+
 // IsUTF16 is true, if f is W (utf16) function. It is false
 // for all A (ascii) functions.
 func (f *Fn) IsUTF16() bool {
@@ -915,8 +933,7 @@
 {{define "helpertmpvars"}}{{range .Params}}{{if .TmpVarHelperCode}}	{{.TmpVarHelperCode}}
 {{end}}{{end}}{{end}}
 
-{{define "maybeabsent"}}{{if .MaybeAbsent}}err = proc{{.DLLFuncName}}.Find()
-if err != nil { return }
+{{define "maybeabsent"}}{{if .MaybeAbsent}}{{.MaybeAbsent}}
 {{end}}{{end}}
 
 {{define "tmpvars"}}{{range .Params}}{{if .TmpVarCode}}	{{.TmpVarCode}}