Fix "PR c++/92804 ICE trying to use concept as a nested-name-specifier"
[official-gcc.git] / libgo / go / syscall / mksyscall.awk
blob50802d9f521f62c07be75be5828f876e724bd2f8
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
21 # hang.
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.
30 BEGIN {
31 print "// This file was automatically generated by mksyscall.awk"
32 print ""
33 print "package syscall"
34 print ""
35 print "import \"unsafe\""
36 print ""
37 status = 0
40 /^\/\/sys/ {
41 if ($1 == "//sysnb") {
42 blocking = 0
43 } else {
44 blocking = 1
47 line = $0
49 if (match(line, "//sys(nb)?[ ]*[a-zA-Z0-9_]+\\([^()]*\\) *(\\(([^()]+)\\))?") == 0) {
50 print "unmatched line:", $0 | "cat 1>&2"
51 status = 1
52 next
55 # Sets a[1] = //sysnb, a[2] == function name.
56 split(line, a, "[ (]+")
57 gofnname = a[2]
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, "\\([^()]*\\)")
65 if (off == 0) {
66 gofnresults = ""
67 } else {
68 end = index(substr(line, off, length(line) - off + 1), ")")
69 gofnresults = substr(line, off + 1, end - 2)
72 getline
73 line = $0
75 if (match(line, "//[a-zA-Z0-9_]+\\([^()]*\\)") == 0) {
76 print "unmatched C line", $0, "after", gofnname | "cat 1>&2"
77 status = 1
78 next
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, " ")
93 if (end != 0) {
94 line = substr(line, 1, end)
96 cfnresult = line
98 printf("// Automatically generated wrapper for %s/%s\n", gofnname, cfnname)
99 if (!(cfnname in cfns)) {
100 cfns[cfnname] = 1
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 ":"
111 haserr = 0
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") {
117 haserr = 1
118 break
124 split(gofnparams, goargs, ", *")
125 split(cfnparams, cargs, ", *")
126 args = ""
127 carg = 1
128 for (goarg = 1; goargs[goarg] != ""; goarg++) {
129 if (cargs[carg] == "") {
130 print loc, "not enough C parameters"
133 if (args != "") {
134 args = args ", "
137 if (split(goargs[goarg], a) != 2) {
138 print loc, "bad parameter:", goargs[goarg] | "cat 1>&2"
139 status = 1
140 next
143 goname = a[1]
144 gotype = a[2]
146 if (split(cargs[carg], a) != 2) {
147 print loc, "bad C parameter:", cargs[carg] | "cat 1>&2"
148 status = 1
149 next
152 ctype = a[2]
154 if (gotype ~ /^\*/) {
155 if (gotype != ctype) {
156 print loc, "Go/C pointer type mismatch:", gotype, ctype | "cat 1>&2"
157 status = 1
158 next
160 args = args goname
161 } else if (gotype == "string") {
162 if (ctype != "*byte") {
163 print loc, "Go string not matched to C *byte:", gotype, ctype | "cat 1>&2"
164 status = 1
165 next
167 printf("\tvar _p%d *byte\n", goarg)
168 if (haserr) {
169 printf("\t_p%d, err = BytePtrFromString(%s)\n", goarg, goname)
170 printf("\tif err != nil {\n\t\treturn\n\t}\n")
171 } else {
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"
179 status = 1
180 next
183 # Convert a slice into a pair of pointer, length.
184 # Don't try to take the address of the zeroth element of a
185 # nil slice.
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)
191 printf("\t}\n")
193 ++carg
194 if (split(cargs[carg], cparam) != 2) {
195 print loc, "bad C parameter:", cargs[carg] | "cat 1>&2"
196 status = 1
197 next
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)
205 } else {
206 args = sprintf("%s%s(%s)", args, ctype, goname)
209 carg++
212 if (cargs[carg] != "") {
213 print loc, "too many C parameters" | "cat 1>&2"
214 status = 1
215 next
218 if (blocking) {
219 print "\tEntersyscall()"
222 printf("\t")
223 if (gofnresults != "") {
224 printf("_r := ")
226 printf("c_%s(%s)\n", cfnname, args)
228 seterr = 0
229 if (gofnresults != "") {
230 fields = split(gofnresults, goresults, ", *")
231 if (fields > 2) {
232 print loc, "too many Go results" | "cat 1>&2"
233 status = 1
234 next
236 usedr = 0
237 for (goresult = 1; goresults[goresult] != ""; goresult++) {
238 if (split(goresults[goresult], goparam) != 2) {
239 print loc, "bad result:", goresults[goresult] | "cat 1>&2"
240 status = 1
241 next
244 goname = goparam[1]
245 gotype = goparam[2]
247 if (goname == "err") {
248 print "\tvar errno Errno"
249 print "\tsetErrno := false"
250 if (cfnresult ~ /^\*/) {
251 print "\tif _r == nil {"
252 } else {
253 print "\tif _r < 0 {"
255 print "\t\terrno = GetErrno()"
256 print "\t\tsetErrno = true"
257 print "\t}"
258 seterr = 1
259 } else if (gotype == "uintptr" && cfnresult ~ /^\*/) {
260 printf("\t%s = (%s)(unsafe.Pointer(_r))\n", goname, gotype)
261 } else {
262 if (usedr) {
263 print loc, "two parameters but no errno parameter" | "cat 1>&2"
264 status = 1
265 next
267 printf("\t%s = (%s)(_r)\n", goname, gotype)
268 usedr = 1
273 if (blocking) {
274 print "\tExitsyscall()"
277 if (seterr) {
278 print "\tif setErrno {"
279 print "\t\terr = errno"
280 print "\t}"
283 if (gofnresults != "") {
284 print "\treturn"
287 print "}"
289 print ""
291 next
294 { next }
296 END {
297 if (status != 0) {
298 print "*** mksyscall.awk failed" | "cat 1>&2"
299 exit status