github.com/Kalvelign/golang-windows-sys-lib@v0.0.0-20221121121202-63da651435e1/unix/mksysnum.go (about)

     1  // Copyright 2018 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  //go:build ignore
     6  // +build ignore
     7  
     8  // Generate system call table for DragonFly, NetBSD,
     9  // FreeBSD or OpenBSD from master list (for example,
    10  // /usr/src/sys/kern/syscalls.master or sys/syscall.h).
    11  package main
    12  
    13  import (
    14  	"bufio"
    15  	"fmt"
    16  	"io"
    17  	"io/ioutil"
    18  	"net/http"
    19  	"os"
    20  	"regexp"
    21  	"strings"
    22  )
    23  
    24  var (
    25  	goos, goarch string
    26  )
    27  
    28  // cmdLine returns this programs's commandline arguments
    29  func cmdLine() string {
    30  	return "go run mksysnum.go " + strings.Join(os.Args[1:], " ")
    31  }
    32  
    33  // goBuildTags returns build tags in the go:build format.
    34  func goBuildTags() string {
    35  	return fmt.Sprintf("%s && %s", goarch, goos)
    36  }
    37  
    38  // plusBuildTags returns build tags in the +build format.
    39  func plusBuildTags() string {
    40  	return fmt.Sprintf("%s,%s", goarch, goos)
    41  }
    42  
    43  func checkErr(err error) {
    44  	if err != nil {
    45  		fmt.Fprintf(os.Stderr, "%v\n", err)
    46  		os.Exit(1)
    47  	}
    48  }
    49  
    50  // source string and substring slice for regexp
    51  type re struct {
    52  	str string   // source string
    53  	sub []string // matched sub-string
    54  }
    55  
    56  // Match performs regular expression match
    57  func (r *re) Match(exp string) bool {
    58  	r.sub = regexp.MustCompile(exp).FindStringSubmatch(r.str)
    59  	if r.sub != nil {
    60  		return true
    61  	}
    62  	return false
    63  }
    64  
    65  // fetchFile fetches a text file from URL
    66  func fetchFile(URL string) io.Reader {
    67  	resp, err := http.Get(URL)
    68  	checkErr(err)
    69  	defer resp.Body.Close()
    70  	body, err := ioutil.ReadAll(resp.Body)
    71  	checkErr(err)
    72  	return strings.NewReader(string(body))
    73  }
    74  
    75  // readFile reads a text file from path
    76  func readFile(path string) io.Reader {
    77  	file, err := os.Open(os.Args[1])
    78  	checkErr(err)
    79  	return file
    80  }
    81  
    82  func format(name, num, proto string) string {
    83  	name = strings.ToUpper(name)
    84  	// There are multiple entries for enosys and nosys, so comment them out.
    85  	nm := re{str: name}
    86  	if nm.Match(`^SYS_E?NOSYS$`) {
    87  		name = fmt.Sprintf("// %s", name)
    88  	}
    89  	if name == `SYS_SYS_EXIT` {
    90  		name = `SYS_EXIT`
    91  	}
    92  	return fmt.Sprintf("	%s = %s;  // %s\n", name, num, proto)
    93  }
    94  
    95  func main() {
    96  	// Get the OS (using GOOS_TARGET if it exist)
    97  	goos = os.Getenv("GOOS_TARGET")
    98  	if goos == "" {
    99  		goos = os.Getenv("GOOS")
   100  	}
   101  	// Get the architecture (using GOARCH_TARGET if it exists)
   102  	goarch = os.Getenv("GOARCH_TARGET")
   103  	if goarch == "" {
   104  		goarch = os.Getenv("GOARCH")
   105  	}
   106  	// Check if GOOS and GOARCH environment variables are defined
   107  	if goarch == "" || goos == "" {
   108  		fmt.Fprintf(os.Stderr, "GOARCH or GOOS not defined in environment\n")
   109  		os.Exit(1)
   110  	}
   111  
   112  	file := strings.TrimSpace(os.Args[1])
   113  	var syscalls io.Reader
   114  	if strings.HasPrefix(file, "https://") || strings.HasPrefix(file, "http://") {
   115  		// Download syscalls.master file
   116  		syscalls = fetchFile(file)
   117  	} else {
   118  		syscalls = readFile(file)
   119  	}
   120  
   121  	var text, line string
   122  	s := bufio.NewScanner(syscalls)
   123  	for s.Scan() {
   124  		t := re{str: line}
   125  		if t.Match(`^(.*)\\$`) {
   126  			// Handle continuation
   127  			line = t.sub[1]
   128  			line += strings.TrimLeft(s.Text(), " \t")
   129  		} else {
   130  			// New line
   131  			line = s.Text()
   132  		}
   133  		t = re{str: line}
   134  		if t.Match(`\\$`) {
   135  			continue
   136  		}
   137  		t = re{str: line}
   138  
   139  		switch goos {
   140  		case "dragonfly":
   141  			if t.Match(`^([0-9]+)\s+STD\s+({ \S+\s+(\w+).*)$`) {
   142  				num, proto := t.sub[1], t.sub[2]
   143  				name := fmt.Sprintf("SYS_%s", t.sub[3])
   144  				text += format(name, num, proto)
   145  			}
   146  		case "freebsd":
   147  			if t.Match(`^([0-9]+)\s+\S+\s+(?:(?:NO)?STD)\s+({ \S+\s+(\w+).*)$`) {
   148  				num, proto := t.sub[1], t.sub[2]
   149  				name := fmt.Sprintf("SYS_%s", t.sub[3])
   150  				// remove whitespace around parens
   151  				proto = regexp.MustCompile(`\( `).ReplaceAllString(proto, "(")
   152  				proto = regexp.MustCompile(` \)`).ReplaceAllString(proto, ")")
   153  				// remove SAL 2.0 annotations
   154  				proto = regexp.MustCompile(`_In[^ ]*[_)] `).ReplaceAllString(proto, "")
   155  				proto = regexp.MustCompile(`_Out[^ ]*[_)] `).ReplaceAllString(proto, "")
   156  				// remove double spaces at the source
   157  				proto = regexp.MustCompile(`\s{2}`).ReplaceAllString(proto, " ")
   158  				text += format(name, num, proto)
   159  			}
   160  		case "openbsd":
   161  			if t.Match(`^([0-9]+)\s+STD\s+(NOLOCK\s+)?({ \S+\s+\*?(\w+).*)$`) {
   162  				num, proto, name := t.sub[1], t.sub[3], t.sub[4]
   163  				text += format(name, num, proto)
   164  			}
   165  		case "netbsd":
   166  			if t.Match(`^([0-9]+)\s+((STD)|(NOERR))\s+(RUMP\s+)?({\s+\S+\s*\*?\s*\|(\S+)\|(\S*)\|(\w+).*\s+})(\s+(\S+))?$`) {
   167  				num, proto, compat := t.sub[1], t.sub[6], t.sub[8]
   168  				name := t.sub[7] + "_" + t.sub[9]
   169  				if t.sub[11] != "" {
   170  					name = t.sub[7] + "_" + t.sub[11]
   171  				}
   172  				name = strings.ToUpper(name)
   173  				if compat == "" || compat == "13" || compat == "30" || compat == "50" {
   174  					text += fmt.Sprintf("	%s = %s;  // %s\n", name, num, proto)
   175  				}
   176  			}
   177  		default:
   178  			fmt.Fprintf(os.Stderr, "unrecognized GOOS=%s\n", goos)
   179  			os.Exit(1)
   180  
   181  		}
   182  	}
   183  	err := s.Err()
   184  	checkErr(err)
   185  
   186  	fmt.Printf(template, cmdLine(), goBuildTags(), plusBuildTags(), text)
   187  }
   188  
   189  const template = `// %s
   190  // Code generated by the command above; see README.md. DO NOT EDIT.
   191  
   192  //go:build %s
   193  // +build %s
   194  
   195  package unix
   196  
   197  const(
   198  %s)`