123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301 |
- # Copyright 2011 The Go Authors. All rights reserved.
- # Use of this source code is governed by a BSD-style
- # license that can be found in the LICENSE file.
- # This AWK script reads a Go file with comments describing syscall
- # functions and the C routines they map to. It generates the Go code
- # which calls the C routines.
- # The syscall functins are marked by lines beginning with "//sys" and
- # read like func declarations if //sys is replaced by func, but:
- # * The parameter lists must give a name for each argument.
- # This includes return parameters.
- # * The parameter lists must give a type for each argument:
- # the (x, y, z int) shorthand is not allowed.
- # * If the return parameter is an error, it must be named err.
- # A line beginning with //sysnb is like //sys, except that the
- # goroutine will not be suspended during the execution of the library
- # call. This must only be used for library calls which can never
- # block, as otherwise the library call could cause all goroutines to
- # hang.
- # After the //sys or //sysnb line comes a second line which describes
- # the C function. The name must be the name of the function in the C
- # library, and may be the same as the Go function. The limitations on
- # the argument list are the same as for the //sys line, but there must
- # be at most one result parameter, and it must be given as just a
- # type, without a name.
- BEGIN {
- print "// Code generated by mksyscall.awk. DO NOT EDIT."
- print ""
- print "package syscall"
- print ""
- print "import \"unsafe\""
- print ""
- status = 0
- }
- /^\/\/sys/ {
- if ($1 == "//sysnb") {
- blocking = 0
- } else {
- blocking = 1
- }
- line = $0
- if (match(line, "//sys(nb)?[ ]*[a-zA-Z0-9_]+\\([^()]*\\) *(\\(([^()]+)\\))?") == 0) {
- print "unmatched line:", $0 | "cat 1>&2"
- status = 1
- next
- }
- # Sets a[1] = //sysnb, a[2] == function name.
- split(line, a, "[ (]+")
- gofnname = a[2]
- off = match(line, "\\([^()]*\\)")
- end = index(substr(line, off, length(line) - off + 1), ")")
- gofnparams = substr(line, off + 1, end - 2)
- line = substr(line, off + end, length(line) - (off + end) + 1)
- off = match(line, "\\([^()]*\\)")
- if (off == 0) {
- gofnresults = ""
- } else {
- end = index(substr(line, off, length(line) - off + 1), ")")
- gofnresults = substr(line, off + 1, end - 2)
- }
- getline
- line = $0
- if (match(line, "//[a-zA-Z0-9_]+\\([^()]*\\)") == 0) {
- print "unmatched C line", $0, "after", gofnname | "cat 1>&2"
- status = 1
- next
- }
- split(line, a, "[ (]+")
- cfnname = substr(a[1], 3, length(a[1]) - 2)
- off = match(line, "\\([^()]*\\)")
- end = index(substr(line, off, length(line) - off + 1), ")")
- cfnparams = substr(line, off + 1, end - 2)
- line = substr(line, off + end + 1, length(line) - (off + end) + 1)
- while (substr(line, 1, 1) == " ") {
- line = substr(line, 2, length(line) - 1)
- }
- end = index(line, " ")
- if (end != 0) {
- line = substr(line, 1, end)
- }
- cfnresult = line
- printf("// Automatically generated wrapper for %s/%s\n", gofnname, cfnname)
- if (!(cfnname in cfns)) {
- cfns[cfnname] = 1
- printf("//go:noescape\n")
- printf("//extern-sysinfo %s\n", cfnname)
- printf("func c_%s(%s) %s\n", cfnname, cfnparams, cfnresult)
- }
- printf("func %s(%s) %s%s%s%s{\n",
- gofnname, gofnparams, gofnresults == "" ? "" : "(", gofnresults,
- gofnresults == "" ? "" : ")", gofnresults == "" ? "" : " ")
- loc = gofnname "/" cfnname ":"
- haserr = 0
- if (gofnresults != "") {
- fields = split(gofnresults, goresults, ", *")
- for (goresult = 1; goresults[goresult] != ""; goresult++) {
- if (split(goresults[goresult], goparam) == 2) {
- if (goparam[1] == "err") {
- haserr = 1
- break
- }
- }
- }
- }
- split(gofnparams, goargs, ", *")
- split(cfnparams, cargs, ", *")
- args = ""
- carg = 1
- for (goarg = 1; goargs[goarg] != ""; goarg++) {
- if (cargs[carg] == "") {
- print loc, "not enough C parameters"
- }
- if (args != "") {
- args = args ", "
- }
- if (split(goargs[goarg], a) != 2) {
- print loc, "bad parameter:", goargs[goarg] | "cat 1>&2"
- status = 1
- next
- }
- goname = a[1]
- gotype = a[2]
- if (split(cargs[carg], a) != 2) {
- print loc, "bad C parameter:", cargs[carg] | "cat 1>&2"
- status = 1
- next
- }
- ctype = a[2]
- if (gotype ~ /^\*/) {
- if (gotype != ctype) {
- print loc, "Go/C pointer type mismatch:", gotype, ctype | "cat 1>&2"
- status = 1
- next
- }
- args = args goname
- } else if (gotype == "string") {
- if (ctype != "*byte") {
- print loc, "Go string not matched to C *byte:", gotype, ctype | "cat 1>&2"
- status = 1
- next
- }
- printf("\tvar _p%d *byte\n", goarg)
- if (haserr) {
- printf("\t_p%d, err = BytePtrFromString(%s)\n", goarg, goname)
- printf("\tif err != nil {\n\t\treturn\n\t}\n")
- } else {
- print loc, "uses string arguments but has no error return" | "cat 1>&2"
- printf("\t_p%d, _ = BytePtrFromString(%s)\n", goarg, goname)
- }
- args = sprintf("%s_p%d", args, goarg)
- } else if (gotype ~ /^\[\](.*)/) {
- if (ctype !~ /^\*/ || cargs[carg + 1] == "") {
- print loc, "bad C type for slice:", gotype, ctype | "cat 1>&2"
- status = 1
- next
- }
- # Convert a slice into a pair of pointer, length.
- # Don't try to take the address of the zeroth element of a
- # nil slice.
- printf("\tvar _p%d %s\n", goarg, ctype)
- printf("\tif len(%s) > 0 {\n", goname)
- printf("\t\t_p%d = (%s)(unsafe.Pointer(&%s[0]))\n", goarg, ctype, goname)
- printf("\t} else {\n")
- printf("\t\t_p%d = (%s)(unsafe.Pointer(&_zero))\n", goarg, ctype)
- printf("\t}\n")
- ++carg
- if (split(cargs[carg], cparam) != 2) {
- print loc, "bad C parameter:", cargs[carg] | "cat 1>&2"
- status = 1
- next
- }
- args = sprintf("%s_p%d, %s(len(%s))", args, goarg, cparam[2], goname)
- } else if (gotype == "uintptr" && ctype ~ /^\*/) {
- args = sprintf("%s(%s)(unsafe.Pointer(%s))", args, ctype, goname)
- } else if (gotype == "unsafe.Pointer" && ctype ~ /^\*/) {
- args = sprintf("%s(%s)(%s)", args, ctype, goname)
- } else {
- args = sprintf("%s%s(%s)", args, ctype, goname)
- }
- carg++
- }
- if (cargs[carg] != "") {
- print loc, "too many C parameters" | "cat 1>&2"
- status = 1
- next
- }
- if (blocking) {
- print "\tEntersyscall()"
- }
- printf("\t")
- if (gofnresults != "") {
- printf("_r := ")
- }
- printf("c_%s(%s)\n", cfnname, args)
- seterr = 0
- if (gofnresults != "") {
- fields = split(gofnresults, goresults, ", *")
- if (fields > 2) {
- print loc, "too many Go results" | "cat 1>&2"
- status = 1
- next
- }
- usedr = 0
- for (goresult = 1; goresults[goresult] != ""; goresult++) {
- if (split(goresults[goresult], goparam) != 2) {
- print loc, "bad result:", goresults[goresult] | "cat 1>&2"
- status = 1
- next
- }
- goname = goparam[1]
- gotype = goparam[2]
- if (goname == "err") {
- print "\tvar errno Errno"
- print "\tsetErrno := false"
- if (cfnresult ~ /^\*/) {
- print "\tif _r == nil {"
- } else {
- print "\tif _r < 0 {"
- }
- print "\t\terrno = GetErrno()"
- print "\t\tsetErrno = true"
- print "\t}"
- seterr = 1
- } else if (gotype == "uintptr" && cfnresult ~ /^\*/) {
- printf("\t%s = (%s)(unsafe.Pointer(_r))\n", goname, gotype)
- } else {
- if (usedr) {
- print loc, "two parameters but no errno parameter" | "cat 1>&2"
- status = 1
- next
- }
- printf("\t%s = (%s)(_r)\n", goname, gotype)
- usedr = 1
- }
- }
- }
- if (blocking) {
- print "\tExitsyscall()"
- }
- if (seterr) {
- print "\tif setErrno {"
- print "\t\terr = errno"
- print "\t}"
- }
- if (gofnresults != "") {
- print "\treturn"
- }
- print "}"
- print ""
- next
- }
- { next }
- END {
- if (status != 0) {
- print "*** mksyscall.awk failed" | "cat 1>&2"
- exit status
- }
- }
|