OSDN Git Service

libgo: Export {enter,exit}syscall and use it for getaddrinfo.
[pf3gnuchains/gcc-fork.git] / libgo / go / syscall / mksyscall.awk
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.
4
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.
8
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.
16
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.
22
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.
29
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
38 }
39
40 /^\/\/sys/ {
41     if ($1 == "//sysnb") {
42         blocking = 0
43     } else {
44         blocking = 1
45     }
46
47     line = $0
48
49     if (match(line, "//sys(nb)?[        ]*[a-zA-Z0-9_]+\\([^()]*\\) *(\\(([^()]+)\\))?") == 0) {
50         print "unmatched line:", $0 | "cat 1>&2"
51         status = 1
52         next
53     }
54
55     # Sets a[1] = //sysnb, a[2] == function name.
56     split(line, a, "[   (]*")
57     gofnname = a[2]
58
59     off = match(line, "\\([^()]*\\)")
60     end = index(substr(line, off, length(line) - off + 1), ")")
61     gofnparams = substr(line, off + 1, end - 2)
62
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)
70     }
71
72     getline
73     line = $0
74
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
79     }
80
81     split(line, a, "[   (]*")
82     cfnname = substr(a[1], 3, length(a[1]) - 2)
83
84     off = match(line, "\\([^()]*\\)")
85     end = index(substr(line, off, length(line) - off + 1), ")")
86     cfnparams = substr(line, off + 1, end - 2)
87
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)
91     }
92     end = index(line, " ")
93     if (end != 0) {
94         line = substr(line, 1, end)
95     }
96     cfnresult = line
97
98     printf("// Automatically generated wrapper for %s/%s\n", gofnname, cfnname)
99     printf("//extern %s\n", cfnname)
100     printf("func c_%s(%s) %s\n", cfnname, cfnparams, cfnresult)
101     printf("func %s(%s) %s%s%s%s{\n",
102            gofnname, gofnparams, gofnresults == "" ? "" : "(", gofnresults,
103            gofnresults == "" ? "" : ")", gofnresults == "" ? "" : " ")
104
105     loc = gofnname "/" cfnname ":"
106
107     split(gofnparams, goargs, ", *")
108     split(cfnparams, cargs, ", *")
109     args = ""
110     carg = 1
111     for (goarg = 1; goargs[goarg] != ""; goarg++) {
112         if (cargs[carg] == "") {
113             print loc, "not enough C parameters"
114         }
115
116         if (args != "") {
117             args = args ", "
118         }
119
120         if (split(goargs[goarg], a) != 2) {
121             print loc, "bad parameter:", goargs[goarg] | "cat 1>&2"
122             status = 1
123             next
124         }
125
126         goname = a[1]
127         gotype = a[2]
128
129         if (split(cargs[carg], a) != 2) {
130             print loc, "bad C parameter:", cargs[carg] | "cat 1>&2"
131             status = 1
132             next
133         }
134
135         ctype = a[2]
136
137         if (gotype ~ /^\*/) {
138             if (gotype != ctype) {
139                 print loc, "Go/C pointer type mismatch:", gotype, ctype | "cat 1>&2"
140                 status = 1
141                 next
142             }
143             args = args goname
144         } else if (gotype == "string") {
145             if (ctype != "*byte") {
146                 print loc, "Go string not matched to C *byte:", gotype, ctype | "cat 1>&2"
147                 status = 1
148                 next
149             }
150             printf("\t_p%d := StringBytePtr(%s)\n", goarg, goname)
151             args = sprintf("%s_p%d", args, goarg)
152         } else if (gotype ~ /^\[\](.*)/) {
153             if (ctype !~ /^\*/ || cargs[carg + 1] == "") {
154                 print loc, "bad C type for slice:", gotype, ctype | "cat 1>&2"
155                 status = 1
156                 next
157             }
158
159             # Convert a slice into a pair of pointer, length.
160             # Don't try to take the address of the zeroth element of a
161             # nil slice.
162             printf("\tvar _p%d %s\n", goarg, ctype)
163             printf("\tif len(%s) > 0 {\n", goname)
164             printf("\t\t_p%d = (%s)(unsafe.Pointer(&%s[0]))\n", goarg, ctype, goname)
165             printf("\t} else {\n")
166             printf("\t\t_p%d = (%s)(unsafe.Pointer(&_zero))\n", goarg, ctype)
167             printf("\t}\n")
168
169             ++carg
170             if (split(cargs[carg], cparam) != 2) {
171                 print loc, "bad C parameter:", cargs[carg] | "cat 1>&2"
172                 status = 1
173                 next
174             }
175
176             args = sprintf("%s_p%d, %s(len(%s))", args, goarg, cparam[2], goname)
177         } else if (gotype == "uintptr" && ctype ~ /^\*/) {
178             args = sprintf("%s(%s)(unsafe.Pointer(%s))", args, ctype, goname)
179         } else {
180             args = sprintf("%s%s(%s)", args, ctype, goname)
181         }
182
183         carg++
184     }
185
186     if (cargs[carg] != "") {
187         print loc, "too many C parameters" | "cat 1>&2"
188         status = 1
189         next
190     }
191
192     if (blocking) {
193         print "\tEntersyscall()"
194     }
195
196     printf("\t")
197     if (gofnresults != "") {
198         printf("_r := ")
199     }
200     printf("c_%s(%s)\n", cfnname, args)
201
202     if (gofnresults != "") {
203         fields = split(gofnresults, goresults, ", *")
204         if (fields > 2) {
205             print loc, "too many Go results" | "cat 1>&2"
206             status = 1
207             next
208         }
209         usedr = 0
210         for (goresult = 1; goresults[goresult] != ""; goresult++) {
211             if (split(goresults[goresult], goparam) != 2) {
212                 print loc, "bad result:", goresults[goresult] | "cat 1>&2"
213                 status = 1
214                 next
215             }
216
217             goname = goparam[1]
218             gotype = goparam[2]
219
220             if (goname == "err") {
221                 if (cfnresult ~ /^\*/) {
222                     print "\tif _r == nil {"
223                 } else {
224                     print "\tif _r < 0 {"
225                 }
226                 print "\t\terr = GetErrno()"
227                 print "\t}"
228             } else if (gotype == "uintptr" && cfnresult ~ /^\*/) {
229                 printf("\t%s = (%s)(unsafe.Pointer(_r))\n", goname, gotype)
230             } else {
231                 if (usedr) {
232                     print loc, "two parameters but no errno parameter" | "cat 1>&2"
233                     status = 1
234                     next
235                 }
236                 printf("\t%s = (%s)(_r)\n", goname, gotype)
237                 usedr = 1
238             }
239         }
240     }
241
242     if (blocking) {
243         print "\tExitsyscall()"
244     }
245
246     if (gofnresults != "") {
247         print "\treturn"
248     }
249
250     print "}"
251
252     print ""
253
254     next
255 }
256
257 { next }
258
259 END {
260     if (status != 0) {
261         print "*** mksyscall.awk failed" | "cat 1>&2"
262         exit status
263     }
264 }