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("//extern %s\n", cfnname
)
102 printf("func c_%s(%s) %s\n", cfnname
, cfnparams
, cfnresult
)
104 printf("func %s(%s) %s%s%s%s{\n",
105 gofnname
, gofnparams
, gofnresults ==
"" ?
"" : "(", gofnresults
,
106 gofnresults ==
"" ?
"" : ")", gofnresults ==
"" ?
"" : " ")
108 loc = gofnname
"/" cfnname
":"
111 if (gofnresults
!= "") {
112 fields =
split(gofnresults
, goresults
, ", *")
113 for (goresult =
1; goresults
[goresult
] != ""; goresult
++) {
114 if (split(goresults
[goresult
], goparam
) ==
2) {
115 if (goparam
[1] ==
"err") {
123 split(gofnparams
, goargs
, ", *")
124 split(cfnparams
, cargs
, ", *")
127 for (goarg =
1; goargs
[goarg
] != ""; goarg
++) {
128 if (cargs
[carg
] ==
"") {
129 print loc
, "not enough C parameters"
136 if (split(goargs
[goarg
], a
) != 2) {
137 print loc
, "bad parameter:", goargs
[goarg
] | "cat 1>&2"
145 if (split(cargs
[carg
], a
) != 2) {
146 print loc
, "bad C parameter:", cargs
[carg
] | "cat 1>&2"
153 if (gotype ~
/^\
*/) {
154 if (gotype
!= ctype
) {
155 print loc
, "Go/C pointer type mismatch:", gotype
, ctype
| "cat 1>&2"
160 } else if (gotype ==
"string") {
161 if (ctype
!= "*byte") {
162 print loc
, "Go string not matched to C *byte:", gotype
, ctype
| "cat 1>&2"
166 printf("\tvar _p%d *byte\n", goarg
)
168 printf("\t_p%d, err = BytePtrFromString(%s)\n", goarg
, goname
)
169 printf("\tif err != nil {\n\t\treturn\n\t}\n")
171 print loc
, "uses string arguments but has no error return" | "cat 1>&2"
172 printf("\t_p%d, _ = BytePtrFromString(%s)\n", goarg
, goname
)
174 args =
sprintf("%s_p%d", args
, goarg
)
175 } else if (gotype ~
/^\
[\
](.
*)/) {
176 if (ctype !~
/^\
*/ || cargs
[carg
+ 1] ==
"") {
177 print loc
, "bad C type for slice:", gotype
, ctype
| "cat 1>&2"
182 # Convert a slice into a pair of pointer, length.
183 # Don't try to take the address of the zeroth element of a
185 printf("\tvar _p%d %s\n", goarg
, ctype
)
186 printf("\tif len(%s) > 0 {\n", goname
)
187 printf("\t\t_p%d = (%s)(unsafe.Pointer(&%s[0]))\n", goarg
, ctype
, goname
)
188 printf("\t} else {\n")
189 printf("\t\t_p%d = (%s)(unsafe.Pointer(&_zero))\n", goarg
, ctype
)
193 if (split(cargs
[carg
], cparam
) != 2) {
194 print loc
, "bad C parameter:", cargs
[carg
] | "cat 1>&2"
199 args =
sprintf("%s_p%d, %s(len(%s))", args
, goarg
, cparam
[2], goname
)
200 } else if (gotype ==
"uintptr" && ctype ~
/^\
*/) {
201 args =
sprintf("%s(%s)(unsafe.Pointer(%s))", args
, ctype
, goname
)
202 } else if (gotype ==
"unsafe.Pointer" && ctype ~
/^\
*/) {
203 args =
sprintf("%s(%s)(%s)", args
, ctype
, goname
)
205 args =
sprintf("%s%s(%s)", args
, ctype
, goname
)
211 if (cargs
[carg
] != "") {
212 print loc
, "too many C parameters" | "cat 1>&2"
218 print "\tEntersyscall()"
222 if (gofnresults
!= "") {
225 printf("c_%s(%s)\n", cfnname
, args
)
228 if (gofnresults
!= "") {
229 fields =
split(gofnresults
, goresults
, ", *")
231 print loc
, "too many Go results" | "cat 1>&2"
236 for (goresult =
1; goresults
[goresult
] != ""; goresult
++) {
237 if (split(goresults
[goresult
], goparam
) != 2) {
238 print loc
, "bad result:", goresults
[goresult
] | "cat 1>&2"
246 if (goname ==
"err") {
247 print "\tvar errno Errno"
248 print "\tsetErrno := false"
249 if (cfnresult ~
/^\
*/) {
250 print "\tif _r == nil {"
252 print "\tif _r < 0 {"
254 print "\t\terrno = GetErrno()"
255 print "\t\tsetErrno = true"
258 } else if (gotype ==
"uintptr" && cfnresult ~
/^\
*/) {
259 printf("\t%s = (%s)(unsafe.Pointer(_r))\n", goname
, gotype
)
262 print loc
, "two parameters but no errno parameter" | "cat 1>&2"
266 printf("\t%s = (%s)(_r)\n", goname
, gotype
)
273 print "\tExitsyscall()"
277 print "\tif setErrno {"
278 print "\t\terr = errno"
282 if (gofnresults
!= "") {
297 print "*** mksyscall.awk failed" | "cat 1>&2"