github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libgo/go/syscall/mksyscall.awk (about)

     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      if (!(cfnname in cfns)) {
   100          cfns[cfnname] = 1
   101          printf("//extern %s\n", cfnname)
   102          printf("func c_%s(%s) %s\n", cfnname, cfnparams, cfnresult)
   103      }
   104      printf("func %s(%s) %s%s%s%s{\n",
   105  	   gofnname, gofnparams, gofnresults == "" ? "" : "(", gofnresults,
   106  	   gofnresults == "" ? "" : ")", gofnresults == "" ? "" : " ")
   107  
   108      loc = gofnname "/" cfnname ":"
   109  
   110      haserr = 0
   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") {
   116  		    haserr = 1
   117  		    break
   118  		}
   119  	    }
   120  	}
   121      }
   122  
   123      split(gofnparams, goargs, ", *")
   124      split(cfnparams, cargs, ", *")
   125      args = ""
   126      carg = 1
   127      for (goarg = 1; goargs[goarg] != ""; goarg++) {
   128  	if (cargs[carg] == "") {
   129  	    print loc, "not enough C parameters"
   130  	}
   131  
   132  	if (args != "") {
   133  	    args = args ", "
   134  	}
   135  
   136  	if (split(goargs[goarg], a) != 2) {
   137  	    print loc, "bad parameter:", goargs[goarg] | "cat 1>&2"
   138  	    status = 1
   139  	    next
   140  	}
   141  
   142  	goname = a[1]
   143  	gotype = a[2]
   144  
   145  	if (split(cargs[carg], a) != 2) {
   146  	    print loc, "bad C parameter:", cargs[carg] | "cat 1>&2"
   147  	    status = 1
   148  	    next
   149  	}
   150  
   151  	ctype = a[2]
   152  
   153  	if (gotype ~ /^\*/) {
   154  	    if (gotype != ctype) {
   155  		print loc, "Go/C pointer type mismatch:", gotype, ctype | "cat 1>&2"
   156  		status = 1
   157  		next
   158  	    }
   159  	    args = args goname
   160  	} else if (gotype == "string") {
   161  	    if (ctype != "*byte") {
   162  		print loc, "Go string not matched to C *byte:", gotype, ctype | "cat 1>&2"
   163  		status = 1
   164  		next
   165  	    }
   166  	    printf("\tvar _p%d *byte\n", goarg)
   167  	    if (haserr) {
   168  		printf("\t_p%d, err = BytePtrFromString(%s)\n", goarg, goname)
   169  		printf("\tif err != nil {\n\t\treturn\n\t}\n")
   170  	    } else {
   171  		print loc, "uses string arguments but has no error return" | "cat 1>&2"
   172  		printf("\t_p%d, _ = BytePtrFromString(%s)\n", goarg, goname)
   173  	    }
   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"
   178  		status = 1
   179  		next
   180  	    }
   181  
   182  	    # Convert a slice into a pair of pointer, length.
   183  	    # Don't try to take the address of the zeroth element of a
   184  	    # nil slice.
   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)
   190  	    printf("\t}\n")
   191  
   192  	    ++carg
   193  	    if (split(cargs[carg], cparam) != 2) {
   194  		print loc, "bad C parameter:", cargs[carg] | "cat 1>&2"
   195  		status = 1
   196  		next
   197  	    }
   198  
   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)
   204  	} else {
   205  	    args = sprintf("%s%s(%s)", args, ctype, goname)
   206  	}
   207  
   208  	carg++
   209      }
   210  
   211      if (cargs[carg] != "") {
   212  	print loc, "too many C parameters" | "cat 1>&2"
   213  	status = 1
   214  	next
   215      }
   216  
   217      if (blocking) {
   218  	print "\tEntersyscall()"
   219      }
   220  
   221      printf("\t")
   222      if (gofnresults != "") {
   223  	printf("_r := ")
   224      }
   225      printf("c_%s(%s)\n", cfnname, args)
   226  
   227      seterr = 0
   228      if (gofnresults != "") {
   229  	fields = split(gofnresults, goresults, ", *")
   230  	if (fields > 2) {
   231  	    print loc, "too many Go results" | "cat 1>&2"
   232  	    status = 1
   233  	    next
   234  	}
   235  	usedr = 0
   236  	for (goresult = 1; goresults[goresult] != ""; goresult++) {
   237  	    if (split(goresults[goresult], goparam) != 2) {
   238  		print loc, "bad result:", goresults[goresult] | "cat 1>&2"
   239  		status = 1
   240  		next
   241  	    }
   242  
   243  	    goname = goparam[1]
   244  	    gotype = goparam[2]
   245  
   246  	    if (goname == "err") {
   247  		print "\tvar errno Errno"
   248  		print "\tsetErrno := false"
   249  		if (cfnresult ~ /^\*/) {
   250  		    print "\tif _r == nil {"
   251  		} else {
   252  		    print "\tif _r < 0 {"
   253  		}
   254  		print "\t\terrno = GetErrno()"
   255  		print "\t\tsetErrno = true"
   256  		print "\t}"
   257  		seterr = 1
   258  	    } else if (gotype == "uintptr" && cfnresult ~ /^\*/) {
   259  		printf("\t%s = (%s)(unsafe.Pointer(_r))\n", goname, gotype)
   260  	    } else {
   261  		if (usedr) {
   262  		    print loc, "two parameters but no errno parameter" | "cat 1>&2"
   263  		    status = 1
   264  		    next
   265  		}
   266  		printf("\t%s = (%s)(_r)\n", goname, gotype)
   267  		usedr = 1
   268  	    }
   269  	}
   270      }
   271  
   272      if (blocking) {
   273  	print "\tExitsyscall()"
   274      }
   275  
   276      if (seterr) {
   277  	print "\tif setErrno {"
   278  	print "\t\terr = errno"
   279  	print "\t}"
   280      }
   281  
   282      if (gofnresults != "") {
   283  	print "\treturn"
   284      }
   285  
   286      print "}"
   287  
   288      print ""
   289  
   290      next
   291  }
   292  
   293  { next }
   294  
   295  END {
   296      if (status != 0) {
   297  	print "*** mksyscall.awk failed" | "cat 1>&2"
   298  	exit status
   299      }
   300  }