1 # Copyright 2011 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.
5 # This AWK script reads a Go file with comments describing syscall
6 # functions and the C routines they map to. It generates the Go code
7 # which calls the C routines.
9 # The syscall functins are marked by lines beginning with "//sys" and
10 # read like func declarations if //sys is replaced by func, but:
11 # * The parameter lists must give a name for each argument.
12 # This includes return parameters.
13 # * The parameter lists must give a type for each argument:
14 # the (x, y, z int) shorthand is not allowed.
15 # * If the return parameter is an error, it must be named err.
17 # A line beginning with //sysnb is like //sys, except that the
18 # goroutine will not be suspended during the execution of the library
19 # call. This must only be used for library calls which can never
20 # block, as otherwise the library call could cause all goroutines to
23 # After the //sys or //sysnb line comes a second line which describes
24 # the C function. The name must be the name of the function in the C
25 # library, and may be the same as the Go function. The limitations on
26 # the argument list are the same as for the //sys line, but there must
27 # be at most one result parameter, and it must be given as just a
28 # type, without a name.
31 print "// This file was automatically generated by mksyscall.awk"
33 print "package syscall"
35 print "import \"unsafe\""
41 if ($
1 ==
"//sysnb") {
49 if (match(line
, "//sys(nb)?[ ]*[a-zA-Z0-9_]+\\([^()]*\\) *(\\(([^()]+)\\))?") ==
0) {
50 print "unmatched line:", $
0 | "cat 1>&2"
55 # Sets a[1] = //sysnb, a[2] == function name.
56 split(line
, a
, "[ (]+")
59 off =
match(line
, "\\([^()]*\\)")
60 end =
index(substr(line
, off
, length(line
) - off
+ 1), ")")
61 gofnparams =
substr(line
, off
+ 1, end - 2)
63 line =
substr(line
, off
+ end, length(line
) - (off
+ end) + 1)
64 off =
match(line
, "\\([^()]*\\)")
68 end =
index(substr(line
, off
, length(line
) - off
+ 1), ")")
69 gofnresults =
substr(line
, off
+ 1, end - 2)
75 if (match(line
, "//[a-zA-Z0-9_]+\\([^()]*\\)") ==
0) {
76 print "unmatched C line", $
0, "after", gofnname
| "cat 1>&2"
81 split(line
, a
, "[ (]+")
82 cfnname =
substr(a
[1], 3, length(a
[1]) - 2)
84 off =
match(line
, "\\([^()]*\\)")
85 end =
index(substr(line
, off
, length(line
) - off
+ 1), ")")
86 cfnparams =
substr(line
, off
+ 1, end - 2)
88 line =
substr(line
, off
+ end + 1, length(line
) - (off
+ end) + 1)
89 while (substr(line
, 1, 1) ==
" ") {
90 line =
substr(line
, 2, length(line
) - 1)
92 end =
index(line
, " ")
94 line =
substr(line
, 1, end)
98 printf("// Automatically generated wrapper for %s/%s\n", gofnname
, cfnname
)
99 if (!
(cfnname in cfns
)) {
101 printf("//go:noescape\n")
102 printf("//extern %s\n", cfnname
)
103 printf("func c_%s(%s) %s\n", cfnname
, cfnparams
, cfnresult
)
105 printf("func %s(%s) %s%s%s%s{\n",
106 gofnname
, gofnparams
, gofnresults ==
"" ?
"" : "(", gofnresults
,
107 gofnresults ==
"" ?
"" : ")", gofnresults ==
"" ?
"" : " ")
109 loc = gofnname
"/" cfnname
":"
112 if (gofnresults
!= "") {
113 fields =
split(gofnresults
, goresults
, ", *")
114 for (goresult =
1; goresults
[goresult
] != ""; goresult
++) {
115 if (split(goresults
[goresult
], goparam
) ==
2) {
116 if (goparam
[1] ==
"err") {
124 split(gofnparams
, goargs
, ", *")
125 split(cfnparams
, cargs
, ", *")
128 for (goarg =
1; goargs
[goarg
] != ""; goarg
++) {
129 if (cargs
[carg
] ==
"") {
130 print loc
, "not enough C parameters"
137 if (split(goargs
[goarg
], a
) != 2) {
138 print loc
, "bad parameter:", goargs
[goarg
] | "cat 1>&2"
146 if (split(cargs
[carg
], a
) != 2) {
147 print loc
, "bad C parameter:", cargs
[carg
] | "cat 1>&2"
154 if (gotype ~
/^\
*/) {
155 if (gotype
!= ctype
) {
156 print loc
, "Go/C pointer type mismatch:", gotype
, ctype
| "cat 1>&2"
161 } else if (gotype ==
"string") {
162 if (ctype
!= "*byte") {
163 print loc
, "Go string not matched to C *byte:", gotype
, ctype
| "cat 1>&2"
167 printf("\tvar _p%d *byte\n", goarg
)
169 printf("\t_p%d, err = BytePtrFromString(%s)\n", goarg
, goname
)
170 printf("\tif err != nil {\n\t\treturn\n\t}\n")
172 print loc
, "uses string arguments but has no error return" | "cat 1>&2"
173 printf("\t_p%d, _ = BytePtrFromString(%s)\n", goarg
, goname
)
175 args =
sprintf("%s_p%d", args
, goarg
)
176 } else if (gotype ~
/^\
[\
](.
*)/) {
177 if (ctype !~
/^\
*/ || cargs
[carg
+ 1] ==
"") {
178 print loc
, "bad C type for slice:", gotype
, ctype
| "cat 1>&2"
183 # Convert a slice into a pair of pointer, length.
184 # Don't try to take the address of the zeroth element of a
186 printf("\tvar _p%d %s\n", goarg
, ctype
)
187 printf("\tif len(%s) > 0 {\n", goname
)
188 printf("\t\t_p%d = (%s)(unsafe.Pointer(&%s[0]))\n", goarg
, ctype
, goname
)
189 printf("\t} else {\n")
190 printf("\t\t_p%d = (%s)(unsafe.Pointer(&_zero))\n", goarg
, ctype
)
194 if (split(cargs
[carg
], cparam
) != 2) {
195 print loc
, "bad C parameter:", cargs
[carg
] | "cat 1>&2"
200 args =
sprintf("%s_p%d, %s(len(%s))", args
, goarg
, cparam
[2], goname
)
201 } else if (gotype ==
"uintptr" && ctype ~
/^\
*/) {
202 args =
sprintf("%s(%s)(unsafe.Pointer(%s))", args
, ctype
, goname
)
203 } else if (gotype ==
"unsafe.Pointer" && ctype ~
/^\
*/) {
204 args =
sprintf("%s(%s)(%s)", args
, ctype
, goname
)
206 args =
sprintf("%s%s(%s)", args
, ctype
, goname
)
212 if (cargs
[carg
] != "") {
213 print loc
, "too many C parameters" | "cat 1>&2"
219 print "\tEntersyscall()"
223 if (gofnresults
!= "") {
226 printf("c_%s(%s)\n", cfnname
, args
)
229 if (gofnresults
!= "") {
230 fields =
split(gofnresults
, goresults
, ", *")
232 print loc
, "too many Go results" | "cat 1>&2"
237 for (goresult =
1; goresults
[goresult
] != ""; goresult
++) {
238 if (split(goresults
[goresult
], goparam
) != 2) {
239 print loc
, "bad result:", goresults
[goresult
] | "cat 1>&2"
247 if (goname ==
"err") {
248 print "\tvar errno Errno"
249 print "\tsetErrno := false"
250 if (cfnresult ~
/^\
*/) {
251 print "\tif _r == nil {"
253 print "\tif _r < 0 {"
255 print "\t\terrno = GetErrno()"
256 print "\t\tsetErrno = true"
259 } else if (gotype ==
"uintptr" && cfnresult ~
/^\
*/) {
260 printf("\t%s = (%s)(unsafe.Pointer(_r))\n", goname
, gotype
)
263 print loc
, "two parameters but no errno parameter" | "cat 1>&2"
267 printf("\t%s = (%s)(_r)\n", goname
, gotype
)
274 print "\tExitsyscall()"
278 print "\tif setErrno {"
279 print "\t\terr = errno"
283 if (gofnresults
!= "") {
298 print "*** mksyscall.awk failed" | "cat 1>&2"