`)
func templatesIndexHtmlBytes() ([]byte, error) {
return _templatesIndexHtml, nil
}
func templatesIndexHtml() (*asset, error) {
bytes, err := templatesIndexHtmlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "templates/index.html", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x2c, 0x8d, 0x8, 0x84, 0x8c, 0xb7, 0x38, 0x19, 0x0, 0x10, 0xf9, 0xa7, 0x67, 0x7c, 0xbe, 0x1f, 0x89, 0xfa, 0xce, 0x7b, 0x7c, 0xfe, 0x23, 0x47, 0x43, 0xe9, 0x1a, 0xa9, 0xa6, 0x42, 0xc8, 0x52}}
return a, nil
}
var _staticStyleCss = []byte(`body {
max-width: 1200px;
margin: 0 auto;
font-family: Helvetica, Arial, sans-serif;
}
`)
func staticStyleCssBytes() ([]byte, error) {
return _staticStyleCss, nil
}
func staticStyleCss() (*asset, error) {
bytes, err := staticStyleCssBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "static/style.css", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf6, 0x2e, 0x3c, 0x9b, 0x2a, 0xb2, 0x32, 0x4c, 0x7d, 0xe0, 0xa5, 0x70, 0x8b, 0x9d, 0x33, 0xf2, 0x4c, 0x1c, 0x32, 0xf9, 0x79, 0xfc, 0x1a, 0x74, 0xd9, 0x1d, 0xae, 0xc, 0x87, 0xf4, 0xdb, 0xa6}}
return a, nil
}
// Asset loads and returns the asset for the given name.
// It returns an error if the asset could not be found or
// could not be loaded.
func Asset(name string) ([]byte, error) {
canonicalName := strings.Replace(name, "\\", "/", -1)
if f, ok := _bindata[canonicalName]; ok {
a, err := f()
if err != nil {
return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
}
return a.bytes, nil
}
return nil, fmt.Errorf("Asset %s not found", name)
}
// AssetString returns the asset contents as a string (instead of a []byte).
func AssetString(name string) (string, error) {
data, err := Asset(name)
return string(data), err
}
// MustAsset is like Asset but panics when Asset would return an error.
// It simplifies safe initialization of global variables.
func MustAsset(name string) []byte {
a, err := Asset(name)
if err != nil {
panic("asset: Asset(" + name + "): " + err.Error())
}
return a
}
// MustAssetString is like AssetString but panics when Asset would return an
// error. It simplifies safe initialization of global variables.
func MustAssetString(name string) string {
return string(MustAsset(name))
}
// AssetInfo loads and returns the asset info for the given name.
// It returns an error if the asset could not be found or
// could not be loaded.
func AssetInfo(name string) (os.FileInfo, error) {
canonicalName := strings.Replace(name, "\\", "/", -1)
if f, ok := _bindata[canonicalName]; ok {
a, err := f()
if err != nil {
return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
}
return a.info, nil
}
return nil, fmt.Errorf("AssetInfo %s not found", name)
}
// AssetDigest returns the digest of the file with the given name. It returns an
// error if the asset could not be found or the digest could not be loaded.
func AssetDigest(name string) ([sha256.Size]byte, error) {
canonicalName := strings.Replace(name, "\\", "/", -1)
if f, ok := _bindata[canonicalName]; ok {
a, err := f()
if err != nil {
return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s can't read by error: %v", name, err)
}
return a.digest, nil
}
return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s not found", name)
}
// Digests returns a map of all known files and their checksums.
func Digests() (map[string][sha256.Size]byte, error) {
mp := make(map[string][sha256.Size]byte, len(_bindata))
for name := range _bindata {
a, err := _bindata[name]()
if err != nil {
return nil, err
}
mp[name] = a.digest
}
return mp, nil
}
// AssetNames returns the names of the assets.
func AssetNames() []string {
names := make([]string, 0, len(_bindata))
for name := range _bindata {
names = append(names, name)
}
return names
}
// _bindata is a table, holding each asset generator, mapped to its name.
var _bindata = map[string]func() (*asset, error){
"templates/index.html": templatesIndexHtml,
"static/style.css": staticStyleCss,
}
// AssetDebug is true if the assets were built with the debug flag enabled.
const AssetDebug = false
// AssetDir returns the file names below a certain
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
// following hierarchy:
//
// data/
// foo.txt
// img/
// a.png
// b.png
//
// then AssetDir("data") would return []string{"foo.txt", "img"},
// AssetDir("data/img") would return []string{"a.png", "b.png"},
// AssetDir("foo.txt") and AssetDir("notexist") would return an error, and
// AssetDir("") will return []string{"data"}.
func AssetDir(name string) ([]string, error) {
node := _bintree
if len(name) != 0 {
canonicalName := strings.Replace(name, "\\", "/", -1)
pathList := strings.Split(canonicalName, "/")
for _, p := range pathList {
node = node.Children[p]
if node == nil {
return nil, fmt.Errorf("Asset %s not found", name)
}
}
}
if node.Func != nil {
return nil, fmt.Errorf("Asset %s not found", name)
}
rv := make([]string, 0, len(node.Children))
for childName := range node.Children {
rv = append(rv, childName)
}
return rv, nil
}
type bintree struct {
Func func() (*asset, error)
Children map[string]*bintree
}
var _bintree = &bintree{nil, map[string]*bintree{
"static": {nil, map[string]*bintree{
"style.css": {staticStyleCss, map[string]*bintree{}},
}},
"templates": {nil, map[string]*bintree{
"index.html": {templatesIndexHtml, map[string]*bintree{}},
}},
}}
// RestoreAsset restores an asset under the given directory.
func RestoreAsset(dir, name string) error {
data, err := Asset(name)
if err != nil {
return err
}
info, err := AssetInfo(name)
if err != nil {
return err
}
err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
if err != nil {
return err
}
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
if err != nil {
return err
}
return os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
}
// RestoreAssets restores an asset under the given directory recursively.
func RestoreAssets(dir, name string) error {
children, err := AssetDir(name)
// File
if err != nil {
return RestoreAsset(dir, name)
}
// Dir
for _, child := range children {
err = RestoreAssets(dir, filepath.Join(name, child))
if err != nil {
return err
}
}
return nil
}
func _filePath(dir, name string) string {
canonicalName := strings.Replace(name, "\\", "/", -1)
return filepath.Join(append([]string{dir}, strings.Split(canonicalName, "/")...)...)
}
================================================
FILE: config.yml
================================================
port: 7065
# Run "make generate_cert" to generate these files.
cert_file: certs/leaf.pem
key_file: certs/leaf.key
================================================
FILE: crypto.go
================================================
package main
// Helpers for two-way encryption with a secret key.
import (
"encoding/base64"
"github.com/kevinburke/nacl"
"github.com/kevinburke/nacl/secretbox"
)
func opaqueByte(b []byte, secretKey nacl.Key) string {
out := secretbox.EasySeal(b, secretKey)
return base64.URLEncoding.EncodeToString(out)
}
func unopaqueByte(compressed string, secretKey nacl.Key) ([]byte, error) {
encrypted, err := base64.URLEncoding.DecodeString(compressed)
if err != nil {
return nil, err
}
return secretbox.EasyOpen(encrypted, secretKey)
}
// Opaque encrypts s with secretKey and returns the encrypted string encoded
// with base64, or an error.
func opaque(s string, secretKey *[32]byte) string {
return opaqueByte([]byte(s), secretKey)
}
// Unopaque decodes compressed using base64, then decrypts the decoded byte
// array using the secretKey.
func unopaque(compressed string, secretKey *[32]byte) (string, error) {
b, err := unopaqueByte(compressed, secretKey)
if err != nil {
return "", err
}
return string(b), nil
}
================================================
FILE: flash.go
================================================
package main
// Helper functions for setting a flash message as a cookie, and then reading
// that flash message in another request.
import (
"net/http"
"strings"
"time"
)
// FlashSuccess encrypts msg and sets it as a cookie on w. Only one success
// message can be set on w; the last call to FlashSuccess will be set on the
// response.
func FlashSuccess(w http.ResponseWriter, msg string, key *[32]byte) {
setCookie(w, msg, "flash-success", key)
}
// FlashError encrypts msg and sets it as a cookie on w. Only one error can be
// set on w; the last call to FlashError will be set on the response.
func FlashError(w http.ResponseWriter, msg string, key *[32]byte) {
setCookie(w, msg, "flash-error", key)
}
func setCookie(w http.ResponseWriter, msg string, name string, key *[32]byte) {
c := &http.Cookie{
Name: name,
Path: "/",
Value: opaque(name+"|"+msg, key),
HttpOnly: true,
}
http.SetCookie(w, c)
}
// GetFlashSuccess finds a flash success message in the request (if one exists).
// If one exists then it's unset and returned.
func GetFlashSuccess(w http.ResponseWriter, r *http.Request, key *[32]byte) string {
return getCookie(w, r, "flash-success", key)
}
// GetFlashError finds a flash error in the request (if one exists). If one
// exists then it's unset and returned.
func GetFlashError(w http.ResponseWriter, r *http.Request, key *[32]byte) string {
return getCookie(w, r, "flash-error", key)
}
func getCookie(w http.ResponseWriter, r *http.Request, name string, key *[32]byte) string {
cookie, err := r.Cookie(name)
if err == http.ErrNoCookie {
return ""
}
clearCookie(w, name)
msg, err := unopaque(cookie.Value, key)
if err != nil {
return ""
}
if !strings.HasPrefix(msg, name+"|") {
clearCookie(w, name)
return ""
}
return msg[len(name)+1:]
}
func clearCookie(w http.ResponseWriter, name string) {
http.SetCookie(w, &http.Cookie{
Name: name,
Path: "/",
MaxAge: -1,
Expires: time.Unix(1, 0),
})
}
================================================
FILE: go.mod
================================================
module github.com/kevinburke/go-html-boilerplate
go 1.24.0
require (
github.com/goccy/go-yaml v1.19.2
github.com/kevinburke/handlers v0.48.0
github.com/kevinburke/nacl v0.9.0
github.com/kevinburke/rest v0.0.0-20260226201626-8eed36da8c35
)
require (
github.com/gofrs/uuid/v5 v5.4.0 // indirect
github.com/inconshreveable/log15/v3 v3.1.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
golang.org/x/crypto v0.40.0 // indirect
golang.org/x/sys v0.41.0 // indirect
golang.org/x/term v0.40.0 // indirect
)
================================================
FILE: go.sum
================================================
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/gofrs/uuid/v5 v5.4.0 h1:EfbpCTjqMuGyq5ZJwxqzn3Cbr2d0rUZU7v5ycAk/e/0=
github.com/gofrs/uuid/v5 v5.4.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
github.com/inconshreveable/log15/v3 v3.1.0 h1:k2mDgq/cBXG0zfVwoDUGvZfel7r+cGD3/6+5cFhM0Zg=
github.com/inconshreveable/log15/v3 v3.1.0/go.mod h1:wBTTBTUs5OkuP5707+qsSwdJidDzxReILCwJgEb8lN8=
github.com/kevinburke/handlers v0.48.0 h1:KlLRpzjfAqkm5nyN5bEbNv+xpB89f76Ojs7sO1ui4sM=
github.com/kevinburke/handlers v0.48.0/go.mod h1:SU5P4j4X4RePv7gr4vNYp2fCWmkWMkqxNvFKRAHJLmk=
github.com/kevinburke/nacl v0.9.0 h1:2C9v+jXTUUlK19kw+9rqfsdO7riP5xIyHNJ3GvsgOro=
github.com/kevinburke/nacl v0.9.0/go.mod h1:qxFJhGMHIPiWJXUauGGORlObOR4bLKBqf/n6PL8l8N0=
github.com/kevinburke/rest v0.0.0-20260226201626-8eed36da8c35 h1:oKRql5U9KOeRmyyetZUKWSoAZFzFHakJ3tqdFBELVTc=
github.com/kevinburke/rest v0.0.0-20260226201626-8eed36da8c35/go.mod h1:Fqq3AMJ2uvn3zSO5bO+FIM3gzJcA1+zAPJU2SnrwOuc=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
================================================
FILE: main.go
================================================
// go-html-boilerplate loads configuration from a file and starts a HTTP server
// that can render HTML templates and static assets.
//
// See config.yml for an explanation of the configuration options for the
// server, and the Makefile for various tasks you can run in coordination with
// the server (run tests, build assets, start the server).
package main
import (
"bytes"
"crypto/sha256"
"encoding/base64"
"flag"
"fmt"
"html/template"
"log/slog"
"net"
"net/http"
"os"
"regexp"
"strconv"
"strings"
"time"
// When you copy this project, change this to the name of your project,
// otherwise you'll get inexplicable 404's.
"github.com/kevinburke/go-html-boilerplate/assets"
"github.com/goccy/go-yaml"
"github.com/kevinburke/handlers"
"github.com/kevinburke/nacl"
"github.com/kevinburke/rest"
)
// DefaultPort is the listening port if no other port is specified.
var DefaultPort = 7065
// The server's Version.
const Version = "0.9.0"
var homepageTpl *template.Template
var logger *slog.Logger
var digests map[string][sha256.Size]byte
// hashurl returns a hash of the resource with the given key
func hashurl(key string) template.URL {
d, ok := digests[strings.TrimPrefix(key, "/")]
if !ok {
return ""
}
// we don't actually need the whole hash.
return template.URL("s=" + b64(d[:12]))
}
func b64(digest []byte) string {
return strings.TrimRight(base64.URLEncoding.EncodeToString(digest), "=")
}
func init() {
var err error
digests, err = assets.Digests()
if err != nil {
panic(err)
}
homepageHTML := assets.MustAssetString("templates/index.html")
homepageTpl = template.Must(
template.New("homepage").Option("missingkey=error").Funcs(template.FuncMap{
"hashurl": hashurl,
}).Parse(homepageHTML),
)
logger = handlers.Logger
// Add more templates here.
}
// A HTTP server for static files. All assets are packaged up in the assets
// directory with the go-bindata binary. Run "make assets" to rerun the
// go-bindata binary.
type static struct {
modTime time.Time
}
var expires = time.Date(2050, time.January, 1, 0, 0, 0, 0, time.UTC).Format(time.RFC1123)
func (s *static) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/favicon.ico" {
r.URL.Path = "/static/favicon.ico"
}
bits, err := assets.Asset(strings.TrimPrefix(r.URL.Path, "/"))
if err != nil {
rest.NotFound(w, r)
return
}
// with the hashurl implementation below, we can set a super-long content
// expiry and ensure content is never stale.
if query := r.URL.Query(); query.Get("s") != "" {
w.Header().Set("Expires", expires)
}
http.ServeContent(w, r, r.URL.Path, s.modTime, bytes.NewReader(bits))
}
// Render a template, or a server error.
func render(w http.ResponseWriter, r *http.Request, tpl *template.Template, name string, data interface{}) {
buf := new(bytes.Buffer)
if err := tpl.ExecuteTemplate(buf, name, data); err != nil {
rest.ServerError(w, r, err)
return
}
w.Write(buf.Bytes())
}
// NewServeMux returns a HTTP handler that covers all routes known to the
// server.
func NewServeMux() http.Handler {
staticServer := &static{
modTime: time.Now().UTC(),
}
r := new(handlers.Regexp)
r.Handle(regexp.MustCompile(`(^/static|^/favicon.ico$)`), []string{"GET"}, handlers.GZip(staticServer))
r.HandleFunc(regexp.MustCompile(`^/$`), []string{"GET"}, func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
render(w, r, homepageTpl, "homepage", nil)
})
// Add more routes here. Routes not matched will get a 404 error page.
// Call rest.RegisterHandler(404, http.HandlerFunc) to provide your own 404
// page instead of the default.
return r
}
// FileConfig represents the data in a config file.
type FileConfig struct {
// SecretKey is used to encrypt sessions and other data before serving it to
// the client. It should be a hex string that's exactly 64 bytes long. For
// example:
//
// d7211b215341871968869dontusethisc0ff1789fc88e0ac6e296ba36703edf8
//
// That key is invalid - you can generate a random key by running:
//
// openssl rand -hex 32
//
// If no secret key is present, we'll generate one when the server starts.
// However, this means that sessions may error when the server restarts.
//
// If a server key is present, but invalid, the server will not start.
SecretKey string `yaml:"secret_key"`
// Port to listen on. Set to 0 to choose a port at random. If unspecified,
// defaults to 7065.
Port *int `yaml:"port"`
// Set to true to listen for HTTP traffic (instead of TLS traffic). Note
// you need to terminate TLS to use HTTP server push.
HTTPOnly bool `yaml:"http_only"`
// For TLS configuration.
CertFile string `yaml:"cert_file"`
KeyFile string `yaml:"key_file"`
// Add other configuration settings here.
}
var cfg = flag.String("config", "config.yml", "Path to a config file")
var version = flag.Bool("version", false, "Print the version string and exit")
func main() {
start := time.Now()
flag.Parse()
if *version {
fmt.Fprintf(os.Stderr, "go-html-boilerplate version %s\n", Version)
os.Exit(0)
}
data, err := os.ReadFile(*cfg)
c := new(FileConfig)
if err == nil {
if err := yaml.Unmarshal(data, c); err != nil {
logger.Error("Couldn't parse config file", "err", err)
os.Exit(2)
}
} else {
logger.Error("Couldn't find config file", "err", err)
os.Exit(2)
}
var key nacl.Key
if c.SecretKey == "" {
logger.Warn("No secret key specified, generating a random one")
key = nacl.NewKey()
} else {
key, err = nacl.Load(c.SecretKey)
if err != nil {
logger.Error("Error getting secret key", "err", err)
os.Exit(2)
}
}
// You can use the secret key with secretbox
// (godoc.org/github.com/kevinburke/nacl/secretbox/) to generate cookies and
// secrets. See flash.go and crypto.go for examples.
_ = key
if c.Port == nil {
port, ok := os.LookupEnv("PORT")
if ok {
iPort, err := strconv.Atoi(port)
if err != nil {
logger.Error("Invalid port", "err", err, "port", port)
os.Exit(2)
}
c.Port = &iPort
} else {
c.Port = &DefaultPort
}
}
mux := NewServeMux()
mux = handlers.UUID(mux) // add UUID header
mux = handlers.Server(mux, "go-html-boilerplate/"+Version) // add Server header
mux = handlers.Log(mux) // log requests/responses
mux = handlers.Duration(mux) // add Duration header
addr := net.JoinHostPort("localhost", strconv.Itoa(*c.Port))
if c.HTTPOnly {
ln, err := net.Listen("tcp", addr)
if err != nil {
logger.Error("Error listening", "addr", addr, "err", err)
os.Exit(2)
}
logger.Info("Started server", "time", time.Since(start).Round(100*time.Microsecond),
"protocol", "http", "port", *c.Port)
http.Serve(ln, mux)
} else {
mux = handlers.STS(mux) // set Strict-Transport-Security header
if c.CertFile == "" {
c.CertFile = "certs/leaf.pem"
}
if _, err := os.Stat(c.CertFile); os.IsNotExist(err) {
logger.Error("Could not find a cert file; generate using 'make generate_cert'", "file", c.CertFile)
os.Exit(2)
}
if c.KeyFile == "" {
c.KeyFile = "certs/leaf.key"
}
if _, err := os.Stat(c.KeyFile); os.IsNotExist(err) {
logger.Error("Could not find a key file; generate using 'make generate_cert'", "file", c.KeyFile)
os.Exit(2)
}
logger.Info("Starting server", "time", time.Since(start).Round(100*time.Microsecond), "protocol", "https", "port", *c.Port)
listenErr := http.ListenAndServeTLS(addr, c.CertFile, c.KeyFile, mux)
logger.Error("server shut down", "err", listenErr)
}
}
================================================
FILE: main_test.go
================================================
package main
import (
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/kevinburke/nacl"
)
func TestServer(t *testing.T) {
mux := NewServeMux()
req := httptest.NewRequest("GET", "/", nil)
w := httptest.NewRecorder()
mux.ServeHTTP(w, req)
if w.Code != 200 {
t.Errorf("GET /: got code %d, want 200", w.Code)
}
if body := w.Body.String(); !strings.Contains(body, "Hello World") {
t.Errorf("GET /: expected 'Hello World' in body, got %s", body)
}
}
func BenchmarkHomepage(b *testing.B) {
mux := NewServeMux()
s := httptest.NewServer(mux)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
res, err := http.Get(s.URL)
if err != nil {
b.Fatal(err)
}
if res.StatusCode != 200 {
b.Fatalf("GET /: expected code 200, got %d", res.StatusCode)
}
n, err := io.ReadAll(res.Body)
if err != nil {
b.Fatal(err)
}
b.SetBytes(int64(len(n)))
res.Body.Close()
}
}
var sink string
// Just curious about how fast secretbox encryption is
func BenchmarkOpaque(b *testing.B) {
key := nacl.NewKey()
secret := "this is an average length message, about sixty characters long."
b.SetBytes(int64(len(secret)))
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
sink = opaque(secret, key)
}
}
================================================
FILE: static/style.css
================================================
body {
max-width: 1200px;
margin: 0 auto;
font-family: Helvetica, Arial, sans-serif;
}
================================================
FILE: templates/index.html
================================================
Go HTML Template
================================================
FILE: vendor/github.com/goccy/go-yaml/.codecov.yml
================================================
codecov:
require_ci_to_pass: yes
coverage:
precision: 2
round: down
range: "70...100"
status:
project:
default:
target: 75%
threshold: 2%
patch: off
changes: no
parsers:
gcov:
branch_detection:
conditional: yes
loop: yes
method: no
macro: no
comment:
layout: "header,diff"
behavior: default
require_changes: no
ignore:
- ast
================================================
FILE: vendor/github.com/goccy/go-yaml/.gitignore
================================================
bin/
.idea/
cover.out
================================================
FILE: vendor/github.com/goccy/go-yaml/.golangci.yml
================================================
version: "2"
linters:
default: none
enable:
- errcheck
- govet
- ineffassign
- misspell
- perfsprint
- staticcheck
- unused
settings:
errcheck:
without_tests: true
govet:
disable:
- tests
misspell:
locale: US
perfsprint:
int-conversion: false
err-error: false
errorf: true
sprintf1: false
strconcat: false
staticcheck:
checks:
- -ST1000
- -ST1005
- all
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
rules:
- linters:
- staticcheck
path: _test\.go
paths:
- third_party$
- builtin$
- examples$
formatters:
enable:
- gci
- gofmt
settings:
gci:
sections:
- standard
- default
- prefix(github.com/goccy/go-yaml)
- blank
- dot
gofmt:
simplify: true
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
================================================
FILE: vendor/github.com/goccy/go-yaml/CHANGELOG.md
================================================
# 1.11.2 - 2023-09-15
### Fix bugs
- Fix quoted comments ( #370 )
- Fix handle of space at start or last ( #376 )
- Fix sequence with comment ( #390 )
# 1.11.1 - 2023-09-14
### Fix bugs
- Handle `\r` in a double-quoted string the same as `\n` ( #372 )
- Replace loop with n.Values = append(n.Values, target.Values...) ( #380 )
- Skip encoding an inline field if it is null ( #386 )
- Fix comment parsing with null value ( #388 )
# 1.11.0 - 2023-04-03
### Features
- Supports dynamically switch encode and decode processing for a given type
# 1.10.1 - 2023-03-28
### Features
- Quote YAML 1.1 bools at encoding time for compatibility with other legacy parsers
- Add support of 32-bit architecture
### Fix bugs
- Don't trim all space characters in block style sequence
- Support strings starting with `@`
# 1.10.0 - 2023-03-01
### Fix bugs
Reversible conversion of comments was not working in various cases, which has been corrected.
**Breaking Change** exists in the comment map interface. However, if you are dealing with CommentMap directly, there is no problem.
# 1.9.8 - 2022-12-19
### Fix feature
- Append new line at the end of file ( #329 )
### Fix bugs
- Fix custom marshaler ( #333, #334 )
- Fix behavior when struct fields conflicted( #335 )
- Fix position calculation for literal, folded and raw folded strings ( #330 )
# 1.9.7 - 2022-12-03
### Fix bugs
- Fix handling of quoted map key ( #328 )
- Fix resusing process of scanning context ( #322 )
## v1.9.6 - 2022-10-26
### New Features
- Introduce MapKeyNode interface to limit node types for map key ( #312 )
### Fix bugs
- Quote strings with special characters in flow mode ( #270 )
- typeError implements PrettyPrinter interface ( #280 )
- Fix incorrect const type ( #284 )
- Fix large literals type inference on 32 bits ( #293 )
- Fix UTF-8 characters ( #294 )
- Fix decoding of unknown aliases ( #317 )
- Fix stream encoder for insert a separator between each encoded document ( #318 )
### Update
- Update golang.org/x/sys ( #289 )
- Update Go version in CI ( #295 )
- Add test cases for missing keys to struct literals ( #300 )
## v1.9.5 - 2022-01-12
### New Features
* Add UseSingleQuote option ( #265 )
### Fix bugs
* Preserve defaults while decoding nested structs ( #260 )
* Fix minor typo in decodeInit error ( #264 )
* Handle empty sequence entries ( #275 )
* Fix encoding of sequence with multiline string ( #276 )
* Fix encoding of BytesMarshaler type ( #277 )
* Fix indentState logic for multi-line value ( #278 )
## v1.9.4 - 2021-10-12
### Fix bugs
* Keep prev/next reference between tokens containing comments when filtering comment tokens ( #257 )
* Supports escaping reserved keywords in PathBuilder ( #258 )
## v1.9.3 - 2021-09-07
### New Features
* Support encoding and decoding `time.Duration` fields ( #246 )
* Allow reserved characters for key name in YAMLPath ( #251 )
* Support getting YAMLPath from ast.Node ( #252 )
* Support CommentToMap option ( #253 )
### Fix bugs
* Fix encoding nested sequences with `yaml.IndentSequence` ( #241 )
* Fix error reporting on inline structs in strict mode ( #244, #245 )
* Fix encoding of large floats ( #247 )
### Improve workflow
* Migrate CI from CircleCI to GitHub Action ( #249 )
* Add workflow for ycat ( #250 )
## v1.9.2 - 2021-07-26
### Support WithComment option ( #238 )
`yaml.WithComment` is a option for encoding with comment.
The position where you want to add a comment is represented by YAMLPath, and it is the key of `yaml.CommentMap`.
Also, you can select `Head` comment or `Line` comment as the comment type.
## v1.9.1 - 2021-07-20
### Fix DecodeFromNode ( #237 )
- Fix YAML handling where anchor exists
## v1.9.0 - 2021-07-19
### New features
- Support encoding of comment node ( #233 )
- Support `yaml.NodeToValue(ast.Node, interface{}, ...DecodeOption) error` ( #236 )
- Can convert a AST node to a value directly
### Fix decoder for comment
- Fix parsing of literal with comment ( #234 )
### Rename API ( #235 )
- Rename `MarshalWithContext` to `MarshalContext`
- Rename `UnmarshalWithContext` to `UnmarshalContext`
## v1.8.10 - 2021-07-02
### Fixed bugs
- Fix searching anchor by alias name ( #212 )
- Fixing Issue 186, scanner should account for newline characters when processing multi-line text. Without this source annotations line/column number (for this and all subsequent tokens) is inconsistent with plain text editors. e.g. https://github.com/goccy/go-yaml/issues/186. This addresses the issue specifically for single and double quote text only. ( #210 )
- Add error for unterminated flow mapping node ( #213 )
- Handle missing required field validation ( #221 )
- Nicely format unexpected node type errors ( #229 )
- Support to encode map which has defined type key ( #231 )
### New features
- Support sequence indentation by EncodeOption ( #232 )
## v1.8.9 - 2021-03-01
### Fixed bugs
- Fix origin buffer for DocumentHeader and DocumentEnd and Directive
- Fix origin buffer for anchor value
- Fix syntax error about map value
- Fix parsing MergeKey ('<<') characters
- Fix encoding of float value
- Fix incorrect column annotation when single or double quotes are used
### New features
- Support to encode/decode of ast.Node directly
================================================
FILE: vendor/github.com/goccy/go-yaml/LICENSE
================================================
MIT License
Copyright (c) 2019 Masaaki Goshima
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: vendor/github.com/goccy/go-yaml/Makefile
================================================
## Location to install dependencies to
LOCALBIN ?= $(shell pwd)/bin
TESTMOD := testdata/go_test.mod
$(LOCALBIN):
mkdir -p $(LOCALBIN)
.PHONY: test
test:
go test -v -race ./...
go test -v -race ./testdata -modfile=$(TESTMOD)
.PHONY: simple-test
simple-test:
go test -v ./...
go test -v ./testdata -modfile=$(TESTMOD)
.PHONY: fuzz
fuzz:
go test -fuzz=Fuzz -fuzztime 60s
.PHONY: cover
cover:
go test -coverpkg=.,./ast,./lexer,./parser,./printer,./scanner,./token -coverprofile=cover.out -modfile=$(TESTMOD) ./... ./testdata
.PHONY: cover-html
cover-html: cover
go tool cover -html=cover.out
.PHONY: ycat/build
ycat/build: $(LOCALBIN)
cd ./cmd/ycat && go build -o $(LOCALBIN)/ycat .
.PHONY: lint
lint: golangci-lint ## Run golangci-lint
@$(GOLANGCI_LINT) run
.PHONY: fmt
fmt: golangci-lint ## Ensure consistent code style
@go mod tidy
@go fmt ./...
@$(GOLANGCI_LINT) run --fix
## Tool Binaries
GOLANGCI_LINT ?= $(LOCALBIN)/golangci-lint
## Tool Versions
GOLANGCI_VERSION := 2.1.2
.PHONY: golangci-lint
.PHONY: $(GOLANGCI_LINT)
golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
$(GOLANGCI_LINT): $(LOCALBIN)
@test -s $(LOCALBIN)/golangci-lint && $(LOCALBIN)/golangci-lint version --short | grep -q $(GOLANGCI_VERSION) || \
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(LOCALBIN) v$(GOLANGCI_VERSION)
================================================
FILE: vendor/github.com/goccy/go-yaml/README.md
================================================
# YAML support for the Go language
[](https://pkg.go.dev/github.com/goccy/go-yaml)

[](https://codecov.io/gh/goccy/go-yaml)
[](https://goreportcard.com/report/github.com/goccy/go-yaml)
## This library has **NO** relation to the go-yaml/yaml library
> [!IMPORTANT]
> This library is developed from scratch to replace [`go-yaml/yaml`](https://github.com/go-yaml/yaml).
> If you're looking for a better YAML library, this one should be helpful.
# Why a new library?
As of this writing, there already exists a de facto standard library for YAML processing for Go: [https://github.com/go-yaml/yaml](https://github.com/go-yaml/yaml). However, we believe that a new YAML library is necessary for the following reasons:
- Not actively maintained
- `go-yaml/yaml` has ported the libyaml written in C to Go, so the source code is not written in Go style
- There is a lot of content that cannot be parsed
- YAML is often used for configuration, and it is common to include validation along with it. However, the errors in `go-yaml/yaml` are not intuitive, and it is difficult to provide meaningful validation errors
- When creating tools that use YAML, there are cases where reversible transformation of YAML is required. However, to perform reversible transformations of content that includes Comments or Anchors/Aliases, manipulating the AST is the only option
- Non-intuitive [Marshaler](https://pkg.go.dev/gopkg.in/yaml.v3#Marshaler) / [Unmarshaler](https://pkg.go.dev/gopkg.in/yaml.v3#Unmarshaler)
By the way, libraries such as [ghodss/yaml](https://github.com/ghodss/yaml) and [sigs.k8s.io/yaml](https://github.com/kubernetes-sigs/yaml) also depend on go-yaml/yaml, so if you are using these libraries, the same issues apply: they cannot parse things that go-yaml/yaml cannot parse, and they inherit many of the problems that go-yaml/yaml has.
# Features
- No dependencies
- A better parser than `go-yaml/yaml`.
- [Support recursive processing](https://github.com/apple/device-management/blob/release/docs/schema.yaml)
- Higher coverage in the [YAML Test Suite](https://github.com/yaml/yaml-test-suite?tab=readme-ov-file)
- YAML Test Suite consists of 402 cases in total, of which `gopkg.in/yaml.v3` passes `295`. In addition to passing all those test cases, `goccy/go-yaml` successfully passes nearly 60 additional test cases ( 2024/12/15 )
- The test code is [here](https://github.com/goccy/go-yaml/blob/master/yaml_test_suite_test.go#L77)
- Ease and sustainability of maintenance
- The main maintainer is [@goccy](https://github.com/goccy), but we are also building a system to develop as a team with trusted developers
- Since it is written from scratch, the code is easy to read for Gophers
- An API structure that allows the use of not only `Encoder`/`Decoder` but also `Tokenizer` and `Parser` functionalities.
- [lexer.Tokenize](https://pkg.go.dev/github.com/goccy/go-yaml@v1.15.4/lexer#Tokenize)
- [parser.Parse](https://pkg.go.dev/github.com/goccy/go-yaml@v1.15.4/parser#Parse)
- Filtering, replacing, and merging YAML content using YAML Path
- Reversible transformation without using the AST for YAML that includes Anchors, Aliases, and Comments
- Customize the Marshal/Unmarshal behavior for primitive types and third-party library types ([RegisterCustomMarshaler](https://pkg.go.dev/github.com/goccy/go-yaml#RegisterCustomMarshaler), [RegisterCustomUnmarshaler](https://pkg.go.dev/github.com/goccy/go-yaml#RegisterCustomUnmarshaler))
- Respects `encoding/json` behavior
- Accept the `json` tag. Note that not all options from the `json` tag will have significance when parsing YAML documents. If both tags exist, `yaml` tag will take precedence.
- [json.Marshaler](https://pkg.go.dev/encoding/json#Marshaler) style [marshaler](https://pkg.go.dev/github.com/goccy/go-yaml#BytesMarshaler)
- [json.Unmarshaler](https://pkg.go.dev/encoding/json#Unmarshaler) style [unmarshaler](https://pkg.go.dev/github.com/goccy/go-yaml#BytesUnmarshaler)
- Options for using `MarshalJSON` and `UnmarshalJSON` ([UseJSONMarshaler](https://pkg.go.dev/github.com/goccy/go-yaml#UseJSONMarshaler), [UseJSONUnmarshaler](https://pkg.go.dev/github.com/goccy/go-yaml#UseJSONUnmarshaler))
- Pretty format for error notifications
- Smart validation processing combined with [go-playground/validator](https://github.com/go-playground/validator)
- [example test code is here](https://github.com/goccy/go-yaml/blob/45889c98b0a0967240eb595a1bd6896e2f575106/testdata/validate_test.go#L12)
- Allow referencing elements declared in another file via anchors
# Users
The repositories that use goccy/go-yaml are listed here.
- https://github.com/goccy/go-yaml/wiki/Users
The source data is [here](https://github.com/goccy/go-yaml/network/dependents).
It is already being used in many repositories. Now it's your turn 😄
# Playground
The Playground visualizes how go-yaml processes YAML text. Use it to assist with your debugging or issue reporting.
https://goccy.github.io/go-yaml
# Installation
```sh
go get github.com/goccy/go-yaml
```
# Synopsis
## 1. Simple Encode/Decode
Has an interface like `go-yaml/yaml` using `reflect`
```go
var v struct {
A int
B string
}
v.A = 1
v.B = "hello"
bytes, err := yaml.Marshal(v)
if err != nil {
//...
}
fmt.Println(string(bytes)) // "a: 1\nb: hello\n"
```
```go
yml := `
%YAML 1.2
---
a: 1
b: c
`
var v struct {
A int
B string
}
if err := yaml.Unmarshal([]byte(yml), &v); err != nil {
//...
}
```
To control marshal/unmarshal behavior, you can use the `yaml` tag.
```go
yml := `---
foo: 1
bar: c
`
var v struct {
A int `yaml:"foo"`
B string `yaml:"bar"`
}
if err := yaml.Unmarshal([]byte(yml), &v); err != nil {
//...
}
```
For convenience, we also accept the `json` tag. Note that not all options from
the `json` tag will have significance when parsing YAML documents. If both
tags exist, `yaml` tag will take precedence.
```go
yml := `---
foo: 1
bar: c
`
var v struct {
A int `json:"foo"`
B string `json:"bar"`
}
if err := yaml.Unmarshal([]byte(yml), &v); err != nil {
//...
}
```
For custom marshal/unmarshaling, implement either `Bytes` or `Interface` variant of marshaler/unmarshaler. The difference is that while `BytesMarshaler`/`BytesUnmarshaler` behaves like [`encoding/json`](https://pkg.go.dev/encoding/json) and `InterfaceMarshaler`/`InterfaceUnmarshaler` behaves like [`gopkg.in/yaml.v2`](https://pkg.go.dev/gopkg.in/yaml.v2).
Semantically both are the same, but they differ in performance. Because indentation matters in YAML, you cannot simply accept a valid YAML fragment from a Marshaler, and expect it to work when it is attached to the parent container's serialized form. Therefore when we receive use the `BytesMarshaler`, which returns `[]byte`, we must decode it once to figure out how to make it work in the given context. If you use the `InterfaceMarshaler`, we can skip the decoding.
If you are repeatedly marshaling complex objects, the latter is always better
performance wise. But if you are, for example, just providing a choice between
a config file format that is read only once, the former is probably easier to
code.
## 2. Reference elements declared in another file
`testdata` directory contains `anchor.yml` file:
```shell
├── testdata
└── anchor.yml
```
And `anchor.yml` is defined as follows:
```yaml
a: &a
b: 1
c: hello
```
Then, if `yaml.ReferenceDirs("testdata")` option is passed to `yaml.Decoder`,
`Decoder` tries to find the anchor definition from YAML files the under `testdata` directory.
```go
buf := bytes.NewBufferString("a: *a\n")
dec := yaml.NewDecoder(buf, yaml.ReferenceDirs("testdata"))
var v struct {
A struct {
B int
C string
}
}
if err := dec.Decode(&v); err != nil {
//...
}
fmt.Printf("%+v\n", v) // {A:{B:1 C:hello}}
```
## 3. Encode with `Anchor` and `Alias`
### 3.1. Explicitly declared `Anchor` name and `Alias` name
If you want to use `anchor`, you can define it as a struct tag.
If the value specified for an anchor is a pointer type and the same address as the pointer is found, the value is automatically set to alias.
If an explicit alias name is specified, an error is raised if its value is different from the value specified in the anchor.
```go
type T struct {
A int
B string
}
var v struct {
C *T `yaml:"c,anchor=x"`
D *T `yaml:"d,alias=x"`
}
v.C = &T{A: 1, B: "hello"}
v.D = v.C
bytes, err := yaml.Marshal(v)
if err != nil {
panic(err)
}
fmt.Println(string(bytes))
/*
c: &x
a: 1
b: hello
d: *x
*/
```
### 3.2. Implicitly declared `Anchor` and `Alias` names
If you do not explicitly declare the anchor name, the default behavior is to
use the equivalent of `strings.ToLower($FieldName)` as the name of the anchor.
If the value specified for an anchor is a pointer type and the same address as the pointer is found, the value is automatically set to alias.
```go
type T struct {
I int
S string
}
var v struct {
A *T `yaml:"a,anchor"`
B *T `yaml:"b,anchor"`
C *T `yaml:"c"`
D *T `yaml:"d"`
}
v.A = &T{I: 1, S: "hello"}
v.B = &T{I: 2, S: "world"}
v.C = v.A // C has same pointer address to A
v.D = v.B // D has same pointer address to B
bytes, err := yaml.Marshal(v)
if err != nil {
//...
}
fmt.Println(string(bytes))
/*
a: &a
i: 1
s: hello
b: &b
i: 2
s: world
c: *a
d: *b
*/
```
### 3.3 MergeKey and Alias
Merge key and alias ( `<<: *alias` ) can be used by embedding a structure with the `inline,alias` tag.
```go
type Person struct {
*Person `yaml:",omitempty,inline,alias"` // embed Person type for default value
Name string `yaml:",omitempty"`
Age int `yaml:",omitempty"`
}
defaultPerson := &Person{
Name: "John Smith",
Age: 20,
}
people := []*Person{
{
Person: defaultPerson, // assign default value
Name: "Ken", // override Name property
Age: 10, // override Age property
},
{
Person: defaultPerson, // assign default value only
},
}
var doc struct {
Default *Person `yaml:"default,anchor"`
People []*Person `yaml:"people"`
}
doc.Default = defaultPerson
doc.People = people
bytes, err := yaml.Marshal(doc)
if err != nil {
//...
}
fmt.Println(string(bytes))
/*
default: &default
name: John Smith
age: 20
people:
- <<: *default
name: Ken
age: 10
- <<: *default
*/
```
## 4. Pretty Formatted Errors
Error values produced during parsing have two extra features over regular
error values.
First, by default, they contain extra information on the location of the error
from the source YAML document, to make it easier to find the error location.
Second, the error messages can optionally be colorized.
If you would like to control exactly how the output looks like, consider
using `yaml.FormatError`, which accepts two boolean values to
control turning these features on or off.
## 5. Use YAMLPath
```go
yml := `
store:
book:
- author: john
price: 10
- author: ken
price: 12
bicycle:
color: red
price: 19.95
`
path, err := yaml.PathString("$.store.book[*].author")
if err != nil {
//...
}
var authors []string
if err := path.Read(strings.NewReader(yml), &authors); err != nil {
//...
}
fmt.Println(authors)
// [john ken]
```
### 5.1 Print customized error with YAML source code
```go
package main
import (
"fmt"
"github.com/goccy/go-yaml"
)
func main() {
yml := `
a: 1
b: "hello"
`
var v struct {
A int
B string
}
if err := yaml.Unmarshal([]byte(yml), &v); err != nil {
panic(err)
}
if v.A != 2 {
// output error with YAML source
path, err := yaml.PathString("$.a")
if err != nil {
panic(err)
}
source, err := path.AnnotateSource([]byte(yml), true)
if err != nil {
panic(err)
}
fmt.Printf("a value expected 2 but actual %d:\n%s\n", v.A, string(source))
}
}
```
output result is the following:
# Tools
## ycat
print yaml file with color
### Installation
```sh
git clone https://github.com/goccy/go-yaml.git
cd go-yaml/cmd/ycat && go install .
```
# For Developers
> [!NOTE]
> In this project, we manage such test code under the `testdata` directory to avoid adding dependencies on libraries that are only needed for testing to the top `go.mod` file. Therefore, if you want to add test cases that use 3rd party libraries, please add the test code to the `testdata` directory.
# Looking for Sponsors
I'm looking for sponsors this library. This library is being developed as a personal project in my spare time. If you want a quick response or problem resolution when using this library in your project, please register as a [sponsor](https://github.com/sponsors/goccy). I will cooperate as much as possible. Of course, this library is developed as an MIT license, so you can use it freely for free.
# License
MIT
================================================
FILE: vendor/github.com/goccy/go-yaml/ast/ast.go
================================================
package ast
import (
"errors"
"fmt"
"io"
"math"
"strconv"
"strings"
"github.com/goccy/go-yaml/token"
)
var (
ErrInvalidTokenType = errors.New("invalid token type")
ErrInvalidAnchorName = errors.New("invalid anchor name")
ErrInvalidAliasName = errors.New("invalid alias name")
)
// NodeType type identifier of node
type NodeType int
const (
// UnknownNodeType type identifier for default
UnknownNodeType NodeType = iota
// DocumentType type identifier for document node
DocumentType
// NullType type identifier for null node
NullType
// BoolType type identifier for boolean node
BoolType
// IntegerType type identifier for integer node
IntegerType
// FloatType type identifier for float node
FloatType
// InfinityType type identifier for infinity node
InfinityType
// NanType type identifier for nan node
NanType
// StringType type identifier for string node
StringType
// MergeKeyType type identifier for merge key node
MergeKeyType
// LiteralType type identifier for literal node
LiteralType
// MappingType type identifier for mapping node
MappingType
// MappingKeyType type identifier for mapping key node
MappingKeyType
// MappingValueType type identifier for mapping value node
MappingValueType
// SequenceType type identifier for sequence node
SequenceType
// SequenceEntryType type identifier for sequence entry node
SequenceEntryType
// AnchorType type identifier for anchor node
AnchorType
// AliasType type identifier for alias node
AliasType
// DirectiveType type identifier for directive node
DirectiveType
// TagType type identifier for tag node
TagType
// CommentType type identifier for comment node
CommentType
// CommentGroupType type identifier for comment group node
CommentGroupType
)
// String node type identifier to text
func (t NodeType) String() string {
switch t {
case UnknownNodeType:
return "UnknownNode"
case DocumentType:
return "Document"
case NullType:
return "Null"
case BoolType:
return "Bool"
case IntegerType:
return "Integer"
case FloatType:
return "Float"
case InfinityType:
return "Infinity"
case NanType:
return "Nan"
case StringType:
return "String"
case MergeKeyType:
return "MergeKey"
case LiteralType:
return "Literal"
case MappingType:
return "Mapping"
case MappingKeyType:
return "MappingKey"
case MappingValueType:
return "MappingValue"
case SequenceType:
return "Sequence"
case SequenceEntryType:
return "SequenceEntry"
case AnchorType:
return "Anchor"
case AliasType:
return "Alias"
case DirectiveType:
return "Directive"
case TagType:
return "Tag"
case CommentType:
return "Comment"
case CommentGroupType:
return "CommentGroup"
}
return ""
}
// String node type identifier to YAML Structure name
// based on https://yaml.org/spec/1.2/spec.html
func (t NodeType) YAMLName() string {
switch t {
case UnknownNodeType:
return "unknown"
case DocumentType:
return "document"
case NullType:
return "null"
case BoolType:
return "boolean"
case IntegerType:
return "int"
case FloatType:
return "float"
case InfinityType:
return "inf"
case NanType:
return "nan"
case StringType:
return "string"
case MergeKeyType:
return "merge key"
case LiteralType:
return "scalar"
case MappingType:
return "mapping"
case MappingKeyType:
return "key"
case MappingValueType:
return "value"
case SequenceType:
return "sequence"
case SequenceEntryType:
return "value"
case AnchorType:
return "anchor"
case AliasType:
return "alias"
case DirectiveType:
return "directive"
case TagType:
return "tag"
case CommentType:
return "comment"
case CommentGroupType:
return "comment"
}
return ""
}
// Node type of node
type Node interface {
io.Reader
// String node to text
String() string
// GetToken returns token instance
GetToken() *token.Token
// Type returns type of node
Type() NodeType
// AddColumn add column number to child nodes recursively
AddColumn(int)
// SetComment set comment token to node
SetComment(*CommentGroupNode) error
// Comment returns comment token instance
GetComment() *CommentGroupNode
// GetPath returns YAMLPath for the current node
GetPath() string
// SetPath set YAMLPath for the current node
SetPath(string)
// MarshalYAML
MarshalYAML() ([]byte, error)
// already read length
readLen() int
// append read length
addReadLen(int)
// clean read length
clearLen()
}
// MapKeyNode type for map key node
type MapKeyNode interface {
Node
IsMergeKey() bool
// String node to text without comment
stringWithoutComment() string
}
// ScalarNode type for scalar node
type ScalarNode interface {
MapKeyNode
GetValue() interface{}
}
type BaseNode struct {
Path string
Comment *CommentGroupNode
read int
}
func addCommentString(base string, node *CommentGroupNode) string {
return fmt.Sprintf("%s %s", base, node.String())
}
func (n *BaseNode) readLen() int {
return n.read
}
func (n *BaseNode) clearLen() {
n.read = 0
}
func (n *BaseNode) addReadLen(len int) {
n.read += len
}
// GetPath returns YAMLPath for the current node.
func (n *BaseNode) GetPath() string {
if n == nil {
return ""
}
return n.Path
}
// SetPath set YAMLPath for the current node.
func (n *BaseNode) SetPath(path string) {
if n == nil {
return
}
n.Path = path
}
// GetComment returns comment token instance
func (n *BaseNode) GetComment() *CommentGroupNode {
return n.Comment
}
// SetComment set comment token
func (n *BaseNode) SetComment(node *CommentGroupNode) error {
n.Comment = node
return nil
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func readNode(p []byte, node Node) (int, error) {
s := node.String()
readLen := node.readLen()
remain := len(s) - readLen
if remain == 0 {
node.clearLen()
return 0, io.EOF
}
size := min(remain, len(p))
for idx, b := range []byte(s[readLen : readLen+size]) {
p[idx] = byte(b)
}
node.addReadLen(size)
return size, nil
}
func checkLineBreak(t *token.Token) bool {
if t.Prev != nil {
lbc := "\n"
prev := t.Prev
var adjustment int
// if the previous type is sequence entry use the previous type for that
if prev.Type == token.SequenceEntryType {
// as well as switching to previous type count any new lines in origin to account for:
// -
// b: c
adjustment = strings.Count(strings.TrimRight(t.Origin, lbc), lbc)
if prev.Prev != nil {
prev = prev.Prev
}
}
lineDiff := t.Position.Line - prev.Position.Line - 1
if lineDiff > 0 {
if prev.Type == token.StringType {
// Remove any line breaks included in multiline string
adjustment += strings.Count(strings.TrimRight(strings.TrimSpace(prev.Origin), lbc), lbc)
}
// Due to the way that comment parsing works its assumed that when a null value does not have new line in origin
// it was squashed therefore difference is ignored.
// foo:
// bar:
// # comment
// baz: 1
// becomes
// foo:
// bar: null # comment
//
// baz: 1
if prev.Type == token.NullType || prev.Type == token.ImplicitNullType {
return strings.Count(prev.Origin, lbc) > 0
}
if lineDiff-adjustment > 0 {
return true
}
}
}
return false
}
// Null create node for null value
func Null(tk *token.Token) *NullNode {
return &NullNode{
BaseNode: &BaseNode{},
Token: tk,
}
}
// Bool create node for boolean value
func Bool(tk *token.Token) *BoolNode {
b, _ := strconv.ParseBool(tk.Value)
return &BoolNode{
BaseNode: &BaseNode{},
Token: tk,
Value: b,
}
}
// Integer create node for integer value
func Integer(tk *token.Token) *IntegerNode {
var v any
if num := token.ToNumber(tk.Value); num != nil {
v = num.Value
}
return &IntegerNode{
BaseNode: &BaseNode{},
Token: tk,
Value: v,
}
}
// Float create node for float value
func Float(tk *token.Token) *FloatNode {
var v float64
if num := token.ToNumber(tk.Value); num != nil && num.Type == token.NumberTypeFloat {
value, ok := num.Value.(float64)
if ok {
v = value
}
}
return &FloatNode{
BaseNode: &BaseNode{},
Token: tk,
Value: v,
}
}
// Infinity create node for .inf or -.inf value
func Infinity(tk *token.Token) *InfinityNode {
node := &InfinityNode{
BaseNode: &BaseNode{},
Token: tk,
}
switch tk.Value {
case ".inf", ".Inf", ".INF":
node.Value = math.Inf(0)
case "-.inf", "-.Inf", "-.INF":
node.Value = math.Inf(-1)
}
return node
}
// Nan create node for .nan value
func Nan(tk *token.Token) *NanNode {
return &NanNode{
BaseNode: &BaseNode{},
Token: tk,
}
}
// String create node for string value
func String(tk *token.Token) *StringNode {
return &StringNode{
BaseNode: &BaseNode{},
Token: tk,
Value: tk.Value,
}
}
// Comment create node for comment
func Comment(tk *token.Token) *CommentNode {
return &CommentNode{
BaseNode: &BaseNode{},
Token: tk,
}
}
func CommentGroup(comments []*token.Token) *CommentGroupNode {
nodes := []*CommentNode{}
for _, comment := range comments {
nodes = append(nodes, Comment(comment))
}
return &CommentGroupNode{
BaseNode: &BaseNode{},
Comments: nodes,
}
}
// MergeKey create node for merge key ( << )
func MergeKey(tk *token.Token) *MergeKeyNode {
return &MergeKeyNode{
BaseNode: &BaseNode{},
Token: tk,
}
}
// Mapping create node for map
func Mapping(tk *token.Token, isFlowStyle bool, values ...*MappingValueNode) *MappingNode {
node := &MappingNode{
BaseNode: &BaseNode{},
Start: tk,
IsFlowStyle: isFlowStyle,
Values: []*MappingValueNode{},
}
node.Values = append(node.Values, values...)
return node
}
// MappingValue create node for mapping value
func MappingValue(tk *token.Token, key MapKeyNode, value Node) *MappingValueNode {
return &MappingValueNode{
BaseNode: &BaseNode{},
Start: tk,
Key: key,
Value: value,
}
}
// MappingKey create node for map key ( '?' ).
func MappingKey(tk *token.Token) *MappingKeyNode {
return &MappingKeyNode{
BaseNode: &BaseNode{},
Start: tk,
}
}
// Sequence create node for sequence
func Sequence(tk *token.Token, isFlowStyle bool) *SequenceNode {
return &SequenceNode{
BaseNode: &BaseNode{},
Start: tk,
IsFlowStyle: isFlowStyle,
Values: []Node{},
}
}
func Anchor(tk *token.Token) *AnchorNode {
return &AnchorNode{
BaseNode: &BaseNode{},
Start: tk,
}
}
func Alias(tk *token.Token) *AliasNode {
return &AliasNode{
BaseNode: &BaseNode{},
Start: tk,
}
}
func Document(tk *token.Token, body Node) *DocumentNode {
return &DocumentNode{
BaseNode: &BaseNode{},
Start: tk,
Body: body,
}
}
func Directive(tk *token.Token) *DirectiveNode {
return &DirectiveNode{
BaseNode: &BaseNode{},
Start: tk,
}
}
func Literal(tk *token.Token) *LiteralNode {
return &LiteralNode{
BaseNode: &BaseNode{},
Start: tk,
}
}
func Tag(tk *token.Token) *TagNode {
return &TagNode{
BaseNode: &BaseNode{},
Start: tk,
}
}
// File contains all documents in YAML file
type File struct {
Name string
Docs []*DocumentNode
}
// Read implements (io.Reader).Read
func (f *File) Read(p []byte) (int, error) {
for _, doc := range f.Docs {
n, err := doc.Read(p)
if err == io.EOF {
continue
}
return n, nil
}
return 0, io.EOF
}
// String all documents to text
func (f *File) String() string {
docs := []string{}
for _, doc := range f.Docs {
docs = append(docs, doc.String())
}
if len(docs) > 0 {
return strings.Join(docs, "\n") + "\n"
} else {
return ""
}
}
// DocumentNode type of Document
type DocumentNode struct {
*BaseNode
Start *token.Token // position of DocumentHeader ( `---` )
End *token.Token // position of DocumentEnd ( `...` )
Body Node
}
// Read implements (io.Reader).Read
func (d *DocumentNode) Read(p []byte) (int, error) {
return readNode(p, d)
}
// Type returns DocumentNodeType
func (d *DocumentNode) Type() NodeType { return DocumentType }
// GetToken returns token instance
func (d *DocumentNode) GetToken() *token.Token {
return d.Body.GetToken()
}
// AddColumn add column number to child nodes recursively
func (d *DocumentNode) AddColumn(col int) {
if d.Body != nil {
d.Body.AddColumn(col)
}
}
// String document to text
func (d *DocumentNode) String() string {
doc := []string{}
if d.Start != nil {
doc = append(doc, d.Start.Value)
}
if d.Body != nil {
doc = append(doc, d.Body.String())
}
if d.End != nil {
doc = append(doc, d.End.Value)
}
return strings.Join(doc, "\n")
}
// MarshalYAML encodes to a YAML text
func (d *DocumentNode) MarshalYAML() ([]byte, error) {
return []byte(d.String()), nil
}
// NullNode type of null node
type NullNode struct {
*BaseNode
Token *token.Token
}
// Read implements (io.Reader).Read
func (n *NullNode) Read(p []byte) (int, error) {
return readNode(p, n)
}
// Type returns NullType
func (n *NullNode) Type() NodeType { return NullType }
// GetToken returns token instance
func (n *NullNode) GetToken() *token.Token {
return n.Token
}
// AddColumn add column number to child nodes recursively
func (n *NullNode) AddColumn(col int) {
n.Token.AddColumn(col)
}
// GetValue returns nil value
func (n *NullNode) GetValue() interface{} {
return nil
}
// String returns `null` text
func (n *NullNode) String() string {
if n.Token.Type == token.ImplicitNullType {
if n.Comment != nil {
return n.Comment.String()
}
return ""
}
if n.Comment != nil {
return addCommentString("null", n.Comment)
}
return n.stringWithoutComment()
}
func (n *NullNode) stringWithoutComment() string {
return "null"
}
// MarshalYAML encodes to a YAML text
func (n *NullNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
// IsMergeKey returns whether it is a MergeKey node.
func (n *NullNode) IsMergeKey() bool {
return false
}
// IntegerNode type of integer node
type IntegerNode struct {
*BaseNode
Token *token.Token
Value interface{} // int64 or uint64 value
}
// Read implements (io.Reader).Read
func (n *IntegerNode) Read(p []byte) (int, error) {
return readNode(p, n)
}
// Type returns IntegerType
func (n *IntegerNode) Type() NodeType { return IntegerType }
// GetToken returns token instance
func (n *IntegerNode) GetToken() *token.Token {
return n.Token
}
// AddColumn add column number to child nodes recursively
func (n *IntegerNode) AddColumn(col int) {
n.Token.AddColumn(col)
}
// GetValue returns int64 value
func (n *IntegerNode) GetValue() interface{} {
return n.Value
}
// String int64 to text
func (n *IntegerNode) String() string {
if n.Comment != nil {
return addCommentString(n.Token.Value, n.Comment)
}
return n.stringWithoutComment()
}
func (n *IntegerNode) stringWithoutComment() string {
return n.Token.Value
}
// MarshalYAML encodes to a YAML text
func (n *IntegerNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
// IsMergeKey returns whether it is a MergeKey node.
func (n *IntegerNode) IsMergeKey() bool {
return false
}
// FloatNode type of float node
type FloatNode struct {
*BaseNode
Token *token.Token
Precision int
Value float64
}
// Read implements (io.Reader).Read
func (n *FloatNode) Read(p []byte) (int, error) {
return readNode(p, n)
}
// Type returns FloatType
func (n *FloatNode) Type() NodeType { return FloatType }
// GetToken returns token instance
func (n *FloatNode) GetToken() *token.Token {
return n.Token
}
// AddColumn add column number to child nodes recursively
func (n *FloatNode) AddColumn(col int) {
n.Token.AddColumn(col)
}
// GetValue returns float64 value
func (n *FloatNode) GetValue() interface{} {
return n.Value
}
// String float64 to text
func (n *FloatNode) String() string {
if n.Comment != nil {
return addCommentString(n.Token.Value, n.Comment)
}
return n.stringWithoutComment()
}
func (n *FloatNode) stringWithoutComment() string {
return n.Token.Value
}
// MarshalYAML encodes to a YAML text
func (n *FloatNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
// IsMergeKey returns whether it is a MergeKey node.
func (n *FloatNode) IsMergeKey() bool {
return false
}
// StringNode type of string node
type StringNode struct {
*BaseNode
Token *token.Token
Value string
}
// Read implements (io.Reader).Read
func (n *StringNode) Read(p []byte) (int, error) {
return readNode(p, n)
}
// Type returns StringType
func (n *StringNode) Type() NodeType { return StringType }
// GetToken returns token instance
func (n *StringNode) GetToken() *token.Token {
return n.Token
}
// AddColumn add column number to child nodes recursively
func (n *StringNode) AddColumn(col int) {
n.Token.AddColumn(col)
}
// GetValue returns string value
func (n *StringNode) GetValue() interface{} {
return n.Value
}
// IsMergeKey returns whether it is a MergeKey node.
func (n *StringNode) IsMergeKey() bool {
return false
}
// escapeSingleQuote escapes s to a single quoted scalar.
// https://yaml.org/spec/1.2.2/#732-single-quoted-style
func escapeSingleQuote(s string) string {
var sb strings.Builder
growLen := len(s) + // s includes also one ' from the doubled pair
2 + // opening and closing '
strings.Count(s, "'") // ' added by ReplaceAll
sb.Grow(growLen)
sb.WriteString("'")
sb.WriteString(strings.ReplaceAll(s, "'", "''"))
sb.WriteString("'")
return sb.String()
}
// String string value to text with quote or literal header if required
func (n *StringNode) String() string {
switch n.Token.Type {
case token.SingleQuoteType:
quoted := escapeSingleQuote(n.Value)
if n.Comment != nil {
return addCommentString(quoted, n.Comment)
}
return quoted
case token.DoubleQuoteType:
quoted := strconv.Quote(n.Value)
if n.Comment != nil {
return addCommentString(quoted, n.Comment)
}
return quoted
}
lbc := token.DetectLineBreakCharacter(n.Value)
if strings.Contains(n.Value, lbc) {
// This block assumes that the line breaks in this inside scalar content and the Outside scalar content are the same.
// It works mostly, but inconsistencies occur if line break characters are mixed.
header := token.LiteralBlockHeader(n.Value)
space := strings.Repeat(" ", n.Token.Position.Column-1)
indent := strings.Repeat(" ", n.Token.Position.IndentNum)
values := []string{}
for _, v := range strings.Split(n.Value, lbc) {
values = append(values, fmt.Sprintf("%s%s%s", space, indent, v))
}
block := strings.TrimSuffix(strings.TrimSuffix(strings.Join(values, lbc), fmt.Sprintf("%s%s%s", lbc, indent, space)), fmt.Sprintf("%s%s", indent, space))
return fmt.Sprintf("%s%s%s", header, lbc, block)
} else if len(n.Value) > 0 && (n.Value[0] == '{' || n.Value[0] == '[') {
return fmt.Sprintf(`'%s'`, n.Value)
}
if n.Comment != nil {
return addCommentString(n.Value, n.Comment)
}
return n.Value
}
func (n *StringNode) stringWithoutComment() string {
switch n.Token.Type {
case token.SingleQuoteType:
quoted := fmt.Sprintf(`'%s'`, n.Value)
return quoted
case token.DoubleQuoteType:
quoted := strconv.Quote(n.Value)
return quoted
}
lbc := token.DetectLineBreakCharacter(n.Value)
if strings.Contains(n.Value, lbc) {
// This block assumes that the line breaks in this inside scalar content and the Outside scalar content are the same.
// It works mostly, but inconsistencies occur if line break characters are mixed.
header := token.LiteralBlockHeader(n.Value)
space := strings.Repeat(" ", n.Token.Position.Column-1)
indent := strings.Repeat(" ", n.Token.Position.IndentNum)
values := []string{}
for _, v := range strings.Split(n.Value, lbc) {
values = append(values, fmt.Sprintf("%s%s%s", space, indent, v))
}
block := strings.TrimSuffix(strings.TrimSuffix(strings.Join(values, lbc), fmt.Sprintf("%s%s%s", lbc, indent, space)), fmt.Sprintf(" %s", space))
return fmt.Sprintf("%s%s%s", header, lbc, block)
} else if len(n.Value) > 0 && (n.Value[0] == '{' || n.Value[0] == '[') {
return fmt.Sprintf(`'%s'`, n.Value)
}
return n.Value
}
// MarshalYAML encodes to a YAML text
func (n *StringNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
// LiteralNode type of literal node
type LiteralNode struct {
*BaseNode
Start *token.Token
Value *StringNode
}
// Read implements (io.Reader).Read
func (n *LiteralNode) Read(p []byte) (int, error) {
return readNode(p, n)
}
// Type returns LiteralType
func (n *LiteralNode) Type() NodeType { return LiteralType }
// GetToken returns token instance
func (n *LiteralNode) GetToken() *token.Token {
return n.Start
}
// AddColumn add column number to child nodes recursively
func (n *LiteralNode) AddColumn(col int) {
n.Start.AddColumn(col)
if n.Value != nil {
n.Value.AddColumn(col)
}
}
// GetValue returns string value
func (n *LiteralNode) GetValue() interface{} {
return n.String()
}
// String literal to text
func (n *LiteralNode) String() string {
origin := n.Value.GetToken().Origin
lit := strings.TrimRight(strings.TrimRight(origin, " "), "\n")
if n.Comment != nil {
return fmt.Sprintf("%s %s\n%s", n.Start.Value, n.Comment.String(), lit)
}
return fmt.Sprintf("%s\n%s", n.Start.Value, lit)
}
func (n *LiteralNode) stringWithoutComment() string {
return n.String()
}
// MarshalYAML encodes to a YAML text
func (n *LiteralNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
// IsMergeKey returns whether it is a MergeKey node.
func (n *LiteralNode) IsMergeKey() bool {
return false
}
// MergeKeyNode type of merge key node
type MergeKeyNode struct {
*BaseNode
Token *token.Token
}
// Read implements (io.Reader).Read
func (n *MergeKeyNode) Read(p []byte) (int, error) {
return readNode(p, n)
}
// Type returns MergeKeyType
func (n *MergeKeyNode) Type() NodeType { return MergeKeyType }
// GetToken returns token instance
func (n *MergeKeyNode) GetToken() *token.Token {
return n.Token
}
// GetValue returns '<<' value
func (n *MergeKeyNode) GetValue() interface{} {
return n.Token.Value
}
// String returns '<<' value
func (n *MergeKeyNode) String() string {
return n.stringWithoutComment()
}
func (n *MergeKeyNode) stringWithoutComment() string {
return n.Token.Value
}
// AddColumn add column number to child nodes recursively
func (n *MergeKeyNode) AddColumn(col int) {
n.Token.AddColumn(col)
}
// MarshalYAML encodes to a YAML text
func (n *MergeKeyNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
// IsMergeKey returns whether it is a MergeKey node.
func (n *MergeKeyNode) IsMergeKey() bool {
return true
}
// BoolNode type of boolean node
type BoolNode struct {
*BaseNode
Token *token.Token
Value bool
}
// Read implements (io.Reader).Read
func (n *BoolNode) Read(p []byte) (int, error) {
return readNode(p, n)
}
// Type returns BoolType
func (n *BoolNode) Type() NodeType { return BoolType }
// GetToken returns token instance
func (n *BoolNode) GetToken() *token.Token {
return n.Token
}
// AddColumn add column number to child nodes recursively
func (n *BoolNode) AddColumn(col int) {
n.Token.AddColumn(col)
}
// GetValue returns boolean value
func (n *BoolNode) GetValue() interface{} {
return n.Value
}
// String boolean to text
func (n *BoolNode) String() string {
if n.Comment != nil {
return addCommentString(n.Token.Value, n.Comment)
}
return n.stringWithoutComment()
}
func (n *BoolNode) stringWithoutComment() string {
return n.Token.Value
}
// MarshalYAML encodes to a YAML text
func (n *BoolNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
// IsMergeKey returns whether it is a MergeKey node.
func (n *BoolNode) IsMergeKey() bool {
return false
}
// InfinityNode type of infinity node
type InfinityNode struct {
*BaseNode
Token *token.Token
Value float64
}
// Read implements (io.Reader).Read
func (n *InfinityNode) Read(p []byte) (int, error) {
return readNode(p, n)
}
// Type returns InfinityType
func (n *InfinityNode) Type() NodeType { return InfinityType }
// GetToken returns token instance
func (n *InfinityNode) GetToken() *token.Token {
return n.Token
}
// AddColumn add column number to child nodes recursively
func (n *InfinityNode) AddColumn(col int) {
n.Token.AddColumn(col)
}
// GetValue returns math.Inf(0) or math.Inf(-1)
func (n *InfinityNode) GetValue() interface{} {
return n.Value
}
// String infinity to text
func (n *InfinityNode) String() string {
if n.Comment != nil {
return addCommentString(n.Token.Value, n.Comment)
}
return n.stringWithoutComment()
}
func (n *InfinityNode) stringWithoutComment() string {
return n.Token.Value
}
// MarshalYAML encodes to a YAML text
func (n *InfinityNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
// IsMergeKey returns whether it is a MergeKey node.
func (n *InfinityNode) IsMergeKey() bool {
return false
}
// NanNode type of nan node
type NanNode struct {
*BaseNode
Token *token.Token
}
// Read implements (io.Reader).Read
func (n *NanNode) Read(p []byte) (int, error) {
return readNode(p, n)
}
// Type returns NanType
func (n *NanNode) Type() NodeType { return NanType }
// GetToken returns token instance
func (n *NanNode) GetToken() *token.Token {
return n.Token
}
// AddColumn add column number to child nodes recursively
func (n *NanNode) AddColumn(col int) {
n.Token.AddColumn(col)
}
// GetValue returns math.NaN()
func (n *NanNode) GetValue() interface{} {
return math.NaN()
}
// String returns .nan
func (n *NanNode) String() string {
if n.Comment != nil {
return addCommentString(n.Token.Value, n.Comment)
}
return n.stringWithoutComment()
}
func (n *NanNode) stringWithoutComment() string {
return n.Token.Value
}
// MarshalYAML encodes to a YAML text
func (n *NanNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
// IsMergeKey returns whether it is a MergeKey node.
func (n *NanNode) IsMergeKey() bool {
return false
}
// MapNode interface of MappingValueNode / MappingNode
type MapNode interface {
MapRange() *MapNodeIter
}
// MapNodeIter is an iterator for ranging over a MapNode
type MapNodeIter struct {
values []*MappingValueNode
idx int
}
const (
startRangeIndex = -1
)
// Next advances the map iterator and reports whether there is another entry.
// It returns false when the iterator is exhausted.
func (m *MapNodeIter) Next() bool {
m.idx++
next := m.idx < len(m.values)
return next
}
// Key returns the key of the iterator's current map node entry.
func (m *MapNodeIter) Key() MapKeyNode {
return m.values[m.idx].Key
}
// Value returns the value of the iterator's current map node entry.
func (m *MapNodeIter) Value() Node {
return m.values[m.idx].Value
}
// KeyValue returns the MappingValueNode of the iterator's current map node entry.
func (m *MapNodeIter) KeyValue() *MappingValueNode {
return m.values[m.idx]
}
// MappingNode type of mapping node
type MappingNode struct {
*BaseNode
Start *token.Token
End *token.Token
IsFlowStyle bool
Values []*MappingValueNode
FootComment *CommentGroupNode
}
func (n *MappingNode) startPos() *token.Position {
if len(n.Values) == 0 {
return n.Start.Position
}
return n.Values[0].Key.GetToken().Position
}
// Merge merge key/value of map.
func (n *MappingNode) Merge(target *MappingNode) {
keyToMapValueMap := map[string]*MappingValueNode{}
for _, value := range n.Values {
key := value.Key.String()
keyToMapValueMap[key] = value
}
column := n.startPos().Column - target.startPos().Column
target.AddColumn(column)
for _, value := range target.Values {
mapValue, exists := keyToMapValueMap[value.Key.String()]
if exists {
mapValue.Value = value.Value
} else {
n.Values = append(n.Values, value)
}
}
}
// SetIsFlowStyle set value to IsFlowStyle field recursively.
func (n *MappingNode) SetIsFlowStyle(isFlow bool) {
n.IsFlowStyle = isFlow
for _, value := range n.Values {
value.SetIsFlowStyle(isFlow)
}
}
// Read implements (io.Reader).Read
func (n *MappingNode) Read(p []byte) (int, error) {
return readNode(p, n)
}
// Type returns MappingType
func (n *MappingNode) Type() NodeType { return MappingType }
// GetToken returns token instance
func (n *MappingNode) GetToken() *token.Token {
return n.Start
}
// AddColumn add column number to child nodes recursively
func (n *MappingNode) AddColumn(col int) {
n.Start.AddColumn(col)
n.End.AddColumn(col)
for _, value := range n.Values {
value.AddColumn(col)
}
}
func (n *MappingNode) flowStyleString(commentMode bool) string {
values := []string{}
for _, value := range n.Values {
values = append(values, strings.TrimLeft(value.String(), " "))
}
mapText := fmt.Sprintf("{%s}", strings.Join(values, ", "))
if commentMode && n.Comment != nil {
return addCommentString(mapText, n.Comment)
}
return mapText
}
func (n *MappingNode) blockStyleString(commentMode bool) string {
values := []string{}
for _, value := range n.Values {
values = append(values, value.String())
}
mapText := strings.Join(values, "\n")
if commentMode && n.Comment != nil {
value := values[0]
var spaceNum int
for i := 0; i < len(value); i++ {
if value[i] != ' ' {
break
}
spaceNum++
}
comment := n.Comment.StringWithSpace(spaceNum)
return fmt.Sprintf("%s\n%s", comment, mapText)
}
return mapText
}
// String mapping values to text
func (n *MappingNode) String() string {
if len(n.Values) == 0 {
if n.Comment != nil {
return addCommentString("{}", n.Comment)
}
return "{}"
}
commentMode := true
if n.IsFlowStyle || len(n.Values) == 0 {
return n.flowStyleString(commentMode)
}
return n.blockStyleString(commentMode)
}
// MapRange implements MapNode protocol
func (n *MappingNode) MapRange() *MapNodeIter {
return &MapNodeIter{
idx: startRangeIndex,
values: n.Values,
}
}
// MarshalYAML encodes to a YAML text
func (n *MappingNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
// MappingKeyNode type of tag node
type MappingKeyNode struct {
*BaseNode
Start *token.Token
Value Node
}
// Read implements (io.Reader).Read
func (n *MappingKeyNode) Read(p []byte) (int, error) {
return readNode(p, n)
}
// Type returns MappingKeyType
func (n *MappingKeyNode) Type() NodeType { return MappingKeyType }
// GetToken returns token instance
func (n *MappingKeyNode) GetToken() *token.Token {
return n.Start
}
// AddColumn add column number to child nodes recursively
func (n *MappingKeyNode) AddColumn(col int) {
n.Start.AddColumn(col)
if n.Value != nil {
n.Value.AddColumn(col)
}
}
// String tag to text
func (n *MappingKeyNode) String() string {
return n.stringWithoutComment()
}
func (n *MappingKeyNode) stringWithoutComment() string {
return fmt.Sprintf("%s %s", n.Start.Value, n.Value.String())
}
// MarshalYAML encodes to a YAML text
func (n *MappingKeyNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
// IsMergeKey returns whether it is a MergeKey node.
func (n *MappingKeyNode) IsMergeKey() bool {
if n.Value == nil {
return false
}
key, ok := n.Value.(MapKeyNode)
if !ok {
return false
}
return key.IsMergeKey()
}
// MappingValueNode type of mapping value
type MappingValueNode struct {
*BaseNode
Start *token.Token // delimiter token ':'.
CollectEntry *token.Token // collect entry token ','.
Key MapKeyNode
Value Node
FootComment *CommentGroupNode
IsFlowStyle bool
}
// Replace replace value node.
func (n *MappingValueNode) Replace(value Node) error {
column := n.Value.GetToken().Position.Column - value.GetToken().Position.Column
value.AddColumn(column)
n.Value = value
return nil
}
// Read implements (io.Reader).Read
func (n *MappingValueNode) Read(p []byte) (int, error) {
return readNode(p, n)
}
// Type returns MappingValueType
func (n *MappingValueNode) Type() NodeType { return MappingValueType }
// GetToken returns token instance
func (n *MappingValueNode) GetToken() *token.Token {
return n.Start
}
// AddColumn add column number to child nodes recursively
func (n *MappingValueNode) AddColumn(col int) {
n.Start.AddColumn(col)
if n.Key != nil {
n.Key.AddColumn(col)
}
if n.Value != nil {
n.Value.AddColumn(col)
}
}
// SetIsFlowStyle set value to IsFlowStyle field recursively.
func (n *MappingValueNode) SetIsFlowStyle(isFlow bool) {
n.IsFlowStyle = isFlow
switch value := n.Value.(type) {
case *MappingNode:
value.SetIsFlowStyle(isFlow)
case *MappingValueNode:
value.SetIsFlowStyle(isFlow)
case *SequenceNode:
value.SetIsFlowStyle(isFlow)
}
}
// String mapping value to text
func (n *MappingValueNode) String() string {
var text string
if n.Comment != nil {
text = fmt.Sprintf(
"%s\n%s",
n.Comment.StringWithSpace(n.Key.GetToken().Position.Column-1),
n.toString(),
)
} else {
text = n.toString()
}
if n.FootComment != nil {
text += fmt.Sprintf("\n%s", n.FootComment.StringWithSpace(n.Key.GetToken().Position.Column-1))
}
return text
}
func (n *MappingValueNode) toString() string {
space := strings.Repeat(" ", n.Key.GetToken().Position.Column-1)
if checkLineBreak(n.Key.GetToken()) {
space = fmt.Sprintf("%s%s", "\n", space)
}
keyIndentLevel := n.Key.GetToken().Position.IndentLevel
valueIndentLevel := n.Value.GetToken().Position.IndentLevel
keyComment := n.Key.GetComment()
if _, ok := n.Value.(ScalarNode); ok {
value := n.Value.String()
if value == "" {
// implicit null value.
return fmt.Sprintf("%s%s:", space, n.Key.String())
}
return fmt.Sprintf("%s%s: %s", space, n.Key.String(), value)
} else if keyIndentLevel < valueIndentLevel && !n.IsFlowStyle {
valueStr := n.Value.String()
// For flow-style values indented on the next line, we need to add the proper indentation
if m, ok := n.Value.(*MappingNode); ok && m.IsFlowStyle {
valueIndent := strings.Repeat(" ", n.Value.GetToken().Position.Column-1)
valueStr = valueIndent + valueStr
} else if s, ok := n.Value.(*SequenceNode); ok && s.IsFlowStyle {
valueIndent := strings.Repeat(" ", n.Value.GetToken().Position.Column-1)
valueStr = valueIndent + valueStr
}
if keyComment != nil {
return fmt.Sprintf(
"%s%s: %s\n%s",
space,
n.Key.stringWithoutComment(),
keyComment.String(),
valueStr,
)
}
return fmt.Sprintf("%s%s:\n%s", space, n.Key.String(), valueStr)
} else if m, ok := n.Value.(*MappingNode); ok && (m.IsFlowStyle || len(m.Values) == 0) {
return fmt.Sprintf("%s%s: %s", space, n.Key.String(), n.Value.String())
} else if s, ok := n.Value.(*SequenceNode); ok && (s.IsFlowStyle || len(s.Values) == 0) {
return fmt.Sprintf("%s%s: %s", space, n.Key.String(), n.Value.String())
} else if _, ok := n.Value.(*AnchorNode); ok {
return fmt.Sprintf("%s%s: %s", space, n.Key.String(), n.Value.String())
} else if _, ok := n.Value.(*AliasNode); ok {
return fmt.Sprintf("%s%s: %s", space, n.Key.String(), n.Value.String())
} else if _, ok := n.Value.(*TagNode); ok {
return fmt.Sprintf("%s%s: %s", space, n.Key.String(), n.Value.String())
}
if keyComment != nil {
return fmt.Sprintf(
"%s%s: %s\n%s",
space,
n.Key.stringWithoutComment(),
keyComment.String(),
n.Value.String(),
)
}
if m, ok := n.Value.(*MappingNode); ok && m.Comment != nil {
return fmt.Sprintf(
"%s%s: %s",
space,
n.Key.String(),
strings.TrimLeft(n.Value.String(), " "),
)
}
return fmt.Sprintf("%s%s:\n%s", space, n.Key.String(), n.Value.String())
}
// MapRange implements MapNode protocol
func (n *MappingValueNode) MapRange() *MapNodeIter {
return &MapNodeIter{
idx: startRangeIndex,
values: []*MappingValueNode{n},
}
}
// MarshalYAML encodes to a YAML text
func (n *MappingValueNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
// ArrayNode interface of SequenceNode
type ArrayNode interface {
ArrayRange() *ArrayNodeIter
}
// ArrayNodeIter is an iterator for ranging over a ArrayNode
type ArrayNodeIter struct {
values []Node
idx int
}
// Next advances the array iterator and reports whether there is another entry.
// It returns false when the iterator is exhausted.
func (m *ArrayNodeIter) Next() bool {
m.idx++
next := m.idx < len(m.values)
return next
}
// Value returns the value of the iterator's current array entry.
func (m *ArrayNodeIter) Value() Node {
return m.values[m.idx]
}
// Len returns length of array
func (m *ArrayNodeIter) Len() int {
return len(m.values)
}
// SequenceNode type of sequence node
type SequenceNode struct {
*BaseNode
Start *token.Token
End *token.Token
IsFlowStyle bool
Values []Node
ValueHeadComments []*CommentGroupNode
Entries []*SequenceEntryNode
FootComment *CommentGroupNode
}
// Replace replace value node.
func (n *SequenceNode) Replace(idx int, value Node) error {
if len(n.Values) <= idx {
return fmt.Errorf(
"invalid index for sequence: sequence length is %d, but specified %d index",
len(n.Values), idx,
)
}
column := n.Values[idx].GetToken().Position.Column - value.GetToken().Position.Column
value.AddColumn(column)
n.Values[idx] = value
return nil
}
// Merge merge sequence value.
func (n *SequenceNode) Merge(target *SequenceNode) {
column := n.Start.Position.Column - target.Start.Position.Column
target.AddColumn(column)
n.Values = append(n.Values, target.Values...)
if len(target.ValueHeadComments) == 0 {
n.ValueHeadComments = append(n.ValueHeadComments, make([]*CommentGroupNode, len(target.Values))...)
return
}
n.ValueHeadComments = append(n.ValueHeadComments, target.ValueHeadComments...)
}
// SetIsFlowStyle set value to IsFlowStyle field recursively.
func (n *SequenceNode) SetIsFlowStyle(isFlow bool) {
n.IsFlowStyle = isFlow
for _, value := range n.Values {
switch value := value.(type) {
case *MappingNode:
value.SetIsFlowStyle(isFlow)
case *MappingValueNode:
value.SetIsFlowStyle(isFlow)
case *SequenceNode:
value.SetIsFlowStyle(isFlow)
}
}
}
// Read implements (io.Reader).Read
func (n *SequenceNode) Read(p []byte) (int, error) {
return readNode(p, n)
}
// Type returns SequenceType
func (n *SequenceNode) Type() NodeType { return SequenceType }
// GetToken returns token instance
func (n *SequenceNode) GetToken() *token.Token {
return n.Start
}
// AddColumn add column number to child nodes recursively
func (n *SequenceNode) AddColumn(col int) {
n.Start.AddColumn(col)
n.End.AddColumn(col)
for _, value := range n.Values {
value.AddColumn(col)
}
}
func (n *SequenceNode) flowStyleString() string {
values := []string{}
for _, value := range n.Values {
values = append(values, value.String())
}
seqText := fmt.Sprintf("[%s]", strings.Join(values, ", "))
if n.Comment != nil {
return addCommentString(seqText, n.Comment)
}
return seqText
}
func (n *SequenceNode) blockStyleString() string {
space := strings.Repeat(" ", n.Start.Position.Column-1)
values := []string{}
if n.Comment != nil {
values = append(values, n.Comment.StringWithSpace(n.Start.Position.Column-1))
}
for idx, value := range n.Values {
if value == nil {
continue
}
valueStr := value.String()
newLinePrefix := ""
if strings.HasPrefix(valueStr, "\n") {
valueStr = valueStr[1:]
newLinePrefix = "\n"
}
splittedValues := strings.Split(valueStr, "\n")
trimmedFirstValue := strings.TrimLeft(splittedValues[0], " ")
diffLength := len(splittedValues[0]) - len(trimmedFirstValue)
if len(splittedValues) > 1 && value.Type() == StringType || value.Type() == LiteralType {
// If multi-line string, the space characters for indent have already been added, so delete them.
prefix := space + " "
for i := 1; i < len(splittedValues); i++ {
splittedValues[i] = strings.TrimPrefix(splittedValues[i], prefix)
}
}
newValues := []string{trimmedFirstValue}
for i := 1; i < len(splittedValues); i++ {
if len(splittedValues[i]) <= diffLength {
// this line is \n or white space only
newValues = append(newValues, "")
continue
}
trimmed := splittedValues[i][diffLength:]
newValues = append(newValues, fmt.Sprintf("%s %s", space, trimmed))
}
newValue := strings.Join(newValues, "\n")
if len(n.ValueHeadComments) == len(n.Values) && n.ValueHeadComments[idx] != nil {
values = append(values, fmt.Sprintf("%s%s", newLinePrefix, n.ValueHeadComments[idx].StringWithSpace(n.Start.Position.Column-1)))
newLinePrefix = ""
}
values = append(values, fmt.Sprintf("%s%s- %s", newLinePrefix, space, newValue))
}
if n.FootComment != nil {
values = append(values, n.FootComment.StringWithSpace(n.Start.Position.Column-1))
}
return strings.Join(values, "\n")
}
// String sequence to text
func (n *SequenceNode) String() string {
if n.IsFlowStyle || len(n.Values) == 0 {
return n.flowStyleString()
}
return n.blockStyleString()
}
// ArrayRange implements ArrayNode protocol
func (n *SequenceNode) ArrayRange() *ArrayNodeIter {
return &ArrayNodeIter{
idx: startRangeIndex,
values: n.Values,
}
}
// MarshalYAML encodes to a YAML text
func (n *SequenceNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
// SequenceEntryNode is the sequence entry.
type SequenceEntryNode struct {
*BaseNode
HeadComment *CommentGroupNode // head comment.
LineComment *CommentGroupNode // line comment e.g.) - # comment.
Start *token.Token // entry token.
Value Node // value node.
}
// String node to text
func (n *SequenceEntryNode) String() string {
return "" // TODO
}
// GetToken returns token instance
func (n *SequenceEntryNode) GetToken() *token.Token {
return n.Start
}
// Type returns type of node
func (n *SequenceEntryNode) Type() NodeType {
return SequenceEntryType
}
// AddColumn add column number to child nodes recursively
func (n *SequenceEntryNode) AddColumn(col int) {
n.Start.AddColumn(col)
}
// SetComment set line comment.
func (n *SequenceEntryNode) SetComment(cm *CommentGroupNode) error {
n.LineComment = cm
return nil
}
// Comment returns comment token instance
func (n *SequenceEntryNode) GetComment() *CommentGroupNode {
return n.LineComment
}
// MarshalYAML
func (n *SequenceEntryNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
func (n *SequenceEntryNode) Read(p []byte) (int, error) {
return readNode(p, n)
}
// SequenceEntry creates SequenceEntryNode instance.
func SequenceEntry(start *token.Token, value Node, headComment *CommentGroupNode) *SequenceEntryNode {
return &SequenceEntryNode{
BaseNode: &BaseNode{},
HeadComment: headComment,
Start: start,
Value: value,
}
}
// SequenceMergeValue creates SequenceMergeValueNode instance.
func SequenceMergeValue(values ...MapNode) *SequenceMergeValueNode {
return &SequenceMergeValueNode{
values: values,
}
}
// SequenceMergeValueNode is used to convert the Sequence node specified for the merge key into a MapNode format.
type SequenceMergeValueNode struct {
values []MapNode
}
// MapRange returns MapNodeIter instance.
func (n *SequenceMergeValueNode) MapRange() *MapNodeIter {
ret := &MapNodeIter{idx: startRangeIndex}
for _, value := range n.values {
iter := value.MapRange()
ret.values = append(ret.values, iter.values...)
}
return ret
}
// AnchorNode type of anchor node
type AnchorNode struct {
*BaseNode
Start *token.Token
Name Node
Value Node
}
func (n *AnchorNode) stringWithoutComment() string {
return n.Value.String()
}
func (n *AnchorNode) SetName(name string) error {
if n.Name == nil {
return ErrInvalidAnchorName
}
s, ok := n.Name.(*StringNode)
if !ok {
return ErrInvalidAnchorName
}
s.Value = name
return nil
}
// Read implements (io.Reader).Read
func (n *AnchorNode) Read(p []byte) (int, error) {
return readNode(p, n)
}
// Type returns AnchorType
func (n *AnchorNode) Type() NodeType { return AnchorType }
// GetToken returns token instance
func (n *AnchorNode) GetToken() *token.Token {
return n.Start
}
func (n *AnchorNode) GetValue() any {
return n.Value.GetToken().Value
}
// AddColumn add column number to child nodes recursively
func (n *AnchorNode) AddColumn(col int) {
n.Start.AddColumn(col)
if n.Name != nil {
n.Name.AddColumn(col)
}
if n.Value != nil {
n.Value.AddColumn(col)
}
}
// String anchor to text
func (n *AnchorNode) String() string {
anchor := "&" + n.Name.String()
value := n.Value.String()
if s, ok := n.Value.(*SequenceNode); ok && !s.IsFlowStyle {
return fmt.Sprintf("%s\n%s", anchor, value)
} else if m, ok := n.Value.(*MappingNode); ok && !m.IsFlowStyle {
return fmt.Sprintf("%s\n%s", anchor, value)
}
if value == "" {
// implicit null value.
return anchor
}
return fmt.Sprintf("%s %s", anchor, value)
}
// MarshalYAML encodes to a YAML text
func (n *AnchorNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
// IsMergeKey returns whether it is a MergeKey node.
func (n *AnchorNode) IsMergeKey() bool {
if n.Value == nil {
return false
}
key, ok := n.Value.(MapKeyNode)
if !ok {
return false
}
return key.IsMergeKey()
}
// AliasNode type of alias node
type AliasNode struct {
*BaseNode
Start *token.Token
Value Node
}
func (n *AliasNode) stringWithoutComment() string {
return n.Value.String()
}
func (n *AliasNode) SetName(name string) error {
if n.Value == nil {
return ErrInvalidAliasName
}
s, ok := n.Value.(*StringNode)
if !ok {
return ErrInvalidAliasName
}
s.Value = name
return nil
}
// Read implements (io.Reader).Read
func (n *AliasNode) Read(p []byte) (int, error) {
return readNode(p, n)
}
// Type returns AliasType
func (n *AliasNode) Type() NodeType { return AliasType }
// GetToken returns token instance
func (n *AliasNode) GetToken() *token.Token {
return n.Start
}
func (n *AliasNode) GetValue() any {
return n.Value.GetToken().Value
}
// AddColumn add column number to child nodes recursively
func (n *AliasNode) AddColumn(col int) {
n.Start.AddColumn(col)
if n.Value != nil {
n.Value.AddColumn(col)
}
}
// String alias to text
func (n *AliasNode) String() string {
return fmt.Sprintf("*%s", n.Value.String())
}
// MarshalYAML encodes to a YAML text
func (n *AliasNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
// IsMergeKey returns whether it is a MergeKey node.
func (n *AliasNode) IsMergeKey() bool {
return false
}
// DirectiveNode type of directive node
type DirectiveNode struct {
*BaseNode
// Start is '%' token.
Start *token.Token
// Name is directive name e.g.) "YAML" or "TAG".
Name Node
// Values is directive values e.g.) "1.2" or "!!" and "tag:clarkevans.com,2002:app/".
Values []Node
}
// Read implements (io.Reader).Read
func (n *DirectiveNode) Read(p []byte) (int, error) {
return readNode(p, n)
}
// Type returns DirectiveType
func (n *DirectiveNode) Type() NodeType { return DirectiveType }
// GetToken returns token instance
func (n *DirectiveNode) GetToken() *token.Token {
return n.Start
}
// AddColumn add column number to child nodes recursively
func (n *DirectiveNode) AddColumn(col int) {
if n.Name != nil {
n.Name.AddColumn(col)
}
for _, value := range n.Values {
value.AddColumn(col)
}
}
// String directive to text
func (n *DirectiveNode) String() string {
values := make([]string, 0, len(n.Values))
for _, val := range n.Values {
values = append(values, val.String())
}
return strings.Join(append([]string{"%" + n.Name.String()}, values...), " ")
}
// MarshalYAML encodes to a YAML text
func (n *DirectiveNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
// TagNode type of tag node
type TagNode struct {
*BaseNode
Directive *DirectiveNode
Start *token.Token
Value Node
}
func (n *TagNode) GetValue() any {
scalar, ok := n.Value.(ScalarNode)
if !ok {
return nil
}
return scalar.GetValue()
}
func (n *TagNode) stringWithoutComment() string {
return n.Value.String()
}
// Read implements (io.Reader).Read
func (n *TagNode) Read(p []byte) (int, error) {
return readNode(p, n)
}
// Type returns TagType
func (n *TagNode) Type() NodeType { return TagType }
// GetToken returns token instance
func (n *TagNode) GetToken() *token.Token {
return n.Start
}
// AddColumn add column number to child nodes recursively
func (n *TagNode) AddColumn(col int) {
n.Start.AddColumn(col)
if n.Value != nil {
n.Value.AddColumn(col)
}
}
// String tag to text
func (n *TagNode) String() string {
value := n.Value.String()
if s, ok := n.Value.(*SequenceNode); ok && !s.IsFlowStyle {
return fmt.Sprintf("%s\n%s", n.Start.Value, value)
} else if m, ok := n.Value.(*MappingNode); ok && !m.IsFlowStyle {
return fmt.Sprintf("%s\n%s", n.Start.Value, value)
}
return fmt.Sprintf("%s %s", n.Start.Value, value)
}
// MarshalYAML encodes to a YAML text
func (n *TagNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
// IsMergeKey returns whether it is a MergeKey node.
func (n *TagNode) IsMergeKey() bool {
if n.Value == nil {
return false
}
key, ok := n.Value.(MapKeyNode)
if !ok {
return false
}
return key.IsMergeKey()
}
func (n *TagNode) ArrayRange() *ArrayNodeIter {
arr, ok := n.Value.(ArrayNode)
if !ok {
return nil
}
return arr.ArrayRange()
}
// CommentNode type of comment node
type CommentNode struct {
*BaseNode
Token *token.Token
}
// Read implements (io.Reader).Read
func (n *CommentNode) Read(p []byte) (int, error) {
return readNode(p, n)
}
// Type returns TagType
func (n *CommentNode) Type() NodeType { return CommentType }
// GetToken returns token instance
func (n *CommentNode) GetToken() *token.Token { return n.Token }
// AddColumn add column number to child nodes recursively
func (n *CommentNode) AddColumn(col int) {
if n.Token == nil {
return
}
n.Token.AddColumn(col)
}
// String comment to text
func (n *CommentNode) String() string {
return fmt.Sprintf("#%s", n.Token.Value)
}
// MarshalYAML encodes to a YAML text
func (n *CommentNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
// CommentGroupNode type of comment node
type CommentGroupNode struct {
*BaseNode
Comments []*CommentNode
}
// Read implements (io.Reader).Read
func (n *CommentGroupNode) Read(p []byte) (int, error) {
return readNode(p, n)
}
// Type returns TagType
func (n *CommentGroupNode) Type() NodeType { return CommentType }
// GetToken returns token instance
func (n *CommentGroupNode) GetToken() *token.Token {
if len(n.Comments) > 0 {
return n.Comments[0].Token
}
return nil
}
// AddColumn add column number to child nodes recursively
func (n *CommentGroupNode) AddColumn(col int) {
for _, comment := range n.Comments {
comment.AddColumn(col)
}
}
// String comment to text
func (n *CommentGroupNode) String() string {
values := []string{}
for _, comment := range n.Comments {
values = append(values, comment.String())
}
return strings.Join(values, "\n")
}
func (n *CommentGroupNode) StringWithSpace(col int) string {
values := []string{}
space := strings.Repeat(" ", col)
for _, comment := range n.Comments {
space := space
if checkLineBreak(comment.Token) {
space = fmt.Sprintf("%s%s", "\n", space)
}
values = append(values, space+comment.String())
}
return strings.Join(values, "\n")
}
// MarshalYAML encodes to a YAML text
func (n *CommentGroupNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
// Visitor has Visit method that is invokded for each node encountered by Walk.
// If the result visitor w is not nil, Walk visits each of the children of node with the visitor w,
// followed by a call of w.Visit(nil).
type Visitor interface {
Visit(Node) Visitor
}
// Walk traverses an AST in depth-first order: It starts by calling v.Visit(node); node must not be nil.
// If the visitor w returned by v.Visit(node) is not nil,
// Walk is invoked recursively with visitor w for each of the non-nil children of node,
// followed by a call of w.Visit(nil).
func Walk(v Visitor, node Node) {
if v = v.Visit(node); v == nil {
return
}
switch n := node.(type) {
case *CommentNode:
case *NullNode:
walkComment(v, n.BaseNode)
case *IntegerNode:
walkComment(v, n.BaseNode)
case *FloatNode:
walkComment(v, n.BaseNode)
case *StringNode:
walkComment(v, n.BaseNode)
case *MergeKeyNode:
walkComment(v, n.BaseNode)
case *BoolNode:
walkComment(v, n.BaseNode)
case *InfinityNode:
walkComment(v, n.BaseNode)
case *NanNode:
walkComment(v, n.BaseNode)
case *LiteralNode:
walkComment(v, n.BaseNode)
Walk(v, n.Value)
case *DirectiveNode:
walkComment(v, n.BaseNode)
Walk(v, n.Name)
for _, value := range n.Values {
Walk(v, value)
}
case *TagNode:
walkComment(v, n.BaseNode)
Walk(v, n.Value)
case *DocumentNode:
walkComment(v, n.BaseNode)
Walk(v, n.Body)
case *MappingNode:
walkComment(v, n.BaseNode)
for _, value := range n.Values {
Walk(v, value)
}
case *MappingKeyNode:
walkComment(v, n.BaseNode)
Walk(v, n.Value)
case *MappingValueNode:
walkComment(v, n.BaseNode)
Walk(v, n.Key)
Walk(v, n.Value)
case *SequenceNode:
walkComment(v, n.BaseNode)
for _, value := range n.Values {
Walk(v, value)
}
case *AnchorNode:
walkComment(v, n.BaseNode)
Walk(v, n.Name)
Walk(v, n.Value)
case *AliasNode:
walkComment(v, n.BaseNode)
Walk(v, n.Value)
}
}
func walkComment(v Visitor, base *BaseNode) {
if base == nil {
return
}
if base.Comment == nil {
return
}
Walk(v, base.Comment)
}
type filterWalker struct {
typ NodeType
results []Node
}
func (v *filterWalker) Visit(n Node) Visitor {
if v.typ == n.Type() {
v.results = append(v.results, n)
}
return v
}
type parentFinder struct {
target Node
}
func (f *parentFinder) walk(parent, node Node) Node {
if f.target == node {
return parent
}
switch n := node.(type) {
case *CommentNode:
return nil
case *NullNode:
return nil
case *IntegerNode:
return nil
case *FloatNode:
return nil
case *StringNode:
return nil
case *MergeKeyNode:
return nil
case *BoolNode:
return nil
case *InfinityNode:
return nil
case *NanNode:
return nil
case *LiteralNode:
return f.walk(node, n.Value)
case *DirectiveNode:
if found := f.walk(node, n.Name); found != nil {
return found
}
for _, value := range n.Values {
if found := f.walk(node, value); found != nil {
return found
}
}
case *TagNode:
return f.walk(node, n.Value)
case *DocumentNode:
return f.walk(node, n.Body)
case *MappingNode:
for _, value := range n.Values {
if found := f.walk(node, value); found != nil {
return found
}
}
case *MappingKeyNode:
return f.walk(node, n.Value)
case *MappingValueNode:
if found := f.walk(node, n.Key); found != nil {
return found
}
return f.walk(node, n.Value)
case *SequenceNode:
for _, value := range n.Values {
if found := f.walk(node, value); found != nil {
return found
}
}
case *AnchorNode:
if found := f.walk(node, n.Name); found != nil {
return found
}
return f.walk(node, n.Value)
case *AliasNode:
return f.walk(node, n.Value)
}
return nil
}
// Parent get parent node from child node.
func Parent(root, child Node) Node {
finder := &parentFinder{target: child}
return finder.walk(root, root)
}
// Filter returns a list of nodes that match the given type.
func Filter(typ NodeType, node Node) []Node {
walker := &filterWalker{typ: typ}
Walk(walker, node)
return walker.results
}
// FilterFile returns a list of nodes that match the given type.
func FilterFile(typ NodeType, file *File) []Node {
results := []Node{}
for _, doc := range file.Docs {
walker := &filterWalker{typ: typ}
Walk(walker, doc)
results = append(results, walker.results...)
}
return results
}
type ErrInvalidMergeType struct {
dst Node
src Node
}
func (e *ErrInvalidMergeType) Error() string {
return fmt.Sprintf("cannot merge %s into %s", e.src.Type(), e.dst.Type())
}
// Merge merge document, map, sequence node.
func Merge(dst Node, src Node) error {
if doc, ok := src.(*DocumentNode); ok {
src = doc.Body
}
err := &ErrInvalidMergeType{dst: dst, src: src}
switch dst.Type() {
case DocumentType:
node, _ := dst.(*DocumentNode)
return Merge(node.Body, src)
case MappingType:
node, _ := dst.(*MappingNode)
target, ok := src.(*MappingNode)
if !ok {
return err
}
node.Merge(target)
return nil
case SequenceType:
node, _ := dst.(*SequenceNode)
target, ok := src.(*SequenceNode)
if !ok {
return err
}
node.Merge(target)
return nil
}
return err
}
================================================
FILE: vendor/github.com/goccy/go-yaml/context.go
================================================
package yaml
import "context"
type (
ctxMergeKey struct{}
ctxAnchorKey struct{}
)
func withMerge(ctx context.Context) context.Context {
return context.WithValue(ctx, ctxMergeKey{}, true)
}
func isMerge(ctx context.Context) bool {
v, ok := ctx.Value(ctxMergeKey{}).(bool)
if !ok {
return false
}
return v
}
func withAnchor(ctx context.Context, name string) context.Context {
anchorMap := getAnchorMap(ctx)
if anchorMap == nil {
anchorMap = make(map[string]struct{})
}
anchorMap[name] = struct{}{}
return context.WithValue(ctx, ctxAnchorKey{}, anchorMap)
}
func getAnchorMap(ctx context.Context) map[string]struct{} {
v, ok := ctx.Value(ctxAnchorKey{}).(map[string]struct{})
if !ok {
return nil
}
return v
}
================================================
FILE: vendor/github.com/goccy/go-yaml/decode.go
================================================
package yaml
import (
"bytes"
"context"
"encoding"
"encoding/base64"
"fmt"
"io"
"maps"
"math"
"os"
"path/filepath"
"reflect"
"sort"
"strconv"
"strings"
"time"
"github.com/goccy/go-yaml/ast"
"github.com/goccy/go-yaml/internal/errors"
"github.com/goccy/go-yaml/internal/format"
"github.com/goccy/go-yaml/parser"
"github.com/goccy/go-yaml/token"
)
// Decoder reads and decodes YAML values from an input stream.
type Decoder struct {
reader io.Reader
referenceReaders []io.Reader
anchorNodeMap map[string]ast.Node
anchorValueMap map[string]reflect.Value
customUnmarshalerMap map[reflect.Type]func(context.Context, interface{}, []byte) error
commentMaps []CommentMap
toCommentMap CommentMap
opts []DecodeOption
referenceFiles []string
referenceDirs []string
isRecursiveDir bool
isResolvedReference bool
validator StructValidator
disallowUnknownField bool
allowedFieldPrefixes []string
allowDuplicateMapKey bool
useOrderedMap bool
useJSONUnmarshaler bool
parsedFile *ast.File
streamIndex int
decodeDepth int
}
// NewDecoder returns a new decoder that reads from r.
func NewDecoder(r io.Reader, opts ...DecodeOption) *Decoder {
return &Decoder{
reader: r,
anchorNodeMap: map[string]ast.Node{},
anchorValueMap: map[string]reflect.Value{},
customUnmarshalerMap: map[reflect.Type]func(context.Context, interface{}, []byte) error{},
opts: opts,
referenceReaders: []io.Reader{},
referenceFiles: []string{},
referenceDirs: []string{},
isRecursiveDir: false,
isResolvedReference: false,
disallowUnknownField: false,
allowDuplicateMapKey: false,
useOrderedMap: false,
}
}
const maxDecodeDepth = 10000
func (d *Decoder) stepIn() {
d.decodeDepth++
}
func (d *Decoder) stepOut() {
d.decodeDepth--
}
func (d *Decoder) isExceededMaxDepth() bool {
return d.decodeDepth > maxDecodeDepth
}
func (d *Decoder) castToFloat(v interface{}) interface{} {
switch vv := v.(type) {
case int:
return float64(vv)
case int8:
return float64(vv)
case int16:
return float64(vv)
case int32:
return float64(vv)
case int64:
return float64(vv)
case uint:
return float64(vv)
case uint8:
return float64(vv)
case uint16:
return float64(vv)
case uint32:
return float64(vv)
case uint64:
return float64(vv)
case float32:
return float64(vv)
case float64:
return vv
case string:
// if error occurred, return zero value
f, _ := strconv.ParseFloat(vv, 64)
return f
}
return 0
}
func (d *Decoder) mapKeyNodeToString(ctx context.Context, node ast.MapKeyNode) (string, error) {
key, err := d.nodeToValue(ctx, node)
if err != nil {
return "", err
}
if key == nil {
return "null", nil
}
if k, ok := key.(string); ok {
return k, nil
}
return fmt.Sprint(key), nil
}
func (d *Decoder) setToMapValue(ctx context.Context, node ast.Node, m map[string]interface{}) error {
d.stepIn()
defer d.stepOut()
if d.isExceededMaxDepth() {
return ErrExceededMaxDepth
}
d.setPathToCommentMap(node)
switch n := node.(type) {
case *ast.MappingValueNode:
if n.Key.IsMergeKey() {
value, err := d.getMapNode(n.Value, true)
if err != nil {
return err
}
iter := value.MapRange()
for iter.Next() {
if err := d.setToMapValue(ctx, iter.KeyValue(), m); err != nil {
return err
}
}
} else {
key, err := d.mapKeyNodeToString(ctx, n.Key)
if err != nil {
return err
}
v, err := d.nodeToValue(ctx, n.Value)
if err != nil {
return err
}
m[key] = v
}
case *ast.MappingNode:
for _, value := range n.Values {
if err := d.setToMapValue(ctx, value, m); err != nil {
return err
}
}
case *ast.AnchorNode:
anchorName := n.Name.GetToken().Value
d.anchorNodeMap[anchorName] = n.Value
}
return nil
}
func (d *Decoder) setToOrderedMapValue(ctx context.Context, node ast.Node, m *MapSlice) error {
d.stepIn()
defer d.stepOut()
if d.isExceededMaxDepth() {
return ErrExceededMaxDepth
}
d.setPathToCommentMap(node)
switch n := node.(type) {
case *ast.MappingValueNode:
if n.Key.IsMergeKey() {
value, err := d.getMapNode(n.Value, true)
if err != nil {
return err
}
iter := value.MapRange()
for iter.Next() {
if err := d.setToOrderedMapValue(ctx, iter.KeyValue(), m); err != nil {
return err
}
}
} else {
key, err := d.mapKeyNodeToString(ctx, n.Key)
if err != nil {
return err
}
value, err := d.nodeToValue(ctx, n.Value)
if err != nil {
return err
}
*m = append(*m, MapItem{Key: key, Value: value})
}
case *ast.MappingNode:
for _, value := range n.Values {
if err := d.setToOrderedMapValue(ctx, value, m); err != nil {
return err
}
}
}
return nil
}
func (d *Decoder) setPathToCommentMap(node ast.Node) {
if node == nil {
return
}
if d.toCommentMap == nil {
return
}
d.addHeadOrLineCommentToMap(node)
d.addFootCommentToMap(node)
}
func (d *Decoder) addHeadOrLineCommentToMap(node ast.Node) {
sequence, ok := node.(*ast.SequenceNode)
if ok {
d.addSequenceNodeCommentToMap(sequence)
return
}
commentGroup := node.GetComment()
if commentGroup == nil {
return
}
texts := []string{}
targetLine := node.GetToken().Position.Line
minCommentLine := math.MaxInt
for _, comment := range commentGroup.Comments {
if minCommentLine > comment.Token.Position.Line {
minCommentLine = comment.Token.Position.Line
}
texts = append(texts, comment.Token.Value)
}
if len(texts) == 0 {
return
}
commentPath := node.GetPath()
if minCommentLine < targetLine {
switch n := node.(type) {
case *ast.MappingNode:
if len(n.Values) != 0 {
commentPath = n.Values[0].Key.GetPath()
}
case *ast.MappingValueNode:
commentPath = n.Key.GetPath()
}
d.addCommentToMap(commentPath, HeadComment(texts...))
} else {
d.addCommentToMap(commentPath, LineComment(texts[0]))
}
}
func (d *Decoder) addSequenceNodeCommentToMap(node *ast.SequenceNode) {
if len(node.ValueHeadComments) != 0 {
for idx, headComment := range node.ValueHeadComments {
if headComment == nil {
continue
}
texts := make([]string, 0, len(headComment.Comments))
for _, comment := range headComment.Comments {
texts = append(texts, comment.Token.Value)
}
if len(texts) != 0 {
d.addCommentToMap(node.Values[idx].GetPath(), HeadComment(texts...))
}
}
}
firstElemHeadComment := node.GetComment()
if firstElemHeadComment != nil {
texts := make([]string, 0, len(firstElemHeadComment.Comments))
for _, comment := range firstElemHeadComment.Comments {
texts = append(texts, comment.Token.Value)
}
if len(texts) != 0 {
if len(node.Values) != 0 {
d.addCommentToMap(node.Values[0].GetPath(), HeadComment(texts...))
}
}
}
}
func (d *Decoder) addFootCommentToMap(node ast.Node) {
var (
footComment *ast.CommentGroupNode
footCommentPath = node.GetPath()
)
switch n := node.(type) {
case *ast.SequenceNode:
footComment = n.FootComment
if n.FootComment != nil {
footCommentPath = n.FootComment.GetPath()
}
case *ast.MappingNode:
footComment = n.FootComment
if n.FootComment != nil {
footCommentPath = n.FootComment.GetPath()
}
case *ast.MappingValueNode:
footComment = n.FootComment
if n.FootComment != nil {
footCommentPath = n.FootComment.GetPath()
}
}
if footComment == nil {
return
}
var texts []string
for _, comment := range footComment.Comments {
texts = append(texts, comment.Token.Value)
}
if len(texts) != 0 {
d.addCommentToMap(footCommentPath, FootComment(texts...))
}
}
func (d *Decoder) addCommentToMap(path string, comment *Comment) {
for _, c := range d.toCommentMap[path] {
if c.Position == comment.Position {
// already added same comment
return
}
}
d.toCommentMap[path] = append(d.toCommentMap[path], comment)
sort.Slice(d.toCommentMap[path], func(i, j int) bool {
return d.toCommentMap[path][i].Position < d.toCommentMap[path][j].Position
})
}
func (d *Decoder) nodeToValue(ctx context.Context, node ast.Node) (any, error) {
d.stepIn()
defer d.stepOut()
if d.isExceededMaxDepth() {
return nil, ErrExceededMaxDepth
}
d.setPathToCommentMap(node)
switch n := node.(type) {
case *ast.NullNode:
return nil, nil
case *ast.StringNode:
return n.GetValue(), nil
case *ast.IntegerNode:
return n.GetValue(), nil
case *ast.FloatNode:
return n.GetValue(), nil
case *ast.BoolNode:
return n.GetValue(), nil
case *ast.InfinityNode:
return n.GetValue(), nil
case *ast.NanNode:
return n.GetValue(), nil
case *ast.TagNode:
if n.Directive != nil {
v, err := d.nodeToValue(ctx, n.Value)
if err != nil {
return nil, err
}
if v == nil {
return "", nil
}
return fmt.Sprint(v), nil
}
switch token.ReservedTagKeyword(n.Start.Value) {
case token.TimestampTag:
t, _ := d.castToTime(ctx, n.Value)
return t, nil
case token.IntegerTag:
v, err := d.nodeToValue(ctx, n.Value)
if err != nil {
return nil, err
}
i, _ := strconv.Atoi(fmt.Sprint(v))
return i, nil
case token.FloatTag:
v, err := d.nodeToValue(ctx, n.Value)
if err != nil {
return nil, err
}
return d.castToFloat(v), nil
case token.NullTag:
return nil, nil
case token.BinaryTag:
v, err := d.nodeToValue(ctx, n.Value)
if err != nil {
return nil, err
}
str, ok := v.(string)
if !ok {
return nil, errors.ErrSyntax(
fmt.Sprintf("cannot convert %q to string", fmt.Sprint(v)),
n.Value.GetToken(),
)
}
b, _ := base64.StdEncoding.DecodeString(str)
return b, nil
case token.BooleanTag:
v, err := d.nodeToValue(ctx, n.Value)
if err != nil {
return nil, err
}
str := strings.ToLower(fmt.Sprint(v))
b, err := strconv.ParseBool(str)
if err == nil {
return b, nil
}
switch str {
case "yes":
return true, nil
case "no":
return false, nil
}
return nil, errors.ErrSyntax(fmt.Sprintf("cannot convert %q to boolean", fmt.Sprint(v)), n.Value.GetToken())
case token.StringTag:
v, err := d.nodeToValue(ctx, n.Value)
if err != nil {
return nil, err
}
if v == nil {
return "", nil
}
return fmt.Sprint(v), nil
case token.MappingTag:
return d.nodeToValue(ctx, n.Value)
default:
return d.nodeToValue(ctx, n.Value)
}
case *ast.AnchorNode:
anchorName := n.Name.GetToken().Value
// To handle the case where alias is processed recursively, the result of alias can be set to nil in advance.
d.anchorNodeMap[anchorName] = nil
anchorValue, err := d.nodeToValue(withAnchor(ctx, anchorName), n.Value)
if err != nil {
delete(d.anchorNodeMap, anchorName)
return nil, err
}
d.anchorNodeMap[anchorName] = n.Value
d.anchorValueMap[anchorName] = reflect.ValueOf(anchorValue)
return anchorValue, nil
case *ast.AliasNode:
text := n.Value.String()
if _, exists := getAnchorMap(ctx)[text]; exists {
// self recursion.
return nil, nil
}
if v, exists := d.anchorValueMap[text]; exists {
if !v.IsValid() {
return nil, nil
}
return v.Interface(), nil
}
if node, exists := d.anchorNodeMap[text]; exists {
return d.nodeToValue(ctx, node)
}
return nil, errors.ErrSyntax(fmt.Sprintf("could not find alias %q", text), n.Value.GetToken())
case *ast.LiteralNode:
return n.Value.GetValue(), nil
case *ast.MappingKeyNode:
return d.nodeToValue(ctx, n.Value)
case *ast.MappingValueNode:
if n.Key.IsMergeKey() {
value, err := d.getMapNode(n.Value, true)
if err != nil {
return nil, err
}
iter := value.MapRange()
if d.useOrderedMap {
m := MapSlice{}
for iter.Next() {
if err := d.setToOrderedMapValue(ctx, iter.KeyValue(), &m); err != nil {
return nil, err
}
}
return m, nil
}
m := make(map[string]any)
for iter.Next() {
if err := d.setToMapValue(ctx, iter.KeyValue(), m); err != nil {
return nil, err
}
}
return m, nil
}
key, err := d.mapKeyNodeToString(ctx, n.Key)
if err != nil {
return nil, err
}
if d.useOrderedMap {
v, err := d.nodeToValue(ctx, n.Value)
if err != nil {
return nil, err
}
return MapSlice{{Key: key, Value: v}}, nil
}
v, err := d.nodeToValue(ctx, n.Value)
if err != nil {
return nil, err
}
return map[string]interface{}{key: v}, nil
case *ast.MappingNode:
if d.useOrderedMap {
m := make(MapSlice, 0, len(n.Values))
for _, value := range n.Values {
if err := d.setToOrderedMapValue(ctx, value, &m); err != nil {
return nil, err
}
}
return m, nil
}
m := make(map[string]interface{}, len(n.Values))
for _, value := range n.Values {
if err := d.setToMapValue(ctx, value, m); err != nil {
return nil, err
}
}
return m, nil
case *ast.SequenceNode:
v := make([]interface{}, 0, len(n.Values))
for _, value := range n.Values {
vv, err := d.nodeToValue(ctx, value)
if err != nil {
return nil, err
}
v = append(v, vv)
}
return v, nil
}
return nil, nil
}
func (d *Decoder) getMapNode(node ast.Node, isMerge bool) (ast.MapNode, error) {
d.stepIn()
defer d.stepOut()
if d.isExceededMaxDepth() {
return nil, ErrExceededMaxDepth
}
switch n := node.(type) {
case ast.MapNode:
return n, nil
case *ast.AnchorNode:
anchorName := n.Name.GetToken().Value
d.anchorNodeMap[anchorName] = n.Value
return d.getMapNode(n.Value, isMerge)
case *ast.AliasNode:
aliasName := n.Value.GetToken().Value
node := d.anchorNodeMap[aliasName]
if node == nil {
return nil, fmt.Errorf("cannot find anchor by alias name %s", aliasName)
}
return d.getMapNode(node, isMerge)
case *ast.SequenceNode:
if !isMerge {
return nil, errors.ErrUnexpectedNodeType(node.Type(), ast.MappingType, node.GetToken())
}
var mapNodes []ast.MapNode
for _, value := range n.Values {
mapNode, err := d.getMapNode(value, false)
if err != nil {
return nil, err
}
mapNodes = append(mapNodes, mapNode)
}
return ast.SequenceMergeValue(mapNodes...), nil
}
return nil, errors.ErrUnexpectedNodeType(node.Type(), ast.MappingType, node.GetToken())
}
func (d *Decoder) getArrayNode(node ast.Node) (ast.ArrayNode, error) {
d.stepIn()
defer d.stepOut()
if d.isExceededMaxDepth() {
return nil, ErrExceededMaxDepth
}
if _, ok := node.(*ast.NullNode); ok {
return nil, nil
}
if anchor, ok := node.(*ast.AnchorNode); ok {
arrayNode, ok := anchor.Value.(ast.ArrayNode)
if ok {
return arrayNode, nil
}
return nil, errors.ErrUnexpectedNodeType(anchor.Value.Type(), ast.SequenceType, node.GetToken())
}
if alias, ok := node.(*ast.AliasNode); ok {
aliasName := alias.Value.GetToken().Value
node := d.anchorNodeMap[aliasName]
if node == nil {
return nil, fmt.Errorf("cannot find anchor by alias name %s", aliasName)
}
arrayNode, ok := node.(ast.ArrayNode)
if ok {
return arrayNode, nil
}
return nil, errors.ErrUnexpectedNodeType(node.Type(), ast.SequenceType, node.GetToken())
}
arrayNode, ok := node.(ast.ArrayNode)
if !ok {
return nil, errors.ErrUnexpectedNodeType(node.Type(), ast.SequenceType, node.GetToken())
}
return arrayNode, nil
}
func (d *Decoder) convertValue(v reflect.Value, typ reflect.Type, src ast.Node) (reflect.Value, error) {
if typ.Kind() != reflect.String {
if !v.Type().ConvertibleTo(typ) {
// Special case for "strings -> floats" aka scientific notation
// If the destination type is a float and the source type is a string, check if we can
// use strconv.ParseFloat to convert the string to a float.
if (typ.Kind() == reflect.Float32 || typ.Kind() == reflect.Float64) &&
v.Type().Kind() == reflect.String {
if f, err := strconv.ParseFloat(v.String(), 64); err == nil {
if typ.Kind() == reflect.Float32 {
return reflect.ValueOf(float32(f)), nil
} else if typ.Kind() == reflect.Float64 {
return reflect.ValueOf(f), nil
}
// else, fall through to the error below
}
}
return reflect.Zero(typ), errors.ErrTypeMismatch(typ, v.Type(), src.GetToken())
}
return v.Convert(typ), nil
}
// cast value to string
var strVal string
switch v.Type().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
strVal = strconv.FormatInt(v.Int(), 10)
case reflect.Float32, reflect.Float64:
strVal = fmt.Sprint(v.Float())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
strVal = strconv.FormatUint(v.Uint(), 10)
case reflect.Bool:
strVal = strconv.FormatBool(v.Bool())
default:
if !v.Type().ConvertibleTo(typ) {
return reflect.Zero(typ), errors.ErrTypeMismatch(typ, v.Type(), src.GetToken())
}
return v.Convert(typ), nil
}
val := reflect.ValueOf(strVal)
if val.Type() != typ {
// Handle named types, e.g., `type MyString string`
val = val.Convert(typ)
}
return val, nil
}
func (d *Decoder) deleteStructKeys(structType reflect.Type, unknownFields map[string]ast.Node) error {
if structType.Kind() == reflect.Ptr {
structType = structType.Elem()
}
structFieldMap, err := structFieldMap(structType)
if err != nil {
return err
}
for j := 0; j < structType.NumField(); j++ {
field := structType.Field(j)
if isIgnoredStructField(field) {
continue
}
structField, exists := structFieldMap[field.Name]
if !exists {
continue
}
if structField.IsInline {
_ = d.deleteStructKeys(field.Type, unknownFields)
} else {
delete(unknownFields, structField.RenderName)
}
}
return nil
}
func (d *Decoder) unmarshalableDocument(node ast.Node) ([]byte, error) {
doc := format.FormatNodeWithResolvedAlias(node, d.anchorNodeMap)
return []byte(doc), nil
}
func (d *Decoder) unmarshalableText(node ast.Node) ([]byte, bool) {
doc := format.FormatNodeWithResolvedAlias(node, d.anchorNodeMap)
var v string
if err := Unmarshal([]byte(doc), &v); err != nil {
return nil, false
}
return []byte(v), true
}
type jsonUnmarshaler interface {
UnmarshalJSON([]byte) error
}
func (d *Decoder) existsTypeInCustomUnmarshalerMap(t reflect.Type) bool {
if _, exists := d.customUnmarshalerMap[t]; exists {
return true
}
globalCustomUnmarshalerMu.Lock()
defer globalCustomUnmarshalerMu.Unlock()
if _, exists := globalCustomUnmarshalerMap[t]; exists {
return true
}
return false
}
func (d *Decoder) unmarshalerFromCustomUnmarshalerMap(t reflect.Type) (func(context.Context, interface{}, []byte) error, bool) {
if unmarshaler, exists := d.customUnmarshalerMap[t]; exists {
return unmarshaler, exists
}
globalCustomUnmarshalerMu.Lock()
defer globalCustomUnmarshalerMu.Unlock()
if unmarshaler, exists := globalCustomUnmarshalerMap[t]; exists {
return unmarshaler, exists
}
return nil, false
}
func (d *Decoder) canDecodeByUnmarshaler(dst reflect.Value) bool {
ptrValue := dst.Addr()
if d.existsTypeInCustomUnmarshalerMap(ptrValue.Type()) {
return true
}
iface := ptrValue.Interface()
switch iface.(type) {
case BytesUnmarshalerContext,
BytesUnmarshaler,
InterfaceUnmarshalerContext,
InterfaceUnmarshaler,
NodeUnmarshaler,
NodeUnmarshalerContext,
*time.Time,
*time.Duration,
encoding.TextUnmarshaler:
return true
case jsonUnmarshaler:
return d.useJSONUnmarshaler
}
return false
}
func (d *Decoder) decodeByUnmarshaler(ctx context.Context, dst reflect.Value, src ast.Node) error {
ptrValue := dst.Addr()
if unmarshaler, exists := d.unmarshalerFromCustomUnmarshalerMap(ptrValue.Type()); exists {
b, err := d.unmarshalableDocument(src)
if err != nil {
return err
}
if err := unmarshaler(ctx, ptrValue.Interface(), b); err != nil {
return err
}
return nil
}
iface := ptrValue.Interface()
if unmarshaler, ok := iface.(BytesUnmarshalerContext); ok {
b, err := d.unmarshalableDocument(src)
if err != nil {
return err
}
if err := unmarshaler.UnmarshalYAML(ctx, b); err != nil {
return err
}
return nil
}
if unmarshaler, ok := iface.(BytesUnmarshaler); ok {
b, err := d.unmarshalableDocument(src)
if err != nil {
return err
}
if err := unmarshaler.UnmarshalYAML(b); err != nil {
return err
}
return nil
}
if unmarshaler, ok := iface.(InterfaceUnmarshalerContext); ok {
if err := unmarshaler.UnmarshalYAML(ctx, func(v interface{}) error {
rv := reflect.ValueOf(v)
if rv.Type().Kind() != reflect.Ptr {
return ErrDecodeRequiredPointerType
}
if err := d.decodeValue(ctx, rv.Elem(), src); err != nil {
return err
}
return nil
}); err != nil {
return err
}
return nil
}
if unmarshaler, ok := iface.(InterfaceUnmarshaler); ok {
if err := unmarshaler.UnmarshalYAML(func(v interface{}) error {
rv := reflect.ValueOf(v)
if rv.Type().Kind() != reflect.Ptr {
return ErrDecodeRequiredPointerType
}
if err := d.decodeValue(ctx, rv.Elem(), src); err != nil {
return err
}
return nil
}); err != nil {
return err
}
return nil
}
if unmarshaler, ok := iface.(NodeUnmarshaler); ok {
if err := unmarshaler.UnmarshalYAML(src); err != nil {
return err
}
return nil
}
if unmarshaler, ok := iface.(NodeUnmarshalerContext); ok {
if err := unmarshaler.UnmarshalYAML(ctx, src); err != nil {
return err
}
return nil
}
if _, ok := iface.(*time.Time); ok {
return d.decodeTime(ctx, dst, src)
}
if _, ok := iface.(*time.Duration); ok {
return d.decodeDuration(ctx, dst, src)
}
if unmarshaler, isText := iface.(encoding.TextUnmarshaler); isText {
b, ok := d.unmarshalableText(src)
if ok {
if err := unmarshaler.UnmarshalText(b); err != nil {
return err
}
return nil
}
}
if d.useJSONUnmarshaler {
if unmarshaler, ok := iface.(jsonUnmarshaler); ok {
b, err := d.unmarshalableDocument(src)
if err != nil {
return err
}
jsonBytes, err := YAMLToJSON(b)
if err != nil {
return err
}
jsonBytes = bytes.TrimRight(jsonBytes, "\n")
if err := unmarshaler.UnmarshalJSON(jsonBytes); err != nil {
return err
}
return nil
}
}
return errors.New("does not implemented Unmarshaler")
}
var (
astNodeType = reflect.TypeOf((*ast.Node)(nil)).Elem()
)
func (d *Decoder) decodeValue(ctx context.Context, dst reflect.Value, src ast.Node) error {
d.stepIn()
defer d.stepOut()
if d.isExceededMaxDepth() {
return ErrExceededMaxDepth
}
if !dst.IsValid() {
return nil
}
if src.Type() == ast.AnchorType {
anchor, _ := src.(*ast.AnchorNode)
anchorName := anchor.Name.GetToken().Value
if err := d.decodeValue(withAnchor(ctx, anchorName), dst, anchor.Value); err != nil {
return err
}
d.anchorValueMap[anchorName] = dst
return nil
}
if d.canDecodeByUnmarshaler(dst) {
if err := d.decodeByUnmarshaler(ctx, dst, src); err != nil {
return err
}
return nil
}
valueType := dst.Type()
switch valueType.Kind() {
case reflect.Ptr:
if dst.IsNil() {
return nil
}
if src.Type() == ast.NullType {
// set nil value to pointer
dst.Set(reflect.Zero(valueType))
return nil
}
v := d.createDecodableValue(dst.Type())
if err := d.decodeValue(ctx, v, src); err != nil {
return err
}
castedValue, err := d.castToAssignableValue(v, dst.Type(), src)
if err != nil {
return err
}
dst.Set(castedValue)
case reflect.Interface:
if dst.Type() == astNodeType {
dst.Set(reflect.ValueOf(src))
return nil
}
srcVal, err := d.nodeToValue(ctx, src)
if err != nil {
return err
}
v := reflect.ValueOf(srcVal)
if v.IsValid() {
dst.Set(v)
} else {
dst.Set(reflect.Zero(valueType))
}
case reflect.Map:
return d.decodeMap(ctx, dst, src)
case reflect.Array:
return d.decodeArray(ctx, dst, src)
case reflect.Slice:
if mapSlice, ok := dst.Addr().Interface().(*MapSlice); ok {
return d.decodeMapSlice(ctx, mapSlice, src)
}
return d.decodeSlice(ctx, dst, src)
case reflect.Struct:
if mapItem, ok := dst.Addr().Interface().(*MapItem); ok {
return d.decodeMapItem(ctx, mapItem, src)
}
return d.decodeStruct(ctx, dst, src)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v, err := d.nodeToValue(ctx, src)
if err != nil {
return err
}
switch vv := v.(type) {
case int64:
if !dst.OverflowInt(vv) {
dst.SetInt(vv)
return nil
}
case uint64:
if vv <= math.MaxInt64 && !dst.OverflowInt(int64(vv)) {
dst.SetInt(int64(vv))
return nil
}
case float64:
if vv <= math.MaxInt64 && !dst.OverflowInt(int64(vv)) {
dst.SetInt(int64(vv))
return nil
}
case string: // handle scientific notation
if i, err := strconv.ParseFloat(vv, 64); err == nil {
if 0 <= i && i <= math.MaxUint64 && !dst.OverflowInt(int64(i)) {
dst.SetInt(int64(i))
return nil
}
} else { // couldn't be parsed as float
return errors.ErrTypeMismatch(valueType, reflect.TypeOf(v), src.GetToken())
}
default:
return errors.ErrTypeMismatch(valueType, reflect.TypeOf(v), src.GetToken())
}
return errors.ErrOverflow(valueType, fmt.Sprint(v), src.GetToken())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v, err := d.nodeToValue(ctx, src)
if err != nil {
return err
}
switch vv := v.(type) {
case int64:
if 0 <= vv && !dst.OverflowUint(uint64(vv)) {
dst.SetUint(uint64(vv))
return nil
}
case uint64:
if !dst.OverflowUint(vv) {
dst.SetUint(vv)
return nil
}
case float64:
if 0 <= vv && vv <= math.MaxUint64 && !dst.OverflowUint(uint64(vv)) {
dst.SetUint(uint64(vv))
return nil
}
case string: // handle scientific notation
if i, err := strconv.ParseFloat(vv, 64); err == nil {
if 0 <= i && i <= math.MaxUint64 && !dst.OverflowUint(uint64(i)) {
dst.SetUint(uint64(i))
return nil
}
} else { // couldn't be parsed as float
return errors.ErrTypeMismatch(valueType, reflect.TypeOf(v), src.GetToken())
}
default:
return errors.ErrTypeMismatch(valueType, reflect.TypeOf(v), src.GetToken())
}
return errors.ErrOverflow(valueType, fmt.Sprint(v), src.GetToken())
}
srcVal, err := d.nodeToValue(ctx, src)
if err != nil {
return err
}
v := reflect.ValueOf(srcVal)
if v.IsValid() {
convertedValue, err := d.convertValue(v, dst.Type(), src)
if err != nil {
return err
}
dst.Set(convertedValue)
}
return nil
}
func (d *Decoder) createDecodableValue(typ reflect.Type) reflect.Value {
for {
if typ.Kind() == reflect.Ptr {
typ = typ.Elem()
continue
}
break
}
return reflect.New(typ).Elem()
}
func (d *Decoder) castToAssignableValue(value reflect.Value, target reflect.Type, src ast.Node) (reflect.Value, error) {
if target.Kind() != reflect.Ptr {
if !value.Type().AssignableTo(target) {
return reflect.Value{}, errors.ErrTypeMismatch(target, value.Type(), src.GetToken())
}
return value, nil
}
const maxAddrCount = 5
for i := 0; i < maxAddrCount; i++ {
if value.Type().AssignableTo(target) {
break
}
if !value.CanAddr() {
break
}
value = value.Addr()
}
if !value.Type().AssignableTo(target) {
return reflect.Value{}, errors.ErrTypeMismatch(target, value.Type(), src.GetToken())
}
return value, nil
}
func (d *Decoder) createDecodedNewValue(
ctx context.Context, typ reflect.Type, defaultVal reflect.Value, node ast.Node,
) (reflect.Value, error) {
if node.Type() == ast.AliasType {
aliasName := node.(*ast.AliasNode).Value.GetToken().Value
value := d.anchorValueMap[aliasName]
if value.IsValid() {
v, err := d.castToAssignableValue(value, typ, node)
if err == nil {
return v, nil
}
}
anchor, exists := d.anchorNodeMap[aliasName]
if exists {
node = anchor
}
}
var newValue reflect.Value
if node.Type() == ast.NullType {
newValue = reflect.New(typ).Elem()
} else {
newValue = d.createDecodableValue(typ)
}
for defaultVal.Kind() == reflect.Ptr {
defaultVal = defaultVal.Elem()
}
if defaultVal.IsValid() && defaultVal.Type().AssignableTo(newValue.Type()) {
newValue.Set(defaultVal)
}
if node.Type() != ast.NullType {
if err := d.decodeValue(ctx, newValue, node); err != nil {
return reflect.Value{}, err
}
}
return d.castToAssignableValue(newValue, typ, node)
}
func (d *Decoder) keyToNodeMap(ctx context.Context, node ast.Node, ignoreMergeKey bool, getKeyOrValueNode func(*ast.MapNodeIter) ast.Node) (map[string]ast.Node, error) {
d.stepIn()
defer d.stepOut()
if d.isExceededMaxDepth() {
return nil, ErrExceededMaxDepth
}
mapNode, err := d.getMapNode(node, false)
if err != nil {
return nil, err
}
keyMap := map[string]struct{}{}
keyToNodeMap := map[string]ast.Node{}
mapIter := mapNode.MapRange()
for mapIter.Next() {
keyNode := mapIter.Key()
if keyNode.IsMergeKey() {
if ignoreMergeKey {
continue
}
mergeMap, err := d.keyToNodeMap(ctx, mapIter.Value(), ignoreMergeKey, getKeyOrValueNode)
if err != nil {
return nil, err
}
for k, v := range mergeMap {
if err := d.validateDuplicateKey(keyMap, k, v); err != nil {
return nil, err
}
keyToNodeMap[k] = v
}
} else {
keyVal, err := d.nodeToValue(ctx, keyNode)
if err != nil {
return nil, err
}
key, ok := keyVal.(string)
if !ok {
return nil, err
}
if err := d.validateDuplicateKey(keyMap, key, keyNode); err != nil {
return nil, err
}
keyToNodeMap[key] = getKeyOrValueNode(mapIter)
}
}
return keyToNodeMap, nil
}
func (d *Decoder) keyToKeyNodeMap(ctx context.Context, node ast.Node, ignoreMergeKey bool) (map[string]ast.Node, error) {
m, err := d.keyToNodeMap(ctx, node, ignoreMergeKey, func(nodeMap *ast.MapNodeIter) ast.Node { return nodeMap.Key() })
if err != nil {
return nil, err
}
return m, nil
}
func (d *Decoder) keyToValueNodeMap(ctx context.Context, node ast.Node, ignoreMergeKey bool) (map[string]ast.Node, error) {
m, err := d.keyToNodeMap(ctx, node, ignoreMergeKey, func(nodeMap *ast.MapNodeIter) ast.Node { return nodeMap.Value() })
if err != nil {
return nil, err
}
return m, nil
}
func (d *Decoder) setDefaultValueIfConflicted(v reflect.Value, fieldMap StructFieldMap) error {
for v.Type().Kind() == reflect.Ptr {
v = v.Elem()
}
typ := v.Type()
if typ.Kind() != reflect.Struct {
return nil
}
embeddedStructFieldMap, err := structFieldMap(typ)
if err != nil {
return err
}
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
if isIgnoredStructField(field) {
continue
}
structField := embeddedStructFieldMap[field.Name]
if !fieldMap.isIncludedRenderName(structField.RenderName) {
continue
}
// if declared same key name, set default value
fieldValue := v.Field(i)
if fieldValue.CanSet() {
fieldValue.Set(reflect.Zero(fieldValue.Type()))
}
}
return nil
}
// This is a subset of the formats allowed by the regular expression
// defined at http://yaml.org/type/timestamp.html.
var allowedTimestampFormats = []string{
"2006-1-2T15:4:5.999999999Z07:00", // RCF3339Nano with short date fields.
"2006-1-2t15:4:5.999999999Z07:00", // RFC3339Nano with short date fields and lower-case "t".
"2006-1-2 15:4:5.999999999", // space separated with no time zone
"2006-1-2", // date only
}
func (d *Decoder) castToTime(ctx context.Context, src ast.Node) (time.Time, error) {
if src == nil {
return time.Time{}, nil
}
v, err := d.nodeToValue(ctx, src)
if err != nil {
return time.Time{}, err
}
if t, ok := v.(time.Time); ok {
return t, nil
}
s, ok := v.(string)
if !ok {
return time.Time{}, errors.ErrTypeMismatch(reflect.TypeOf(time.Time{}), reflect.TypeOf(v), src.GetToken())
}
for _, format := range allowedTimestampFormats {
t, err := time.Parse(format, s)
if err != nil {
// invalid format
continue
}
return t, nil
}
return time.Time{}, nil
}
func (d *Decoder) decodeTime(ctx context.Context, dst reflect.Value, src ast.Node) error {
t, err := d.castToTime(ctx, src)
if err != nil {
return err
}
dst.Set(reflect.ValueOf(t))
return nil
}
func (d *Decoder) castToDuration(ctx context.Context, src ast.Node) (time.Duration, error) {
if src == nil {
return 0, nil
}
v, err := d.nodeToValue(ctx, src)
if err != nil {
return 0, err
}
if t, ok := v.(time.Duration); ok {
return t, nil
}
s, ok := v.(string)
if !ok {
return 0, errors.ErrTypeMismatch(reflect.TypeOf(time.Duration(0)), reflect.TypeOf(v), src.GetToken())
}
t, err := time.ParseDuration(s)
if err != nil {
return 0, err
}
return t, nil
}
func (d *Decoder) decodeDuration(ctx context.Context, dst reflect.Value, src ast.Node) error {
t, err := d.castToDuration(ctx, src)
if err != nil {
return err
}
dst.Set(reflect.ValueOf(t))
return nil
}
// getMergeAliasName support single alias only
func (d *Decoder) getMergeAliasName(src ast.Node) string {
mapNode, err := d.getMapNode(src, true)
if err != nil {
return ""
}
mapIter := mapNode.MapRange()
for mapIter.Next() {
key := mapIter.Key()
value := mapIter.Value()
if key.IsMergeKey() && value.Type() == ast.AliasType {
return value.(*ast.AliasNode).Value.GetToken().Value
}
}
return ""
}
func (d *Decoder) decodeStruct(ctx context.Context, dst reflect.Value, src ast.Node) error {
if src == nil {
return nil
}
d.stepIn()
defer d.stepOut()
if d.isExceededMaxDepth() {
return ErrExceededMaxDepth
}
structType := dst.Type()
srcValue := reflect.ValueOf(src)
srcType := srcValue.Type()
if srcType.Kind() == reflect.Ptr {
srcType = srcType.Elem()
srcValue = srcValue.Elem()
}
if structType == srcType {
// dst value implements ast.Node
dst.Set(srcValue)
return nil
}
structFieldMap, err := structFieldMap(structType)
if err != nil {
return err
}
ignoreMergeKey := structFieldMap.hasMergeProperty()
keyToNodeMap, err := d.keyToValueNodeMap(ctx, src, ignoreMergeKey)
if err != nil {
return err
}
var unknownFields map[string]ast.Node
if d.disallowUnknownField {
unknownFields, err = d.keyToKeyNodeMap(ctx, src, ignoreMergeKey)
if err != nil {
return err
}
}
aliasName := d.getMergeAliasName(src)
var foundErr error
for i := 0; i < structType.NumField(); i++ {
field := structType.Field(i)
if isIgnoredStructField(field) {
continue
}
structField := structFieldMap[field.Name]
if structField.IsInline {
fieldValue := dst.FieldByName(field.Name)
if structField.IsAutoAlias {
if aliasName != "" {
newFieldValue := d.anchorValueMap[aliasName]
if newFieldValue.IsValid() {
value, err := d.castToAssignableValue(newFieldValue, fieldValue.Type(), d.anchorNodeMap[aliasName])
if err != nil {
return err
}
fieldValue.Set(value)
}
}
continue
}
if !fieldValue.CanSet() {
return fmt.Errorf("cannot set embedded type as unexported field %s.%s", field.PkgPath, field.Name)
}
if fieldValue.Type().Kind() == reflect.Ptr && src.Type() == ast.NullType {
// set nil value to pointer
fieldValue.Set(reflect.Zero(fieldValue.Type()))
continue
}
mapNode := ast.Mapping(nil, false)
for k, v := range keyToNodeMap {
key := &ast.StringNode{BaseNode: &ast.BaseNode{}, Value: k}
mapNode.Values = append(mapNode.Values, ast.MappingValue(nil, key, v))
}
newFieldValue, err := d.createDecodedNewValue(ctx, fieldValue.Type(), fieldValue, mapNode)
if d.disallowUnknownField {
if err := d.deleteStructKeys(fieldValue.Type(), unknownFields); err != nil {
return err
}
}
if err != nil {
if foundErr != nil {
continue
}
var te *errors.TypeError
if errors.As(err, &te) {
if te.StructFieldName != nil {
fieldName := fmt.Sprintf("%s.%s", structType.Name(), *te.StructFieldName)
te.StructFieldName = &fieldName
} else {
fieldName := fmt.Sprintf("%s.%s", structType.Name(), field.Name)
te.StructFieldName = &fieldName
}
foundErr = te
continue
} else {
foundErr = err
}
continue
}
_ = d.setDefaultValueIfConflicted(newFieldValue, structFieldMap)
fieldValue.Set(newFieldValue)
continue
}
v, exists := keyToNodeMap[structField.RenderName]
if !exists {
continue
}
delete(unknownFields, structField.RenderName)
fieldValue := dst.FieldByName(field.Name)
if fieldValue.Type().Kind() == reflect.Ptr && src.Type() == ast.NullType {
// set nil value to pointer
fieldValue.Set(reflect.Zero(fieldValue.Type()))
continue
}
newFieldValue, err := d.createDecodedNewValue(ctx, fieldValue.Type(), fieldValue, v)
if err != nil {
if foundErr != nil {
continue
}
var te *errors.TypeError
if errors.As(err, &te) {
fieldName := fmt.Sprintf("%s.%s", structType.Name(), field.Name)
te.StructFieldName = &fieldName
foundErr = te
} else {
foundErr = err
}
continue
}
fieldValue.Set(newFieldValue)
}
if foundErr != nil {
return foundErr
}
// Ignore unknown fields when parsing an inline struct (recognized by a nil token).
// Unknown fields are expected (they could be fields from the parent struct).
if len(unknownFields) != 0 && d.disallowUnknownField && src.GetToken() != nil {
for key, node := range unknownFields {
var ok bool
for _, prefix := range d.allowedFieldPrefixes {
if strings.HasPrefix(key, prefix) {
ok = true
break
}
}
if !ok {
return errors.ErrUnknownField(fmt.Sprintf(`unknown field "%s"`, key), node.GetToken())
}
}
}
if d.validator != nil {
if err := d.validator.Struct(dst.Interface()); err != nil {
ev := reflect.ValueOf(err)
if ev.Type().Kind() == reflect.Slice {
for i := 0; i < ev.Len(); i++ {
fieldErr, ok := ev.Index(i).Interface().(FieldError)
if !ok {
continue
}
fieldName := fieldErr.StructField()
structField, exists := structFieldMap[fieldName]
if !exists {
continue
}
node, exists := keyToNodeMap[structField.RenderName]
if exists {
// TODO: to make FieldError message cutomizable
return errors.ErrSyntax(
fmt.Sprintf("%s", err),
d.getParentMapTokenIfExistsForValidationError(node.Type(), node.GetToken()),
)
} else if t := src.GetToken(); t != nil && t.Prev != nil && t.Prev.Prev != nil {
// A missing required field will not be in the keyToNodeMap
// the error needs to be associated with the parent of the source node
return errors.ErrSyntax(fmt.Sprintf("%s", err), t.Prev.Prev)
}
}
}
return err
}
}
return nil
}
// getParentMapTokenIfExists if the NodeType is a container type such as MappingType or SequenceType,
// it is necessary to return the parent MapNode's colon token to represent the entire container.
func (d *Decoder) getParentMapTokenIfExistsForValidationError(typ ast.NodeType, tk *token.Token) *token.Token {
if tk == nil {
return nil
}
if typ == ast.MappingType {
// map:
// key: value
// ^ current token ( colon )
if tk.Prev == nil {
return tk
}
key := tk.Prev
if key.Prev == nil {
return tk
}
return key.Prev
}
if typ == ast.SequenceType {
// map:
// - value
// ^ current token ( sequence entry )
if tk.Prev == nil {
return tk
}
return tk.Prev
}
return tk
}
func (d *Decoder) decodeArray(ctx context.Context, dst reflect.Value, src ast.Node) error {
d.stepIn()
defer d.stepOut()
if d.isExceededMaxDepth() {
return ErrExceededMaxDepth
}
arrayNode, err := d.getArrayNode(src)
if err != nil {
return err
}
if arrayNode == nil {
return nil
}
iter := arrayNode.ArrayRange()
arrayValue := reflect.New(dst.Type()).Elem()
arrayType := dst.Type()
elemType := arrayType.Elem()
idx := 0
var foundErr error
for iter.Next() {
v := iter.Value()
if elemType.Kind() == reflect.Ptr && v.Type() == ast.NullType {
// set nil value to pointer
arrayValue.Index(idx).Set(reflect.Zero(elemType))
} else {
dstValue, err := d.createDecodedNewValue(ctx, elemType, reflect.Value{}, v)
if err != nil {
if foundErr == nil {
foundErr = err
}
continue
}
arrayValue.Index(idx).Set(dstValue)
}
idx++
}
dst.Set(arrayValue)
if foundErr != nil {
return foundErr
}
return nil
}
func (d *Decoder) decodeSlice(ctx context.Context, dst reflect.Value, src ast.Node) error {
d.stepIn()
defer d.stepOut()
if d.isExceededMaxDepth() {
return ErrExceededMaxDepth
}
arrayNode, err := d.getArrayNode(src)
if err != nil {
return err
}
if arrayNode == nil {
return nil
}
iter := arrayNode.ArrayRange()
sliceType := dst.Type()
sliceValue := reflect.MakeSlice(sliceType, 0, iter.Len())
elemType := sliceType.Elem()
var foundErr error
for iter.Next() {
v := iter.Value()
if elemType.Kind() == reflect.Ptr && v.Type() == ast.NullType {
// set nil value to pointer
sliceValue = reflect.Append(sliceValue, reflect.Zero(elemType))
continue
}
dstValue, err := d.createDecodedNewValue(ctx, elemType, reflect.Value{}, v)
if err != nil {
if foundErr == nil {
foundErr = err
}
continue
}
sliceValue = reflect.Append(sliceValue, dstValue)
}
dst.Set(sliceValue)
if foundErr != nil {
return foundErr
}
return nil
}
func (d *Decoder) decodeMapItem(ctx context.Context, dst *MapItem, src ast.Node) error {
d.stepIn()
defer d.stepOut()
if d.isExceededMaxDepth() {
return ErrExceededMaxDepth
}
mapNode, err := d.getMapNode(src, isMerge(ctx))
if err != nil {
return err
}
mapIter := mapNode.MapRange()
if !mapIter.Next() {
return nil
}
key := mapIter.Key()
value := mapIter.Value()
if key.IsMergeKey() {
if err := d.decodeMapItem(withMerge(ctx), dst, value); err != nil {
return err
}
return nil
}
k, err := d.nodeToValue(ctx, key)
if err != nil {
return err
}
v, err := d.nodeToValue(ctx, value)
if err != nil {
return err
}
*dst = MapItem{Key: k, Value: v}
return nil
}
func (d *Decoder) validateDuplicateKey(keyMap map[string]struct{}, key interface{}, keyNode ast.Node) error {
k, ok := key.(string)
if !ok {
return nil
}
if !d.allowDuplicateMapKey {
if _, exists := keyMap[k]; exists {
return errors.ErrDuplicateKey(fmt.Sprintf(`duplicate key "%s"`, k), keyNode.GetToken())
}
}
keyMap[k] = struct{}{}
return nil
}
func (d *Decoder) decodeMapSlice(ctx context.Context, dst *MapSlice, src ast.Node) error {
d.stepIn()
defer d.stepOut()
if d.isExceededMaxDepth() {
return ErrExceededMaxDepth
}
mapNode, err := d.getMapNode(src, isMerge(ctx))
if err != nil {
return err
}
mapSlice := MapSlice{}
mapIter := mapNode.MapRange()
keyMap := map[string]struct{}{}
for mapIter.Next() {
key := mapIter.Key()
value := mapIter.Value()
if key.IsMergeKey() {
var m MapSlice
if err := d.decodeMapSlice(withMerge(ctx), &m, value); err != nil {
return err
}
for _, v := range m {
if err := d.validateDuplicateKey(keyMap, v.Key, value); err != nil {
return err
}
mapSlice = append(mapSlice, v)
}
continue
}
k, err := d.nodeToValue(ctx, key)
if err != nil {
return err
}
if err := d.validateDuplicateKey(keyMap, k, key); err != nil {
return err
}
v, err := d.nodeToValue(ctx, value)
if err != nil {
return err
}
mapSlice = append(mapSlice, MapItem{Key: k, Value: v})
}
*dst = mapSlice
return nil
}
func (d *Decoder) decodeMap(ctx context.Context, dst reflect.Value, src ast.Node) error {
d.stepIn()
defer d.stepOut()
if d.isExceededMaxDepth() {
return ErrExceededMaxDepth
}
mapNode, err := d.getMapNode(src, isMerge(ctx))
if err != nil {
return err
}
mapType := dst.Type()
mapValue := reflect.MakeMap(mapType)
keyType := mapValue.Type().Key()
valueType := mapValue.Type().Elem()
mapIter := mapNode.MapRange()
keyMap := map[string]struct{}{}
var foundErr error
for mapIter.Next() {
key := mapIter.Key()
value := mapIter.Value()
if key.IsMergeKey() {
if err := d.decodeMap(withMerge(ctx), dst, value); err != nil {
return err
}
iter := dst.MapRange()
for iter.Next() {
if err := d.validateDuplicateKey(keyMap, iter.Key(), value); err != nil {
return err
}
mapValue.SetMapIndex(iter.Key(), iter.Value())
}
continue
}
k := d.createDecodableValue(keyType)
if d.canDecodeByUnmarshaler(k) {
if err := d.decodeByUnmarshaler(ctx, k, key); err != nil {
return err
}
} else {
keyVal, err := d.createDecodedNewValue(ctx, keyType, reflect.Value{}, key)
if err != nil {
return err
}
k = keyVal
}
if k.IsValid() {
if err := d.validateDuplicateKey(keyMap, k.Interface(), key); err != nil {
return err
}
}
if valueType.Kind() == reflect.Ptr && value.Type() == ast.NullType {
// set nil value to pointer
mapValue.SetMapIndex(k, reflect.Zero(valueType))
continue
}
dstValue, err := d.createDecodedNewValue(ctx, valueType, reflect.Value{}, value)
if err != nil {
if foundErr == nil {
foundErr = err
}
}
if !k.IsValid() {
// expect nil key
mapValue.SetMapIndex(d.createDecodableValue(keyType), dstValue)
continue
}
if keyType.Kind() != k.Kind() {
return errors.ErrSyntax(
fmt.Sprintf("cannot convert %q type to %q type", k.Kind(), keyType.Kind()),
key.GetToken(),
)
}
mapValue.SetMapIndex(k, dstValue)
}
dst.Set(mapValue)
if foundErr != nil {
return foundErr
}
return nil
}
func (d *Decoder) fileToReader(file string) (io.Reader, error) {
reader, err := os.Open(file)
if err != nil {
return nil, err
}
return reader, nil
}
func (d *Decoder) isYAMLFile(file string) bool {
ext := filepath.Ext(file)
if ext == ".yml" {
return true
}
if ext == ".yaml" {
return true
}
return false
}
func (d *Decoder) readersUnderDir(dir string) ([]io.Reader, error) {
pattern := fmt.Sprintf("%s/*", dir)
matches, err := filepath.Glob(pattern)
if err != nil {
return nil, err
}
readers := []io.Reader{}
for _, match := range matches {
if !d.isYAMLFile(match) {
continue
}
reader, err := d.fileToReader(match)
if err != nil {
return nil, err
}
readers = append(readers, reader)
}
return readers, nil
}
func (d *Decoder) readersUnderDirRecursive(dir string) ([]io.Reader, error) {
readers := []io.Reader{}
if err := filepath.Walk(dir, func(path string, info os.FileInfo, _ error) error {
if !d.isYAMLFile(path) {
return nil
}
reader, readerErr := d.fileToReader(path)
if readerErr != nil {
return readerErr
}
readers = append(readers, reader)
return nil
}); err != nil {
return nil, err
}
return readers, nil
}
func (d *Decoder) resolveReference(ctx context.Context) error {
for _, opt := range d.opts {
if err := opt(d); err != nil {
return err
}
}
for _, file := range d.referenceFiles {
reader, err := d.fileToReader(file)
if err != nil {
return err
}
d.referenceReaders = append(d.referenceReaders, reader)
}
for _, dir := range d.referenceDirs {
if !d.isRecursiveDir {
readers, err := d.readersUnderDir(dir)
if err != nil {
return err
}
d.referenceReaders = append(d.referenceReaders, readers...)
} else {
readers, err := d.readersUnderDirRecursive(dir)
if err != nil {
return err
}
d.referenceReaders = append(d.referenceReaders, readers...)
}
}
for _, reader := range d.referenceReaders {
bytes, err := io.ReadAll(reader)
if err != nil {
return err
}
// assign new anchor definition to anchorMap
if _, err := d.parse(ctx, bytes); err != nil {
return err
}
}
d.isResolvedReference = true
return nil
}
func (d *Decoder) parse(ctx context.Context, bytes []byte) (*ast.File, error) {
var parseMode parser.Mode
if d.toCommentMap != nil {
parseMode = parser.ParseComments
}
var opts []parser.Option
if d.allowDuplicateMapKey {
opts = append(opts, parser.AllowDuplicateMapKey())
}
f, err := parser.ParseBytes(bytes, parseMode, opts...)
if err != nil {
return nil, err
}
normalizedFile := &ast.File{}
for _, doc := range f.Docs {
// try to decode ast.Node to value and map anchor value to anchorMap
v, err := d.nodeToValue(ctx, doc.Body)
if err != nil {
return nil, err
}
if v != nil || (doc.Body != nil && doc.Body.Type() == ast.NullType) {
normalizedFile.Docs = append(normalizedFile.Docs, doc)
cm := CommentMap{}
maps.Copy(cm, d.toCommentMap)
d.commentMaps = append(d.commentMaps, cm)
}
for k := range d.toCommentMap {
delete(d.toCommentMap, k)
}
}
return normalizedFile, nil
}
func (d *Decoder) isInitialized() bool {
return d.parsedFile != nil
}
func (d *Decoder) decodeInit(ctx context.Context) error {
if !d.isResolvedReference {
if err := d.resolveReference(ctx); err != nil {
return err
}
}
var buf bytes.Buffer
if _, err := io.Copy(&buf, d.reader); err != nil {
return err
}
file, err := d.parse(ctx, buf.Bytes())
if err != nil {
return err
}
d.parsedFile = file
return nil
}
func (d *Decoder) decode(ctx context.Context, v reflect.Value) error {
d.decodeDepth = 0
d.anchorValueMap = make(map[string]reflect.Value)
if len(d.parsedFile.Docs) == 0 {
// empty document.
dst := v.Elem()
if dst.IsValid() {
dst.Set(reflect.Zero(dst.Type()))
}
}
if len(d.parsedFile.Docs) <= d.streamIndex {
return io.EOF
}
body := d.parsedFile.Docs[d.streamIndex].Body
if body == nil {
return nil
}
if len(d.commentMaps) > d.streamIndex {
maps.Copy(d.toCommentMap, d.commentMaps[d.streamIndex])
}
if err := d.decodeValue(ctx, v.Elem(), body); err != nil {
return err
}
d.streamIndex++
return nil
}
// Decode reads the next YAML-encoded value from its input
// and stores it in the value pointed to by v.
//
// See the documentation for Unmarshal for details about the
// conversion of YAML into a Go value.
func (d *Decoder) Decode(v interface{}) error {
return d.DecodeContext(context.Background(), v)
}
// DecodeContext reads the next YAML-encoded value from its input
// and stores it in the value pointed to by v with context.Context.
func (d *Decoder) DecodeContext(ctx context.Context, v interface{}) error {
rv := reflect.ValueOf(v)
if !rv.IsValid() || rv.Type().Kind() != reflect.Ptr {
return ErrDecodeRequiredPointerType
}
if d.isInitialized() {
if err := d.decode(ctx, rv); err != nil {
return err
}
return nil
}
if err := d.decodeInit(ctx); err != nil {
return err
}
if err := d.decode(ctx, rv); err != nil {
return err
}
return nil
}
// DecodeFromNode decodes node into the value pointed to by v.
func (d *Decoder) DecodeFromNode(node ast.Node, v interface{}) error {
return d.DecodeFromNodeContext(context.Background(), node, v)
}
// DecodeFromNodeContext decodes node into the value pointed to by v with context.Context.
func (d *Decoder) DecodeFromNodeContext(ctx context.Context, node ast.Node, v interface{}) error {
rv := reflect.ValueOf(v)
if rv.Type().Kind() != reflect.Ptr {
return ErrDecodeRequiredPointerType
}
if !d.isInitialized() {
if err := d.decodeInit(ctx); err != nil {
return err
}
}
// resolve references to the anchor on the same file
if _, err := d.nodeToValue(ctx, node); err != nil {
return err
}
if err := d.decodeValue(ctx, rv.Elem(), node); err != nil {
return err
}
return nil
}
================================================
FILE: vendor/github.com/goccy/go-yaml/encode.go
================================================
package yaml
import (
"context"
"encoding"
"fmt"
"io"
"math"
"reflect"
"sort"
"strconv"
"strings"
"time"
"github.com/goccy/go-yaml/ast"
"github.com/goccy/go-yaml/internal/errors"
"github.com/goccy/go-yaml/parser"
"github.com/goccy/go-yaml/printer"
"github.com/goccy/go-yaml/token"
)
const (
// DefaultIndentSpaces default number of space for indent
DefaultIndentSpaces = 2
)
// Encoder writes YAML values to an output stream.
type Encoder struct {
writer io.Writer
opts []EncodeOption
singleQuote bool
isFlowStyle bool
isJSONStyle bool
useJSONMarshaler bool
enableSmartAnchor bool
aliasRefToName map[uintptr]string
anchorRefToName map[uintptr]string
anchorNameMap map[string]struct{}
anchorCallback func(*ast.AnchorNode, interface{}) error
customMarshalerMap map[reflect.Type]func(context.Context, interface{}) ([]byte, error)
omitZero bool
omitEmpty bool
autoInt bool
useLiteralStyleIfMultiline bool
commentMap map[*Path][]*Comment
written bool
line int
column int
offset int
indentNum int
indentLevel int
indentSequence bool
}
// NewEncoder returns a new encoder that writes to w.
// The Encoder should be closed after use to flush all data to w.
func NewEncoder(w io.Writer, opts ...EncodeOption) *Encoder {
return &Encoder{
writer: w,
opts: opts,
customMarshalerMap: map[reflect.Type]func(context.Context, interface{}) ([]byte, error){},
line: 1,
column: 1,
offset: 0,
indentNum: DefaultIndentSpaces,
anchorRefToName: make(map[uintptr]string),
anchorNameMap: make(map[string]struct{}),
aliasRefToName: make(map[uintptr]string),
}
}
// Close closes the encoder by writing any remaining data.
// It does not write a stream terminating string "...".
func (e *Encoder) Close() error {
return nil
}
// Encode writes the YAML encoding of v to the stream.
// If multiple items are encoded to the stream,
// the second and subsequent document will be preceded with a "---" document separator,
// but the first will not.
//
// See the documentation for Marshal for details about the conversion of Go values to YAML.
func (e *Encoder) Encode(v interface{}) error {
return e.EncodeContext(context.Background(), v)
}
// EncodeContext writes the YAML encoding of v to the stream with context.Context.
func (e *Encoder) EncodeContext(ctx context.Context, v interface{}) error {
node, err := e.EncodeToNodeContext(ctx, v)
if err != nil {
return err
}
if err := e.setCommentByCommentMap(node); err != nil {
return err
}
if !e.written {
e.written = true
} else {
// write document separator
_, _ = e.writer.Write([]byte("---\n"))
}
var p printer.Printer
_, _ = e.writer.Write(p.PrintNode(node))
return nil
}
// EncodeToNode convert v to ast.Node.
func (e *Encoder) EncodeToNode(v interface{}) (ast.Node, error) {
return e.EncodeToNodeContext(context.Background(), v)
}
// EncodeToNodeContext convert v to ast.Node with context.Context.
func (e *Encoder) EncodeToNodeContext(ctx context.Context, v interface{}) (ast.Node, error) {
for _, opt := range e.opts {
if err := opt(e); err != nil {
return nil, err
}
}
if e.enableSmartAnchor {
// during the first encoding, store all mappings between alias addresses and their names.
if _, err := e.encodeValue(ctx, reflect.ValueOf(v), 1); err != nil {
return nil, err
}
e.clearSmartAnchorRef()
}
node, err := e.encodeValue(ctx, reflect.ValueOf(v), 1)
if err != nil {
return nil, err
}
return node, nil
}
func (e *Encoder) setCommentByCommentMap(node ast.Node) error {
if e.commentMap == nil {
return nil
}
for path, comments := range e.commentMap {
n, err := path.FilterNode(node)
if err != nil {
return err
}
if n == nil {
continue
}
for _, comment := range comments {
commentTokens := []*token.Token{}
for _, text := range comment.Texts {
commentTokens = append(commentTokens, token.New(text, text, nil))
}
commentGroup := ast.CommentGroup(commentTokens)
switch comment.Position {
case CommentHeadPosition:
if err := e.setHeadComment(node, n, commentGroup); err != nil {
return err
}
case CommentLinePosition:
if err := e.setLineComment(node, n, commentGroup); err != nil {
return err
}
case CommentFootPosition:
if err := e.setFootComment(node, n, commentGroup); err != nil {
return err
}
default:
return ErrUnknownCommentPositionType
}
}
}
return nil
}
func (e *Encoder) setHeadComment(node ast.Node, filtered ast.Node, comment *ast.CommentGroupNode) error {
parent := ast.Parent(node, filtered)
if parent == nil {
return ErrUnsupportedHeadPositionType(node)
}
switch p := parent.(type) {
case *ast.MappingValueNode:
if err := p.SetComment(comment); err != nil {
return err
}
case *ast.MappingNode:
if err := p.SetComment(comment); err != nil {
return err
}
case *ast.SequenceNode:
if len(p.ValueHeadComments) == 0 {
p.ValueHeadComments = make([]*ast.CommentGroupNode, len(p.Values))
}
var foundIdx int
for idx, v := range p.Values {
if v == filtered {
foundIdx = idx
break
}
}
p.ValueHeadComments[foundIdx] = comment
default:
return ErrUnsupportedHeadPositionType(node)
}
return nil
}
func (e *Encoder) setLineComment(node ast.Node, filtered ast.Node, comment *ast.CommentGroupNode) error {
switch filtered.(type) {
case *ast.MappingValueNode, *ast.SequenceNode:
// Line comment cannot be set for mapping value node.
// It should probably be set for the parent map node
if err := e.setLineCommentToParentMapNode(node, filtered, comment); err != nil {
return err
}
default:
if err := filtered.SetComment(comment); err != nil {
return err
}
}
return nil
}
func (e *Encoder) setLineCommentToParentMapNode(node ast.Node, filtered ast.Node, comment *ast.CommentGroupNode) error {
parent := ast.Parent(node, filtered)
if parent == nil {
return ErrUnsupportedLinePositionType(node)
}
switch p := parent.(type) {
case *ast.MappingValueNode:
if err := p.Key.SetComment(comment); err != nil {
return err
}
case *ast.MappingNode:
if err := p.SetComment(comment); err != nil {
return err
}
default:
return ErrUnsupportedLinePositionType(parent)
}
return nil
}
func (e *Encoder) setFootComment(node ast.Node, filtered ast.Node, comment *ast.CommentGroupNode) error {
parent := ast.Parent(node, filtered)
if parent == nil {
return ErrUnsupportedFootPositionType(node)
}
switch n := parent.(type) {
case *ast.MappingValueNode:
n.FootComment = comment
case *ast.MappingNode:
n.FootComment = comment
case *ast.SequenceNode:
n.FootComment = comment
default:
return ErrUnsupportedFootPositionType(n)
}
return nil
}
func (e *Encoder) encodeDocument(doc []byte) (ast.Node, error) {
f, err := parser.ParseBytes(doc, 0)
if err != nil {
return nil, err
}
for _, docNode := range f.Docs {
if docNode.Body != nil {
return docNode.Body, nil
}
}
return nil, nil
}
func (e *Encoder) isInvalidValue(v reflect.Value) bool {
if !v.IsValid() {
return true
}
kind := v.Type().Kind()
if kind == reflect.Ptr && v.IsNil() {
return true
}
if kind == reflect.Interface && v.IsNil() {
return true
}
return false
}
type jsonMarshaler interface {
MarshalJSON() ([]byte, error)
}
func (e *Encoder) existsTypeInCustomMarshalerMap(t reflect.Type) bool {
if _, exists := e.customMarshalerMap[t]; exists {
return true
}
globalCustomMarshalerMu.Lock()
defer globalCustomMarshalerMu.Unlock()
if _, exists := globalCustomMarshalerMap[t]; exists {
return true
}
return false
}
func (e *Encoder) marshalerFromCustomMarshalerMap(t reflect.Type) (func(context.Context, interface{}) ([]byte, error), bool) {
if marshaler, exists := e.customMarshalerMap[t]; exists {
return marshaler, exists
}
globalCustomMarshalerMu.Lock()
defer globalCustomMarshalerMu.Unlock()
if marshaler, exists := globalCustomMarshalerMap[t]; exists {
return marshaler, exists
}
return nil, false
}
func (e *Encoder) canEncodeByMarshaler(v reflect.Value) bool {
if !v.CanInterface() {
return false
}
if e.existsTypeInCustomMarshalerMap(v.Type()) {
return true
}
iface := v.Interface()
switch iface.(type) {
case BytesMarshalerContext:
return true
case BytesMarshaler:
return true
case InterfaceMarshalerContext:
return true
case InterfaceMarshaler:
return true
case time.Time, *time.Time:
return true
case time.Duration:
return true
case encoding.TextMarshaler:
return true
case jsonMarshaler:
return e.useJSONMarshaler
}
return false
}
func (e *Encoder) encodeByMarshaler(ctx context.Context, v reflect.Value, column int) (ast.Node, error) {
iface := v.Interface()
if marshaler, exists := e.marshalerFromCustomMarshalerMap(v.Type()); exists {
doc, err := marshaler(ctx, iface)
if err != nil {
return nil, err
}
node, err := e.encodeDocument(doc)
if err != nil {
return nil, err
}
return node, nil
}
if marshaler, ok := iface.(BytesMarshalerContext); ok {
doc, err := marshaler.MarshalYAML(ctx)
if err != nil {
return nil, err
}
node, err := e.encodeDocument(doc)
if err != nil {
return nil, err
}
return node, nil
}
if marshaler, ok := iface.(BytesMarshaler); ok {
doc, err := marshaler.MarshalYAML()
if err != nil {
return nil, err
}
node, err := e.encodeDocument(doc)
if err != nil {
return nil, err
}
return node, nil
}
if marshaler, ok := iface.(InterfaceMarshalerContext); ok {
marshalV, err := marshaler.MarshalYAML(ctx)
if err != nil {
return nil, err
}
return e.encodeValue(ctx, reflect.ValueOf(marshalV), column)
}
if marshaler, ok := iface.(InterfaceMarshaler); ok {
marshalV, err := marshaler.MarshalYAML()
if err != nil {
return nil, err
}
return e.encodeValue(ctx, reflect.ValueOf(marshalV), column)
}
if t, ok := iface.(time.Time); ok {
return e.encodeTime(t, column), nil
}
// Handle *time.Time explicitly since it implements TextMarshaler and shouldn't be treated as plain text
if t, ok := iface.(*time.Time); ok && t != nil {
return e.encodeTime(*t, column), nil
}
if t, ok := iface.(time.Duration); ok {
return e.encodeDuration(t, column), nil
}
if marshaler, ok := iface.(encoding.TextMarshaler); ok {
text, err := marshaler.MarshalText()
if err != nil {
return nil, err
}
node := e.encodeString(string(text), column)
return node, nil
}
if e.useJSONMarshaler {
if marshaler, ok := iface.(jsonMarshaler); ok {
jsonBytes, err := marshaler.MarshalJSON()
if err != nil {
return nil, err
}
doc, err := JSONToYAML(jsonBytes)
if err != nil {
return nil, err
}
node, err := e.encodeDocument(doc)
if err != nil {
return nil, err
}
return node, nil
}
}
return nil, errors.New("does not implemented Marshaler")
}
func (e *Encoder) encodeValue(ctx context.Context, v reflect.Value, column int) (ast.Node, error) {
if e.isInvalidValue(v) {
return e.encodeNil(), nil
}
if e.canEncodeByMarshaler(v) {
node, err := e.encodeByMarshaler(ctx, v, column)
if err != nil {
return nil, err
}
return node, nil
}
switch v.Type().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return e.encodeInt(v.Int()), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return e.encodeUint(v.Uint()), nil
case reflect.Float32:
return e.encodeFloat(v.Float(), 32), nil
case reflect.Float64:
return e.encodeFloat(v.Float(), 64), nil
case reflect.Ptr:
if value := e.encodePtrAnchor(v, column); value != nil {
return value, nil
}
return e.encodeValue(ctx, v.Elem(), column)
case reflect.Interface:
return e.encodeValue(ctx, v.Elem(), column)
case reflect.String:
return e.encodeString(v.String(), column), nil
case reflect.Bool:
return e.encodeBool(v.Bool()), nil
case reflect.Slice:
if mapSlice, ok := v.Interface().(MapSlice); ok {
return e.encodeMapSlice(ctx, mapSlice, column)
}
if value := e.encodePtrAnchor(v, column); value != nil {
return value, nil
}
return e.encodeSlice(ctx, v)
case reflect.Array:
return e.encodeArray(ctx, v)
case reflect.Struct:
if v.CanInterface() {
if mapItem, ok := v.Interface().(MapItem); ok {
return e.encodeMapItem(ctx, mapItem, column)
}
if t, ok := v.Interface().(time.Time); ok {
return e.encodeTime(t, column), nil
}
}
return e.encodeStruct(ctx, v, column)
case reflect.Map:
if value := e.encodePtrAnchor(v, column); value != nil {
return value, nil
}
return e.encodeMap(ctx, v, column)
default:
return nil, fmt.Errorf("unknown value type %s", v.Type().String())
}
}
func (e *Encoder) encodePtrAnchor(v reflect.Value, column int) ast.Node {
anchorName, exists := e.getAnchor(v.Pointer())
if !exists {
return nil
}
aliasName := anchorName
alias := ast.Alias(token.New("*", "*", e.pos(column)))
alias.Value = ast.String(token.New(aliasName, aliasName, e.pos(column)))
e.setSmartAlias(aliasName, v.Pointer())
return alias
}
func (e *Encoder) pos(column int) *token.Position {
return &token.Position{
Line: e.line,
Column: column,
Offset: e.offset,
IndentNum: e.indentNum,
IndentLevel: e.indentLevel,
}
}
func (e *Encoder) encodeNil() *ast.NullNode {
value := "null"
return ast.Null(token.New(value, value, e.pos(e.column)))
}
func (e *Encoder) encodeInt(v int64) *ast.IntegerNode {
value := strconv.FormatInt(v, 10)
return ast.Integer(token.New(value, value, e.pos(e.column)))
}
func (e *Encoder) encodeUint(v uint64) *ast.IntegerNode {
value := strconv.FormatUint(v, 10)
return ast.Integer(token.New(value, value, e.pos(e.column)))
}
func (e *Encoder) encodeFloat(v float64, bitSize int) ast.Node {
if v == math.Inf(0) {
value := ".inf"
return ast.Infinity(token.New(value, value, e.pos(e.column)))
} else if v == math.Inf(-1) {
value := "-.inf"
return ast.Infinity(token.New(value, value, e.pos(e.column)))
} else if math.IsNaN(v) {
value := ".nan"
return ast.Nan(token.New(value, value, e.pos(e.column)))
}
value := strconv.FormatFloat(v, 'g', -1, bitSize)
if !strings.Contains(value, ".") && !strings.Contains(value, "e") {
if e.autoInt {
return ast.Integer(token.New(value, value, e.pos(e.column)))
}
// append x.0 suffix to keep float value context
value = fmt.Sprintf("%s.0", value)
}
return ast.Float(token.New(value, value, e.pos(e.column)))
}
func (e *Encoder) isNeedQuoted(v string) bool {
if e.isJSONStyle {
return true
}
if e.useLiteralStyleIfMultiline && strings.ContainsAny(v, "\n\r") {
return false
}
if e.isFlowStyle && strings.ContainsAny(v, `]},'"`) {
return true
}
if e.isFlowStyle {
for i := 0; i < len(v); i++ {
if v[i] != ':' {
continue
}
if i+1 < len(v) && v[i+1] == '/' {
continue
}
return true
}
}
if token.IsNeedQuoted(v) {
return true
}
return false
}
func (e *Encoder) encodeString(v string, column int) *ast.StringNode {
if e.isNeedQuoted(v) {
if e.singleQuote {
v = quoteWith(v, '\'')
} else {
v = strconv.Quote(v)
}
}
return ast.String(token.New(v, v, e.pos(column)))
}
func (e *Encoder) encodeBool(v bool) *ast.BoolNode {
value := strconv.FormatBool(v)
return ast.Bool(token.New(value, value, e.pos(e.column)))
}
func (e *Encoder) encodeSlice(ctx context.Context, value reflect.Value) (*ast.SequenceNode, error) {
if e.indentSequence {
e.column += e.indentNum
defer func() { e.column -= e.indentNum }()
}
column := e.column
sequence := ast.Sequence(token.New("-", "-", e.pos(column)), e.isFlowStyle)
for i := 0; i < value.Len(); i++ {
node, err := e.encodeValue(ctx, value.Index(i), column)
if err != nil {
return nil, err
}
sequence.Values = append(sequence.Values, node)
}
return sequence, nil
}
func (e *Encoder) encodeArray(ctx context.Context, value reflect.Value) (*ast.SequenceNode, error) {
if e.indentSequence {
e.column += e.indentNum
defer func() { e.column -= e.indentNum }()
}
column := e.column
sequence := ast.Sequence(token.New("-", "-", e.pos(column)), e.isFlowStyle)
for i := 0; i < value.Len(); i++ {
node, err := e.encodeValue(ctx, value.Index(i), column)
if err != nil {
return nil, err
}
sequence.Values = append(sequence.Values, node)
}
return sequence, nil
}
func (e *Encoder) encodeMapItem(ctx context.Context, item MapItem, column int) (*ast.MappingValueNode, error) {
k := reflect.ValueOf(item.Key)
v := reflect.ValueOf(item.Value)
value, err := e.encodeValue(ctx, v, column)
if err != nil {
return nil, err
}
if e.isMapNode(value) {
value.AddColumn(e.indentNum)
}
if e.isTagAndMapNode(value) {
value.AddColumn(e.indentNum)
}
return ast.MappingValue(
token.New("", "", e.pos(column)),
e.encodeString(k.Interface().(string), column),
value,
), nil
}
func (e *Encoder) encodeMapSlice(ctx context.Context, value MapSlice, column int) (*ast.MappingNode, error) {
node := ast.Mapping(token.New("", "", e.pos(column)), e.isFlowStyle)
for _, item := range value {
encoded, err := e.encodeMapItem(ctx, item, column)
if err != nil {
return nil, err
}
node.Values = append(node.Values, encoded)
}
return node, nil
}
func (e *Encoder) isMapNode(node ast.Node) bool {
_, ok := node.(ast.MapNode)
return ok
}
func (e *Encoder) isTagAndMapNode(node ast.Node) bool {
tn, ok := node.(*ast.TagNode)
return ok && e.isMapNode(tn.Value)
}
func (e *Encoder) encodeMap(ctx context.Context, value reflect.Value, column int) (ast.Node, error) {
node := ast.Mapping(token.New("", "", e.pos(column)), e.isFlowStyle)
keys := make([]interface{}, len(value.MapKeys()))
for i, k := range value.MapKeys() {
keys[i] = k.Interface()
}
sort.Slice(keys, func(i, j int) bool {
return fmt.Sprint(keys[i]) < fmt.Sprint(keys[j])
})
for _, key := range keys {
k := reflect.ValueOf(key)
v := value.MapIndex(k)
encoded, err := e.encodeValue(ctx, v, column)
if err != nil {
return nil, err
}
if e.isMapNode(encoded) {
encoded.AddColumn(e.indentNum)
}
if e.isTagAndMapNode(encoded) {
encoded.AddColumn(e.indentNum)
}
keyText := fmt.Sprint(key)
vRef := e.toPointer(v)
// during the second encoding, an anchor is assigned if it is found to be used by an alias.
if aliasName, exists := e.getSmartAlias(vRef); exists {
anchorName := aliasName
anchorNode := ast.Anchor(token.New("&", "&", e.pos(column)))
anchorNode.Name = ast.String(token.New(anchorName, anchorName, e.pos(column)))
anchorNode.Value = encoded
encoded = anchorNode
}
kn, err := e.encodeValue(ctx, reflect.ValueOf(key), column)
keyNode, ok := kn.(ast.MapKeyNode)
if !ok || err != nil {
keyNode = e.encodeString(fmt.Sprint(key), column)
}
node.Values = append(node.Values, ast.MappingValue(
nil,
keyNode,
encoded,
))
e.setSmartAnchor(vRef, keyText)
}
return node, nil
}
// IsZeroer is used to check whether an object is zero to determine
// whether it should be omitted when marshaling with the omitempty flag.
// One notable implementation is time.Time.
type IsZeroer interface {
IsZero() bool
}
func (e *Encoder) isOmittedByOmitZero(v reflect.Value) bool {
kind := v.Kind()
if z, ok := v.Interface().(IsZeroer); ok {
if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() {
return true
}
return z.IsZero()
}
switch kind {
case reflect.String:
return len(v.String()) == 0
case reflect.Interface, reflect.Ptr, reflect.Slice, reflect.Map:
return v.IsNil()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Bool:
return !v.Bool()
case reflect.Struct:
vt := v.Type()
for i := v.NumField() - 1; i >= 0; i-- {
if vt.Field(i).PkgPath != "" {
continue // private field
}
if !e.isOmittedByOmitZero(v.Field(i)) {
return false
}
}
return true
}
return false
}
func (e *Encoder) isOmittedByOmitEmptyOption(v reflect.Value) bool {
switch v.Kind() {
case reflect.String:
return len(v.String()) == 0
case reflect.Interface, reflect.Ptr:
return v.IsNil()
case reflect.Slice, reflect.Map:
return v.Len() == 0
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Bool:
return !v.Bool()
}
return false
}
// The current implementation of the omitempty tag combines the functionality of encoding/json's omitempty and omitzero tags.
// This stems from a historical decision to respect the implementation of gopkg.in/yaml.v2, but it has caused confusion,
// so we are working to integrate it into the functionality of encoding/json. (However, this will take some time.)
// In the current implementation, in addition to the exclusion conditions of omitempty,
// if a type implements IsZero, that implementation will be used.
// Furthermore, for non-pointer structs, if all fields are eligible for exclusion,
// the struct itself will also be excluded. These behaviors are originally the functionality of omitzero.
func (e *Encoder) isOmittedByOmitEmptyTag(v reflect.Value) bool {
kind := v.Kind()
if z, ok := v.Interface().(IsZeroer); ok {
if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() {
return true
}
return z.IsZero()
}
switch kind {
case reflect.String:
return len(v.String()) == 0
case reflect.Interface, reflect.Ptr:
return v.IsNil()
case reflect.Slice, reflect.Map:
return v.Len() == 0
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Bool:
return !v.Bool()
case reflect.Struct:
vt := v.Type()
for i := v.NumField() - 1; i >= 0; i-- {
if vt.Field(i).PkgPath != "" {
continue // private field
}
if !e.isOmittedByOmitEmptyTag(v.Field(i)) {
return false
}
}
return true
}
return false
}
func (e *Encoder) encodeTime(v time.Time, column int) *ast.StringNode {
value := v.Format(time.RFC3339Nano)
if e.isJSONStyle {
value = strconv.Quote(value)
}
return ast.String(token.New(value, value, e.pos(column)))
}
func (e *Encoder) encodeDuration(v time.Duration, column int) *ast.StringNode {
value := v.String()
if e.isJSONStyle {
value = strconv.Quote(value)
}
return ast.String(token.New(value, value, e.pos(column)))
}
func (e *Encoder) encodeAnchor(anchorName string, value ast.Node, fieldValue reflect.Value, column int) (*ast.AnchorNode, error) {
anchorNode := ast.Anchor(token.New("&", "&", e.pos(column)))
anchorNode.Name = ast.String(token.New(anchorName, anchorName, e.pos(column)))
anchorNode.Value = value
if e.anchorCallback != nil {
if err := e.anchorCallback(anchorNode, fieldValue.Interface()); err != nil {
return nil, err
}
if snode, ok := anchorNode.Name.(*ast.StringNode); ok {
anchorName = snode.Value
}
}
if fieldValue.Kind() == reflect.Ptr {
e.setAnchor(fieldValue.Pointer(), anchorName)
}
return anchorNode, nil
}
func (e *Encoder) encodeStruct(ctx context.Context, value reflect.Value, column int) (ast.Node, error) {
node := ast.Mapping(token.New("", "", e.pos(column)), e.isFlowStyle)
structType := value.Type()
fieldMap, err := structFieldMap(structType)
if err != nil {
return nil, err
}
hasInlineAnchorField := false
var inlineAnchorValue reflect.Value
for i := 0; i < value.NumField(); i++ {
field := structType.Field(i)
if isIgnoredStructField(field) {
continue
}
fieldValue := value.FieldByName(field.Name)
sf := fieldMap[field.Name]
if (e.omitZero || sf.IsOmitZero) && e.isOmittedByOmitZero(fieldValue) {
// omit encoding by omitzero tag or OmitZero option.
continue
}
if e.omitEmpty && e.isOmittedByOmitEmptyOption(fieldValue) {
// omit encoding by OmitEmpty option.
continue
}
if sf.IsOmitEmpty && e.isOmittedByOmitEmptyTag(fieldValue) {
// omit encoding by omitempty tag.
continue
}
ve := e
if !e.isFlowStyle && sf.IsFlow {
ve = &Encoder{}
*ve = *e
ve.isFlowStyle = true
}
encoded, err := ve.encodeValue(ctx, fieldValue, column)
if err != nil {
return nil, err
}
if e.isMapNode(encoded) {
encoded.AddColumn(e.indentNum)
}
var key ast.MapKeyNode = e.encodeString(sf.RenderName, column)
switch {
case encoded.Type() == ast.AliasType:
if aliasName := sf.AliasName; aliasName != "" {
alias, ok := encoded.(*ast.AliasNode)
if !ok {
return nil, errors.ErrUnexpectedNodeType(encoded.Type(), ast.AliasType, encoded.GetToken())
}
got := alias.Value.String()
if aliasName != got {
return nil, fmt.Errorf("expected alias name is %q but got %q", aliasName, got)
}
}
if sf.IsInline {
// if both used alias and inline, output `<<: *alias`
key = ast.MergeKey(token.New("<<", "<<", e.pos(column)))
}
case sf.AnchorName != "":
anchorNode, err := e.encodeAnchor(sf.AnchorName, encoded, fieldValue, column)
if err != nil {
return nil, err
}
encoded = anchorNode
case sf.IsInline:
isAutoAnchor := sf.IsAutoAnchor
if !hasInlineAnchorField {
hasInlineAnchorField = isAutoAnchor
}
if isAutoAnchor {
inlineAnchorValue = fieldValue
}
mapNode, ok := encoded.(ast.MapNode)
if !ok {
// if an inline field is null, skip encoding it
if _, ok := encoded.(*ast.NullNode); ok {
continue
}
return nil, errors.New("inline value is must be map or struct type")
}
mapIter := mapNode.MapRange()
for mapIter.Next() {
mapKey := mapIter.Key()
mapValue := mapIter.Value()
keyName := mapKey.GetToken().Value
if fieldMap.isIncludedRenderName(keyName) {
// if declared the same key name, skip encoding this field
continue
}
mapKey.AddColumn(-e.indentNum)
mapValue.AddColumn(-e.indentNum)
node.Values = append(node.Values, ast.MappingValue(nil, mapKey, mapValue))
}
continue
case sf.IsAutoAnchor:
anchorNode, err := e.encodeAnchor(sf.RenderName, encoded, fieldValue, column)
if err != nil {
return nil, err
}
encoded = anchorNode
}
node.Values = append(node.Values, ast.MappingValue(nil, key, encoded))
}
if hasInlineAnchorField {
node.AddColumn(e.indentNum)
anchorName := "anchor"
anchorNode := ast.Anchor(token.New("&", "&", e.pos(column)))
anchorNode.Name = ast.String(token.New(anchorName, anchorName, e.pos(column)))
anchorNode.Value = node
if e.anchorCallback != nil {
if err := e.anchorCallback(anchorNode, value.Addr().Interface()); err != nil {
return nil, err
}
if snode, ok := anchorNode.Name.(*ast.StringNode); ok {
anchorName = snode.Value
}
}
if inlineAnchorValue.Kind() == reflect.Ptr {
e.setAnchor(inlineAnchorValue.Pointer(), anchorName)
}
return anchorNode, nil
}
return node, nil
}
func (e *Encoder) toPointer(v reflect.Value) uintptr {
if e.isInvalidValue(v) {
return 0
}
switch v.Type().Kind() {
case reflect.Ptr:
return v.Pointer()
case reflect.Interface:
return e.toPointer(v.Elem())
case reflect.Slice:
return v.Pointer()
case reflect.Map:
return v.Pointer()
}
return 0
}
func (e *Encoder) clearSmartAnchorRef() {
if !e.enableSmartAnchor {
return
}
e.anchorRefToName = make(map[uintptr]string)
e.anchorNameMap = make(map[string]struct{})
}
func (e *Encoder) setSmartAnchor(ptr uintptr, name string) {
if !e.enableSmartAnchor {
return
}
e.setAnchor(ptr, e.generateAnchorName(name))
}
func (e *Encoder) setAnchor(ptr uintptr, name string) {
if ptr == 0 {
return
}
if name == "" {
return
}
e.anchorRefToName[ptr] = name
e.anchorNameMap[name] = struct{}{}
}
func (e *Encoder) generateAnchorName(base string) string {
if _, exists := e.anchorNameMap[base]; !exists {
return base
}
for i := 1; i < 100; i++ {
name := base + strconv.Itoa(i)
if _, exists := e.anchorNameMap[name]; exists {
continue
}
return name
}
return ""
}
func (e *Encoder) getAnchor(ref uintptr) (string, bool) {
anchorName, exists := e.anchorRefToName[ref]
return anchorName, exists
}
func (e *Encoder) setSmartAlias(name string, ref uintptr) {
if !e.enableSmartAnchor {
return
}
e.aliasRefToName[ref] = name
}
func (e *Encoder) getSmartAlias(ref uintptr) (string, bool) {
if !e.enableSmartAnchor {
return "", false
}
aliasName, exists := e.aliasRefToName[ref]
return aliasName, exists
}
================================================
FILE: vendor/github.com/goccy/go-yaml/error.go
================================================
package yaml
import (
"fmt"
"github.com/goccy/go-yaml/ast"
"github.com/goccy/go-yaml/internal/errors"
)
var (
ErrInvalidQuery = errors.New("invalid query")
ErrInvalidPath = errors.New("invalid path instance")
ErrInvalidPathString = errors.New("invalid path string")
ErrNotFoundNode = errors.New("node not found")
ErrUnknownCommentPositionType = errors.New("unknown comment position type")
ErrInvalidCommentMapValue = errors.New("invalid comment map value. it must be not nil value")
ErrDecodeRequiredPointerType = errors.New("required pointer type value")
ErrExceededMaxDepth = errors.New("exceeded max depth")
FormatErrorWithToken = errors.FormatError
)
type (
SyntaxError = errors.SyntaxError
TypeError = errors.TypeError
OverflowError = errors.OverflowError
DuplicateKeyError = errors.DuplicateKeyError
UnknownFieldError = errors.UnknownFieldError
UnexpectedNodeTypeError = errors.UnexpectedNodeTypeError
Error = errors.Error
)
func ErrUnsupportedHeadPositionType(node ast.Node) error {
return fmt.Errorf("unsupported comment head position for %s", node.Type())
}
func ErrUnsupportedLinePositionType(node ast.Node) error {
return fmt.Errorf("unsupported comment line position for %s", node.Type())
}
func ErrUnsupportedFootPositionType(node ast.Node) error {
return fmt.Errorf("unsupported comment foot position for %s", node.Type())
}
// IsInvalidQueryError whether err is ErrInvalidQuery or not.
func IsInvalidQueryError(err error) bool {
return errors.Is(err, ErrInvalidQuery)
}
// IsInvalidPathError whether err is ErrInvalidPath or not.
func IsInvalidPathError(err error) bool {
return errors.Is(err, ErrInvalidPath)
}
// IsInvalidPathStringError whether err is ErrInvalidPathString or not.
func IsInvalidPathStringError(err error) bool {
return errors.Is(err, ErrInvalidPathString)
}
// IsNotFoundNodeError whether err is ErrNotFoundNode or not.
func IsNotFoundNodeError(err error) bool {
return errors.Is(err, ErrNotFoundNode)
}
// IsInvalidTokenTypeError whether err is ast.ErrInvalidTokenType or not.
func IsInvalidTokenTypeError(err error) bool {
return errors.Is(err, ast.ErrInvalidTokenType)
}
// IsInvalidAnchorNameError whether err is ast.ErrInvalidAnchorName or not.
func IsInvalidAnchorNameError(err error) bool {
return errors.Is(err, ast.ErrInvalidAnchorName)
}
// IsInvalidAliasNameError whether err is ast.ErrInvalidAliasName or not.
func IsInvalidAliasNameError(err error) bool {
return errors.Is(err, ast.ErrInvalidAliasName)
}
================================================
FILE: vendor/github.com/goccy/go-yaml/internal/errors/error.go
================================================
package errors
import (
"errors"
"fmt"
"reflect"
"github.com/goccy/go-yaml/ast"
"github.com/goccy/go-yaml/printer"
"github.com/goccy/go-yaml/token"
)
var (
As = errors.As
Is = errors.Is
New = errors.New
)
const (
defaultFormatColor = false
defaultIncludeSource = true
)
type Error interface {
error
GetToken() *token.Token
GetMessage() string
FormatError(bool, bool) string
}
var (
_ Error = new(SyntaxError)
_ Error = new(TypeError)
_ Error = new(OverflowError)
_ Error = new(DuplicateKeyError)
_ Error = new(UnknownFieldError)
_ Error = new(UnexpectedNodeTypeError)
)
type SyntaxError struct {
Message string
Token *token.Token
}
type TypeError struct {
DstType reflect.Type
SrcType reflect.Type
StructFieldName *string
Token *token.Token
}
type OverflowError struct {
DstType reflect.Type
SrcNum string
Token *token.Token
}
type DuplicateKeyError struct {
Message string
Token *token.Token
}
type UnknownFieldError struct {
Message string
Token *token.Token
}
type UnexpectedNodeTypeError struct {
Actual ast.NodeType
Expected ast.NodeType
Token *token.Token
}
// ErrSyntax create syntax error instance with message and token
func ErrSyntax(msg string, tk *token.Token) *SyntaxError {
return &SyntaxError{
Message: msg,
Token: tk,
}
}
// ErrOverflow creates an overflow error instance with message and a token.
func ErrOverflow(dstType reflect.Type, num string, tk *token.Token) *OverflowError {
return &OverflowError{
DstType: dstType,
SrcNum: num,
Token: tk,
}
}
// ErrTypeMismatch cerates an type mismatch error instance with token.
func ErrTypeMismatch(dstType, srcType reflect.Type, token *token.Token) *TypeError {
return &TypeError{
DstType: dstType,
SrcType: srcType,
Token: token,
}
}
// ErrDuplicateKey creates an duplicate key error instance with token.
func ErrDuplicateKey(msg string, tk *token.Token) *DuplicateKeyError {
return &DuplicateKeyError{
Message: msg,
Token: tk,
}
}
// ErrUnknownField creates an unknown field error instance with token.
func ErrUnknownField(msg string, tk *token.Token) *UnknownFieldError {
return &UnknownFieldError{
Message: msg,
Token: tk,
}
}
func ErrUnexpectedNodeType(actual, expected ast.NodeType, tk *token.Token) *UnexpectedNodeTypeError {
return &UnexpectedNodeTypeError{
Actual: actual,
Expected: expected,
Token: tk,
}
}
func (e *SyntaxError) GetMessage() string {
return e.Message
}
func (e *SyntaxError) GetToken() *token.Token {
return e.Token
}
func (e *SyntaxError) Error() string {
return e.FormatError(defaultFormatColor, defaultIncludeSource)
}
func (e *SyntaxError) FormatError(colored, inclSource bool) string {
return FormatError(e.Message, e.Token, colored, inclSource)
}
func (e *OverflowError) GetMessage() string {
return e.msg()
}
func (e *OverflowError) GetToken() *token.Token {
return e.Token
}
func (e *OverflowError) Error() string {
return e.FormatError(defaultFormatColor, defaultIncludeSource)
}
func (e *OverflowError) FormatError(colored, inclSource bool) string {
return FormatError(e.msg(), e.Token, colored, inclSource)
}
func (e *OverflowError) msg() string {
return fmt.Sprintf("cannot unmarshal %s into Go value of type %s ( overflow )", e.SrcNum, e.DstType)
}
func (e *TypeError) msg() string {
if e.StructFieldName != nil {
return fmt.Sprintf("cannot unmarshal %s into Go struct field %s of type %s", e.SrcType, *e.StructFieldName, e.DstType)
}
return fmt.Sprintf("cannot unmarshal %s into Go value of type %s", e.SrcType, e.DstType)
}
func (e *TypeError) GetMessage() string {
return e.msg()
}
func (e *TypeError) GetToken() *token.Token {
return e.Token
}
func (e *TypeError) Error() string {
return e.FormatError(defaultFormatColor, defaultIncludeSource)
}
func (e *TypeError) FormatError(colored, inclSource bool) string {
return FormatError(e.msg(), e.Token, colored, inclSource)
}
func (e *DuplicateKeyError) GetMessage() string {
return e.Message
}
func (e *DuplicateKeyError) GetToken() *token.Token {
return e.Token
}
func (e *DuplicateKeyError) Error() string {
return e.FormatError(defaultFormatColor, defaultIncludeSource)
}
func (e *DuplicateKeyError) FormatError(colored, inclSource bool) string {
return FormatError(e.Message, e.Token, colored, inclSource)
}
func (e *UnknownFieldError) GetMessage() string {
return e.Message
}
func (e *UnknownFieldError) GetToken() *token.Token {
return e.Token
}
func (e *UnknownFieldError) Error() string {
return e.FormatError(defaultFormatColor, defaultIncludeSource)
}
func (e *UnknownFieldError) FormatError(colored, inclSource bool) string {
return FormatError(e.Message, e.Token, colored, inclSource)
}
func (e *UnexpectedNodeTypeError) GetMessage() string {
return e.msg()
}
func (e *UnexpectedNodeTypeError) GetToken() *token.Token {
return e.Token
}
func (e *UnexpectedNodeTypeError) Error() string {
return e.FormatError(defaultFormatColor, defaultIncludeSource)
}
func (e *UnexpectedNodeTypeError) FormatError(colored, inclSource bool) string {
return FormatError(e.msg(), e.Token, colored, inclSource)
}
func (e *UnexpectedNodeTypeError) msg() string {
return fmt.Sprintf("%s was used where %s is expected", e.Actual.YAMLName(), e.Expected.YAMLName())
}
func FormatError(errMsg string, token *token.Token, colored, inclSource bool) string {
var pp printer.Printer
if token == nil {
return pp.PrintErrorMessage(errMsg, colored)
}
pos := fmt.Sprintf("[%d:%d] ", token.Position.Line, token.Position.Column)
msg := pp.PrintErrorMessage(fmt.Sprintf("%s%s", pos, errMsg), colored)
if inclSource {
msg += "\n" + pp.PrintErrorToken(token, colored)
}
return msg
}
================================================
FILE: vendor/github.com/goccy/go-yaml/internal/format/format.go
================================================
package format
import (
"strings"
"github.com/goccy/go-yaml/ast"
"github.com/goccy/go-yaml/token"
)
func FormatNodeWithResolvedAlias(n ast.Node, anchorNodeMap map[string]ast.Node) string {
tk := getFirstToken(n)
if tk == nil {
return ""
}
formatter := newFormatter(tk, hasComment(n))
formatter.anchorNodeMap = anchorNodeMap
return formatter.format(n)
}
func FormatNode(n ast.Node) string {
tk := getFirstToken(n)
if tk == nil {
return ""
}
return newFormatter(tk, hasComment(n)).format(n)
}
func FormatFile(file *ast.File) string {
if len(file.Docs) == 0 {
return ""
}
tk := getFirstToken(file.Docs[0])
if tk == nil {
return ""
}
return newFormatter(tk, hasCommentFile(file)).formatFile(file)
}
func hasCommentFile(f *ast.File) bool {
for _, doc := range f.Docs {
if hasComment(doc.Body) {
return true
}
}
return false
}
func hasComment(n ast.Node) bool {
if n == nil {
return false
}
switch nn := n.(type) {
case *ast.DocumentNode:
return hasComment(nn.Body)
case *ast.NullNode:
return nn.Comment != nil
case *ast.BoolNode:
return nn.Comment != nil
case *ast.IntegerNode:
return nn.Comment != nil
case *ast.FloatNode:
return nn.Comment != nil
case *ast.StringNode:
return nn.Comment != nil
case *ast.InfinityNode:
return nn.Comment != nil
case *ast.NanNode:
return nn.Comment != nil
case *ast.LiteralNode:
return nn.Comment != nil
case *ast.DirectiveNode:
if nn.Comment != nil {
return true
}
for _, value := range nn.Values {
if hasComment(value) {
return true
}
}
case *ast.TagNode:
if nn.Comment != nil {
return true
}
return hasComment(nn.Value)
case *ast.MappingNode:
if nn.Comment != nil || nn.FootComment != nil {
return true
}
for _, value := range nn.Values {
if value.Comment != nil || value.FootComment != nil {
return true
}
if hasComment(value.Key) {
return true
}
if hasComment(value.Value) {
return true
}
}
case *ast.MappingKeyNode:
return nn.Comment != nil
case *ast.MergeKeyNode:
return nn.Comment != nil
case *ast.SequenceNode:
if nn.Comment != nil || nn.FootComment != nil {
return true
}
for _, entry := range nn.Entries {
if entry.Comment != nil || entry.HeadComment != nil || entry.LineComment != nil {
return true
}
if hasComment(entry.Value) {
return true
}
}
case *ast.AnchorNode:
if nn.Comment != nil {
return true
}
if hasComment(nn.Name) || hasComment(nn.Value) {
return true
}
case *ast.AliasNode:
if nn.Comment != nil {
return true
}
if hasComment(nn.Value) {
return true
}
}
return false
}
func getFirstToken(n ast.Node) *token.Token {
if n == nil {
return nil
}
switch nn := n.(type) {
case *ast.DocumentNode:
if nn.Start != nil {
return nn.Start
}
return getFirstToken(nn.Body)
case *ast.NullNode:
return nn.Token
case *ast.BoolNode:
return nn.Token
case *ast.IntegerNode:
return nn.Token
case *ast.FloatNode:
return nn.Token
case *ast.StringNode:
return nn.Token
case *ast.InfinityNode:
return nn.Token
case *ast.NanNode:
return nn.Token
case *ast.LiteralNode:
return nn.Start
case *ast.DirectiveNode:
return nn.Start
case *ast.TagNode:
return nn.Start
case *ast.MappingNode:
if nn.IsFlowStyle {
return nn.Start
}
if len(nn.Values) == 0 {
return nn.Start
}
return getFirstToken(nn.Values[0].Key)
case *ast.MappingKeyNode:
return nn.Start
case *ast.MergeKeyNode:
return nn.Token
case *ast.SequenceNode:
return nn.Start
case *ast.AnchorNode:
return nn.Start
case *ast.AliasNode:
return nn.Start
}
return nil
}
type Formatter struct {
existsComment bool
tokenToOriginMap map[*token.Token]string
anchorNodeMap map[string]ast.Node
}
func newFormatter(tk *token.Token, existsComment bool) *Formatter {
tokenToOriginMap := make(map[*token.Token]string)
for tk.Prev != nil {
tk = tk.Prev
}
tokenToOriginMap[tk] = tk.Origin
var origin string
for tk.Next != nil {
tk = tk.Next
if tk.Type == token.CommentType {
origin += strings.Repeat("\n", strings.Count(normalizeNewLineChars(tk.Origin), "\n"))
continue
}
origin += tk.Origin
tokenToOriginMap[tk] = origin
origin = ""
}
return &Formatter{
existsComment: existsComment,
tokenToOriginMap: tokenToOriginMap,
}
}
func getIndentNumByFirstLineToken(tk *token.Token) int {
defaultIndent := tk.Position.Column - 1
// key: value
// ^
// next
if tk.Type == token.SequenceEntryType {
// If the current token is the sequence entry.
// the indent is calculated from the column value of the current token.
return defaultIndent
}
// key: value
// ^
// next
if tk.Next != nil && tk.Next.Type == token.MappingValueType {
// If the current token is the key in the mapping-value,
// the indent is calculated from the column value of the current token.
return defaultIndent
}
if tk.Prev == nil {
return defaultIndent
}
prev := tk.Prev
// key: value
// ^
// prev
if prev.Type == token.MappingValueType {
// If the current token is the value in the mapping-value,
// the indent is calculated from the column value of the key two steps back.
if prev.Prev == nil {
return defaultIndent
}
return prev.Prev.Position.Column - 1
}
// - value
// ^
// prev
if prev.Type == token.SequenceEntryType {
// If the value is not a mapping-value and the previous token was a sequence entry,
// the indent is calculated using the column value of the sequence entry token.
return prev.Position.Column - 1
}
return defaultIndent
}
func (f *Formatter) format(n ast.Node) string {
return f.trimSpacePrefix(
f.trimIndentSpace(
getIndentNumByFirstLineToken(getFirstToken(n)),
f.trimNewLineCharPrefix(f.formatNode(n)),
),
)
}
func (f *Formatter) formatFile(file *ast.File) string {
if len(file.Docs) == 0 {
return ""
}
var ret string
for _, doc := range file.Docs {
ret += f.formatDocument(doc)
}
return ret
}
func (f *Formatter) origin(tk *token.Token) string {
if tk == nil {
return ""
}
if f.existsComment {
return tk.Origin
}
return f.tokenToOriginMap[tk]
}
func (f *Formatter) formatDocument(n *ast.DocumentNode) string {
return f.origin(n.Start) + f.formatNode(n.Body) + f.origin(n.End)
}
func (f *Formatter) formatNull(n *ast.NullNode) string {
return f.origin(n.Token) + f.formatCommentGroup(n.Comment)
}
func (f *Formatter) formatString(n *ast.StringNode) string {
return f.origin(n.Token) + f.formatCommentGroup(n.Comment)
}
func (f *Formatter) formatInteger(n *ast.IntegerNode) string {
return f.origin(n.Token) + f.formatCommentGroup(n.Comment)
}
func (f *Formatter) formatFloat(n *ast.FloatNode) string {
return f.origin(n.Token) + f.formatCommentGroup(n.Comment)
}
func (f *Formatter) formatBool(n *ast.BoolNode) string {
return f.origin(n.Token) + f.formatCommentGroup(n.Comment)
}
func (f *Formatter) formatInfinity(n *ast.InfinityNode) string {
return f.origin(n.Token) + f.formatCommentGroup(n.Comment)
}
func (f *Formatter) formatNan(n *ast.NanNode) string {
return f.origin(n.Token) + f.formatCommentGroup(n.Comment)
}
func (f *Formatter) formatLiteral(n *ast.LiteralNode) string {
return f.origin(n.Start) + f.formatCommentGroup(n.Comment) + f.origin(n.Value.Token)
}
func (f *Formatter) formatMergeKey(n *ast.MergeKeyNode) string {
return f.origin(n.Token)
}
func (f *Formatter) formatMappingValue(n *ast.MappingValueNode) string {
return f.formatCommentGroup(n.Comment) +
f.origin(n.Key.GetToken()) + ":" + f.formatCommentGroup(n.Key.GetComment()) + f.formatNode(n.Value) +
f.formatCommentGroup(n.FootComment)
}
func (f *Formatter) formatDirective(n *ast.DirectiveNode) string {
ret := f.origin(n.Start) + f.formatNode(n.Name)
for _, val := range n.Values {
ret += f.formatNode(val)
}
return ret
}
func (f *Formatter) formatMapping(n *ast.MappingNode) string {
var ret string
if n.IsFlowStyle {
ret = f.origin(n.Start)
} else {
ret += f.formatCommentGroup(n.Comment)
}
for _, value := range n.Values {
if value.CollectEntry != nil {
ret += f.origin(value.CollectEntry)
}
ret += f.formatMappingValue(value)
}
if n.IsFlowStyle {
ret += f.origin(n.End)
ret += f.formatCommentGroup(n.Comment)
}
return ret
}
func (f *Formatter) formatTag(n *ast.TagNode) string {
return f.origin(n.Start) + f.formatNode(n.Value)
}
func (f *Formatter) formatMappingKey(n *ast.MappingKeyNode) string {
return f.origin(n.Start) + f.formatNode(n.Value)
}
func (f *Formatter) formatSequence(n *ast.SequenceNode) string {
var ret string
if n.IsFlowStyle {
ret = f.origin(n.Start)
} else {
// add head comment.
ret += f.formatCommentGroup(n.Comment)
}
for _, entry := range n.Entries {
ret += f.formatNode(entry)
}
if n.IsFlowStyle {
ret += f.origin(n.End)
ret += f.formatCommentGroup(n.Comment)
}
ret += f.formatCommentGroup(n.FootComment)
return ret
}
func (f *Formatter) formatSequenceEntry(n *ast.SequenceEntryNode) string {
return f.formatCommentGroup(n.HeadComment) + f.origin(n.Start) + f.formatCommentGroup(n.LineComment) + f.formatNode(n.Value)
}
func (f *Formatter) formatAnchor(n *ast.AnchorNode) string {
return f.origin(n.Start) + f.formatNode(n.Name) + f.formatNode(n.Value)
}
func (f *Formatter) formatAlias(n *ast.AliasNode) string {
if f.anchorNodeMap != nil {
anchorName := n.Value.GetToken().Value
node := f.anchorNodeMap[anchorName]
if node != nil {
formatted := f.formatNode(node)
// If formatted text contains newline characters, indentation needs to be considered.
if strings.Contains(formatted, "\n") {
// If the first character is not a newline, the first line should be output without indentation.
isIgnoredFirstLine := !strings.HasPrefix(formatted, "\n")
formatted = f.addIndentSpace(n.GetToken().Position.IndentNum, formatted, isIgnoredFirstLine)
}
return formatted
}
}
return f.origin(n.Start) + f.formatNode(n.Value)
}
func (f *Formatter) formatNode(n ast.Node) string {
switch nn := n.(type) {
case *ast.DocumentNode:
return f.formatDocument(nn)
case *ast.NullNode:
return f.formatNull(nn)
case *ast.BoolNode:
return f.formatBool(nn)
case *ast.IntegerNode:
return f.formatInteger(nn)
case *ast.FloatNode:
return f.formatFloat(nn)
case *ast.StringNode:
return f.formatString(nn)
case *ast.InfinityNode:
return f.formatInfinity(nn)
case *ast.NanNode:
return f.formatNan(nn)
case *ast.LiteralNode:
return f.formatLiteral(nn)
case *ast.DirectiveNode:
return f.formatDirective(nn)
case *ast.TagNode:
return f.formatTag(nn)
case *ast.MappingNode:
return f.formatMapping(nn)
case *ast.MappingKeyNode:
return f.formatMappingKey(nn)
case *ast.MappingValueNode:
return f.formatMappingValue(nn)
case *ast.MergeKeyNode:
return f.formatMergeKey(nn)
case *ast.SequenceNode:
return f.formatSequence(nn)
case *ast.SequenceEntryNode:
return f.formatSequenceEntry(nn)
case *ast.AnchorNode:
return f.formatAnchor(nn)
case *ast.AliasNode:
return f.formatAlias(nn)
}
return ""
}
func (f *Formatter) formatCommentGroup(g *ast.CommentGroupNode) string {
if g == nil {
return ""
}
var ret string
for _, cm := range g.Comments {
ret += f.formatComment(cm)
}
return ret
}
func (f *Formatter) formatComment(n *ast.CommentNode) string {
if n == nil {
return ""
}
return n.Token.Origin
}
// nolint: unused
func (f *Formatter) formatIndent(col int) string {
if col <= 1 {
return ""
}
return strings.Repeat(" ", col-1)
}
func (f *Formatter) trimNewLineCharPrefix(v string) string {
return strings.TrimLeftFunc(v, func(r rune) bool {
return r == '\n' || r == '\r'
})
}
func (f *Formatter) trimSpacePrefix(v string) string {
return strings.TrimLeftFunc(v, func(r rune) bool {
return r == ' '
})
}
func (f *Formatter) trimIndentSpace(trimIndentNum int, v string) string {
if trimIndentNum == 0 {
return v
}
lines := strings.Split(normalizeNewLineChars(v), "\n")
out := make([]string, 0, len(lines))
for _, line := range lines {
var cnt int
out = append(out, strings.TrimLeftFunc(line, func(r rune) bool {
cnt++
return r == ' ' && cnt <= trimIndentNum
}))
}
return strings.Join(out, "\n")
}
func (f *Formatter) addIndentSpace(indentNum int, v string, isIgnoredFirstLine bool) string {
if indentNum == 0 {
return v
}
indent := strings.Repeat(" ", indentNum)
lines := strings.Split(normalizeNewLineChars(v), "\n")
out := make([]string, 0, len(lines))
for idx, line := range lines {
if line == "" || (isIgnoredFirstLine && idx == 0) {
out = append(out, line)
continue
}
out = append(out, indent+line)
}
return strings.Join(out, "\n")
}
// normalizeNewLineChars normalize CRLF and CR to LF.
func normalizeNewLineChars(v string) string {
return strings.ReplaceAll(strings.ReplaceAll(v, "\r\n", "\n"), "\r", "\n")
}
================================================
FILE: vendor/github.com/goccy/go-yaml/lexer/lexer.go
================================================
package lexer
import (
"io"
"github.com/goccy/go-yaml/scanner"
"github.com/goccy/go-yaml/token"
)
// Tokenize split to token instances from string
func Tokenize(src string) token.Tokens {
var s scanner.Scanner
s.Init(src)
var tokens token.Tokens
for {
subTokens, err := s.Scan()
if err == io.EOF {
break
}
tokens.Add(subTokens...)
}
return tokens
}
================================================
FILE: vendor/github.com/goccy/go-yaml/option.go
================================================
package yaml
import (
"context"
"io"
"reflect"
"github.com/goccy/go-yaml/ast"
)
// DecodeOption functional option type for Decoder
type DecodeOption func(d *Decoder) error
// ReferenceReaders pass to Decoder that reference to anchor defined by passed readers
func ReferenceReaders(readers ...io.Reader) DecodeOption {
return func(d *Decoder) error {
d.referenceReaders = append(d.referenceReaders, readers...)
return nil
}
}
// ReferenceFiles pass to Decoder that reference to anchor defined by passed files
func ReferenceFiles(files ...string) DecodeOption {
return func(d *Decoder) error {
d.referenceFiles = files
return nil
}
}
// ReferenceDirs pass to Decoder that reference to anchor defined by files under the passed dirs
func ReferenceDirs(dirs ...string) DecodeOption {
return func(d *Decoder) error {
d.referenceDirs = dirs
return nil
}
}
// RecursiveDir search yaml file recursively from passed dirs by ReferenceDirs option
func RecursiveDir(isRecursive bool) DecodeOption {
return func(d *Decoder) error {
d.isRecursiveDir = isRecursive
return nil
}
}
// Validator set StructValidator instance to Decoder
func Validator(v StructValidator) DecodeOption {
return func(d *Decoder) error {
d.validator = v
return nil
}
}
// Strict enable DisallowUnknownField
func Strict() DecodeOption {
return func(d *Decoder) error {
d.disallowUnknownField = true
return nil
}
}
// DisallowUnknownField causes the Decoder to return an error when the destination
// is a struct and the input contains object keys which do not match any
// non-ignored, exported fields in the destination.
func DisallowUnknownField() DecodeOption {
return func(d *Decoder) error {
d.disallowUnknownField = true
return nil
}
}
// AllowFieldPrefixes, when paired with [DisallowUnknownField], allows fields
// with the specified prefixes to bypass the unknown field check.
func AllowFieldPrefixes(prefixes ...string) DecodeOption {
return func(d *Decoder) error {
d.allowedFieldPrefixes = append(d.allowedFieldPrefixes, prefixes...)
return nil
}
}
// AllowDuplicateMapKey ignore syntax error when mapping keys that are duplicates.
func AllowDuplicateMapKey() DecodeOption {
return func(d *Decoder) error {
d.allowDuplicateMapKey = true
return nil
}
}
// UseOrderedMap can be interpreted as a map,
// and uses MapSlice ( ordered map ) aggressively if there is no type specification
func UseOrderedMap() DecodeOption {
return func(d *Decoder) error {
d.useOrderedMap = true
return nil
}
}
// UseJSONUnmarshaler if neither `BytesUnmarshaler` nor `InterfaceUnmarshaler` is implemented
// and `UnmashalJSON([]byte)error` is implemented, convert the argument from `YAML` to `JSON` and then call it.
func UseJSONUnmarshaler() DecodeOption {
return func(d *Decoder) error {
d.useJSONUnmarshaler = true
return nil
}
}
// CustomUnmarshaler overrides any decoding process for the type specified in generics.
//
// NOTE: If RegisterCustomUnmarshaler and CustomUnmarshaler of DecodeOption are specified for the same type,
// the CustomUnmarshaler specified in DecodeOption takes precedence.
func CustomUnmarshaler[T any](unmarshaler func(*T, []byte) error) DecodeOption {
return func(d *Decoder) error {
var typ *T
d.customUnmarshalerMap[reflect.TypeOf(typ)] = func(ctx context.Context, v interface{}, b []byte) error {
return unmarshaler(v.(*T), b)
}
return nil
}
}
// CustomUnmarshalerContext overrides any decoding process for the type specified in generics.
// Similar to CustomUnmarshaler, but allows passing a context to the unmarshaler function.
func CustomUnmarshalerContext[T any](unmarshaler func(context.Context, *T, []byte) error) DecodeOption {
return func(d *Decoder) error {
var typ *T
d.customUnmarshalerMap[reflect.TypeOf(typ)] = func(ctx context.Context, v interface{}, b []byte) error {
return unmarshaler(ctx, v.(*T), b)
}
return nil
}
}
// EncodeOption functional option type for Encoder
type EncodeOption func(e *Encoder) error
// Indent change indent number
func Indent(spaces int) EncodeOption {
return func(e *Encoder) error {
e.indentNum = spaces
return nil
}
}
// IndentSequence causes sequence values to be indented the same value as Indent
func IndentSequence(indent bool) EncodeOption {
return func(e *Encoder) error {
e.indentSequence = indent
return nil
}
}
// UseSingleQuote determines if single or double quotes should be preferred for strings.
func UseSingleQuote(sq bool) EncodeOption {
return func(e *Encoder) error {
e.singleQuote = sq
return nil
}
}
// Flow encoding by flow style
func Flow(isFlowStyle bool) EncodeOption {
return func(e *Encoder) error {
e.isFlowStyle = isFlowStyle
return nil
}
}
// WithSmartAnchor when multiple map values share the same pointer,
// an anchor is automatically assigned to the first occurrence, and aliases are used for subsequent elements.
// The map key name is used as the anchor name by default.
// If key names conflict, a suffix is automatically added to avoid collisions.
// This is an experimental feature and cannot be used simultaneously with anchor tags.
func WithSmartAnchor() EncodeOption {
return func(e *Encoder) error {
e.enableSmartAnchor = true
return nil
}
}
// UseLiteralStyleIfMultiline causes encoding multiline strings with a literal syntax,
// no matter what characters they include
func UseLiteralStyleIfMultiline(useLiteralStyleIfMultiline bool) EncodeOption {
return func(e *Encoder) error {
e.useLiteralStyleIfMultiline = useLiteralStyleIfMultiline
return nil
}
}
// JSON encode in JSON format
func JSON() EncodeOption {
return func(e *Encoder) error {
e.isJSONStyle = true
e.isFlowStyle = true
return nil
}
}
// MarshalAnchor call back if encoder find an anchor during encoding
func MarshalAnchor(callback func(*ast.AnchorNode, interface{}) error) EncodeOption {
return func(e *Encoder) error {
e.anchorCallback = callback
return nil
}
}
// UseJSONMarshaler if neither `BytesMarshaler` nor `InterfaceMarshaler`
// nor `encoding.TextMarshaler` is implemented and `MarshalJSON()([]byte, error)` is implemented,
// call `MarshalJSON` to convert the returned `JSON` to `YAML` for processing.
func UseJSONMarshaler() EncodeOption {
return func(e *Encoder) error {
e.useJSONMarshaler = true
return nil
}
}
// CustomMarshaler overrides any encoding process for the type specified in generics.
//
// NOTE: If type T implements MarshalYAML for pointer receiver, the type specified in CustomMarshaler must be *T.
// If RegisterCustomMarshaler and CustomMarshaler of EncodeOption are specified for the same type,
// the CustomMarshaler specified in EncodeOption takes precedence.
func CustomMarshaler[T any](marshaler func(T) ([]byte, error)) EncodeOption {
return func(e *Encoder) error {
var typ T
e.customMarshalerMap[reflect.TypeOf(typ)] = func(ctx context.Context, v interface{}) ([]byte, error) {
return marshaler(v.(T))
}
return nil
}
}
// CustomMarshalerContext overrides any encoding process for the type specified in generics.
// Similar to CustomMarshaler, but allows passing a context to the marshaler function.
func CustomMarshalerContext[T any](marshaler func(context.Context, T) ([]byte, error)) EncodeOption {
return func(e *Encoder) error {
var typ T
e.customMarshalerMap[reflect.TypeOf(typ)] = func(ctx context.Context, v interface{}) ([]byte, error) {
return marshaler(ctx, v.(T))
}
return nil
}
}
// AutoInt automatically converts floating-point numbers to integers when the fractional part is zero.
// For example, a value of 1.0 will be encoded as 1.
func AutoInt() EncodeOption {
return func(e *Encoder) error {
e.autoInt = true
return nil
}
}
// OmitEmpty behaves in the same way as the interpretation of the omitempty tag in the encoding/json library.
// set on all the fields.
// In the current implementation, the omitempty tag is not implemented in the same way as encoding/json,
// so please specify this option if you expect the same behavior.
func OmitEmpty() EncodeOption {
return func(e *Encoder) error {
e.omitEmpty = true
return nil
}
}
// OmitZero forces the encoder to assume an `omitzero` struct tag is
// set on all the fields. See `Marshal` commentary for the `omitzero` tag logic.
func OmitZero() EncodeOption {
return func(e *Encoder) error {
e.omitZero = true
return nil
}
}
// CommentPosition type of the position for comment.
type CommentPosition int
const (
CommentHeadPosition CommentPosition = CommentPosition(iota)
CommentLinePosition
CommentFootPosition
)
func (p CommentPosition) String() string {
switch p {
case CommentHeadPosition:
return "Head"
case CommentLinePosition:
return "Line"
case CommentFootPosition:
return "Foot"
default:
return ""
}
}
// LineComment create a one-line comment for CommentMap.
func LineComment(text string) *Comment {
return &Comment{
Texts: []string{text},
Position: CommentLinePosition,
}
}
// HeadComment create a multiline comment for CommentMap.
func HeadComment(texts ...string) *Comment {
return &Comment{
Texts: texts,
Position: CommentHeadPosition,
}
}
// FootComment create a multiline comment for CommentMap.
func FootComment(texts ...string) *Comment {
return &Comment{
Texts: texts,
Position: CommentFootPosition,
}
}
// Comment raw data for comment.
type Comment struct {
Texts []string
Position CommentPosition
}
// CommentMap map of the position of the comment and the comment information.
type CommentMap map[string][]*Comment
// WithComment add a comment using the location and text information given in the CommentMap.
func WithComment(cm CommentMap) EncodeOption {
return func(e *Encoder) error {
commentMap := map[*Path][]*Comment{}
for k, v := range cm {
path, err := PathString(k)
if err != nil {
return err
}
commentMap[path] = v
}
e.commentMap = commentMap
return nil
}
}
// CommentToMap apply the position and content of comments in a YAML document to a CommentMap.
func CommentToMap(cm CommentMap) DecodeOption {
return func(d *Decoder) error {
if cm == nil {
return ErrInvalidCommentMapValue
}
d.toCommentMap = cm
return nil
}
}
================================================
FILE: vendor/github.com/goccy/go-yaml/parser/color.go
================================================
package parser
import "fmt"
const (
colorFgHiBlack int = iota + 90
colorFgHiRed
colorFgHiGreen
colorFgHiYellow
colorFgHiBlue
colorFgHiMagenta
colorFgHiCyan
)
var colorTable = []int{
colorFgHiRed,
colorFgHiGreen,
colorFgHiYellow,
colorFgHiBlue,
colorFgHiMagenta,
colorFgHiCyan,
}
func colorize(idx int, content string) string {
colorIdx := idx % len(colorTable)
color := colorTable[colorIdx]
return fmt.Sprintf("\x1b[1;%dm", color) + content + "\x1b[22;0m"
}
================================================
FILE: vendor/github.com/goccy/go-yaml/parser/context.go
================================================
package parser
import (
"fmt"
"strings"
"github.com/goccy/go-yaml/token"
)
// context context at parsing
type context struct {
tokenRef *tokenRef
path string
isFlow bool
}
type tokenRef struct {
tokens []*Token
size int
idx int
}
var pathSpecialChars = []string{
"$", "*", ".", "[", "]",
}
func containsPathSpecialChar(path string) bool {
for _, char := range pathSpecialChars {
if strings.Contains(path, char) {
return true
}
}
return false
}
func normalizePath(path string) string {
if containsPathSpecialChar(path) {
return fmt.Sprintf("'%s'", path)
}
return path
}
func (c *context) currentToken() *Token {
if c.tokenRef.idx >= c.tokenRef.size {
return nil
}
return c.tokenRef.tokens[c.tokenRef.idx]
}
func (c *context) isComment() bool {
return c.currentToken().Type() == token.CommentType
}
func (c *context) nextToken() *Token {
if c.tokenRef.idx+1 >= c.tokenRef.size {
return nil
}
return c.tokenRef.tokens[c.tokenRef.idx+1]
}
func (c *context) nextNotCommentToken() *Token {
for i := c.tokenRef.idx + 1; i < c.tokenRef.size; i++ {
tk := c.tokenRef.tokens[i]
if tk.Type() == token.CommentType {
continue
}
return tk
}
return nil
}
func (c *context) isTokenNotFound() bool {
return c.currentToken() == nil
}
func (c *context) withGroup(g *TokenGroup) *context {
ctx := *c
ctx.tokenRef = &tokenRef{
tokens: g.Tokens,
size: len(g.Tokens),
}
return &ctx
}
func (c *context) withChild(path string) *context {
ctx := *c
ctx.path = c.path + "." + normalizePath(path)
return &ctx
}
func (c *context) withIndex(idx uint) *context {
ctx := *c
ctx.path = c.path + "[" + fmt.Sprint(idx) + "]"
return &ctx
}
func (c *context) withFlow(isFlow bool) *context {
ctx := *c
ctx.isFlow = isFlow
return &ctx
}
func newContext() *context {
return &context{
path: "$",
}
}
func (c *context) goNext() {
ref := c.tokenRef
if ref.size <= ref.idx+1 {
ref.idx = ref.size
} else {
ref.idx++
}
}
func (c *context) next() bool {
return c.tokenRef.idx < c.tokenRef.size
}
func (c *context) insertNullToken(tk *Token) *Token {
nullToken := c.createImplicitNullToken(tk)
c.insertToken(nullToken)
c.goNext()
return nullToken
}
func (c *context) addNullValueToken(tk *Token) *Token {
nullToken := c.createImplicitNullToken(tk)
rawTk := nullToken.RawToken()
// add space for map or sequence value.
rawTk.Position.Column++
c.addToken(nullToken)
c.goNext()
return nullToken
}
func (c *context) createImplicitNullToken(base *Token) *Token {
pos := *(base.RawToken().Position)
pos.Column++
tk := token.New("null", " null", &pos)
tk.Type = token.ImplicitNullType
return &Token{Token: tk}
}
func (c *context) insertToken(tk *Token) {
ref := c.tokenRef
idx := ref.idx
if ref.size < idx {
return
}
if ref.size == idx {
curToken := ref.tokens[ref.size-1]
tk.RawToken().Next = curToken.RawToken()
curToken.RawToken().Prev = tk.RawToken()
ref.tokens = append(ref.tokens, tk)
ref.size = len(ref.tokens)
return
}
curToken := ref.tokens[idx]
tk.RawToken().Next = curToken.RawToken()
curToken.RawToken().Prev = tk.RawToken()
ref.tokens = append(ref.tokens[:idx+1], ref.tokens[idx:]...)
ref.tokens[idx] = tk
ref.size = len(ref.tokens)
}
func (c *context) addToken(tk *Token) {
ref := c.tokenRef
lastTk := ref.tokens[ref.size-1]
if lastTk.Group != nil {
lastTk = lastTk.Group.Last()
}
lastTk.RawToken().Next = tk.RawToken()
tk.RawToken().Prev = lastTk.RawToken()
ref.tokens = append(ref.tokens, tk)
ref.size = len(ref.tokens)
}
================================================
FILE: vendor/github.com/goccy/go-yaml/parser/node.go
================================================
package parser
import (
"fmt"
"github.com/goccy/go-yaml/ast"
"github.com/goccy/go-yaml/internal/errors"
"github.com/goccy/go-yaml/token"
)
func newMappingNode(ctx *context, tk *Token, isFlow bool, values ...*ast.MappingValueNode) (*ast.MappingNode, error) {
node := ast.Mapping(tk.RawToken(), isFlow, values...)
node.SetPath(ctx.path)
return node, nil
}
func newMappingValueNode(ctx *context, colonTk, entryTk *Token, key ast.MapKeyNode, value ast.Node) (*ast.MappingValueNode, error) {
node := ast.MappingValue(colonTk.RawToken(), key, value)
node.SetPath(ctx.path)
node.CollectEntry = entryTk.RawToken()
if key.GetToken().Position.Line == value.GetToken().Position.Line {
// originally key was commented, but now that null value has been added, value must be commented.
if err := setLineComment(ctx, value, colonTk); err != nil {
return nil, err
}
// set line comment by colonTk or entryTk.
if err := setLineComment(ctx, value, entryTk); err != nil {
return nil, err
}
} else {
if err := setLineComment(ctx, key, colonTk); err != nil {
return nil, err
}
// set line comment by colonTk or entryTk.
if err := setLineComment(ctx, key, entryTk); err != nil {
return nil, err
}
}
return node, nil
}
func newMappingKeyNode(ctx *context, tk *Token) (*ast.MappingKeyNode, error) {
node := ast.MappingKey(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newAnchorNode(ctx *context, tk *Token) (*ast.AnchorNode, error) {
node := ast.Anchor(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newAliasNode(ctx *context, tk *Token) (*ast.AliasNode, error) {
node := ast.Alias(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newDirectiveNode(ctx *context, tk *Token) (*ast.DirectiveNode, error) {
node := ast.Directive(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newMergeKeyNode(ctx *context, tk *Token) (*ast.MergeKeyNode, error) {
node := ast.MergeKey(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newNullNode(ctx *context, tk *Token) (*ast.NullNode, error) {
node := ast.Null(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newBoolNode(ctx *context, tk *Token) (*ast.BoolNode, error) {
node := ast.Bool(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newIntegerNode(ctx *context, tk *Token) (*ast.IntegerNode, error) {
node := ast.Integer(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newFloatNode(ctx *context, tk *Token) (*ast.FloatNode, error) {
node := ast.Float(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newInfinityNode(ctx *context, tk *Token) (*ast.InfinityNode, error) {
node := ast.Infinity(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newNanNode(ctx *context, tk *Token) (*ast.NanNode, error) {
node := ast.Nan(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newStringNode(ctx *context, tk *Token) (*ast.StringNode, error) {
node := ast.String(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newLiteralNode(ctx *context, tk *Token) (*ast.LiteralNode, error) {
node := ast.Literal(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newTagNode(ctx *context, tk *Token) (*ast.TagNode, error) {
node := ast.Tag(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newSequenceNode(ctx *context, tk *Token, isFlow bool) (*ast.SequenceNode, error) {
node := ast.Sequence(tk.RawToken(), isFlow)
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newTagDefaultScalarValueNode(ctx *context, tag *token.Token) (ast.ScalarNode, error) {
pos := *(tag.Position)
pos.Column++
var (
tk *Token
node ast.ScalarNode
)
switch token.ReservedTagKeyword(tag.Value) {
case token.IntegerTag:
tk = &Token{Token: token.New("0", "0", &pos)}
n, err := newIntegerNode(ctx, tk)
if err != nil {
return nil, err
}
node = n
case token.FloatTag:
tk = &Token{Token: token.New("0", "0", &pos)}
n, err := newFloatNode(ctx, tk)
if err != nil {
return nil, err
}
node = n
case token.StringTag, token.BinaryTag, token.TimestampTag:
tk = &Token{Token: token.New("", "", &pos)}
n, err := newStringNode(ctx, tk)
if err != nil {
return nil, err
}
node = n
case token.BooleanTag:
tk = &Token{Token: token.New("false", "false", &pos)}
n, err := newBoolNode(ctx, tk)
if err != nil {
return nil, err
}
node = n
case token.NullTag:
tk = &Token{Token: token.New("null", "null", &pos)}
n, err := newNullNode(ctx, tk)
if err != nil {
return nil, err
}
node = n
default:
return nil, errors.ErrSyntax(fmt.Sprintf("cannot assign default value for %q tag", tag.Value), tag)
}
ctx.insertToken(tk)
ctx.goNext()
return node, nil
}
func setLineComment(ctx *context, node ast.Node, tk *Token) error {
if tk == nil || tk.LineComment == nil {
return nil
}
comment := ast.CommentGroup([]*token.Token{tk.LineComment})
comment.SetPath(ctx.path)
if err := node.SetComment(comment); err != nil {
return err
}
return nil
}
func setHeadComment(cm *ast.CommentGroupNode, value ast.Node) error {
if cm == nil {
return nil
}
switch n := value.(type) {
case *ast.MappingNode:
if len(n.Values) != 0 && value.GetComment() == nil {
cm.SetPath(n.Values[0].GetPath())
return n.Values[0].SetComment(cm)
}
case *ast.MappingValueNode:
cm.SetPath(n.GetPath())
return n.SetComment(cm)
}
cm.SetPath(value.GetPath())
return value.SetComment(cm)
}
================================================
FILE: vendor/github.com/goccy/go-yaml/parser/option.go
================================================
package parser
// Option represents parser's option.
type Option func(p *parser)
// AllowDuplicateMapKey allow the use of keys with the same name in the same map,
// but by default, this is not permitted.
func AllowDuplicateMapKey() Option {
return func(p *parser) {
p.allowDuplicateMapKey = true
}
}
================================================
FILE: vendor/github.com/goccy/go-yaml/parser/parser.go
================================================
package parser
import (
"fmt"
"os"
"strings"
"github.com/goccy/go-yaml/ast"
"github.com/goccy/go-yaml/internal/errors"
"github.com/goccy/go-yaml/lexer"
"github.com/goccy/go-yaml/token"
)
type Mode uint
const (
ParseComments Mode = 1 << iota // parse comments and add them to AST
)
// ParseBytes parse from byte slice, and returns ast.File
func ParseBytes(bytes []byte, mode Mode, opts ...Option) (*ast.File, error) {
tokens := lexer.Tokenize(string(bytes))
f, err := Parse(tokens, mode, opts...)
if err != nil {
return nil, err
}
return f, nil
}
// Parse parse from token instances, and returns ast.File
func Parse(tokens token.Tokens, mode Mode, opts ...Option) (*ast.File, error) {
if tk := tokens.InvalidToken(); tk != nil {
return nil, errors.ErrSyntax(tk.Error, tk)
}
p, err := newParser(tokens, mode, opts)
if err != nil {
return nil, err
}
f, err := p.parse(newContext())
if err != nil {
return nil, err
}
return f, nil
}
// Parse parse from filename, and returns ast.File
func ParseFile(filename string, mode Mode, opts ...Option) (*ast.File, error) {
file, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
f, err := ParseBytes(file, mode, opts...)
if err != nil {
return nil, err
}
f.Name = filename
return f, nil
}
type YAMLVersion string
const (
YAML10 YAMLVersion = "1.0"
YAML11 YAMLVersion = "1.1"
YAML12 YAMLVersion = "1.2"
YAML13 YAMLVersion = "1.3"
)
var yamlVersionMap = map[string]YAMLVersion{
"1.0": YAML10,
"1.1": YAML11,
"1.2": YAML12,
"1.3": YAML13,
}
type parser struct {
tokens []*Token
pathMap map[string]ast.Node
yamlVersion YAMLVersion
allowDuplicateMapKey bool
secondaryTagDirective *ast.DirectiveNode
}
func newParser(tokens token.Tokens, mode Mode, opts []Option) (*parser, error) {
filteredTokens := []*token.Token{}
if mode&ParseComments != 0 {
filteredTokens = tokens
} else {
for _, tk := range tokens {
if tk.Type == token.CommentType {
continue
}
// keep prev/next reference between tokens containing comments
// https://github.com/goccy/go-yaml/issues/254
filteredTokens = append(filteredTokens, tk)
}
}
tks, err := CreateGroupedTokens(token.Tokens(filteredTokens))
if err != nil {
return nil, err
}
p := &parser{
tokens: tks,
pathMap: make(map[string]ast.Node),
}
for _, opt := range opts {
opt(p)
}
return p, nil
}
func (p *parser) parse(ctx *context) (*ast.File, error) {
file := &ast.File{Docs: []*ast.DocumentNode{}}
for _, token := range p.tokens {
doc, err := p.parseDocument(ctx, token.Group)
if err != nil {
return nil, err
}
file.Docs = append(file.Docs, doc)
}
return file, nil
}
func (p *parser) parseDocument(ctx *context, docGroup *TokenGroup) (*ast.DocumentNode, error) {
if len(docGroup.Tokens) == 0 {
return ast.Document(docGroup.RawToken(), nil), nil
}
p.pathMap = make(map[string]ast.Node)
var (
tokens = docGroup.Tokens
start *token.Token
end *token.Token
)
if docGroup.First().Type() == token.DocumentHeaderType {
start = docGroup.First().RawToken()
tokens = tokens[1:]
}
if docGroup.Last().Type() == token.DocumentEndType {
end = docGroup.Last().RawToken()
tokens = tokens[:len(tokens)-1]
defer func() {
// clear yaml version value if DocumentEnd token (...) is specified.
p.yamlVersion = ""
}()
}
if len(tokens) == 0 {
return ast.Document(docGroup.RawToken(), nil), nil
}
body, err := p.parseDocumentBody(ctx.withGroup(&TokenGroup{
Type: TokenGroupDocumentBody,
Tokens: tokens,
}))
if err != nil {
return nil, err
}
node := ast.Document(start, body)
node.End = end
return node, nil
}
func (p *parser) parseDocumentBody(ctx *context) (ast.Node, error) {
node, err := p.parseToken(ctx, ctx.currentToken())
if err != nil {
return nil, err
}
if ctx.next() {
return nil, errors.ErrSyntax("value is not allowed in this context", ctx.currentToken().RawToken())
}
return node, nil
}
func (p *parser) parseToken(ctx *context, tk *Token) (ast.Node, error) {
switch tk.GroupType() {
case TokenGroupMapKey, TokenGroupMapKeyValue:
return p.parseMap(ctx)
case TokenGroupDirective:
node, err := p.parseDirective(ctx.withGroup(tk.Group), tk.Group)
if err != nil {
return nil, err
}
ctx.goNext()
return node, nil
case TokenGroupDirectiveName:
node, err := p.parseDirectiveName(ctx.withGroup(tk.Group))
if err != nil {
return nil, err
}
ctx.goNext()
return node, nil
case TokenGroupAnchor:
node, err := p.parseAnchor(ctx.withGroup(tk.Group), tk.Group)
if err != nil {
return nil, err
}
ctx.goNext()
return node, nil
case TokenGroupAnchorName:
anchor, err := p.parseAnchorName(ctx.withGroup(tk.Group))
if err != nil {
return nil, err
}
ctx.goNext()
if ctx.isTokenNotFound() {
return nil, errors.ErrSyntax("could not find anchor value", tk.RawToken())
}
value, err := p.parseToken(ctx, ctx.currentToken())
if err != nil {
return nil, err
}
if _, ok := value.(*ast.AnchorNode); ok {
return nil, errors.ErrSyntax("anchors cannot be used consecutively", value.GetToken())
}
anchor.Value = value
return anchor, nil
case TokenGroupAlias:
node, err := p.parseAlias(ctx.withGroup(tk.Group))
if err != nil {
return nil, err
}
ctx.goNext()
return node, nil
case TokenGroupLiteral, TokenGroupFolded:
node, err := p.parseLiteral(ctx.withGroup(tk.Group))
if err != nil {
return nil, err
}
ctx.goNext()
return node, nil
case TokenGroupScalarTag:
node, err := p.parseTag(ctx.withGroup(tk.Group))
if err != nil {
return nil, err
}
ctx.goNext()
return node, nil
}
switch tk.Type() {
case token.CommentType:
return p.parseComment(ctx)
case token.TagType:
return p.parseTag(ctx)
case token.MappingStartType:
return p.parseFlowMap(ctx.withFlow(true))
case token.SequenceStartType:
return p.parseFlowSequence(ctx.withFlow(true))
case token.SequenceEntryType:
return p.parseSequence(ctx)
case token.SequenceEndType:
// SequenceEndType is always validated in parseFlowSequence.
// Therefore, if this is found in other cases, it is treated as a syntax error.
return nil, errors.ErrSyntax("could not find '[' character corresponding to ']'", tk.RawToken())
case token.MappingEndType:
// MappingEndType is always validated in parseFlowMap.
// Therefore, if this is found in other cases, it is treated as a syntax error.
return nil, errors.ErrSyntax("could not find '{' character corresponding to '}'", tk.RawToken())
case token.MappingValueType:
return nil, errors.ErrSyntax("found an invalid key for this map", tk.RawToken())
}
node, err := p.parseScalarValue(ctx, tk)
if err != nil {
return nil, err
}
ctx.goNext()
return node, nil
}
func (p *parser) parseScalarValue(ctx *context, tk *Token) (ast.ScalarNode, error) {
if tk.Group != nil {
switch tk.GroupType() {
case TokenGroupAnchor:
return p.parseAnchor(ctx.withGroup(tk.Group), tk.Group)
case TokenGroupAnchorName:
anchor, err := p.parseAnchorName(ctx.withGroup(tk.Group))
if err != nil {
return nil, err
}
ctx.goNext()
if ctx.isTokenNotFound() {
return nil, errors.ErrSyntax("could not find anchor value", tk.RawToken())
}
value, err := p.parseToken(ctx, ctx.currentToken())
if err != nil {
return nil, err
}
if _, ok := value.(*ast.AnchorNode); ok {
return nil, errors.ErrSyntax("anchors cannot be used consecutively", value.GetToken())
}
anchor.Value = value
return anchor, nil
case TokenGroupAlias:
return p.parseAlias(ctx.withGroup(tk.Group))
case TokenGroupLiteral, TokenGroupFolded:
return p.parseLiteral(ctx.withGroup(tk.Group))
case TokenGroupScalarTag:
return p.parseTag(ctx.withGroup(tk.Group))
default:
return nil, errors.ErrSyntax("unexpected scalar value", tk.RawToken())
}
}
switch tk.Type() {
case token.MergeKeyType:
return newMergeKeyNode(ctx, tk)
case token.NullType, token.ImplicitNullType:
return newNullNode(ctx, tk)
case token.BoolType:
return newBoolNode(ctx, tk)
case token.IntegerType, token.BinaryIntegerType, token.OctetIntegerType, token.HexIntegerType:
return newIntegerNode(ctx, tk)
case token.FloatType:
return newFloatNode(ctx, tk)
case token.InfinityType:
return newInfinityNode(ctx, tk)
case token.NanType:
return newNanNode(ctx, tk)
case token.StringType, token.SingleQuoteType, token.DoubleQuoteType:
return newStringNode(ctx, tk)
case token.TagType:
// this case applies when it is a scalar tag and its value does not exist.
// Examples of cases where the value does not exist include cases like `key: !!str,` or `!!str : value`.
return p.parseScalarTag(ctx)
}
return nil, errors.ErrSyntax("unexpected scalar value type", tk.RawToken())
}
func (p *parser) parseFlowMap(ctx *context) (*ast.MappingNode, error) {
node, err := newMappingNode(ctx, ctx.currentToken(), true)
if err != nil {
return nil, err
}
ctx.goNext() // skip MappingStart token
isFirst := true
for ctx.next() {
tk := ctx.currentToken()
if tk.Type() == token.MappingEndType {
node.End = tk.RawToken()
break
}
var entryTk *Token
if tk.Type() == token.CollectEntryType {
entryTk = tk
ctx.goNext()
} else if !isFirst {
return nil, errors.ErrSyntax("',' or '}' must be specified", tk.RawToken())
}
if tk := ctx.currentToken(); tk.Type() == token.MappingEndType {
// this case is here: "{ elem, }".
// In this case, ignore the last element and break mapping parsing.
node.End = tk.RawToken()
break
}
mapKeyTk := ctx.currentToken()
switch mapKeyTk.GroupType() {
case TokenGroupMapKeyValue:
value, err := p.parseMapKeyValue(ctx.withGroup(mapKeyTk.Group), mapKeyTk.Group, entryTk)
if err != nil {
return nil, err
}
node.Values = append(node.Values, value)
ctx.goNext()
case TokenGroupMapKey:
key, err := p.parseMapKey(ctx.withGroup(mapKeyTk.Group), mapKeyTk.Group)
if err != nil {
return nil, err
}
ctx := ctx.withChild(p.mapKeyText(key))
colonTk := mapKeyTk.Group.Last()
if p.isFlowMapDelim(ctx.nextToken()) {
value, err := newNullNode(ctx, ctx.insertNullToken(colonTk))
if err != nil {
return nil, err
}
mapValue, err := newMappingValueNode(ctx, colonTk, entryTk, key, value)
if err != nil {
return nil, err
}
node.Values = append(node.Values, mapValue)
ctx.goNext()
} else {
ctx.goNext()
if ctx.isTokenNotFound() {
return nil, errors.ErrSyntax("could not find map value", colonTk.RawToken())
}
value, err := p.parseToken(ctx, ctx.currentToken())
if err != nil {
return nil, err
}
mapValue, err := newMappingValueNode(ctx, colonTk, entryTk, key, value)
if err != nil {
return nil, err
}
node.Values = append(node.Values, mapValue)
}
default:
if !p.isFlowMapDelim(ctx.nextToken()) {
errTk := mapKeyTk
if errTk == nil {
errTk = tk
}
return nil, errors.ErrSyntax("could not find flow map content", errTk.RawToken())
}
key, err := p.parseScalarValue(ctx, mapKeyTk)
if err != nil {
return nil, err
}
value, err := newNullNode(ctx, ctx.insertNullToken(mapKeyTk))
if err != nil {
return nil, err
}
mapValue, err := newMappingValueNode(ctx, mapKeyTk, entryTk, key, value)
if err != nil {
return nil, err
}
node.Values = append(node.Values, mapValue)
ctx.goNext()
}
isFirst = false
}
if node.End == nil {
return nil, errors.ErrSyntax("could not find flow mapping end token '}'", node.Start)
}
// set line comment if exists. e.g.) } # comment
if err := setLineComment(ctx, node, ctx.currentToken()); err != nil {
return nil, err
}
ctx.goNext() // skip mapping end token.
return node, nil
}
func (p *parser) isFlowMapDelim(tk *Token) bool {
return tk.Type() == token.MappingEndType || tk.Type() == token.CollectEntryType
}
func (p *parser) parseMap(ctx *context) (*ast.MappingNode, error) {
keyTk := ctx.currentToken()
if keyTk.Group == nil {
return nil, errors.ErrSyntax("unexpected map key", keyTk.RawToken())
}
var keyValueNode *ast.MappingValueNode
if keyTk.GroupType() == TokenGroupMapKeyValue {
node, err := p.parseMapKeyValue(ctx.withGroup(keyTk.Group), keyTk.Group, nil)
if err != nil {
return nil, err
}
keyValueNode = node
ctx.goNext()
if err := p.validateMapKeyValueNextToken(ctx, keyTk, ctx.currentToken()); err != nil {
return nil, err
}
} else {
key, err := p.parseMapKey(ctx.withGroup(keyTk.Group), keyTk.Group)
if err != nil {
return nil, err
}
ctx.goNext()
valueTk := ctx.currentToken()
if keyTk.Line() == valueTk.Line() && valueTk.Type() == token.SequenceEntryType {
return nil, errors.ErrSyntax("block sequence entries are not allowed in this context", valueTk.RawToken())
}
ctx := ctx.withChild(p.mapKeyText(key))
value, err := p.parseMapValue(ctx, key, keyTk.Group.Last())
if err != nil {
return nil, err
}
node, err := newMappingValueNode(ctx, keyTk.Group.Last(), nil, key, value)
if err != nil {
return nil, err
}
keyValueNode = node
}
mapNode, err := newMappingNode(ctx, &Token{Token: keyValueNode.GetToken()}, false, keyValueNode)
if err != nil {
return nil, err
}
var tk *Token
if ctx.isComment() {
tk = ctx.nextNotCommentToken()
} else {
tk = ctx.currentToken()
}
for tk.Column() == keyTk.Column() {
typ := tk.Type()
if ctx.isFlow && typ == token.SequenceEndType {
// [
// key: value
// ] <=
break
}
if !p.isMapToken(tk) {
return nil, errors.ErrSyntax("non-map value is specified", tk.RawToken())
}
cm := p.parseHeadComment(ctx)
if typ == token.MappingEndType {
// a: {
// b: c
// } <=
ctx.goNext()
break
}
node, err := p.parseMap(ctx)
if err != nil {
return nil, err
}
if len(node.Values) != 0 {
if err := setHeadComment(cm, node.Values[0]); err != nil {
return nil, err
}
}
mapNode.Values = append(mapNode.Values, node.Values...)
if node.FootComment != nil {
mapNode.Values[len(mapNode.Values)-1].FootComment = node.FootComment
}
tk = ctx.currentToken()
}
if ctx.isComment() {
if keyTk.Column() <= ctx.currentToken().Column() {
// If the comment is in the same or deeper column as the last element column in map value,
// treat it as a footer comment for the last element.
if len(mapNode.Values) == 1 {
mapNode.Values[0].FootComment = p.parseFootComment(ctx, keyTk.Column())
mapNode.Values[0].FootComment.SetPath(mapNode.Values[0].Key.GetPath())
} else {
mapNode.FootComment = p.parseFootComment(ctx, keyTk.Column())
mapNode.FootComment.SetPath(mapNode.GetPath())
}
}
}
return mapNode, nil
}
func (p *parser) validateMapKeyValueNextToken(ctx *context, keyTk, tk *Token) error {
if tk == nil {
return nil
}
if tk.Column() <= keyTk.Column() {
return nil
}
if ctx.isComment() {
return nil
}
if ctx.isFlow && (tk.Type() == token.CollectEntryType || tk.Type() == token.SequenceEndType) {
return nil
}
// a: b
// c <= this token is invalid.
return errors.ErrSyntax("value is not allowed in this context. map key-value is pre-defined", tk.RawToken())
}
func (p *parser) isMapToken(tk *Token) bool {
if tk.Group == nil {
return tk.Type() == token.MappingStartType || tk.Type() == token.MappingEndType
}
g := tk.Group
return g.Type == TokenGroupMapKey || g.Type == TokenGroupMapKeyValue
}
func (p *parser) parseMapKeyValue(ctx *context, g *TokenGroup, entryTk *Token) (*ast.MappingValueNode, error) {
if g.Type != TokenGroupMapKeyValue {
return nil, errors.ErrSyntax("unexpected map key-value pair", g.RawToken())
}
if g.First().Group == nil {
return nil, errors.ErrSyntax("unexpected map key", g.RawToken())
}
keyGroup := g.First().Group
key, err := p.parseMapKey(ctx.withGroup(keyGroup), keyGroup)
if err != nil {
return nil, err
}
c := ctx.withChild(p.mapKeyText(key))
value, err := p.parseToken(c, g.Last())
if err != nil {
return nil, err
}
return newMappingValueNode(c, keyGroup.Last(), entryTk, key, value)
}
func (p *parser) parseMapKey(ctx *context, g *TokenGroup) (ast.MapKeyNode, error) {
if g.Type != TokenGroupMapKey {
return nil, errors.ErrSyntax("unexpected map key", g.RawToken())
}
if g.First().Type() == token.MappingKeyType {
mapKeyTk := g.First()
if mapKeyTk.Group != nil {
ctx = ctx.withGroup(mapKeyTk.Group)
}
key, err := newMappingKeyNode(ctx, mapKeyTk)
if err != nil {
return nil, err
}
ctx.goNext() // skip mapping key token
if ctx.isTokenNotFound() {
return nil, errors.ErrSyntax("could not find value for mapping key", mapKeyTk.RawToken())
}
scalar, err := p.parseScalarValue(ctx, ctx.currentToken())
if err != nil {
return nil, err
}
key.Value = scalar
keyText := p.mapKeyText(scalar)
keyPath := ctx.withChild(keyText).path
key.SetPath(keyPath)
if err := p.validateMapKey(ctx, key.GetToken(), keyPath, g.Last()); err != nil {
return nil, err
}
p.pathMap[keyPath] = key
return key, nil
}
if g.Last().Type() != token.MappingValueType {
return nil, errors.ErrSyntax("expected map key-value delimiter ':'", g.Last().RawToken())
}
scalar, err := p.parseScalarValue(ctx, g.First())
if err != nil {
return nil, err
}
key, ok := scalar.(ast.MapKeyNode)
if !ok {
return nil, errors.ErrSyntax("cannot take map-key node", scalar.GetToken())
}
keyText := p.mapKeyText(key)
keyPath := ctx.withChild(keyText).path
key.SetPath(keyPath)
if err := p.validateMapKey(ctx, key.GetToken(), keyPath, g.Last()); err != nil {
return nil, err
}
p.pathMap[keyPath] = key
return key, nil
}
func (p *parser) validateMapKey(ctx *context, tk *token.Token, keyPath string, colonTk *Token) error {
if !p.allowDuplicateMapKey {
if n, exists := p.pathMap[keyPath]; exists {
pos := n.GetToken().Position
return errors.ErrSyntax(
fmt.Sprintf("mapping key %q already defined at [%d:%d]", tk.Value, pos.Line, pos.Column),
tk,
)
}
}
origin := p.removeLeftWhiteSpace(tk.Origin)
if ctx.isFlow {
if tk.Type == token.StringType {
origin = p.removeRightWhiteSpace(origin)
if tk.Position.Line+p.newLineCharacterNum(origin) != colonTk.Line() {
return errors.ErrSyntax("map key definition includes an implicit line break", tk)
}
}
return nil
}
if tk.Type != token.StringType && tk.Type != token.SingleQuoteType && tk.Type != token.DoubleQuoteType {
return nil
}
if p.existsNewLineCharacter(origin) {
return errors.ErrSyntax("unexpected key name", tk)
}
return nil
}
func (p *parser) removeLeftWhiteSpace(src string) string {
// CR or LF or CRLF
return strings.TrimLeftFunc(src, func(r rune) bool {
return r == ' ' || r == '\r' || r == '\n'
})
}
func (p *parser) removeRightWhiteSpace(src string) string {
// CR or LF or CRLF
return strings.TrimRightFunc(src, func(r rune) bool {
return r == ' ' || r == '\r' || r == '\n'
})
}
func (p *parser) existsNewLineCharacter(src string) bool {
return p.newLineCharacterNum(src) > 0
}
func (p *parser) newLineCharacterNum(src string) int {
var num int
for i := 0; i < len(src); i++ {
switch src[i] {
case '\r':
if len(src) > i+1 && src[i+1] == '\n' {
i++
}
num++
case '\n':
num++
}
}
return num
}
func (p *parser) mapKeyText(n ast.Node) string {
if n == nil {
return ""
}
switch nn := n.(type) {
case *ast.MappingKeyNode:
return p.mapKeyText(nn.Value)
case *ast.TagNode:
return p.mapKeyText(nn.Value)
case *ast.AnchorNode:
return p.mapKeyText(nn.Value)
case *ast.AliasNode:
return ""
}
return n.GetToken().Value
}
func (p *parser) parseMapValue(ctx *context, key ast.MapKeyNode, colonTk *Token) (ast.Node, error) {
tk := ctx.currentToken()
if tk == nil {
return newNullNode(ctx, ctx.addNullValueToken(colonTk))
}
if ctx.isComment() {
tk = ctx.nextNotCommentToken()
}
keyCol := key.GetToken().Position.Column
keyLine := key.GetToken().Position.Line
if tk.Column() != keyCol && tk.Line() == keyLine && (tk.GroupType() == TokenGroupMapKey || tk.GroupType() == TokenGroupMapKeyValue) {
// a: b:
// ^
//
// a: b: c
// ^
return nil, errors.ErrSyntax("mapping value is not allowed in this context", tk.RawToken())
}
if tk.Column() == keyCol && p.isMapToken(tk) {
// in this case,
// ----
// key:
// next
return newNullNode(ctx, ctx.insertNullToken(colonTk))
}
if tk.Line() == keyLine && tk.GroupType() == TokenGroupAnchorName &&
ctx.nextToken().Column() == keyCol && p.isMapToken(ctx.nextToken()) {
// in this case,
// ----
// key: &anchor
// next
group := &TokenGroup{
Type: TokenGroupAnchor,
Tokens: []*Token{tk, ctx.createImplicitNullToken(tk)},
}
anchor, err := p.parseAnchor(ctx.withGroup(group), group)
if err != nil {
return nil, err
}
ctx.goNext()
return anchor, nil
}
if tk.Column() <= keyCol && tk.GroupType() == TokenGroupAnchorName {
// key:
// &anchor
return nil, errors.ErrSyntax("anchor is not allowed in this context", tk.RawToken())
}
if tk.Column() <= keyCol && tk.Type() == token.TagType {
// key:
// !!tag
return nil, errors.ErrSyntax("tag is not allowed in this context", tk.RawToken())
}
if tk.Column() < keyCol {
// in this case,
// ----
// key:
// next
return newNullNode(ctx, ctx.insertNullToken(colonTk))
}
if tk.Line() == keyLine && tk.GroupType() == TokenGroupAnchorName &&
ctx.nextToken().Column() < keyCol {
// in this case,
// ----
// key: &anchor
// next
group := &TokenGroup{
Type: TokenGroupAnchor,
Tokens: []*Token{tk, ctx.createImplicitNullToken(tk)},
}
anchor, err := p.parseAnchor(ctx.withGroup(group), group)
if err != nil {
return nil, err
}
ctx.goNext()
return anchor, nil
}
value, err := p.parseToken(ctx, ctx.currentToken())
if err != nil {
return nil, err
}
if err := p.validateAnchorValueInMapOrSeq(value, keyCol); err != nil {
return nil, err
}
return value, nil
}
func (p *parser) validateAnchorValueInMapOrSeq(value ast.Node, col int) error {
anchor, ok := value.(*ast.AnchorNode)
if !ok {
return nil
}
tag, ok := anchor.Value.(*ast.TagNode)
if !ok {
return nil
}
anchorTk := anchor.GetToken()
tagTk := tag.GetToken()
if anchorTk.Position.Line == tagTk.Position.Line {
// key:
// &anchor !!tag
//
// - &anchor !!tag
return nil
}
if tagTk.Position.Column <= col {
// key: &anchor
// !!tag
//
// - &anchor
// !!tag
return errors.ErrSyntax("tag is not allowed in this context", tagTk)
}
return nil
}
func (p *parser) parseAnchor(ctx *context, g *TokenGroup) (*ast.AnchorNode, error) {
anchorNameGroup := g.First().Group
anchor, err := p.parseAnchorName(ctx.withGroup(anchorNameGroup))
if err != nil {
return nil, err
}
ctx.goNext()
if ctx.isTokenNotFound() {
return nil, errors.ErrSyntax("could not find anchor value", anchor.GetToken())
}
value, err := p.parseToken(ctx, ctx.currentToken())
if err != nil {
return nil, err
}
if _, ok := value.(*ast.AnchorNode); ok {
return nil, errors.ErrSyntax("anchors cannot be used consecutively", value.GetToken())
}
anchor.Value = value
return anchor, nil
}
func (p *parser) parseAnchorName(ctx *context) (*ast.AnchorNode, error) {
anchor, err := newAnchorNode(ctx, ctx.currentToken())
if err != nil {
return nil, err
}
ctx.goNext()
if ctx.isTokenNotFound() {
return nil, errors.ErrSyntax("could not find anchor value", anchor.GetToken())
}
anchorName, err := p.parseScalarValue(ctx, ctx.currentToken())
if err != nil {
return nil, err
}
if anchorName == nil {
return nil, errors.ErrSyntax("unexpected anchor. anchor name is not scalar value", ctx.currentToken().RawToken())
}
anchor.Name = anchorName
return anchor, nil
}
func (p *parser) parseAlias(ctx *context) (*ast.AliasNode, error) {
alias, err := newAliasNode(ctx, ctx.currentToken())
if err != nil {
return nil, err
}
ctx.goNext()
if ctx.isTokenNotFound() {
return nil, errors.ErrSyntax("could not find alias value", alias.GetToken())
}
aliasName, err := p.parseScalarValue(ctx, ctx.currentToken())
if err != nil {
return nil, err
}
if aliasName == nil {
return nil, errors.ErrSyntax("unexpected alias. alias name is not scalar value", ctx.currentToken().RawToken())
}
alias.Value = aliasName
return alias, nil
}
func (p *parser) parseLiteral(ctx *context) (*ast.LiteralNode, error) {
node, err := newLiteralNode(ctx, ctx.currentToken())
if err != nil {
return nil, err
}
ctx.goNext() // skip literal/folded token
tk := ctx.currentToken()
if tk == nil {
value, err := newStringNode(ctx, &Token{Token: token.New("", "", node.Start.Position)})
if err != nil {
return nil, err
}
node.Value = value
return node, nil
}
value, err := p.parseToken(ctx, tk)
if err != nil {
return nil, err
}
str, ok := value.(*ast.StringNode)
if !ok {
return nil, errors.ErrSyntax("unexpected token. required string token", value.GetToken())
}
node.Value = str
return node, nil
}
func (p *parser) parseScalarTag(ctx *context) (*ast.TagNode, error) {
tag, err := p.parseTag(ctx)
if err != nil {
return nil, err
}
if tag.Value == nil {
return nil, errors.ErrSyntax("specified not scalar tag", tag.GetToken())
}
if _, ok := tag.Value.(ast.ScalarNode); !ok {
return nil, errors.ErrSyntax("specified not scalar tag", tag.GetToken())
}
return tag, nil
}
func (p *parser) parseTag(ctx *context) (*ast.TagNode, error) {
tagTk := ctx.currentToken()
tagRawTk := tagTk.RawToken()
node, err := newTagNode(ctx, tagTk)
if err != nil {
return nil, err
}
ctx.goNext()
comment := p.parseHeadComment(ctx)
var tagValue ast.Node
if p.secondaryTagDirective != nil {
value, err := newStringNode(ctx, ctx.currentToken())
if err != nil {
return nil, err
}
tagValue = value
node.Directive = p.secondaryTagDirective
} else {
value, err := p.parseTagValue(ctx, tagRawTk, ctx.currentToken())
if err != nil {
return nil, err
}
tagValue = value
}
if err := setHeadComment(comment, tagValue); err != nil {
return nil, err
}
node.Value = tagValue
return node, nil
}
func (p *parser) parseTagValue(ctx *context, tagRawTk *token.Token, tk *Token) (ast.Node, error) {
if tk == nil {
return newNullNode(ctx, ctx.createImplicitNullToken(&Token{Token: tagRawTk}))
}
switch token.ReservedTagKeyword(tagRawTk.Value) {
case token.MappingTag, token.SetTag:
if !p.isMapToken(tk) {
return nil, errors.ErrSyntax("could not find map", tk.RawToken())
}
if tk.Type() == token.MappingStartType {
return p.parseFlowMap(ctx.withFlow(true))
}
return p.parseMap(ctx)
case token.IntegerTag, token.FloatTag, token.StringTag, token.BinaryTag, token.TimestampTag, token.BooleanTag, token.NullTag:
if tk.GroupType() == TokenGroupLiteral || tk.GroupType() == TokenGroupFolded {
return p.parseLiteral(ctx.withGroup(tk.Group))
} else if tk.Type() == token.CollectEntryType || tk.Type() == token.MappingValueType {
return newTagDefaultScalarValueNode(ctx, tagRawTk)
}
scalar, err := p.parseScalarValue(ctx, tk)
if err != nil {
return nil, err
}
ctx.goNext()
return scalar, nil
case token.SequenceTag, token.OrderedMapTag:
if tk.Type() == token.SequenceStartType {
return p.parseFlowSequence(ctx.withFlow(true))
}
return p.parseSequence(ctx)
}
return p.parseToken(ctx, tk)
}
func (p *parser) parseFlowSequence(ctx *context) (*ast.SequenceNode, error) {
node, err := newSequenceNode(ctx, ctx.currentToken(), true)
if err != nil {
return nil, err
}
ctx.goNext() // skip SequenceStart token
isFirst := true
for ctx.next() {
tk := ctx.currentToken()
if tk.Type() == token.SequenceEndType {
node.End = tk.RawToken()
break
}
var entryTk *Token
if tk.Type() == token.CollectEntryType {
if isFirst {
return nil, errors.ErrSyntax("expected sequence element, but found ','", tk.RawToken())
}
entryTk = tk
ctx.goNext()
} else if !isFirst {
return nil, errors.ErrSyntax("',' or ']' must be specified", tk.RawToken())
}
if tk := ctx.currentToken(); tk.Type() == token.SequenceEndType {
// this case is here: "[ elem, ]".
// In this case, ignore the last element and break sequence parsing.
node.End = tk.RawToken()
break
}
if ctx.isTokenNotFound() {
break
}
ctx := ctx.withIndex(uint(len(node.Values)))
value, err := p.parseToken(ctx, ctx.currentToken())
if err != nil {
return nil, err
}
node.Values = append(node.Values, value)
seqEntry := ast.SequenceEntry(entryTk.RawToken(), value, nil)
if err := setLineComment(ctx, seqEntry, entryTk); err != nil {
return nil, err
}
seqEntry.SetPath(ctx.path)
node.Entries = append(node.Entries, seqEntry)
isFirst = false
}
if node.End == nil {
return nil, errors.ErrSyntax("sequence end token ']' not found", node.Start)
}
// set line comment if exists. e.g.) ] # comment
if err := setLineComment(ctx, node, ctx.currentToken()); err != nil {
return nil, err
}
ctx.goNext() // skip sequence end token.
return node, nil
}
func (p *parser) parseSequence(ctx *context) (*ast.SequenceNode, error) {
seqTk := ctx.currentToken()
seqNode, err := newSequenceNode(ctx, seqTk, false)
if err != nil {
return nil, err
}
tk := seqTk
for tk.Type() == token.SequenceEntryType && tk.Column() == seqTk.Column() {
seqTk := tk
headComment := p.parseHeadComment(ctx)
ctx.goNext() // skip sequence entry token
ctx := ctx.withIndex(uint(len(seqNode.Values)))
value, err := p.parseSequenceValue(ctx, seqTk)
if err != nil {
return nil, err
}
seqEntry := ast.SequenceEntry(seqTk.RawToken(), value, headComment)
if err := setLineComment(ctx, seqEntry, seqTk); err != nil {
return nil, err
}
seqEntry.SetPath(ctx.path)
seqNode.ValueHeadComments = append(seqNode.ValueHeadComments, headComment)
seqNode.Values = append(seqNode.Values, value)
seqNode.Entries = append(seqNode.Entries, seqEntry)
if ctx.isComment() {
tk = ctx.nextNotCommentToken()
} else {
tk = ctx.currentToken()
}
}
if ctx.isComment() {
if seqTk.Column() <= ctx.currentToken().Column() {
// If the comment is in the same or deeper column as the last element column in sequence value,
// treat it as a footer comment for the last element.
seqNode.FootComment = p.parseFootComment(ctx, seqTk.Column())
if len(seqNode.Values) != 0 {
seqNode.FootComment.SetPath(seqNode.Values[len(seqNode.Values)-1].GetPath())
}
}
}
return seqNode, nil
}
func (p *parser) parseSequenceValue(ctx *context, seqTk *Token) (ast.Node, error) {
tk := ctx.currentToken()
if tk == nil {
return newNullNode(ctx, ctx.addNullValueToken(seqTk))
}
if ctx.isComment() {
tk = ctx.nextNotCommentToken()
}
seqCol := seqTk.Column()
seqLine := seqTk.Line()
if tk.Column() == seqCol && tk.Type() == token.SequenceEntryType {
// in this case,
// ----
// -
// -
return newNullNode(ctx, ctx.insertNullToken(seqTk))
}
if tk.Line() == seqLine && tk.GroupType() == TokenGroupAnchorName &&
ctx.nextToken().Column() == seqCol && ctx.nextToken().Type() == token.SequenceEntryType {
// in this case,
// ----
// - &anchor
// -
group := &TokenGroup{
Type: TokenGroupAnchor,
Tokens: []*Token{tk, ctx.createImplicitNullToken(tk)},
}
anchor, err := p.parseAnchor(ctx.withGroup(group), group)
if err != nil {
return nil, err
}
ctx.goNext()
return anchor, nil
}
if tk.Column() <= seqCol && tk.GroupType() == TokenGroupAnchorName {
// -
// &anchor
return nil, errors.ErrSyntax("anchor is not allowed in this sequence context", tk.RawToken())
}
if tk.Column() <= seqCol && tk.Type() == token.TagType {
// -
// !!tag
return nil, errors.ErrSyntax("tag is not allowed in this sequence context", tk.RawToken())
}
if tk.Column() < seqCol {
// in this case,
// ----
// -
// next
return newNullNode(ctx, ctx.insertNullToken(seqTk))
}
if tk.Line() == seqLine && tk.GroupType() == TokenGroupAnchorName &&
ctx.nextToken().Column() < seqCol {
// in this case,
// ----
// - &anchor
// next
group := &TokenGroup{
Type: TokenGroupAnchor,
Tokens: []*Token{tk, ctx.createImplicitNullToken(tk)},
}
anchor, err := p.parseAnchor(ctx.withGroup(group), group)
if err != nil {
return nil, err
}
ctx.goNext()
return anchor, nil
}
value, err := p.parseToken(ctx, ctx.currentToken())
if err != nil {
return nil, err
}
if err := p.validateAnchorValueInMapOrSeq(value, seqCol); err != nil {
return nil, err
}
return value, nil
}
func (p *parser) parseDirective(ctx *context, g *TokenGroup) (*ast.DirectiveNode, error) {
directiveNameGroup := g.First().Group
directive, err := p.parseDirectiveName(ctx.withGroup(directiveNameGroup))
if err != nil {
return nil, err
}
switch directive.Name.String() {
case "YAML":
if len(g.Tokens) != 2 {
return nil, errors.ErrSyntax("unexpected format YAML directive", g.First().RawToken())
}
valueTk := g.Tokens[1]
valueRawTk := valueTk.RawToken()
value := valueRawTk.Value
ver, exists := yamlVersionMap[value]
if !exists {
return nil, errors.ErrSyntax(fmt.Sprintf("unknown YAML version %q", value), valueRawTk)
}
if p.yamlVersion != "" {
return nil, errors.ErrSyntax("YAML version has already been specified", valueRawTk)
}
p.yamlVersion = ver
versionNode, err := newStringNode(ctx, valueTk)
if err != nil {
return nil, err
}
directive.Values = append(directive.Values, versionNode)
case "TAG":
if len(g.Tokens) != 3 {
return nil, errors.ErrSyntax("unexpected format TAG directive", g.First().RawToken())
}
tagKey, err := newStringNode(ctx, g.Tokens[1])
if err != nil {
return nil, err
}
if tagKey.Value == "!!" {
p.secondaryTagDirective = directive
}
tagValue, err := newStringNode(ctx, g.Tokens[2])
if err != nil {
return nil, err
}
directive.Values = append(directive.Values, tagKey, tagValue)
default:
if len(g.Tokens) > 1 {
for _, tk := range g.Tokens[1:] {
value, err := newStringNode(ctx, tk)
if err != nil {
return nil, err
}
directive.Values = append(directive.Values, value)
}
}
}
return directive, nil
}
func (p *parser) parseDirectiveName(ctx *context) (*ast.DirectiveNode, error) {
directive, err := newDirectiveNode(ctx, ctx.currentToken())
if err != nil {
return nil, err
}
ctx.goNext()
if ctx.isTokenNotFound() {
return nil, errors.ErrSyntax("could not find directive value", directive.GetToken())
}
directiveName, err := p.parseScalarValue(ctx, ctx.currentToken())
if err != nil {
return nil, err
}
if directiveName == nil {
return nil, errors.ErrSyntax("unexpected directive. directive name is not scalar value", ctx.currentToken().RawToken())
}
directive.Name = directiveName
return directive, nil
}
func (p *parser) parseComment(ctx *context) (ast.Node, error) {
cm := p.parseHeadComment(ctx)
if ctx.isTokenNotFound() {
return cm, nil
}
node, err := p.parseToken(ctx, ctx.currentToken())
if err != nil {
return nil, err
}
if err := setHeadComment(cm, node); err != nil {
return nil, err
}
return node, nil
}
func (p *parser) parseHeadComment(ctx *context) *ast.CommentGroupNode {
tks := []*token.Token{}
for ctx.isComment() {
tks = append(tks, ctx.currentToken().RawToken())
ctx.goNext()
}
if len(tks) == 0 {
return nil
}
return ast.CommentGroup(tks)
}
func (p *parser) parseFootComment(ctx *context, col int) *ast.CommentGroupNode {
tks := []*token.Token{}
for ctx.isComment() && col <= ctx.currentToken().Column() {
tks = append(tks, ctx.currentToken().RawToken())
ctx.goNext()
}
if len(tks) == 0 {
return nil
}
return ast.CommentGroup(tks)
}
================================================
FILE: vendor/github.com/goccy/go-yaml/parser/token.go
================================================
package parser
import (
"fmt"
"os"
"strings"
"github.com/goccy/go-yaml/internal/errors"
"github.com/goccy/go-yaml/token"
)
type TokenGroupType int
const (
TokenGroupNone TokenGroupType = iota
TokenGroupDirective
TokenGroupDirectiveName
TokenGroupDocument
TokenGroupDocumentBody
TokenGroupAnchor
TokenGroupAnchorName
TokenGroupAlias
TokenGroupLiteral
TokenGroupFolded
TokenGroupScalarTag
TokenGroupMapKey
TokenGroupMapKeyValue
)
func (t TokenGroupType) String() string {
switch t {
case TokenGroupNone:
return "none"
case TokenGroupDirective:
return "directive"
case TokenGroupDirectiveName:
return "directive_name"
case TokenGroupDocument:
return "document"
case TokenGroupDocumentBody:
return "document_body"
case TokenGroupAnchor:
return "anchor"
case TokenGroupAnchorName:
return "anchor_name"
case TokenGroupAlias:
return "alias"
case TokenGroupLiteral:
return "literal"
case TokenGroupFolded:
return "folded"
case TokenGroupScalarTag:
return "scalar_tag"
case TokenGroupMapKey:
return "map_key"
case TokenGroupMapKeyValue:
return "map_key_value"
}
return "none"
}
type Token struct {
Token *token.Token
Group *TokenGroup
LineComment *token.Token
}
func (t *Token) RawToken() *token.Token {
if t == nil {
return nil
}
if t.Token != nil {
return t.Token
}
return t.Group.RawToken()
}
func (t *Token) Type() token.Type {
if t == nil {
return 0
}
if t.Token != nil {
return t.Token.Type
}
return t.Group.TokenType()
}
func (t *Token) GroupType() TokenGroupType {
if t == nil {
return TokenGroupNone
}
if t.Token != nil {
return TokenGroupNone
}
return t.Group.Type
}
func (t *Token) Line() int {
if t == nil {
return 0
}
if t.Token != nil {
return t.Token.Position.Line
}
return t.Group.Line()
}
func (t *Token) Column() int {
if t == nil {
return 0
}
if t.Token != nil {
return t.Token.Position.Column
}
return t.Group.Column()
}
func (t *Token) SetGroupType(typ TokenGroupType) {
if t.Group == nil {
return
}
t.Group.Type = typ
}
func (t *Token) Dump() {
ctx := new(groupTokenRenderContext)
if t.Token != nil {
fmt.Fprint(os.Stdout, t.Token.Value)
return
}
t.Group.dump(ctx)
fmt.Fprintf(os.Stdout, "\n")
}
func (t *Token) dump(ctx *groupTokenRenderContext) {
if t.Token != nil {
fmt.Fprint(os.Stdout, t.Token.Value)
return
}
t.Group.dump(ctx)
}
type groupTokenRenderContext struct {
num int
}
type TokenGroup struct {
Type TokenGroupType
Tokens []*Token
}
func (g *TokenGroup) First() *Token {
if len(g.Tokens) == 0 {
return nil
}
return g.Tokens[0]
}
func (g *TokenGroup) Last() *Token {
if len(g.Tokens) == 0 {
return nil
}
return g.Tokens[len(g.Tokens)-1]
}
func (g *TokenGroup) dump(ctx *groupTokenRenderContext) {
num := ctx.num
fmt.Fprint(os.Stdout, colorize(num, "("))
ctx.num++
for _, tk := range g.Tokens {
tk.dump(ctx)
}
fmt.Fprint(os.Stdout, colorize(num, ")"))
}
func (g *TokenGroup) RawToken() *token.Token {
if len(g.Tokens) == 0 {
return nil
}
return g.Tokens[0].RawToken()
}
func (g *TokenGroup) Line() int {
if len(g.Tokens) == 0 {
return 0
}
return g.Tokens[0].Line()
}
func (g *TokenGroup) Column() int {
if len(g.Tokens) == 0 {
return 0
}
return g.Tokens[0].Column()
}
func (g *TokenGroup) TokenType() token.Type {
if len(g.Tokens) == 0 {
return 0
}
return g.Tokens[0].Type()
}
func CreateGroupedTokens(tokens token.Tokens) ([]*Token, error) {
var err error
tks := newTokens(tokens)
tks = createLineCommentTokenGroups(tks)
tks, err = createLiteralAndFoldedTokenGroups(tks)
if err != nil {
return nil, err
}
tks, err = createAnchorAndAliasTokenGroups(tks)
if err != nil {
return nil, err
}
tks, err = createScalarTagTokenGroups(tks)
if err != nil {
return nil, err
}
tks, err = createAnchorWithScalarTagTokenGroups(tks)
if err != nil {
return nil, err
}
tks, err = createMapKeyTokenGroups(tks)
if err != nil {
return nil, err
}
tks = createMapKeyValueTokenGroups(tks)
tks, err = createDirectiveTokenGroups(tks)
if err != nil {
return nil, err
}
tks, err = createDocumentTokens(tks)
if err != nil {
return nil, err
}
return tks, nil
}
func newTokens(tks token.Tokens) []*Token {
ret := make([]*Token, 0, len(tks))
for _, tk := range tks {
ret = append(ret, &Token{Token: tk})
}
return ret
}
func createLineCommentTokenGroups(tokens []*Token) []*Token {
ret := make([]*Token, 0, len(tokens))
for i := 0; i < len(tokens); i++ {
tk := tokens[i]
switch tk.Type() {
case token.CommentType:
if i > 0 && tokens[i-1].Line() == tk.Line() {
tokens[i-1].LineComment = tk.RawToken()
} else {
ret = append(ret, tk)
}
default:
ret = append(ret, tk)
}
}
return ret
}
func createLiteralAndFoldedTokenGroups(tokens []*Token) ([]*Token, error) {
ret := make([]*Token, 0, len(tokens))
for i := 0; i < len(tokens); i++ {
tk := tokens[i]
switch tk.Type() {
case token.LiteralType:
tks := []*Token{tk}
if i+1 < len(tokens) {
tks = append(tks, tokens[i+1])
}
ret = append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupLiteral,
Tokens: tks,
},
})
i++
case token.FoldedType:
tks := []*Token{tk}
if i+1 < len(tokens) {
tks = append(tks, tokens[i+1])
}
ret = append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupFolded,
Tokens: tks,
},
})
i++
default:
ret = append(ret, tk)
}
}
return ret, nil
}
func createAnchorAndAliasTokenGroups(tokens []*Token) ([]*Token, error) {
ret := make([]*Token, 0, len(tokens))
for i := 0; i < len(tokens); i++ {
tk := tokens[i]
switch tk.Type() {
case token.AnchorType:
if i+1 >= len(tokens) {
return nil, errors.ErrSyntax("undefined anchor name", tk.RawToken())
}
if i+2 >= len(tokens) {
return nil, errors.ErrSyntax("undefined anchor value", tk.RawToken())
}
anchorName := &Token{
Group: &TokenGroup{
Type: TokenGroupAnchorName,
Tokens: []*Token{tk, tokens[i+1]},
},
}
valueTk := tokens[i+2]
if tk.Line() == valueTk.Line() && valueTk.Type() == token.SequenceEntryType {
return nil, errors.ErrSyntax("sequence entries are not allowed after anchor on the same line", valueTk.RawToken())
}
if tk.Line() == valueTk.Line() && isScalarType(valueTk) {
ret = append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupAnchor,
Tokens: []*Token{anchorName, valueTk},
},
})
i++
} else {
ret = append(ret, anchorName)
}
i++
case token.AliasType:
if i+1 == len(tokens) {
return nil, errors.ErrSyntax("undefined alias name", tk.RawToken())
}
ret = append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupAlias,
Tokens: []*Token{tk, tokens[i+1]},
},
})
i++
default:
ret = append(ret, tk)
}
}
return ret, nil
}
func createScalarTagTokenGroups(tokens []*Token) ([]*Token, error) {
ret := make([]*Token, 0, len(tokens))
for i := 0; i < len(tokens); i++ {
tk := tokens[i]
if tk.Type() != token.TagType {
ret = append(ret, tk)
continue
}
tag := tk.RawToken()
if strings.HasPrefix(tag.Value, "!!") {
// secondary tag.
switch token.ReservedTagKeyword(tag.Value) {
case token.IntegerTag, token.FloatTag, token.StringTag, token.BinaryTag, token.TimestampTag, token.BooleanTag, token.NullTag:
if len(tokens) <= i+1 {
ret = append(ret, tk)
continue
}
if tk.Line() != tokens[i+1].Line() {
ret = append(ret, tk)
continue
}
if tokens[i+1].GroupType() == TokenGroupAnchorName {
ret = append(ret, tk)
continue
}
if isScalarType(tokens[i+1]) {
ret = append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupScalarTag,
Tokens: []*Token{tk, tokens[i+1]},
},
})
i++
} else {
ret = append(ret, tk)
}
case token.MergeTag:
if len(tokens) <= i+1 {
ret = append(ret, tk)
continue
}
if tk.Line() != tokens[i+1].Line() {
ret = append(ret, tk)
continue
}
if tokens[i+1].GroupType() == TokenGroupAnchorName {
ret = append(ret, tk)
continue
}
if tokens[i+1].Type() != token.MergeKeyType {
return nil, errors.ErrSyntax("could not find merge key", tokens[i+1].RawToken())
}
ret = append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupScalarTag,
Tokens: []*Token{tk, tokens[i+1]},
},
})
i++
default:
ret = append(ret, tk)
}
} else {
if len(tokens) <= i+1 {
ret = append(ret, tk)
continue
}
if tk.Line() != tokens[i+1].Line() {
ret = append(ret, tk)
continue
}
if tokens[i+1].GroupType() == TokenGroupAnchorName {
ret = append(ret, tk)
continue
}
if isFlowType(tokens[i+1]) {
ret = append(ret, tk)
continue
}
ret = append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupScalarTag,
Tokens: []*Token{tk, tokens[i+1]},
},
})
i++
}
}
return ret, nil
}
func createAnchorWithScalarTagTokenGroups(tokens []*Token) ([]*Token, error) {
ret := make([]*Token, 0, len(tokens))
for i := 0; i < len(tokens); i++ {
tk := tokens[i]
switch tk.GroupType() {
case TokenGroupAnchorName:
if i+1 >= len(tokens) {
return nil, errors.ErrSyntax("undefined anchor value", tk.RawToken())
}
valueTk := tokens[i+1]
if tk.Line() == valueTk.Line() && valueTk.GroupType() == TokenGroupScalarTag {
ret = append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupAnchor,
Tokens: []*Token{tk, tokens[i+1]},
},
})
i++
} else {
ret = append(ret, tk)
}
default:
ret = append(ret, tk)
}
}
return ret, nil
}
func createMapKeyTokenGroups(tokens []*Token) ([]*Token, error) {
tks, err := createMapKeyByMappingKey(tokens)
if err != nil {
return nil, err
}
return createMapKeyByMappingValue(tks)
}
func createMapKeyByMappingKey(tokens []*Token) ([]*Token, error) {
ret := make([]*Token, 0, len(tokens))
for i := 0; i < len(tokens); i++ {
tk := tokens[i]
switch tk.Type() {
case token.MappingKeyType:
if i+1 >= len(tokens) {
return nil, errors.ErrSyntax("undefined map key", tk.RawToken())
}
ret = append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupMapKey,
Tokens: []*Token{tk, tokens[i+1]},
},
})
i++
default:
ret = append(ret, tk)
}
}
return ret, nil
}
func createMapKeyByMappingValue(tokens []*Token) ([]*Token, error) {
ret := make([]*Token, 0, len(tokens))
for i := 0; i < len(tokens); i++ {
tk := tokens[i]
switch tk.Type() {
case token.MappingValueType:
if i == 0 {
return nil, errors.ErrSyntax("unexpected key name", tk.RawToken())
}
mapKeyTk := tokens[i-1]
if isNotMapKeyType(mapKeyTk) {
return nil, errors.ErrSyntax("found an invalid key for this map", tokens[i].RawToken())
}
newTk := &Token{Token: mapKeyTk.Token, Group: mapKeyTk.Group}
mapKeyTk.Token = nil
mapKeyTk.Group = &TokenGroup{
Type: TokenGroupMapKey,
Tokens: []*Token{newTk, tk},
}
default:
ret = append(ret, tk)
}
}
return ret, nil
}
func createMapKeyValueTokenGroups(tokens []*Token) []*Token {
ret := make([]*Token, 0, len(tokens))
for i := 0; i < len(tokens); i++ {
tk := tokens[i]
switch tk.GroupType() {
case TokenGroupMapKey:
if len(tokens) <= i+1 {
ret = append(ret, tk)
continue
}
valueTk := tokens[i+1]
if tk.Line() != valueTk.Line() {
ret = append(ret, tk)
continue
}
if valueTk.GroupType() == TokenGroupAnchorName {
ret = append(ret, tk)
continue
}
if valueTk.Type() == token.TagType && valueTk.GroupType() != TokenGroupScalarTag {
ret = append(ret, tk)
continue
}
if isScalarType(valueTk) || valueTk.Type() == token.TagType {
ret = append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupMapKeyValue,
Tokens: []*Token{tk, valueTk},
},
})
i++
} else {
ret = append(ret, tk)
continue
}
default:
ret = append(ret, tk)
}
}
return ret
}
func createDirectiveTokenGroups(tokens []*Token) ([]*Token, error) {
ret := make([]*Token, 0, len(tokens))
for i := 0; i < len(tokens); i++ {
tk := tokens[i]
switch tk.Type() {
case token.DirectiveType:
if i+1 >= len(tokens) {
return nil, errors.ErrSyntax("undefined directive value", tk.RawToken())
}
directiveName := &Token{
Group: &TokenGroup{
Type: TokenGroupDirectiveName,
Tokens: []*Token{tk, tokens[i+1]},
},
}
i++
var valueTks []*Token
for j := i + 1; j < len(tokens); j++ {
if tokens[j].Line() != tk.Line() {
break
}
valueTks = append(valueTks, tokens[j])
i++
}
if i+1 >= len(tokens) || tokens[i+1].Type() != token.DocumentHeaderType {
return nil, errors.ErrSyntax("unexpected directive value. document not started", tk.RawToken())
}
if len(valueTks) != 0 {
ret = append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupDirective,
Tokens: append([]*Token{directiveName}, valueTks...),
},
})
} else {
ret = append(ret, directiveName)
}
default:
ret = append(ret, tk)
}
}
return ret, nil
}
func createDocumentTokens(tokens []*Token) ([]*Token, error) {
var ret []*Token
for i := 0; i < len(tokens); i++ {
tk := tokens[i]
switch tk.Type() {
case token.DocumentHeaderType:
if i != 0 {
ret = append(ret, &Token{
Group: &TokenGroup{Tokens: tokens[:i]},
})
}
if i+1 == len(tokens) {
// if current token is last token, add DocumentHeader only tokens to ret.
return append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupDocument,
Tokens: []*Token{tk},
},
}), nil
}
if tokens[i+1].Type() == token.DocumentHeaderType {
return append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupDocument,
Tokens: []*Token{tk},
},
}), nil
}
if tokens[i].Line() == tokens[i+1].Line() {
switch tokens[i+1].GroupType() {
case TokenGroupMapKey, TokenGroupMapKeyValue:
return nil, errors.ErrSyntax("value cannot be placed after document separator", tokens[i+1].RawToken())
}
switch tokens[i+1].Type() {
case token.SequenceEntryType:
return nil, errors.ErrSyntax("value cannot be placed after document separator", tokens[i+1].RawToken())
}
}
tks, err := createDocumentTokens(tokens[i+1:])
if err != nil {
return nil, err
}
if len(tks) != 0 {
tks[0].SetGroupType(TokenGroupDocument)
tks[0].Group.Tokens = append([]*Token{tk}, tks[0].Group.Tokens...)
return append(ret, tks...), nil
}
return append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupDocument,
Tokens: []*Token{tk},
},
}), nil
case token.DocumentEndType:
if i != 0 {
ret = append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupDocument,
Tokens: tokens[0 : i+1],
},
})
}
if i+1 == len(tokens) {
return ret, nil
}
if isScalarType(tokens[i+1]) {
return nil, errors.ErrSyntax("unexpected end content", tokens[i+1].RawToken())
}
tks, err := createDocumentTokens(tokens[i+1:])
if err != nil {
return nil, err
}
return append(ret, tks...), nil
}
}
return append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupDocument,
Tokens: tokens,
},
}), nil
}
func isScalarType(tk *Token) bool {
switch tk.GroupType() {
case TokenGroupMapKey, TokenGroupMapKeyValue:
return false
}
typ := tk.Type()
return typ == token.AnchorType ||
typ == token.AliasType ||
typ == token.LiteralType ||
typ == token.FoldedType ||
typ == token.NullType ||
typ == token.ImplicitNullType ||
typ == token.BoolType ||
typ == token.IntegerType ||
typ == token.BinaryIntegerType ||
typ == token.OctetIntegerType ||
typ == token.HexIntegerType ||
typ == token.FloatType ||
typ == token.InfinityType ||
typ == token.NanType ||
typ == token.StringType ||
typ == token.SingleQuoteType ||
typ == token.DoubleQuoteType
}
func isNotMapKeyType(tk *Token) bool {
typ := tk.Type()
return typ == token.DirectiveType ||
typ == token.DocumentHeaderType ||
typ == token.DocumentEndType ||
typ == token.CollectEntryType ||
typ == token.MappingStartType ||
typ == token.MappingValueType ||
typ == token.MappingEndType ||
typ == token.SequenceStartType ||
typ == token.SequenceEntryType ||
typ == token.SequenceEndType
}
func isFlowType(tk *Token) bool {
typ := tk.Type()
return typ == token.MappingStartType ||
typ == token.MappingEndType ||
typ == token.SequenceStartType ||
typ == token.SequenceEntryType
}
================================================
FILE: vendor/github.com/goccy/go-yaml/path.go
================================================
package yaml
import (
"bytes"
"fmt"
"io"
"strconv"
"strings"
"github.com/goccy/go-yaml/ast"
"github.com/goccy/go-yaml/parser"
"github.com/goccy/go-yaml/printer"
)
// PathString create Path from string
//
// YAMLPath rule
// $ : the root object/element
// . : child operator
// .. : recursive descent
// [num] : object/element of array by number
// [*] : all objects/elements for array.
//
// If you want to use reserved characters such as `.` and `*` as a key name,
// enclose them in single quotation as follows ( $.foo.'bar.baz-*'.hoge ).
// If you want to use a single quote with reserved characters, escape it with `\` ( $.foo.'bar.baz\'s value'.hoge ).
func PathString(s string) (*Path, error) {
buf := []rune(s)
length := len(buf)
cursor := 0
builder := &PathBuilder{}
for cursor < length {
c := buf[cursor]
switch c {
case '$':
builder = builder.Root()
cursor++
case '.':
b, buf, c, err := parsePathDot(builder, buf, cursor)
if err != nil {
return nil, err
}
length = len(buf)
builder = b
cursor = c
case '[':
b, buf, c, err := parsePathIndex(builder, buf, cursor)
if err != nil {
return nil, err
}
length = len(buf)
builder = b
cursor = c
default:
return nil, fmt.Errorf("invalid path at %d: %w", cursor, ErrInvalidPathString)
}
}
return builder.Build(), nil
}
func parsePathRecursive(b *PathBuilder, buf []rune, cursor int) (*PathBuilder, []rune, int, error) {
length := len(buf)
cursor += 2 // skip .. characters
start := cursor
for ; cursor < length; cursor++ {
c := buf[cursor]
switch c {
case '$':
return nil, nil, 0, fmt.Errorf("specified '$' after '..' character: %w", ErrInvalidPathString)
case '*':
return nil, nil, 0, fmt.Errorf("specified '*' after '..' character: %w", ErrInvalidPathString)
case '.', '[':
goto end
case ']':
return nil, nil, 0, fmt.Errorf("specified ']' after '..' character: %w", ErrInvalidPathString)
}
}
end:
if start == cursor {
return nil, nil, 0, fmt.Errorf("not found recursive selector: %w", ErrInvalidPathString)
}
return b.Recursive(string(buf[start:cursor])), buf, cursor, nil
}
func parsePathDot(b *PathBuilder, buf []rune, cursor int) (*PathBuilder, []rune, int, error) {
if b.root == nil || b.node == nil {
return nil, nil, 0, fmt.Errorf("required '$' character at first: %w", ErrInvalidPathString)
}
length := len(buf)
if cursor+1 < length && buf[cursor+1] == '.' {
b, buf, c, err := parsePathRecursive(b, buf, cursor)
if err != nil {
return nil, nil, 0, err
}
return b, buf, c, nil
}
cursor++ // skip . character
start := cursor
// if started single quote, looking for end single quote char
if cursor < length && buf[cursor] == '\'' {
return parseQuotedKey(b, buf, cursor)
}
for ; cursor < length; cursor++ {
c := buf[cursor]
switch c {
case '$':
return nil, nil, 0, fmt.Errorf("specified '$' after '.' character: %w", ErrInvalidPathString)
case '*':
return nil, nil, 0, fmt.Errorf("specified '*' after '.' character: %w", ErrInvalidPathString)
case '.', '[':
goto end
case ']':
return nil, nil, 0, fmt.Errorf("specified ']' after '.' character: %w", ErrInvalidPathString)
}
}
end:
if start == cursor {
return nil, nil, 0, fmt.Errorf("could not find by empty key: %w", ErrInvalidPathString)
}
return b.child(string(buf[start:cursor])), buf, cursor, nil
}
func parseQuotedKey(b *PathBuilder, buf []rune, cursor int) (*PathBuilder, []rune, int, error) {
if b.root == nil || b.node == nil {
return nil, nil, 0, fmt.Errorf("required '$' character at first: %w", ErrInvalidPathString)
}
cursor++ // skip single quote
start := cursor
length := len(buf)
var foundEndDelim bool
for ; cursor < length; cursor++ {
switch buf[cursor] {
case '\\':
buf = append(append([]rune{}, buf[:cursor]...), buf[cursor+1:]...)
length = len(buf)
case '\'':
foundEndDelim = true
goto end
}
}
end:
if !foundEndDelim {
return nil, nil, 0, fmt.Errorf("could not find end delimiter for key: %w", ErrInvalidPathString)
}
if start == cursor {
return nil, nil, 0, fmt.Errorf("could not find by empty key: %w", ErrInvalidPathString)
}
selector := buf[start:cursor]
cursor++
if cursor < length {
switch buf[cursor] {
case '$':
return nil, nil, 0, fmt.Errorf("specified '$' after '.' character: %w", ErrInvalidPathString)
case '*':
return nil, nil, 0, fmt.Errorf("specified '*' after '.' character: %w", ErrInvalidPathString)
case ']':
return nil, nil, 0, fmt.Errorf("specified ']' after '.' character: %w", ErrInvalidPathString)
}
}
return b.child(string(selector)), buf, cursor, nil
}
func parsePathIndex(b *PathBuilder, buf []rune, cursor int) (*PathBuilder, []rune, int, error) {
if b.root == nil || b.node == nil {
return nil, nil, 0, fmt.Errorf("required '$' character at first: %w", ErrInvalidPathString)
}
length := len(buf)
cursor++ // skip '[' character
if length <= cursor {
return nil, nil, 0, fmt.Errorf("unexpected end of YAML Path: %w", ErrInvalidPathString)
}
c := buf[cursor]
switch c {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*':
start := cursor
cursor++
for ; cursor < length; cursor++ {
c := buf[cursor]
switch c {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
continue
}
break
}
if buf[cursor] != ']' {
return nil, nil, 0, fmt.Errorf("invalid character %s at %d: %w", string(buf[cursor]), cursor, ErrInvalidPathString)
}
numOrAll := string(buf[start:cursor])
if numOrAll == "*" {
return b.IndexAll(), buf, cursor + 1, nil
}
num, err := strconv.ParseInt(numOrAll, 10, 64)
if err != nil {
return nil, nil, 0, err
}
return b.Index(uint(num)), buf, cursor + 1, nil
}
return nil, nil, 0, fmt.Errorf("invalid character %q at %d: %w", c, cursor, ErrInvalidPathString)
}
// Path represent YAMLPath ( like a JSONPath ).
type Path struct {
node pathNode
}
// String path to text.
func (p *Path) String() string {
return p.node.String()
}
// Read decode from r and set extracted value by YAMLPath to v.
func (p *Path) Read(r io.Reader, v interface{}) error {
node, err := p.ReadNode(r)
if err != nil {
return err
}
if err := Unmarshal([]byte(node.String()), v); err != nil {
return err
}
return nil
}
// ReadNode create AST from r and extract node by YAMLPath.
func (p *Path) ReadNode(r io.Reader) (ast.Node, error) {
if p.node == nil {
return nil, ErrInvalidPath
}
var buf bytes.Buffer
if _, err := io.Copy(&buf, r); err != nil {
return nil, err
}
f, err := parser.ParseBytes(buf.Bytes(), 0)
if err != nil {
return nil, err
}
node, err := p.FilterFile(f)
if err != nil {
return nil, err
}
return node, nil
}
// Filter filter from target by YAMLPath and set it to v.
func (p *Path) Filter(target, v interface{}) error {
b, err := Marshal(target)
if err != nil {
return err
}
if err := p.Read(bytes.NewBuffer(b), v); err != nil {
return err
}
return nil
}
// FilterFile filter from ast.File by YAMLPath.
func (p *Path) FilterFile(f *ast.File) (ast.Node, error) {
for _, doc := range f.Docs {
// For simplicity, directives cannot be the target of operations
if doc.Body != nil && doc.Body.Type() == ast.DirectiveType {
continue
}
node, err := p.FilterNode(doc.Body)
if err != nil {
return nil, err
}
if node != nil {
return node, nil
}
}
return nil, fmt.Errorf("failed to find path ( %s ): %w", p.node, ErrNotFoundNode)
}
// FilterNode filter from node by YAMLPath.
func (p *Path) FilterNode(node ast.Node) (ast.Node, error) {
if node == nil {
return nil, nil
}
n, err := p.node.filter(node)
if err != nil {
return nil, err
}
return n, nil
}
// MergeFromReader merge YAML text into ast.File.
func (p *Path) MergeFromReader(dst *ast.File, src io.Reader) error {
var buf bytes.Buffer
if _, err := io.Copy(&buf, src); err != nil {
return err
}
file, err := parser.ParseBytes(buf.Bytes(), 0)
if err != nil {
return err
}
if err := p.MergeFromFile(dst, file); err != nil {
return err
}
return nil
}
// MergeFromFile merge ast.File into ast.File.
func (p *Path) MergeFromFile(dst *ast.File, src *ast.File) error {
base, err := p.FilterFile(dst)
if err != nil {
return err
}
for _, doc := range src.Docs {
if err := ast.Merge(base, doc); err != nil {
return err
}
}
return nil
}
// MergeFromNode merge ast.Node into ast.File.
func (p *Path) MergeFromNode(dst *ast.File, src ast.Node) error {
base, err := p.FilterFile(dst)
if err != nil {
return err
}
if err := ast.Merge(base, src); err != nil {
return err
}
return nil
}
// ReplaceWithReader replace ast.File with io.Reader.
func (p *Path) ReplaceWithReader(dst *ast.File, src io.Reader) error {
var buf bytes.Buffer
if _, err := io.Copy(&buf, src); err != nil {
return err
}
file, err := parser.ParseBytes(buf.Bytes(), 0)
if err != nil {
return err
}
if err := p.ReplaceWithFile(dst, file); err != nil {
return err
}
return nil
}
// ReplaceWithFile replace ast.File with ast.File.
func (p *Path) ReplaceWithFile(dst *ast.File, src *ast.File) error {
for _, doc := range src.Docs {
if err := p.ReplaceWithNode(dst, doc); err != nil {
return err
}
}
return nil
}
// ReplaceNode replace ast.File with ast.Node.
func (p *Path) ReplaceWithNode(dst *ast.File, node ast.Node) error {
for _, doc := range dst.Docs {
// For simplicity, directives cannot be the target of operations
if doc.Body != nil && doc.Body.Type() == ast.DirectiveType {
continue
}
if node.Type() == ast.DocumentType {
node = node.(*ast.DocumentNode).Body
}
if err := p.node.replace(doc.Body, node); err != nil {
return err
}
}
return nil
}
// AnnotateSource add annotation to passed source ( see section 5.1 in README.md ).
func (p *Path) AnnotateSource(source []byte, colored bool) ([]byte, error) {
file, err := parser.ParseBytes(source, 0)
if err != nil {
return nil, err
}
node, err := p.FilterFile(file)
if err != nil {
return nil, err
}
var pp printer.Printer
return []byte(pp.PrintErrorToken(node.GetToken(), colored)), nil
}
// PathBuilder represent builder for YAMLPath.
type PathBuilder struct {
root *rootNode
node pathNode
}
// Root add '$' to current path.
func (b *PathBuilder) Root() *PathBuilder {
root := newRootNode()
return &PathBuilder{root: root, node: root}
}
// IndexAll add '[*]' to current path.
func (b *PathBuilder) IndexAll() *PathBuilder {
b.node = b.node.chain(newIndexAllNode())
return b
}
// Recursive add '..selector' to current path.
func (b *PathBuilder) Recursive(selector string) *PathBuilder {
b.node = b.node.chain(newRecursiveNode(selector))
return b
}
func (b *PathBuilder) containsReservedPathCharacters(path string) bool {
if strings.Contains(path, ".") {
return true
}
if strings.Contains(path, "*") {
return true
}
return false
}
func (b *PathBuilder) enclosedSingleQuote(name string) bool {
return strings.HasPrefix(name, "'") && strings.HasSuffix(name, "'")
}
func (b *PathBuilder) normalizeSelectorName(name string) string {
if b.enclosedSingleQuote(name) {
// already escaped name
return name
}
if b.containsReservedPathCharacters(name) {
escapedName := strings.ReplaceAll(name, `'`, `\'`)
return "'" + escapedName + "'"
}
return name
}
func (b *PathBuilder) child(name string) *PathBuilder {
b.node = b.node.chain(newSelectorNode(name))
return b
}
// Child add '.name' to current path.
func (b *PathBuilder) Child(name string) *PathBuilder {
return b.child(b.normalizeSelectorName(name))
}
// Index add '[idx]' to current path.
func (b *PathBuilder) Index(idx uint) *PathBuilder {
b.node = b.node.chain(newIndexNode(idx))
return b
}
// Build build YAMLPath.
func (b *PathBuilder) Build() *Path {
return &Path{node: b.root}
}
type pathNode interface {
fmt.Stringer
chain(pathNode) pathNode
filter(ast.Node) (ast.Node, error)
replace(ast.Node, ast.Node) error
}
type basePathNode struct {
child pathNode
}
func (n *basePathNode) chain(node pathNode) pathNode {
n.child = node
return node
}
type rootNode struct {
*basePathNode
}
func newRootNode() *rootNode {
return &rootNode{basePathNode: &basePathNode{}}
}
func (n *rootNode) String() string {
s := "$"
if n.child != nil {
s += n.child.String()
}
return s
}
func (n *rootNode) filter(node ast.Node) (ast.Node, error) {
if n.child == nil {
return node, nil
}
filtered, err := n.child.filter(node)
if err != nil {
return nil, err
}
return filtered, nil
}
func (n *rootNode) replace(node ast.Node, target ast.Node) error {
if n.child == nil {
return nil
}
if err := n.child.replace(node, target); err != nil {
return err
}
return nil
}
type selectorNode struct {
*basePathNode
selector string
}
func newSelectorNode(selector string) *selectorNode {
return &selectorNode{
basePathNode: &basePathNode{},
selector: selector,
}
}
func (n *selectorNode) filter(node ast.Node) (ast.Node, error) {
selector := n.selector
if len(selector) > 1 && selector[0] == '\'' && selector[len(selector)-1] == '\'' {
selector = selector[1 : len(selector)-1]
}
switch node.Type() {
case ast.MappingType:
for _, value := range node.(*ast.MappingNode).Values {
key := value.Key.GetToken().Value
if len(key) > 0 {
switch key[0] {
case '"':
var err error
key, err = strconv.Unquote(key)
if err != nil {
return nil, err
}
case '\'':
if len(key) > 1 && key[len(key)-1] == '\'' {
key = key[1 : len(key)-1]
}
}
}
if key == selector {
if n.child == nil {
return value.Value, nil
}
filtered, err := n.child.filter(value.Value)
if err != nil {
return nil, err
}
return filtered, nil
}
}
case ast.MappingValueType:
value, _ := node.(*ast.MappingValueNode)
key := value.Key.GetToken().Value
if key == selector {
if n.child == nil {
return value.Value, nil
}
filtered, err := n.child.filter(value.Value)
if err != nil {
return nil, err
}
return filtered, nil
}
default:
return nil, fmt.Errorf("expected node type is map or map value. but got %s: %w", node.Type(), ErrInvalidQuery)
}
return nil, nil
}
func (n *selectorNode) replaceMapValue(value *ast.MappingValueNode, target ast.Node) error {
key := value.Key.GetToken().Value
if key != n.selector {
return nil
}
if n.child == nil {
if err := value.Replace(target); err != nil {
return err
}
} else {
if err := n.child.replace(value.Value, target); err != nil {
return err
}
}
return nil
}
func (n *selectorNode) replace(node ast.Node, target ast.Node) error {
switch node.Type() {
case ast.MappingType:
for _, value := range node.(*ast.MappingNode).Values {
if err := n.replaceMapValue(value, target); err != nil {
return err
}
}
case ast.MappingValueType:
value, _ := node.(*ast.MappingValueNode)
if err := n.replaceMapValue(value, target); err != nil {
return err
}
default:
return fmt.Errorf("expected node type is map or map value. but got %s: %w", node.Type(), ErrInvalidQuery)
}
return nil
}
func (n *selectorNode) String() string {
var builder PathBuilder
selector := builder.normalizeSelectorName(n.selector)
s := fmt.Sprintf(".%s", selector)
if n.child != nil {
s += n.child.String()
}
return s
}
type indexNode struct {
*basePathNode
selector uint
}
func newIndexNode(selector uint) *indexNode {
return &indexNode{
basePathNode: &basePathNode{},
selector: selector,
}
}
func (n *indexNode) filter(node ast.Node) (ast.Node, error) {
if node.Type() != ast.SequenceType {
return nil, fmt.Errorf("expected sequence type node. but got %s: %w", node.Type(), ErrInvalidQuery)
}
sequence, _ := node.(*ast.SequenceNode)
if n.selector >= uint(len(sequence.Values)) {
return nil, fmt.Errorf("expected index is %d. but got sequences has %d items: %w", n.selector, len(sequence.Values), ErrInvalidQuery)
}
value := sequence.Values[n.selector]
if n.child == nil {
return value, nil
}
filtered, err := n.child.filter(value)
if err != nil {
return nil, err
}
return filtered, nil
}
func (n *indexNode) replace(node ast.Node, target ast.Node) error {
if node.Type() != ast.SequenceType {
return fmt.Errorf("expected sequence type node. but got %s: %w", node.Type(), ErrInvalidQuery)
}
sequence, _ := node.(*ast.SequenceNode)
if n.selector >= uint(len(sequence.Values)) {
return fmt.Errorf("expected index is %d. but got sequences has %d items: %w", n.selector, len(sequence.Values), ErrInvalidQuery)
}
if n.child == nil {
if err := sequence.Replace(int(n.selector), target); err != nil {
return err
}
return nil
}
if err := n.child.replace(sequence.Values[n.selector], target); err != nil {
return err
}
return nil
}
func (n *indexNode) String() string {
s := fmt.Sprintf("[%d]", n.selector)
if n.child != nil {
s += n.child.String()
}
return s
}
type indexAllNode struct {
*basePathNode
}
func newIndexAllNode() *indexAllNode {
return &indexAllNode{
basePathNode: &basePathNode{},
}
}
func (n *indexAllNode) String() string {
s := "[*]"
if n.child != nil {
s += n.child.String()
}
return s
}
func (n *indexAllNode) filter(node ast.Node) (ast.Node, error) {
if node.Type() != ast.SequenceType {
return nil, fmt.Errorf("expected sequence type node. but got %s: %w", node.Type(), ErrInvalidQuery)
}
sequence, _ := node.(*ast.SequenceNode)
if n.child == nil {
return sequence, nil
}
out := *sequence
out.Values = []ast.Node{}
for _, value := range sequence.Values {
filtered, err := n.child.filter(value)
if err != nil {
return nil, err
}
out.Values = append(out.Values, filtered)
}
return &out, nil
}
func (n *indexAllNode) replace(node ast.Node, target ast.Node) error {
if node.Type() != ast.SequenceType {
return fmt.Errorf("expected sequence type node. but got %s: %w", node.Type(), ErrInvalidQuery)
}
sequence, _ := node.(*ast.SequenceNode)
if n.child == nil {
for idx := range sequence.Values {
if err := sequence.Replace(idx, target); err != nil {
return err
}
}
return nil
}
for _, value := range sequence.Values {
if err := n.child.replace(value, target); err != nil {
return err
}
}
return nil
}
type recursiveNode struct {
*basePathNode
selector string
}
func newRecursiveNode(selector string) *recursiveNode {
return &recursiveNode{
basePathNode: &basePathNode{},
selector: selector,
}
}
func (n *recursiveNode) String() string {
s := fmt.Sprintf("..%s", n.selector)
if n.child != nil {
s += n.child.String()
}
return s
}
func (n *recursiveNode) filterNode(node ast.Node) (*ast.SequenceNode, error) {
sequence := &ast.SequenceNode{BaseNode: &ast.BaseNode{}}
switch typedNode := node.(type) {
case *ast.MappingNode:
for _, value := range typedNode.Values {
seq, err := n.filterNode(value)
if err != nil {
return nil, err
}
sequence.Values = append(sequence.Values, seq.Values...)
}
case *ast.MappingValueNode:
key := typedNode.Key.GetToken().Value
if n.selector == key {
sequence.Values = append(sequence.Values, typedNode.Value)
}
seq, err := n.filterNode(typedNode.Value)
if err != nil {
return nil, err
}
sequence.Values = append(sequence.Values, seq.Values...)
case *ast.SequenceNode:
for _, value := range typedNode.Values {
seq, err := n.filterNode(value)
if err != nil {
return nil, err
}
sequence.Values = append(sequence.Values, seq.Values...)
}
}
return sequence, nil
}
func (n *recursiveNode) filter(node ast.Node) (ast.Node, error) {
sequence, err := n.filterNode(node)
if err != nil {
return nil, err
}
sequence.Start = node.GetToken()
return sequence, nil
}
func (n *recursiveNode) replaceNode(node ast.Node, target ast.Node) error {
switch typedNode := node.(type) {
case *ast.MappingNode:
for _, value := range typedNode.Values {
if err := n.replaceNode(value, target); err != nil {
return err
}
}
case *ast.MappingValueNode:
key := typedNode.Key.GetToken().Value
if n.selector == key {
if err := typedNode.Replace(target); err != nil {
return err
}
}
if err := n.replaceNode(typedNode.Value, target); err != nil {
return err
}
case *ast.SequenceNode:
for _, value := range typedNode.Values {
if err := n.replaceNode(value, target); err != nil {
return err
}
}
}
return nil
}
func (n *recursiveNode) replace(node ast.Node, target ast.Node) error {
if err := n.replaceNode(node, target); err != nil {
return err
}
return nil
}
================================================
FILE: vendor/github.com/goccy/go-yaml/printer/color.go
================================================
// This source inspired by https://github.com/fatih/color.
package printer
import (
"fmt"
"strings"
)
type ColorAttribute int
const (
ColorReset ColorAttribute = iota
ColorBold
ColorFaint
ColorItalic
ColorUnderline
ColorBlinkSlow
ColorBlinkRapid
ColorReverseVideo
ColorConcealed
ColorCrossedOut
)
const (
ColorFgHiBlack ColorAttribute = iota + 90
ColorFgHiRed
ColorFgHiGreen
ColorFgHiYellow
ColorFgHiBlue
ColorFgHiMagenta
ColorFgHiCyan
ColorFgHiWhite
)
const (
ColorResetBold ColorAttribute = iota + 22
ColorResetItalic
ColorResetUnderline
ColorResetBlinking
ColorResetReversed
ColorResetConcealed
ColorResetCrossedOut
)
const escape = "\x1b"
var colorResetMap = map[ColorAttribute]ColorAttribute{
ColorBold: ColorResetBold,
ColorFaint: ColorResetBold,
ColorItalic: ColorResetItalic,
ColorUnderline: ColorResetUnderline,
ColorBlinkSlow: ColorResetBlinking,
ColorBlinkRapid: ColorResetBlinking,
ColorReverseVideo: ColorResetReversed,
ColorConcealed: ColorResetConcealed,
ColorCrossedOut: ColorResetCrossedOut,
}
func format(attrs ...ColorAttribute) string {
format := make([]string, 0, len(attrs))
for _, attr := range attrs {
format = append(format, fmt.Sprint(attr))
}
return fmt.Sprintf("%s[%sm", escape, strings.Join(format, ";"))
}
func unformat(attrs ...ColorAttribute) string {
format := make([]string, len(attrs))
for _, attr := range attrs {
v := fmt.Sprint(ColorReset)
reset, exists := colorResetMap[attr]
if exists {
v = fmt.Sprint(reset)
}
format = append(format, v)
}
return fmt.Sprintf("%s[%sm", escape, strings.Join(format, ";"))
}
func colorize(msg string, attrs ...ColorAttribute) string {
return format(attrs...) + msg + unformat(attrs...)
}
================================================
FILE: vendor/github.com/goccy/go-yaml/printer/printer.go
================================================
package printer
import (
"fmt"
"math"
"strings"
"github.com/goccy/go-yaml/ast"
"github.com/goccy/go-yaml/token"
)
// Property additional property set for each the token
type Property struct {
Prefix string
Suffix string
}
// PrintFunc returns property instance
type PrintFunc func() *Property
// Printer create text from token collection or ast
type Printer struct {
LineNumber bool
LineNumberFormat func(num int) string
MapKey PrintFunc
Anchor PrintFunc
Alias PrintFunc
Bool PrintFunc
String PrintFunc
Number PrintFunc
Comment PrintFunc
}
func defaultLineNumberFormat(num int) string {
return fmt.Sprintf("%2d | ", num)
}
func (p *Printer) property(tk *token.Token) *Property {
prop := &Property{}
switch tk.PreviousType() {
case token.AnchorType:
if p.Anchor != nil {
return p.Anchor()
}
return prop
case token.AliasType:
if p.Alias != nil {
return p.Alias()
}
return prop
}
switch tk.NextType() {
case token.MappingValueType:
if p.MapKey != nil {
return p.MapKey()
}
return prop
}
switch tk.Type {
case token.BoolType:
if p.Bool != nil {
return p.Bool()
}
return prop
case token.AnchorType:
if p.Anchor != nil {
return p.Anchor()
}
return prop
case token.AliasType:
if p.Anchor != nil {
return p.Alias()
}
return prop
case token.StringType, token.SingleQuoteType, token.DoubleQuoteType:
if p.String != nil {
return p.String()
}
return prop
case token.IntegerType, token.FloatType:
if p.Number != nil {
return p.Number()
}
return prop
case token.CommentType:
if p.Comment != nil {
return p.Comment()
}
return prop
default:
}
return prop
}
// PrintTokens create text from token collection
func (p *Printer) PrintTokens(tokens token.Tokens) string {
if len(tokens) == 0 {
return ""
}
if p.LineNumber {
if p.LineNumberFormat == nil {
p.LineNumberFormat = defaultLineNumberFormat
}
}
texts := []string{}
lineNumber := tokens[0].Position.Line
for _, tk := range tokens {
lines := strings.Split(tk.Origin, "\n")
prop := p.property(tk)
header := ""
if p.LineNumber {
header = p.LineNumberFormat(lineNumber)
}
if len(lines) == 1 {
line := prop.Prefix + lines[0] + prop.Suffix
if len(texts) == 0 {
texts = append(texts, header+line)
lineNumber++
} else {
text := texts[len(texts)-1]
texts[len(texts)-1] = text + line
}
} else {
for idx, src := range lines {
if p.LineNumber {
header = p.LineNumberFormat(lineNumber)
}
line := prop.Prefix + src + prop.Suffix
if idx == 0 {
if len(texts) == 0 {
texts = append(texts, header+line)
lineNumber++
} else {
text := texts[len(texts)-1]
texts[len(texts)-1] = text + line
}
} else {
texts = append(texts, fmt.Sprintf("%s%s", header, line))
lineNumber++
}
}
}
}
return strings.Join(texts, "\n")
}
// PrintNode create text from ast.Node
func (p *Printer) PrintNode(node ast.Node) []byte {
return []byte(fmt.Sprintf("%+v\n", node))
}
func (p *Printer) setDefaultColorSet() {
p.Bool = func() *Property {
return &Property{
Prefix: format(ColorFgHiMagenta),
Suffix: format(ColorReset),
}
}
p.Number = func() *Property {
return &Property{
Prefix: format(ColorFgHiMagenta),
Suffix: format(ColorReset),
}
}
p.MapKey = func() *Property {
return &Property{
Prefix: format(ColorFgHiCyan),
Suffix: format(ColorReset),
}
}
p.Anchor = func() *Property {
return &Property{
Prefix: format(ColorFgHiYellow),
Suffix: format(ColorReset),
}
}
p.Alias = func() *Property {
return &Property{
Prefix: format(ColorFgHiYellow),
Suffix: format(ColorReset),
}
}
p.String = func() *Property {
return &Property{
Prefix: format(ColorFgHiGreen),
Suffix: format(ColorReset),
}
}
p.Comment = func() *Property {
return &Property{
Prefix: format(ColorFgHiBlack),
Suffix: format(ColorReset),
}
}
}
func (p *Printer) PrintErrorMessage(msg string, isColored bool) string {
if isColored {
return fmt.Sprintf("%s%s%s",
format(ColorFgHiRed),
msg,
format(ColorReset),
)
}
return msg
}
func (p *Printer) removeLeftSideNewLineChar(src string) string {
return strings.TrimLeft(strings.TrimLeft(strings.TrimLeft(src, "\r"), "\n"), "\r\n")
}
func (p *Printer) removeRightSideNewLineChar(src string) string {
return strings.TrimRight(strings.TrimRight(strings.TrimRight(src, "\r"), "\n"), "\r\n")
}
func (p *Printer) removeRightSideWhiteSpaceChar(src string) string {
return p.removeRightSideNewLineChar(strings.TrimRight(src, " "))
}
func (p *Printer) newLineCount(s string) int {
src := []rune(s)
size := len(src)
cnt := 0
for i := 0; i < size; i++ {
c := src[i]
switch c {
case '\r':
if i+1 < size && src[i+1] == '\n' {
i++
}
cnt++
case '\n':
cnt++
}
}
return cnt
}
func (p *Printer) isNewLineLastChar(s string) bool {
for i := len(s) - 1; i > 0; i-- {
c := s[i]
switch c {
case ' ':
continue
case '\n', '\r':
return true
}
break
}
return false
}
func (p *Printer) printBeforeTokens(tk *token.Token, minLine, extLine int) token.Tokens {
for tk.Prev != nil {
if tk.Prev.Position.Line < minLine {
break
}
tk = tk.Prev
}
minTk := tk.Clone()
if minTk.Prev != nil {
// add white spaces to minTk by prev token
prev := minTk.Prev
whiteSpaceLen := len(prev.Origin) - len(strings.TrimRight(prev.Origin, " "))
minTk.Origin = strings.Repeat(" ", whiteSpaceLen) + minTk.Origin
}
minTk.Origin = p.removeLeftSideNewLineChar(minTk.Origin)
tokens := token.Tokens{minTk}
tk = minTk.Next
for tk != nil && tk.Position.Line <= extLine {
clonedTk := tk.Clone()
tokens.Add(clonedTk)
tk = clonedTk.Next
}
lastTk := tokens[len(tokens)-1]
trimmedOrigin := p.removeRightSideWhiteSpaceChar(lastTk.Origin)
suffix := lastTk.Origin[len(trimmedOrigin):]
lastTk.Origin = trimmedOrigin
if lastTk.Next != nil && len(suffix) > 1 {
next := lastTk.Next.Clone()
// add suffix to header of next token
if suffix[0] == '\n' || suffix[0] == '\r' {
suffix = suffix[1:]
}
next.Origin = suffix + next.Origin
lastTk.Next = next
}
return tokens
}
func (p *Printer) printAfterTokens(tk *token.Token, maxLine int) token.Tokens {
tokens := token.Tokens{}
if tk == nil {
return tokens
}
if tk.Position.Line > maxLine {
return tokens
}
minTk := tk.Clone()
minTk.Origin = p.removeLeftSideNewLineChar(minTk.Origin)
tokens.Add(minTk)
tk = minTk.Next
for tk != nil && tk.Position.Line <= maxLine {
clonedTk := tk.Clone()
tokens.Add(clonedTk)
tk = clonedTk.Next
}
return tokens
}
func (p *Printer) setupErrorTokenFormat(annotateLine int, isColored bool) {
prefix := func(annotateLine, num int) string {
if annotateLine == num {
return fmt.Sprintf("> %2d | ", num)
}
return fmt.Sprintf(" %2d | ", num)
}
p.LineNumber = true
p.LineNumberFormat = func(num int) string {
if isColored {
return colorize(prefix(annotateLine, num), ColorBold, ColorFgHiWhite)
}
return prefix(annotateLine, num)
}
if isColored {
p.setDefaultColorSet()
}
}
func (p *Printer) PrintErrorToken(tk *token.Token, isColored bool) string {
errToken := tk
curLine := tk.Position.Line
curExtLine := curLine + p.newLineCount(p.removeLeftSideNewLineChar(tk.Origin))
if p.isNewLineLastChar(tk.Origin) {
// if last character ( exclude white space ) is new line character, ignore it.
curExtLine--
}
minLine := int(math.Max(float64(curLine-3), 1))
maxLine := curExtLine + 3
p.setupErrorTokenFormat(curLine, isColored)
beforeTokens := p.printBeforeTokens(tk, minLine, curExtLine)
lastTk := beforeTokens[len(beforeTokens)-1]
afterTokens := p.printAfterTokens(lastTk.Next, maxLine)
beforeSource := p.PrintTokens(beforeTokens)
prefixSpaceNum := len(fmt.Sprintf(" %2d | ", curLine))
annotateLine := strings.Repeat(" ", prefixSpaceNum+errToken.Position.Column-1) + "^"
afterSource := p.PrintTokens(afterTokens)
return fmt.Sprintf("%s\n%s\n%s", beforeSource, annotateLine, afterSource)
}
================================================
FILE: vendor/github.com/goccy/go-yaml/scanner/context.go
================================================
package scanner
import (
"errors"
"strconv"
"strings"
"sync"
"github.com/goccy/go-yaml/token"
)
// Context context at scanning
type Context struct {
idx int
size int
notSpaceCharPos int
notSpaceOrgCharPos int
src []rune
buf []rune
obuf []rune
tokens token.Tokens
mstate *MultiLineState
}
type MultiLineState struct {
opt string
firstLineIndentColumn int
prevLineIndentColumn int
lineIndentColumn int
lastNotSpaceOnlyLineIndentColumn int
spaceOnlyIndentColumn int
foldedNewLine bool
isRawFolded bool
isLiteral bool
isFolded bool
}
var (
ctxPool = sync.Pool{
New: func() interface{} {
return createContext()
},
}
)
func createContext() *Context {
return &Context{
idx: 0,
tokens: token.Tokens{},
}
}
func newContext(src []rune) *Context {
ctx, _ := ctxPool.Get().(*Context)
ctx.reset(src)
return ctx
}
func (c *Context) release() {
ctxPool.Put(c)
}
func (c *Context) clear() {
c.resetBuffer()
c.mstate = nil
}
func (c *Context) reset(src []rune) {
c.idx = 0
c.size = len(src)
c.src = src
c.tokens = c.tokens[:0]
c.resetBuffer()
c.mstate = nil
}
func (c *Context) resetBuffer() {
c.buf = c.buf[:0]
c.obuf = c.obuf[:0]
c.notSpaceCharPos = 0
c.notSpaceOrgCharPos = 0
}
func (c *Context) breakMultiLine() {
c.mstate = nil
}
func (c *Context) getMultiLineState() *MultiLineState {
return c.mstate
}
func (c *Context) setLiteral(lastDelimColumn int, opt string) {
mstate := &MultiLineState{
isLiteral: true,
opt: opt,
}
indent := firstLineIndentColumnByOpt(opt)
if indent > 0 {
mstate.firstLineIndentColumn = lastDelimColumn + indent
}
c.mstate = mstate
}
func (c *Context) setFolded(lastDelimColumn int, opt string) {
mstate := &MultiLineState{
isFolded: true,
opt: opt,
}
indent := firstLineIndentColumnByOpt(opt)
if indent > 0 {
mstate.firstLineIndentColumn = lastDelimColumn + indent
}
c.mstate = mstate
}
func (c *Context) setRawFolded(column int) {
mstate := &MultiLineState{
isRawFolded: true,
}
mstate.updateIndentColumn(column)
c.mstate = mstate
}
func firstLineIndentColumnByOpt(opt string) int {
opt = strings.TrimPrefix(opt, "-")
opt = strings.TrimPrefix(opt, "+")
opt = strings.TrimSuffix(opt, "-")
opt = strings.TrimSuffix(opt, "+")
i, _ := strconv.ParseInt(opt, 10, 64)
return int(i)
}
func (s *MultiLineState) lastDelimColumn() int {
if s.firstLineIndentColumn == 0 {
return 0
}
return s.firstLineIndentColumn - 1
}
func (s *MultiLineState) updateIndentColumn(column int) {
if s.firstLineIndentColumn == 0 {
s.firstLineIndentColumn = column
}
if s.lineIndentColumn == 0 {
s.lineIndentColumn = column
}
}
func (s *MultiLineState) updateSpaceOnlyIndentColumn(column int) {
if s.firstLineIndentColumn != 0 {
return
}
s.spaceOnlyIndentColumn = column
}
func (s *MultiLineState) validateIndentAfterSpaceOnly(column int) error {
if s.firstLineIndentColumn != 0 {
return nil
}
if s.spaceOnlyIndentColumn > column {
return errors.New("invalid number of indent is specified after space only")
}
return nil
}
func (s *MultiLineState) validateIndentColumn() error {
if firstLineIndentColumnByOpt(s.opt) == 0 {
return nil
}
if s.firstLineIndentColumn > s.lineIndentColumn {
return errors.New("invalid number of indent is specified in the multi-line header")
}
return nil
}
func (s *MultiLineState) updateNewLineState() {
s.prevLineIndentColumn = s.lineIndentColumn
if s.lineIndentColumn != 0 {
s.lastNotSpaceOnlyLineIndentColumn = s.lineIndentColumn
}
s.foldedNewLine = true
s.lineIndentColumn = 0
}
func (s *MultiLineState) isIndentColumn(column int) bool {
if s.firstLineIndentColumn == 0 {
return column == 1
}
return s.firstLineIndentColumn > column
}
func (s *MultiLineState) addIndent(ctx *Context, column int) {
if s.firstLineIndentColumn == 0 {
return
}
// If the first line of the document has already been evaluated, the number is treated as the threshold, since the `firstLineIndentColumn` is a positive number.
if column < s.firstLineIndentColumn {
return
}
// `c.foldedNewLine` is a variable that is set to true for every newline.
if !s.isLiteral && s.foldedNewLine {
s.foldedNewLine = false
}
// Since addBuf ignore space character, add to the buffer directly.
ctx.buf = append(ctx.buf, ' ')
ctx.notSpaceCharPos = len(ctx.buf)
}
// updateNewLineInFolded if Folded or RawFolded context and the content on the current line starts at the same column as the previous line,
// treat the new-line-char as a space.
func (s *MultiLineState) updateNewLineInFolded(ctx *Context, column int) {
if s.isLiteral {
return
}
// Folded or RawFolded.
if !s.foldedNewLine {
return
}
var (
lastChar rune
prevLastChar rune
)
if len(ctx.buf) != 0 {
lastChar = ctx.buf[len(ctx.buf)-1]
}
if len(ctx.buf) > 1 {
prevLastChar = ctx.buf[len(ctx.buf)-2]
}
if s.lineIndentColumn == s.prevLineIndentColumn {
// ---
// >
// a
// b
if lastChar == '\n' {
ctx.buf[len(ctx.buf)-1] = ' '
}
} else if s.prevLineIndentColumn == 0 && s.lastNotSpaceOnlyLineIndentColumn == column {
// if previous line is indent-space and new-line-char only, prevLineIndentColumn is zero.
// In this case, last new-line-char is removed.
// ---
// >
// a
//
// b
if lastChar == '\n' && prevLastChar == '\n' {
ctx.buf = ctx.buf[:len(ctx.buf)-1]
ctx.notSpaceCharPos = len(ctx.buf)
}
}
s.foldedNewLine = false
}
func (s *MultiLineState) hasTrimAllEndNewlineOpt() bool {
return strings.HasPrefix(s.opt, "-") || strings.HasSuffix(s.opt, "-") || s.isRawFolded
}
func (s *MultiLineState) hasKeepAllEndNewlineOpt() bool {
return strings.HasPrefix(s.opt, "+") || strings.HasSuffix(s.opt, "+")
}
func (c *Context) addToken(tk *token.Token) {
if tk == nil {
return
}
c.tokens = append(c.tokens, tk)
}
func (c *Context) addBuf(r rune) {
if len(c.buf) == 0 && (r == ' ' || r == '\t') {
return
}
c.buf = append(c.buf, r)
if r != ' ' && r != '\t' {
c.notSpaceCharPos = len(c.buf)
}
}
func (c *Context) addBufWithTab(r rune) {
if len(c.buf) == 0 && r == ' ' {
return
}
c.buf = append(c.buf, r)
if r != ' ' {
c.notSpaceCharPos = len(c.buf)
}
}
func (c *Context) addOriginBuf(r rune) {
c.obuf = append(c.obuf, r)
if r != ' ' && r != '\t' {
c.notSpaceOrgCharPos = len(c.obuf)
}
}
func (c *Context) removeRightSpaceFromBuf() {
trimmedBuf := c.obuf[:c.notSpaceOrgCharPos]
buflen := len(trimmedBuf)
diff := len(c.obuf) - buflen
if diff > 0 {
c.obuf = c.obuf[:buflen]
c.buf = c.bufferedSrc()
}
}
func (c *Context) isEOS() bool {
return len(c.src)-1 <= c.idx
}
func (c *Context) isNextEOS() bool {
return len(c.src) <= c.idx+1
}
func (c *Context) next() bool {
return c.idx < c.size
}
func (c *Context) source(s, e int) string {
return string(c.src[s:e])
}
func (c *Context) previousChar() rune {
if c.idx > 0 {
return c.src[c.idx-1]
}
return rune(0)
}
func (c *Context) currentChar() rune {
if c.size > c.idx {
return c.src[c.idx]
}
return rune(0)
}
func (c *Context) nextChar() rune {
if c.size > c.idx+1 {
return c.src[c.idx+1]
}
return rune(0)
}
func (c *Context) repeatNum(r rune) int {
cnt := 0
for i := c.idx; i < c.size; i++ {
if c.src[i] == r {
cnt++
} else {
break
}
}
return cnt
}
func (c *Context) progress(num int) {
c.idx += num
}
func (c *Context) existsBuffer() bool {
return len(c.bufferedSrc()) != 0
}
func (c *Context) isMultiLine() bool {
return c.mstate != nil
}
func (c *Context) bufferedSrc() []rune {
src := c.buf[:c.notSpaceCharPos]
if c.isMultiLine() {
mstate := c.getMultiLineState()
// remove end '\n' character and trailing empty lines.
// https://yaml.org/spec/1.2.2/#8112-block-chomping-indicator
if mstate.hasTrimAllEndNewlineOpt() {
// If the '-' flag is specified, all trailing newline characters will be removed.
src = []rune(strings.TrimRight(string(src), "\n"))
} else if !mstate.hasKeepAllEndNewlineOpt() {
// Normally, all but one of the trailing newline characters are removed.
var newLineCharCount int
for i := len(src) - 1; i >= 0; i-- {
if src[i] == '\n' {
newLineCharCount++
continue
}
break
}
removedNewLineCharCount := newLineCharCount - 1
for removedNewLineCharCount > 0 {
src = []rune(strings.TrimSuffix(string(src), "\n"))
removedNewLineCharCount--
}
}
// If the text ends with a space character, remove all of them.
if mstate.hasTrimAllEndNewlineOpt() {
src = []rune(strings.TrimRight(string(src), " "))
}
if string(src) == "\n" {
// If the content consists only of a newline,
// it can be considered as the document ending without any specified value,
// so it is treated as an empty string.
src = []rune{}
}
if mstate.hasKeepAllEndNewlineOpt() && len(src) == 0 {
src = []rune{'\n'}
}
}
return src
}
func (c *Context) bufferedToken(pos *token.Position) *token.Token {
if c.idx == 0 {
return nil
}
source := c.bufferedSrc()
if len(source) == 0 {
c.buf = c.buf[:0] // clear value's buffer only.
return nil
}
var tk *token.Token
if c.isMultiLine() {
tk = token.String(string(source), string(c.obuf), pos)
} else {
tk = token.New(string(source), string(c.obuf), pos)
}
c.setTokenTypeByPrevTag(tk)
c.resetBuffer()
return tk
}
func (c *Context) setTokenTypeByPrevTag(tk *token.Token) {
lastTk := c.lastToken()
if lastTk == nil {
return
}
if lastTk.Type != token.TagType {
return
}
tag := token.ReservedTagKeyword(lastTk.Value)
if _, exists := token.ReservedTagKeywordMap[tag]; !exists {
tk.Type = token.StringType
}
}
func (c *Context) lastToken() *token.Token {
if len(c.tokens) != 0 {
return c.tokens[len(c.tokens)-1]
}
return nil
}
================================================
FILE: vendor/github.com/goccy/go-yaml/scanner/error.go
================================================
package scanner
import "github.com/goccy/go-yaml/token"
type InvalidTokenError struct {
Token *token.Token
}
func (e *InvalidTokenError) Error() string {
return e.Token.Error
}
func ErrInvalidToken(tk *token.Token) *InvalidTokenError {
return &InvalidTokenError{
Token: tk,
}
}
================================================
FILE: vendor/github.com/goccy/go-yaml/scanner/scanner.go
================================================
package scanner
import (
"errors"
"fmt"
"io"
"strconv"
"strings"
"github.com/goccy/go-yaml/token"
)
// IndentState state for indent
type IndentState int
const (
// IndentStateEqual equals previous indent
IndentStateEqual IndentState = iota
// IndentStateUp more indent than previous
IndentStateUp
// IndentStateDown less indent than previous
IndentStateDown
// IndentStateKeep uses not indent token
IndentStateKeep
)
// Scanner holds the scanner's internal state while processing a given text.
// It can be allocated as part of another data structure but must be initialized via Init before use.
type Scanner struct {
source []rune
sourcePos int
sourceSize int
// line number. This number starts from 1.
line int
// column number. This number starts from 1.
column int
// offset represents the offset from the beginning of the source.
offset int
// lastDelimColumn is the last column needed to compare indent is retained.
lastDelimColumn int
// indentNum indicates the number of spaces used for indentation.
indentNum int
// prevLineIndentNum indicates the number of spaces used for indentation at previous line.
prevLineIndentNum int
// indentLevel indicates the level of indent depth. This value does not match the column value.
indentLevel int
isFirstCharAtLine bool
isAnchor bool
isAlias bool
isDirective bool
startedFlowSequenceNum int
startedFlowMapNum int
indentState IndentState
savedPos *token.Position
}
func (s *Scanner) pos() *token.Position {
return &token.Position{
Line: s.line,
Column: s.column,
Offset: s.offset,
IndentNum: s.indentNum,
IndentLevel: s.indentLevel,
}
}
func (s *Scanner) bufferedToken(ctx *Context) *token.Token {
if s.savedPos != nil {
tk := ctx.bufferedToken(s.savedPos)
s.savedPos = nil
return tk
}
line := s.line
column := s.column - len(ctx.buf)
level := s.indentLevel
if ctx.isMultiLine() {
line -= s.newLineCount(ctx.buf)
column = strings.Index(string(ctx.obuf), string(ctx.buf)) + 1
// Since we are in a literal, folded or raw folded
// we can use the indent level from the last token.
last := ctx.lastToken()
if last != nil { // The last token should never be nil here.
level = last.Position.IndentLevel + 1
}
}
return ctx.bufferedToken(&token.Position{
Line: line,
Column: column,
Offset: s.offset - len(ctx.buf),
IndentNum: s.indentNum,
IndentLevel: level,
})
}
func (s *Scanner) progressColumn(ctx *Context, num int) {
s.column += num
s.offset += num
s.progress(ctx, num)
}
func (s *Scanner) progressOnly(ctx *Context, num int) {
s.offset += num
s.progress(ctx, num)
}
func (s *Scanner) progressLine(ctx *Context) {
s.prevLineIndentNum = s.indentNum
s.column = 1
s.line++
s.offset++
s.indentNum = 0
s.isFirstCharAtLine = true
s.isAnchor = false
s.isAlias = false
s.isDirective = false
s.progress(ctx, 1)
}
func (s *Scanner) progress(ctx *Context, num int) {
ctx.progress(num)
s.sourcePos += num
}
func (s *Scanner) isNewLineChar(c rune) bool {
if c == '\n' {
return true
}
if c == '\r' {
return true
}
return false
}
func (s *Scanner) newLineCount(src []rune) int {
size := len(src)
cnt := 0
for i := 0; i < size; i++ {
c := src[i]
switch c {
case '\r':
if i+1 < size && src[i+1] == '\n' {
i++
}
cnt++
case '\n':
cnt++
}
}
return cnt
}
func (s *Scanner) updateIndentLevel() {
if s.prevLineIndentNum < s.indentNum {
s.indentLevel++
} else if s.prevLineIndentNum > s.indentNum {
if s.indentLevel > 0 {
s.indentLevel--
}
}
}
func (s *Scanner) updateIndentState(ctx *Context) {
if s.lastDelimColumn == 0 {
return
}
if s.lastDelimColumn < s.column {
s.indentState = IndentStateUp
} else {
// If lastDelimColumn and s.column are the same,
// treat as Down state since it is the same column as delimiter.
s.indentState = IndentStateDown
}
}
func (s *Scanner) updateIndent(ctx *Context, c rune) {
if s.isFirstCharAtLine && s.isNewLineChar(c) {
return
}
if s.isFirstCharAtLine && c == ' ' {
s.indentNum++
return
}
if s.isFirstCharAtLine && c == '\t' {
// found tab indent.
// In this case, scanTab returns error.
return
}
if !s.isFirstCharAtLine {
s.indentState = IndentStateKeep
return
}
s.updateIndentLevel()
s.updateIndentState(ctx)
s.isFirstCharAtLine = false
}
func (s *Scanner) isChangedToIndentStateDown() bool {
return s.indentState == IndentStateDown
}
func (s *Scanner) isChangedToIndentStateUp() bool {
return s.indentState == IndentStateUp
}
func (s *Scanner) addBufferedTokenIfExists(ctx *Context) {
ctx.addToken(s.bufferedToken(ctx))
}
func (s *Scanner) breakMultiLine(ctx *Context) {
ctx.breakMultiLine()
}
func (s *Scanner) scanSingleQuote(ctx *Context) (*token.Token, error) {
ctx.addOriginBuf('\'')
srcpos := s.pos()
startIndex := ctx.idx + 1
src := ctx.src
size := len(src)
value := []rune{}
isFirstLineChar := false
isNewLine := false
for idx := startIndex; idx < size; idx++ {
if !isNewLine {
s.progressColumn(ctx, 1)
} else {
isNewLine = false
}
c := src[idx]
ctx.addOriginBuf(c)
if s.isNewLineChar(c) {
notSpaceIdx := -1
for i := len(value) - 1; i >= 0; i-- {
if value[i] == ' ' {
continue
}
notSpaceIdx = i
break
}
if len(value) > notSpaceIdx {
value = value[:notSpaceIdx+1]
}
if isFirstLineChar {
value = append(value, '\n')
} else {
value = append(value, ' ')
}
isFirstLineChar = true
isNewLine = true
s.progressLine(ctx)
if idx+1 < size {
if err := s.validateDocumentSeparatorMarker(ctx, src[idx+1:]); err != nil {
return nil, err
}
}
continue
} else if isFirstLineChar && c == ' ' {
continue
} else if isFirstLineChar && c == '\t' {
if s.lastDelimColumn >= s.column {
return nil, ErrInvalidToken(
token.Invalid(
"tab character cannot be used for indentation in single-quoted text",
string(ctx.obuf), s.pos(),
),
)
}
continue
} else if c != '\'' {
value = append(value, c)
isFirstLineChar = false
continue
} else if idx+1 < len(ctx.src) && ctx.src[idx+1] == '\'' {
// '' handle as ' character
value = append(value, c)
ctx.addOriginBuf(c)
idx++
s.progressColumn(ctx, 1)
continue
}
s.progressColumn(ctx, 1)
return token.SingleQuote(string(value), string(ctx.obuf), srcpos), nil
}
s.progressColumn(ctx, 1)
return nil, ErrInvalidToken(
token.Invalid(
"could not find end character of single-quoted text",
string(ctx.obuf), srcpos,
),
)
}
func hexToInt(b rune) int {
if b >= 'A' && b <= 'F' {
return int(b) - 'A' + 10
}
if b >= 'a' && b <= 'f' {
return int(b) - 'a' + 10
}
return int(b) - '0'
}
func hexRunesToInt(b []rune) int {
sum := 0
for i := 0; i < len(b); i++ {
sum += hexToInt(b[i]) << (uint(len(b)-i-1) * 4)
}
return sum
}
func (s *Scanner) scanDoubleQuote(ctx *Context) (*token.Token, error) {
ctx.addOriginBuf('"')
srcpos := s.pos()
startIndex := ctx.idx + 1
src := ctx.src
size := len(src)
value := []rune{}
isFirstLineChar := false
isNewLine := false
for idx := startIndex; idx < size; idx++ {
if !isNewLine {
s.progressColumn(ctx, 1)
} else {
isNewLine = false
}
c := src[idx]
ctx.addOriginBuf(c)
if s.isNewLineChar(c) {
notSpaceIdx := -1
for i := len(value) - 1; i >= 0; i-- {
if value[i] == ' ' {
continue
}
notSpaceIdx = i
break
}
if len(value) > notSpaceIdx {
value = value[:notSpaceIdx+1]
}
if isFirstLineChar {
value = append(value, '\n')
} else {
value = append(value, ' ')
}
isFirstLineChar = true
isNewLine = true
s.progressLine(ctx)
if idx+1 < size {
if err := s.validateDocumentSeparatorMarker(ctx, src[idx+1:]); err != nil {
return nil, err
}
}
continue
} else if isFirstLineChar && c == ' ' {
continue
} else if isFirstLineChar && c == '\t' {
if s.lastDelimColumn >= s.column {
return nil, ErrInvalidToken(
token.Invalid(
"tab character cannot be used for indentation in double-quoted text",
string(ctx.obuf), s.pos(),
),
)
}
continue
} else if c == '\\' {
isFirstLineChar = false
if idx+1 >= size {
value = append(value, c)
continue
}
nextChar := src[idx+1]
progress := 0
switch nextChar {
case '0':
progress = 1
ctx.addOriginBuf(nextChar)
value = append(value, 0x00)
case 'a':
progress = 1
ctx.addOriginBuf(nextChar)
value = append(value, 0x07)
case 'b':
progress = 1
ctx.addOriginBuf(nextChar)
value = append(value, 0x08)
case 't':
progress = 1
ctx.addOriginBuf(nextChar)
value = append(value, 0x09)
case 'n':
progress = 1
ctx.addOriginBuf(nextChar)
value = append(value, 0x0A)
case 'v':
progress = 1
ctx.addOriginBuf(nextChar)
value = append(value, 0x0B)
case 'f':
progress = 1
ctx.addOriginBuf(nextChar)
value = append(value, 0x0C)
case 'r':
progress = 1
ctx.addOriginBuf(nextChar)
value = append(value, 0x0D)
case 'e':
progress = 1
ctx.addOriginBuf(nextChar)
value = append(value, 0x1B)
case ' ':
progress = 1
ctx.addOriginBuf(nextChar)
value = append(value, 0x20)
case '"':
progress = 1
ctx.addOriginBuf(nextChar)
value = append(value, 0x22)
case '/':
progress = 1
ctx.addOriginBuf(nextChar)
value = append(value, 0x2F)
case '\\':
progress = 1
ctx.addOriginBuf(nextChar)
value = append(value, 0x5C)
case 'N':
progress = 1
ctx.addOriginBuf(nextChar)
value = append(value, 0x85)
case '_':
progress = 1
ctx.addOriginBuf(nextChar)
value = append(value, 0xA0)
case 'L':
progress = 1
ctx.addOriginBuf(nextChar)
value = append(value, 0x2028)
case 'P':
progress = 1
ctx.addOriginBuf(nextChar)
value = append(value, 0x2029)
case 'x':
if idx+3 >= size {
progress = 1
ctx.addOriginBuf(nextChar)
value = append(value, nextChar)
} else {
progress = 3
codeNum := hexRunesToInt(src[idx+2 : idx+progress+1])
value = append(value, rune(codeNum))
}
case 'u':
// \u0000 style must have 5 characters at least.
if idx+5 >= size {
return nil, ErrInvalidToken(
token.Invalid(
"not enough length for escaped UTF-16 character",
string(ctx.obuf), s.pos(),
),
)
}
progress = 5
codeNum := hexRunesToInt(src[idx+2 : idx+6])
// handle surrogate pairs.
if codeNum >= 0xD800 && codeNum <= 0xDBFF {
high := codeNum
// \u0000\u0000 style must have 11 characters at least.
if idx+11 >= size {
return nil, ErrInvalidToken(
token.Invalid(
"not enough length for escaped UTF-16 surrogate pair",
string(ctx.obuf), s.pos(),
),
)
}
if src[idx+6] != '\\' || src[idx+7] != 'u' {
return nil, ErrInvalidToken(
token.Invalid(
"found unexpected character after high surrogate for UTF-16 surrogate pair",
string(ctx.obuf), s.pos(),
),
)
}
low := hexRunesToInt(src[idx+8 : idx+12])
if low < 0xDC00 || low > 0xDFFF {
return nil, ErrInvalidToken(
token.Invalid(
"found unexpected low surrogate after high surrogate",
string(ctx.obuf), s.pos(),
),
)
}
codeNum = ((high - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000
progress += 6
}
value = append(value, rune(codeNum))
case 'U':
// \U00000000 style must have 9 characters at least.
if idx+9 >= size {
return nil, ErrInvalidToken(
token.Invalid(
"not enough length for escaped UTF-32 character",
string(ctx.obuf), s.pos(),
),
)
}
progress = 9
codeNum := hexRunesToInt(src[idx+2 : idx+10])
value = append(value, rune(codeNum))
case '\n':
isFirstLineChar = true
isNewLine = true
ctx.addOriginBuf(nextChar)
s.progressColumn(ctx, 1)
s.progressLine(ctx)
idx++
continue
case '\r':
isFirstLineChar = true
isNewLine = true
ctx.addOriginBuf(nextChar)
s.progressLine(ctx)
progress = 1
// Skip \n after \r in CRLF sequences
if idx+2 < size && src[idx+2] == '\n' {
ctx.addOriginBuf('\n')
progress = 2
}
case '\t':
progress = 1
ctx.addOriginBuf(nextChar)
value = append(value, nextChar)
default:
s.progressColumn(ctx, 1)
return nil, ErrInvalidToken(
token.Invalid(
fmt.Sprintf("found unknown escape character %q", nextChar),
string(ctx.obuf), s.pos(),
),
)
}
idx += progress
s.progressColumn(ctx, progress)
continue
} else if c == '\t' {
var (
foundNotSpaceChar bool
progress int
)
for i := idx + 1; i < size; i++ {
if src[i] == ' ' || src[i] == '\t' {
progress++
continue
}
if s.isNewLineChar(src[i]) {
break
}
foundNotSpaceChar = true
}
if foundNotSpaceChar {
value = append(value, c)
if src[idx+1] != '"' {
s.progressColumn(ctx, 1)
}
} else {
idx += progress
s.progressColumn(ctx, progress)
}
continue
} else if c != '"' {
value = append(value, c)
isFirstLineChar = false
continue
}
s.progressColumn(ctx, 1)
return token.DoubleQuote(string(value), string(ctx.obuf), srcpos), nil
}
s.progressColumn(ctx, 1)
return nil, ErrInvalidToken(
token.Invalid(
"could not find end character of double-quoted text",
string(ctx.obuf), srcpos,
),
)
}
func (s *Scanner) validateDocumentSeparatorMarker(ctx *Context, src []rune) error {
if s.foundDocumentSeparatorMarker(src) {
return ErrInvalidToken(
token.Invalid("found unexpected document separator", string(ctx.obuf), s.pos()),
)
}
return nil
}
func (s *Scanner) foundDocumentSeparatorMarker(src []rune) bool {
if len(src) < 3 {
return false
}
var marker string
if len(src) == 3 {
marker = string(src)
} else {
marker = strings.TrimRightFunc(string(src[:4]), func(r rune) bool {
return r == ' ' || r == '\t' || r == '\n' || r == '\r'
})
}
return marker == "---" || marker == "..."
}
func (s *Scanner) scanQuote(ctx *Context, ch rune) (bool, error) {
if ctx.existsBuffer() {
return false, nil
}
if ch == '\'' {
tk, err := s.scanSingleQuote(ctx)
if err != nil {
return false, err
}
ctx.addToken(tk)
} else {
tk, err := s.scanDoubleQuote(ctx)
if err != nil {
return false, err
}
ctx.addToken(tk)
}
ctx.clear()
return true, nil
}
func (s *Scanner) scanWhiteSpace(ctx *Context) bool {
if ctx.isMultiLine() {
return false
}
if !s.isAnchor && !s.isDirective && !s.isAlias && !s.isFirstCharAtLine {
return false
}
if s.isFirstCharAtLine {
s.progressColumn(ctx, 1)
ctx.addOriginBuf(' ')
return true
}
if s.isDirective {
s.addBufferedTokenIfExists(ctx)
s.progressColumn(ctx, 1)
ctx.addOriginBuf(' ')
return true
}
s.addBufferedTokenIfExists(ctx)
s.isAnchor = false
s.isAlias = false
return true
}
func (s *Scanner) isMergeKey(ctx *Context) bool {
if ctx.repeatNum('<') != 2 {
return false
}
src := ctx.src
size := len(src)
for idx := ctx.idx + 2; idx < size; idx++ {
c := src[idx]
if c == ' ' {
continue
}
if c != ':' {
return false
}
if idx+1 < size {
nc := src[idx+1]
if nc == ' ' || s.isNewLineChar(nc) {
return true
}
}
}
return false
}
func (s *Scanner) scanTag(ctx *Context) (bool, error) {
if ctx.existsBuffer() || s.isDirective {
return false, nil
}
ctx.addOriginBuf('!')
s.progress(ctx, 1) // skip '!' character
var progress int
for idx, c := range ctx.src[ctx.idx:] {
progress = idx + 1
switch c {
case ' ':
ctx.addOriginBuf(c)
value := ctx.source(ctx.idx-1, ctx.idx+idx)
ctx.addToken(token.Tag(value, string(ctx.obuf), s.pos()))
s.progressColumn(ctx, len([]rune(value)))
ctx.clear()
return true, nil
case ',':
if s.startedFlowSequenceNum > 0 || s.startedFlowMapNum > 0 {
value := ctx.source(ctx.idx-1, ctx.idx+idx)
ctx.addToken(token.Tag(value, string(ctx.obuf), s.pos()))
s.progressColumn(ctx, len([]rune(value))-1) // progress column before collect-entry for scanning it at scanFlowEntry function.
ctx.clear()
return true, nil
} else {
ctx.addOriginBuf(c)
}
case '\n', '\r':
ctx.addOriginBuf(c)
value := ctx.source(ctx.idx-1, ctx.idx+idx)
ctx.addToken(token.Tag(value, string(ctx.obuf), s.pos()))
s.progressColumn(ctx, len([]rune(value))-1) // progress column before new-line-char for scanning new-line-char at scanNewLine function.
ctx.clear()
return true, nil
case '{', '}':
ctx.addOriginBuf(c)
s.progressColumn(ctx, progress)
invalidTk := token.Invalid(fmt.Sprintf("found invalid tag character %q", c), string(ctx.obuf), s.pos())
return false, ErrInvalidToken(invalidTk)
default:
ctx.addOriginBuf(c)
}
}
s.progressColumn(ctx, progress)
ctx.clear()
return true, nil
}
func (s *Scanner) scanComment(ctx *Context) bool {
if ctx.existsBuffer() {
c := ctx.previousChar()
if c != ' ' && c != '\t' && !s.isNewLineChar(c) {
return false
}
}
s.addBufferedTokenIfExists(ctx)
ctx.addOriginBuf('#')
s.progress(ctx, 1) // skip '#' character
for idx, c := range ctx.src[ctx.idx:] {
ctx.addOriginBuf(c)
if !s.isNewLineChar(c) {
continue
}
if ctx.previousChar() == '\\' {
continue
}
value := ctx.source(ctx.idx, ctx.idx+idx)
progress := len([]rune(value))
ctx.addToken(token.Comment(value, string(ctx.obuf), s.pos()))
s.progressColumn(ctx, progress)
s.progressLine(ctx)
ctx.clear()
return true
}
// document ends with comment.
value := string(ctx.src[ctx.idx:])
ctx.addToken(token.Comment(value, string(ctx.obuf), s.pos()))
progress := len([]rune(value))
s.progressColumn(ctx, progress)
s.progressLine(ctx)
ctx.clear()
return true
}
func (s *Scanner) scanMultiLine(ctx *Context, c rune) error {
state := ctx.getMultiLineState()
ctx.addOriginBuf(c)
// normalize CR and CRLF to LF
if c == '\r' {
if ctx.nextChar() == '\n' {
ctx.addOriginBuf('\n')
s.progress(ctx, 1)
s.offset++
}
c = '\n'
}
if ctx.isEOS() {
if s.isFirstCharAtLine && c == ' ' {
state.addIndent(ctx, s.column)
} else {
ctx.addBuf(c)
}
state.updateIndentColumn(s.column)
if err := state.validateIndentColumn(); err != nil {
invalidTk := token.Invalid(err.Error(), string(ctx.obuf), s.pos())
s.progressColumn(ctx, 1)
return ErrInvalidToken(invalidTk)
}
value := ctx.bufferedSrc()
ctx.addToken(token.String(string(value), string(ctx.obuf), s.pos()))
ctx.clear()
s.progressColumn(ctx, 1)
} else if s.isNewLineChar(c) {
ctx.addBuf(c)
state.updateSpaceOnlyIndentColumn(s.column - 1)
state.updateNewLineState()
s.progressLine(ctx)
if ctx.next() {
if s.foundDocumentSeparatorMarker(ctx.src[ctx.idx:]) {
value := ctx.bufferedSrc()
ctx.addToken(token.String(string(value), string(ctx.obuf), s.pos()))
ctx.clear()
s.breakMultiLine(ctx)
}
}
} else if s.isFirstCharAtLine && c == ' ' {
state.addIndent(ctx, s.column)
s.progressColumn(ctx, 1)
} else if s.isFirstCharAtLine && c == '\t' && state.isIndentColumn(s.column) {
err := ErrInvalidToken(
token.Invalid(
"found a tab character where an indentation space is expected",
string(ctx.obuf), s.pos(),
),
)
s.progressColumn(ctx, 1)
return err
} else if c == '\t' && !state.isIndentColumn(s.column) {
ctx.addBufWithTab(c)
s.progressColumn(ctx, 1)
} else {
if err := state.validateIndentAfterSpaceOnly(s.column); err != nil {
invalidTk := token.Invalid(err.Error(), string(ctx.obuf), s.pos())
s.progressColumn(ctx, 1)
return ErrInvalidToken(invalidTk)
}
state.updateIndentColumn(s.column)
if err := state.validateIndentColumn(); err != nil {
invalidTk := token.Invalid(err.Error(), string(ctx.obuf), s.pos())
s.progressColumn(ctx, 1)
return ErrInvalidToken(invalidTk)
}
if col := state.lastDelimColumn(); col > 0 {
s.lastDelimColumn = col
}
state.updateNewLineInFolded(ctx, s.column)
ctx.addBufWithTab(c)
s.progressColumn(ctx, 1)
}
return nil
}
func (s *Scanner) scanNewLine(ctx *Context, c rune) {
if len(ctx.buf) > 0 && s.savedPos == nil {
bufLen := len(ctx.bufferedSrc())
s.savedPos = s.pos()
s.savedPos.Column -= bufLen
s.savedPos.Offset -= bufLen
}
// if the following case, origin buffer has unnecessary two spaces.
// So, `removeRightSpaceFromOriginBuf` remove them, also fix column number too.
// ---
// a:[space][space]
// b: c
ctx.removeRightSpaceFromBuf()
// There is no problem that we ignore CR which followed by LF and normalize it to LF, because of following YAML1.2 spec.
// > Line breaks inside scalar content must be normalized by the YAML processor. Each such line break must be parsed into a single line feed character.
// > Outside scalar content, YAML allows any line break to be used to terminate lines.
// > -- https://yaml.org/spec/1.2/spec.html
if c == '\r' && ctx.nextChar() == '\n' {
ctx.addOriginBuf('\r')
s.progress(ctx, 1)
s.offset++
c = '\n'
}
if ctx.isEOS() {
s.addBufferedTokenIfExists(ctx)
} else if s.isAnchor || s.isAlias || s.isDirective {
s.addBufferedTokenIfExists(ctx)
}
if ctx.existsBuffer() && s.isFirstCharAtLine {
if ctx.buf[len(ctx.buf)-1] == ' ' {
ctx.buf[len(ctx.buf)-1] = '\n'
} else {
ctx.buf = append(ctx.buf, '\n')
}
} else {
ctx.addBuf(' ')
}
ctx.addOriginBuf(c)
s.progressLine(ctx)
}
func (s *Scanner) isFlowMode() bool {
if s.startedFlowSequenceNum > 0 {
return true
}
if s.startedFlowMapNum > 0 {
return true
}
return false
}
func (s *Scanner) scanFlowMapStart(ctx *Context) bool {
if ctx.existsBuffer() && !s.isFlowMode() {
return false
}
s.addBufferedTokenIfExists(ctx)
ctx.addOriginBuf('{')
ctx.addToken(token.MappingStart(string(ctx.obuf), s.pos()))
s.startedFlowMapNum++
s.progressColumn(ctx, 1)
ctx.clear()
return true
}
func (s *Scanner) scanFlowMapEnd(ctx *Context) bool {
if s.startedFlowMapNum <= 0 {
return false
}
s.addBufferedTokenIfExists(ctx)
ctx.addOriginBuf('}')
ctx.addToken(token.MappingEnd(string(ctx.obuf), s.pos()))
s.startedFlowMapNum--
s.progressColumn(ctx, 1)
ctx.clear()
return true
}
func (s *Scanner) scanFlowArrayStart(ctx *Context) bool {
if ctx.existsBuffer() && !s.isFlowMode() {
return false
}
s.addBufferedTokenIfExists(ctx)
ctx.addOriginBuf('[')
ctx.addToken(token.SequenceStart(string(ctx.obuf), s.pos()))
s.startedFlowSequenceNum++
s.progressColumn(ctx, 1)
ctx.clear()
return true
}
func (s *Scanner) scanFlowArrayEnd(ctx *Context) bool {
if ctx.existsBuffer() && s.startedFlowSequenceNum <= 0 {
return false
}
s.addBufferedTokenIfExists(ctx)
ctx.addOriginBuf(']')
ctx.addToken(token.SequenceEnd(string(ctx.obuf), s.pos()))
s.startedFlowSequenceNum--
s.progressColumn(ctx, 1)
ctx.clear()
return true
}
func (s *Scanner) scanFlowEntry(ctx *Context, c rune) bool {
if s.startedFlowSequenceNum <= 0 && s.startedFlowMapNum <= 0 {
return false
}
s.addBufferedTokenIfExists(ctx)
ctx.addOriginBuf(c)
ctx.addToken(token.CollectEntry(string(ctx.obuf), s.pos()))
s.progressColumn(ctx, 1)
ctx.clear()
return true
}
func (s *Scanner) scanMapDelim(ctx *Context) (bool, error) {
nc := ctx.nextChar()
if s.isDirective || s.isAnchor || s.isAlias {
return false, nil
}
if s.startedFlowMapNum <= 0 && nc != ' ' && nc != '\t' && !s.isNewLineChar(nc) && !ctx.isNextEOS() {
return false, nil
}
if s.startedFlowMapNum > 0 && nc == '/' {
// like http://
return false, nil
}
if s.startedFlowMapNum > 0 {
tk := ctx.lastToken()
if tk != nil && tk.Type == token.MappingValueType {
return false, nil
}
}
if strings.HasPrefix(strings.TrimPrefix(string(ctx.obuf), " "), "\t") && !strings.HasPrefix(string(ctx.buf), "\t") {
invalidTk := token.Invalid("tab character cannot use as a map key directly", string(ctx.obuf), s.pos())
s.progressColumn(ctx, 1)
return false, ErrInvalidToken(invalidTk)
}
// mapping value
tk := s.bufferedToken(ctx)
if tk != nil {
s.lastDelimColumn = tk.Position.Column
ctx.addToken(tk)
} else if tk := ctx.lastToken(); tk != nil {
// If the map key is quote, the buffer does not exist because it has already been cut into tokens.
// Therefore, we need to check the last token.
if tk.Indicator == token.QuotedScalarIndicator {
s.lastDelimColumn = tk.Position.Column
}
}
ctx.addToken(token.MappingValue(s.pos()))
s.progressColumn(ctx, 1)
ctx.clear()
return true, nil
}
func (s *Scanner) scanDocumentStart(ctx *Context) bool {
if s.indentNum != 0 {
return false
}
if s.column != 1 {
return false
}
if ctx.repeatNum('-') != 3 {
return false
}
if ctx.size > ctx.idx+3 {
c := ctx.src[ctx.idx+3]
if c != ' ' && c != '\t' && c != '\n' && c != '\r' {
return false
}
}
s.addBufferedTokenIfExists(ctx)
ctx.addToken(token.DocumentHeader(string(ctx.obuf)+"---", s.pos()))
s.progressColumn(ctx, 3)
ctx.clear()
s.clearState()
return true
}
func (s *Scanner) scanDocumentEnd(ctx *Context) bool {
if s.indentNum != 0 {
return false
}
if s.column != 1 {
return false
}
if ctx.repeatNum('.') != 3 {
return false
}
s.addBufferedTokenIfExists(ctx)
ctx.addToken(token.DocumentEnd(string(ctx.obuf)+"...", s.pos()))
s.progressColumn(ctx, 3)
ctx.clear()
return true
}
func (s *Scanner) scanMergeKey(ctx *Context) bool {
if !s.isMergeKey(ctx) {
return false
}
s.lastDelimColumn = s.column
ctx.addToken(token.MergeKey(string(ctx.obuf)+"<<", s.pos()))
s.progressColumn(ctx, 2)
ctx.clear()
return true
}
func (s *Scanner) scanRawFoldedChar(ctx *Context) bool {
if !ctx.existsBuffer() {
return false
}
if !s.isChangedToIndentStateUp() {
return false
}
ctx.setRawFolded(s.column)
ctx.addBuf('-')
ctx.addOriginBuf('-')
s.progressColumn(ctx, 1)
return true
}
func (s *Scanner) scanSequence(ctx *Context) (bool, error) {
if ctx.existsBuffer() {
return false, nil
}
nc := ctx.nextChar()
if nc != 0 && nc != ' ' && nc != '\t' && !s.isNewLineChar(nc) {
return false, nil
}
if strings.HasPrefix(strings.TrimPrefix(string(ctx.obuf), " "), "\t") {
invalidTk := token.Invalid("tab character cannot use as a sequence delimiter", string(ctx.obuf), s.pos())
s.progressColumn(ctx, 1)
return false, ErrInvalidToken(invalidTk)
}
s.addBufferedTokenIfExists(ctx)
ctx.addOriginBuf('-')
tk := token.SequenceEntry(string(ctx.obuf), s.pos())
s.lastDelimColumn = tk.Position.Column
ctx.addToken(tk)
s.progressColumn(ctx, 1)
ctx.clear()
return true, nil
}
func (s *Scanner) scanMultiLineHeader(ctx *Context) (bool, error) {
if ctx.existsBuffer() {
return false, nil
}
if err := s.scanMultiLineHeaderOption(ctx); err != nil {
return false, err
}
s.progressLine(ctx)
return true, nil
}
func (s *Scanner) validateMultiLineHeaderOption(opt string) error {
if len(opt) == 0 {
return nil
}
orgOpt := opt
opt = strings.TrimPrefix(opt, "-")
opt = strings.TrimPrefix(opt, "+")
opt = strings.TrimSuffix(opt, "-")
opt = strings.TrimSuffix(opt, "+")
if len(opt) == 0 {
return nil
}
if opt == "0" {
return fmt.Errorf("invalid header option: %q", orgOpt)
}
i, err := strconv.ParseInt(opt, 10, 64)
if err != nil {
return fmt.Errorf("invalid header option: %q", orgOpt)
}
if i > 9 {
return fmt.Errorf("invalid header option: %q", orgOpt)
}
return nil
}
func (s *Scanner) scanMultiLineHeaderOption(ctx *Context) error {
header := ctx.currentChar()
ctx.addOriginBuf(header)
s.progress(ctx, 1) // skip '|' or '>' character
var progress int
var crlf bool
for idx, c := range ctx.src[ctx.idx:] {
progress = idx
ctx.addOriginBuf(c)
if s.isNewLineChar(c) {
nextIdx := ctx.idx + idx + 1
if c == '\r' && nextIdx < len(ctx.src) && ctx.src[nextIdx] == '\n' {
crlf = true
continue // process \n in the next iteration
}
break
}
}
endPos := ctx.idx + progress
if crlf {
// Exclude \r
endPos = endPos - 1
}
value := strings.TrimRight(ctx.source(ctx.idx, endPos), " ")
commentValueIndex := strings.Index(value, "#")
opt := value
if commentValueIndex > 0 {
opt = value[:commentValueIndex]
}
opt = strings.TrimRightFunc(opt, func(r rune) bool {
return r == ' ' || r == '\t'
})
if len(opt) != 0 {
if err := s.validateMultiLineHeaderOption(opt); err != nil {
invalidTk := token.Invalid(err.Error(), string(ctx.obuf), s.pos())
s.progressColumn(ctx, progress)
return ErrInvalidToken(invalidTk)
}
}
if s.column == 1 {
s.lastDelimColumn = 1
}
commentIndex := strings.Index(string(ctx.obuf), "#")
headerBuf := string(ctx.obuf)
if commentIndex > 0 {
headerBuf = headerBuf[:commentIndex]
}
switch header {
case '|':
ctx.addToken(token.Literal("|"+opt, headerBuf, s.pos()))
ctx.setLiteral(s.lastDelimColumn, opt)
case '>':
ctx.addToken(token.Folded(">"+opt, headerBuf, s.pos()))
ctx.setFolded(s.lastDelimColumn, opt)
}
if commentIndex > 0 {
comment := value[commentValueIndex+1:]
s.offset += len(headerBuf)
s.column += len(headerBuf)
ctx.addToken(token.Comment(comment, string(ctx.obuf[len(headerBuf):]), s.pos()))
}
s.indentState = IndentStateKeep
ctx.resetBuffer()
s.progressColumn(ctx, progress)
return nil
}
func (s *Scanner) scanMapKey(ctx *Context) bool {
if ctx.existsBuffer() {
return false
}
nc := ctx.nextChar()
if nc != ' ' && nc != '\t' {
return false
}
tk := token.MappingKey(s.pos())
s.lastDelimColumn = tk.Position.Column
ctx.addToken(tk)
s.progressColumn(ctx, 1)
ctx.clear()
return true
}
func (s *Scanner) scanDirective(ctx *Context) bool {
if ctx.existsBuffer() {
return false
}
if s.indentNum != 0 {
return false
}
s.addBufferedTokenIfExists(ctx)
ctx.addOriginBuf('%')
ctx.addToken(token.Directive(string(ctx.obuf), s.pos()))
s.progressColumn(ctx, 1)
ctx.clear()
s.isDirective = true
return true
}
func (s *Scanner) scanAnchor(ctx *Context) bool {
if ctx.existsBuffer() {
return false
}
s.addBufferedTokenIfExists(ctx)
ctx.addOriginBuf('&')
ctx.addToken(token.Anchor(string(ctx.obuf), s.pos()))
s.progressColumn(ctx, 1)
s.isAnchor = true
ctx.clear()
return true
}
func (s *Scanner) scanAlias(ctx *Context) bool {
if ctx.existsBuffer() {
return false
}
s.addBufferedTokenIfExists(ctx)
ctx.addOriginBuf('*')
ctx.addToken(token.Alias(string(ctx.obuf), s.pos()))
s.progressColumn(ctx, 1)
s.isAlias = true
ctx.clear()
return true
}
func (s *Scanner) scanReservedChar(ctx *Context, c rune) error {
if ctx.existsBuffer() {
return nil
}
ctx.addBuf(c)
ctx.addOriginBuf(c)
err := ErrInvalidToken(
token.Invalid(
fmt.Sprintf("%q is a reserved character", c),
string(ctx.obuf), s.pos(),
),
)
s.progressColumn(ctx, 1)
ctx.clear()
return err
}
func (s *Scanner) scanTab(ctx *Context, c rune) error {
if s.startedFlowSequenceNum > 0 || s.startedFlowMapNum > 0 {
// tabs character is allowed in flow mode.
return nil
}
if !s.isFirstCharAtLine {
return nil
}
ctx.addBuf(c)
ctx.addOriginBuf(c)
err := ErrInvalidToken(
token.Invalid("found character '\t' that cannot start any token",
string(ctx.obuf), s.pos(),
),
)
s.progressColumn(ctx, 1)
ctx.clear()
return err
}
func (s *Scanner) scan(ctx *Context) error {
for ctx.next() {
c := ctx.currentChar()
// First, change the IndentState.
// If the target character is the first character in a line, IndentState is Up/Down/Equal state.
// The second and subsequent letters are Keep.
s.updateIndent(ctx, c)
// If IndentState is down, tokens are split, so the buffer accumulated until that point needs to be cutted as a token.
if s.isChangedToIndentStateDown() {
s.addBufferedTokenIfExists(ctx)
}
if ctx.isMultiLine() {
if s.isChangedToIndentStateDown() {
if tk := ctx.lastToken(); tk != nil {
// If literal/folded content is empty, no string token is added.
// Therefore, add an empty string token.
// But if literal/folded token column is 1, it is invalid at down state.
if tk.Position.Column == 1 {
return ErrInvalidToken(
token.Invalid(
"could not find multi-line content",
string(ctx.obuf), s.pos(),
),
)
}
if tk.Type != token.StringType {
ctx.addToken(token.String("", "", s.pos()))
}
}
s.breakMultiLine(ctx)
} else {
if err := s.scanMultiLine(ctx, c); err != nil {
return err
}
continue
}
}
switch c {
case '{':
if s.scanFlowMapStart(ctx) {
continue
}
case '}':
if s.scanFlowMapEnd(ctx) {
continue
}
case '.':
if s.scanDocumentEnd(ctx) {
continue
}
case '<':
if s.scanMergeKey(ctx) {
continue
}
case '-':
if s.scanDocumentStart(ctx) {
continue
}
if s.scanRawFoldedChar(ctx) {
continue
}
scanned, err := s.scanSequence(ctx)
if err != nil {
return err
}
if scanned {
continue
}
case '[':
if s.scanFlowArrayStart(ctx) {
continue
}
case ']':
if s.scanFlowArrayEnd(ctx) {
continue
}
case ',':
if s.scanFlowEntry(ctx, c) {
continue
}
case ':':
scanned, err := s.scanMapDelim(ctx)
if err != nil {
return err
}
if scanned {
continue
}
case '|', '>':
scanned, err := s.scanMultiLineHeader(ctx)
if err != nil {
return err
}
if scanned {
continue
}
case '!':
scanned, err := s.scanTag(ctx)
if err != nil {
return err
}
if scanned {
continue
}
case '%':
if s.scanDirective(ctx) {
continue
}
case '?':
if s.scanMapKey(ctx) {
continue
}
case '&':
if s.scanAnchor(ctx) {
continue
}
case '*':
if s.scanAlias(ctx) {
continue
}
case '#':
if s.scanComment(ctx) {
continue
}
case '\'', '"':
scanned, err := s.scanQuote(ctx, c)
if err != nil {
return err
}
if scanned {
continue
}
case '\r', '\n':
s.scanNewLine(ctx, c)
continue
case ' ':
if s.scanWhiteSpace(ctx) {
continue
}
case '@', '`':
if err := s.scanReservedChar(ctx, c); err != nil {
return err
}
case '\t':
if ctx.existsBuffer() && s.lastDelimColumn == 0 {
// tab indent for plain text (yaml-test-suite's spec-example-7-12-plain-lines).
s.indentNum++
ctx.addOriginBuf(c)
s.progressOnly(ctx, 1)
continue
}
if s.lastDelimColumn < s.column {
s.indentNum++
ctx.addOriginBuf(c)
s.progressOnly(ctx, 1)
continue
}
if err := s.scanTab(ctx, c); err != nil {
return err
}
}
ctx.addBuf(c)
ctx.addOriginBuf(c)
s.progressColumn(ctx, 1)
}
s.addBufferedTokenIfExists(ctx)
return nil
}
// Init prepares the scanner s to tokenize the text src by setting the scanner at the beginning of src.
func (s *Scanner) Init(text string) {
src := []rune(text)
s.source = src
s.sourcePos = 0
s.sourceSize = len(src)
s.line = 1
s.column = 1
s.offset = 1
s.isFirstCharAtLine = true
s.clearState()
}
func (s *Scanner) clearState() {
s.prevLineIndentNum = 0
s.lastDelimColumn = 0
s.indentLevel = 0
s.indentNum = 0
}
// Scan scans the next token and returns the token collection. The source end is indicated by io.EOF.
func (s *Scanner) Scan() (token.Tokens, error) {
if s.sourcePos >= s.sourceSize {
return nil, io.EOF
}
ctx := newContext(s.source[s.sourcePos:])
defer ctx.release()
var tokens token.Tokens
err := s.scan(ctx)
tokens = append(tokens, ctx.tokens...)
if err != nil {
var invalidTokenErr *InvalidTokenError
if errors.As(err, &invalidTokenErr) {
tokens = append(tokens, invalidTokenErr.Token)
}
return tokens, err
}
return tokens, nil
}
================================================
FILE: vendor/github.com/goccy/go-yaml/stdlib_quote.go
================================================
// Copied and trimmed down from https://github.com/golang/go/blob/e3769299cd3484e018e0e2a6e1b95c2b18ce4f41/src/strconv/quote.go
// We want to use the standard library's private "quoteWith" function rather than write our own so that we get robust unicode support.
// Every private function called by quoteWith was copied.
// There are 2 modifications to simplify the code:
// 1. The unicode.IsPrint function was substituted for the custom implementation of IsPrint
// 2. All code paths reachable only when ASCIIonly or grphicOnly are set to true were removed.
// Copyright 2009 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.
package yaml
import (
"unicode"
"unicode/utf8"
)
const (
lowerhex = "0123456789abcdef"
)
func quoteWith(s string, quote byte) string {
return string(appendQuotedWith(make([]byte, 0, 3*len(s)/2), s, quote))
}
func appendQuotedWith(buf []byte, s string, quote byte) []byte {
// Often called with big strings, so preallocate. If there's quoting,
// this is conservative but still helps a lot.
if cap(buf)-len(buf) < len(s) {
nBuf := make([]byte, len(buf), len(buf)+1+len(s)+1)
copy(nBuf, buf)
buf = nBuf
}
buf = append(buf, quote)
for width := 0; len(s) > 0; s = s[width:] {
r := rune(s[0])
width = 1
if r >= utf8.RuneSelf {
r, width = utf8.DecodeRuneInString(s)
}
if width == 1 && r == utf8.RuneError {
buf = append(buf, `\x`...)
buf = append(buf, lowerhex[s[0]>>4])
buf = append(buf, lowerhex[s[0]&0xF])
continue
}
buf = appendEscapedRune(buf, r, quote)
}
buf = append(buf, quote)
return buf
}
func appendEscapedRune(buf []byte, r rune, quote byte) []byte {
var runeTmp [utf8.UTFMax]byte
// goccy/go-yaml patch on top of the standard library's appendEscapedRune function.
//
// We use this to implement the YAML single-quoted string, where the only escape sequence is '', which represents a single quote.
// The below snippet from the standard library is for escaping e.g. \ with \\, which is not what we want for the single-quoted string.
//
// if r == rune(quote) || r == '\\' { // always backslashed
// buf = append(buf, '\\')
// buf = append(buf, byte(r))
// return buf
// }
if r == rune(quote) {
buf = append(buf, byte(r))
buf = append(buf, byte(r))
return buf
}
if unicode.IsPrint(r) {
n := utf8.EncodeRune(runeTmp[:], r)
buf = append(buf, runeTmp[:n]...)
return buf
}
switch r {
case '\a':
buf = append(buf, `\a`...)
case '\b':
buf = append(buf, `\b`...)
case '\f':
buf = append(buf, `\f`...)
case '\n':
buf = append(buf, `\n`...)
case '\r':
buf = append(buf, `\r`...)
case '\t':
buf = append(buf, `\t`...)
case '\v':
buf = append(buf, `\v`...)
default:
switch {
case r < ' ':
buf = append(buf, `\x`...)
buf = append(buf, lowerhex[byte(r)>>4])
buf = append(buf, lowerhex[byte(r)&0xF])
case r > utf8.MaxRune:
r = 0xFFFD
fallthrough
case r < 0x10000:
buf = append(buf, `\u`...)
for s := 12; s >= 0; s -= 4 {
buf = append(buf, lowerhex[r>>uint(s)&0xF])
}
default:
buf = append(buf, `\U`...)
for s := 28; s >= 0; s -= 4 {
buf = append(buf, lowerhex[r>>uint(s)&0xF])
}
}
}
return buf
}
================================================
FILE: vendor/github.com/goccy/go-yaml/struct.go
================================================
package yaml
import (
"fmt"
"reflect"
"strings"
)
const (
// StructTagName tag keyword for Marshal/Unmarshal
StructTagName = "yaml"
)
// StructField information for each the field in structure
type StructField struct {
FieldName string
RenderName string
AnchorName string
AliasName string
IsAutoAnchor bool
IsAutoAlias bool
IsOmitEmpty bool
IsOmitZero bool
IsFlow bool
IsInline bool
}
func getTag(field reflect.StructField) string {
// If struct tag `yaml` exist, use that. If no `yaml`
// exists, but `json` does, use that and try the best to
// adhere to its rules
tag := field.Tag.Get(StructTagName)
if tag == "" {
tag = field.Tag.Get(`json`)
}
return tag
}
func structField(field reflect.StructField) *StructField {
tag := getTag(field)
fieldName := strings.ToLower(field.Name)
options := strings.Split(tag, ",")
if len(options) > 0 {
if options[0] != "" {
fieldName = options[0]
}
}
sf := &StructField{
FieldName: field.Name,
RenderName: fieldName,
}
if len(options) > 1 {
for _, opt := range options[1:] {
switch {
case opt == "omitempty":
sf.IsOmitEmpty = true
case opt == "omitzero":
sf.IsOmitZero = true
case opt == "flow":
sf.IsFlow = true
case opt == "inline":
sf.IsInline = true
case strings.HasPrefix(opt, "anchor"):
anchor := strings.Split(opt, "=")
if len(anchor) > 1 {
sf.AnchorName = anchor[1]
} else {
sf.IsAutoAnchor = true
}
case strings.HasPrefix(opt, "alias"):
alias := strings.Split(opt, "=")
if len(alias) > 1 {
sf.AliasName = alias[1]
} else {
sf.IsAutoAlias = true
}
default:
}
}
}
return sf
}
func isIgnoredStructField(field reflect.StructField) bool {
if field.PkgPath != "" && !field.Anonymous {
// private field
return true
}
return getTag(field) == "-"
}
type StructFieldMap map[string]*StructField
func (m StructFieldMap) isIncludedRenderName(name string) bool {
for _, v := range m {
if !v.IsInline && v.RenderName == name {
return true
}
}
return false
}
func (m StructFieldMap) hasMergeProperty() bool {
for _, v := range m {
if v.IsOmitEmpty && v.IsInline && v.IsAutoAlias {
return true
}
}
return false
}
func structFieldMap(structType reflect.Type) (StructFieldMap, error) {
fieldMap := StructFieldMap{}
renderNameMap := map[string]struct{}{}
for i := 0; i < structType.NumField(); i++ {
field := structType.Field(i)
if isIgnoredStructField(field) {
continue
}
sf := structField(field)
if _, exists := renderNameMap[sf.RenderName]; exists {
return nil, fmt.Errorf("duplicated struct field name %s", sf.RenderName)
}
fieldMap[sf.FieldName] = sf
renderNameMap[sf.RenderName] = struct{}{}
}
return fieldMap, nil
}
================================================
FILE: vendor/github.com/goccy/go-yaml/token/token.go
================================================
package token
import (
"errors"
"fmt"
"strconv"
"strings"
"time"
)
// Character type for character
type Character byte
const (
// SequenceEntryCharacter character for sequence entry
SequenceEntryCharacter Character = '-'
// MappingKeyCharacter character for mapping key
MappingKeyCharacter Character = '?'
// MappingValueCharacter character for mapping value
MappingValueCharacter Character = ':'
// CollectEntryCharacter character for collect entry
CollectEntryCharacter Character = ','
// SequenceStartCharacter character for sequence start
SequenceStartCharacter Character = '['
// SequenceEndCharacter character for sequence end
SequenceEndCharacter Character = ']'
// MappingStartCharacter character for mapping start
MappingStartCharacter Character = '{'
// MappingEndCharacter character for mapping end
MappingEndCharacter Character = '}'
// CommentCharacter character for comment
CommentCharacter Character = '#'
// AnchorCharacter character for anchor
AnchorCharacter Character = '&'
// AliasCharacter character for alias
AliasCharacter Character = '*'
// TagCharacter character for tag
TagCharacter Character = '!'
// LiteralCharacter character for literal
LiteralCharacter Character = '|'
// FoldedCharacter character for folded
FoldedCharacter Character = '>'
// SingleQuoteCharacter character for single quote
SingleQuoteCharacter Character = '\''
// DoubleQuoteCharacter character for double quote
DoubleQuoteCharacter Character = '"'
// DirectiveCharacter character for directive
DirectiveCharacter Character = '%'
// SpaceCharacter character for space
SpaceCharacter Character = ' '
// LineBreakCharacter character for line break
LineBreakCharacter Character = '\n'
)
// Type type identifier for token
type Type int
const (
// UnknownType reserve for invalid type
UnknownType Type = iota
// DocumentHeaderType type for DocumentHeader token
DocumentHeaderType
// DocumentEndType type for DocumentEnd token
DocumentEndType
// SequenceEntryType type for SequenceEntry token
SequenceEntryType
// MappingKeyType type for MappingKey token
MappingKeyType
// MappingValueType type for MappingValue token
MappingValueType
// MergeKeyType type for MergeKey token
MergeKeyType
// CollectEntryType type for CollectEntry token
CollectEntryType
// SequenceStartType type for SequenceStart token
SequenceStartType
// SequenceEndType type for SequenceEnd token
SequenceEndType
// MappingStartType type for MappingStart token
MappingStartType
// MappingEndType type for MappingEnd token
MappingEndType
// CommentType type for Comment token
CommentType
// AnchorType type for Anchor token
AnchorType
// AliasType type for Alias token
AliasType
// TagType type for Tag token
TagType
// LiteralType type for Literal token
LiteralType
// FoldedType type for Folded token
FoldedType
// SingleQuoteType type for SingleQuote token
SingleQuoteType
// DoubleQuoteType type for DoubleQuote token
DoubleQuoteType
// DirectiveType type for Directive token
DirectiveType
// SpaceType type for Space token
SpaceType
// NullType type for Null token
NullType
// ImplicitNullType type for implicit Null token.
// This is used when explicit keywords such as null or ~ are not specified.
// It is distinguished during encoding and output as an empty string.
ImplicitNullType
// InfinityType type for Infinity token
InfinityType
// NanType type for Nan token
NanType
// IntegerType type for Integer token
IntegerType
// BinaryIntegerType type for BinaryInteger token
BinaryIntegerType
// OctetIntegerType type for OctetInteger token
OctetIntegerType
// HexIntegerType type for HexInteger token
HexIntegerType
// FloatType type for Float token
FloatType
// StringType type for String token
StringType
// BoolType type for Bool token
BoolType
// InvalidType type for invalid token
InvalidType
)
// String type identifier to text
func (t Type) String() string {
switch t {
case UnknownType:
return "Unknown"
case DocumentHeaderType:
return "DocumentHeader"
case DocumentEndType:
return "DocumentEnd"
case SequenceEntryType:
return "SequenceEntry"
case MappingKeyType:
return "MappingKey"
case MappingValueType:
return "MappingValue"
case MergeKeyType:
return "MergeKey"
case CollectEntryType:
return "CollectEntry"
case SequenceStartType:
return "SequenceStart"
case SequenceEndType:
return "SequenceEnd"
case MappingStartType:
return "MappingStart"
case MappingEndType:
return "MappingEnd"
case CommentType:
return "Comment"
case AnchorType:
return "Anchor"
case AliasType:
return "Alias"
case TagType:
return "Tag"
case LiteralType:
return "Literal"
case FoldedType:
return "Folded"
case SingleQuoteType:
return "SingleQuote"
case DoubleQuoteType:
return "DoubleQuote"
case DirectiveType:
return "Directive"
case SpaceType:
return "Space"
case StringType:
return "String"
case BoolType:
return "Bool"
case IntegerType:
return "Integer"
case BinaryIntegerType:
return "BinaryInteger"
case OctetIntegerType:
return "OctetInteger"
case HexIntegerType:
return "HexInteger"
case FloatType:
return "Float"
case NullType:
return "Null"
case ImplicitNullType:
return "ImplicitNull"
case InfinityType:
return "Infinity"
case NanType:
return "Nan"
case InvalidType:
return "Invalid"
}
return ""
}
// CharacterType type for character category
type CharacterType int
const (
// CharacterTypeIndicator type of indicator character
CharacterTypeIndicator CharacterType = iota
// CharacterTypeWhiteSpace type of white space character
CharacterTypeWhiteSpace
// CharacterTypeMiscellaneous type of miscellaneous character
CharacterTypeMiscellaneous
// CharacterTypeEscaped type of escaped character
CharacterTypeEscaped
// CharacterTypeInvalid type for a invalid token.
CharacterTypeInvalid
)
// String character type identifier to text
func (c CharacterType) String() string {
switch c {
case CharacterTypeIndicator:
return "Indicator"
case CharacterTypeWhiteSpace:
return "WhiteSpace"
case CharacterTypeMiscellaneous:
return "Miscellaneous"
case CharacterTypeEscaped:
return "Escaped"
}
return ""
}
// Indicator type for indicator
type Indicator int
const (
// NotIndicator not indicator
NotIndicator Indicator = iota
// BlockStructureIndicator indicator for block structure ( '-', '?', ':' )
BlockStructureIndicator
// FlowCollectionIndicator indicator for flow collection ( '[', ']', '{', '}', ',' )
FlowCollectionIndicator
// CommentIndicator indicator for comment ( '#' )
CommentIndicator
// NodePropertyIndicator indicator for node property ( '!', '&', '*' )
NodePropertyIndicator
// BlockScalarIndicator indicator for block scalar ( '|', '>' )
BlockScalarIndicator
// QuotedScalarIndicator indicator for quoted scalar ( ''', '"' )
QuotedScalarIndicator
// DirectiveIndicator indicator for directive ( '%' )
DirectiveIndicator
// InvalidUseOfReservedIndicator indicator for invalid use of reserved keyword ( '@', '`' )
InvalidUseOfReservedIndicator
)
// String indicator to text
func (i Indicator) String() string {
switch i {
case NotIndicator:
return "NotIndicator"
case BlockStructureIndicator:
return "BlockStructure"
case FlowCollectionIndicator:
return "FlowCollection"
case CommentIndicator:
return "Comment"
case NodePropertyIndicator:
return "NodeProperty"
case BlockScalarIndicator:
return "BlockScalar"
case QuotedScalarIndicator:
return "QuotedScalar"
case DirectiveIndicator:
return "Directive"
case InvalidUseOfReservedIndicator:
return "InvalidUseOfReserved"
}
return ""
}
var (
reservedNullKeywords = []string{
"null",
"Null",
"NULL",
"~",
}
reservedBoolKeywords = []string{
"true",
"True",
"TRUE",
"false",
"False",
"FALSE",
}
// For compatibility with other YAML 1.1 parsers
// Note that we use these solely for encoding the bool value with quotes.
// go-yaml should not treat these as reserved keywords at parsing time.
// as go-yaml is supposed to be compliant only with YAML 1.2.
reservedLegacyBoolKeywords = []string{
"y",
"Y",
"yes",
"Yes",
"YES",
"n",
"N",
"no",
"No",
"NO",
"on",
"On",
"ON",
"off",
"Off",
"OFF",
}
reservedInfKeywords = []string{
".inf",
".Inf",
".INF",
"-.inf",
"-.Inf",
"-.INF",
}
reservedNanKeywords = []string{
".nan",
".NaN",
".NAN",
}
reservedKeywordMap = map[string]func(string, string, *Position) *Token{}
// reservedEncKeywordMap contains is the keyword map used at encoding time.
// This is supposed to be a superset of reservedKeywordMap,
// and used to quote legacy keywords present in YAML 1.1 or lesser for compatibility reasons,
// even though this library is supposed to be YAML 1.2-compliant.
reservedEncKeywordMap = map[string]func(string, string, *Position) *Token{}
)
func reservedKeywordToken(typ Type, value, org string, pos *Position) *Token {
return &Token{
Type: typ,
CharacterType: CharacterTypeMiscellaneous,
Indicator: NotIndicator,
Value: value,
Origin: org,
Position: pos,
}
}
func init() {
for _, keyword := range reservedNullKeywords {
f := func(value, org string, pos *Position) *Token {
return reservedKeywordToken(NullType, value, org, pos)
}
reservedKeywordMap[keyword] = f
reservedEncKeywordMap[keyword] = f
}
for _, keyword := range reservedBoolKeywords {
f := func(value, org string, pos *Position) *Token {
return reservedKeywordToken(BoolType, value, org, pos)
}
reservedKeywordMap[keyword] = f
reservedEncKeywordMap[keyword] = f
}
for _, keyword := range reservedLegacyBoolKeywords {
reservedEncKeywordMap[keyword] = func(value, org string, pos *Position) *Token {
return reservedKeywordToken(BoolType, value, org, pos)
}
}
for _, keyword := range reservedInfKeywords {
reservedKeywordMap[keyword] = func(value, org string, pos *Position) *Token {
return reservedKeywordToken(InfinityType, value, org, pos)
}
}
for _, keyword := range reservedNanKeywords {
reservedKeywordMap[keyword] = func(value, org string, pos *Position) *Token {
return reservedKeywordToken(NanType, value, org, pos)
}
}
}
// ReservedTagKeyword type of reserved tag keyword
type ReservedTagKeyword string
const (
// IntegerTag `!!int` tag
IntegerTag ReservedTagKeyword = "!!int"
// FloatTag `!!float` tag
FloatTag ReservedTagKeyword = "!!float"
// NullTag `!!null` tag
NullTag ReservedTagKeyword = "!!null"
// SequenceTag `!!seq` tag
SequenceTag ReservedTagKeyword = "!!seq"
// MappingTag `!!map` tag
MappingTag ReservedTagKeyword = "!!map"
// StringTag `!!str` tag
StringTag ReservedTagKeyword = "!!str"
// BinaryTag `!!binary` tag
BinaryTag ReservedTagKeyword = "!!binary"
// OrderedMapTag `!!omap` tag
OrderedMapTag ReservedTagKeyword = "!!omap"
// SetTag `!!set` tag
SetTag ReservedTagKeyword = "!!set"
// TimestampTag `!!timestamp` tag
TimestampTag ReservedTagKeyword = "!!timestamp"
// BooleanTag `!!bool` tag
BooleanTag ReservedTagKeyword = "!!bool"
// MergeTag `!!merge` tag
MergeTag ReservedTagKeyword = "!!merge"
)
var (
// ReservedTagKeywordMap map for reserved tag keywords
ReservedTagKeywordMap = map[ReservedTagKeyword]func(string, string, *Position) *Token{
IntegerTag: func(value, org string, pos *Position) *Token {
return &Token{
Type: TagType,
CharacterType: CharacterTypeIndicator,
Indicator: NodePropertyIndicator,
Value: value,
Origin: org,
Position: pos,
}
},
FloatTag: func(value, org string, pos *Position) *Token {
return &Token{
Type: TagType,
CharacterType: CharacterTypeIndicator,
Indicator: NodePropertyIndicator,
Value: value,
Origin: org,
Position: pos,
}
},
NullTag: func(value, org string, pos *Position) *Token {
return &Token{
Type: TagType,
CharacterType: CharacterTypeIndicator,
Indicator: NodePropertyIndicator,
Value: value,
Origin: org,
Position: pos,
}
},
SequenceTag: func(value, org string, pos *Position) *Token {
return &Token{
Type: TagType,
CharacterType: CharacterTypeIndicator,
Indicator: NodePropertyIndicator,
Value: value,
Origin: org,
Position: pos,
}
},
MappingTag: func(value, org string, pos *Position) *Token {
return &Token{
Type: TagType,
CharacterType: CharacterTypeIndicator,
Indicator: NodePropertyIndicator,
Value: value,
Origin: org,
Position: pos,
}
},
StringTag: func(value, org string, pos *Position) *Token {
return &Token{
Type: TagType,
CharacterType: CharacterTypeIndicator,
Indicator: NodePropertyIndicator,
Value: value,
Origin: org,
Position: pos,
}
},
BinaryTag: func(value, org string, pos *Position) *Token {
return &Token{
Type: TagType,
CharacterType: CharacterTypeIndicator,
Indicator: NodePropertyIndicator,
Value: value,
Origin: org,
Position: pos,
}
},
OrderedMapTag: func(value, org string, pos *Position) *Token {
return &Token{
Type: TagType,
CharacterType: CharacterTypeIndicator,
Indicator: NodePropertyIndicator,
Value: value,
Origin: org,
Position: pos,
}
},
SetTag: func(value, org string, pos *Position) *Token {
return &Token{
Type: TagType,
CharacterType: CharacterTypeIndicator,
Indicator: NodePropertyIndicator,
Value: value,
Origin: org,
Position: pos,
}
},
TimestampTag: func(value, org string, pos *Position) *Token {
return &Token{
Type: TagType,
CharacterType: CharacterTypeIndicator,
Indicator: NodePropertyIndicator,
Value: value,
Origin: org,
Position: pos,
}
},
BooleanTag: func(value, org string, pos *Position) *Token {
return &Token{
Type: TagType,
CharacterType: CharacterTypeIndicator,
Indicator: NodePropertyIndicator,
Value: value,
Origin: org,
Position: pos,
}
},
MergeTag: func(value, org string, pos *Position) *Token {
return &Token{
Type: TagType,
CharacterType: CharacterTypeIndicator,
Indicator: NodePropertyIndicator,
Value: value,
Origin: org,
Position: pos,
}
},
}
)
type NumberType string
const (
NumberTypeDecimal NumberType = "decimal"
NumberTypeBinary NumberType = "binary"
NumberTypeOctet NumberType = "octet"
NumberTypeHex NumberType = "hex"
NumberTypeFloat NumberType = "float"
)
type NumberValue struct {
Type NumberType
Value any
Text string
}
func ToNumber(value string) *NumberValue {
num, err := toNumber(value)
if err != nil {
return nil
}
return num
}
func isNumber(value string) bool {
num, err := toNumber(value)
if err != nil {
var numErr *strconv.NumError
if errors.As(err, &numErr) && errors.Is(numErr.Err, strconv.ErrRange) {
return true
}
return false
}
return num != nil
}
func toNumber(value string) (*NumberValue, error) {
if len(value) == 0 {
return nil, nil
}
if strings.HasPrefix(value, "_") {
return nil, nil
}
dotCount := strings.Count(value, ".")
if dotCount > 1 {
return nil, nil
}
isNegative := strings.HasPrefix(value, "-")
normalized := strings.ReplaceAll(strings.TrimPrefix(strings.TrimPrefix(value, "+"), "-"), "_", "")
var (
typ NumberType
base int
)
switch {
case strings.HasPrefix(normalized, "0x"):
normalized = strings.TrimPrefix(normalized, "0x")
base = 16
typ = NumberTypeHex
case strings.HasPrefix(normalized, "0o"):
normalized = strings.TrimPrefix(normalized, "0o")
base = 8
typ = NumberTypeOctet
case strings.HasPrefix(normalized, "0b"):
normalized = strings.TrimPrefix(normalized, "0b")
base = 2
typ = NumberTypeBinary
case strings.HasPrefix(normalized, "0") && len(normalized) > 1 && dotCount == 0:
base = 8
typ = NumberTypeOctet
case dotCount == 1:
typ = NumberTypeFloat
default:
typ = NumberTypeDecimal
base = 10
}
text := normalized
if isNegative {
text = "-" + text
}
var v any
if typ == NumberTypeFloat {
f, err := strconv.ParseFloat(text, 64)
if err != nil {
return nil, err
}
v = f
} else if isNegative {
i, err := strconv.ParseInt(text, base, 64)
if err != nil {
return nil, err
}
v = i
} else {
u, err := strconv.ParseUint(text, base, 64)
if err != nil {
return nil, err
}
v = u
}
return &NumberValue{
Type: typ,
Value: v,
Text: text,
}, nil
}
// This is a subset of the formats permitted by the regular expression
// defined at http://yaml.org/type/timestamp.html. Note that time.Parse
// cannot handle: "2001-12-14 21:59:43.10 -5" from the examples.
var timestampFormats = []string{
time.RFC3339Nano,
"2006-01-02t15:04:05.999999999Z07:00", // RFC3339Nano with lower-case "t".
time.DateTime,
time.DateOnly,
// Not in examples, but to preserve backward compatibility by quoting time values.
"15:4",
}
func isTimestamp(value string) bool {
for _, format := range timestampFormats {
if _, err := time.Parse(format, value); err == nil {
return true
}
}
return false
}
// IsNeedQuoted checks whether the value needs quote for passed string or not
func IsNeedQuoted(value string) bool {
if value == "" {
return true
}
if _, exists := reservedEncKeywordMap[value]; exists {
return true
}
if isNumber(value) {
return true
}
if value == "-" {
return true
}
first := value[0]
switch first {
case '*', '&', '[', '{', '}', ']', ',', '!', '|', '>', '%', '\'', '"', '@', ' ', '`':
return true
}
last := value[len(value)-1]
switch last {
case ':', ' ':
return true
}
if isTimestamp(value) {
return true
}
for i, c := range value {
switch c {
case '#', '\\':
return true
case ':', '-':
if i+1 < len(value) && value[i+1] == ' ' {
return true
}
}
}
return false
}
// LiteralBlockHeader detect literal block scalar header
func LiteralBlockHeader(value string) string {
lbc := DetectLineBreakCharacter(value)
switch {
case !strings.Contains(value, lbc):
return ""
case strings.HasSuffix(value, fmt.Sprintf("%s%s", lbc, lbc)):
return "|+"
case strings.HasSuffix(value, lbc):
return "|"
default:
return "|-"
}
}
// New create reserved keyword token or number token and other string token.
func New(value string, org string, pos *Position) *Token {
fn := reservedKeywordMap[value]
if fn != nil {
return fn(value, org, pos)
}
if num := ToNumber(value); num != nil {
tk := &Token{
Type: IntegerType,
CharacterType: CharacterTypeMiscellaneous,
Indicator: NotIndicator,
Value: value,
Origin: org,
Position: pos,
}
switch num.Type {
case NumberTypeFloat:
tk.Type = FloatType
case NumberTypeBinary:
tk.Type = BinaryIntegerType
case NumberTypeOctet:
tk.Type = OctetIntegerType
case NumberTypeHex:
tk.Type = HexIntegerType
}
return tk
}
return String(value, org, pos)
}
// Position type for position in YAML document
type Position struct {
Line int
Column int
Offset int
IndentNum int
IndentLevel int
}
// String position to text
func (p *Position) String() string {
return fmt.Sprintf("[level:%d,line:%d,column:%d,offset:%d]", p.IndentLevel, p.Line, p.Column, p.Offset)
}
// Token type for token
type Token struct {
// Type is a token type.
Type Type
// CharacterType is a character type.
CharacterType CharacterType
// Indicator is a indicator type.
Indicator Indicator
// Value is a string extracted with only meaningful characters, with spaces and such removed.
Value string
// Origin is a string that stores the original text as-is.
Origin string
// Error keeps error message for InvalidToken.
Error string
// Position is a token position.
Position *Position
// Next is a next token reference.
Next *Token
// Prev is a previous token reference.
Prev *Token
}
// PreviousType previous token type
func (t *Token) PreviousType() Type {
if t.Prev != nil {
return t.Prev.Type
}
return UnknownType
}
// NextType next token type
func (t *Token) NextType() Type {
if t.Next != nil {
return t.Next.Type
}
return UnknownType
}
// AddColumn append column number to current position of column
func (t *Token) AddColumn(col int) {
if t == nil {
return
}
t.Position.Column += col
}
// Clone copy token ( preserve Prev/Next reference )
func (t *Token) Clone() *Token {
if t == nil {
return nil
}
copied := *t
if t.Position != nil {
pos := *(t.Position)
copied.Position = &pos
}
return &copied
}
// Dump outputs token information to stdout for debugging.
func (t *Token) Dump() {
fmt.Printf(
"[TYPE]:%q [CHARTYPE]:%q [INDICATOR]:%q [VALUE]:%q [ORG]:%q [POS(line:column:level:offset)]: %d:%d:%d:%d\n",
t.Type, t.CharacterType, t.Indicator, t.Value, t.Origin, t.Position.Line, t.Position.Column, t.Position.IndentLevel, t.Position.Offset,
)
}
// Tokens type of token collection
type Tokens []*Token
func (t Tokens) InvalidToken() *Token {
for _, tt := range t {
if tt.Type == InvalidType {
return tt
}
}
return nil
}
func (t *Tokens) add(tk *Token) {
tokens := *t
if len(tokens) == 0 {
tokens = append(tokens, tk)
} else {
last := tokens[len(tokens)-1]
last.Next = tk
tk.Prev = last
tokens = append(tokens, tk)
}
*t = tokens
}
// Add append new some tokens
func (t *Tokens) Add(tks ...*Token) {
for _, tk := range tks {
t.add(tk)
}
}
// Dump dump all token structures for debugging
func (t Tokens) Dump() {
for _, tk := range t {
fmt.Print("- ")
tk.Dump()
}
}
// String create token for String
func String(value string, org string, pos *Position) *Token {
return &Token{
Type: StringType,
CharacterType: CharacterTypeMiscellaneous,
Indicator: NotIndicator,
Value: value,
Origin: org,
Position: pos,
}
}
// SequenceEntry create token for SequenceEntry
func SequenceEntry(org string, pos *Position) *Token {
return &Token{
Type: SequenceEntryType,
CharacterType: CharacterTypeIndicator,
Indicator: BlockStructureIndicator,
Value: string(SequenceEntryCharacter),
Origin: org,
Position: pos,
}
}
// MappingKey create token for MappingKey
func MappingKey(pos *Position) *Token {
return &Token{
Type: MappingKeyType,
CharacterType: CharacterTypeIndicator,
Indicator: BlockStructureIndicator,
Value: string(MappingKeyCharacter),
Origin: string(MappingKeyCharacter),
Position: pos,
}
}
// MappingValue create token for MappingValue
func MappingValue(pos *Position) *Token {
return &Token{
Type: MappingValueType,
CharacterType: CharacterTypeIndicator,
Indicator: BlockStructureIndicator,
Value: string(MappingValueCharacter),
Origin: string(MappingValueCharacter),
Position: pos,
}
}
// CollectEntry create token for CollectEntry
func CollectEntry(org string, pos *Position) *Token {
return &Token{
Type: CollectEntryType,
CharacterType: CharacterTypeIndicator,
Indicator: FlowCollectionIndicator,
Value: string(CollectEntryCharacter),
Origin: org,
Position: pos,
}
}
// SequenceStart create token for SequenceStart
func SequenceStart(org string, pos *Position) *Token {
return &Token{
Type: SequenceStartType,
CharacterType: CharacterTypeIndicator,
Indicator: FlowCollectionIndicator,
Value: string(SequenceStartCharacter),
Origin: org,
Position: pos,
}
}
// SequenceEnd create token for SequenceEnd
func SequenceEnd(org string, pos *Position) *Token {
return &Token{
Type: SequenceEndType,
CharacterType: CharacterTypeIndicator,
Indicator: FlowCollectionIndicator,
Value: string(SequenceEndCharacter),
Origin: org,
Position: pos,
}
}
// MappingStart create token for MappingStart
func MappingStart(org string, pos *Position) *Token {
return &Token{
Type: MappingStartType,
CharacterType: CharacterTypeIndicator,
Indicator: FlowCollectionIndicator,
Value: string(MappingStartCharacter),
Origin: org,
Position: pos,
}
}
// MappingEnd create token for MappingEnd
func MappingEnd(org string, pos *Position) *Token {
return &Token{
Type: MappingEndType,
CharacterType: CharacterTypeIndicator,
Indicator: FlowCollectionIndicator,
Value: string(MappingEndCharacter),
Origin: org,
Position: pos,
}
}
// Comment create token for Comment
func Comment(value string, org string, pos *Position) *Token {
return &Token{
Type: CommentType,
CharacterType: CharacterTypeIndicator,
Indicator: CommentIndicator,
Value: value,
Origin: org,
Position: pos,
}
}
// Anchor create token for Anchor
func Anchor(org string, pos *Position) *Token {
return &Token{
Type: AnchorType,
CharacterType: CharacterTypeIndicator,
Indicator: NodePropertyIndicator,
Value: string(AnchorCharacter),
Origin: org,
Position: pos,
}
}
// Alias create token for Alias
func Alias(org string, pos *Position) *Token {
return &Token{
Type: AliasType,
CharacterType: CharacterTypeIndicator,
Indicator: NodePropertyIndicator,
Value: string(AliasCharacter),
Origin: org,
Position: pos,
}
}
// Tag create token for Tag
func Tag(value string, org string, pos *Position) *Token {
fn := ReservedTagKeywordMap[ReservedTagKeyword(value)]
if fn != nil {
return fn(value, org, pos)
}
return &Token{
Type: TagType,
CharacterType: CharacterTypeIndicator,
Indicator: NodePropertyIndicator,
Value: value,
Origin: org,
Position: pos,
}
}
// Literal create token for Literal
func Literal(value string, org string, pos *Position) *Token {
return &Token{
Type: LiteralType,
CharacterType: CharacterTypeIndicator,
Indicator: BlockScalarIndicator,
Value: value,
Origin: org,
Position: pos,
}
}
// Folded create token for Folded
func Folded(value string, org string, pos *Position) *Token {
return &Token{
Type: FoldedType,
CharacterType: CharacterTypeIndicator,
Indicator: BlockScalarIndicator,
Value: value,
Origin: org,
Position: pos,
}
}
// SingleQuote create token for SingleQuote
func SingleQuote(value string, org string, pos *Position) *Token {
return &Token{
Type: SingleQuoteType,
CharacterType: CharacterTypeIndicator,
Indicator: QuotedScalarIndicator,
Value: value,
Origin: org,
Position: pos,
}
}
// DoubleQuote create token for DoubleQuote
func DoubleQuote(value string, org string, pos *Position) *Token {
return &Token{
Type: DoubleQuoteType,
CharacterType: CharacterTypeIndicator,
Indicator: QuotedScalarIndicator,
Value: value,
Origin: org,
Position: pos,
}
}
// Directive create token for Directive
func Directive(org string, pos *Position) *Token {
return &Token{
Type: DirectiveType,
CharacterType: CharacterTypeIndicator,
Indicator: DirectiveIndicator,
Value: string(DirectiveCharacter),
Origin: org,
Position: pos,
}
}
// Space create token for Space
func Space(pos *Position) *Token {
return &Token{
Type: SpaceType,
CharacterType: CharacterTypeWhiteSpace,
Indicator: NotIndicator,
Value: string(SpaceCharacter),
Origin: string(SpaceCharacter),
Position: pos,
}
}
// MergeKey create token for MergeKey
func MergeKey(org string, pos *Position) *Token {
return &Token{
Type: MergeKeyType,
CharacterType: CharacterTypeMiscellaneous,
Indicator: NotIndicator,
Value: "<<",
Origin: org,
Position: pos,
}
}
// DocumentHeader create token for DocumentHeader
func DocumentHeader(org string, pos *Position) *Token {
return &Token{
Type: DocumentHeaderType,
CharacterType: CharacterTypeMiscellaneous,
Indicator: NotIndicator,
Value: "---",
Origin: org,
Position: pos,
}
}
// DocumentEnd create token for DocumentEnd
func DocumentEnd(org string, pos *Position) *Token {
return &Token{
Type: DocumentEndType,
CharacterType: CharacterTypeMiscellaneous,
Indicator: NotIndicator,
Value: "...",
Origin: org,
Position: pos,
}
}
func Invalid(err string, org string, pos *Position) *Token {
return &Token{
Type: InvalidType,
CharacterType: CharacterTypeInvalid,
Indicator: NotIndicator,
Value: org,
Origin: org,
Error: err,
Position: pos,
}
}
// DetectLineBreakCharacter detect line break character in only one inside scalar content scope.
func DetectLineBreakCharacter(src string) string {
nc := strings.Count(src, "\n")
rc := strings.Count(src, "\r")
rnc := strings.Count(src, "\r\n")
switch {
case nc == rnc && rc == rnc:
return "\r\n"
case rc > nc:
return "\r"
default:
return "\n"
}
}
================================================
FILE: vendor/github.com/goccy/go-yaml/validate.go
================================================
package yaml
// StructValidator need to implement Struct method only
// ( see https://pkg.go.dev/github.com/go-playground/validator/v10#Validate.Struct )
type StructValidator interface {
Struct(interface{}) error
}
// FieldError need to implement StructField method only
// ( see https://pkg.go.dev/github.com/go-playground/validator/v10#FieldError )
type FieldError interface {
StructField() string
}
================================================
FILE: vendor/github.com/goccy/go-yaml/yaml.go
================================================
package yaml
import (
"bytes"
"context"
"io"
"reflect"
"sync"
"github.com/goccy/go-yaml/ast"
"github.com/goccy/go-yaml/internal/errors"
)
// BytesMarshaler interface may be implemented by types to customize their
// behavior when being marshaled into a YAML document. The returned value
// is marshaled in place of the original value implementing Marshaler.
//
// If an error is returned by MarshalYAML, the marshaling procedure stops
// and returns with the provided error.
type BytesMarshaler interface {
MarshalYAML() ([]byte, error)
}
// BytesMarshalerContext interface use BytesMarshaler with context.Context.
type BytesMarshalerContext interface {
MarshalYAML(context.Context) ([]byte, error)
}
// InterfaceMarshaler interface has MarshalYAML compatible with github.com/go-yaml/yaml package.
type InterfaceMarshaler interface {
MarshalYAML() (interface{}, error)
}
// InterfaceMarshalerContext interface use InterfaceMarshaler with context.Context.
type InterfaceMarshalerContext interface {
MarshalYAML(context.Context) (interface{}, error)
}
// BytesUnmarshaler interface may be implemented by types to customize their
// behavior when being unmarshaled from a YAML document.
type BytesUnmarshaler interface {
UnmarshalYAML([]byte) error
}
// BytesUnmarshalerContext interface use BytesUnmarshaler with context.Context.
type BytesUnmarshalerContext interface {
UnmarshalYAML(context.Context, []byte) error
}
// InterfaceUnmarshaler interface has UnmarshalYAML compatible with github.com/go-yaml/yaml package.
type InterfaceUnmarshaler interface {
UnmarshalYAML(func(interface{}) error) error
}
// InterfaceUnmarshalerContext interface use InterfaceUnmarshaler with context.Context.
type InterfaceUnmarshalerContext interface {
UnmarshalYAML(context.Context, func(interface{}) error) error
}
// NodeUnmarshaler interface is similar to BytesUnmarshaler but provide related AST node instead of raw YAML source.
type NodeUnmarshaler interface {
UnmarshalYAML(ast.Node) error
}
// NodeUnmarshalerContext interface is similar to BytesUnmarshaler but provide related AST node instead of raw YAML source.
type NodeUnmarshalerContext interface {
UnmarshalYAML(context.Context, ast.Node) error
}
// MapItem is an item in a MapSlice.
type MapItem struct {
Key, Value interface{}
}
// MapSlice encodes and decodes as a YAML map.
// The order of keys is preserved when encoding and decoding.
type MapSlice []MapItem
// ToMap convert to map[interface{}]interface{}.
func (s MapSlice) ToMap() map[interface{}]interface{} {
v := map[interface{}]interface{}{}
for _, item := range s {
v[item.Key] = item.Value
}
return v
}
// Marshal serializes the value provided into a YAML document. The structure
// of the generated document will reflect the structure of the value itself.
// Maps and pointers (to struct, string, int, etc) are accepted as the in value.
//
// Struct fields are only marshaled if they are exported (have an upper case
// first letter), and are marshaled using the field name lowercased as the
// default key. Custom keys may be defined via the "yaml" name in the field
// tag: the content preceding the first comma is used as the key, and the
// following comma-separated options are used to tweak the marshaling process.
// Conflicting names result in a runtime error.
//
// The field tag format accepted is:
//
// `(...) yaml:"[][,[,]]" (...)`
//
// The following flags are currently supported:
//
// omitempty Only include the field if it's not set to the zero
// value for the type or to empty slices or maps.
// Zero valued structs will be omitted if all their public
// fields are zero, unless they implement an IsZero
// method (see the IsZeroer interface type), in which
// case the field will be included if that method returns true.
// Note that this definition is slightly different from the Go's
// encoding/json 'omitempty' definition. It combines some elements
// of 'omitempty' and 'omitzero'. See https://github.com/goccy/go-yaml/issues/695.
//
// omitzero The omitzero tag behaves in the same way as the interpretation of the omitzero tag in the encoding/json library.
// 1) If the field type has an "IsZero() bool" method, that will be used to determine whether the value is zero.
// 2) Otherwise, the value is zero if it is the zero value for its type.
//
// flow Marshal using a flow style (useful for structs,
// sequences and maps).
//
// inline Inline the field, which must be a struct or a map,
// causing all of its fields or keys to be processed as if
// they were part of the outer struct. For maps, keys must
// not conflict with the yaml keys of other struct fields.
//
// anchor Marshal with anchor. If want to define anchor name explicitly, use anchor=name style.
// Otherwise, if used 'anchor' name only, used the field name lowercased as the anchor name
//
// alias Marshal with alias. If want to define alias name explicitly, use alias=name style.
// Otherwise, If omitted alias name and the field type is pointer type,
// assigned anchor name automatically from same pointer address.
//
// In addition, if the key is "-", the field is ignored.
//
// For example:
//
// type T struct {
// F int `yaml:"a,omitempty"`
// B int
// }
// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
// yaml.Marshal(&T{F: 1}) // Returns "a: 1\nb: 0\n"
func Marshal(v interface{}) ([]byte, error) {
return MarshalWithOptions(v)
}
// MarshalWithOptions serializes the value provided into a YAML document with EncodeOptions.
func MarshalWithOptions(v interface{}, opts ...EncodeOption) ([]byte, error) {
return MarshalContext(context.Background(), v, opts...)
}
// MarshalContext serializes the value provided into a YAML document with context.Context and EncodeOptions.
func MarshalContext(ctx context.Context, v interface{}, opts ...EncodeOption) ([]byte, error) {
var buf bytes.Buffer
if err := NewEncoder(&buf, opts...).EncodeContext(ctx, v); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// ValueToNode convert from value to ast.Node.
func ValueToNode(v interface{}, opts ...EncodeOption) (ast.Node, error) {
var buf bytes.Buffer
node, err := NewEncoder(&buf, opts...).EncodeToNode(v)
if err != nil {
return nil, err
}
return node, nil
}
// Unmarshal decodes the first document found within the in byte slice
// and assigns decoded values into the out value.
//
// Struct fields are only unmarshalled if they are exported (have an
// upper case first letter), and are unmarshalled using the field name
// lowercased as the default key. Custom keys may be defined via the
// "yaml" name in the field tag: the content preceding the first comma
// is used as the key, and the following comma-separated options are
// used to tweak the marshaling process (see Marshal).
// Conflicting names result in a runtime error.
//
// For example:
//
// type T struct {
// F int `yaml:"a,omitempty"`
// B int
// }
// var t T
// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
//
// See the documentation of Marshal for the format of tags and a list of
// supported tag options.
func Unmarshal(data []byte, v interface{}) error {
return UnmarshalWithOptions(data, v)
}
// UnmarshalWithOptions decodes with DecodeOptions the first document found within the in byte slice
// and assigns decoded values into the out value.
func UnmarshalWithOptions(data []byte, v interface{}, opts ...DecodeOption) error {
return UnmarshalContext(context.Background(), data, v, opts...)
}
// UnmarshalContext decodes with context.Context and DecodeOptions.
func UnmarshalContext(ctx context.Context, data []byte, v interface{}, opts ...DecodeOption) error {
dec := NewDecoder(bytes.NewBuffer(data), opts...)
if err := dec.DecodeContext(ctx, v); err != nil {
if err == io.EOF {
return nil
}
return err
}
return nil
}
// NodeToValue converts node to the value pointed to by v.
func NodeToValue(node ast.Node, v interface{}, opts ...DecodeOption) error {
var buf bytes.Buffer
if err := NewDecoder(&buf, opts...).DecodeFromNode(node, v); err != nil {
return err
}
return nil
}
// FormatError is a utility function that takes advantage of the metadata
// stored in the errors returned by this package's parser.
//
// If the second argument `colored` is true, the error message is colorized.
// If the third argument `inclSource` is true, the error message will
// contain snippets of the YAML source that was used.
func FormatError(e error, colored, inclSource bool) string {
var yamlErr Error
if errors.As(e, &yamlErr) {
return yamlErr.FormatError(colored, inclSource)
}
return e.Error()
}
// YAMLToJSON convert YAML bytes to JSON.
func YAMLToJSON(bytes []byte) ([]byte, error) {
var v interface{}
if err := UnmarshalWithOptions(bytes, &v, UseOrderedMap()); err != nil {
return nil, err
}
out, err := MarshalWithOptions(v, JSON())
if err != nil {
return nil, err
}
return out, nil
}
// JSONToYAML convert JSON bytes to YAML.
func JSONToYAML(bytes []byte) ([]byte, error) {
var v interface{}
if err := UnmarshalWithOptions(bytes, &v, UseOrderedMap()); err != nil {
return nil, err
}
out, err := Marshal(v)
if err != nil {
return nil, err
}
return out, nil
}
var (
globalCustomMarshalerMu sync.Mutex
globalCustomUnmarshalerMu sync.Mutex
globalCustomMarshalerMap = map[reflect.Type]func(context.Context, interface{}) ([]byte, error){}
globalCustomUnmarshalerMap = map[reflect.Type]func(context.Context, interface{}, []byte) error{}
)
// RegisterCustomMarshaler overrides any encoding process for the type specified in generics.
// If you want to switch the behavior for each encoder, use `CustomMarshaler` defined as EncodeOption.
//
// NOTE: If type T implements MarshalYAML for pointer receiver, the type specified in RegisterCustomMarshaler must be *T.
// If RegisterCustomMarshaler and CustomMarshaler of EncodeOption are specified for the same type,
// the CustomMarshaler specified in EncodeOption takes precedence.
func RegisterCustomMarshaler[T any](marshaler func(T) ([]byte, error)) {
globalCustomMarshalerMu.Lock()
defer globalCustomMarshalerMu.Unlock()
var typ T
globalCustomMarshalerMap[reflect.TypeOf(typ)] = func(ctx context.Context, v interface{}) ([]byte, error) {
return marshaler(v.(T))
}
}
// RegisterCustomMarshalerContext overrides any encoding process for the type specified in generics.
// Similar to RegisterCustomMarshalerContext, but allows passing a context to the unmarshaler function.
func RegisterCustomMarshalerContext[T any](marshaler func(context.Context, T) ([]byte, error)) {
globalCustomMarshalerMu.Lock()
defer globalCustomMarshalerMu.Unlock()
var typ T
globalCustomMarshalerMap[reflect.TypeOf(typ)] = func(ctx context.Context, v interface{}) ([]byte, error) {
return marshaler(ctx, v.(T))
}
}
// RegisterCustomUnmarshaler overrides any decoding process for the type specified in generics.
// If you want to switch the behavior for each decoder, use `CustomUnmarshaler` defined as DecodeOption.
//
// NOTE: If RegisterCustomUnmarshaler and CustomUnmarshaler of DecodeOption are specified for the same type,
// the CustomUnmarshaler specified in DecodeOption takes precedence.
func RegisterCustomUnmarshaler[T any](unmarshaler func(*T, []byte) error) {
globalCustomUnmarshalerMu.Lock()
defer globalCustomUnmarshalerMu.Unlock()
var typ *T
globalCustomUnmarshalerMap[reflect.TypeOf(typ)] = func(ctx context.Context, v interface{}, b []byte) error {
return unmarshaler(v.(*T), b)
}
}
// RegisterCustomUnmarshalerContext overrides any decoding process for the type specified in generics.
// Similar to RegisterCustomUnmarshalerContext, but allows passing a context to the unmarshaler function.
func RegisterCustomUnmarshalerContext[T any](unmarshaler func(context.Context, *T, []byte) error) {
globalCustomUnmarshalerMu.Lock()
defer globalCustomUnmarshalerMu.Unlock()
var typ *T
globalCustomUnmarshalerMap[reflect.TypeOf(typ)] = func(ctx context.Context, v interface{}, b []byte) error {
return unmarshaler(ctx, v.(*T), b)
}
}
// RawMessage is a raw encoded YAML value. It implements [BytesMarshaler] and
// [BytesUnmarshaler] and can be used to delay YAML decoding or precompute a YAML
// encoding.
// It also implements [json.Marshaler] and [json.Unmarshaler].
//
// This is similar to [json.RawMessage] in the stdlib.
type RawMessage []byte
func (m RawMessage) MarshalYAML() ([]byte, error) {
if m == nil {
return []byte("null"), nil
}
return m, nil
}
func (m *RawMessage) UnmarshalYAML(dt []byte) error {
if m == nil {
return errors.New("yaml.RawMessage: UnmarshalYAML on nil pointer")
}
*m = append((*m)[0:0], dt...)
return nil
}
func (m *RawMessage) UnmarshalJSON(b []byte) error {
return m.UnmarshalYAML(b)
}
func (m RawMessage) MarshalJSON() ([]byte, error) {
return YAMLToJSON(m)
}
================================================
FILE: vendor/github.com/gofrs/uuid/v5/.gitignore
================================================
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# binary bundle generated by go-fuzz
uuid-fuzz.zip
================================================
FILE: vendor/github.com/gofrs/uuid/v5/.pre-commit-config.yaml
================================================
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.16.3
hooks:
- id: gitleaks
- repo: https://github.com/golangci/golangci-lint
rev: v1.52.2
hooks:
- id: golangci-lint
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
================================================
FILE: vendor/github.com/gofrs/uuid/v5/LICENSE
================================================
Copyright (C) 2013-2018 by Maxim Bublis
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: vendor/github.com/gofrs/uuid/v5/README.md
================================================
# UUID
[](https://github.com/gofrs/uuid/blob/master/LICENSE)
[](https://github.com/gofrs/uuid/actions/workflows/go.yml)
[](https://pkg.go.dev/github.com/gofrs/uuid/v5)
[](https://codecov.io/gh/gofrs/uuid/)
[](https://goreportcard.com/report/github.com/gofrs/uuid)
[](https://github.com/gofrs/uuid/actions/workflows/codeql.yml)
[](https://www.bestpractices.dev/projects/8929)
[](https://scorecard.dev/viewer/?uri=github.com/gofrs/uuid)
Package uuid provides a pure Go implementation of Universally Unique Identifiers
(UUID) variant as defined in RFC-9562. This package supports both the creation
and parsing of UUIDs in different formats.
This package supports the following UUID versions:
* Version 1, based on timestamp and MAC address
* Version 3, based on MD5 hashing of a named value
* Version 4, based on random numbers
* Version 5, based on SHA-1 hashing of a named value
* Version 6, a k-sortable id based on timestamp, and field-compatible with v1
* Version 7, a k-sortable id based on timestamp
## Project History
This project was originally forked from the
[github.com/satori/go.uuid](https://github.com/satori/go.uuid) repository after
it appeared to be no longer maintained, while exhibiting [critical
flaws](https://github.com/satori/go.uuid/issues/73). We have decided to take
over this project to ensure it receives regular maintenance for the benefit of
the larger Go community.
We'd like to thank Maxim Bublis for his hard work on the original iteration of
the package.
## License
This source code of this package is released under the MIT License. Please see
the [LICENSE](https://github.com/gofrs/uuid/blob/master/LICENSE) for the full
content of the license.
## Recommended Package Version
We recommend using v2.0.0+ of this package, as versions prior to 2.0.0 were
created before our fork of the original package and have some known
deficiencies.
## Requirements
This package requires Go 1.19 or later
## Usage
Here is a quick overview of how to use this package. For more detailed
documentation, please see the [GoDoc Page](http://godoc.org/github.com/gofrs/uuid).
```go
package main
import (
"log"
"github.com/gofrs/uuid/v5"
)
// Create a Version 4 UUID, panicking on error.
// Use this form to initialize package-level variables.
var u1 = uuid.Must(uuid.NewV4())
func main() {
// Create a Version 4 UUID.
u2, err := uuid.NewV4()
if err != nil {
log.Fatalf("failed to generate UUID: %v", err)
}
log.Printf("generated Version 4 UUID %v", u2)
// Parse a UUID from a string.
s := "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
u3, err := uuid.FromString(s)
if err != nil {
log.Fatalf("failed to parse UUID %q: %v", s, err)
}
log.Printf("successfully parsed UUID %v", u3)
}
```
## References
* [RFC-9562](https://tools.ietf.org/html/rfc9562) (replaces RFC-4122)
* [DCE 1.1: Authentication and Security Services](http://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01)
================================================
FILE: vendor/github.com/gofrs/uuid/v5/SECURITY.md
================================================
# Security Policy
## Supported Versions
We support the latest version of this library. We do not guarantee support of previous versions. If a defect is reported, it will generally be fixed on the latest version
(provided it exists) irrespective of whether it was introduced in a prior version.
## Reporting a Vulnerability
If you discover a vulnerability against this package, please report it in the issues tab with a `vulnerability` label. We will examine promptly.
If you would like to disclose the vulnerability privately, you may reach the maintainers in our [channel](https://gophers.slack.com/archives/CBP4N9BEU) on the gophers slack.
## Security Scorecard
This project submits security [results](https://scorecard.dev/viewer/?uri=github.com/gofrs/uuid) to the [OpenSSF Scorecard](https://securityscorecards.dev/).
### Actively Maintained
One heuristic these scorecards measure to gauge whether a package is safe for consumption is an "Actively Maintained" metric. Because this library implements UUIDs,
it is very stable - there is not much maintenance required other than adding/updating newer UUID versions, keeping up to date with latest versions of Go, and responding
to reported exploits. As a result, periods of low active maintenance are to be expected.
================================================
FILE: vendor/github.com/gofrs/uuid/v5/codec.go
================================================
// Copyright (C) 2013-2018 by Maxim Bublis
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package uuid
import "fmt"
// FromBytes returns a UUID generated from the raw byte slice input.
// It will return an error if the slice isn't 16 bytes long.
func FromBytes(input []byte) (UUID, error) {
u := UUID{}
err := u.UnmarshalBinary(input)
return u, err
}
// FromBytesOrNil returns a UUID generated from the raw byte slice input.
// Same behavior as FromBytes(), but returns uuid.Nil instead of an error.
func FromBytesOrNil(input []byte) UUID {
// The logic here is duplicated from UnmarshalBinary as there is unnecessary
// overhead generating errors which would be checked and discarded.
if len(input) != Size {
return Nil
}
uuid := UUID{}
copy(uuid[:], input)
return uuid
}
func fromHexChar(c byte) byte {
switch {
case '0' <= c && c <= '9':
return c - '0'
case 'a' <= c && c <= 'f':
return c - 'a' + 10
case 'A' <= c && c <= 'F':
return c - 'A' + 10
}
return 255
}
// parseBytes parses UUID text representation from a byte slice and populates
// the provided UUID reference. It centralizes the parsing logic so that both
// Parse (string input) and UnmarshalText ([]byte input) can delegate to this
// single implementation, eliminating code duplication.
//
// Supported formats and ABNF grammar are documented on UnmarshalText; refer
// there for full details. This helper simply enforces those rules.
func parseBytes(b []byte, u *UUID) error {
// Fast-path: ensure we don't accidentally mutate the caller's slice.
// We will only reslice, never modify the underlying bytes.
switch len(b) {
case 32: // hash
case 36: // canonical
case 34, 38:
if b[0] != '{' || b[len(b)-1] != '}' {
return fmt.Errorf("%w %q", ErrIncorrectFormatInString, b)
}
b = b[1 : len(b)-1]
case 41, 45:
if string(b[:9]) != "urn:uuid:" {
return fmt.Errorf("%w %q", ErrIncorrectFormatInString, b[:9])
}
b = b[9:]
default:
return fmt.Errorf("%w %d in string %q", ErrIncorrectLength, len(b), b)
}
// canonical (36 chars with dashes at fixed positions)
if len(b) == 36 {
if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' {
return fmt.Errorf("%w %q", ErrIncorrectFormatInString, b)
}
for i, x := range [16]byte{
0, 2, 4, 6,
9, 11,
14, 16,
19, 21,
24, 26, 28, 30, 32, 34,
} {
v1 := fromHexChar(b[x])
v2 := fromHexChar(b[x+1])
if v1|v2 == 255 {
return ErrInvalidFormat
}
u[i] = (v1 << 4) | v2
}
return nil
}
// hash-like (32 hex chars, no dashes)
for i := 0; i < 32; i += 2 {
v1 := fromHexChar(b[i])
v2 := fromHexChar(b[i+1])
if v1|v2 == 255 {
return ErrInvalidFormat
}
u[i/2] = (v1 << 4) | v2
}
return nil
}
// Parse parses the UUID stored in the string text. Parsing and supported
// formats are the same as UnmarshalText.
func (u *UUID) Parse(s string) error {
return parseBytes([]byte(s), u)
}
// FromString returns a UUID parsed from the input string.
// Input is expected in a form accepted by UnmarshalText.
func FromString(text string) (UUID, error) {
var u UUID
err := u.Parse(text)
return u, err
}
// FromStringOrNil returns a UUID parsed from the input string.
// Same behavior as FromString(), but returns uuid.Nil instead of an error.
func FromStringOrNil(input string) UUID {
uuid, err := FromString(input)
if err != nil {
return Nil
}
return uuid
}
// MarshalText implements the encoding.TextMarshaler interface.
// The encoding is the same as returned by the String() method.
func (u UUID) MarshalText() ([]byte, error) {
var buf [36]byte
encodeCanonical(buf[:], u)
return buf[:], nil
}
// Following formats are supported:
//
// "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
// "6ba7b8109dad11d180b400c04fd430c8",
// "{6ba7b8109dad11d180b400c04fd430c8}",
// "urn:uuid:6ba7b8109dad11d180b400c04fd430c8"
//
// ABNF for supported UUID text representation follows:
//
// URN := "urn"
// UUID-NID := "uuid"
//
// hexdig := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" |
// "a" | "b" | "c" | "d" | "e" | "f" |
// "A" | "B" | "C" | "D" | "E" | "F"
//
// hexoct := hexdig hexdig
// 2hexoct := hexoct hexoct
// 4hexoct := 2hexoct 2hexoct
// 6hexoct := 4hexoct 2hexoct
// 12hexoct := 6hexoct 6hexoct
//
// hashlike := 12hexoct
// canonical := 4hexoct "-" 2hexoct "-" 2hexoct "-" 2hexoct "-" 6hexoct
//
// plain := canonical | hashlike
// braced := "{" plain "}"
// urn := URN ":" UUID-NID ":" plain
//
// uuid := canonical | hashlike | braced | urn
//
// The function delegates validation to internal parseBytes().
func (u *UUID) UnmarshalText(b []byte) error {
return parseBytes(b, u)
}
// MarshalBinary implements the encoding.BinaryMarshaler interface.
func (u UUID) MarshalBinary() ([]byte, error) {
return u.Bytes(), nil
}
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
// It will return an error if the slice isn't 16 bytes long.
func (u *UUID) UnmarshalBinary(data []byte) error {
if len(data) != Size {
return fmt.Errorf("%w, got %d bytes", ErrIncorrectByteLength, len(data))
}
copy(u[:], data)
return nil
}
================================================
FILE: vendor/github.com/gofrs/uuid/v5/error.go
================================================
package uuid
// Error is a custom error type for UUID-related errors
type Error string
// The strings defined in the errors is matching the previous behavior before
// the custom error type was implemented. The reason is that some people might
// be relying on the exact string representation to handle errors in their code.
const (
// ErrInvalidFormat is returned when the UUID string representation does not
// match the expected format. See also ErrIncorrectFormatInString.
ErrInvalidFormat = Error("uuid: invalid UUID format")
// ErrIncorrectFormatInString can be returned instead of ErrInvalidFormat.
// A separate error type is used because of how errors used to be formatted
// before custom error types were introduced.
ErrIncorrectFormatInString = Error("uuid: incorrect UUID format in string")
// ErrIncorrectLength is returned when the UUID does not have the
// appropriate string length for parsing the UUID.
ErrIncorrectLength = Error("uuid: incorrect UUID length")
// ErrIncorrectByteLength indicates the UUID byte slice length is invalid.
ErrIncorrectByteLength = Error("uuid: UUID must be exactly 16 bytes long")
// ErrNoHwAddressFound is returned when a hardware (MAC) address cannot be
// found for UUID generation.
ErrNoHwAddressFound = Error("uuid: no HW address found")
// ErrTypeConvertError is returned for type conversion operation fails.
ErrTypeConvertError = Error("uuid: cannot convert")
// ErrInvalidVersion indicates an unsupported or invalid UUID version.
ErrInvalidVersion = Error("uuid:")
)
// Error returns the string representation of the UUID error.
func (e Error) Error() string {
return string(e)
}
================================================
FILE: vendor/github.com/gofrs/uuid/v5/generator.go
================================================
// Copyright (C) 2013-2018 by Maxim Bublis
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package uuid
import (
"crypto/md5"
"crypto/rand"
"crypto/sha1"
"encoding/binary"
"io"
"net"
"sync"
"time"
)
// Difference in 100-nanosecond intervals between
// UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970).
const epochStart = 122192928000000000
// EpochFunc is the function type used to provide the current time.
type EpochFunc func() time.Time
// HWAddrFunc is the function type used to provide hardware (MAC) addresses.
type HWAddrFunc func() (net.HardwareAddr, error)
// DefaultGenerator is the default UUID Generator used by this package.
var DefaultGenerator Generator = NewGen()
// NewV1 returns a UUID based on the current timestamp and MAC address.
func NewV1() (UUID, error) {
return DefaultGenerator.NewV1()
}
// NewV1 returns a UUID based on the provided timestamp and MAC address.
func NewV1AtTime(atTime time.Time) (UUID, error) {
return DefaultGenerator.NewV1AtTime(atTime)
}
// NewV3 returns a UUID based on the MD5 hash of the namespace UUID and name.
func NewV3(ns UUID, name string) UUID {
return DefaultGenerator.NewV3(ns, name)
}
// NewV4 returns a randomly generated UUID.
func NewV4() (UUID, error) {
return DefaultGenerator.NewV4()
}
// NewV5 returns a UUID based on SHA-1 hash of the namespace UUID and name.
func NewV5(ns UUID, name string) UUID {
return DefaultGenerator.NewV5(ns, name)
}
// NewV6 returns a k-sortable UUID based on the current timestamp and 48 bits of
// pseudorandom data. The timestamp in a V6 UUID is the same as V1, with the bit
// order being adjusted to allow the UUID to be k-sortable.
func NewV6() (UUID, error) {
return DefaultGenerator.NewV6()
}
// NewV6 returns a k-sortable UUID based on the provided timestamp and 48 bits of
// pseudorandom data. The timestamp in a V6 UUID is the same as V1, with the bit
// order being adjusted to allow the UUID to be k-sortable.
func NewV6AtTime(atTime time.Time) (UUID, error) {
return DefaultGenerator.NewV6AtTime(atTime)
}
// NewV7 returns a k-sortable UUID based on the current millisecond-precision
// UNIX epoch and 74 bits of pseudorandom data. It supports single-node batch
// generation (multiple UUIDs in the same timestamp) with a Monotonic Random counter.
func NewV7() (UUID, error) {
return DefaultGenerator.NewV7()
}
// NewV7 returns a k-sortable UUID based on the provided millisecond-precision
// UNIX epoch and 74 bits of pseudorandom data. It supports single-node batch
// generation (multiple UUIDs in the same timestamp) with a Monotonic Random counter.
func NewV7AtTime(atTime time.Time) (UUID, error) {
return DefaultGenerator.NewV7AtTime(atTime)
}
// Generator provides an interface for generating UUIDs.
type Generator interface {
NewV1() (UUID, error)
NewV1AtTime(time.Time) (UUID, error)
NewV3(ns UUID, name string) UUID
NewV4() (UUID, error)
NewV5(ns UUID, name string) UUID
NewV6() (UUID, error)
NewV6AtTime(time.Time) (UUID, error)
NewV7() (UUID, error)
NewV7AtTime(time.Time) (UUID, error)
}
// Gen is a reference UUID generator based on the specifications laid out in
// RFC-9562 and DCE 1.1: Authentication and Security Services. This type
// satisfies the Generator interface as defined in this package.
//
// For consumers who are generating V1 UUIDs, but don't want to expose the MAC
// address of the node generating the UUIDs, the NewGenWithHWAF() function has been
// provided as a convenience. See the function's documentation for more info.
//
// The authors of this package do not feel that the majority of users will need
// to obfuscate their MAC address, and so we recommend using NewGen() to create
// a new generator.
type Gen struct {
clockSequenceOnce sync.Once
hardwareAddrOnce sync.Once
storageMutex sync.Mutex
rand io.Reader
epochFunc EpochFunc
hwAddrFunc HWAddrFunc
lastTime uint64
clockSequence uint16
hardwareAddr [6]byte
}
// GenOption is a function type that can be used to configure a Gen generator.
type GenOption func(*Gen)
// interface check -- build will fail if *Gen doesn't satisfy Generator
var _ Generator = (*Gen)(nil)
// NewGen returns a new instance of Gen with some default values set. Most
// people should use this.
func NewGen() *Gen {
return NewGenWithHWAF(defaultHWAddrFunc)
}
// NewGenWithHWAF builds a new UUID generator with the HWAddrFunc provided. Most
// consumers should use NewGen() instead.
//
// This is used so that consumers can generate their own MAC addresses, for use
// in the generated UUIDs, if there is some concern about exposing the physical
// address of the machine generating the UUID.
//
// The Gen generator will only invoke the HWAddrFunc once, and cache that MAC
// address for all the future UUIDs generated by it. If you'd like to switch the
// MAC address being used, you'll need to create a new generator using this
// function.
func NewGenWithHWAF(hwaf HWAddrFunc) *Gen {
return NewGenWithOptions(WithHWAddrFunc(hwaf))
}
// NewGenWithOptions returns a new instance of Gen with the options provided.
// Most people should use NewGen() or NewGenWithHWAF() instead.
//
// To customize the generator, you can pass in one or more GenOption functions.
// For example:
//
// gen := NewGenWithOptions(
// WithHWAddrFunc(myHWAddrFunc),
// WithEpochFunc(myEpochFunc),
// WithRandomReader(myRandomReader),
// )
//
// NewGenWithOptions(WithHWAddrFunc(myHWAddrFunc)) is equivalent to calling
// NewGenWithHWAF(myHWAddrFunc)
// NewGenWithOptions() is equivalent to calling NewGen()
func NewGenWithOptions(opts ...GenOption) *Gen {
gen := &Gen{
epochFunc: time.Now,
hwAddrFunc: defaultHWAddrFunc,
rand: rand.Reader,
}
for _, opt := range opts {
opt(gen)
}
return gen
}
// WithHWAddrFunc is a GenOption that allows you to provide your own HWAddrFunc
// function.
// When this option is nil, the defaultHWAddrFunc is used.
func WithHWAddrFunc(hwaf HWAddrFunc) GenOption {
return func(gen *Gen) {
if hwaf == nil {
hwaf = defaultHWAddrFunc
}
gen.hwAddrFunc = hwaf
}
}
// WithEpochFunc is a GenOption that allows you to provide your own EpochFunc
// function.
// When this option is nil, time.Now is used.
func WithEpochFunc(epochf EpochFunc) GenOption {
return func(gen *Gen) {
if epochf == nil {
epochf = time.Now
}
gen.epochFunc = epochf
}
}
// WithRandomReader is a GenOption that allows you to provide your own random
// reader.
// When this option is nil, the default rand.Reader is used.
func WithRandomReader(reader io.Reader) GenOption {
return func(gen *Gen) {
if reader == nil {
reader = rand.Reader
}
gen.rand = reader
}
}
// NewV1 returns a UUID based on the current timestamp and MAC address.
func (g *Gen) NewV1() (UUID, error) {
return g.NewV1AtTime(g.epochFunc())
}
// NewV1AtTime returns a UUID based on the provided timestamp and current MAC address.
func (g *Gen) NewV1AtTime(atTime time.Time) (UUID, error) {
u := UUID{}
timeNow, clockSeq, err := g.getClockSequence(false, atTime)
if err != nil {
return Nil, err
}
binary.BigEndian.PutUint32(u[0:], uint32(timeNow))
binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
binary.BigEndian.PutUint16(u[8:], clockSeq)
hardwareAddr, err := g.getHardwareAddr()
if err != nil {
return Nil, err
}
copy(u[10:], hardwareAddr)
u.SetVersion(V1)
u.SetVariant(VariantRFC9562)
return u, nil
}
// NewV3 returns a UUID based on the MD5 hash of the namespace UUID and name.
func (g *Gen) NewV3(ns UUID, name string) (u UUID) {
h := md5.New()
h.Write(ns[:])
h.Write([]byte(name))
copy(u[:], h.Sum(make([]byte, 0, md5.Size)))
u.SetVersion(V3)
u.SetVariant(VariantRFC9562)
return u
}
// NewV4 returns a randomly generated UUID.
func (g *Gen) NewV4() (UUID, error) {
u := UUID{}
if _, err := io.ReadFull(g.rand, u[:]); err != nil {
return Nil, err
}
u.SetVersion(V4)
u.SetVariant(VariantRFC9562)
return u, nil
}
// NewV5 returns a UUID based on SHA-1 hash of the namespace UUID and name.
func (g *Gen) NewV5(ns UUID, name string) (u UUID) {
h := sha1.New()
h.Write(ns[:])
h.Write([]byte(name))
copy(u[:], h.Sum(make([]byte, 0, sha1.Size)))
u.SetVersion(V5)
u.SetVariant(VariantRFC9562)
return u
}
// NewV6 returns a k-sortable UUID based on the current timestamp and 48 bits of
// pseudorandom data. The timestamp in a V6 UUID is the same as V1, with the bit
// order being adjusted to allow the UUID to be k-sortable.
func (g *Gen) NewV6() (UUID, error) {
return g.NewV6AtTime(g.epochFunc())
}
// NewV6 returns a k-sortable UUID based on the provided timestamp and 48 bits of
// pseudorandom data. The timestamp in a V6 UUID is the same as V1, with the bit
// order being adjusted to allow the UUID to be k-sortable.
func (g *Gen) NewV6AtTime(atTime time.Time) (UUID, error) {
/* https://datatracker.ietf.org/doc/html/rfc9562#name-uuid-version-6
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time_high |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time_mid | ver | time_low |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| clock_seq | node |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| node |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
var u UUID
timeNow, _, err := g.getClockSequence(false, atTime)
if err != nil {
return Nil, err
}
binary.BigEndian.PutUint32(u[0:], uint32(timeNow>>28)) // set time_high
binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>12)) // set time_mid
binary.BigEndian.PutUint16(u[6:], uint16(timeNow&0xfff)) // set time_low (minus four version bits)
// Based on the RFC 9562 recommendation that this data be fully random and not a monotonic counter,
//we do NOT support batching version 6 UUIDs.
//set clock_seq (14 bits) and node (48 bits) pseudo-random bits (first 2 bits will be overridden)
if _, err = io.ReadFull(g.rand, u[8:]); err != nil {
return Nil, err
}
u.SetVersion(V6)
//overwrite first 2 bits of byte[8] for the variant
u.SetVariant(VariantRFC9562)
return u, nil
}
// NewV7 returns a k-sortable UUID based on the current millisecond-precision
// UNIX epoch and 74 bits of pseudorandom data.
func (g *Gen) NewV7() (UUID, error) {
return g.NewV7AtTime(g.epochFunc())
}
// NewV7 returns a k-sortable UUID based on the provided millisecond-precision
// UNIX epoch and 74 bits of pseudorandom data.
func (g *Gen) NewV7AtTime(atTime time.Time) (UUID, error) {
var u UUID
/* https://datatracker.ietf.org/doc/html/rfc9562#name-uuid-version-7
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms | ver | rand_a |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| rand_b |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| rand_b |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
ms, clockSeq, err := g.getClockSequence(true, atTime)
if err != nil {
return Nil, err
}
//UUIDv7 features a 48 bit timestamp. First 32bit (4bytes) represents seconds since 1970, followed by 2 bytes for the ms granularity.
u[0] = byte(ms >> 40) //1-6 bytes: big-endian unsigned number of Unix epoch timestamp
u[1] = byte(ms >> 32)
u[2] = byte(ms >> 24)
u[3] = byte(ms >> 16)
u[4] = byte(ms >> 8)
u[5] = byte(ms)
//Support batching by using a monotonic pseudo-random sequence,
//as described in RFC 9562 section 6.2, Method 1.
//The 6th byte contains the version and partially rand_a data.
//We will lose the most significant bites from the clockSeq (with SetVersion), but it is ok,
//we need the least significant that contains the counter to ensure the monotonic property
binary.BigEndian.PutUint16(u[6:8], clockSeq) // set rand_a with clock seq which is random and monotonic
//override first 4bits of u[6].
u.SetVersion(V7)
//set rand_b 64bits of pseudo-random bits (first 2 will be overridden)
if _, err = io.ReadFull(g.rand, u[8:16]); err != nil {
return Nil, err
}
//override first 2 bits of byte[8] for the variant
u.SetVariant(VariantRFC9562)
return u, nil
}
// getClockSequence returns the epoch and clock sequence of the provided time,
// used for generating V1,V6 and V7 UUIDs.
//
// When useUnixTSMs is false, it uses the Coordinated Universal Time (UTC) as a count of
// 100-nanosecond intervals since 00:00:00.00, 15 October 1582 (the date of Gregorian
// reform to the Christian calendar).
func (g *Gen) getClockSequence(useUnixTSMs bool, atTime time.Time) (uint64, uint16, error) {
var err error
g.clockSequenceOnce.Do(func() {
buf := make([]byte, 2)
if _, err = io.ReadFull(g.rand, buf); err != nil {
return
}
g.clockSequence = binary.BigEndian.Uint16(buf)
})
if err != nil {
return 0, 0, err
}
g.storageMutex.Lock()
defer g.storageMutex.Unlock()
var timeNow uint64
if useUnixTSMs {
timeNow = uint64(atTime.UnixMilli())
} else {
timeNow = g.getEpoch(atTime)
}
// Clock didn't change since last UUID generation.
// Should increase clock sequence.
if timeNow <= g.lastTime {
g.clockSequence++
}
g.lastTime = timeNow
return timeNow, g.clockSequence, nil
}
// Returns the hardware address.
func (g *Gen) getHardwareAddr() ([]byte, error) {
var err error
g.hardwareAddrOnce.Do(func() {
var hwAddr net.HardwareAddr
if hwAddr, err = g.hwAddrFunc(); err == nil {
copy(g.hardwareAddr[:], hwAddr)
return
}
// Initialize hardwareAddr randomly in case
// of real network interfaces absence.
if _, err = io.ReadFull(g.rand, g.hardwareAddr[:]); err != nil {
return
}
// Set multicast bit as recommended by RFC-9562
g.hardwareAddr[0] |= 0x01
})
if err != nil {
return []byte{}, err
}
return g.hardwareAddr[:], nil
}
// Returns the difference between UUID epoch (October 15, 1582)
// and the provided time in 100-nanosecond intervals.
func (g *Gen) getEpoch(atTime time.Time) uint64 {
return epochStart + uint64(atTime.UnixNano()/100)
}
var netInterfaces = net.Interfaces
// Returns the hardware address.
func defaultHWAddrFunc() (net.HardwareAddr, error) {
ifaces, err := netInterfaces()
if err != nil {
return []byte{}, err
}
for _, iface := range ifaces {
if len(iface.HardwareAddr) >= 6 {
return iface.HardwareAddr, nil
}
}
return []byte{}, ErrNoHwAddressFound
}
================================================
FILE: vendor/github.com/gofrs/uuid/v5/sql.go
================================================
// Copyright (C) 2013-2018 by Maxim Bublis
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package uuid
import (
"database/sql"
"database/sql/driver"
"fmt"
)
var _ driver.Valuer = UUID{}
var _ sql.Scanner = (*UUID)(nil)
// Value implements the driver.Valuer interface.
func (u UUID) Value() (driver.Value, error) {
return u.String(), nil
}
// Scan implements the sql.Scanner interface.
// A 16-byte slice will be handled by UnmarshalBinary, while
// a longer byte slice or a string will be handled by UnmarshalText.
func (u *UUID) Scan(src interface{}) error {
switch src := src.(type) {
case UUID: // support gorm convert from UUID to NullUUID
*u = src
return nil
case []byte:
if len(src) == Size {
return u.UnmarshalBinary(src)
}
return u.UnmarshalText(src)
case string:
uu, err := FromString(src)
*u = uu
return err
}
return fmt.Errorf("%w %T to UUID", ErrTypeConvertError, src)
}
// NullUUID can be used with the standard sql package to represent a
// UUID value that can be NULL in the database.
type NullUUID struct {
UUID UUID
Valid bool
}
// Value implements the driver.Valuer interface.
func (u NullUUID) Value() (driver.Value, error) {
if !u.Valid {
return nil, nil
}
// Delegate to UUID Value function
return u.UUID.Value()
}
// Scan implements the sql.Scanner interface.
func (u *NullUUID) Scan(src interface{}) error {
if src == nil {
u.UUID, u.Valid = Nil, false
return nil
}
// Delegate to UUID Scan function
u.Valid = true
return u.UUID.Scan(src)
}
var nullJSON = []byte("null")
// MarshalJSON marshals the NullUUID as null or the nested UUID
func (u NullUUID) MarshalJSON() ([]byte, error) {
if !u.Valid {
return nullJSON, nil
}
var buf [38]byte
buf[0] = '"'
encodeCanonical(buf[1:37], u.UUID)
buf[37] = '"'
return buf[:], nil
}
// UnmarshalJSON unmarshals a NullUUID
func (u *NullUUID) UnmarshalJSON(b []byte) error {
if string(b) == "null" {
u.UUID, u.Valid = Nil, false
return nil
}
if n := len(b); n >= 2 && b[0] == '"' {
b = b[1 : n-1]
}
err := u.UUID.UnmarshalText(b)
u.Valid = (err == nil)
return err
}
================================================
FILE: vendor/github.com/gofrs/uuid/v5/uuid.go
================================================
// Copyright (C) 2013-2018 by Maxim Bublis
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// Package uuid provides implementations of the Universally Unique Identifier
// (UUID), as specified in RFC-9562 (formerly RFC-4122).
//
// RFC-9562[1] provides the specification for versions 1, 3, 4, 5, 6 and 7.
//
// DCE 1.1[2] provides the specification for version 2, but version 2 support
// was removed from this package in v4 due to some concerns with the
// specification itself. Reading the spec, it seems that it would result in
// generating UUIDs that aren't very unique. In having read the spec it seemed
// that our implementation did not meet the spec. It also seems to be at-odds
// with RFC 9562, meaning we would need quite a bit of special code to support
// it. Lastly, there were no Version 2 implementations that we could find to
// ensure we were understanding the specification correctly.
//
// [1] https://tools.ietf.org/html/rfc9562
// [2] http://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01
package uuid
import (
"encoding/binary"
"encoding/hex"
"fmt"
"time"
)
// Size of a UUID in bytes.
const Size = 16
// UUID is an array type to represent the value of a UUID, as defined in RFC-9562.
type UUID [Size]byte
// UUID versions.
const (
_ byte = iota
V1 // Version 1 (date-time and MAC address)
_ // Version 2 (date-time and MAC address, DCE security version) [removed]
V3 // Version 3 (namespace name-based)
V4 // Version 4 (random)
V5 // Version 5 (namespace name-based)
V6 // Version 6 (k-sortable timestamp and random data, field-compatible with v1)
V7 // Version 7 (k-sortable timestamp and random data)
_ // Version 8 (k-sortable timestamp, meant for custom implementations) [not implemented]
)
// UUID layout variants.
const (
VariantNCS byte = iota
VariantRFC9562
VariantMicrosoft
VariantFuture
)
// Backward-compatible variant for RFC 4122
const VariantRFC4122 = VariantRFC9562
// UUID DCE domains.
const (
DomainPerson = iota
DomainGroup
DomainOrg
)
// Timestamp is the count of 100-nanosecond intervals since 00:00:00.00,
// 15 October 1582 within a V1 or V6 UUID, or as a common intermediate
// representation of the (Unix Millisecond) timestamp within a V7 UUID.
// This type has no meaning for other UUID versions since they don't
// have an embedded timestamp.
type Timestamp uint64
const _100nsPerSecond = 10000000
// Time returns the time.Time representation of a Timestamp.
//
// The resulting time.Time:
// - Contains only wall clock time (no monotonic clock component)
// - Uses the local system timezone for the location
func (t Timestamp) Time() (time.Time, error) {
secs := uint64(t) / _100nsPerSecond
nsecs := 100 * (uint64(t) % _100nsPerSecond)
return time.Unix(int64(secs)-(epochStart/_100nsPerSecond), int64(nsecs)), nil
}
// TimestampFromV1 returns the Timestamp embedded within a V1 UUID.
// Returns an error if the UUID is any version other than 1.
func TimestampFromV1(u UUID) (Timestamp, error) {
if u.Version() != 1 {
err := fmt.Errorf("%w %s is version %d, not version 1", ErrInvalidVersion, u, u.Version())
return 0, err
}
low := binary.BigEndian.Uint32(u[0:4])
mid := binary.BigEndian.Uint16(u[4:6])
hi := binary.BigEndian.Uint16(u[6:8]) & 0xfff
return Timestamp(uint64(low) + (uint64(mid) << 32) + (uint64(hi) << 48)), nil
}
// TimestampFromV6 returns the Timestamp embedded within a V6 UUID. This
// function returns an error if the UUID is any version other than 6.
func TimestampFromV6(u UUID) (Timestamp, error) {
if u.Version() != 6 {
return 0, fmt.Errorf("%w %s is version %d, not version 6", ErrInvalidVersion, u, u.Version())
}
hi := binary.BigEndian.Uint32(u[0:4])
mid := binary.BigEndian.Uint16(u[4:6])
low := binary.BigEndian.Uint16(u[6:8]) & 0xfff
return Timestamp(uint64(low) + (uint64(mid) << 12) + (uint64(hi) << 28)), nil
}
// TimestampFromV7 returns the Timestamp embedded within a V7 UUID. This
// function returns an error if the UUID is any version other than 7.
func TimestampFromV7(u UUID) (Timestamp, error) {
if u.Version() != 7 {
return 0, fmt.Errorf("%w %s is version %d, not version 7", ErrInvalidVersion, u, u.Version())
}
t := 0 |
(int64(u[0]) << 40) |
(int64(u[1]) << 32) |
(int64(u[2]) << 24) |
(int64(u[3]) << 16) |
(int64(u[4]) << 8) |
int64(u[5])
// UUIDv7 stores MS since 1970-01-01 00:00:00, but the Timestamp
// type stores 100-nanosecond increments since 1582-10-15 00:00:00.
// This conversion multiplies ms by 10,000 to get 100-ns chunks and adds
// the difference between October 1582 and January 1970.
tsNanos := epochStart + (t * 10000)
return Timestamp(tsNanos), nil
}
// Nil is the nil UUID, as specified in RFC-9562, that has all 128 bits set to
// zero.
var Nil = UUID{}
// Max is the maximum UUID, as specified in RFC-9562, that has all 128 bits
// set to one.
var Max = UUID{
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
}
// Predefined namespace UUIDs.
var (
NamespaceDNS = Must(FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8"))
NamespaceURL = Must(FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8"))
NamespaceOID = Must(FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8"))
NamespaceX500 = Must(FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8"))
)
// IsNil returns if the UUID is equal to the nil UUID
func (u UUID) IsNil() bool {
return u == Nil
}
// IsZero returns if the UUID is equal to the zero UUID (same as IsNil).
// This method is provided to satisfy the bsoncodec.Zeroer interface for MongoDB
// omitzero tag support. See: https://github.com/gofrs/uuid/issues/224
func (u UUID) IsZero() bool {
return u == Nil
}
// Version returns the algorithm version used to generate the UUID.
func (u UUID) Version() byte {
return u[6] >> 4
}
// Variant returns the UUID layout variant.
func (u UUID) Variant() byte {
switch {
case (u[8] >> 7) == 0x00:
return VariantNCS
case (u[8] >> 6) == 0x02:
return VariantRFC9562
case (u[8] >> 5) == 0x06:
return VariantMicrosoft
case (u[8] >> 5) == 0x07:
fallthrough
default:
return VariantFuture
}
}
// Bytes returns a byte slice representation of the UUID.
func (u UUID) Bytes() []byte {
return u[:]
}
// encodeCanonical encodes the canonical RFC-9562 form of UUID u into the
// first 36 bytes dst.
func encodeCanonical(dst []byte, u UUID) {
const hextable = "0123456789abcdef"
dst[8] = '-'
dst[13] = '-'
dst[18] = '-'
dst[23] = '-'
for i, x := range [16]byte{
0, 2, 4, 6,
9, 11,
14, 16,
19, 21,
24, 26, 28, 30, 32, 34,
} {
c := u[i]
dst[x] = hextable[c>>4]
dst[x+1] = hextable[c&0x0f]
}
}
// String returns a canonical RFC-9562 string representation of the UUID:
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
func (u UUID) String() string {
var buf [36]byte
encodeCanonical(buf[:], u)
return string(buf[:])
}
// Format implements fmt.Formatter for UUID values.
//
// The behavior is as follows:
// The 'x' and 'X' verbs output only the hex digits of the UUID, using a-f for 'x' and A-F for 'X'.
// The 'v', '+v', 's' and 'q' verbs return the canonical RFC-9562 string representation.
// The 'S' verb returns the RFC-9562 format, but with capital hex digits.
// The '#v' verb returns the "Go syntax" representation, which is a 16 byte array initializer.
// All other verbs not handled directly by the fmt package (like '%p') are unsupported and will return
// "%!verb(uuid.UUID=value)" as recommended by the fmt package.
func (u UUID) Format(f fmt.State, c rune) {
if c == 'v' && f.Flag('#') {
fmt.Fprintf(f, "%#v", [Size]byte(u))
return
}
switch c {
case 'x', 'X':
b := make([]byte, 32)
hex.Encode(b, u[:])
if c == 'X' {
toUpperHex(b)
}
_, _ = f.Write(b)
case 'v', 's', 'S':
b, _ := u.MarshalText()
if c == 'S' {
toUpperHex(b)
}
_, _ = f.Write(b)
case 'q':
b := make([]byte, 38)
b[0] = '"'
encodeCanonical(b[1:], u)
b[37] = '"'
_, _ = f.Write(b)
default:
// invalid/unsupported format verb
fmt.Fprintf(f, "%%!%c(uuid.UUID=%s)", c, u.String())
}
}
func toUpperHex(b []byte) {
for i, c := range b {
if 'a' <= c && c <= 'f' {
b[i] = c - ('a' - 'A')
}
}
}
// SetVersion sets the version bits.
func (u *UUID) SetVersion(v byte) {
u[6] = (u[6] & 0x0f) | (v << 4)
}
// SetVariant sets the variant bits.
func (u *UUID) SetVariant(v byte) {
switch v {
case VariantNCS:
u[8] = (u[8]&(0xff>>1) | (0x00 << 7))
case VariantRFC9562:
u[8] = (u[8]&(0xff>>2) | (0x02 << 6))
case VariantMicrosoft:
u[8] = (u[8]&(0xff>>3) | (0x06 << 5))
case VariantFuture:
fallthrough
default:
u[8] = (u[8]&(0xff>>3) | (0x07 << 5))
}
}
// Must is a helper that wraps a call to a function returning (UUID, error)
// and panics if the error is non-nil. It is intended for use in variable
// initializations such as
//
// var packageUUID = uuid.Must(uuid.FromString("123e4567-e89b-12d3-a456-426655440000"))
func Must(u UUID, err error) UUID {
if err != nil {
panic(err)
}
return u
}
================================================
FILE: vendor/github.com/inconshreveable/log15/v3/LICENSE
================================================
Copyright 2014 Alan Shreve
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: vendor/github.com/inconshreveable/log15/v3/doc.go
================================================
/*
Package log15 provides an opinionated, simple toolkit for best-practice logging that is
both human and machine readable. It is modeled after the standard library's io and net/http
packages.
This package enforces you to only log key/value pairs. Keys must be strings. Values may be
any type that you like. The default output format is logfmt, but you may also choose to use
JSON instead if that suits you. Here's how you log:
log.Info("page accessed", "path", r.URL.Path, "user_id", user.id)
This will output a line that looks like:
lvl=info t=2014-05-02T16:07:23-0700 msg="page accessed" path=/org/71/profile user_id=9
# Getting Started
To get started, you'll want to import the library:
import log "github.com/inconshreveable/log15/v3"
Now you're ready to start logging:
func main() {
log.Info("Program starting", "args", os.Args)
}
# Convention
Because recording a human-meaningful message is common and good practice, the first argument to every
logging method is the value to the *implicit* key 'msg'.
Additionally, the level you choose for a message will be automatically added with the key 'lvl', and so
will the current timestamp with key 't'.
You may supply any additional context as a set of key/value pairs to the logging function. log15 allows
you to favor terseness, ordering, and speed over safety. This is a reasonable tradeoff for
logging functions. You don't need to explicitly state keys/values, log15 understands that they alternate
in the variadic argument list:
log.Warn("size out of bounds", "low", lowBound, "high", highBound, "val", val)
If you really do favor your type-safety, you may choose to pass a log.Ctx instead:
log.Warn("size out of bounds", log.Ctx{"low": lowBound, "high": highBound, "val": val})
# Context loggers
Frequently, you want to add context to a logger so that you can track actions associated with it. An http
request is a good example. You can easily create new loggers that have context that is automatically included
with each log line:
requestlogger := log.New("path", r.URL.Path)
// later
requestlogger.Debug("db txn commit", "duration", txnTimer.Finish())
This will output a log line that includes the path context that is attached to the logger:
lvl=dbug t=2014-05-02T16:07:23-0700 path=/repo/12/add_hook msg="db txn commit" duration=0.12
# Handlers
The Handler interface defines where log lines are printed to and how they are formatted. Handler is a
single interface that is inspired by net/http's handler interface:
type Handler interface {
Log(r *Record) error
}
Handlers can filter records, format them, or dispatch to multiple other Handlers.
This package implements a number of Handlers for common logging patterns that are
easily composed to create flexible, custom logging structures.
Here's an example handler that prints logfmt output to Stdout:
handler := log.StreamHandler(os.Stdout, log.LogfmtFormat())
Here's an example handler that defers to two other handlers. One handler only prints records
from the rpc package in logfmt to standard out. The other prints records at Error level
or above in JSON formatted output to the file /var/log/service.json
handler := log.MultiHandler(
log.LvlFilterHandler(log.LvlError, log.Must.FileHandler("/var/log/service.json", log.JsonFormat())),
log.MatchFilterHandler("pkg", "app/rpc" log.StdoutHandler())
)
# Custom Handlers
The Handler interface is so simple that it's also trivial to write your own. Let's create an
example handler which tries to write to one handler, but if that fails it falls back to
writing to another handler and includes the error that it encountered when trying to write
to the primary. This might be useful when trying to log over a network socket, but if that
fails you want to log those records to a file on disk.
type BackupHandler struct {
Primary Handler
Secondary Handler
}
func (h *BackupHandler) Log (r *Record) error {
err := h.Primary.Log(r)
if err != nil {
r.Ctx = append(ctx, "primary_err", err)
return h.Secondary.Log(r)
}
return nil
}
This pattern is so useful that a generic version that handles an arbitrary number of Handlers
is included as part of this library called FailoverHandler.
# Logging Expensive Operations
Sometimes, you want to log values that are extremely expensive to compute, but you don't want to pay
the price of computing them if you haven't turned up your logging level to a high level of detail.
This package provides a simple type to annotate a logging operation that you want to be evaluated
lazily, just when it is about to be logged, so that it would not be evaluated if an upstream Handler
filters it out. Just wrap any function which takes no arguments with the log.Lazy type. For example:
func factorRSAKey() (factors []int) {
// return the factors of a very large number
}
log.Debug("factors", log.Lazy{factorRSAKey})
If this message is not logged for any reason (like logging at the Error level), then
factorRSAKey is never evaluated.
# Dynamic context values
The same log.Lazy mechanism can be used to attach context to a logger which you want to be
evaluated when the message is logged, but not when the logger is created. For example, let's imagine
a game where you have Player objects:
type Player struct {
name string
alive bool
log.Logger
}
You always want to log a player's name and whether they're alive or dead, so when you create the player
object, you might do:
p := &Player{name: name, alive: true}
p.Logger = log.New("name", p.name, "alive", p.alive)
Only now, even after a player has died, the logger will still report they are alive because the logging
context is evaluated when the logger was created. By using the Lazy wrapper, we can defer the evaluation
of whether the player is alive or not to each log message, so that the log records will reflect the player's
current state no matter when the log message is written:
p := &Player{name: name, alive: true}
isAlive := func() bool { return p.alive }
player.Logger = log.New("name", p.name, "alive", log.Lazy{isAlive})
# Terminal Format
If log15 detects that stdout is a terminal, it will configure the default
handler for it (which is log.StdoutHandler) to use TerminalFormat. This format
logs records nicely for your terminal, including color-coded output based
on log level.
# Error Handling
Becasuse log15 allows you to step around the type system, there are a few ways you can specify
invalid arguments to the logging functions. You could, for example, wrap something that is not
a zero-argument function with log.Lazy or pass a context key that is not a string. Since logging libraries
are typically the mechanism by which errors are reported, it would be onerous for the logging functions
to return errors. Instead, log15 handles errors by making these guarantees to you:
- Any log record containing an error will still be printed with the error explained to you as part of the log record.
- Any log record containing an error will include the context key LOG15_ERROR, enabling you to easily
(and if you like, automatically) detect if any of your logging calls are passing bad values.
Understanding this, you might wonder why the Handler interface can return an error value in its Log method. Handlers
are encouraged to return errors only if they fail to write their log records out to an external source like if the
syslog daemon is not responding. This allows the construction of useful handlers which cope with those failures
like the FailoverHandler.
# Library Use
log15 is intended to be useful for library authors as a way to provide configurable logging to
users of their library. Best practice for use in a library is to always disable all output for your logger
by default and to provide a public Logger instance that consumers of your library can configure. Like so:
package yourlib
import "github.com/inconshreveable/log15/v3"
var Log = log.New()
func init() {
Log.SetHandler(log.DiscardHandler())
}
Users of your library may then enable it if they like:
import "github.com/inconshreveable/log15/v3"
import "example.com/yourlib"
func main() {
handler := // custom handler setup
yourlib.Log.SetHandler(handler)
}
# Best practices attaching logger context
The ability to attach context to a logger is a powerful one. Where should you do it and why?
I favor embedding a Logger directly into any persistent object in my application and adding
unique, tracing context keys to it. For instance, imagine I am writing a web browser:
type Tab struct {
url string
render *RenderingContext
// ...
Logger
}
func NewTab(url string) *Tab {
return &Tab {
// ...
url: url,
Logger: log.New("url", url),
}
}
When a new tab is created, I assign a logger to it with the url of
the tab as context so it can easily be traced through the logs.
Now, whenever we perform any operation with the tab, we'll log with its
embedded logger and it will include the tab title automatically:
tab.Debug("moved position", "idx", tab.idx)
There's only one problem. What if the tab url changes? We could
use log.Lazy to make sure the current url is always written, but that
would mean that we couldn't trace a tab's full lifetime through our
logs after the user navigate to a new URL.
Instead, think about what values to attach to your loggers the
same way you think about what to use as a key in a SQL database schema.
If it's possible to use a natural key that is unique for the lifetime of the
object, do so. But otherwise, log15's ext package has a handy RandId
function to let you generate what you might call "surrogate keys"
They're just random hex identifiers to use for tracing. Back to our
Tab example, we would prefer to set up our Logger like so:
import logext "github.com/inconshreveable/log15/v3/ext"
t := &Tab {
// ...
url: url,
}
t.Logger = log.New("id", logext.RandId(8), "url", log.Lazy{t.getUrl})
return t
Now we'll have a unique traceable identifier even across loading new urls, but
we'll still be able to see the tab's current url in the log messages.
# Must
For all Handler functions which can return an error, there is a version of that
function which will return no error but panics on failure. They are all available
on the Must object. For example:
log.Must.FileHandler("/path", log.JsonFormat)
log.Must.NetHandler("tcp", ":1234", log.JsonFormat)
# Inspiration and Credit
All of the following excellent projects inspired the design of this library:
code.google.com/p/log4go
github.com/op/go-logging
github.com/technoweenie/grohl
github.com/Sirupsen/logrus
github.com/kr/logfmt
github.com/spacemonkeygo/spacelog
golang's stdlib, notably io and net/http
# The Name
https://xkcd.com/927/
*/
package log15
================================================
FILE: vendor/github.com/inconshreveable/log15/v3/format.go
================================================
package log15
import (
"bytes"
"encoding/json"
"fmt"
"reflect"
"strconv"
"strings"
"sync"
"time"
)
const (
timeFormat = "2006-01-02T15:04:05-0700"
termTimeFormat = "01-02|15:04:05"
floatFormat = 'f'
termMsgJust = 40
)
// Format is the interface implemented by StreamHandler formatters.
type Format interface {
Format(r Record) []byte
}
// FormatFunc returns a new Format object which uses
// the given function to perform record formatting.
func FormatFunc(f func(Record) []byte) Format {
return formatFunc(f)
}
type formatFunc func(Record) []byte
func (f formatFunc) Format(r Record) []byte {
return f(r)
}
// TerminalFormat formats log records optimized for human readability on
// a terminal with color-coded level output and terser human friendly timestamp.
// This format should only be used for interactive programs or while developing.
//
// [TIME] [LEVEL] MESSAGE key=value key=value ...
//
// Example:
//
// [May 16 20:58:45] [DBUG] remove route ns=haproxy addr=127.0.0.1:50002
func TerminalFormat() Format {
return FormatFunc(func(r Record) []byte {
var color = 0
switch r.Lvl {
case LvlCrit:
color = 35
case LvlError:
color = 31
case LvlWarn:
color = 33
case LvlInfo:
color = 32
case LvlDebug:
color = 36
}
b := &bytes.Buffer{}
lvl := strings.ToUpper(r.Lvl.String())
if color > 0 {
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %s ", color, lvl, r.Time.Format(termTimeFormat), r.Msg)
} else {
fmt.Fprintf(b, "[%s] [%s] %s ", lvl, r.Time.Format(termTimeFormat), r.Msg)
}
// try to justify the log output for short messages
if len(r.Ctx) > 0 && len(r.Msg) < termMsgJust {
b.Write(bytes.Repeat([]byte{' '}, termMsgJust-len(r.Msg)))
}
// print the keys logfmt style
logfmt(b, r.Ctx, color)
return b.Bytes()
})
}
// LogfmtFormat prints records in logfmt format, an easy machine-parseable but human-readable
// format for key/value pairs.
//
// For more details see: http://godoc.org/github.com/kr/logfmt
func LogfmtFormat() Format {
return FormatFunc(func(r Record) []byte {
common := []interface{}{r.KeyNames.Time, r.Time, r.KeyNames.Lvl, r.Lvl, r.KeyNames.Msg, r.Msg}
buf := &bytes.Buffer{}
logfmt(buf, append(common, r.Ctx...), 0)
return buf.Bytes()
})
}
func logfmt(buf *bytes.Buffer, ctx []interface{}, color int) {
for i := 0; i < len(ctx); i += 2 {
if i != 0 {
buf.WriteByte(' ')
}
k, ok := ctx[i].(string)
v := formatLogfmtValue(ctx[i+1])
if !ok {
k, v = errorKey, formatLogfmtValue(k)
}
// XXX: we should probably check that all of your key bytes aren't invalid
if color > 0 {
fmt.Fprintf(buf, "\x1b[%dm%s\x1b[0m=%s", color, k, v)
} else {
buf.WriteString(k)
buf.WriteByte('=')
buf.WriteString(v)
}
}
buf.WriteByte('\n')
}
// JsonFormat formats log records as JSON objects separated by newlines.
// It is the equivalent of JsonFormatEx(false, true).
func JsonFormat() Format {
return JsonFormatEx(false, true)
}
// JsonFormatEx formats log records as JSON objects. If pretty is true,
// records will be pretty-printed. If lineSeparated is true, records
// will be logged with a new line between each record.
func JsonFormatEx(pretty, lineSeparated bool) Format {
jsonMarshal := json.Marshal
if pretty {
jsonMarshal = func(v interface{}) ([]byte, error) {
return json.MarshalIndent(v, "", " ")
}
}
return FormatFunc(func(r Record) []byte {
props := make(map[string]interface{})
props[r.KeyNames.Time] = r.Time
props[r.KeyNames.Lvl] = r.Lvl.String()
props[r.KeyNames.Msg] = r.Msg
for i := 0; i < len(r.Ctx); i += 2 {
k, ok := r.Ctx[i].(string)
if !ok {
props[errorKey] = fmt.Sprintf("%+v is not a string key", r.Ctx[i])
}
props[k] = formatJSONValue(r.Ctx[i+1])
}
b, err := jsonMarshal(props)
if err != nil {
b, _ = jsonMarshal(map[string]string{
errorKey: err.Error(),
})
return b
}
if lineSeparated {
b = append(b, '\n')
}
return b
})
}
func formatShared(value interface{}) (result interface{}) {
defer func() {
if err := recover(); err != nil {
if v := reflect.ValueOf(value); v.Kind() == reflect.Ptr && v.IsNil() {
result = "nil"
} else {
panic(err)
}
}
}()
switch v := value.(type) {
case time.Time:
return v.Format(timeFormat)
case error:
return v.Error()
case fmt.Stringer:
return v.String()
default:
return v
}
}
func formatJSONValue(value interface{}) interface{} {
value = formatShared(value)
switch value.(type) {
case int, int8, int16, int32, int64, float32, float64, uint, uint8, uint16, uint32, uint64, string:
return value
case interface{}, map[string]interface{}, []interface{}:
return value
default:
return fmt.Sprintf("%+v", value)
}
}
// formatValue formats a value for serialization
func formatLogfmtValue(value interface{}) string {
if value == nil {
return "nil"
}
if t, ok := value.(time.Time); ok {
// Performance optimization: No need for escaping since the provided
// timeFormat doesn't have any escape characters, and escaping is
// expensive.
return t.Format(timeFormat)
}
value = formatShared(value)
switch v := value.(type) {
case bool:
return strconv.FormatBool(v)
case float32:
return strconv.FormatFloat(float64(v), floatFormat, 3, 64)
case float64:
return strconv.FormatFloat(v, floatFormat, 3, 64)
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
return fmt.Sprintf("%d", value)
case string:
return escapeString(v)
default:
return escapeString(fmt.Sprintf("%+v", value))
}
}
var stringBufPool = sync.Pool{
New: func() interface{} { return new(bytes.Buffer) },
}
func escapeString(s string) string {
needsQuotes := false
needsEscape := false
for _, r := range s {
if r <= ' ' || r == '=' || r == '"' {
needsQuotes = true
}
if r == '\\' || r == '"' || r == '\n' || r == '\r' || r == '\t' {
needsEscape = true
}
}
if needsEscape == false && needsQuotes == false {
return s
}
e := stringBufPool.Get().(*bytes.Buffer)
e.WriteByte('"')
for _, r := range s {
switch r {
case '\\', '"':
e.WriteByte('\\')
e.WriteByte(byte(r))
case '\n':
e.WriteString("\\n")
case '\r':
e.WriteString("\\r")
case '\t':
e.WriteString("\\t")
default:
e.WriteRune(r)
}
}
e.WriteByte('"')
var ret string
if needsQuotes {
ret = e.String()
} else {
ret = string(e.Bytes()[1 : e.Len()-1])
}
e.Reset()
stringBufPool.Put(e)
return ret
}
================================================
FILE: vendor/github.com/inconshreveable/log15/v3/handler.go
================================================
package log15
import (
"fmt"
"io"
"net"
"os"
"reflect"
"sync"
)
// Handler interface defines where and how log records are written.
// A logger prints its log records by writing to a Handler.
// Handlers are composable, providing you great flexibility in combining
// them to achieve the logging structure that suits your applications.
type Handler interface {
Log(r Record) error
}
// FuncHandler returns a Handler that logs records with the given
// function.
func FuncHandler(fn func(r Record) error) Handler {
return funcHandler(fn)
}
type funcHandler func(r Record) error
func (h funcHandler) Log(r Record) error {
return h(r)
}
// StreamHandler writes log records to an io.Writer
// with the given format. StreamHandler can be used
// to easily begin writing log records to other
// outputs.
//
// StreamHandler wraps itself with LazyHandler and SyncHandler
// to evaluate Lazy objects and perform safe concurrent writes.
func StreamHandler(wr io.Writer, fmtr Format) Handler {
h := FuncHandler(func(r Record) error {
_, err := wr.Write(fmtr.Format(r))
return err
})
return LazyHandler(SyncHandler(h))
}
// SyncHandler can be wrapped around a handler to guarantee that
// only a single Log operation can proceed at a time. It's necessary
// for thread-safe concurrent writes.
func SyncHandler(h Handler) Handler {
var mu sync.Mutex
return FuncHandler(func(r Record) error {
defer mu.Unlock()
mu.Lock()
return h.Log(r)
})
}
// FileHandler returns a handler which writes log records to the give file
// using the given format. If the path
// already exists, FileHandler will append to the given file. If it does not,
// FileHandler will create the file with mode 0644.
func FileHandler(path string, fmtr Format) (Handler, error) {
f, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return nil, err
}
return closingHandler{f, StreamHandler(f, fmtr)}, nil
}
// NetHandler opens a socket to the given address and writes records
// over the connection.
func NetHandler(network, addr string, fmtr Format) (Handler, error) {
conn, err := net.Dial(network, addr)
if err != nil {
return nil, err
}
return closingHandler{conn, StreamHandler(conn, fmtr)}, nil
}
// XXX: closingHandler is essentially unused at the moment
// it's meant for a future time when the Handler interface supports
// a possible Close() operation
type closingHandler struct {
io.WriteCloser
Handler
}
func (h *closingHandler) Close() error {
return h.WriteCloser.Close()
}
// FilterHandler returns a Handler that only writes records to the
// wrapped Handler if the given function evaluates true. For example,
// to only log records where the 'err' key is not nil:
//
// logger.SetHandler(FilterHandler(func(r *Record) bool {
// for i := 0; i < len(r.Ctx); i += 2 {
// if r.Ctx[i] == "err" {
// return r.Ctx[i+1] != nil
// }
// }
// return false
// }, h))
func FilterHandler(fn func(r Record) bool, h Handler) Handler {
return FuncHandler(func(r Record) error {
if fn(r) {
return h.Log(r)
}
return nil
})
}
// MatchFilterHandler returns a Handler that only writes records
// to the wrapped Handler if the given key in the logged
// context matches the value. For example, to only log records
// from your ui package:
//
// log.MatchFilterHandler("pkg", "app/ui", log.StdoutHandler)
func MatchFilterHandler(key string, value interface{}, h Handler) Handler {
return FilterHandler(func(r Record) (pass bool) {
switch key {
case r.KeyNames.Lvl:
return r.Lvl == value
case r.KeyNames.Time:
return r.Time == value
case r.KeyNames.Msg:
return r.Msg == value
}
for i := 0; i < len(r.Ctx); i += 2 {
if r.Ctx[i] == key {
return r.Ctx[i+1] == value
}
}
return false
}, h)
}
// LvlFilterHandler returns a Handler that only writes
// records which are less than the given verbosity
// level to the wrapped Handler. For example, to only
// log Error/Crit records:
//
// log.LvlFilterHandler(log.LvlError, log.StdoutHandler)
func LvlFilterHandler(maxLvl Lvl, h Handler) Handler {
return FilterHandler(func(r Record) (pass bool) {
return r.Lvl <= maxLvl
}, h)
}
// MultiHandler dispatches any write to each of its handlers.
// This is useful for writing different types of log information
// to different locations. For example, to log to a file and
// standard error:
//
// log.MultiHandler(
// log.Must.FileHandler("/var/log/app.log", log.LogfmtFormat()),
// log.StderrHandler)
func MultiHandler(hs ...Handler) Handler {
return FuncHandler(func(r Record) error {
for _, h := range hs {
// what to do about failures?
h.Log(r)
}
return nil
})
}
// FailoverHandler writes all log records to the first handler
// specified, but will failover and write to the second handler if
// the first handler has failed, and so on for all handlers specified.
// For example you might want to log to a network socket, but failover
// to writing to a file if the network fails, and then to
// standard out if the file write fails:
//
// log.FailoverHandler(
// log.Must.NetHandler("tcp", ":9090", log.JsonFormat()),
// log.Must.FileHandler("/var/log/app.log", log.LogfmtFormat()),
// log.StdoutHandler)
//
// All writes that do not go to the first handler will add context with keys of
// the form "failover_err_{idx}" which explain the error encountered while
// trying to write to the handlers before them in the list.
func FailoverHandler(hs ...Handler) Handler {
return FuncHandler(func(r Record) error {
var err error
for i, h := range hs {
err = h.Log(r)
if err == nil {
return nil
}
r.Ctx = append(r.Ctx, fmt.Sprintf("failover_err_%d", i), err)
}
return err
})
}
// ChannelHandler writes all records to the given channel.
// It blocks if the channel is full. Useful for async processing
// of log messages, it's used by BufferedHandler.
func ChannelHandler(recs chan<- Record) Handler {
return FuncHandler(func(r Record) error {
recs <- r
return nil
})
}
// BufferedHandler writes all records to a buffered
// channel of the given size which flushes into the wrapped
// handler whenever it is available for writing. Since these
// writes happen asynchronously, all writes to a BufferedHandler
// never return an error and any errors from the wrapped handler are ignored.
func BufferedHandler(bufSize int, h Handler) Handler {
recs := make(chan Record, bufSize)
go func() {
for m := range recs {
_ = h.Log(m)
}
}()
return ChannelHandler(recs)
}
// LazyHandler writes all values to the wrapped handler after evaluating
// any lazy functions in the record's context. It is already wrapped
// around StreamHandler and SyslogHandler in this library, you'll only need
// it if you write your own Handler.
func LazyHandler(h Handler) Handler {
return FuncHandler(func(r Record) error {
// go through the values (odd indices) and reassign
// the values of any lazy fn to the result of its execution
hadErr := false
for i := 1; i < len(r.Ctx); i += 2 {
lz, ok := r.Ctx[i].(Lazy)
if ok {
v, err := evaluateLazy(lz)
if err != nil {
hadErr = true
r.Ctx[i] = err
} else {
r.Ctx[i] = v
}
}
}
if hadErr {
r.Ctx = append(r.Ctx, errorKey, "bad lazy")
}
return h.Log(r)
})
}
func evaluateLazy(lz Lazy) (interface{}, error) {
t := reflect.TypeOf(lz.Fn)
if t.Kind() != reflect.Func {
return nil, fmt.Errorf("INVALID_LAZY, not func: %+v", lz.Fn)
}
if t.NumIn() > 0 {
return nil, fmt.Errorf("INVALID_LAZY, func takes args: %+v", lz.Fn)
}
if t.NumOut() == 0 {
return nil, fmt.Errorf("INVALID_LAZY, no func return val: %+v", lz.Fn)
}
value := reflect.ValueOf(lz.Fn)
results := value.Call([]reflect.Value{})
if len(results) == 1 {
return results[0].Interface(), nil
}
values := make([]interface{}, len(results))
for i, v := range results {
values[i] = v.Interface()
}
return values, nil
}
// DiscardHandler reports success for all writes but does nothing.
// It is useful for dynamically disabling logging at runtime via
// a Logger's SetHandler method.
func DiscardHandler() Handler {
return FuncHandler(func(r Record) error {
return nil
})
}
// Must object provides the following Handler creation functions
// which instead of returning an error parameter only return a Handler
// and panic on failure: FileHandler, NetHandler, SyslogHandler, SyslogNetHandler
var Must muster
func must(h Handler, err error) Handler {
if err != nil {
panic(err)
}
return h
}
type muster struct{}
func (m muster) FileHandler(path string, fmtr Format) Handler {
return must(FileHandler(path, fmtr))
}
func (m muster) NetHandler(network, addr string, fmtr Format) Handler {
return must(NetHandler(network, addr, fmtr))
}
================================================
FILE: vendor/github.com/inconshreveable/log15/v3/handler_go13.go
================================================
//go:build !go1.4
// +build !go1.4
package log15
import (
"sync/atomic"
"unsafe"
)
// swapHandler wraps another handler that may be swapped out
// dynamically at runtime in a thread-safe fashion.
type swapHandler struct {
handler unsafe.Pointer
}
func (h *swapHandler) Log(r *Record) error {
return h.Get().Log(r)
}
func (h *swapHandler) Get() Handler {
return *(*Handler)(atomic.LoadPointer(&h.handler))
}
func (h *swapHandler) Swap(newHandler Handler) {
atomic.StorePointer(&h.handler, unsafe.Pointer(&newHandler))
}
================================================
FILE: vendor/github.com/inconshreveable/log15/v3/handler_go14.go
================================================
//go:build go1.4
// +build go1.4
package log15
import "sync/atomic"
// swapHandler wraps another handler that may be swapped out
// dynamically at runtime in a thread-safe fashion.
type swapHandler struct {
handler atomic.Value
}
func (h *swapHandler) Log(r Record) error {
return (*h.handler.Load().(*Handler)).Log(r)
}
func (h *swapHandler) Swap(newHandler Handler) {
h.handler.Store(&newHandler)
}
func (h *swapHandler) Get() Handler {
return *h.handler.Load().(*Handler)
}
================================================
FILE: vendor/github.com/inconshreveable/log15/v3/logger.go
================================================
package log15
import (
"fmt"
"strings"
"time"
)
const timeKey = "t"
const lvlKey = "lvl"
const msgKey = "msg"
const errorKey = "LOG15_ERROR"
// Lvl is a type for predefined log levels.
type Lvl int
// List of predefined log Levels
const (
LvlCrit Lvl = iota
LvlError
LvlWarn
LvlInfo
LvlDebug
)
// Returns the name of a Lvl
func (l Lvl) String() string {
switch l {
case LvlDebug:
return "dbug"
case LvlInfo:
return "info"
case LvlWarn:
return "warn"
case LvlError:
return "eror"
case LvlCrit:
return "crit"
default:
panic("bad level")
}
}
// LvlFromString returns the appropriate Lvl from a string name.
// Useful for parsing command line args and configuration files.
func LvlFromString(lvlString string) (Lvl, error) {
switch lvlString {
case "debug", "dbug":
return LvlDebug, nil
case "info":
return LvlInfo, nil
case "warn":
return LvlWarn, nil
case "error", "eror":
return LvlError, nil
case "crit":
return LvlCrit, nil
default:
// try to catch e.g. "INFO", "WARN" without slowing down the fast path
lower := strings.ToLower(lvlString)
if lower != lvlString {
return LvlFromString(lower)
}
return LvlDebug, fmt.Errorf("log15: unknown level: %v", lvlString)
}
}
// A Record is what a Logger asks its handler to write
type Record struct {
Time time.Time
Lvl Lvl
Msg string
Ctx []interface{}
KeyNames *RecordKeyNames
}
// RecordKeyNames are the predefined names of the log props used by the Logger interface.
type RecordKeyNames struct {
Time string
Msg string
Lvl string
}
var DefaultRecordKeyNames = &RecordKeyNames{
Time: timeKey,
Msg: msgKey,
Lvl: lvlKey,
}
// A Logger writes key/value pairs to a Handler
type Logger interface {
// New returns a new Logger that has this logger's context plus the given context
New(ctx ...interface{}) Logger
// GetHandler gets the handler associated with the logger.
GetHandler() Handler
// SetHandler updates the logger to write records to the specified handler.
SetHandler(h Handler)
// Log a message at the given level with context key/value pairs
Debug(msg string, ctx ...interface{})
Info(msg string, ctx ...interface{})
Warn(msg string, ctx ...interface{})
Error(msg string, ctx ...interface{})
Crit(msg string, ctx ...interface{})
}
type logger struct {
ctx []interface{}
h *swapHandler
}
func (l *logger) write(msg string, lvl Lvl, ctx []interface{}) {
l.h.Log(Record{
Time: time.Now(),
Lvl: lvl,
Msg: msg,
Ctx: newContext(l.ctx, ctx),
KeyNames: DefaultRecordKeyNames,
})
}
func (l *logger) New(ctx ...interface{}) Logger {
child := &logger{newContext(l.ctx, ctx), new(swapHandler)}
child.SetHandler(l.h)
return child
}
func newContext(prefix []interface{}, suffix []interface{}) []interface{} {
normalizedSuffix := normalize(suffix)
newCtx := make([]interface{}, len(prefix)+len(normalizedSuffix))
n := copy(newCtx, prefix)
copy(newCtx[n:], normalizedSuffix)
return newCtx
}
func (l *logger) Debug(msg string, ctx ...interface{}) {
l.write(msg, LvlDebug, ctx)
}
func (l *logger) Info(msg string, ctx ...interface{}) {
l.write(msg, LvlInfo, ctx)
}
func (l *logger) Warn(msg string, ctx ...interface{}) {
l.write(msg, LvlWarn, ctx)
}
func (l *logger) Error(msg string, ctx ...interface{}) {
l.write(msg, LvlError, ctx)
}
func (l *logger) Crit(msg string, ctx ...interface{}) {
l.write(msg, LvlCrit, ctx)
}
func (l *logger) GetHandler() Handler {
return l.h.Get()
}
func (l *logger) SetHandler(h Handler) {
l.h.Swap(h)
}
func normalize(ctx []interface{}) []interface{} {
// if the caller passed a Ctx object, then expand it
if len(ctx) == 1 {
if ctxMap, ok := ctx[0].(Ctx); ok {
ctx = ctxMap.toArray()
}
}
// ctx needs to be even because it's a series of key/value pairs
// no one wants to check for errors on logging functions,
// so instead of erroring on bad input, we'll just make sure
// that things are the right length and users can fix bugs
// when they see the output looks wrong
if len(ctx)%2 != 0 {
ctx = append(ctx, nil, errorKey, "Normalized odd number of arguments by adding nil")
}
return ctx
}
// Lazy allows you to defer calculation of a logged value that is expensive
// to compute until it is certain that it must be evaluated with the given filters.
//
// Lazy may also be used in conjunction with a Logger's New() function
// to generate a child logger which always reports the current value of changing
// state.
//
// You may wrap any function which takes no arguments to Lazy. It may return any
// number of values of any type.
type Lazy struct {
Fn interface{}
}
// Ctx is a map of key/value pairs to pass as context to a log function
// Use this only if you really need greater safety around the arguments you pass
// to the logging functions.
type Ctx map[string]interface{}
func (c Ctx) toArray() []interface{} {
arr := make([]interface{}, len(c)*2)
i := 0
for k, v := range c {
arr[i] = k
arr[i+1] = v
i += 2
}
return arr
}
================================================
FILE: vendor/github.com/inconshreveable/log15/v3/root.go
================================================
package log15
import (
"os"
"github.com/mattn/go-colorable"
"golang.org/x/term"
)
// Predefined handlers
var (
root *logger
StdoutHandler = StreamHandler(os.Stdout, LogfmtFormat())
StderrHandler = StreamHandler(os.Stderr, LogfmtFormat())
)
func init() {
if term.IsTerminal(int(os.Stdout.Fd())) {
StdoutHandler = StreamHandler(colorable.NewColorableStdout(), TerminalFormat())
}
if term.IsTerminal(int(os.Stderr.Fd())) {
StderrHandler = StreamHandler(colorable.NewColorableStderr(), TerminalFormat())
}
root = &logger{[]interface{}{}, new(swapHandler)}
root.SetHandler(StdoutHandler)
}
// New returns a new logger with the given context.
// New is a convenient alias for Root().New
func New(ctx ...interface{}) Logger {
return root.New(ctx...)
}
// Root returns the root logger
func Root() Logger {
return root
}
// The following functions bypass the exported logger methods (logger.Debug,
// etc.) to keep the call depth the same for all paths to logger.write so
// runtime.Caller(2) always refers to the call site in client code.
// Debug is a convenient alias for Root().Debug
func Debug(msg string, ctx ...interface{}) {
root.write(msg, LvlDebug, ctx)
}
// Info is a convenient alias for Root().Info
func Info(msg string, ctx ...interface{}) {
root.write(msg, LvlInfo, ctx)
}
// Warn is a convenient alias for Root().Warn
func Warn(msg string, ctx ...interface{}) {
root.write(msg, LvlWarn, ctx)
}
// Error is a convenient alias for Root().Error
func Error(msg string, ctx ...interface{}) {
root.write(msg, LvlError, ctx)
}
// Crit is a convenient alias for Root().Crit
func Crit(msg string, ctx ...interface{}) {
root.write(msg, LvlCrit, ctx)
}
================================================
FILE: vendor/github.com/inconshreveable/log15/v3/syslog.go
================================================
//go:build !windows && !plan9
// +build !windows,!plan9
package log15
import (
"log/syslog"
"strings"
)
// SyslogHandler opens a connection to the system syslog daemon by calling
// syslog.New and writes all records to it.
func SyslogHandler(priority syslog.Priority, tag string, fmtr Format) (Handler, error) {
wr, err := syslog.New(priority, tag)
return sharedSyslog(fmtr, wr, err)
}
// SyslogNetHandler opens a connection to a log daemon over the network and writes
// all log records to it.
func SyslogNetHandler(net, addr string, priority syslog.Priority, tag string, fmtr Format) (Handler, error) {
wr, err := syslog.Dial(net, addr, priority, tag)
return sharedSyslog(fmtr, wr, err)
}
func sharedSyslog(fmtr Format, sysWr *syslog.Writer, err error) (Handler, error) {
if err != nil {
return nil, err
}
h := FuncHandler(func(r Record) error {
var syslogFn = sysWr.Info
switch r.Lvl {
case LvlCrit:
syslogFn = sysWr.Crit
case LvlError:
syslogFn = sysWr.Err
case LvlWarn:
syslogFn = sysWr.Warning
case LvlInfo:
syslogFn = sysWr.Info
case LvlDebug:
syslogFn = sysWr.Debug
}
s := strings.TrimSpace(string(fmtr.Format(r)))
return syslogFn(s)
})
return LazyHandler(&closingHandler{sysWr, h}), nil
}
func (m muster) SyslogHandler(priority syslog.Priority, tag string, fmtr Format) Handler {
return must(SyslogHandler(priority, tag, fmtr))
}
func (m muster) SyslogNetHandler(net, addr string, priority syslog.Priority, tag string, fmtr Format) Handler {
return must(SyslogNetHandler(net, addr, priority, tag, fmtr))
}
================================================
FILE: vendor/github.com/kevinburke/handlers/.gitignore
================================================
/bazel-*
================================================
FILE: vendor/github.com/kevinburke/handlers/CHANGELOG.md
================================================
### 0.38
If WriteHeader is never called, Log will log status=200 to the log, instead of
status=0.
### 0.37
Support OPTIONS queries with a nil route.
### 0.35
If two paths are declared that both match a given path, we'll try both of them
before giving up and returning a HTTP 405. This is slightly slower (we have to
try every route before giving up), but does the right thing.
### 0.34
Pass nil to specify you want to handle all HTTP methods in the router.
### 0.33
Make copies of all HTTP requests before passing them further down the chain. Per
the documentation, this is the correct way to handle this situation.
### 0.32
Fix an error in the duration information reported by X-Request-Duration.
================================================
FILE: vendor/github.com/kevinburke/handlers/LICENSE
================================================
There are three licenses in this file; the Log code was taken from two
different places. I believe you should include all of them if you redistribute
this software.
Copyright (c) 2016 Kevin Burke.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
==========
Portions of log.go have been added from github.com/inconshreveable/log15. The
following changes were made:
- The terminal logger doesn't pad the Msg to 40 characters.
- No Msg is printed if Msg is empty.
- Timestamps include millisecond/nanosecond precision.
The license for the log15 code is below:
Copyright 2014 Alan Shreve
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
===========
Portions of the Log() code and gzip.go have been added from
github.com/gorilla/handlers. License for that code is below:
Copyright (c) 2013 The Gorilla Handlers Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: vendor/github.com/kevinburke/handlers/Makefile
================================================
SHELL = /bin/bash -o pipefail
BUMP_VERSION := $(GOPATH)/bin/bump_version
vet:
go vet ./...
staticcheck ./...
test: vet
go test -timeout=10s ./...
install-ci:
GO111MODULE=on go install honnef.co/go/tools/cmd/staticcheck@latest
GO111MODULE=on go install github.com/kevinburke/goget@latest
goget -https github.com/gofrs/uuid/v5
goget -https github.com/inconshreveable/log15
goget -https github.com/kevinburke/rest
goget -https github.com/mattn/go-colorable
goget -https github.com/mattn/go-isatty
goget -https golang.org/x/term
goget -https golang.org/x/sys
ci: install-ci vet race-test
race-test: vet
go test -race -timeout=10s ./...
install:
go install ./...
$(BUMP_VERSION):
go get github.com/kevinburke/bump_version
release: race-test | $(BUMP_VERSION)
$(BUMP_VERSION) --tag-prefix=v minor lib.go
================================================
FILE: vendor/github.com/kevinburke/handlers/README.md
================================================
This project contains middlewares that I often found myself reimplementing
in new projects. In addition, it includes a middleware that logs in a format
similar to Heroku's, but which includes the request's user agent, and only a
single proxy IP address.
See the [godoc](https://godoc.org/github.com/kevinburke/handlers) for more
information and documentation.
## Versions
`handlers` requires Go 1.8 or newer. Version 0.30 is the last version that works
with versions older than Go 1.8.
## Donating
Donations free up time to make improvements to the library, and respond to
bug reports. You can send donations via Paypal's "Send Money" feature to
kev@inburke.com. Donations are not tax deductible in the USA.
================================================
FILE: vendor/github.com/kevinburke/handlers/ctx.go
================================================
package handlers
import (
"context"
"net/http"
"strings"
"time"
"github.com/gofrs/uuid/v5"
)
type ctxVar int
var requestID ctxVar = 0
var startTime ctxVar = 1
var extraLog ctxVar = 2
// SetRequestID sets the given UUID on the request context and returns the
// modified HTTP request.
func SetRequestID(r *http.Request, u uuid.UUID) *http.Request {
ctx := context.WithValue(r.Context(), requestID, u)
r2 := r.Clone(ctx)
r2.Header.Set("X-Request-Id", u.String())
return r2
}
// GetRequestID returns a UUID (if it exists in the context) or false if none
// could be found.
func GetRequestID(ctx context.Context) (uuid.UUID, bool) {
val := ctx.Value(requestID)
if val != nil {
v, ok := val.(uuid.UUID)
return v, ok
}
return uuid.UUID{}, false
}
// GetDuration returns the amount of time since the Duration handler ran, or
// 0 if no Duration was set for this context.
func GetDuration(ctx context.Context) time.Duration {
t := getStart(ctx)
if t.IsZero() {
return time.Duration(0)
}
return time.Since(t)
}
// GetStartTime returns the time the Duration handler ran.
func GetStartTime(ctx context.Context) time.Time {
val := ctx.Value(startTime)
if val != nil {
t := val.(time.Time)
return t
}
return time.Time{}
}
// getStart returns the time the Duration handler ran.
func getStart(ctx context.Context) time.Time {
val := ctx.Value(startTime)
if val != nil {
t := val.(time.Time)
return t
}
return time.Time{}
}
type startWriter struct {
w http.ResponseWriter
start time.Time
wroteHeader bool
}
func (s *startWriter) duration() string {
d := time.Since(s.start) / (100 * time.Microsecond) * 100 * time.Microsecond
return strings.Replace(d.String(), "µ", "u", 1)
}
func (s *startWriter) WriteHeader(code int) {
//lint:ignore S1002 prefer it this way
if s.wroteHeader == false {
s.w.Header().Set("X-Request-Duration", s.duration())
s.wroteHeader = true
}
s.w.WriteHeader(code)
}
func (s *startWriter) Write(b []byte) (int, error) {
// Some chunked encoding transfers won't ever call WriteHeader(), so set
// the header here.
//lint:ignore S1002 prefer it this way
if s.wroteHeader == false {
s.w.Header().Set("X-Request-Duration", s.duration())
s.wroteHeader = true
}
return s.w.Write(b)
}
func (s *startWriter) Header() http.Header {
return s.w.Header()
}
// Push implements the http.Pusher interface.
func (s *startWriter) Push(target string, opts *http.PushOptions) error {
return push(s.w, target, opts)
}
// Duration sets the start time in the context and sets a X-Request-Duration
// header on the response, from the time this handler started executing to the
// time of the first WriteHeader() or Write() call.
func Duration(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
sw := &startWriter{
w: w,
start: time.Now().UTC(),
wroteHeader: false,
}
r2 := r.WithContext(context.WithValue(r.Context(), startTime, sw.start))
h.ServeHTTP(sw, r2)
//lint:ignore S1002 prefer it this way
if sw.wroteHeader == false {
// never called Write() or WriteHeader()
sw.w.Header().Set("X-Request-Duration", sw.duration())
sw.wroteHeader = true
}
})
}
// WithTimeout sets the given timeout in the Context of every incoming request
// before passing it to the next handler.
func WithTimeout(h http.Handler, timeout time.Duration) http.Handler {
if timeout < 0 {
panic("invalid timeout (negative number)")
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), timeout)
defer cancel()
h.ServeHTTP(w, r.Clone(ctx))
})
}
================================================
FILE: vendor/github.com/kevinburke/handlers/gzip.go
================================================
// Copyright 2013 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package handlers
import (
"compress/flate"
"compress/gzip"
"io"
"net/http"
"strings"
)
type compressResponseWriter struct {
io.Writer
http.ResponseWriter
http.Hijacker
http.Flusher
}
func (w *compressResponseWriter) WriteHeader(c int) {
w.ResponseWriter.Header().Del("Content-Length")
w.ResponseWriter.WriteHeader(c)
}
func (w *compressResponseWriter) Header() http.Header {
return w.ResponseWriter.Header()
}
func (w *compressResponseWriter) Write(b []byte) (int, error) {
h := w.ResponseWriter.Header()
if h.Get("Content-Type") == "" {
h.Set("Content-Type", http.DetectContentType(b))
}
h.Del("Content-Length")
return w.Writer.Write(b)
}
type flusher interface {
Flush() error
}
func (w *compressResponseWriter) Flush() {
// Flush compressed data if compressor supports it.
if f, ok := w.Writer.(flusher); ok {
f.Flush()
}
// Flush HTTP response.
if w.Flusher != nil {
w.Flusher.Flush()
}
}
// GZip gzip compresses HTTP responses for clients that support it via the
// 'Accept-Encoding' header.
//
// Compressing TLS traffic may leak the page contents to an attacker
// if the page contains user input, known as the CRIME/BEAST attacks:
// http://security.stackexchange.com/a/102015/12208. Only use the GZip handler
// with unencrypted traffic, static pages, or pages that only contain public
// data.
func GZip(h http.Handler) http.Handler {
return compressHandlerLevel(h, gzip.DefaultCompression)
}
// compressHandlerLevel gzip compresses HTTP responses with specified compression level
// for clients that support it via the 'Accept-Encoding' header.
//
// The compression level should be gzip.DefaultCompression, gzip.NoCompression,
// or any integer value between gzip.BestSpeed and gzip.BestCompression inclusive.
// gzip.DefaultCompression is used in case of invalid compression level.
func compressHandlerLevel(h http.Handler, level int) http.Handler {
if level < gzip.DefaultCompression || level > gzip.BestCompression {
level = gzip.DefaultCompression
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
L:
for _, enc := range strings.Split(r.Header.Get("Accept-Encoding"), ",") {
switch strings.TrimSpace(enc) {
case "gzip":
w.Header().Set("Content-Encoding", "gzip")
w.Header().Add("Vary", "Accept-Encoding")
gw, _ := gzip.NewWriterLevel(w, level)
defer gw.Close()
h, hok := w.(http.Hijacker)
if !hok { /* w is not Hijacker... oh well... */
h = nil
}
f, fok := w.(http.Flusher)
if !fok {
f = nil
}
w = &compressResponseWriter{
Writer: gw,
ResponseWriter: w,
Hijacker: h,
Flusher: f,
}
break L
case "deflate":
w.Header().Set("Content-Encoding", "deflate")
w.Header().Add("Vary", "Accept-Encoding")
fw, _ := flate.NewWriter(w, level)
defer fw.Close()
h, hok := w.(http.Hijacker)
if !hok { /* w is not Hijacker... oh well... */
h = nil
}
f, fok := w.(http.Flusher)
if !fok {
f = nil
}
w = &compressResponseWriter{
Writer: fw,
ResponseWriter: w,
Hijacker: h,
Flusher: f,
}
break L
}
}
h.ServeHTTP(w, r)
})
}
================================================
FILE: vendor/github.com/kevinburke/handlers/lib.go
================================================
// Package handlers implements a number of useful HTTP middlewares.
//
// The general format of the middlewares in this package is to wrap an existing
// http.Handler in another one. So if you have a ServeMux, you can simply do:
//
// mux := http.NewServeMux()
// h := handlers.Log(handlers.Debug(mux))
// http.ListenAndServe(":5050", h)
//
// And wrap as many handlers as you'd like using that idiom.
package handlers
import (
"bytes"
"context"
"crypto/subtle"
"fmt"
"io"
"net/http"
"net/http/httptest"
"net/http/httputil"
"net/url"
"os"
"strings"
"sync"
"time"
uuid "github.com/gofrs/uuid/v5"
"github.com/kevinburke/rest"
"github.com/kevinburke/rest/resterror"
)
const Version = "0.48.0"
func push(w http.ResponseWriter, target string, opts *http.PushOptions) error {
if pusher, ok := w.(http.Pusher); ok {
return pusher.Push(target, opts)
}
return http.ErrNotSupported
}
// All wraps h with every handler in this file.
func All(h http.Handler, serverName string) http.Handler {
return Duration(Log(Debug(UUID(TrailingSlashRedirect(JSON(Server(h, serverName)))))))
}
// JSON sets the Content-Type to application/json; charset=utf-8.
func JSON(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
h.ServeHTTP(w, r)
})
}
type serverWriter struct {
w http.ResponseWriter
name string
wroteHeader bool
}
func (s *serverWriter) WriteHeader(code int) {
//lint:ignore S1002 prefer it this way
if s.wroteHeader == false {
s.w.Header().Set("Server", s.name)
s.wroteHeader = true
}
s.w.WriteHeader(code)
}
func (s *serverWriter) Write(b []byte) (int, error) {
//lint:ignore S1002 prefer it this way
if s.wroteHeader == false {
s.w.Header().Set("Server", s.name)
s.wroteHeader = true
}
return s.w.Write(b)
}
func (s *serverWriter) Header() http.Header {
return s.w.Header()
}
// Push implements the http.Pusher interface.
func (s *serverWriter) Push(target string, opts *http.PushOptions) error {
return push(s.w, target, opts)
}
// TrailingSlashRedirect redirects any path that ends with a "/" - say,
// "/messages/" - to the stripped version, say "/messages".
func TrailingSlashRedirect(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if len(r.URL.Path) > 1 && strings.HasSuffix(r.URL.Path, "/") {
http.Redirect(w, r, r.URL.Path[:len(r.URL.Path)-1], http.StatusMovedPermanently)
return
}
h.ServeHTTP(w, r)
})
}
// Server attaches a Server header to the response.
func Server(h http.Handler, serverName string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
sw := &serverWriter{
w: w,
name: serverName,
wroteHeader: false,
}
h.ServeHTTP(sw, r)
//lint:ignore S1002 prefer it this way
if sw.wroteHeader == false {
sw.w.Header().Set("Server", sw.name)
sw.wroteHeader = true
}
})
}
// UUID attaches a X-Request-Id header to the request, and sets one on the
// request context, unless one already exists.
func UUID(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
rid := r.Header.Get("X-Request-Id")
if rid == "" {
id, _ := uuid.NewV4()
r = SetRequestID(r, id)
}
h.ServeHTTP(w, r)
})
}
// BasicAuth protects all requests to the given handler, unless the request has
// basic auth with a username and password in the users map.
func BasicAuth(h http.Handler, realm string, users map[string]string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
user, pass, ok := r.BasicAuth()
if !ok {
rest.Unauthorized(w, r, realm)
return
}
serverPass, ok := users[user]
if !ok {
if user == "" {
rest.Unauthorized(w, r, realm)
} else {
rest.Forbidden(w, r, &resterror.Error{
Title: "Username or password are invalid. Please double check your credentials",
ID: "forbidden",
})
}
return
}
if subtle.ConstantTimeCompare([]byte(pass), []byte(serverPass)) != 1 {
rest.Forbidden(w, r, &resterror.Error{
Title: fmt.Sprintf("Incorrect password for user %s", user),
ID: "incorrect_password",
Instance: r.URL.Path,
})
return
}
h.ServeHTTP(w, r)
})
}
var envFunc = os.Getenv
// Debug prints debugging information about the request to output if the
// DEBUG_HTTP_TRAFFIC environment variable is set to "true".
func DebugWriter(h http.Handler, output io.Writer) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if envFunc("DEBUG_HTTP_TRAFFIC") != "true" && envFunc("DEBUG_HTTP_SERVER_TRAFFIC") != "true" {
h.ServeHTTP(w, r)
return
}
// You need to write the entire thing in one Write, otherwise the
// output will be jumbled with other requests.
b := new(bytes.Buffer)
bits, err := httputil.DumpRequest(r, true)
if err != nil {
_, _ = b.WriteString(err.Error())
} else {
if w.Header().Get("Content-Encoding") == "gzip" {
_, _ = b.WriteString("[binary data omitted]")
} else {
_, _ = b.Write(bits)
}
}
res := httptest.NewRecorder()
h.ServeHTTP(res, r)
_, _ = b.WriteString(fmt.Sprintf("HTTP/1.1 %d\r\n", res.Code))
_ = res.Header().Write(b)
for k, v := range res.Header() {
w.Header()[k] = v
}
w.WriteHeader(res.Code)
_, _ = b.WriteString("\r\n")
if w.Header().Get("Content-Encoding") == "gzip" {
io.WriteString(b, "[binary data omitted]")
res.Body.WriteTo(w)
} else {
writer := io.MultiWriter(w, b)
res.Body.WriteTo(writer)
}
_, _ = b.WriteTo(output)
})
}
// Debug prints debugging information about the request to stderr if the
// DEBUG_HTTP_TRAFFIC environment variable is set to "true".
func Debug(h http.Handler) http.Handler {
return DebugWriter(h, os.Stderr)
}
// responseLogger is wrapper of http.ResponseWriter that keeps track of its HTTP
// status code and body size
type responseLogger struct {
w http.ResponseWriter
status int
size int
}
func (l *responseLogger) Header() http.Header {
return l.w.Header()
}
func (l *responseLogger) Write(b []byte) (int, error) {
if l.status == 0 {
// The status will be StatusOK if WriteHeader has not been called yet
l.status = http.StatusOK
}
size, err := l.w.Write(b)
l.size += size
return size, err
}
func (l *responseLogger) WriteHeader(s int) {
l.w.WriteHeader(s)
l.status = s
}
func (l *responseLogger) Status() int {
if l.status == 0 {
return http.StatusOK // default status
}
return l.status
}
func (l *responseLogger) Size() int {
return l.size
}
func (l *responseLogger) Flush() {
f, ok := l.w.(http.Flusher)
if ok {
f.Flush()
}
}
// Push implements the http.Pusher interface.
func (l *responseLogger) Push(target string, opts *http.PushOptions) error {
return push(l.w, target, opts)
}
type hijackLogger struct {
responseLogger
}
func makeLogger(w http.ResponseWriter) loggingResponseWriter {
var logger loggingResponseWriter = &responseLogger{w: w}
if _, ok := w.(http.Hijacker); ok {
logger = &hijackLogger{responseLogger{w: w}}
}
return logger
}
type loggingResponseWriter interface {
http.ResponseWriter
http.Flusher
Status() int
Size() int
}
func (l logHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
t := time.Now()
logWriter := makeLogger(w)
u := *r.URL
r = r.WithContext(context.WithValue(r.Context(), extraLog, &logHolder{}))
l.h.ServeHTTP(logWriter, r)
writeLog(l.l, r, u, t, logWriter.Status(), logWriter.Size())
}
func getRemoteIP(r *http.Request) string {
fwd := r.Header.Get("X-Forwarded-For")
if fwd == "" {
return r.RemoteAddr
}
return strings.Split(fwd, ",")[0]
}
// Return the time since the given time, in ms.
func timeSinceMs(t time.Time) int64 {
// Add 500 microseconds so we round up or down to the nearest MS.
ns := time.Since(t).Nanoseconds() + 500*int64(time.Microsecond)
return ns / int64(time.Millisecond)
}
type logHolder struct {
mu sync.Mutex
logs []interface{}
}
// Append will append the logctx arguments to the log line for this request.
// The logctx arguments should come in pairs and match those provided to a
// log15.Logger.
func AppendLog(r *http.Request, logctx ...interface{}) {
val := r.Context().Value(extraLog)
if val == nil {
// This should always be set by logHandler.ServeHTTP; if it's not set,
// it means you're trying to append to something that was not wrapped
// with Log or WithLogger().
//
// In practice, it's not uncommon in places like tests or sub-routers to
// not have this value set, so silently ignore it for now.
return
}
holder := val.(*logHolder)
holder.mu.Lock()
defer holder.mu.Unlock()
if holder.logs == nil {
holder.logs = make([]interface{}, 0)
}
holder.logs = append(holder.logs, logctx...)
}
// Log serves the http request and writes information about the
// request/response using the default Logger (handlers.Logger). Any errors
// writing to the Logger are ignored.
func Log(h http.Handler) http.Handler {
return WithLogger(h, Logger)
}
// RedirectProto redirects requests with an "X-Forwarded-Proto: http" header to
// their HTTPS equivalent.
func RedirectProto(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("X-Forwarded-Proto") == "http" {
r2 := new(http.Request)
*r2 = *r
r2.URL = new(url.URL)
*r2.URL = *r.URL
r2.URL.Scheme = "https"
r2.URL.Host = r.Host
http.Redirect(w, r2, r2.URL.String(), http.StatusFound)
return
}
h.ServeHTTP(w, r)
})
}
// STS sets a Strict-Transport-Security header on the response.
func STS(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Strict-Transport-Security", "max-age=31536000; preload")
h.ServeHTTP(w, r)
})
}
================================================
FILE: vendor/github.com/kevinburke/handlers/lib_noslog.go
================================================
//go:build !go1.21
// +build !go1.21
package handlers
import (
"net/http"
"net/url"
"strconv"
"time"
"github.com/inconshreveable/log15/v3"
"github.com/kevinburke/rest"
)
// Logger is a logger configured to avoid the 40-char spacing gap between the
// message and the first key, and to write timestamps with full nanosecond
// precision.
var Logger log15.Logger
func init() {
Logger = NewLogger()
rest.Logger = Logger
}
type logHandler struct {
h http.Handler
l log15.Logger
}
// WithLogger logs information about HTTP requests and responses to the
// provided Logger, including a detailed timestamp, the user agent, the
// response time, the number of bytes written, and more. Any errors writing log
// information to the Logger are ignored.
func WithLogger(h http.Handler, logger log15.Logger) http.Handler {
return &logHandler{h, logger}
}
func writeLog(l log15.Logger, r *http.Request, u url.URL, t time.Time, status int, size int) {
user, _, _ := r.BasicAuth()
args := []interface{}{
"method", r.Method,
"path", r.URL.RequestURI(),
"time", strconv.FormatInt(timeSinceMs(t), 10),
"bytes", strconv.Itoa(size),
"status", strconv.Itoa(status),
// Set X-Forwarded-For to pass through headers from a proxy.
"remote_addr", getRemoteIP(r),
"host", r.Host,
"user_agent", r.UserAgent(),
}
if user != "" {
args = append(args, "user", user)
}
if id := r.Header.Get("X-Request-Id"); id != "" {
args = append(args, "request_id", id)
}
holder := r.Context().Value(extraLog).(*logHolder)
args = append(args, holder.logs...)
l.Info("", args...)
}
================================================
FILE: vendor/github.com/kevinburke/handlers/lib_slog.go
================================================
//go:build go1.21
// +build go1.21
package handlers
import (
"log/slog"
"net/http"
"net/url"
"strconv"
"time"
"github.com/kevinburke/rest"
)
type logHandler struct {
h http.Handler
l *slog.Logger
}
var Logger *slog.Logger
func init() {
Logger = NewLogger()
rest.Logger = Logger
}
// WithLogger logs information about HTTP requests and responses to the
// provided Logger, including a detailed timestamp, the user agent, the
// response time, the number of bytes written, and more. Any errors writing log
// information to the Logger are ignored.
func WithLogger(h http.Handler, logger *slog.Logger) http.Handler {
return &logHandler{h, logger}
}
func writeLog(l *slog.Logger, r *http.Request, u url.URL, t time.Time, status int, size int) {
user, _, _ := r.BasicAuth()
args := []interface{}{
"method", r.Method,
"path", r.URL.RequestURI(),
"time", strconv.FormatInt(timeSinceMs(t), 10),
"bytes", strconv.Itoa(size),
"status", strconv.Itoa(status),
// Set X-Forwarded-For to pass through headers from a proxy.
"remote_addr", getRemoteIP(r),
"host", r.Host,
"user_agent", r.UserAgent(),
}
if user != "" {
args = append(args, "user", user)
}
if id := r.Header.Get("X-Request-Id"); id != "" {
args = append(args, "request_id", id)
}
holder := r.Context().Value(extraLog).(*logHolder)
args = append(args, holder.logs...)
l.Info("", args...)
}
================================================
FILE: vendor/github.com/kevinburke/handlers/logger_noslog.go
================================================
//go:build !go1.21
// +build !go1.21
// Most of this is copied from github.com/inconshreveable/log15/format.go, with
// some changes:
//
// - The time format prints milliseconds if a TTY, and nanoseconds if writing
// to a file.
// - The TTY format doesn't try to pad a msg.
// - The logfmt fmt doesn't try to write an empty message.
package handlers
import (
"bytes"
"fmt"
"os"
"reflect"
"strconv"
"strings"
"time"
"github.com/inconshreveable/log15/v3"
"github.com/mattn/go-colorable"
"golang.org/x/term"
)
var errorKey = "HANDLER_ERROR"
const timeFormat = "2006-01-02T15:04:05.000000-07:00"
const termTimeFormat = "15:04:05.000-07:00"
const termDateTimeFormat = "2006-01-02T15:04:05.000-07:00"
const floatFormat = 'f'
// NewLogger returns a new customizable Logger, with the same initial settings
// as the package Logger. Compared with a default log15.Logger, the 40-char
// spacing gap between the message and the first key is omitted, and timestamps
// are written with more precision.
func NewLogger() log15.Logger {
return NewLoggerLevel(log15.LvlInfo)
}
// NewLoggerLevel returns a Logger with our customized settings, set to log
// messages at or more critical than the given level.
func NewLoggerLevel(lvl log15.Lvl) log15.Logger {
l := log15.New()
var h log15.Handler
if term.IsTerminal(int(os.Stdout.Fd())) {
h = log15.StreamHandler(colorable.NewColorableStdout(), termFormat())
} else {
h = log15.StreamHandler(os.Stdout, logfmtFormat())
}
l.SetHandler(log15.LvlFilterHandler(lvl, h))
return l
}
// LogfmtFormat prints records in logfmt format, an easy machine-parseable but human-readable
// format for key/value pairs.
//
// For more details see: http://godoc.org/github.com/kr/logfmt
func logfmtFormat() log15.Format {
return log15.FormatFunc(func(r *log15.Record) []byte {
common := []interface{}{r.KeyNames.Time, r.Time.Format(termDateTimeFormat), r.KeyNames.Lvl, r.Lvl}
if len(r.Msg) > 0 {
common = append(common, r.KeyNames.Msg, r.Msg)
}
buf := &bytes.Buffer{}
logfmt(buf, append(common, r.Ctx...), 0)
return buf.Bytes()
})
}
func termFormat() log15.Format {
return log15.FormatFunc(func(r *log15.Record) []byte {
var color = 0
switch r.Lvl {
case log15.LvlCrit:
color = 35
case log15.LvlError:
color = 31
case log15.LvlWarn:
color = 33
case log15.LvlInfo:
color = 32
case log15.LvlDebug:
color = 36
}
b := new(bytes.Buffer)
lvl := strings.ToUpper(r.Lvl.String())
if color > 0 {
if r.Msg != "" && !strings.HasSuffix(r.Msg, " ") {
r.Msg = r.Msg + " "
}
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %s", color, lvl, r.Time.Format(termTimeFormat), r.Msg)
} else {
fmt.Fprintf(b, "[%s] [%s] %s ", lvl, r.Time.Format(termTimeFormat), r.Msg)
}
// print the keys logfmt style
logfmt(b, r.Ctx, color)
return b.Bytes()
})
}
// formatValue formats a value for serialization
func formatLogfmtValue(value interface{}) string {
if value == nil {
return "nil"
}
value = formatShared(value)
switch v := value.(type) {
case bool:
return strconv.FormatBool(v)
case float32:
return strconv.FormatFloat(float64(v), floatFormat, 3, 64)
case float64:
return strconv.FormatFloat(v, floatFormat, 3, 64)
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
return fmt.Sprintf("%d", value)
case string:
return escapeString(v)
default:
return escapeString(fmt.Sprintf("%+v", value))
}
}
func formatShared(value interface{}) (result interface{}) {
defer func() {
if err := recover(); err != nil {
if v := reflect.ValueOf(value); v.Kind() == reflect.Ptr && v.IsNil() {
result = "nil"
} else {
panic(err)
}
}
}()
switch v := value.(type) {
case time.Time:
return v.Format(timeFormat)
case error:
return v.Error()
case fmt.Stringer:
return v.String()
default:
return v
}
}
func escapeString(s string) string {
needQuotes := false
e := bytes.Buffer{}
e.WriteByte('"')
for _, r := range s {
if r <= ' ' || r == '=' || r == '"' {
needQuotes = true
}
switch r {
case '\\', '"':
e.WriteByte('\\')
e.WriteByte(byte(r))
case '\n':
e.WriteByte('\\')
e.WriteByte('n')
case '\r':
e.WriteByte('\\')
e.WriteByte('r')
case '\t':
e.WriteByte('\\')
e.WriteByte('t')
default:
e.WriteRune(r)
}
}
e.WriteByte('"')
start, stop := 0, e.Len()
if !needQuotes {
start, stop = 1, stop-1
}
return string(e.Bytes()[start:stop])
}
func logfmt(buf *bytes.Buffer, ctx []interface{}, color int) {
for i := 0; i < len(ctx); i += 2 {
if i != 0 {
buf.WriteByte(' ')
}
k, ok := ctx[i].(string)
v := formatLogfmtValue(ctx[i+1])
if !ok {
k, v = errorKey, formatLogfmtValue(k)
}
// XXX: we should probably check that all of your key bytes aren't invalid
if color > 0 {
fmt.Fprintf(buf, "\x1b[%dm%s\x1b[0m=%s", color, k, v)
} else {
fmt.Fprintf(buf, "%s=%s", k, v)
}
}
buf.WriteByte('\n')
}
================================================
FILE: vendor/github.com/kevinburke/handlers/logger_slog.go
================================================
//go:build go1.21
// +build go1.21
package handlers
import (
"log/slog"
"os"
"golang.org/x/term"
)
// NewLogger returns a new customizable Logger, with the same initial settings
// as the package Logger. Compared with a default log15.Logger, the 40-char
// spacing gap between the message and the first key is omitted, and timestamps
// are written with more precision.
func NewLogger() *slog.Logger {
return NewLoggerLevel(slog.LevelInfo)
}
// NewLoggerLevel returns a Logger with our customized settings, set to log
// messages at or more critical than the given level.
func NewLoggerLevel(lvl slog.Level) *slog.Logger {
// TODO add colorized logger
if term.IsTerminal(int(os.Stdout.Fd())) {
return slog.Default()
} else {
return slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
Level: lvl,
}))
}
}
================================================
FILE: vendor/github.com/kevinburke/handlers/regex_handler.go
================================================
package handlers
import (
"fmt"
"net/http"
"regexp"
"strings"
"github.com/kevinburke/rest"
)
type route struct {
pattern *regexp.Regexp
methods []string
handler http.Handler
}
// A RegexpHandler is a simple http.Handler that can match regular expressions
// for routes.
type Regexp struct {
routes []*route
}
// Handle calls the provided handler for requests whose URL matches the given
// pattern and HTTP method. The first matching route will get called. If methods
// is nil, all HTTP methods will be allowed. If GET is in the list of methods,
// HEAD requests will also be allowed.
func (h *Regexp) Handle(pattern *regexp.Regexp, methods []string, handler http.Handler) {
h.routes = append(h.routes, &route{
pattern: pattern,
methods: methods,
handler: handler,
})
}
// HandleString is like Handle, but will compile s to a regexp first.
// If s is not a valid regexp HandleString will panic.
func (h *Regexp) HandleString(s string, methods []string, handler http.Handler) {
rx, err := regexp.Compile(s)
if err != nil {
panic(fmt.Sprintf("handlers: could not compile pattern %q to a regex: got error %v", s, err))
}
h.Handle(rx, methods, handler)
}
// HandleFunc calls the provided HandlerFunc for requests whose URL matches the
// given pattern and HTTP method. The first matching route will get called.
// If methods is nil, all HTTP methods are allowed. If GET is in the list of
// methods, HEAD requests will also be allowed.
func (h *Regexp) HandleFunc(pattern *regexp.Regexp, methods []string, handler func(http.ResponseWriter, *http.Request)) {
h.routes = append(h.routes, &route{
pattern: pattern,
methods: methods,
handler: http.HandlerFunc(handler),
})
}
// HandleStringFunc is like HandleFunc, but will compile s to a regexp first.
// If s is not a valid regexp HandleStringFunc will panic.
func (h *Regexp) HandleStringFunc(s string, methods []string, handler func(http.ResponseWriter, *http.Request)) {
rx, err := regexp.Compile(s)
if err != nil {
panic(fmt.Sprintf("handlers: could not compile pattern %q to a regex: got error %v", s, err))
}
h.HandleFunc(rx, methods, handler)
}
var allMethods = []string{
"GET",
"POST",
"PUT",
"PATCH",
"DELETE",
"CONNECT",
"TRACE",
}
// ServeHTTP checks all registered routes in turn for a match, and calls
// handler.ServeHTTP on the first matching handler. If no routes match,
// StatusMethodNotAllowed will be rendered.
func (h *Regexp) ServeHTTP(w http.ResponseWriter, r *http.Request) {
upperMethod := strings.ToUpper(r.Method)
allowed := make([]string, 0)
oneMatch := false
for _, route := range h.routes {
if route.pattern.MatchString(r.URL.Path) {
oneMatch = true
if route.methods == nil && upperMethod != "OPTIONS" {
route.handler.ServeHTTP(w, r)
return
}
for _, method := range route.methods {
upper := strings.ToUpper(method)
if upper == upperMethod || upperMethod == "HEAD" && upper == "GET" {
route.handler.ServeHTTP(w, r)
return
}
}
if upperMethod == "OPTIONS" {
allowed = append(allowed, route.methods...)
}
}
}
if upperMethod == "OPTIONS" {
var methods string
if len(allowed) > 0 {
methods = strings.Join(append(allowed, "OPTIONS"), ", ")
} else {
methods = strings.Join(append(allMethods, "OPTIONS"), ", ")
}
w.Header().Set("Allow", methods)
return
}
if oneMatch {
rest.NotAllowed(w, r)
} else {
rest.NotFound(w, r)
}
}
================================================
FILE: vendor/github.com/kevinburke/nacl/.gitignore
================================================
/bazel-*
================================================
FILE: vendor/github.com/kevinburke/nacl/CHANGELOG.md
================================================
# Changelog
## 0.7
Replace golang.org/x/crypto/ed25519 with crypto/ed25519.
## 0.4
Add KeySize, NonceSize constants.
Update Makefile to be smarter about dependencies. Update rules_go to version
0.5.3.
================================================
FILE: vendor/github.com/kevinburke/nacl/LICENSE
================================================
Copyright (c) 2017 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: vendor/github.com/kevinburke/nacl/Makefile
================================================
SHELL = /bin/bash -o pipefail
BENCHSTAT := $(GOPATH)/bin/benchstat
BUMP_VERSION := $(GOPATH)/bin/bump_version
GODOCDOC := $(GOPATH)/bin/godocdoc
STATICCHECK := $(GOPATH)/bin/staticcheck
test: vet
@# this target should always be listed first so "make" runs the tests.
go test -trimpath ./...
$(STATICCHECK):
GO111MODULE=on go install honnef.co/go/tools/cmd/staticcheck@latest
check: $(STATICCHECK)
$(STATICCHECK) ./...
race-test:
go test -trimpath -race ./...
vet:
go vet -trimpath ./...
$(GODOCDOC):
go get github.com/kevinburke/godocdoc
docs: $(GODOCDOC)
$(GODOCDOC)
$(BENCHSTAT):
go get golang.org/x/perf/cmd/benchstat
bench: $(BENCHSTAT)
go test -trimpath -count=3 -benchtime=2s -bench=. -run='^$$' ./... | $(BENCHSTAT) /dev/stdin
$(BUMP_VERSION):
go get github.com/kevinburke/bump_version
release: check race-test | $(BUMP_VERSION)
$(BUMP_VERSION) --tag-prefix=v minor nacl.go
================================================
FILE: vendor/github.com/kevinburke/nacl/README.md
================================================
# go-nacl
[](https://godoc.org/github.com/kevinburke/nacl)
This is a pure Go implementation of the API's available in NaCL:
https://nacl.cr.yp.to. Compared with the implementation in
golang.org/x/crypto/nacl, this library offers *all* of the API's present in
NaCL, better compatibility with NaCL implementations written in other languages,
as well as some utilities for generating and loading keys and nonces, and
encrypting messages.
Many of them are simple wrappers around functions or libraries available in the
Go standard library, or in the golang.org/x/crypto package. Other code I copied
directly into this library with the appropriate LICENSE; if a function is longer
than, say, 5 lines, I didn't write it myself. There are no dependencies outside
of the standard library or golang.org/x/crypto.
The goal is to both show how to implement the NaCL functions in pure Go, and
to provide interoperability between messages encrypted/hashed/authenticated in
other languages, and available in Go.
Among other benefits, NaCL is designed to be misuse resistant and standardizes
on the use of 32 byte keys and 24 byte nonces everywhere. Several helpers are
present for generating keys/nonces and loading them from configuration, as well
as for encrypting messages. You can generate a key by running `openssl rand -hex
32` and use the helpers in your program like so:
```go
import "github.com/kevinburke/nacl"
import "github.com/kevinburke/nacl/secretbox"
func main() {
key, err := nacl.Load("6368616e676520746869732070617373776f726420746f206120736563726574")
if err != nil {
panic(err)
}
encrypted := secretbox.EasySeal([]byte("hello world"), key)
fmt.Println(base64.StdEncoding.EncodeToString(encrypted))
}
```
The package names match the primitives available in NaCL, with the `crypto_`
prefix removed. Some function names have been changed to match the Go
conventions.
### Installation
```
go get github.com/kevinburke/nacl
```
Or you can Git clone the code directly to $GOPATH/src/github.com/kevinburke/nacl.
### Who am I?
While you probably shouldn't trust random security code from the Internet,
I'm reasonably confident that this code is secure. I did not implement any
of the hard math (poly1305, XSalsa20, curve25519) myself - I call into
golang.org/x/crypto for all of those functions. I also ported over every test
I could find from the C/C++ code, and associated RFC's, and ensured that these
libraries passed those tests.
I'm [a contributor to the Go Standard Library and associated
tools][contributor], and I've also been paid to do [security
consulting][services] for startups, and [found security problems in consumer
sites][capital-one].
[contributor]: https://go-review.googlesource.com/q/owner:kev%2540inburke.com
[capital-one]: https://burke.services/capital-one-open-redirect.html
[services]: https://burke.services
### Errata
- The implementation of `crypto_sign` uses the `ref10` implementation of ed25519
from SUPERCOP, *not* the current implementation in NaCL. The difference is that
the entire 64-byte signature is prepended to the message; in the current version
of NaCL, separate bits are prepended and appended to the message.
- Compared with `crypto/ed25519`, this library's Sign
implementation returns the message along with the signature, and Verify
expects the first 64 bytes of the message to be the signature. This simplifies
the API and matches the behavior of the ref10 implementation and other NaCL
implementations. Sign also flips the order of the message and the private key:
`Sign(message, privatekey)`, to match the NaCL implementation.
- Compared with `golang.org/x/crypto/nacl/box`, `Precompute` returns the shared
key instead of modifying the input. In several places the code was modified to
call functions that now exist in `nacl`.
- Compared with `golang.org/x/crypto/nacl/secretbox`, `Seal` and `Open`
call the `onetimeauth` package in this library, instead of calling
`golang.org/x/crypto/poly1305` directly.
================================================
FILE: vendor/github.com/kevinburke/nacl/internal/subtle/aliasing.go
================================================
// Copyright 2018 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.
// +build !appengine
// Package subtle implements functions that are often useful in cryptographic
// code but require careful thought to use correctly.
package subtle // import "github.com/kevinburke/nacl/internal/subtle"
import "unsafe"
// AnyOverlap reports whether x and y share memory at any (not necessarily
// corresponding) index. The memory beyond the slice length is ignored.
func AnyOverlap(x, y []byte) bool {
return len(x) > 0 && len(y) > 0 &&
uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) &&
uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1]))
}
// InexactOverlap reports whether x and y share memory at any non-corresponding
// index. The memory beyond the slice length is ignored. Note that x and y can
// have different lengths and still not have any inexact overlap.
//
// InexactOverlap can be used to implement the requirements of the crypto/cipher
// AEAD, Block, BlockMode and Stream interfaces.
func InexactOverlap(x, y []byte) bool {
if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
return false
}
return AnyOverlap(x, y)
}
================================================
FILE: vendor/github.com/kevinburke/nacl/internal/subtle/aliasing_appengine.go
================================================
// Copyright 2018 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.
// +build appengine
// Package subtle implements functions that are often useful in cryptographic
// code but require careful thought to use correctly.
package subtle // import "github.com/kevinburke/nacl/internal/subtle"
// This is the Google App Engine standard variant based on reflect
// because the unsafe package and cgo are disallowed.
import "reflect"
// AnyOverlap reports whether x and y share memory at any (not necessarily
// corresponding) index. The memory beyond the slice length is ignored.
func AnyOverlap(x, y []byte) bool {
return len(x) > 0 && len(y) > 0 &&
reflect.ValueOf(&x[0]).Pointer() <= reflect.ValueOf(&y[len(y)-1]).Pointer() &&
reflect.ValueOf(&y[0]).Pointer() <= reflect.ValueOf(&x[len(x)-1]).Pointer()
}
// InexactOverlap reports whether x and y share memory at any non-corresponding
// index. The memory beyond the slice length is ignored. Note that x and y can
// have different lengths and still not have any inexact overlap.
//
// InexactOverlap can be used to implement the requirements of the crypto/cipher
// AEAD, Block, BlockMode and Stream interfaces.
func InexactOverlap(x, y []byte) bool {
if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
return false
}
return AnyOverlap(x, y)
}
================================================
FILE: vendor/github.com/kevinburke/nacl/nacl.go
================================================
// Package nacl is a pure Go implementation of the NaCL cryptography library.
//
// Compared with the implementation in golang.org/x/crypto/nacl, this library
// offers all of the API's present in NaCL, as well as some utilities for
// generating and loading keys and nonces, and encrypting messages.
//
// NaCl's goal is to provide all of the core operations needed to build
// higher-level cryptographic tools, as well as to demonstrate how to implement
// these tools in Go.
//
// Compared with the equivalent packages in the Go standard library and x/crypto
// package, we replace some function calls with their equivalents in this
// package, and make more use of return values (versus writing to a byte array
// specified at stdin). Most functions should be compatible with their C/C++
// counterparts in the library here: https://nacl.cr.yp.to/. In many cases the
// tests are ported directly to this library.
package nacl
import (
"crypto/sha512"
"crypto/subtle"
"encoding/hex"
"fmt"
"github.com/kevinburke/nacl/randombytes"
"golang.org/x/crypto/salsa20/salsa"
)
// The software version.
const Version = "0.9.0"
// Size of a public or private key in bytes.
const KeySize = 32
// Size of a nonce in bytes.
const NonceSize = 24
// Key represents a private or public key for use in encryption or
// authentication. A key should be random bytes and *not* simply 32 characters
// in the visible ASCII set.
type Key *[KeySize]byte
// Nonce is an arbitrary value that should be used only once per (sender,
// receiver) pair. For example, the lexicographically smaller public key can
// use nonce 1 for its first message to the other key, nonce 3 for its second
// message, nonce 5 for its third message, etc., while the lexicographically
// larger public key uses nonce 2 for its first message to the other key, nonce
// 4 for its second message, nonce 6 for its third message, etc. Nonces are long
// enough that randomly generated nonces have negligible risk of collision.
type Nonce *[NonceSize]byte
// Load decodes a 64-byte hex string into a Key. A hex key is suitable for
// representation in a configuration file. You can generate one by running
// "openssl rand -hex 32".
func Load(hexkey string) (Key, error) {
if len(hexkey) != 64 {
return nil, fmt.Errorf("nacl: incorrect hex key length: %d, should be 64", len(hexkey))
}
keyBytes, err := hex.DecodeString(hexkey)
if err != nil {
return nil, err
}
if len(keyBytes) != KeySize {
return nil, fmt.Errorf("nacl: incorrect key length: %d", len(keyBytes))
}
key := new([KeySize]byte)
copy(key[:], keyBytes)
return key, nil
}
// Load decodes a 128-byte hex string into a Key. A hex key is suitable for
// representation in a configuration file. You can generate one by running
// nacl/sign.GenerateKey(nil).
func Load64(hexkey string) (*[64]byte, error) {
if len(hexkey) != 128 {
return nil, fmt.Errorf("nacl: incorrect hex key length: %d, should be 64", len(hexkey))
}
keyBytes, err := hex.DecodeString(hexkey)
if err != nil {
return nil, err
}
if len(keyBytes) != 64 {
return nil, fmt.Errorf("nacl: incorrect key length: %d", len(keyBytes))
}
key := new([64]byte)
copy(key[:], keyBytes)
return key, nil
}
// NewKey returns a new Key with cryptographically random data. NewKey panics if
// we could not read the correct amount of random data into key.
func NewKey() Key {
key := new([KeySize]byte)
randombytes.MustRead(key[:])
return key
}
// NewNonce returns a new Nonce with cryptographically random data. It panics if
// we could not read the correct amount of random data into nonce.
func NewNonce() Nonce {
nonce := new([NonceSize]byte)
randombytes.MustRead(nonce[:])
return nonce
}
// Verify returns true if and only if a and b have equal contents. The time
// taken is a function of the length of the slices and is independent of the
// contents. If an attacker controls the length of a, they may be able to
// determine the length of b (and vice versa).
func Verify(a, b []byte) bool {
return subtle.ConstantTimeCompare(a, b) == 1
}
// Verify16 returns true if and only if a and b have equal contents, without
// leaking timing information.
func Verify16(a, b *[16]byte) bool {
if a == nil || b == nil {
panic("nacl: nil input")
}
return subtle.ConstantTimeCompare(a[:], b[:]) == 1
}
// Verify32 returns true if and only if a and b have equal contents, without
// leaking timing information.
func Verify32(a, b *[KeySize]byte) bool {
if a == nil || b == nil {
panic("nacl: nil input")
}
return subtle.ConstantTimeCompare(a[:], b[:]) == 1
}
// HashSize is the size, in bytes, of the result of calling Hash.
const HashSize = sha512.Size
// Hash hashes a message m.
//
// The crypto_hash function is designed to be usable as a strong component of
// DSA, RSA-PSS, key derivation, hash-based message-authentication codes,
// hash-based ciphers, and various other common applications. "Strong" means
// that the security of these applications, when instantiated with crypto_hash,
// is the same as the security of the applications against generic attacks.
// In particular, the crypto_hash function is designed to make finding
// collisions difficult.
//
// Hash is currently an implementation of SHA-512.
func Hash(m []byte) *[HashSize]byte {
out := sha512.Sum512(m)
return &out
}
// Setup produces a sub-key and Salsa20 counter given a nonce and key.
func Setup(nonce Nonce, key Key) (Key, *[16]byte) {
// We use XSalsa20 for encryption so first we need to generate a
// key and nonce with HSalsa20.
var hNonce [16]byte
copy(hNonce[:], nonce[:])
var subKey [32]byte
salsa.HSalsa20(&subKey, &hNonce, key, &salsa.Sigma)
// The final 8 bytes of the original nonce form the new nonce.
var counter [16]byte
copy(counter[:], nonce[16:])
return &subKey, &counter
}
================================================
FILE: vendor/github.com/kevinburke/nacl/onetimeauth/onetimeauth.go
================================================
// Package onetimeauth provides primitives for secret-key, single-message
// authentication.
//
// The onetimeauth function, viewed as a function of the message for a
// uniform random key, is designed to meet the standard notion of unforgeability
// after a single message. After the sender authenticates one message, an
// attacker cannot find authenticators for any other messages.
//
// The sender must not use onetimeauth to authenticate more than one message
// under the same key. Authenticators for two messages under the same key should
// be expected to reveal enough information to allow forgeries of authenticators
// on other messages.
//
// The selected primitive is poly1305, an authenticator specified in
// "Cryptography in NaCl", Section 9. This authenticator is proven to meet the
// standard notion of unforgeability after a single message.
//
// This package is interoperable with NaCL: https://nacl.cr.yp.to/onetimeauth.html
package onetimeauth
import (
"github.com/kevinburke/nacl"
//lint:ignore SA1019 Poly1305 usage is safe for our specific cryptographic building block use case
"golang.org/x/crypto/poly1305"
)
// Size is the size, in bytes, of the result of a call to Sum.
const Size = poly1305.TagSize
// Sum generates an authenticator for m using a one-time key and puts the result
// (of length Size) into out.
// Authenticating two different messages with the same key allows an attacker to
// forge messages at will.
func Sum(m []byte, key nacl.Key) *[Size]byte {
out := new([Size]byte)
poly1305.Sum(out, m, key)
return out
}
// Verify returns true if mac is a valid authenticator for m with the given
// key, without leaking timing information.
func Verify(mac *[Size]byte, m []byte, key nacl.Key) bool {
return poly1305.Verify(mac, m, key)
}
================================================
FILE: vendor/github.com/kevinburke/nacl/randombytes/randombytes.go
================================================
// Package randombytes implements helpers for reading random data.
package randombytes
import (
"crypto/rand"
"strconv"
)
// Read fills in with random data.
func Read(in []byte) (int, error) {
return rand.Read(in)
}
// MustRead fills in entirely with random data, or panics.
func MustRead(in []byte) {
n, err := Read(in)
if err != nil {
panic(err)
}
if n != len(in) {
panic("did not read enough random data: only " + strconv.Itoa(n) + " bytes")
}
}
================================================
FILE: vendor/github.com/kevinburke/nacl/secretbox/secretbox.go
================================================
// Copyright 2012 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.
/*
Package secretbox encrypts and authenticates small messages.
Secretbox uses XSalsa20 and Poly1305 to encrypt and authenticate messages with
secret-key cryptography. The length of messages is not hidden.
It is the caller's responsibility to ensure the uniqueness of nonces—for
example, by using nonce 1 for the first message, nonce 2 for the second
message, etc. Nonces are long enough that randomly generated nonces have
negligible risk of collision.
Messages should be small because:
1. The whole message needs to be held in memory to be processed.
2. Using large messages pressures implementations on small machines to decrypt
and process plaintext before authenticating it. This is very dangerous, and
this API does not allow it, but a protocol that uses excessive message sizes
might present some implementations with no other choice.
3. Fixed overheads will be sufficiently amortised by messages as small as 8KB.
4. Performance may be improved by working with messages that fit into data caches.
Thus large amounts of data should be chunked so that each message is small.
(Each message still needs a unique nonce.) If in doubt, 16KB is a reasonable
chunk size.
This package is interoperable with NaCl: https://nacl.cr.yp.to/secretbox.html.
*/
package secretbox // import "github.com/kevinburke/nacl/secretbox"
import (
"errors"
"github.com/kevinburke/nacl"
"github.com/kevinburke/nacl/internal/subtle"
"github.com/kevinburke/nacl/onetimeauth"
"golang.org/x/crypto/salsa20/salsa"
)
// Overhead is the number of bytes of overhead when boxing a message.
const Overhead = onetimeauth.Size
// sliceForAppend takes a slice and a requested number of bytes. It returns a
// slice with the contents of the given slice followed by that many bytes and a
// second slice that aliases into it and contains only the extra bytes. If the
// original slice has sufficient capacity then no allocation is performed.
func sliceForAppend(in []byte, n int) (head, tail []byte) {
if total := len(in) + n; cap(in) >= total {
head = in[:total]
} else {
head = make([]byte, total)
copy(head, in)
}
tail = head[len(in):]
return
}
// EasySeal encrypts message using key. A 24-byte nonce is generated and
// prepended to the output. The key and nonce pair must be unique for each
// distinct message, and the output will be Overhead+24 bytes longer than
// message.
func EasySeal(message []byte, key nacl.Key) []byte {
nonce := nacl.NewNonce()
return Seal(nonce[:], message, nonce, key)
}
// Seal appends an encrypted and authenticated copy of message to out, which
// must not overlap message. The key and nonce pair must be unique for each
// distinct message and the output will be Overhead bytes longer than message.
func Seal(out, message []byte, nonce nacl.Nonce, key nacl.Key) []byte {
subKey, counter := nacl.Setup(nonce, key)
// The Poly1305 key is generated by encrypting 32 bytes of zeros. Since
// Salsa20 works with 64-byte blocks, we also generate 32 bytes of
// keystream as a side effect.
var firstBlock [64]byte
salsa.XORKeyStream(firstBlock[:], firstBlock[:], counter, subKey)
var poly1305Key [32]byte
copy(poly1305Key[:], firstBlock[:])
ret, out := sliceForAppend(out, len(message)+onetimeauth.Size)
if subtle.AnyOverlap(out, message) {
panic("nacl: invalid buffer overlap")
}
// We XOR up to 32 bytes of message with the keystream generated from
// the first block.
firstMessageBlock := message
if len(firstMessageBlock) > 32 {
firstMessageBlock = firstMessageBlock[:32]
}
tagOut := out
out = out[onetimeauth.Size:]
for i, x := range firstMessageBlock {
out[i] = firstBlock[32+i] ^ x
}
message = message[len(firstMessageBlock):]
ciphertext := out
out = out[len(firstMessageBlock):]
// Now encrypt the rest.
counter[8] = 1
salsa.XORKeyStream(out, message, counter, subKey)
tag := onetimeauth.Sum(ciphertext, &poly1305Key)
copy(tagOut, tag[:])
return ret
}
var errInvalidInput = errors.New("secretbox: Could not decrypt invalid input")
// EasyOpen decrypts box using key. We assume a 24-byte nonce is prepended to
// the encrypted text in box. The key and nonce pair must be unique for each
// distinct message.
func EasyOpen(box []byte, key nacl.Key) ([]byte, error) {
if len(box) < 24 {
return nil, errors.New("secretbox: message too short")
}
decryptNonce := new([24]byte)
copy(decryptNonce[:], box[:24])
decrypted, ok := Open([]byte{}, box[24:], decryptNonce, key)
if !ok {
return nil, errInvalidInput
}
return decrypted, nil
}
// Open authenticates and decrypts a box produced by Seal and appends the
// message to out, which must not overlap box. The output will be Overhead
// bytes smaller than box.
func Open(out, box []byte, nonce nacl.Nonce, key nacl.Key) ([]byte, bool) {
if len(box) < Overhead {
return nil, false
}
subKey, counter := nacl.Setup(nonce, key)
// The Poly1305 key is generated by encrypting 32 bytes of zeros. Since
// Salsa20 works with 64-byte blocks, we also generate 32 bytes of
// keystream as a side effect.
var firstBlock [64]byte
salsa.XORKeyStream(firstBlock[:], firstBlock[:], counter, subKey)
var poly1305Key [32]byte
copy(poly1305Key[:], firstBlock[:])
var tag [onetimeauth.Size]byte
copy(tag[:], box)
if !onetimeauth.Verify(&tag, box[onetimeauth.Size:], &poly1305Key) {
return nil, false
}
ret, out := sliceForAppend(out, len(box)-Overhead)
// We XOR up to 32 bytes of box with the keystream generated from
// the first block.
box = box[Overhead:]
firstMessageBlock := box
if len(firstMessageBlock) > 32 {
firstMessageBlock = firstMessageBlock[:32]
}
for i, x := range firstMessageBlock {
out[i] = firstBlock[32+i] ^ x
}
box = box[len(firstMessageBlock):]
out = out[len(firstMessageBlock):]
// Now decrypt the rest.
counter[8] = 1
salsa.XORKeyStream(out, box, counter, subKey)
return ret, true
}
================================================
FILE: vendor/github.com/kevinburke/rest/.gitignore
================================================
/bazel-*
/*.out
================================================
FILE: vendor/github.com/kevinburke/rest/CHANGELOG.md
================================================
## 2.8
Replace Client.Token with Client.Token(). Add new SetToken() method to allow
updating the token.
Replace handlers.Logger with the new `log/slog` package in the standard library.
Log lines are not printed in color as a result.
## 2.6
Add Client.NewRequestWithContext to mirror http.NewRequestWithContext.
## 2.5
Add back DefaultErrorParser, NewBearerClient (these got missed in the move).
## 2.3
Move rest.Client to new restclient package, and rest.Error to a new resterror
package. If you would like to remove the 3rd party dependencies like log15 from
your client code, change imports as follows:
```
rest.Error => resterror.Error
rest.NewClient => restclient.New
rest.Client => restclient.Client
rest.DefaultTransport => restclient.DefaultTransport
```
The old imports should still work the same way as before thanks to aliasing.
## 2.2
Support Bearer authentication.
If the `path` value in `*Client.NewRequest()` begins with `Client.Base` (e.g.
`client.NewRequest("GET", "https://api.github.com"), it will be stripped before
making the request.
## 2.1
Remove Bazel for testing purposes.
## 2.0
- rest.Error.StatusCode has been renamed to rest.Error.Status to match the
change in the accepted RFC.
- rest.Client no longer has a default timeout. Use context.Context to specify
a timeout for HTTP requests.
- Add rest.Gone for 410 responses.
================================================
FILE: vendor/github.com/kevinburke/rest/LICENSE
================================================
Copyright (c) 2016 Shyp, Inc.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: vendor/github.com/kevinburke/rest/Makefile
================================================
SHELL = /bin/bash -o pipefail
BUMP_VERSION := $(GOPATH)/bin/bump_version
STATICCHECK := $(GOPATH)/bin/staticcheck
deps:
go get -u ./...
test-deps:
go get -t -v ./...
test: lint
go test ./...
lint: | $(STATICCHECK)
go vet ./...
$(STATICCHECK) ./...
$(STATICCHECK):
go install honnef.co/go/tools/cmd/staticcheck@latest
race-test: lint
go test -race ./...
$(BUMP_VERSION):
go install github.com/kevinburke/bump_version
release: race-test | $(BUMP_VERSION)
$(BUMP_VERSION) --tag-prefix=v minor restclient/client.go
ci: test-deps lint race-test
================================================
FILE: vendor/github.com/kevinburke/rest/README.md
================================================
# rest
This library contains a HTTP client, and a number of useful middlewares for
writing a HTTP client and server in Go. For more information and package
documentation, please [see the godoc documentation][gddo].
### Client
The `Client` struct makes it easy to interact with a JSON API.
```go
client := restclient.New("username", "password", "http://ipinfo.io")
req, _ := client.NewRequest("GET", "/json", nil)
type resp struct {
City string `json:"city"`
Ip string `json:"ip"`
}
var r resp
client.Do(req, &r)
fmt.Println(r.Ip)
```
### Transport
Use the `restclient.Transport` as the `http.Transport` to easily inspect the raw
HTTP request and response. Set `DEBUG_HTTP_TRAFFIC=true` in your environment to
dump HTTP requests and responses to stderr.
### Defining Custom Error Responses
`rest` exposes a number of HTTP error handlers - for example,
`rest.ServerError(w, r, err)` will write a 500 server error to w. By default,
these error handlers will write a generic JSON response over the wire, using
fields specified by the [HTTP problem spec][spec].
You can define a custom error handler if you like (say if you want to return
a HTML server error, or 404 error or similar) by calling RegisterHandler:
```go
rest.RegisterHandler(500, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
err := rest.CtxErr(r)
fmt.Println("Server error:", err)
w.Header().Set("Content-Type", "text/html")
w.WriteHeader(500)
w.Write([]byte("Server Error"))
}))
```
[spec]: https://tools.ietf.org/html/draft-ietf-appsawg-http-problem-03
### Debugging
Set the `DEBUG_HTTP_TRAFFIC` environment variable to print out all
request/response traffic being made by the client.
`rest` also includes a `Transport` that is a drop in for a `http.Transport`,
but includes support for debugging HTTP requests. Add it like so:
```go
client := http.Client{
Transport: &restclient.Transport{
Debug: true,
Output: os.Stderr,
Transport: http.DefaultTransport,
},
}
```
## Donating
Donations free up time to make improvements to the library, and respond to
bug reports. You can send donations via Paypal's "Send Money" feature to
kev@inburke.com. Donations are not tax deductible in the USA.
[gddo]: https://godoc.org/github.com/kevinburke/rest
================================================
FILE: vendor/github.com/kevinburke/rest/ctx.go
================================================
// +build go1.7
package rest
import (
"context"
"net/http"
)
type ctxVar int
var errCtx ctxVar = 0
var domainCtx ctxVar = 1
// CtxErr returns an error that's been stored in the Request context.
func CtxErr(r *http.Request) error {
val := r.Context().Value(errCtx)
if val == nil {
return nil
}
return val.(error)
}
// ctxSetErr sets err in the request context, and returns the new request.
func ctxSetErr(r *http.Request, err error) *http.Request {
return r.WithContext(context.WithValue(r.Context(), errCtx, err))
}
// CtxDomain returns a domain that's been set on the request. Use it to get the
// domain set on a 401 error handler.
func CtxDomain(r *http.Request) string {
val := r.Context().Value(domainCtx)
if val == nil {
return ""
}
return val.(string)
}
// ctxSetDomain sets a domain in the request context, and returns the new
// request.
func ctxSetDomain(r *http.Request, domain string) *http.Request {
return r.WithContext(context.WithValue(r.Context(), domainCtx, domain))
}
================================================
FILE: vendor/github.com/kevinburke/rest/noctx.go
================================================
// +build !go1.7
package rest
import "net/http"
// CtxErr returns an error that's been stored in the Request context. This is
// a no-op in older versions of Go.
func CtxErr(r *http.Request) error {
return nil
}
// ctxSetErr sets err in the request context, and returns the new request.
func ctxSetErr(r *http.Request, err error) *http.Request {
Logger.Info("cannot set error in context", "err", err)
return r
}
// CtxDomain returns a domain that's been set on the request. This is a no-op
// in older versions of Go.
func CtxDomain(r *http.Request) string {
return ""
}
// ctxSetDomain sets a domain in the request context, and returns the new
// request.
func ctxSetDomain(r *http.Request, domain string) *http.Request {
Logger.Info("cannot set domain in context", "domain", domain)
return r
}
================================================
FILE: vendor/github.com/kevinburke/rest/rest.go
================================================
// Package rest implements responses and a HTTP client for API consumption.
package rest
import (
"encoding/json"
"fmt"
"net/http"
"sync"
"github.com/kevinburke/rest/restclient"
"github.com/kevinburke/rest/resterror"
)
type (
// Backwards compatibility
Error = resterror.Error
Client = restclient.Client
Transport = restclient.Transport
UploadType = restclient.UploadType
)
var (
NewClient = restclient.New
NewBearerClient = restclient.NewBearerClient
DefaultTransport = restclient.DefaultTransport
JSON = restclient.JSON
FormURLEncoded = restclient.FormURLEncoded
Version = restclient.Version
DefaultErrorParser = restclient.DefaultErrorParser
)
const jsonContentType = "application/json; charset=utf-8"
var (
handlerMap = make(map[int]http.Handler)
handlerMu sync.RWMutex
)
// RegisterHandler registers the given HandlerFunc to serve HTTP requests for
// the given status code. Use CtxErr and CtxDomain to retrieve extra values set
// on the request in f (if any).
//
// Despite registering the handler for the code, f is responsible for calling
// WriteHeader(code) since it may want to set response headers first.
//
// To delete a Handler, call RegisterHandler with nil for the second argument.
func RegisterHandler(code int, f http.Handler) {
handlerMu.Lock()
defer handlerMu.Unlock()
switch f {
case nil:
delete(handlerMap, code)
default:
handlerMap[code] = f
}
}
// ServerError logs the error to the Logger, and then responds to the request
// with a generic 500 server error message. ServerError panics if err is nil.
func ServerError(w http.ResponseWriter, r *http.Request, err error) {
handlerMu.RLock()
f, ok := handlerMap[http.StatusInternalServerError]
handlerMu.RUnlock()
if ok {
r = ctxSetErr(r, err)
f.ServeHTTP(w, r)
} else {
defaultServerError(w, r, err)
}
}
var serverError = Error{
Status: http.StatusInternalServerError,
ID: "server_error",
Title: "Unexpected server error. Please try again",
}
func defaultServerError(w http.ResponseWriter, r *http.Request, err error) {
if err == nil {
panic("rest: no error to log")
}
Logger.Error("Server error", "code", 500, "method", r.Method, "path", r.URL.Path, "err", err)
w.Header().Set("Content-Type", jsonContentType)
w.WriteHeader(http.StatusInternalServerError)
if err := json.NewEncoder(w).Encode(serverError); err != nil {
Logger.Info("Couldn't write error", "path", r.URL.Path, "code", 500, "err", err)
}
}
var notFound = Error{
Title: "Resource not found",
ID: "not_found",
Status: http.StatusNotFound,
}
// NotFound returns a 404 Not Found error to the client.
func NotFound(w http.ResponseWriter, r *http.Request) {
handlerMu.RLock()
f, ok := handlerMap[http.StatusNotFound]
handlerMu.RUnlock()
if ok {
f.ServeHTTP(w, r)
} else {
defaultNotFound(w, r)
}
}
func defaultNotFound(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", jsonContentType)
w.WriteHeader(http.StatusNotFound)
nf := notFound
nf.Instance = r.URL.Path
if err := json.NewEncoder(w).Encode(nf); err != nil {
Logger.Info("Couldn't write error", "path", r.URL.Path, "code", 404, "err", err)
}
}
// BadRequest logs a 400 error and then returns a 400 response to the client.
func BadRequest(w http.ResponseWriter, r *http.Request, err *Error) {
handlerMu.RLock()
f, ok := handlerMap[http.StatusBadRequest]
handlerMu.RUnlock()
if ok {
r = ctxSetErr(r, err)
f.ServeHTTP(w, r)
} else {
defaultBadRequest(w, r, err)
}
}
var gone = Error{
Title: "Resource is gone",
ID: "gone",
Status: http.StatusGone,
}
// Gone responds to the request with a 410 Gone error message
func Gone(w http.ResponseWriter, r *http.Request) {
handlerMu.RLock()
f, ok := handlerMap[http.StatusGone]
handlerMu.RUnlock()
if ok {
f.ServeHTTP(w, r)
} else {
defaultGone(w, r)
}
}
func defaultGone(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", jsonContentType)
w.WriteHeader(http.StatusGone)
g := gone
g.Instance = r.URL.Path
if err := json.NewEncoder(w).Encode(g); err != nil {
Logger.Info("Couldn't write error", "path", r.URL.Path, "code", 404, "err", err)
}
}
func defaultBadRequest(w http.ResponseWriter, r *http.Request, err *Error) {
if err == nil {
panic("rest: no error to write")
}
if err.Status == 0 {
err.Status = http.StatusBadRequest
}
Logger.Info("Bad request", "code", 400, "method", r.Method, "path", r.URL.Path, "err", err)
w.Header().Set("Content-Type", jsonContentType)
w.WriteHeader(http.StatusBadRequest)
if err := json.NewEncoder(w).Encode(err); err != nil {
Logger.Info("Couldn't write error", "path", r.URL.Path, "code", 400, "err", err)
}
}
var notAllowed = Error{
Title: "Method not allowed",
ID: "method_not_allowed",
Status: http.StatusMethodNotAllowed,
}
var authenticate = Error{
Title: "Unauthorized. Please include your API credentials",
ID: "unauthorized",
Status: http.StatusUnauthorized,
}
// NotAllowed returns a generic HTTP 405 Not Allowed status and response body
// to the client.
func NotAllowed(w http.ResponseWriter, r *http.Request) {
handlerMu.RLock()
f, ok := handlerMap[http.StatusMethodNotAllowed]
handlerMu.RUnlock()
if ok {
f.ServeHTTP(w, r)
} else {
defaultNotAllowed(w, r)
}
}
func defaultNotAllowed(w http.ResponseWriter, r *http.Request) {
e := notAllowed
e.Instance = r.URL.Path
w.Header().Set("Content-Type", jsonContentType)
w.WriteHeader(http.StatusMethodNotAllowed)
if err := json.NewEncoder(w).Encode(e); err != nil {
Logger.Info("Couldn't write error", "path", r.URL.Path, "code", 405, "err", err)
}
}
// Forbidden returns a 403 Forbidden status code to the client, with the given
// Error object in the response body.
func Forbidden(w http.ResponseWriter, r *http.Request, err *Error) {
handlerMu.RLock()
f, ok := handlerMap[http.StatusForbidden]
handlerMu.RUnlock()
if ok {
r = ctxSetErr(r, err)
f.ServeHTTP(w, r)
} else {
defaultForbidden(w, r, err)
}
}
func defaultForbidden(w http.ResponseWriter, r *http.Request, err *Error) {
if err.ID == "" {
err.ID = "forbidden"
}
w.Header().Set("Content-Type", jsonContentType)
w.WriteHeader(http.StatusForbidden)
if err := json.NewEncoder(w).Encode(err); err != nil {
Logger.Info("Couldn't write error", "path", r.URL.Path, "code", 403, "err", err)
}
}
// NoContent returns a 204 No Content message.
func NoContent(w http.ResponseWriter) {
// No custom handler since there's no custom behavior.
w.Header().Del("Content-Type")
w.WriteHeader(http.StatusNoContent)
}
// Unauthorized sets the Domain in the request context
func Unauthorized(w http.ResponseWriter, r *http.Request, domain string) {
handlerMu.RLock()
f, ok := handlerMap[http.StatusUnauthorized]
handlerMu.RUnlock()
if ok {
r = ctxSetDomain(r, domain)
f.ServeHTTP(w, r)
} else {
defaultUnauthorized(w, r, domain)
}
}
func defaultUnauthorized(w http.ResponseWriter, r *http.Request, domain string) {
err := authenticate
err.Instance = r.URL.Path
w.Header().Set("WWW-Authenticate", fmt.Sprintf(`Basic realm="%s"`, domain))
w.Header().Set("Content-Type", jsonContentType)
w.WriteHeader(http.StatusUnauthorized)
if err := json.NewEncoder(w).Encode(err); err != nil {
Logger.Info("Couldn't write error", "path", r.URL.Path, "code", 401, "err", err)
}
}
================================================
FILE: vendor/github.com/kevinburke/rest/rest_noslog.go
================================================
//go:build !go1.21
// +build !go1.21
package rest
import log "github.com/inconshreveable/log15/v3"
// Logger logs information about incoming requests.
var Logger log.Logger = log.New()
================================================
FILE: vendor/github.com/kevinburke/rest/rest_slog.go
================================================
//go:build go1.21
// +build go1.21
package rest
import (
"log/slog"
"os"
)
func init() {
h := slog.NewTextHandler(os.Stderr, nil)
Logger = slog.New(h)
}
// Logger logs information about incoming requests.
var Logger *slog.Logger
================================================
FILE: vendor/github.com/kevinburke/rest/restclient/client.go
================================================
package restclient
import (
"context"
"encoding/json"
"fmt"
"io"
"net"
"net/http"
"runtime"
"strings"
"sync/atomic"
"time"
"github.com/kevinburke/rest/resterror"
)
type UploadType string
// JSON specifies you'd like to upload JSON data.
var JSON UploadType = "application/json"
// FormURLEncoded specifies you'd like to upload form-urlencoded data.
var FormURLEncoded UploadType = "application/x-www-form-urlencoded"
const Version = "2.12.0"
var ua string
func init() {
gv := strings.Replace(runtime.Version(), "go", "", 1)
ua = fmt.Sprintf("rest-client/%s (https://github.com/kevinburke/rest) go/%s (%s/%s)",
Version, gv, runtime.GOOS, runtime.GOARCH)
}
// Client is a generic Rest client for making HTTP requests.
type Client struct {
// Username for use in HTTP Basic Auth
ID string
// HTTP Client to use for making requests
Client *http.Client
// The base URL for all requests to this API, for example,
// "https://fax.twilio.com/v1"
Base string
// Set UploadType to JSON or FormURLEncoded to control how data is sent to
// the server. Defaults to FormURLEncoded.
UploadType UploadType
// ErrorParser is invoked when the client gets a 400-or-higher status code
// from the server. Defaults to rest.DefaultErrorParser.
ErrorParser func(*http.Response) error
useBearerAuth bool
// Password for use in HTTP Basic Auth, or single token in Bearer auth
token atomic.Value
}
func (c *Client) Token() string {
l := c.token.Load()
s, _ := l.(string)
return s
}
// New returns a new Client with HTTP Basic Auth with the given user and
// password. Base is the scheme+domain to hit for all requests.
func New(user, pass, base string) *Client {
c := &Client{
ID: user,
Client: defaultHttpClient,
Base: base,
UploadType: JSON,
ErrorParser: DefaultErrorParser,
}
c.token.Store(pass)
return c
}
// NewBearerClient returns a new Client configured to use Bearer authentication.
func NewBearerClient(token, base string) *Client {
c := &Client{
ID: "",
Client: defaultHttpClient,
Base: base,
UploadType: JSON,
ErrorParser: DefaultErrorParser,
useBearerAuth: true,
}
c.token.Store(token)
return c
}
func (c *Client) UpdateToken(newToken string) {
c.token.Store(newToken)
}
var defaultDialer = &net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}
// DialSocket configures c to use the provided socket and http.Transport to
// dial a Unix socket instead of a TCP port.
//
// If transport is nil, the settings from DefaultTransport are used.
func (c *Client) DialSocket(socket string, transport *http.Transport) {
dialSock := func(ctx context.Context, proto, addr string) (conn net.Conn, err error) {
return defaultDialer.DialContext(ctx, "unix", socket)
}
if transport == nil {
ht := http.DefaultTransport.(*http.Transport)
transport = &http.Transport{
Proxy: ht.Proxy,
MaxIdleConns: ht.MaxIdleConns,
IdleConnTimeout: ht.IdleConnTimeout,
TLSHandshakeTimeout: ht.TLSHandshakeTimeout,
ExpectContinueTimeout: ht.ExpectContinueTimeout,
DialContext: dialSock,
}
}
if c.Client == nil {
// need to copy this so we don't modify the default client
c.Client = &http.Client{
Timeout: defaultHttpClient.Timeout,
}
}
switch tp := c.Client.Transport.(type) {
// TODO both of these cases clobbber the existing transport which isn't
// ideal.
case nil, *Transport:
c.Client.Transport = &Transport{
RoundTripper: transport,
Debug: DefaultTransport.Debug,
Output: DefaultTransport.Output,
}
case *http.Transport:
c.Client.Transport = transport
default:
panic(fmt.Sprintf("could not set DialSocket on unknown transport: %#v", tp))
}
}
func (c *Client) NewRequestWithContext(ctx context.Context, method, path string, body io.Reader) (*http.Request, error) {
if c == nil {
panic("cannot call NewRequestWithContext on nil *Client")
}
// see for example https://github.com/meterup/github-release/issues/1 - if
// the path contains the full URL including the base, strip it out
path = strings.TrimPrefix(path, c.Base)
req, err := http.NewRequestWithContext(ctx, method, c.Base+path, body)
if err != nil {
return nil, err
}
token := c.Token()
switch {
case c.useBearerAuth && token != "":
req.Header.Add("Authorization", "Bearer "+token)
case !c.useBearerAuth && (c.ID != "" || token != ""):
req.SetBasicAuth(c.ID, token)
}
req.Header.Add("User-Agent", ua)
req.Header.Add("Accept", "application/json")
req.Header.Add("Accept-Charset", "utf-8")
if method == "POST" || method == "PUT" {
uploadType := c.UploadType
if uploadType == "" {
uploadType = JSON
}
req.Header.Add("Content-Type", string(uploadType)+"; charset=utf-8")
}
return req, nil
}
// NewRequest creates a new Request and sets basic auth based on the client's
// authentication information.
func (c *Client) NewRequest(method, path string, body io.Reader) (*http.Request, error) {
return c.NewRequestWithContext(context.Background(), method, path, body)
}
// Do performs the HTTP request. If the HTTP response is in the 2xx range,
// Unmarshal the response body into v. If the response status code is 400 or
// above, attempt to Unmarshal the response into an Error. Otherwise return
// a generic http error.
func (c *Client) Do(r *http.Request, v interface{}) error {
var res *http.Response
var err error
if c.Client == nil {
res, err = defaultHttpClient.Do(r)
} else {
res, err = c.Client.Do(r)
}
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode >= 400 {
if c.ErrorParser != nil {
return c.ErrorParser(res)
}
return DefaultErrorParser(res)
}
resBody, err := io.ReadAll(res.Body)
if err != nil {
return err
}
if v == nil || res.StatusCode == http.StatusNoContent {
return nil
} else {
return json.Unmarshal(resBody, v)
}
}
// DefaultErrorParser attempts to parse the response body as a rest.Error. If
// it cannot do so, return an error containing the entire response body.
func DefaultErrorParser(resp *http.Response) error {
resBody, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
defer resp.Body.Close()
rerr := new(resterror.Error)
err = json.Unmarshal(resBody, rerr)
if err != nil {
return fmt.Errorf("invalid response body: %s", string(resBody))
}
if rerr.Title == "" {
return fmt.Errorf("invalid response body: %s", string(resBody))
} else {
rerr.Status = resp.StatusCode
return rerr
}
}
================================================
FILE: vendor/github.com/kevinburke/rest/restclient/transport.go
================================================
package restclient
import (
"bytes"
"io"
"net/http"
"net/http/httputil"
"os"
)
// DefaultTransport is like http.DefaultTransport, but prints the contents of
// HTTP requests to os.Stderr if the DEBUG_HTTP_TRAFFIC environment variable is
// set to true.
var DefaultTransport *Transport
var defaultHttpClient *http.Client
func init() {
DefaultTransport = &Transport{
RoundTripper: http.DefaultTransport,
Debug: os.Getenv("DEBUG_HTTP_TRAFFIC") == "true",
Output: os.Stderr,
}
defaultHttpClient = &http.Client{
Transport: DefaultTransport,
}
}
// Transport implements HTTP round trips, but adds hooks for debugging the HTTP
// request.
type Transport struct {
// The underlying RoundTripper.
RoundTripper http.RoundTripper
// Whether to write the HTTP request and response contents to Output.
Debug bool
// If Debug is true, write the HTTP request and response contents here. If
// Output is nil, os.Stderr will be used.
Output io.Writer
}
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
if t == nil {
panic("nil Transport")
}
var w io.ReadWriter = nil
if t.Debug {
w = new(bytes.Buffer)
bits, err := httputil.DumpRequestOut(req, true)
if err != nil {
return nil, err
}
if len(bits) > 0 && bits[len(bits)-1] != '\n' {
bits = append(bits, '\n')
}
w.Write(bits)
}
var res *http.Response
var err error
if t.RoundTripper == nil {
res, err = http.DefaultTransport.RoundTrip(req)
} else {
res, err = t.RoundTripper.RoundTrip(req)
}
if err != nil {
return res, err
}
if t.Debug {
bits, err := httputil.DumpResponse(res, true)
if err != nil {
return res, err
}
if len(bits) > 0 && bits[len(bits)-1] != '\n' {
bits = append(bits, '\n')
}
w.Write(bits)
if t.Output == nil {
t.Output = os.Stderr
}
_, err = io.Copy(t.Output, w)
if err != nil {
return res, err
}
}
return res, err
}
================================================
FILE: vendor/github.com/kevinburke/rest/resterror/resterror.go
================================================
package resterror
import "fmt"
// Error implements the HTTP Problem spec laid out here:
// https://tools.ietf.org/html/rfc7807
type Error struct {
// The main error message. Should be short enough to fit in a phone's
// alert box. Do not end this message with a period.
Title string `json:"title"`
// Id of this error message ("forbidden", "invalid_parameter", etc)
ID string `json:"id"`
// More information about what went wrong.
Detail string `json:"detail,omitempty"`
// Path to the object that's in error.
Instance string `json:"instance,omitempty"`
// Link to more information about the error (Zendesk, API docs, etc).
Type string `json:"type,omitempty"`
// HTTP status code of the error.
Status int `json:"status,omitempty"`
}
func (e *Error) Error() string {
return e.Title
}
func (e *Error) String() string {
if e.Detail != "" {
return fmt.Sprintf("rest: %s. %s", e.Title, e.Detail)
} else {
return fmt.Sprintf("rest: %s", e.Title)
}
}
================================================
FILE: vendor/github.com/mattn/go-colorable/LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2016 Yasuhiro Matsumoto
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: vendor/github.com/mattn/go-colorable/README.md
================================================
# go-colorable
[](https://github.com/mattn/go-colorable/actions?query=workflow%3Atest)
[](https://codecov.io/gh/mattn/go-colorable)
[](http://godoc.org/github.com/mattn/go-colorable)
[](https://goreportcard.com/report/mattn/go-colorable)
Colorable writer for windows.
For example, most of logger packages doesn't show colors on windows. (I know we can do it with ansicon. But I don't want.)
This package is possible to handle escape sequence for ansi color on windows.
## Too Bad!

## So Good!

## Usage
```go
logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true})
logrus.SetOutput(colorable.NewColorableStdout())
logrus.Info("succeeded")
logrus.Warn("not correct")
logrus.Error("something error")
logrus.Fatal("panic")
```
You can compile above code on non-windows OSs.
## Installation
```
$ go get github.com/mattn/go-colorable
```
# License
MIT
# Author
Yasuhiro Matsumoto (a.k.a mattn)
================================================
FILE: vendor/github.com/mattn/go-colorable/colorable_others.go
================================================
//go:build !windows || appengine
// +build !windows appengine
package colorable
import (
"io"
"os"
_ "github.com/mattn/go-isatty"
)
// NewColorable returns new instance of Writer which handles escape sequence.
func NewColorable(file *os.File) io.Writer {
if file == nil {
panic("nil passed instead of *os.File to NewColorable()")
}
return file
}
// NewColorableStdout returns new instance of Writer which handles escape sequence for stdout.
func NewColorableStdout() io.Writer {
return os.Stdout
}
// NewColorableStderr returns new instance of Writer which handles escape sequence for stderr.
func NewColorableStderr() io.Writer {
return os.Stderr
}
// EnableColorsStdout enable colors if possible.
func EnableColorsStdout(enabled *bool) func() {
if enabled != nil {
*enabled = true
}
return func() {}
}
================================================
FILE: vendor/github.com/mattn/go-colorable/colorable_windows.go
================================================
//go:build windows && !appengine
// +build windows,!appengine
package colorable
import (
"bytes"
"io"
"math"
"os"
"strconv"
"strings"
"sync"
syscall "golang.org/x/sys/windows"
"unsafe"
"github.com/mattn/go-isatty"
)
const (
foregroundBlue = 0x1
foregroundGreen = 0x2
foregroundRed = 0x4
foregroundIntensity = 0x8
foregroundMask = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity)
backgroundBlue = 0x10
backgroundGreen = 0x20
backgroundRed = 0x40
backgroundIntensity = 0x80
backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity)
commonLvbUnderscore = 0x8000
cENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4
)
const (
genericRead = 0x80000000
genericWrite = 0x40000000
)
const (
consoleTextmodeBuffer = 0x1
)
type wchar uint16
type short int16
type dword uint32
type word uint16
type coord struct {
x short
y short
}
type smallRect struct {
left short
top short
right short
bottom short
}
type consoleScreenBufferInfo struct {
size coord
cursorPosition coord
attributes word
window smallRect
maximumWindowSize coord
}
type consoleCursorInfo struct {
size dword
visible int32
}
var (
kernel32 = syscall.NewLazySystemDLL("kernel32.dll")
procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute")
procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition")
procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute")
procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo")
procSetConsoleCursorInfo = kernel32.NewProc("SetConsoleCursorInfo")
procSetConsoleTitle = kernel32.NewProc("SetConsoleTitleW")
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
procCreateConsoleScreenBuffer = kernel32.NewProc("CreateConsoleScreenBuffer")
)
// writer provides colorable Writer to the console
type writer struct {
out io.Writer
handle syscall.Handle
althandle syscall.Handle
oldattr word
oldpos coord
rest bytes.Buffer
mutex sync.Mutex
}
// NewColorable returns new instance of writer which handles escape sequence from File.
func NewColorable(file *os.File) io.Writer {
if file == nil {
panic("nil passed instead of *os.File to NewColorable()")
}
if isatty.IsTerminal(file.Fd()) {
var mode uint32
if r, _, _ := procGetConsoleMode.Call(file.Fd(), uintptr(unsafe.Pointer(&mode))); r != 0 && mode&cENABLE_VIRTUAL_TERMINAL_PROCESSING != 0 {
return file
}
var csbi consoleScreenBufferInfo
handle := syscall.Handle(file.Fd())
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
return &writer{out: file, handle: handle, oldattr: csbi.attributes, oldpos: coord{0, 0}}
}
return file
}
// NewColorableStdout returns new instance of writer which handles escape sequence for stdout.
func NewColorableStdout() io.Writer {
return NewColorable(os.Stdout)
}
// NewColorableStderr returns new instance of writer which handles escape sequence for stderr.
func NewColorableStderr() io.Writer {
return NewColorable(os.Stderr)
}
var color256 = map[int]int{
0: 0x000000,
1: 0x800000,
2: 0x008000,
3: 0x808000,
4: 0x000080,
5: 0x800080,
6: 0x008080,
7: 0xc0c0c0,
8: 0x808080,
9: 0xff0000,
10: 0x00ff00,
11: 0xffff00,
12: 0x0000ff,
13: 0xff00ff,
14: 0x00ffff,
15: 0xffffff,
16: 0x000000,
17: 0x00005f,
18: 0x000087,
19: 0x0000af,
20: 0x0000d7,
21: 0x0000ff,
22: 0x005f00,
23: 0x005f5f,
24: 0x005f87,
25: 0x005faf,
26: 0x005fd7,
27: 0x005fff,
28: 0x008700,
29: 0x00875f,
30: 0x008787,
31: 0x0087af,
32: 0x0087d7,
33: 0x0087ff,
34: 0x00af00,
35: 0x00af5f,
36: 0x00af87,
37: 0x00afaf,
38: 0x00afd7,
39: 0x00afff,
40: 0x00d700,
41: 0x00d75f,
42: 0x00d787,
43: 0x00d7af,
44: 0x00d7d7,
45: 0x00d7ff,
46: 0x00ff00,
47: 0x00ff5f,
48: 0x00ff87,
49: 0x00ffaf,
50: 0x00ffd7,
51: 0x00ffff,
52: 0x5f0000,
53: 0x5f005f,
54: 0x5f0087,
55: 0x5f00af,
56: 0x5f00d7,
57: 0x5f00ff,
58: 0x5f5f00,
59: 0x5f5f5f,
60: 0x5f5f87,
61: 0x5f5faf,
62: 0x5f5fd7,
63: 0x5f5fff,
64: 0x5f8700,
65: 0x5f875f,
66: 0x5f8787,
67: 0x5f87af,
68: 0x5f87d7,
69: 0x5f87ff,
70: 0x5faf00,
71: 0x5faf5f,
72: 0x5faf87,
73: 0x5fafaf,
74: 0x5fafd7,
75: 0x5fafff,
76: 0x5fd700,
77: 0x5fd75f,
78: 0x5fd787,
79: 0x5fd7af,
80: 0x5fd7d7,
81: 0x5fd7ff,
82: 0x5fff00,
83: 0x5fff5f,
84: 0x5fff87,
85: 0x5fffaf,
86: 0x5fffd7,
87: 0x5fffff,
88: 0x870000,
89: 0x87005f,
90: 0x870087,
91: 0x8700af,
92: 0x8700d7,
93: 0x8700ff,
94: 0x875f00,
95: 0x875f5f,
96: 0x875f87,
97: 0x875faf,
98: 0x875fd7,
99: 0x875fff,
100: 0x878700,
101: 0x87875f,
102: 0x878787,
103: 0x8787af,
104: 0x8787d7,
105: 0x8787ff,
106: 0x87af00,
107: 0x87af5f,
108: 0x87af87,
109: 0x87afaf,
110: 0x87afd7,
111: 0x87afff,
112: 0x87d700,
113: 0x87d75f,
114: 0x87d787,
115: 0x87d7af,
116: 0x87d7d7,
117: 0x87d7ff,
118: 0x87ff00,
119: 0x87ff5f,
120: 0x87ff87,
121: 0x87ffaf,
122: 0x87ffd7,
123: 0x87ffff,
124: 0xaf0000,
125: 0xaf005f,
126: 0xaf0087,
127: 0xaf00af,
128: 0xaf00d7,
129: 0xaf00ff,
130: 0xaf5f00,
131: 0xaf5f5f,
132: 0xaf5f87,
133: 0xaf5faf,
134: 0xaf5fd7,
135: 0xaf5fff,
136: 0xaf8700,
137: 0xaf875f,
138: 0xaf8787,
139: 0xaf87af,
140: 0xaf87d7,
141: 0xaf87ff,
142: 0xafaf00,
143: 0xafaf5f,
144: 0xafaf87,
145: 0xafafaf,
146: 0xafafd7,
147: 0xafafff,
148: 0xafd700,
149: 0xafd75f,
150: 0xafd787,
151: 0xafd7af,
152: 0xafd7d7,
153: 0xafd7ff,
154: 0xafff00,
155: 0xafff5f,
156: 0xafff87,
157: 0xafffaf,
158: 0xafffd7,
159: 0xafffff,
160: 0xd70000,
161: 0xd7005f,
162: 0xd70087,
163: 0xd700af,
164: 0xd700d7,
165: 0xd700ff,
166: 0xd75f00,
167: 0xd75f5f,
168: 0xd75f87,
169: 0xd75faf,
170: 0xd75fd7,
171: 0xd75fff,
172: 0xd78700,
173: 0xd7875f,
174: 0xd78787,
175: 0xd787af,
176: 0xd787d7,
177: 0xd787ff,
178: 0xd7af00,
179: 0xd7af5f,
180: 0xd7af87,
181: 0xd7afaf,
182: 0xd7afd7,
183: 0xd7afff,
184: 0xd7d700,
185: 0xd7d75f,
186: 0xd7d787,
187: 0xd7d7af,
188: 0xd7d7d7,
189: 0xd7d7ff,
190: 0xd7ff00,
191: 0xd7ff5f,
192: 0xd7ff87,
193: 0xd7ffaf,
194: 0xd7ffd7,
195: 0xd7ffff,
196: 0xff0000,
197: 0xff005f,
198: 0xff0087,
199: 0xff00af,
200: 0xff00d7,
201: 0xff00ff,
202: 0xff5f00,
203: 0xff5f5f,
204: 0xff5f87,
205: 0xff5faf,
206: 0xff5fd7,
207: 0xff5fff,
208: 0xff8700,
209: 0xff875f,
210: 0xff8787,
211: 0xff87af,
212: 0xff87d7,
213: 0xff87ff,
214: 0xffaf00,
215: 0xffaf5f,
216: 0xffaf87,
217: 0xffafaf,
218: 0xffafd7,
219: 0xffafff,
220: 0xffd700,
221: 0xffd75f,
222: 0xffd787,
223: 0xffd7af,
224: 0xffd7d7,
225: 0xffd7ff,
226: 0xffff00,
227: 0xffff5f,
228: 0xffff87,
229: 0xffffaf,
230: 0xffffd7,
231: 0xffffff,
232: 0x080808,
233: 0x121212,
234: 0x1c1c1c,
235: 0x262626,
236: 0x303030,
237: 0x3a3a3a,
238: 0x444444,
239: 0x4e4e4e,
240: 0x585858,
241: 0x626262,
242: 0x6c6c6c,
243: 0x767676,
244: 0x808080,
245: 0x8a8a8a,
246: 0x949494,
247: 0x9e9e9e,
248: 0xa8a8a8,
249: 0xb2b2b2,
250: 0xbcbcbc,
251: 0xc6c6c6,
252: 0xd0d0d0,
253: 0xdadada,
254: 0xe4e4e4,
255: 0xeeeeee,
}
// `\033]0;TITLESTR\007`
func doTitleSequence(er *bytes.Reader) error {
var c byte
var err error
c, err = er.ReadByte()
if err != nil {
return err
}
if c != '0' && c != '2' {
return nil
}
c, err = er.ReadByte()
if err != nil {
return err
}
if c != ';' {
return nil
}
title := make([]byte, 0, 80)
for {
c, err = er.ReadByte()
if err != nil {
return err
}
if c == 0x07 || c == '\n' {
break
}
title = append(title, c)
}
if len(title) > 0 {
title8, err := syscall.UTF16PtrFromString(string(title))
if err == nil {
procSetConsoleTitle.Call(uintptr(unsafe.Pointer(title8)))
}
}
return nil
}
// returns Atoi(s) unless s == "" in which case it returns def
func atoiWithDefault(s string, def int) (int, error) {
if s == "" {
return def, nil
}
return strconv.Atoi(s)
}
// Write writes data on console
func (w *writer) Write(data []byte) (n int, err error) {
w.mutex.Lock()
defer w.mutex.Unlock()
var csbi consoleScreenBufferInfo
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
handle := w.handle
var er *bytes.Reader
if w.rest.Len() > 0 {
var rest bytes.Buffer
w.rest.WriteTo(&rest)
w.rest.Reset()
rest.Write(data)
er = bytes.NewReader(rest.Bytes())
} else {
er = bytes.NewReader(data)
}
var plaintext bytes.Buffer
loop:
for {
c1, err := er.ReadByte()
if err != nil {
plaintext.WriteTo(w.out)
break loop
}
if c1 != 0x1b {
plaintext.WriteByte(c1)
continue
}
_, err = plaintext.WriteTo(w.out)
if err != nil {
break loop
}
c2, err := er.ReadByte()
if err != nil {
break loop
}
switch c2 {
case '>':
continue
case ']':
w.rest.WriteByte(c1)
w.rest.WriteByte(c2)
er.WriteTo(&w.rest)
if bytes.IndexByte(w.rest.Bytes(), 0x07) == -1 {
break loop
}
er = bytes.NewReader(w.rest.Bytes()[2:])
err := doTitleSequence(er)
if err != nil {
break loop
}
w.rest.Reset()
continue
// https://github.com/mattn/go-colorable/issues/27
case '7':
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
w.oldpos = csbi.cursorPosition
continue
case '8':
procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&w.oldpos)))
continue
case 0x5b:
// execute part after switch
default:
continue
}
w.rest.WriteByte(c1)
w.rest.WriteByte(c2)
er.WriteTo(&w.rest)
var buf bytes.Buffer
var m byte
for i, c := range w.rest.Bytes()[2:] {
if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
m = c
er = bytes.NewReader(w.rest.Bytes()[2+i+1:])
w.rest.Reset()
break
}
buf.Write([]byte(string(c)))
}
if m == 0 {
break loop
}
switch m {
case 'A':
n, err = atoiWithDefault(buf.String(), 1)
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.y -= short(n)
procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'B':
n, err = atoiWithDefault(buf.String(), 1)
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.y += short(n)
procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'C':
n, err = atoiWithDefault(buf.String(), 1)
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.x += short(n)
procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'D':
n, err = atoiWithDefault(buf.String(), 1)
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.x -= short(n)
if csbi.cursorPosition.x < 0 {
csbi.cursorPosition.x = 0
}
procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'E':
n, err = atoiWithDefault(buf.String(), 1)
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.x = 0
csbi.cursorPosition.y += short(n)
procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'F':
n, err = atoiWithDefault(buf.String(), 1)
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.x = 0
csbi.cursorPosition.y -= short(n)
procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'G':
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
if n < 1 {
n = 1
}
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.x = short(n - 1)
procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'H', 'f':
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
if buf.Len() > 0 {
token := strings.Split(buf.String(), ";")
switch len(token) {
case 1:
n1, err := strconv.Atoi(token[0])
if err != nil {
continue
}
csbi.cursorPosition.y = short(n1 - 1)
case 2:
n1, err := strconv.Atoi(token[0])
if err != nil {
continue
}
n2, err := strconv.Atoi(token[1])
if err != nil {
continue
}
csbi.cursorPosition.x = short(n2 - 1)
csbi.cursorPosition.y = short(n1 - 1)
}
} else {
csbi.cursorPosition.y = 0
}
procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'J':
n := 0
if buf.Len() > 0 {
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
}
var count, written dword
var cursor coord
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
switch n {
case 0:
cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y}
count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.size.y-csbi.cursorPosition.y)*dword(csbi.size.x)
case 1:
cursor = coord{x: csbi.window.left, y: csbi.window.top}
count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.window.top-csbi.cursorPosition.y)*dword(csbi.size.x)
case 2:
cursor = coord{x: csbi.window.left, y: csbi.window.top}
count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.size.y-csbi.cursorPosition.y)*dword(csbi.size.x)
}
procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
case 'K':
n := 0
if buf.Len() > 0 {
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
}
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
var cursor coord
var count, written dword
switch n {
case 0:
cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y}
count = dword(csbi.size.x - csbi.cursorPosition.x)
case 1:
cursor = coord{x: csbi.window.left, y: csbi.cursorPosition.y}
count = dword(csbi.size.x - csbi.cursorPosition.x)
case 2:
cursor = coord{x: csbi.window.left, y: csbi.cursorPosition.y}
count = dword(csbi.size.x)
}
procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
case 'X':
n := 0
if buf.Len() > 0 {
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
}
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
var cursor coord
var written dword
cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y}
procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(n), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(n), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
case 'm':
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
attr := csbi.attributes
cs := buf.String()
if cs == "" {
procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(w.oldattr))
continue
}
token := strings.Split(cs, ";")
for i := 0; i < len(token); i++ {
ns := token[i]
if n, err = strconv.Atoi(ns); err == nil {
switch {
case n == 0 || n == 100:
attr = w.oldattr
case n == 4:
attr |= commonLvbUnderscore
case (1 <= n && n <= 3) || n == 5:
attr |= foregroundIntensity
case n == 7 || n == 27:
attr =
(attr &^ (foregroundMask | backgroundMask)) |
((attr & foregroundMask) << 4) |
((attr & backgroundMask) >> 4)
case n == 22:
attr &^= foregroundIntensity
case n == 24:
attr &^= commonLvbUnderscore
case 30 <= n && n <= 37:
attr &= backgroundMask
if (n-30)&1 != 0 {
attr |= foregroundRed
}
if (n-30)&2 != 0 {
attr |= foregroundGreen
}
if (n-30)&4 != 0 {
attr |= foregroundBlue
}
case n == 38: // set foreground color.
if i < len(token)-2 && (token[i+1] == "5" || token[i+1] == "05") {
if n256, err := strconv.Atoi(token[i+2]); err == nil {
if n256foreAttr == nil {
n256setup()
}
attr &= backgroundMask
attr |= n256foreAttr[n256%len(n256foreAttr)]
i += 2
}
} else if len(token) == 5 && token[i+1] == "2" {
var r, g, b int
r, _ = strconv.Atoi(token[i+2])
g, _ = strconv.Atoi(token[i+3])
b, _ = strconv.Atoi(token[i+4])
i += 4
if r > 127 {
attr |= foregroundRed
}
if g > 127 {
attr |= foregroundGreen
}
if b > 127 {
attr |= foregroundBlue
}
} else {
attr = attr & (w.oldattr & backgroundMask)
}
case n == 39: // reset foreground color.
attr &= backgroundMask
attr |= w.oldattr & foregroundMask
case 40 <= n && n <= 47:
attr &= foregroundMask
if (n-40)&1 != 0 {
attr |= backgroundRed
}
if (n-40)&2 != 0 {
attr |= backgroundGreen
}
if (n-40)&4 != 0 {
attr |= backgroundBlue
}
case n == 48: // set background color.
if i < len(token)-2 && token[i+1] == "5" {
if n256, err := strconv.Atoi(token[i+2]); err == nil {
if n256backAttr == nil {
n256setup()
}
attr &= foregroundMask
attr |= n256backAttr[n256%len(n256backAttr)]
i += 2
}
} else if len(token) == 5 && token[i+1] == "2" {
var r, g, b int
r, _ = strconv.Atoi(token[i+2])
g, _ = strconv.Atoi(token[i+3])
b, _ = strconv.Atoi(token[i+4])
i += 4
if r > 127 {
attr |= backgroundRed
}
if g > 127 {
attr |= backgroundGreen
}
if b > 127 {
attr |= backgroundBlue
}
} else {
attr = attr & (w.oldattr & foregroundMask)
}
case n == 49: // reset foreground color.
attr &= foregroundMask
attr |= w.oldattr & backgroundMask
case 90 <= n && n <= 97:
attr = (attr & backgroundMask)
attr |= foregroundIntensity
if (n-90)&1 != 0 {
attr |= foregroundRed
}
if (n-90)&2 != 0 {
attr |= foregroundGreen
}
if (n-90)&4 != 0 {
attr |= foregroundBlue
}
case 100 <= n && n <= 107:
attr = (attr & foregroundMask)
attr |= backgroundIntensity
if (n-100)&1 != 0 {
attr |= backgroundRed
}
if (n-100)&2 != 0 {
attr |= backgroundGreen
}
if (n-100)&4 != 0 {
attr |= backgroundBlue
}
}
procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(attr))
}
}
case 'h':
var ci consoleCursorInfo
cs := buf.String()
if cs == "5>" {
procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
ci.visible = 0
procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
} else if cs == "?25" {
procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
ci.visible = 1
procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
} else if cs == "?1049" {
if w.althandle == 0 {
h, _, _ := procCreateConsoleScreenBuffer.Call(uintptr(genericRead|genericWrite), 0, 0, uintptr(consoleTextmodeBuffer), 0, 0)
w.althandle = syscall.Handle(h)
if w.althandle != 0 {
handle = w.althandle
}
}
}
case 'l':
var ci consoleCursorInfo
cs := buf.String()
if cs == "5>" {
procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
ci.visible = 1
procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
} else if cs == "?25" {
procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
ci.visible = 0
procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
} else if cs == "?1049" {
if w.althandle != 0 {
syscall.CloseHandle(w.althandle)
w.althandle = 0
handle = w.handle
}
}
case 's':
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
w.oldpos = csbi.cursorPosition
case 'u':
procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&w.oldpos)))
}
}
return len(data), nil
}
type consoleColor struct {
rgb int
red bool
green bool
blue bool
intensity bool
}
func (c consoleColor) foregroundAttr() (attr word) {
if c.red {
attr |= foregroundRed
}
if c.green {
attr |= foregroundGreen
}
if c.blue {
attr |= foregroundBlue
}
if c.intensity {
attr |= foregroundIntensity
}
return
}
func (c consoleColor) backgroundAttr() (attr word) {
if c.red {
attr |= backgroundRed
}
if c.green {
attr |= backgroundGreen
}
if c.blue {
attr |= backgroundBlue
}
if c.intensity {
attr |= backgroundIntensity
}
return
}
var color16 = []consoleColor{
{0x000000, false, false, false, false},
{0x000080, false, false, true, false},
{0x008000, false, true, false, false},
{0x008080, false, true, true, false},
{0x800000, true, false, false, false},
{0x800080, true, false, true, false},
{0x808000, true, true, false, false},
{0xc0c0c0, true, true, true, false},
{0x808080, false, false, false, true},
{0x0000ff, false, false, true, true},
{0x00ff00, false, true, false, true},
{0x00ffff, false, true, true, true},
{0xff0000, true, false, false, true},
{0xff00ff, true, false, true, true},
{0xffff00, true, true, false, true},
{0xffffff, true, true, true, true},
}
type hsv struct {
h, s, v float32
}
func (a hsv) dist(b hsv) float32 {
dh := a.h - b.h
switch {
case dh > 0.5:
dh = 1 - dh
case dh < -0.5:
dh = -1 - dh
}
ds := a.s - b.s
dv := a.v - b.v
return float32(math.Sqrt(float64(dh*dh + ds*ds + dv*dv)))
}
func toHSV(rgb int) hsv {
r, g, b := float32((rgb&0xFF0000)>>16)/256.0,
float32((rgb&0x00FF00)>>8)/256.0,
float32(rgb&0x0000FF)/256.0
min, max := minmax3f(r, g, b)
h := max - min
if h > 0 {
if max == r {
h = (g - b) / h
if h < 0 {
h += 6
}
} else if max == g {
h = 2 + (b-r)/h
} else {
h = 4 + (r-g)/h
}
}
h /= 6.0
s := max - min
if max != 0 {
s /= max
}
v := max
return hsv{h: h, s: s, v: v}
}
type hsvTable []hsv
func toHSVTable(rgbTable []consoleColor) hsvTable {
t := make(hsvTable, len(rgbTable))
for i, c := range rgbTable {
t[i] = toHSV(c.rgb)
}
return t
}
func (t hsvTable) find(rgb int) consoleColor {
hsv := toHSV(rgb)
n := 7
l := float32(5.0)
for i, p := range t {
d := hsv.dist(p)
if d < l {
l, n = d, i
}
}
return color16[n]
}
func minmax3f(a, b, c float32) (min, max float32) {
if a < b {
if b < c {
return a, c
} else if a < c {
return a, b
} else {
return c, b
}
} else {
if a < c {
return b, c
} else if b < c {
return b, a
} else {
return c, a
}
}
}
var n256foreAttr []word
var n256backAttr []word
func n256setup() {
n256foreAttr = make([]word, 256)
n256backAttr = make([]word, 256)
t := toHSVTable(color16)
for i, rgb := range color256 {
c := t.find(rgb)
n256foreAttr[i] = c.foregroundAttr()
n256backAttr[i] = c.backgroundAttr()
}
}
// EnableColorsStdout enable colors if possible.
func EnableColorsStdout(enabled *bool) func() {
var mode uint32
h := os.Stdout.Fd()
if r, _, _ := procGetConsoleMode.Call(h, uintptr(unsafe.Pointer(&mode))); r != 0 {
if r, _, _ = procSetConsoleMode.Call(h, uintptr(mode|cENABLE_VIRTUAL_TERMINAL_PROCESSING)); r != 0 {
if enabled != nil {
*enabled = true
}
return func() {
procSetConsoleMode.Call(h, uintptr(mode))
}
}
}
if enabled != nil {
*enabled = true
}
return func() {}
}
================================================
FILE: vendor/github.com/mattn/go-colorable/go.test.sh
================================================
#!/usr/bin/env bash
set -e
echo "" > coverage.txt
for d in $(go list ./... | grep -v vendor); do
go test -race -coverprofile=profile.out -covermode=atomic "$d"
if [ -f profile.out ]; then
cat profile.out >> coverage.txt
rm profile.out
fi
done
================================================
FILE: vendor/github.com/mattn/go-colorable/noncolorable.go
================================================
package colorable
import (
"bytes"
"io"
)
// NonColorable holds writer but removes escape sequence.
type NonColorable struct {
out io.Writer
}
// NewNonColorable returns new instance of Writer which removes escape sequence from Writer.
func NewNonColorable(w io.Writer) io.Writer {
return &NonColorable{out: w}
}
// Write writes data on console
func (w *NonColorable) Write(data []byte) (n int, err error) {
er := bytes.NewReader(data)
var plaintext bytes.Buffer
loop:
for {
c1, err := er.ReadByte()
if err != nil {
plaintext.WriteTo(w.out)
break loop
}
if c1 != 0x1b {
plaintext.WriteByte(c1)
continue
}
_, err = plaintext.WriteTo(w.out)
if err != nil {
break loop
}
c2, err := er.ReadByte()
if err != nil {
break loop
}
if c2 != 0x5b {
continue
}
for {
c, err := er.ReadByte()
if err != nil {
break loop
}
if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
break
}
}
}
return len(data), nil
}
================================================
FILE: vendor/github.com/mattn/go-isatty/LICENSE
================================================
Copyright (c) Yasuhiro MATSUMOTO
MIT License (Expat)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: vendor/github.com/mattn/go-isatty/README.md
================================================
# go-isatty
[](http://godoc.org/github.com/mattn/go-isatty)
[](https://codecov.io/gh/mattn/go-isatty)
[](https://coveralls.io/github/mattn/go-isatty?branch=master)
[](https://goreportcard.com/report/mattn/go-isatty)
isatty for golang
## Usage
```go
package main
import (
"fmt"
"github.com/mattn/go-isatty"
"os"
)
func main() {
if isatty.IsTerminal(os.Stdout.Fd()) {
fmt.Println("Is Terminal")
} else if isatty.IsCygwinTerminal(os.Stdout.Fd()) {
fmt.Println("Is Cygwin/MSYS2 Terminal")
} else {
fmt.Println("Is Not Terminal")
}
}
```
## Installation
```
$ go get github.com/mattn/go-isatty
```
## License
MIT
## Author
Yasuhiro Matsumoto (a.k.a mattn)
## Thanks
* k-takata: base idea for IsCygwinTerminal
https://github.com/k-takata/go-iscygpty
================================================
FILE: vendor/github.com/mattn/go-isatty/doc.go
================================================
// Package isatty implements interface to isatty
package isatty
================================================
FILE: vendor/github.com/mattn/go-isatty/go.test.sh
================================================
#!/usr/bin/env bash
set -e
echo "" > coverage.txt
for d in $(go list ./... | grep -v vendor); do
go test -race -coverprofile=profile.out -covermode=atomic "$d"
if [ -f profile.out ]; then
cat profile.out >> coverage.txt
rm profile.out
fi
done
================================================
FILE: vendor/github.com/mattn/go-isatty/isatty_bsd.go
================================================
//go:build (darwin || freebsd || openbsd || netbsd || dragonfly || hurd) && !appengine && !tinygo
// +build darwin freebsd openbsd netbsd dragonfly hurd
// +build !appengine
// +build !tinygo
package isatty
import "golang.org/x/sys/unix"
// IsTerminal return true if the file descriptor is terminal.
func IsTerminal(fd uintptr) bool {
_, err := unix.IoctlGetTermios(int(fd), unix.TIOCGETA)
return err == nil
}
// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
// terminal. This is also always false on this environment.
func IsCygwinTerminal(fd uintptr) bool {
return false
}
================================================
FILE: vendor/github.com/mattn/go-isatty/isatty_others.go
================================================
//go:build (appengine || js || nacl || tinygo || wasm) && !windows
// +build appengine js nacl tinygo wasm
// +build !windows
package isatty
// IsTerminal returns true if the file descriptor is terminal which
// is always false on js and appengine classic which is a sandboxed PaaS.
func IsTerminal(fd uintptr) bool {
return false
}
// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
// terminal. This is also always false on this environment.
func IsCygwinTerminal(fd uintptr) bool {
return false
}
================================================
FILE: vendor/github.com/mattn/go-isatty/isatty_plan9.go
================================================
//go:build plan9
// +build plan9
package isatty
import (
"syscall"
)
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd uintptr) bool {
path, err := syscall.Fd2path(int(fd))
if err != nil {
return false
}
return path == "/dev/cons" || path == "/mnt/term/dev/cons"
}
// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
// terminal. This is also always false on this environment.
func IsCygwinTerminal(fd uintptr) bool {
return false
}
================================================
FILE: vendor/github.com/mattn/go-isatty/isatty_solaris.go
================================================
//go:build solaris && !appengine
// +build solaris,!appengine
package isatty
import (
"golang.org/x/sys/unix"
)
// IsTerminal returns true if the given file descriptor is a terminal.
// see: https://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libc/port/gen/isatty.c
func IsTerminal(fd uintptr) bool {
_, err := unix.IoctlGetTermio(int(fd), unix.TCGETA)
return err == nil
}
// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
// terminal. This is also always false on this environment.
func IsCygwinTerminal(fd uintptr) bool {
return false
}
================================================
FILE: vendor/github.com/mattn/go-isatty/isatty_tcgets.go
================================================
//go:build (linux || aix || zos) && !appengine && !tinygo
// +build linux aix zos
// +build !appengine
// +build !tinygo
package isatty
import "golang.org/x/sys/unix"
// IsTerminal return true if the file descriptor is terminal.
func IsTerminal(fd uintptr) bool {
_, err := unix.IoctlGetTermios(int(fd), unix.TCGETS)
return err == nil
}
// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
// terminal. This is also always false on this environment.
func IsCygwinTerminal(fd uintptr) bool {
return false
}
================================================
FILE: vendor/github.com/mattn/go-isatty/isatty_windows.go
================================================
//go:build windows && !appengine
// +build windows,!appengine
package isatty
import (
"errors"
"strings"
"syscall"
"unicode/utf16"
"unsafe"
)
const (
objectNameInfo uintptr = 1
fileNameInfo = 2
fileTypePipe = 3
)
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
ntdll = syscall.NewLazyDLL("ntdll.dll")
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
procGetFileInformationByHandleEx = kernel32.NewProc("GetFileInformationByHandleEx")
procGetFileType = kernel32.NewProc("GetFileType")
procNtQueryObject = ntdll.NewProc("NtQueryObject")
)
func init() {
// Check if GetFileInformationByHandleEx is available.
if procGetFileInformationByHandleEx.Find() != nil {
procGetFileInformationByHandleEx = nil
}
}
// IsTerminal return true if the file descriptor is terminal.
func IsTerminal(fd uintptr) bool {
var st uint32
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0
}
// Check pipe name is used for cygwin/msys2 pty.
// Cygwin/MSYS2 PTY has a name like:
// \{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master
func isCygwinPipeName(name string) bool {
token := strings.Split(name, "-")
if len(token) < 5 {
return false
}
if token[0] != `\msys` &&
token[0] != `\cygwin` &&
token[0] != `\Device\NamedPipe\msys` &&
token[0] != `\Device\NamedPipe\cygwin` {
return false
}
if token[1] == "" {
return false
}
if !strings.HasPrefix(token[2], "pty") {
return false
}
if token[3] != `from` && token[3] != `to` {
return false
}
if token[4] != "master" {
return false
}
return true
}
// getFileNameByHandle use the undocomented ntdll NtQueryObject to get file full name from file handler
// since GetFileInformationByHandleEx is not available under windows Vista and still some old fashion
// guys are using Windows XP, this is a workaround for those guys, it will also work on system from
// Windows vista to 10
// see https://stackoverflow.com/a/18792477 for details
func getFileNameByHandle(fd uintptr) (string, error) {
if procNtQueryObject == nil {
return "", errors.New("ntdll.dll: NtQueryObject not supported")
}
var buf [4 + syscall.MAX_PATH]uint16
var result int
r, _, e := syscall.Syscall6(procNtQueryObject.Addr(), 5,
fd, objectNameInfo, uintptr(unsafe.Pointer(&buf)), uintptr(2*len(buf)), uintptr(unsafe.Pointer(&result)), 0)
if r != 0 {
return "", e
}
return string(utf16.Decode(buf[4 : 4+buf[0]/2])), nil
}
// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
// terminal.
func IsCygwinTerminal(fd uintptr) bool {
if procGetFileInformationByHandleEx == nil {
name, err := getFileNameByHandle(fd)
if err != nil {
return false
}
return isCygwinPipeName(name)
}
// Cygwin/msys's pty is a pipe.
ft, _, e := syscall.Syscall(procGetFileType.Addr(), 1, fd, 0, 0)
if ft != fileTypePipe || e != 0 {
return false
}
var buf [2 + syscall.MAX_PATH]uint16
r, _, e := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(),
4, fd, fileNameInfo, uintptr(unsafe.Pointer(&buf)),
uintptr(len(buf)*2), 0, 0)
if r == 0 || e != 0 {
return false
}
l := *(*uint32)(unsafe.Pointer(&buf))
return isCygwinPipeName(string(utf16.Decode(buf[2 : 2+l/2])))
}
================================================
FILE: vendor/golang.org/x/crypto/LICENSE
================================================
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: vendor/golang.org/x/crypto/PATENTS
================================================
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the Go project.
Google hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as stated in this section)
patent license to make, have made, use, offer to sell, sell, import,
transfer and otherwise run, modify and propagate the contents of this
implementation of Go, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of Go. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of Go or any code incorporated within this
implementation of Go constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of Go
shall terminate as of the date such litigation is filed.
================================================
FILE: vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go
================================================
// Copyright 2018 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.
//go:build (!amd64 && !loong64 && !ppc64le && !ppc64 && !s390x) || !gc || purego
package poly1305
type mac struct{ macGeneric }
================================================
FILE: vendor/golang.org/x/crypto/internal/poly1305/poly1305.go
================================================
// Copyright 2012 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.
// Package poly1305 implements Poly1305 one-time message authentication code as
// specified in https://cr.yp.to/mac/poly1305-20050329.pdf.
//
// Poly1305 is a fast, one-time authentication function. It is infeasible for an
// attacker to generate an authenticator for a message without the key. However, a
// key must only be used for a single message. Authenticating two different
// messages with the same key allows an attacker to forge authenticators for other
// messages with the same key.
//
// Poly1305 was originally coupled with AES in order to make Poly1305-AES. AES was
// used with a fixed key in order to generate one-time keys from an nonce.
// However, in this package AES isn't used and the one-time key is specified
// directly.
package poly1305
import "crypto/subtle"
// TagSize is the size, in bytes, of a poly1305 authenticator.
const TagSize = 16
// Sum generates an authenticator for msg using a one-time key and puts the
// 16-byte result into out. Authenticating two different messages with the same
// key allows an attacker to forge messages at will.
func Sum(out *[16]byte, m []byte, key *[32]byte) {
h := New(key)
h.Write(m)
h.Sum(out[:0])
}
// Verify returns true if mac is a valid authenticator for m with the given key.
func Verify(mac *[16]byte, m []byte, key *[32]byte) bool {
var tmp [16]byte
Sum(&tmp, m, key)
return subtle.ConstantTimeCompare(tmp[:], mac[:]) == 1
}
// New returns a new MAC computing an authentication
// tag of all data written to it with the given key.
// This allows writing the message progressively instead
// of passing it as a single slice. Common users should use
// the Sum function instead.
//
// The key must be unique for each message, as authenticating
// two different messages with the same key allows an attacker
// to forge messages at will.
func New(key *[32]byte) *MAC {
m := &MAC{}
initialize(key, &m.macState)
return m
}
// MAC is an io.Writer computing an authentication tag
// of the data written to it.
//
// MAC cannot be used like common hash.Hash implementations,
// because using a poly1305 key twice breaks its security.
// Therefore writing data to a running MAC after calling
// Sum or Verify causes it to panic.
type MAC struct {
mac // platform-dependent implementation
finalized bool
}
// Size returns the number of bytes Sum will return.
func (h *MAC) Size() int { return TagSize }
// Write adds more data to the running message authentication code.
// It never returns an error.
//
// It must not be called after the first call of Sum or Verify.
func (h *MAC) Write(p []byte) (n int, err error) {
if h.finalized {
panic("poly1305: write to MAC after Sum or Verify")
}
return h.mac.Write(p)
}
// Sum computes the authenticator of all data written to the
// message authentication code.
func (h *MAC) Sum(b []byte) []byte {
var mac [TagSize]byte
h.mac.Sum(&mac)
h.finalized = true
return append(b, mac[:]...)
}
// Verify returns whether the authenticator of all data written to
// the message authentication code matches the expected value.
func (h *MAC) Verify(expected []byte) bool {
var mac [TagSize]byte
h.mac.Sum(&mac)
h.finalized = true
return subtle.ConstantTimeCompare(expected, mac[:]) == 1
}
================================================
FILE: vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s
================================================
// Code generated by command: go run sum_amd64_asm.go -out ../sum_amd64.s -pkg poly1305. DO NOT EDIT.
//go:build gc && !purego
// func update(state *macState, msg []byte)
TEXT ·update(SB), $0-32
MOVQ state+0(FP), DI
MOVQ msg_base+8(FP), SI
MOVQ msg_len+16(FP), R15
MOVQ (DI), R8
MOVQ 8(DI), R9
MOVQ 16(DI), R10
MOVQ 24(DI), R11
MOVQ 32(DI), R12
CMPQ R15, $0x10
JB bytes_between_0_and_15
loop:
ADDQ (SI), R8
ADCQ 8(SI), R9
ADCQ $0x01, R10
LEAQ 16(SI), SI
multiply:
MOVQ R11, AX
MULQ R8
MOVQ AX, BX
MOVQ DX, CX
MOVQ R11, AX
MULQ R9
ADDQ AX, CX
ADCQ $0x00, DX
MOVQ R11, R13
IMULQ R10, R13
ADDQ DX, R13
MOVQ R12, AX
MULQ R8
ADDQ AX, CX
ADCQ $0x00, DX
MOVQ DX, R8
MOVQ R12, R14
IMULQ R10, R14
MOVQ R12, AX
MULQ R9
ADDQ AX, R13
ADCQ DX, R14
ADDQ R8, R13
ADCQ $0x00, R14
MOVQ BX, R8
MOVQ CX, R9
MOVQ R13, R10
ANDQ $0x03, R10
MOVQ R13, BX
ANDQ $-4, BX
ADDQ BX, R8
ADCQ R14, R9
ADCQ $0x00, R10
SHRQ $0x02, R14, R13
SHRQ $0x02, R14
ADDQ R13, R8
ADCQ R14, R9
ADCQ $0x00, R10
SUBQ $0x10, R15
CMPQ R15, $0x10
JAE loop
bytes_between_0_and_15:
TESTQ R15, R15
JZ done
MOVQ $0x00000001, BX
XORQ CX, CX
XORQ R13, R13
ADDQ R15, SI
flush_buffer:
SHLQ $0x08, BX, CX
SHLQ $0x08, BX
MOVB -1(SI), R13
XORQ R13, BX
DECQ SI
DECQ R15
JNZ flush_buffer
ADDQ BX, R8
ADCQ CX, R9
ADCQ $0x00, R10
MOVQ $0x00000010, R15
JMP multiply
done:
MOVQ R8, (DI)
MOVQ R9, 8(DI)
MOVQ R10, 16(DI)
RET
================================================
FILE: vendor/golang.org/x/crypto/internal/poly1305/sum_asm.go
================================================
// Copyright 2012 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.
//go:build gc && !purego && (amd64 || loong64 || ppc64 || ppc64le)
package poly1305
//go:noescape
func update(state *macState, msg []byte)
// mac is a wrapper for macGeneric that redirects calls that would have gone to
// updateGeneric to update.
//
// Its Write and Sum methods are otherwise identical to the macGeneric ones, but
// using function pointers would carry a major performance cost.
type mac struct{ macGeneric }
func (h *mac) Write(p []byte) (int, error) {
nn := len(p)
if h.offset > 0 {
n := copy(h.buffer[h.offset:], p)
if h.offset+n < TagSize {
h.offset += n
return nn, nil
}
p = p[n:]
h.offset = 0
update(&h.macState, h.buffer[:])
}
if n := len(p) - (len(p) % TagSize); n > 0 {
update(&h.macState, p[:n])
p = p[n:]
}
if len(p) > 0 {
h.offset += copy(h.buffer[h.offset:], p)
}
return nn, nil
}
func (h *mac) Sum(out *[16]byte) {
state := h.macState
if h.offset > 0 {
update(&state, h.buffer[:h.offset])
}
finalize(out, &state.h, &state.s)
}
================================================
FILE: vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go
================================================
// Copyright 2018 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 file provides the generic implementation of Sum and MAC. Other files
// might provide optimized assembly implementations of some of this code.
package poly1305
import (
"encoding/binary"
"math/bits"
)
// Poly1305 [RFC 7539] is a relatively simple algorithm: the authentication tag
// for a 64 bytes message is approximately
//
// s + m[0:16] * r⁴ + m[16:32] * r³ + m[32:48] * r² + m[48:64] * r mod 2¹³⁰ - 5
//
// for some secret r and s. It can be computed sequentially like
//
// for len(msg) > 0:
// h += read(msg, 16)
// h *= r
// h %= 2¹³⁰ - 5
// return h + s
//
// All the complexity is about doing performant constant-time math on numbers
// larger than any available numeric type.
func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) {
h := newMACGeneric(key)
h.Write(msg)
h.Sum(out)
}
func newMACGeneric(key *[32]byte) macGeneric {
m := macGeneric{}
initialize(key, &m.macState)
return m
}
// macState holds numbers in saturated 64-bit little-endian limbs. That is,
// the value of [x0, x1, x2] is x[0] + x[1] * 2⁶⁴ + x[2] * 2¹²⁸.
type macState struct {
// h is the main accumulator. It is to be interpreted modulo 2¹³⁰ - 5, but
// can grow larger during and after rounds. It must, however, remain below
// 2 * (2¹³⁰ - 5).
h [3]uint64
// r and s are the private key components.
r [2]uint64
s [2]uint64
}
type macGeneric struct {
macState
buffer [TagSize]byte
offset int
}
// Write splits the incoming message into TagSize chunks, and passes them to
// update. It buffers incomplete chunks.
func (h *macGeneric) Write(p []byte) (int, error) {
nn := len(p)
if h.offset > 0 {
n := copy(h.buffer[h.offset:], p)
if h.offset+n < TagSize {
h.offset += n
return nn, nil
}
p = p[n:]
h.offset = 0
updateGeneric(&h.macState, h.buffer[:])
}
if n := len(p) - (len(p) % TagSize); n > 0 {
updateGeneric(&h.macState, p[:n])
p = p[n:]
}
if len(p) > 0 {
h.offset += copy(h.buffer[h.offset:], p)
}
return nn, nil
}
// Sum flushes the last incomplete chunk from the buffer, if any, and generates
// the MAC output. It does not modify its state, in order to allow for multiple
// calls to Sum, even if no Write is allowed after Sum.
func (h *macGeneric) Sum(out *[TagSize]byte) {
state := h.macState
if h.offset > 0 {
updateGeneric(&state, h.buffer[:h.offset])
}
finalize(out, &state.h, &state.s)
}
// [rMask0, rMask1] is the specified Poly1305 clamping mask in little-endian. It
// clears some bits of the secret coefficient to make it possible to implement
// multiplication more efficiently.
const (
rMask0 = 0x0FFFFFFC0FFFFFFF
rMask1 = 0x0FFFFFFC0FFFFFFC
)
// initialize loads the 256-bit key into the two 128-bit secret values r and s.
func initialize(key *[32]byte, m *macState) {
m.r[0] = binary.LittleEndian.Uint64(key[0:8]) & rMask0
m.r[1] = binary.LittleEndian.Uint64(key[8:16]) & rMask1
m.s[0] = binary.LittleEndian.Uint64(key[16:24])
m.s[1] = binary.LittleEndian.Uint64(key[24:32])
}
// uint128 holds a 128-bit number as two 64-bit limbs, for use with the
// bits.Mul64 and bits.Add64 intrinsics.
type uint128 struct {
lo, hi uint64
}
func mul64(a, b uint64) uint128 {
hi, lo := bits.Mul64(a, b)
return uint128{lo, hi}
}
func add128(a, b uint128) uint128 {
lo, c := bits.Add64(a.lo, b.lo, 0)
hi, c := bits.Add64(a.hi, b.hi, c)
if c != 0 {
panic("poly1305: unexpected overflow")
}
return uint128{lo, hi}
}
func shiftRightBy2(a uint128) uint128 {
a.lo = a.lo>>2 | (a.hi&3)<<62
a.hi = a.hi >> 2
return a
}
// updateGeneric absorbs msg into the state.h accumulator. For each chunk m of
// 128 bits of message, it computes
//
// h₊ = (h + m) * r mod 2¹³⁰ - 5
//
// If the msg length is not a multiple of TagSize, it assumes the last
// incomplete chunk is the final one.
func updateGeneric(state *macState, msg []byte) {
h0, h1, h2 := state.h[0], state.h[1], state.h[2]
r0, r1 := state.r[0], state.r[1]
for len(msg) > 0 {
var c uint64
// For the first step, h + m, we use a chain of bits.Add64 intrinsics.
// The resulting value of h might exceed 2¹³⁰ - 5, but will be partially
// reduced at the end of the multiplication below.
//
// The spec requires us to set a bit just above the message size, not to
// hide leading zeroes. For full chunks, that's 1 << 128, so we can just
// add 1 to the most significant (2¹²⁸) limb, h2.
if len(msg) >= TagSize {
h0, c = bits.Add64(h0, binary.LittleEndian.Uint64(msg[0:8]), 0)
h1, c = bits.Add64(h1, binary.LittleEndian.Uint64(msg[8:16]), c)
h2 += c + 1
msg = msg[TagSize:]
} else {
var buf [TagSize]byte
copy(buf[:], msg)
buf[len(msg)] = 1
h0, c = bits.Add64(h0, binary.LittleEndian.Uint64(buf[0:8]), 0)
h1, c = bits.Add64(h1, binary.LittleEndian.Uint64(buf[8:16]), c)
h2 += c
msg = nil
}
// Multiplication of big number limbs is similar to elementary school
// columnar multiplication. Instead of digits, there are 64-bit limbs.
//
// We are multiplying a 3 limbs number, h, by a 2 limbs number, r.
//
// h2 h1 h0 x
// r1 r0 =
// ----------------
// h2r0 h1r0 h0r0 <-- individual 128-bit products
// + h2r1 h1r1 h0r1
// ------------------------
// m3 m2 m1 m0 <-- result in 128-bit overlapping limbs
// ------------------------
// m3.hi m2.hi m1.hi m0.hi <-- carry propagation
// + m3.lo m2.lo m1.lo m0.lo
// -------------------------------
// t4 t3 t2 t1 t0 <-- final result in 64-bit limbs
//
// The main difference from pen-and-paper multiplication is that we do
// carry propagation in a separate step, as if we wrote two digit sums
// at first (the 128-bit limbs), and then carried the tens all at once.
h0r0 := mul64(h0, r0)
h1r0 := mul64(h1, r0)
h2r0 := mul64(h2, r0)
h0r1 := mul64(h0, r1)
h1r1 := mul64(h1, r1)
h2r1 := mul64(h2, r1)
// Since h2 is known to be at most 7 (5 + 1 + 1), and r0 and r1 have their
// top 4 bits cleared by rMask{0,1}, we know that their product is not going
// to overflow 64 bits, so we can ignore the high part of the products.
//
// This also means that the product doesn't have a fifth limb (t4).
if h2r0.hi != 0 {
panic("poly1305: unexpected overflow")
}
if h2r1.hi != 0 {
panic("poly1305: unexpected overflow")
}
m0 := h0r0
m1 := add128(h1r0, h0r1) // These two additions don't overflow thanks again
m2 := add128(h2r0, h1r1) // to the 4 masked bits at the top of r0 and r1.
m3 := h2r1
t0 := m0.lo
t1, c := bits.Add64(m1.lo, m0.hi, 0)
t2, c := bits.Add64(m2.lo, m1.hi, c)
t3, _ := bits.Add64(m3.lo, m2.hi, c)
// Now we have the result as 4 64-bit limbs, and we need to reduce it
// modulo 2¹³⁰ - 5. The special shape of this Crandall prime lets us do
// a cheap partial reduction according to the reduction identity
//
// c * 2¹³⁰ + n = c * 5 + n mod 2¹³⁰ - 5
//
// because 2¹³⁰ = 5 mod 2¹³⁰ - 5. Partial reduction since the result is
// likely to be larger than 2¹³⁰ - 5, but still small enough to fit the
// assumptions we make about h in the rest of the code.
//
// See also https://speakerdeck.com/gtank/engineering-prime-numbers?slide=23
// We split the final result at the 2¹³⁰ mark into h and cc, the carry.
// Note that the carry bits are effectively shifted left by 2, in other
// words, cc = c * 4 for the c in the reduction identity.
h0, h1, h2 = t0, t1, t2&maskLow2Bits
cc := uint128{t2 & maskNotLow2Bits, t3}
// To add c * 5 to h, we first add cc = c * 4, and then add (cc >> 2) = c.
h0, c = bits.Add64(h0, cc.lo, 0)
h1, c = bits.Add64(h1, cc.hi, c)
h2 += c
cc = shiftRightBy2(cc)
h0, c = bits.Add64(h0, cc.lo, 0)
h1, c = bits.Add64(h1, cc.hi, c)
h2 += c
// h2 is at most 3 + 1 + 1 = 5, making the whole of h at most
//
// 5 * 2¹²⁸ + (2¹²⁸ - 1) = 6 * 2¹²⁸ - 1
}
state.h[0], state.h[1], state.h[2] = h0, h1, h2
}
const (
maskLow2Bits uint64 = 0x0000000000000003
maskNotLow2Bits uint64 = ^maskLow2Bits
)
// select64 returns x if v == 1 and y if v == 0, in constant time.
func select64(v, x, y uint64) uint64 { return ^(v-1)&x | (v-1)&y }
// [p0, p1, p2] is 2¹³⁰ - 5 in little endian order.
const (
p0 = 0xFFFFFFFFFFFFFFFB
p1 = 0xFFFFFFFFFFFFFFFF
p2 = 0x0000000000000003
)
// finalize completes the modular reduction of h and computes
//
// out = h + s mod 2¹²⁸
func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) {
h0, h1, h2 := h[0], h[1], h[2]
// After the partial reduction in updateGeneric, h might be more than
// 2¹³⁰ - 5, but will be less than 2 * (2¹³⁰ - 5). To complete the reduction
// in constant time, we compute t = h - (2¹³⁰ - 5), and select h as the
// result if the subtraction underflows, and t otherwise.
hMinusP0, b := bits.Sub64(h0, p0, 0)
hMinusP1, b := bits.Sub64(h1, p1, b)
_, b = bits.Sub64(h2, p2, b)
// h = h if h < p else h - p
h0 = select64(b, h0, hMinusP0)
h1 = select64(b, h1, hMinusP1)
// Finally, we compute the last Poly1305 step
//
// tag = h + s mod 2¹²⁸
//
// by just doing a wide addition with the 128 low bits of h and discarding
// the overflow.
h0, c := bits.Add64(h0, s[0], 0)
h1, _ = bits.Add64(h1, s[1], c)
binary.LittleEndian.PutUint64(out[0:8], h0)
binary.LittleEndian.PutUint64(out[8:16], h1)
}
================================================
FILE: vendor/golang.org/x/crypto/internal/poly1305/sum_loong64.s
================================================
// Copyright 2025 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.
//go:build gc && !purego
// func update(state *macState, msg []byte)
TEXT ·update(SB), $0-32
MOVV state+0(FP), R4
MOVV msg_base+8(FP), R5
MOVV msg_len+16(FP), R6
MOVV $0x10, R7
MOVV (R4), R8 // h0
MOVV 8(R4), R9 // h1
MOVV 16(R4), R10 // h2
MOVV 24(R4), R11 // r0
MOVV 32(R4), R12 // r1
BLT R6, R7, bytes_between_0_and_15
loop:
MOVV (R5), R14 // msg[0:8]
MOVV 8(R5), R16 // msg[8:16]
ADDV R14, R8, R8 // h0 (x1 + y1 = z1', if z1' < x1 then z1' overflow)
ADDV R16, R9, R27
SGTU R14, R8, R24 // h0.carry
SGTU R9, R27, R28
ADDV R27, R24, R9 // h1
SGTU R27, R9, R24
OR R24, R28, R24 // h1.carry
ADDV $0x01, R24, R24
ADDV R10, R24, R10 // h2
ADDV $16, R5, R5 // msg = msg[16:]
multiply:
MULV R8, R11, R14 // h0r0.lo
MULHVU R8, R11, R15 // h0r0.hi
MULV R9, R11, R13 // h1r0.lo
MULHVU R9, R11, R16 // h1r0.hi
ADDV R13, R15, R15
SGTU R13, R15, R24
ADDV R24, R16, R16
MULV R10, R11, R25
ADDV R16, R25, R25
MULV R8, R12, R13 // h0r1.lo
MULHVU R8, R12, R16 // h0r1.hi
ADDV R13, R15, R15
SGTU R13, R15, R24
ADDV R24, R16, R16
MOVV R16, R8
MULV R10, R12, R26 // h2r1
MULV R9, R12, R13 // h1r1.lo
MULHVU R9, R12, R16 // h1r1.hi
ADDV R13, R25, R25
ADDV R16, R26, R27
SGTU R13, R25, R24
ADDV R27, R24, R26
ADDV R8, R25, R25
SGTU R8, R25, R24
ADDV R24, R26, R26
AND $3, R25, R10
AND $-4, R25, R17
ADDV R17, R14, R8
ADDV R26, R15, R27
SGTU R17, R8, R24
SGTU R26, R27, R28
ADDV R27, R24, R9
SGTU R27, R9, R24
OR R24, R28, R24
ADDV R24, R10, R10
SLLV $62, R26, R27
SRLV $2, R25, R28
SRLV $2, R26, R26
OR R27, R28, R25
ADDV R25, R8, R8
ADDV R26, R9, R27
SGTU R25, R8, R24
SGTU R26, R27, R28
ADDV R27, R24, R9
SGTU R27, R9, R24
OR R24, R28, R24
ADDV R24, R10, R10
SUBV $16, R6, R6
BGE R6, R7, loop
bytes_between_0_and_15:
BEQ R6, R0, done
MOVV $1, R14
XOR R15, R15
ADDV R6, R5, R5
flush_buffer:
MOVBU -1(R5), R25
SRLV $56, R14, R24
SLLV $8, R15, R28
SLLV $8, R14, R14
OR R24, R28, R15
XOR R25, R14, R14
SUBV $1, R6, R6
SUBV $1, R5, R5
BNE R6, R0, flush_buffer
ADDV R14, R8, R8
SGTU R14, R8, R24
ADDV R15, R9, R27
SGTU R15, R27, R28
ADDV R27, R24, R9
SGTU R27, R9, R24
OR R24, R28, R24
ADDV R10, R24, R10
MOVV $16, R6
JMP multiply
done:
MOVV R8, (R4)
MOVV R9, 8(R4)
MOVV R10, 16(R4)
RET
================================================
FILE: vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64x.s
================================================
// Copyright 2019 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.
//go:build gc && !purego && (ppc64 || ppc64le)
#include "textflag.h"
// This was ported from the amd64 implementation.
#ifdef GOARCH_ppc64le
#define LE_MOVD MOVD
#define LE_MOVWZ MOVWZ
#define LE_MOVHZ MOVHZ
#else
#define LE_MOVD MOVDBR
#define LE_MOVWZ MOVWBR
#define LE_MOVHZ MOVHBR
#endif
#define POLY1305_ADD(msg, h0, h1, h2, t0, t1, t2) \
LE_MOVD (msg)( R0), t0; \
LE_MOVD (msg)(R24), t1; \
MOVD $1, t2; \
ADDC t0, h0, h0; \
ADDE t1, h1, h1; \
ADDE t2, h2; \
ADD $16, msg
#define POLY1305_MUL(h0, h1, h2, r0, r1, t0, t1, t2, t3, t4, t5) \
MULLD r0, h0, t0; \
MULHDU r0, h0, t1; \
MULLD r0, h1, t4; \
MULHDU r0, h1, t5; \
ADDC t4, t1, t1; \
MULLD r0, h2, t2; \
MULHDU r1, h0, t4; \
MULLD r1, h0, h0; \
ADDE t5, t2, t2; \
ADDC h0, t1, t1; \
MULLD h2, r1, t3; \
ADDZE t4, h0; \
MULHDU r1, h1, t5; \
MULLD r1, h1, t4; \
ADDC t4, t2, t2; \
ADDE t5, t3, t3; \
ADDC h0, t2, t2; \
MOVD $-4, t4; \
ADDZE t3; \
RLDICL $0, t2, $62, h2; \
AND t2, t4, h0; \
ADDC t0, h0, h0; \
ADDE t3, t1, h1; \
SLD $62, t3, t4; \
SRD $2, t2; \
ADDZE h2; \
OR t4, t2, t2; \
SRD $2, t3; \
ADDC t2, h0, h0; \
ADDE t3, h1, h1; \
ADDZE h2
// func update(state *[7]uint64, msg []byte)
TEXT ·update(SB), $0-32
MOVD state+0(FP), R3
MOVD msg_base+8(FP), R4
MOVD msg_len+16(FP), R5
MOVD 0(R3), R8 // h0
MOVD 8(R3), R9 // h1
MOVD 16(R3), R10 // h2
MOVD 24(R3), R11 // r0
MOVD 32(R3), R12 // r1
MOVD $8, R24
CMP R5, $16
BLT bytes_between_0_and_15
loop:
POLY1305_ADD(R4, R8, R9, R10, R20, R21, R22)
PCALIGN $16
multiply:
POLY1305_MUL(R8, R9, R10, R11, R12, R16, R17, R18, R14, R20, R21)
ADD $-16, R5
CMP R5, $16
BGE loop
bytes_between_0_and_15:
CMP R5, $0
BEQ done
MOVD $0, R16 // h0
MOVD $0, R17 // h1
flush_buffer:
CMP R5, $8
BLE just1
MOVD $8, R21
SUB R21, R5, R21
// Greater than 8 -- load the rightmost remaining bytes in msg
// and put into R17 (h1)
LE_MOVD (R4)(R21), R17
MOVD $16, R22
// Find the offset to those bytes
SUB R5, R22, R22
SLD $3, R22
// Shift to get only the bytes in msg
SRD R22, R17, R17
// Put 1 at high end
MOVD $1, R23
SLD $3, R21
SLD R21, R23, R23
OR R23, R17, R17
// Remainder is 8
MOVD $8, R5
just1:
CMP R5, $8
BLT less8
// Exactly 8
LE_MOVD (R4), R16
CMP R17, $0
// Check if we've already set R17; if not
// set 1 to indicate end of msg.
BNE carry
MOVD $1, R17
BR carry
less8:
MOVD $0, R16 // h0
MOVD $0, R22 // shift count
CMP R5, $4
BLT less4
LE_MOVWZ (R4), R16
ADD $4, R4
ADD $-4, R5
MOVD $32, R22
less4:
CMP R5, $2
BLT less2
LE_MOVHZ (R4), R21
SLD R22, R21, R21
OR R16, R21, R16
ADD $16, R22
ADD $-2, R5
ADD $2, R4
less2:
CMP R5, $0
BEQ insert1
MOVBZ (R4), R21
SLD R22, R21, R21
OR R16, R21, R16
ADD $8, R22
insert1:
// Insert 1 at end of msg
MOVD $1, R21
SLD R22, R21, R21
OR R16, R21, R16
carry:
// Add new values to h0, h1, h2
ADDC R16, R8
ADDE R17, R9
ADDZE R10, R10
MOVD $16, R5
ADD R5, R4
BR multiply
done:
// Save h0, h1, h2 in state
MOVD R8, 0(R3)
MOVD R9, 8(R3)
MOVD R10, 16(R3)
RET
================================================
FILE: vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go
================================================
// Copyright 2018 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.
//go:build gc && !purego
package poly1305
import (
"golang.org/x/sys/cpu"
)
// updateVX is an assembly implementation of Poly1305 that uses vector
// instructions. It must only be called if the vector facility (vx) is
// available.
//
//go:noescape
func updateVX(state *macState, msg []byte)
// mac is a replacement for macGeneric that uses a larger buffer and redirects
// calls that would have gone to updateGeneric to updateVX if the vector
// facility is installed.
//
// A larger buffer is required for good performance because the vector
// implementation has a higher fixed cost per call than the generic
// implementation.
type mac struct {
macState
buffer [16 * TagSize]byte // size must be a multiple of block size (16)
offset int
}
func (h *mac) Write(p []byte) (int, error) {
nn := len(p)
if h.offset > 0 {
n := copy(h.buffer[h.offset:], p)
if h.offset+n < len(h.buffer) {
h.offset += n
return nn, nil
}
p = p[n:]
h.offset = 0
if cpu.S390X.HasVX {
updateVX(&h.macState, h.buffer[:])
} else {
updateGeneric(&h.macState, h.buffer[:])
}
}
tail := len(p) % len(h.buffer) // number of bytes to copy into buffer
body := len(p) - tail // number of bytes to process now
if body > 0 {
if cpu.S390X.HasVX {
updateVX(&h.macState, p[:body])
} else {
updateGeneric(&h.macState, p[:body])
}
}
h.offset = copy(h.buffer[:], p[body:]) // copy tail bytes - can be 0
return nn, nil
}
func (h *mac) Sum(out *[TagSize]byte) {
state := h.macState
remainder := h.buffer[:h.offset]
// Use the generic implementation if we have 2 or fewer blocks left
// to sum. The vector implementation has a higher startup time.
if cpu.S390X.HasVX && len(remainder) > 2*TagSize {
updateVX(&state, remainder)
} else if len(remainder) > 0 {
updateGeneric(&state, remainder)
}
finalize(out, &state.h, &state.s)
}
================================================
FILE: vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s
================================================
// Copyright 2018 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.
//go:build gc && !purego
#include "textflag.h"
// This implementation of Poly1305 uses the vector facility (vx)
// to process up to 2 blocks (32 bytes) per iteration using an
// algorithm based on the one described in:
//
// NEON crypto, Daniel J. Bernstein & Peter Schwabe
// https://cryptojedi.org/papers/neoncrypto-20120320.pdf
//
// This algorithm uses 5 26-bit limbs to represent a 130-bit
// value. These limbs are, for the most part, zero extended and
// placed into 64-bit vector register elements. Each vector
// register is 128-bits wide and so holds 2 of these elements.
// Using 26-bit limbs allows us plenty of headroom to accommodate
// accumulations before and after multiplication without
// overflowing either 32-bits (before multiplication) or 64-bits
// (after multiplication).
//
// In order to parallelise the operations required to calculate
// the sum we use two separate accumulators and then sum those
// in an extra final step. For compatibility with the generic
// implementation we perform this summation at the end of every
// updateVX call.
//
// To use two accumulators we must multiply the message blocks
// by r² rather than r. Only the final message block should be
// multiplied by r.
//
// Example:
//
// We want to calculate the sum (h) for a 64 byte message (m):
//
// h = m[0:16]r⁴ + m[16:32]r³ + m[32:48]r² + m[48:64]r
//
// To do this we split the calculation into the even indices
// and odd indices of the message. These form our SIMD 'lanes':
//
// h = m[ 0:16]r⁴ + m[32:48]r² + <- lane 0
// m[16:32]r³ + m[48:64]r <- lane 1
//
// To calculate this iteratively we refactor so that both lanes
// are written in terms of r² and r:
//
// h = (m[ 0:16]r² + m[32:48])r² + <- lane 0
// (m[16:32]r² + m[48:64])r <- lane 1
// ^ ^
// | coefficients for second iteration
// coefficients for first iteration
//
// So in this case we would have two iterations. In the first
// both lanes are multiplied by r². In the second only the
// first lane is multiplied by r² and the second lane is
// instead multiplied by r. This gives use the odd and even
// powers of r that we need from the original equation.
//
// Notation:
//
// h - accumulator
// r - key
// m - message
//
// [a, b] - SIMD register holding two 64-bit values
// [a, b, c, d] - SIMD register holding four 32-bit values
// xᵢ[n] - limb n of variable x with bit width i
//
// Limbs are expressed in little endian order, so for 26-bit
// limbs x₂₆[4] will be the most significant limb and x₂₆[0]
// will be the least significant limb.
// masking constants
#define MOD24 V0 // [0x0000000000ffffff, 0x0000000000ffffff] - mask low 24-bits
#define MOD26 V1 // [0x0000000003ffffff, 0x0000000003ffffff] - mask low 26-bits
// expansion constants (see EXPAND macro)
#define EX0 V2
#define EX1 V3
#define EX2 V4
// key (r², r or 1 depending on context)
#define R_0 V5
#define R_1 V6
#define R_2 V7
#define R_3 V8
#define R_4 V9
// precalculated coefficients (5r², 5r or 0 depending on context)
#define R5_1 V10
#define R5_2 V11
#define R5_3 V12
#define R5_4 V13
// message block (m)
#define M_0 V14
#define M_1 V15
#define M_2 V16
#define M_3 V17
#define M_4 V18
// accumulator (h)
#define H_0 V19
#define H_1 V20
#define H_2 V21
#define H_3 V22
#define H_4 V23
// temporary registers (for short-lived values)
#define T_0 V24
#define T_1 V25
#define T_2 V26
#define T_3 V27
#define T_4 V28
GLOBL ·constants<>(SB), RODATA, $0x30
// EX0
DATA ·constants<>+0x00(SB)/8, $0x0006050403020100
DATA ·constants<>+0x08(SB)/8, $0x1016151413121110
// EX1
DATA ·constants<>+0x10(SB)/8, $0x060c0b0a09080706
DATA ·constants<>+0x18(SB)/8, $0x161c1b1a19181716
// EX2
DATA ·constants<>+0x20(SB)/8, $0x0d0d0d0d0d0f0e0d
DATA ·constants<>+0x28(SB)/8, $0x1d1d1d1d1d1f1e1d
// MULTIPLY multiplies each lane of f and g, partially reduced
// modulo 2¹³⁰ - 5. The result, h, consists of partial products
// in each lane that need to be reduced further to produce the
// final result.
//
// h₁₃₀ = (f₁₃₀g₁₃₀) % 2¹³⁰ + (5f₁₃₀g₁₃₀) / 2¹³⁰
//
// Note that the multiplication by 5 of the high bits is
// achieved by precalculating the multiplication of four of the
// g coefficients by 5. These are g51-g54.
#define MULTIPLY(f0, f1, f2, f3, f4, g0, g1, g2, g3, g4, g51, g52, g53, g54, h0, h1, h2, h3, h4) \
VMLOF f0, g0, h0 \
VMLOF f0, g3, h3 \
VMLOF f0, g1, h1 \
VMLOF f0, g4, h4 \
VMLOF f0, g2, h2 \
VMLOF f1, g54, T_0 \
VMLOF f1, g2, T_3 \
VMLOF f1, g0, T_1 \
VMLOF f1, g3, T_4 \
VMLOF f1, g1, T_2 \
VMALOF f2, g53, h0, h0 \
VMALOF f2, g1, h3, h3 \
VMALOF f2, g54, h1, h1 \
VMALOF f2, g2, h4, h4 \
VMALOF f2, g0, h2, h2 \
VMALOF f3, g52, T_0, T_0 \
VMALOF f3, g0, T_3, T_3 \
VMALOF f3, g53, T_1, T_1 \
VMALOF f3, g1, T_4, T_4 \
VMALOF f3, g54, T_2, T_2 \
VMALOF f4, g51, h0, h0 \
VMALOF f4, g54, h3, h3 \
VMALOF f4, g52, h1, h1 \
VMALOF f4, g0, h4, h4 \
VMALOF f4, g53, h2, h2 \
VAG T_0, h0, h0 \
VAG T_3, h3, h3 \
VAG T_1, h1, h1 \
VAG T_4, h4, h4 \
VAG T_2, h2, h2
// REDUCE performs the following carry operations in four
// stages, as specified in Bernstein & Schwabe:
//
// 1: h₂₆[0]->h₂₆[1] h₂₆[3]->h₂₆[4]
// 2: h₂₆[1]->h₂₆[2] h₂₆[4]->h₂₆[0]
// 3: h₂₆[0]->h₂₆[1] h₂₆[2]->h₂₆[3]
// 4: h₂₆[3]->h₂₆[4]
//
// The result is that all of the limbs are limited to 26-bits
// except for h₂₆[1] and h₂₆[4] which are limited to 27-bits.
//
// Note that although each limb is aligned at 26-bit intervals
// they may contain values that exceed 2²⁶ - 1, hence the need
// to carry the excess bits in each limb.
#define REDUCE(h0, h1, h2, h3, h4) \
VESRLG $26, h0, T_0 \
VESRLG $26, h3, T_1 \
VN MOD26, h0, h0 \
VN MOD26, h3, h3 \
VAG T_0, h1, h1 \
VAG T_1, h4, h4 \
VESRLG $26, h1, T_2 \
VESRLG $26, h4, T_3 \
VN MOD26, h1, h1 \
VN MOD26, h4, h4 \
VESLG $2, T_3, T_4 \
VAG T_3, T_4, T_4 \
VAG T_2, h2, h2 \
VAG T_4, h0, h0 \
VESRLG $26, h2, T_0 \
VESRLG $26, h0, T_1 \
VN MOD26, h2, h2 \
VN MOD26, h0, h0 \
VAG T_0, h3, h3 \
VAG T_1, h1, h1 \
VESRLG $26, h3, T_2 \
VN MOD26, h3, h3 \
VAG T_2, h4, h4
// EXPAND splits the 128-bit little-endian values in0 and in1
// into 26-bit big-endian limbs and places the results into
// the first and second lane of d₂₆[0:4] respectively.
//
// The EX0, EX1 and EX2 constants are arrays of byte indices
// for permutation. The permutation both reverses the bytes
// in the input and ensures the bytes are copied into the
// destination limb ready to be shifted into their final
// position.
#define EXPAND(in0, in1, d0, d1, d2, d3, d4) \
VPERM in0, in1, EX0, d0 \
VPERM in0, in1, EX1, d2 \
VPERM in0, in1, EX2, d4 \
VESRLG $26, d0, d1 \
VESRLG $30, d2, d3 \
VESRLG $4, d2, d2 \
VN MOD26, d0, d0 \ // [in0₂₆[0], in1₂₆[0]]
VN MOD26, d3, d3 \ // [in0₂₆[3], in1₂₆[3]]
VN MOD26, d1, d1 \ // [in0₂₆[1], in1₂₆[1]]
VN MOD24, d4, d4 \ // [in0₂₆[4], in1₂₆[4]]
VN MOD26, d2, d2 // [in0₂₆[2], in1₂₆[2]]
// func updateVX(state *macState, msg []byte)
TEXT ·updateVX(SB), NOSPLIT, $0
MOVD state+0(FP), R1
LMG msg+8(FP), R2, R3 // R2=msg_base, R3=msg_len
// load EX0, EX1 and EX2
MOVD $·constants<>(SB), R5
VLM (R5), EX0, EX2
// generate masks
VGMG $(64-24), $63, MOD24 // [0x00ffffff, 0x00ffffff]
VGMG $(64-26), $63, MOD26 // [0x03ffffff, 0x03ffffff]
// load h (accumulator) and r (key) from state
VZERO T_1 // [0, 0]
VL 0(R1), T_0 // [h₆₄[0], h₆₄[1]]
VLEG $0, 16(R1), T_1 // [h₆₄[2], 0]
VL 24(R1), T_2 // [r₆₄[0], r₆₄[1]]
VPDI $0, T_0, T_2, T_3 // [h₆₄[0], r₆₄[0]]
VPDI $5, T_0, T_2, T_4 // [h₆₄[1], r₆₄[1]]
// unpack h and r into 26-bit limbs
// note: h₆₄[2] may have the low 3 bits set, so h₂₆[4] is a 27-bit value
VN MOD26, T_3, H_0 // [h₂₆[0], r₂₆[0]]
VZERO H_1 // [0, 0]
VZERO H_3 // [0, 0]
VGMG $(64-12-14), $(63-12), T_0 // [0x03fff000, 0x03fff000] - 26-bit mask with low 12 bits masked out
VESLG $24, T_1, T_1 // [h₆₄[2]<<24, 0]
VERIMG $-26&63, T_3, MOD26, H_1 // [h₂₆[1], r₂₆[1]]
VESRLG $+52&63, T_3, H_2 // [h₂₆[2], r₂₆[2]] - low 12 bits only
VERIMG $-14&63, T_4, MOD26, H_3 // [h₂₆[1], r₂₆[1]]
VESRLG $40, T_4, H_4 // [h₂₆[4], r₂₆[4]] - low 24 bits only
VERIMG $+12&63, T_4, T_0, H_2 // [h₂₆[2], r₂₆[2]] - complete
VO T_1, H_4, H_4 // [h₂₆[4], r₂₆[4]] - complete
// replicate r across all 4 vector elements
VREPF $3, H_0, R_0 // [r₂₆[0], r₂₆[0], r₂₆[0], r₂₆[0]]
VREPF $3, H_1, R_1 // [r₂₆[1], r₂₆[1], r₂₆[1], r₂₆[1]]
VREPF $3, H_2, R_2 // [r₂₆[2], r₂₆[2], r₂₆[2], r₂₆[2]]
VREPF $3, H_3, R_3 // [r₂₆[3], r₂₆[3], r₂₆[3], r₂₆[3]]
VREPF $3, H_4, R_4 // [r₂₆[4], r₂₆[4], r₂₆[4], r₂₆[4]]
// zero out lane 1 of h
VLEIG $1, $0, H_0 // [h₂₆[0], 0]
VLEIG $1, $0, H_1 // [h₂₆[1], 0]
VLEIG $1, $0, H_2 // [h₂₆[2], 0]
VLEIG $1, $0, H_3 // [h₂₆[3], 0]
VLEIG $1, $0, H_4 // [h₂₆[4], 0]
// calculate 5r (ignore least significant limb)
VREPIF $5, T_0
VMLF T_0, R_1, R5_1 // [5r₂₆[1], 5r₂₆[1], 5r₂₆[1], 5r₂₆[1]]
VMLF T_0, R_2, R5_2 // [5r₂₆[2], 5r₂₆[2], 5r₂₆[2], 5r₂₆[2]]
VMLF T_0, R_3, R5_3 // [5r₂₆[3], 5r₂₆[3], 5r₂₆[3], 5r₂₆[3]]
VMLF T_0, R_4, R5_4 // [5r₂₆[4], 5r₂₆[4], 5r₂₆[4], 5r₂₆[4]]
// skip r² calculation if we are only calculating one block
CMPBLE R3, $16, skip
// calculate r²
MULTIPLY(R_0, R_1, R_2, R_3, R_4, R_0, R_1, R_2, R_3, R_4, R5_1, R5_2, R5_3, R5_4, M_0, M_1, M_2, M_3, M_4)
REDUCE(M_0, M_1, M_2, M_3, M_4)
VGBM $0x0f0f, T_0
VERIMG $0, M_0, T_0, R_0 // [r₂₆[0], r²₂₆[0], r₂₆[0], r²₂₆[0]]
VERIMG $0, M_1, T_0, R_1 // [r₂₆[1], r²₂₆[1], r₂₆[1], r²₂₆[1]]
VERIMG $0, M_2, T_0, R_2 // [r₂₆[2], r²₂₆[2], r₂₆[2], r²₂₆[2]]
VERIMG $0, M_3, T_0, R_3 // [r₂₆[3], r²₂₆[3], r₂₆[3], r²₂₆[3]]
VERIMG $0, M_4, T_0, R_4 // [r₂₆[4], r²₂₆[4], r₂₆[4], r²₂₆[4]]
// calculate 5r² (ignore least significant limb)
VREPIF $5, T_0
VMLF T_0, R_1, R5_1 // [5r₂₆[1], 5r²₂₆[1], 5r₂₆[1], 5r²₂₆[1]]
VMLF T_0, R_2, R5_2 // [5r₂₆[2], 5r²₂₆[2], 5r₂₆[2], 5r²₂₆[2]]
VMLF T_0, R_3, R5_3 // [5r₂₆[3], 5r²₂₆[3], 5r₂₆[3], 5r²₂₆[3]]
VMLF T_0, R_4, R5_4 // [5r₂₆[4], 5r²₂₆[4], 5r₂₆[4], 5r²₂₆[4]]
loop:
CMPBLE R3, $32, b2 // 2 or fewer blocks remaining, need to change key coefficients
// load next 2 blocks from message
VLM (R2), T_0, T_1
// update message slice
SUB $32, R3
MOVD $32(R2), R2
// unpack message blocks into 26-bit big-endian limbs
EXPAND(T_0, T_1, M_0, M_1, M_2, M_3, M_4)
// add 2¹²⁸ to each message block value
VLEIB $4, $1, M_4
VLEIB $12, $1, M_4
multiply:
// accumulate the incoming message
VAG H_0, M_0, M_0
VAG H_3, M_3, M_3
VAG H_1, M_1, M_1
VAG H_4, M_4, M_4
VAG H_2, M_2, M_2
// multiply the accumulator by the key coefficient
MULTIPLY(M_0, M_1, M_2, M_3, M_4, R_0, R_1, R_2, R_3, R_4, R5_1, R5_2, R5_3, R5_4, H_0, H_1, H_2, H_3, H_4)
// carry and partially reduce the partial products
REDUCE(H_0, H_1, H_2, H_3, H_4)
CMPBNE R3, $0, loop
finish:
// sum lane 0 and lane 1 and put the result in lane 1
VZERO T_0
VSUMQG H_0, T_0, H_0
VSUMQG H_3, T_0, H_3
VSUMQG H_1, T_0, H_1
VSUMQG H_4, T_0, H_4
VSUMQG H_2, T_0, H_2
// reduce again after summation
// TODO(mundaym): there might be a more efficient way to do this
// now that we only have 1 active lane. For example, we could
// simultaneously pack the values as we reduce them.
REDUCE(H_0, H_1, H_2, H_3, H_4)
// carry h[1] through to h[4] so that only h[4] can exceed 2²⁶ - 1
// TODO(mundaym): in testing this final carry was unnecessary.
// Needs a proof before it can be removed though.
VESRLG $26, H_1, T_1
VN MOD26, H_1, H_1
VAQ T_1, H_2, H_2
VESRLG $26, H_2, T_2
VN MOD26, H_2, H_2
VAQ T_2, H_3, H_3
VESRLG $26, H_3, T_3
VN MOD26, H_3, H_3
VAQ T_3, H_4, H_4
// h is now < 2(2¹³⁰ - 5)
// Pack each lane in h₂₆[0:4] into h₁₂₈[0:1].
VESLG $26, H_1, H_1
VESLG $26, H_3, H_3
VO H_0, H_1, H_0
VO H_2, H_3, H_2
VESLG $4, H_2, H_2
VLEIB $7, $48, H_1
VSLB H_1, H_2, H_2
VO H_0, H_2, H_0
VLEIB $7, $104, H_1
VSLB H_1, H_4, H_3
VO H_3, H_0, H_0
VLEIB $7, $24, H_1
VSRLB H_1, H_4, H_1
// update state
VSTEG $1, H_0, 0(R1)
VSTEG $0, H_0, 8(R1)
VSTEG $1, H_1, 16(R1)
RET
b2: // 2 or fewer blocks remaining
CMPBLE R3, $16, b1
// Load the 2 remaining blocks (17-32 bytes remaining).
MOVD $-17(R3), R0 // index of final byte to load modulo 16
VL (R2), T_0 // load full 16 byte block
VLL R0, 16(R2), T_1 // load final (possibly partial) block and pad with zeros to 16 bytes
// The Poly1305 algorithm requires that a 1 bit be appended to
// each message block. If the final block is less than 16 bytes
// long then it is easiest to insert the 1 before the message
// block is split into 26-bit limbs. If, on the other hand, the
// final message block is 16 bytes long then we append the 1 bit
// after expansion as normal.
MOVBZ $1, R0
MOVD $-16(R3), R3 // index of byte in last block to insert 1 at (could be 16)
CMPBEQ R3, $16, 2(PC) // skip the insertion if the final block is 16 bytes long
VLVGB R3, R0, T_1 // insert 1 into the byte at index R3
// Split both blocks into 26-bit limbs in the appropriate lanes.
EXPAND(T_0, T_1, M_0, M_1, M_2, M_3, M_4)
// Append a 1 byte to the end of the second to last block.
VLEIB $4, $1, M_4
// Append a 1 byte to the end of the last block only if it is a
// full 16 byte block.
CMPBNE R3, $16, 2(PC)
VLEIB $12, $1, M_4
// Finally, set up the coefficients for the final multiplication.
// We have previously saved r and 5r in the 32-bit even indexes
// of the R_[0-4] and R5_[1-4] coefficient registers.
//
// We want lane 0 to be multiplied by r² so that can be kept the
// same. We want lane 1 to be multiplied by r so we need to move
// the saved r value into the 32-bit odd index in lane 1 by
// rotating the 64-bit lane by 32.
VGBM $0x00ff, T_0 // [0, 0xffffffffffffffff] - mask lane 1 only
VERIMG $32, R_0, T_0, R_0 // [_, r²₂₆[0], _, r₂₆[0]]
VERIMG $32, R_1, T_0, R_1 // [_, r²₂₆[1], _, r₂₆[1]]
VERIMG $32, R_2, T_0, R_2 // [_, r²₂₆[2], _, r₂₆[2]]
VERIMG $32, R_3, T_0, R_3 // [_, r²₂₆[3], _, r₂₆[3]]
VERIMG $32, R_4, T_0, R_4 // [_, r²₂₆[4], _, r₂₆[4]]
VERIMG $32, R5_1, T_0, R5_1 // [_, 5r²₂₆[1], _, 5r₂₆[1]]
VERIMG $32, R5_2, T_0, R5_2 // [_, 5r²₂₆[2], _, 5r₂₆[2]]
VERIMG $32, R5_3, T_0, R5_3 // [_, 5r²₂₆[3], _, 5r₂₆[3]]
VERIMG $32, R5_4, T_0, R5_4 // [_, 5r²₂₆[4], _, 5r₂₆[4]]
MOVD $0, R3
BR multiply
skip:
CMPBEQ R3, $0, finish
b1: // 1 block remaining
// Load the final block (1-16 bytes). This will be placed into
// lane 0.
MOVD $-1(R3), R0
VLL R0, (R2), T_0 // pad to 16 bytes with zeros
// The Poly1305 algorithm requires that a 1 bit be appended to
// each message block. If the final block is less than 16 bytes
// long then it is easiest to insert the 1 before the message
// block is split into 26-bit limbs. If, on the other hand, the
// final message block is 16 bytes long then we append the 1 bit
// after expansion as normal.
MOVBZ $1, R0
CMPBEQ R3, $16, 2(PC)
VLVGB R3, R0, T_0
// Set the message block in lane 1 to the value 0 so that it
// can be accumulated without affecting the final result.
VZERO T_1
// Split the final message block into 26-bit limbs in lane 0.
// Lane 1 will be contain 0.
EXPAND(T_0, T_1, M_0, M_1, M_2, M_3, M_4)
// Append a 1 byte to the end of the last block only if it is a
// full 16 byte block.
CMPBNE R3, $16, 2(PC)
VLEIB $4, $1, M_4
// We have previously saved r and 5r in the 32-bit even indexes
// of the R_[0-4] and R5_[1-4] coefficient registers.
//
// We want lane 0 to be multiplied by r so we need to move the
// saved r value into the 32-bit odd index in lane 0. We want
// lane 1 to be set to the value 1. This makes multiplication
// a no-op. We do this by setting lane 1 in every register to 0
// and then just setting the 32-bit index 3 in R_0 to 1.
VZERO T_0
MOVD $0, R0
MOVD $0x10111213, R12
VLVGP R12, R0, T_1 // [_, 0x10111213, _, 0x00000000]
VPERM T_0, R_0, T_1, R_0 // [_, r₂₆[0], _, 0]
VPERM T_0, R_1, T_1, R_1 // [_, r₂₆[1], _, 0]
VPERM T_0, R_2, T_1, R_2 // [_, r₂₆[2], _, 0]
VPERM T_0, R_3, T_1, R_3 // [_, r₂₆[3], _, 0]
VPERM T_0, R_4, T_1, R_4 // [_, r₂₆[4], _, 0]
VPERM T_0, R5_1, T_1, R5_1 // [_, 5r₂₆[1], _, 0]
VPERM T_0, R5_2, T_1, R5_2 // [_, 5r₂₆[2], _, 0]
VPERM T_0, R5_3, T_1, R5_3 // [_, 5r₂₆[3], _, 0]
VPERM T_0, R5_4, T_1, R5_4 // [_, 5r₂₆[4], _, 0]
// Set the value of lane 1 to be 1.
VLEIF $3, $1, R_0 // [_, r₂₆[0], _, 1]
MOVD $0, R3
BR multiply
================================================
FILE: vendor/golang.org/x/crypto/poly1305/poly1305_compat.go
================================================
// Copyright 2012 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.
// Package poly1305 implements Poly1305 one-time message authentication code as
// specified in https://cr.yp.to/mac/poly1305-20050329.pdf.
//
// Poly1305 is a fast, one-time authentication function. It is infeasible for an
// attacker to generate an authenticator for a message without the key. However, a
// key must only be used for a single message. Authenticating two different
// messages with the same key allows an attacker to forge authenticators for other
// messages with the same key.
//
// Poly1305 was originally coupled with AES in order to make Poly1305-AES. AES was
// used with a fixed key in order to generate one-time keys from an nonce.
// However, in this package AES isn't used and the one-time key is specified
// directly.
//
// Deprecated: Poly1305 as implemented by this package is a cryptographic
// building block that is not safe for general purpose use.
// For encryption, use the full ChaCha20-Poly1305 construction implemented by
// golang.org/x/crypto/chacha20poly1305. For authentication, use a general
// purpose MAC such as HMAC implemented by crypto/hmac.
package poly1305
import "golang.org/x/crypto/internal/poly1305"
// TagSize is the size, in bytes, of a poly1305 authenticator.
//
// For use with golang.org/x/crypto/chacha20poly1305, chacha20poly1305.Overhead
// can be used instead.
const TagSize = 16
// Sum generates an authenticator for msg using a one-time key and puts the
// 16-byte result into out. Authenticating two different messages with the same
// key allows an attacker to forge messages at will.
func Sum(out *[16]byte, m []byte, key *[32]byte) {
poly1305.Sum(out, m, key)
}
// Verify returns true if mac is a valid authenticator for m with the given key.
func Verify(mac *[16]byte, m []byte, key *[32]byte) bool {
return poly1305.Verify(mac, m, key)
}
// New returns a new MAC computing an authentication
// tag of all data written to it with the given key.
// This allows writing the message progressively instead
// of passing it as a single slice. Common users should use
// the Sum function instead.
//
// The key must be unique for each message, as authenticating
// two different messages with the same key allows an attacker
// to forge messages at will.
func New(key *[32]byte) *MAC {
return &MAC{mac: poly1305.New(key)}
}
// MAC is an io.Writer computing an authentication tag
// of the data written to it.
//
// MAC cannot be used like common hash.Hash implementations,
// because using a poly1305 key twice breaks its security.
// Therefore writing data to a running MAC after calling
// Sum or Verify causes it to panic.
type MAC struct {
mac *poly1305.MAC
}
// Size returns the number of bytes Sum will return.
func (h *MAC) Size() int { return TagSize }
// Write adds more data to the running message authentication code.
// It never returns an error.
//
// It must not be called after the first call of Sum or Verify.
func (h *MAC) Write(p []byte) (n int, err error) {
return h.mac.Write(p)
}
// Sum computes the authenticator of all data written to the
// message authentication code.
func (h *MAC) Sum(b []byte) []byte {
return h.mac.Sum(b)
}
// Verify returns whether the authenticator of all data written to
// the message authentication code matches the expected value.
func (h *MAC) Verify(expected []byte) bool {
return h.mac.Verify(expected)
}
================================================
FILE: vendor/golang.org/x/crypto/salsa20/salsa/hsalsa20.go
================================================
// Copyright 2012 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.
// Package salsa provides low-level access to functions in the Salsa family.
package salsa
import "math/bits"
// Sigma is the Salsa20 constant for 256-bit keys.
var Sigma = [16]byte{'e', 'x', 'p', 'a', 'n', 'd', ' ', '3', '2', '-', 'b', 'y', 't', 'e', ' ', 'k'}
// HSalsa20 applies the HSalsa20 core function to a 16-byte input in, 32-byte
// key k, and 16-byte constant c, and puts the result into the 32-byte array
// out.
func HSalsa20(out *[32]byte, in *[16]byte, k *[32]byte, c *[16]byte) {
x0 := uint32(c[0]) | uint32(c[1])<<8 | uint32(c[2])<<16 | uint32(c[3])<<24
x1 := uint32(k[0]) | uint32(k[1])<<8 | uint32(k[2])<<16 | uint32(k[3])<<24
x2 := uint32(k[4]) | uint32(k[5])<<8 | uint32(k[6])<<16 | uint32(k[7])<<24
x3 := uint32(k[8]) | uint32(k[9])<<8 | uint32(k[10])<<16 | uint32(k[11])<<24
x4 := uint32(k[12]) | uint32(k[13])<<8 | uint32(k[14])<<16 | uint32(k[15])<<24
x5 := uint32(c[4]) | uint32(c[5])<<8 | uint32(c[6])<<16 | uint32(c[7])<<24
x6 := uint32(in[0]) | uint32(in[1])<<8 | uint32(in[2])<<16 | uint32(in[3])<<24
x7 := uint32(in[4]) | uint32(in[5])<<8 | uint32(in[6])<<16 | uint32(in[7])<<24
x8 := uint32(in[8]) | uint32(in[9])<<8 | uint32(in[10])<<16 | uint32(in[11])<<24
x9 := uint32(in[12]) | uint32(in[13])<<8 | uint32(in[14])<<16 | uint32(in[15])<<24
x10 := uint32(c[8]) | uint32(c[9])<<8 | uint32(c[10])<<16 | uint32(c[11])<<24
x11 := uint32(k[16]) | uint32(k[17])<<8 | uint32(k[18])<<16 | uint32(k[19])<<24
x12 := uint32(k[20]) | uint32(k[21])<<8 | uint32(k[22])<<16 | uint32(k[23])<<24
x13 := uint32(k[24]) | uint32(k[25])<<8 | uint32(k[26])<<16 | uint32(k[27])<<24
x14 := uint32(k[28]) | uint32(k[29])<<8 | uint32(k[30])<<16 | uint32(k[31])<<24
x15 := uint32(c[12]) | uint32(c[13])<<8 | uint32(c[14])<<16 | uint32(c[15])<<24
for i := 0; i < 20; i += 2 {
u := x0 + x12
x4 ^= bits.RotateLeft32(u, 7)
u = x4 + x0
x8 ^= bits.RotateLeft32(u, 9)
u = x8 + x4
x12 ^= bits.RotateLeft32(u, 13)
u = x12 + x8
x0 ^= bits.RotateLeft32(u, 18)
u = x5 + x1
x9 ^= bits.RotateLeft32(u, 7)
u = x9 + x5
x13 ^= bits.RotateLeft32(u, 9)
u = x13 + x9
x1 ^= bits.RotateLeft32(u, 13)
u = x1 + x13
x5 ^= bits.RotateLeft32(u, 18)
u = x10 + x6
x14 ^= bits.RotateLeft32(u, 7)
u = x14 + x10
x2 ^= bits.RotateLeft32(u, 9)
u = x2 + x14
x6 ^= bits.RotateLeft32(u, 13)
u = x6 + x2
x10 ^= bits.RotateLeft32(u, 18)
u = x15 + x11
x3 ^= bits.RotateLeft32(u, 7)
u = x3 + x15
x7 ^= bits.RotateLeft32(u, 9)
u = x7 + x3
x11 ^= bits.RotateLeft32(u, 13)
u = x11 + x7
x15 ^= bits.RotateLeft32(u, 18)
u = x0 + x3
x1 ^= bits.RotateLeft32(u, 7)
u = x1 + x0
x2 ^= bits.RotateLeft32(u, 9)
u = x2 + x1
x3 ^= bits.RotateLeft32(u, 13)
u = x3 + x2
x0 ^= bits.RotateLeft32(u, 18)
u = x5 + x4
x6 ^= bits.RotateLeft32(u, 7)
u = x6 + x5
x7 ^= bits.RotateLeft32(u, 9)
u = x7 + x6
x4 ^= bits.RotateLeft32(u, 13)
u = x4 + x7
x5 ^= bits.RotateLeft32(u, 18)
u = x10 + x9
x11 ^= bits.RotateLeft32(u, 7)
u = x11 + x10
x8 ^= bits.RotateLeft32(u, 9)
u = x8 + x11
x9 ^= bits.RotateLeft32(u, 13)
u = x9 + x8
x10 ^= bits.RotateLeft32(u, 18)
u = x15 + x14
x12 ^= bits.RotateLeft32(u, 7)
u = x12 + x15
x13 ^= bits.RotateLeft32(u, 9)
u = x13 + x12
x14 ^= bits.RotateLeft32(u, 13)
u = x14 + x13
x15 ^= bits.RotateLeft32(u, 18)
}
out[0] = byte(x0)
out[1] = byte(x0 >> 8)
out[2] = byte(x0 >> 16)
out[3] = byte(x0 >> 24)
out[4] = byte(x5)
out[5] = byte(x5 >> 8)
out[6] = byte(x5 >> 16)
out[7] = byte(x5 >> 24)
out[8] = byte(x10)
out[9] = byte(x10 >> 8)
out[10] = byte(x10 >> 16)
out[11] = byte(x10 >> 24)
out[12] = byte(x15)
out[13] = byte(x15 >> 8)
out[14] = byte(x15 >> 16)
out[15] = byte(x15 >> 24)
out[16] = byte(x6)
out[17] = byte(x6 >> 8)
out[18] = byte(x6 >> 16)
out[19] = byte(x6 >> 24)
out[20] = byte(x7)
out[21] = byte(x7 >> 8)
out[22] = byte(x7 >> 16)
out[23] = byte(x7 >> 24)
out[24] = byte(x8)
out[25] = byte(x8 >> 8)
out[26] = byte(x8 >> 16)
out[27] = byte(x8 >> 24)
out[28] = byte(x9)
out[29] = byte(x9 >> 8)
out[30] = byte(x9 >> 16)
out[31] = byte(x9 >> 24)
}
================================================
FILE: vendor/golang.org/x/crypto/salsa20/salsa/salsa208.go
================================================
// Copyright 2012 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.
package salsa
import "math/bits"
// Core208 applies the Salsa20/8 core function to the 64-byte array in and puts
// the result into the 64-byte array out. The input and output may be the same array.
func Core208(out *[64]byte, in *[64]byte) {
j0 := uint32(in[0]) | uint32(in[1])<<8 | uint32(in[2])<<16 | uint32(in[3])<<24
j1 := uint32(in[4]) | uint32(in[5])<<8 | uint32(in[6])<<16 | uint32(in[7])<<24
j2 := uint32(in[8]) | uint32(in[9])<<8 | uint32(in[10])<<16 | uint32(in[11])<<24
j3 := uint32(in[12]) | uint32(in[13])<<8 | uint32(in[14])<<16 | uint32(in[15])<<24
j4 := uint32(in[16]) | uint32(in[17])<<8 | uint32(in[18])<<16 | uint32(in[19])<<24
j5 := uint32(in[20]) | uint32(in[21])<<8 | uint32(in[22])<<16 | uint32(in[23])<<24
j6 := uint32(in[24]) | uint32(in[25])<<8 | uint32(in[26])<<16 | uint32(in[27])<<24
j7 := uint32(in[28]) | uint32(in[29])<<8 | uint32(in[30])<<16 | uint32(in[31])<<24
j8 := uint32(in[32]) | uint32(in[33])<<8 | uint32(in[34])<<16 | uint32(in[35])<<24
j9 := uint32(in[36]) | uint32(in[37])<<8 | uint32(in[38])<<16 | uint32(in[39])<<24
j10 := uint32(in[40]) | uint32(in[41])<<8 | uint32(in[42])<<16 | uint32(in[43])<<24
j11 := uint32(in[44]) | uint32(in[45])<<8 | uint32(in[46])<<16 | uint32(in[47])<<24
j12 := uint32(in[48]) | uint32(in[49])<<8 | uint32(in[50])<<16 | uint32(in[51])<<24
j13 := uint32(in[52]) | uint32(in[53])<<8 | uint32(in[54])<<16 | uint32(in[55])<<24
j14 := uint32(in[56]) | uint32(in[57])<<8 | uint32(in[58])<<16 | uint32(in[59])<<24
j15 := uint32(in[60]) | uint32(in[61])<<8 | uint32(in[62])<<16 | uint32(in[63])<<24
x0, x1, x2, x3, x4, x5, x6, x7, x8 := j0, j1, j2, j3, j4, j5, j6, j7, j8
x9, x10, x11, x12, x13, x14, x15 := j9, j10, j11, j12, j13, j14, j15
for i := 0; i < 8; i += 2 {
u := x0 + x12
x4 ^= bits.RotateLeft32(u, 7)
u = x4 + x0
x8 ^= bits.RotateLeft32(u, 9)
u = x8 + x4
x12 ^= bits.RotateLeft32(u, 13)
u = x12 + x8
x0 ^= bits.RotateLeft32(u, 18)
u = x5 + x1
x9 ^= bits.RotateLeft32(u, 7)
u = x9 + x5
x13 ^= bits.RotateLeft32(u, 9)
u = x13 + x9
x1 ^= bits.RotateLeft32(u, 13)
u = x1 + x13
x5 ^= bits.RotateLeft32(u, 18)
u = x10 + x6
x14 ^= bits.RotateLeft32(u, 7)
u = x14 + x10
x2 ^= bits.RotateLeft32(u, 9)
u = x2 + x14
x6 ^= bits.RotateLeft32(u, 13)
u = x6 + x2
x10 ^= bits.RotateLeft32(u, 18)
u = x15 + x11
x3 ^= bits.RotateLeft32(u, 7)
u = x3 + x15
x7 ^= bits.RotateLeft32(u, 9)
u = x7 + x3
x11 ^= bits.RotateLeft32(u, 13)
u = x11 + x7
x15 ^= bits.RotateLeft32(u, 18)
u = x0 + x3
x1 ^= bits.RotateLeft32(u, 7)
u = x1 + x0
x2 ^= bits.RotateLeft32(u, 9)
u = x2 + x1
x3 ^= bits.RotateLeft32(u, 13)
u = x3 + x2
x0 ^= bits.RotateLeft32(u, 18)
u = x5 + x4
x6 ^= bits.RotateLeft32(u, 7)
u = x6 + x5
x7 ^= bits.RotateLeft32(u, 9)
u = x7 + x6
x4 ^= bits.RotateLeft32(u, 13)
u = x4 + x7
x5 ^= bits.RotateLeft32(u, 18)
u = x10 + x9
x11 ^= bits.RotateLeft32(u, 7)
u = x11 + x10
x8 ^= bits.RotateLeft32(u, 9)
u = x8 + x11
x9 ^= bits.RotateLeft32(u, 13)
u = x9 + x8
x10 ^= bits.RotateLeft32(u, 18)
u = x15 + x14
x12 ^= bits.RotateLeft32(u, 7)
u = x12 + x15
x13 ^= bits.RotateLeft32(u, 9)
u = x13 + x12
x14 ^= bits.RotateLeft32(u, 13)
u = x14 + x13
x15 ^= bits.RotateLeft32(u, 18)
}
x0 += j0
x1 += j1
x2 += j2
x3 += j3
x4 += j4
x5 += j5
x6 += j6
x7 += j7
x8 += j8
x9 += j9
x10 += j10
x11 += j11
x12 += j12
x13 += j13
x14 += j14
x15 += j15
out[0] = byte(x0)
out[1] = byte(x0 >> 8)
out[2] = byte(x0 >> 16)
out[3] = byte(x0 >> 24)
out[4] = byte(x1)
out[5] = byte(x1 >> 8)
out[6] = byte(x1 >> 16)
out[7] = byte(x1 >> 24)
out[8] = byte(x2)
out[9] = byte(x2 >> 8)
out[10] = byte(x2 >> 16)
out[11] = byte(x2 >> 24)
out[12] = byte(x3)
out[13] = byte(x3 >> 8)
out[14] = byte(x3 >> 16)
out[15] = byte(x3 >> 24)
out[16] = byte(x4)
out[17] = byte(x4 >> 8)
out[18] = byte(x4 >> 16)
out[19] = byte(x4 >> 24)
out[20] = byte(x5)
out[21] = byte(x5 >> 8)
out[22] = byte(x5 >> 16)
out[23] = byte(x5 >> 24)
out[24] = byte(x6)
out[25] = byte(x6 >> 8)
out[26] = byte(x6 >> 16)
out[27] = byte(x6 >> 24)
out[28] = byte(x7)
out[29] = byte(x7 >> 8)
out[30] = byte(x7 >> 16)
out[31] = byte(x7 >> 24)
out[32] = byte(x8)
out[33] = byte(x8 >> 8)
out[34] = byte(x8 >> 16)
out[35] = byte(x8 >> 24)
out[36] = byte(x9)
out[37] = byte(x9 >> 8)
out[38] = byte(x9 >> 16)
out[39] = byte(x9 >> 24)
out[40] = byte(x10)
out[41] = byte(x10 >> 8)
out[42] = byte(x10 >> 16)
out[43] = byte(x10 >> 24)
out[44] = byte(x11)
out[45] = byte(x11 >> 8)
out[46] = byte(x11 >> 16)
out[47] = byte(x11 >> 24)
out[48] = byte(x12)
out[49] = byte(x12 >> 8)
out[50] = byte(x12 >> 16)
out[51] = byte(x12 >> 24)
out[52] = byte(x13)
out[53] = byte(x13 >> 8)
out[54] = byte(x13 >> 16)
out[55] = byte(x13 >> 24)
out[56] = byte(x14)
out[57] = byte(x14 >> 8)
out[58] = byte(x14 >> 16)
out[59] = byte(x14 >> 24)
out[60] = byte(x15)
out[61] = byte(x15 >> 8)
out[62] = byte(x15 >> 16)
out[63] = byte(x15 >> 24)
}
================================================
FILE: vendor/golang.org/x/crypto/salsa20/salsa/salsa20_amd64.go
================================================
// Copyright 2012 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.
//go:build amd64 && !purego && gc
package salsa
//go:noescape
// salsa2020XORKeyStream is implemented in salsa20_amd64.s.
func salsa2020XORKeyStream(out, in *byte, n uint64, nonce, key *byte)
// XORKeyStream crypts bytes from in to out using the given key and counters.
// In and out must overlap entirely or not at all. Counter
// contains the raw salsa20 counter bytes (both nonce and block counter).
func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) {
if len(in) == 0 {
return
}
_ = out[len(in)-1]
salsa2020XORKeyStream(&out[0], &in[0], uint64(len(in)), &counter[0], &key[0])
}
================================================
FILE: vendor/golang.org/x/crypto/salsa20/salsa/salsa20_amd64.s
================================================
// Code generated by command: go run salsa20_amd64_asm.go -out ../salsa20_amd64.s -pkg salsa. DO NOT EDIT.
//go:build amd64 && !purego && gc
// func salsa2020XORKeyStream(out *byte, in *byte, n uint64, nonce *byte, key *byte)
// Requires: SSE2
TEXT ·salsa2020XORKeyStream(SB), $456-40
// This needs up to 64 bytes at 360(R12); hence the non-obvious frame size.
MOVQ out+0(FP), DI
MOVQ in+8(FP), SI
MOVQ n+16(FP), DX
MOVQ nonce+24(FP), CX
MOVQ key+32(FP), R8
MOVQ SP, R12
ADDQ $0x1f, R12
ANDQ $-32, R12
MOVQ DX, R9
MOVQ CX, DX
MOVQ R8, R10
CMPQ R9, $0x00
JBE DONE
MOVL 20(R10), CX
MOVL (R10), R8
MOVL (DX), AX
MOVL 16(R10), R11
MOVL CX, (R12)
MOVL R8, 4(R12)
MOVL AX, 8(R12)
MOVL R11, 12(R12)
MOVL 8(DX), CX
MOVL 24(R10), R8
MOVL 4(R10), AX
MOVL 4(DX), R11
MOVL CX, 16(R12)
MOVL R8, 20(R12)
MOVL AX, 24(R12)
MOVL R11, 28(R12)
MOVL 12(DX), CX
MOVL 12(R10), DX
MOVL 28(R10), R8
MOVL 8(R10), AX
MOVL DX, 32(R12)
MOVL CX, 36(R12)
MOVL R8, 40(R12)
MOVL AX, 44(R12)
MOVQ $0x61707865, DX
MOVQ $0x3320646e, CX
MOVQ $0x79622d32, R8
MOVQ $0x6b206574, AX
MOVL DX, 48(R12)
MOVL CX, 52(R12)
MOVL R8, 56(R12)
MOVL AX, 60(R12)
CMPQ R9, $0x00000100
JB BYTESBETWEEN1AND255
MOVOA 48(R12), X0
PSHUFL $0x55, X0, X1
PSHUFL $0xaa, X0, X2
PSHUFL $0xff, X0, X3
PSHUFL $0x00, X0, X0
MOVOA X1, 64(R12)
MOVOA X2, 80(R12)
MOVOA X3, 96(R12)
MOVOA X0, 112(R12)
MOVOA (R12), X0
PSHUFL $0xaa, X0, X1
PSHUFL $0xff, X0, X2
PSHUFL $0x00, X0, X3
PSHUFL $0x55, X0, X0
MOVOA X1, 128(R12)
MOVOA X2, 144(R12)
MOVOA X3, 160(R12)
MOVOA X0, 176(R12)
MOVOA 16(R12), X0
PSHUFL $0xff, X0, X1
PSHUFL $0x55, X0, X2
PSHUFL $0xaa, X0, X0
MOVOA X1, 192(R12)
MOVOA X2, 208(R12)
MOVOA X0, 224(R12)
MOVOA 32(R12), X0
PSHUFL $0x00, X0, X1
PSHUFL $0xaa, X0, X2
PSHUFL $0xff, X0, X0
MOVOA X1, 240(R12)
MOVOA X2, 256(R12)
MOVOA X0, 272(R12)
BYTESATLEAST256:
MOVL 16(R12), DX
MOVL 36(R12), CX
MOVL DX, 288(R12)
MOVL CX, 304(R12)
SHLQ $0x20, CX
ADDQ CX, DX
ADDQ $0x01, DX
MOVQ DX, CX
SHRQ $0x20, CX
MOVL DX, 292(R12)
MOVL CX, 308(R12)
ADDQ $0x01, DX
MOVQ DX, CX
SHRQ $0x20, CX
MOVL DX, 296(R12)
MOVL CX, 312(R12)
ADDQ $0x01, DX
MOVQ DX, CX
SHRQ $0x20, CX
MOVL DX, 300(R12)
MOVL CX, 316(R12)
ADDQ $0x01, DX
MOVQ DX, CX
SHRQ $0x20, CX
MOVL DX, 16(R12)
MOVL CX, 36(R12)
MOVQ R9, 352(R12)
MOVQ $0x00000014, DX
MOVOA 64(R12), X0
MOVOA 80(R12), X1
MOVOA 96(R12), X2
MOVOA 256(R12), X3
MOVOA 272(R12), X4
MOVOA 128(R12), X5
MOVOA 144(R12), X6
MOVOA 176(R12), X7
MOVOA 192(R12), X8
MOVOA 208(R12), X9
MOVOA 224(R12), X10
MOVOA 304(R12), X11
MOVOA 112(R12), X12
MOVOA 160(R12), X13
MOVOA 240(R12), X14
MOVOA 288(R12), X15
MAINLOOP1:
MOVOA X1, 320(R12)
MOVOA X2, 336(R12)
MOVOA X13, X1
PADDL X12, X1
MOVOA X1, X2
PSLLL $0x07, X1
PXOR X1, X14
PSRLL $0x19, X2
PXOR X2, X14
MOVOA X7, X1
PADDL X0, X1
MOVOA X1, X2
PSLLL $0x07, X1
PXOR X1, X11
PSRLL $0x19, X2
PXOR X2, X11
MOVOA X12, X1
PADDL X14, X1
MOVOA X1, X2
PSLLL $0x09, X1
PXOR X1, X15
PSRLL $0x17, X2
PXOR X2, X15
MOVOA X0, X1
PADDL X11, X1
MOVOA X1, X2
PSLLL $0x09, X1
PXOR X1, X9
PSRLL $0x17, X2
PXOR X2, X9
MOVOA X14, X1
PADDL X15, X1
MOVOA X1, X2
PSLLL $0x0d, X1
PXOR X1, X13
PSRLL $0x13, X2
PXOR X2, X13
MOVOA X11, X1
PADDL X9, X1
MOVOA X1, X2
PSLLL $0x0d, X1
PXOR X1, X7
PSRLL $0x13, X2
PXOR X2, X7
MOVOA X15, X1
PADDL X13, X1
MOVOA X1, X2
PSLLL $0x12, X1
PXOR X1, X12
PSRLL $0x0e, X2
PXOR X2, X12
MOVOA 320(R12), X1
MOVOA X12, 320(R12)
MOVOA X9, X2
PADDL X7, X2
MOVOA X2, X12
PSLLL $0x12, X2
PXOR X2, X0
PSRLL $0x0e, X12
PXOR X12, X0
MOVOA X5, X2
PADDL X1, X2
MOVOA X2, X12
PSLLL $0x07, X2
PXOR X2, X3
PSRLL $0x19, X12
PXOR X12, X3
MOVOA 336(R12), X2
MOVOA X0, 336(R12)
MOVOA X6, X0
PADDL X2, X0
MOVOA X0, X12
PSLLL $0x07, X0
PXOR X0, X4
PSRLL $0x19, X12
PXOR X12, X4
MOVOA X1, X0
PADDL X3, X0
MOVOA X0, X12
PSLLL $0x09, X0
PXOR X0, X10
PSRLL $0x17, X12
PXOR X12, X10
MOVOA X2, X0
PADDL X4, X0
MOVOA X0, X12
PSLLL $0x09, X0
PXOR X0, X8
PSRLL $0x17, X12
PXOR X12, X8
MOVOA X3, X0
PADDL X10, X0
MOVOA X0, X12
PSLLL $0x0d, X0
PXOR X0, X5
PSRLL $0x13, X12
PXOR X12, X5
MOVOA X4, X0
PADDL X8, X0
MOVOA X0, X12
PSLLL $0x0d, X0
PXOR X0, X6
PSRLL $0x13, X12
PXOR X12, X6
MOVOA X10, X0
PADDL X5, X0
MOVOA X0, X12
PSLLL $0x12, X0
PXOR X0, X1
PSRLL $0x0e, X12
PXOR X12, X1
MOVOA 320(R12), X0
MOVOA X1, 320(R12)
MOVOA X4, X1
PADDL X0, X1
MOVOA X1, X12
PSLLL $0x07, X1
PXOR X1, X7
PSRLL $0x19, X12
PXOR X12, X7
MOVOA X8, X1
PADDL X6, X1
MOVOA X1, X12
PSLLL $0x12, X1
PXOR X1, X2
PSRLL $0x0e, X12
PXOR X12, X2
MOVOA 336(R12), X12
MOVOA X2, 336(R12)
MOVOA X14, X1
PADDL X12, X1
MOVOA X1, X2
PSLLL $0x07, X1
PXOR X1, X5
PSRLL $0x19, X2
PXOR X2, X5
MOVOA X0, X1
PADDL X7, X1
MOVOA X1, X2
PSLLL $0x09, X1
PXOR X1, X10
PSRLL $0x17, X2
PXOR X2, X10
MOVOA X12, X1
PADDL X5, X1
MOVOA X1, X2
PSLLL $0x09, X1
PXOR X1, X8
PSRLL $0x17, X2
PXOR X2, X8
MOVOA X7, X1
PADDL X10, X1
MOVOA X1, X2
PSLLL $0x0d, X1
PXOR X1, X4
PSRLL $0x13, X2
PXOR X2, X4
MOVOA X5, X1
PADDL X8, X1
MOVOA X1, X2
PSLLL $0x0d, X1
PXOR X1, X14
PSRLL $0x13, X2
PXOR X2, X14
MOVOA X10, X1
PADDL X4, X1
MOVOA X1, X2
PSLLL $0x12, X1
PXOR X1, X0
PSRLL $0x0e, X2
PXOR X2, X0
MOVOA 320(R12), X1
MOVOA X0, 320(R12)
MOVOA X8, X0
PADDL X14, X0
MOVOA X0, X2
PSLLL $0x12, X0
PXOR X0, X12
PSRLL $0x0e, X2
PXOR X2, X12
MOVOA X11, X0
PADDL X1, X0
MOVOA X0, X2
PSLLL $0x07, X0
PXOR X0, X6
PSRLL $0x19, X2
PXOR X2, X6
MOVOA 336(R12), X2
MOVOA X12, 336(R12)
MOVOA X3, X0
PADDL X2, X0
MOVOA X0, X12
PSLLL $0x07, X0
PXOR X0, X13
PSRLL $0x19, X12
PXOR X12, X13
MOVOA X1, X0
PADDL X6, X0
MOVOA X0, X12
PSLLL $0x09, X0
PXOR X0, X15
PSRLL $0x17, X12
PXOR X12, X15
MOVOA X2, X0
PADDL X13, X0
MOVOA X0, X12
PSLLL $0x09, X0
PXOR X0, X9
PSRLL $0x17, X12
PXOR X12, X9
MOVOA X6, X0
PADDL X15, X0
MOVOA X0, X12
PSLLL $0x0d, X0
PXOR X0, X11
PSRLL $0x13, X12
PXOR X12, X11
MOVOA X13, X0
PADDL X9, X0
MOVOA X0, X12
PSLLL $0x0d, X0
PXOR X0, X3
PSRLL $0x13, X12
PXOR X12, X3
MOVOA X15, X0
PADDL X11, X0
MOVOA X0, X12
PSLLL $0x12, X0
PXOR X0, X1
PSRLL $0x0e, X12
PXOR X12, X1
MOVOA X9, X0
PADDL X3, X0
MOVOA X0, X12
PSLLL $0x12, X0
PXOR X0, X2
PSRLL $0x0e, X12
PXOR X12, X2
MOVOA 320(R12), X12
MOVOA 336(R12), X0
SUBQ $0x02, DX
JA MAINLOOP1
PADDL 112(R12), X12
PADDL 176(R12), X7
PADDL 224(R12), X10
PADDL 272(R12), X4
MOVD X12, DX
MOVD X7, CX
MOVD X10, R8
MOVD X4, R9
PSHUFL $0x39, X12, X12
PSHUFL $0x39, X7, X7
PSHUFL $0x39, X10, X10
PSHUFL $0x39, X4, X4
XORL (SI), DX
XORL 4(SI), CX
XORL 8(SI), R8
XORL 12(SI), R9
MOVL DX, (DI)
MOVL CX, 4(DI)
MOVL R8, 8(DI)
MOVL R9, 12(DI)
MOVD X12, DX
MOVD X7, CX
MOVD X10, R8
MOVD X4, R9
PSHUFL $0x39, X12, X12
PSHUFL $0x39, X7, X7
PSHUFL $0x39, X10, X10
PSHUFL $0x39, X4, X4
XORL 64(SI), DX
XORL 68(SI), CX
XORL 72(SI), R8
XORL 76(SI), R9
MOVL DX, 64(DI)
MOVL CX, 68(DI)
MOVL R8, 72(DI)
MOVL R9, 76(DI)
MOVD X12, DX
MOVD X7, CX
MOVD X10, R8
MOVD X4, R9
PSHUFL $0x39, X12, X12
PSHUFL $0x39, X7, X7
PSHUFL $0x39, X10, X10
PSHUFL $0x39, X4, X4
XORL 128(SI), DX
XORL 132(SI), CX
XORL 136(SI), R8
XORL 140(SI), R9
MOVL DX, 128(DI)
MOVL CX, 132(DI)
MOVL R8, 136(DI)
MOVL R9, 140(DI)
MOVD X12, DX
MOVD X7, CX
MOVD X10, R8
MOVD X4, R9
XORL 192(SI), DX
XORL 196(SI), CX
XORL 200(SI), R8
XORL 204(SI), R9
MOVL DX, 192(DI)
MOVL CX, 196(DI)
MOVL R8, 200(DI)
MOVL R9, 204(DI)
PADDL 240(R12), X14
PADDL 64(R12), X0
PADDL 128(R12), X5
PADDL 192(R12), X8
MOVD X14, DX
MOVD X0, CX
MOVD X5, R8
MOVD X8, R9
PSHUFL $0x39, X14, X14
PSHUFL $0x39, X0, X0
PSHUFL $0x39, X5, X5
PSHUFL $0x39, X8, X8
XORL 16(SI), DX
XORL 20(SI), CX
XORL 24(SI), R8
XORL 28(SI), R9
MOVL DX, 16(DI)
MOVL CX, 20(DI)
MOVL R8, 24(DI)
MOVL R9, 28(DI)
MOVD X14, DX
MOVD X0, CX
MOVD X5, R8
MOVD X8, R9
PSHUFL $0x39, X14, X14
PSHUFL $0x39, X0, X0
PSHUFL $0x39, X5, X5
PSHUFL $0x39, X8, X8
XORL 80(SI), DX
XORL 84(SI), CX
XORL 88(SI), R8
XORL 92(SI), R9
MOVL DX, 80(DI)
MOVL CX, 84(DI)
MOVL R8, 88(DI)
MOVL R9, 92(DI)
MOVD X14, DX
MOVD X0, CX
MOVD X5, R8
MOVD X8, R9
PSHUFL $0x39, X14, X14
PSHUFL $0x39, X0, X0
PSHUFL $0x39, X5, X5
PSHUFL $0x39, X8, X8
XORL 144(SI), DX
XORL 148(SI), CX
XORL 152(SI), R8
XORL 156(SI), R9
MOVL DX, 144(DI)
MOVL CX, 148(DI)
MOVL R8, 152(DI)
MOVL R9, 156(DI)
MOVD X14, DX
MOVD X0, CX
MOVD X5, R8
MOVD X8, R9
XORL 208(SI), DX
XORL 212(SI), CX
XORL 216(SI), R8
XORL 220(SI), R9
MOVL DX, 208(DI)
MOVL CX, 212(DI)
MOVL R8, 216(DI)
MOVL R9, 220(DI)
PADDL 288(R12), X15
PADDL 304(R12), X11
PADDL 80(R12), X1
PADDL 144(R12), X6
MOVD X15, DX
MOVD X11, CX
MOVD X1, R8
MOVD X6, R9
PSHUFL $0x39, X15, X15
PSHUFL $0x39, X11, X11
PSHUFL $0x39, X1, X1
PSHUFL $0x39, X6, X6
XORL 32(SI), DX
XORL 36(SI), CX
XORL 40(SI), R8
XORL 44(SI), R9
MOVL DX, 32(DI)
MOVL CX, 36(DI)
MOVL R8, 40(DI)
MOVL R9, 44(DI)
MOVD X15, DX
MOVD X11, CX
MOVD X1, R8
MOVD X6, R9
PSHUFL $0x39, X15, X15
PSHUFL $0x39, X11, X11
PSHUFL $0x39, X1, X1
PSHUFL $0x39, X6, X6
XORL 96(SI), DX
XORL 100(SI), CX
XORL 104(SI), R8
XORL 108(SI), R9
MOVL DX, 96(DI)
MOVL CX, 100(DI)
MOVL R8, 104(DI)
MOVL R9, 108(DI)
MOVD X15, DX
MOVD X11, CX
MOVD X1, R8
MOVD X6, R9
PSHUFL $0x39, X15, X15
PSHUFL $0x39, X11, X11
PSHUFL $0x39, X1, X1
PSHUFL $0x39, X6, X6
XORL 160(SI), DX
XORL 164(SI), CX
XORL 168(SI), R8
XORL 172(SI), R9
MOVL DX, 160(DI)
MOVL CX, 164(DI)
MOVL R8, 168(DI)
MOVL R9, 172(DI)
MOVD X15, DX
MOVD X11, CX
MOVD X1, R8
MOVD X6, R9
XORL 224(SI), DX
XORL 228(SI), CX
XORL 232(SI), R8
XORL 236(SI), R9
MOVL DX, 224(DI)
MOVL CX, 228(DI)
MOVL R8, 232(DI)
MOVL R9, 236(DI)
PADDL 160(R12), X13
PADDL 208(R12), X9
PADDL 256(R12), X3
PADDL 96(R12), X2
MOVD X13, DX
MOVD X9, CX
MOVD X3, R8
MOVD X2, R9
PSHUFL $0x39, X13, X13
PSHUFL $0x39, X9, X9
PSHUFL $0x39, X3, X3
PSHUFL $0x39, X2, X2
XORL 48(SI), DX
XORL 52(SI), CX
XORL 56(SI), R8
XORL 60(SI), R9
MOVL DX, 48(DI)
MOVL CX, 52(DI)
MOVL R8, 56(DI)
MOVL R9, 60(DI)
MOVD X13, DX
MOVD X9, CX
MOVD X3, R8
MOVD X2, R9
PSHUFL $0x39, X13, X13
PSHUFL $0x39, X9, X9
PSHUFL $0x39, X3, X3
PSHUFL $0x39, X2, X2
XORL 112(SI), DX
XORL 116(SI), CX
XORL 120(SI), R8
XORL 124(SI), R9
MOVL DX, 112(DI)
MOVL CX, 116(DI)
MOVL R8, 120(DI)
MOVL R9, 124(DI)
MOVD X13, DX
MOVD X9, CX
MOVD X3, R8
MOVD X2, R9
PSHUFL $0x39, X13, X13
PSHUFL $0x39, X9, X9
PSHUFL $0x39, X3, X3
PSHUFL $0x39, X2, X2
XORL 176(SI), DX
XORL 180(SI), CX
XORL 184(SI), R8
XORL 188(SI), R9
MOVL DX, 176(DI)
MOVL CX, 180(DI)
MOVL R8, 184(DI)
MOVL R9, 188(DI)
MOVD X13, DX
MOVD X9, CX
MOVD X3, R8
MOVD X2, R9
XORL 240(SI), DX
XORL 244(SI), CX
XORL 248(SI), R8
XORL 252(SI), R9
MOVL DX, 240(DI)
MOVL CX, 244(DI)
MOVL R8, 248(DI)
MOVL R9, 252(DI)
MOVQ 352(R12), R9
SUBQ $0x00000100, R9
ADDQ $0x00000100, SI
ADDQ $0x00000100, DI
CMPQ R9, $0x00000100
JAE BYTESATLEAST256
CMPQ R9, $0x00
JBE DONE
BYTESBETWEEN1AND255:
CMPQ R9, $0x40
JAE NOCOPY
MOVQ DI, DX
LEAQ 360(R12), DI
MOVQ R9, CX
REP; MOVSB
LEAQ 360(R12), DI
LEAQ 360(R12), SI
NOCOPY:
MOVQ R9, 352(R12)
MOVOA 48(R12), X0
MOVOA (R12), X1
MOVOA 16(R12), X2
MOVOA 32(R12), X3
MOVOA X1, X4
MOVQ $0x00000014, CX
MAINLOOP2:
PADDL X0, X4
MOVOA X0, X5
MOVOA X4, X6
PSLLL $0x07, X4
PSRLL $0x19, X6
PXOR X4, X3
PXOR X6, X3
PADDL X3, X5
MOVOA X3, X4
MOVOA X5, X6
PSLLL $0x09, X5
PSRLL $0x17, X6
PXOR X5, X2
PSHUFL $0x93, X3, X3
PXOR X6, X2
PADDL X2, X4
MOVOA X2, X5
MOVOA X4, X6
PSLLL $0x0d, X4
PSRLL $0x13, X6
PXOR X4, X1
PSHUFL $0x4e, X2, X2
PXOR X6, X1
PADDL X1, X5
MOVOA X3, X4
MOVOA X5, X6
PSLLL $0x12, X5
PSRLL $0x0e, X6
PXOR X5, X0
PSHUFL $0x39, X1, X1
PXOR X6, X0
PADDL X0, X4
MOVOA X0, X5
MOVOA X4, X6
PSLLL $0x07, X4
PSRLL $0x19, X6
PXOR X4, X1
PXOR X6, X1
PADDL X1, X5
MOVOA X1, X4
MOVOA X5, X6
PSLLL $0x09, X5
PSRLL $0x17, X6
PXOR X5, X2
PSHUFL $0x93, X1, X1
PXOR X6, X2
PADDL X2, X4
MOVOA X2, X5
MOVOA X4, X6
PSLLL $0x0d, X4
PSRLL $0x13, X6
PXOR X4, X3
PSHUFL $0x4e, X2, X2
PXOR X6, X3
PADDL X3, X5
MOVOA X1, X4
MOVOA X5, X6
PSLLL $0x12, X5
PSRLL $0x0e, X6
PXOR X5, X0
PSHUFL $0x39, X3, X3
PXOR X6, X0
PADDL X0, X4
MOVOA X0, X5
MOVOA X4, X6
PSLLL $0x07, X4
PSRLL $0x19, X6
PXOR X4, X3
PXOR X6, X3
PADDL X3, X5
MOVOA X3, X4
MOVOA X5, X6
PSLLL $0x09, X5
PSRLL $0x17, X6
PXOR X5, X2
PSHUFL $0x93, X3, X3
PXOR X6, X2
PADDL X2, X4
MOVOA X2, X5
MOVOA X4, X6
PSLLL $0x0d, X4
PSRLL $0x13, X6
PXOR X4, X1
PSHUFL $0x4e, X2, X2
PXOR X6, X1
PADDL X1, X5
MOVOA X3, X4
MOVOA X5, X6
PSLLL $0x12, X5
PSRLL $0x0e, X6
PXOR X5, X0
PSHUFL $0x39, X1, X1
PXOR X6, X0
PADDL X0, X4
MOVOA X0, X5
MOVOA X4, X6
PSLLL $0x07, X4
PSRLL $0x19, X6
PXOR X4, X1
PXOR X6, X1
PADDL X1, X5
MOVOA X1, X4
MOVOA X5, X6
PSLLL $0x09, X5
PSRLL $0x17, X6
PXOR X5, X2
PSHUFL $0x93, X1, X1
PXOR X6, X2
PADDL X2, X4
MOVOA X2, X5
MOVOA X4, X6
PSLLL $0x0d, X4
PSRLL $0x13, X6
PXOR X4, X3
PSHUFL $0x4e, X2, X2
PXOR X6, X3
SUBQ $0x04, CX
PADDL X3, X5
MOVOA X1, X4
MOVOA X5, X6
PSLLL $0x12, X5
PXOR X7, X7
PSRLL $0x0e, X6
PXOR X5, X0
PSHUFL $0x39, X3, X3
PXOR X6, X0
JA MAINLOOP2
PADDL 48(R12), X0
PADDL (R12), X1
PADDL 16(R12), X2
PADDL 32(R12), X3
MOVD X0, CX
MOVD X1, R8
MOVD X2, R9
MOVD X3, AX
PSHUFL $0x39, X0, X0
PSHUFL $0x39, X1, X1
PSHUFL $0x39, X2, X2
PSHUFL $0x39, X3, X3
XORL (SI), CX
XORL 48(SI), R8
XORL 32(SI), R9
XORL 16(SI), AX
MOVL CX, (DI)
MOVL R8, 48(DI)
MOVL R9, 32(DI)
MOVL AX, 16(DI)
MOVD X0, CX
MOVD X1, R8
MOVD X2, R9
MOVD X3, AX
PSHUFL $0x39, X0, X0
PSHUFL $0x39, X1, X1
PSHUFL $0x39, X2, X2
PSHUFL $0x39, X3, X3
XORL 20(SI), CX
XORL 4(SI), R8
XORL 52(SI), R9
XORL 36(SI), AX
MOVL CX, 20(DI)
MOVL R8, 4(DI)
MOVL R9, 52(DI)
MOVL AX, 36(DI)
MOVD X0, CX
MOVD X1, R8
MOVD X2, R9
MOVD X3, AX
PSHUFL $0x39, X0, X0
PSHUFL $0x39, X1, X1
PSHUFL $0x39, X2, X2
PSHUFL $0x39, X3, X3
XORL 40(SI), CX
XORL 24(SI), R8
XORL 8(SI), R9
XORL 56(SI), AX
MOVL CX, 40(DI)
MOVL R8, 24(DI)
MOVL R9, 8(DI)
MOVL AX, 56(DI)
MOVD X0, CX
MOVD X1, R8
MOVD X2, R9
MOVD X3, AX
XORL 60(SI), CX
XORL 44(SI), R8
XORL 28(SI), R9
XORL 12(SI), AX
MOVL CX, 60(DI)
MOVL R8, 44(DI)
MOVL R9, 28(DI)
MOVL AX, 12(DI)
MOVQ 352(R12), R9
MOVL 16(R12), CX
MOVL 36(R12), R8
ADDQ $0x01, CX
SHLQ $0x20, R8
ADDQ R8, CX
MOVQ CX, R8
SHRQ $0x20, R8
MOVL CX, 16(R12)
MOVL R8, 36(R12)
CMPQ R9, $0x40
JA BYTESATLEAST65
JAE BYTESATLEAST64
MOVQ DI, SI
MOVQ DX, DI
MOVQ R9, CX
REP; MOVSB
BYTESATLEAST64:
DONE:
RET
BYTESATLEAST65:
SUBQ $0x40, R9
ADDQ $0x40, DI
ADDQ $0x40, SI
JMP BYTESBETWEEN1AND255
================================================
FILE: vendor/golang.org/x/crypto/salsa20/salsa/salsa20_noasm.go
================================================
// Copyright 2019 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.
//go:build !amd64 || purego || !gc
package salsa
// XORKeyStream crypts bytes from in to out using the given key and counters.
// In and out must overlap entirely or not at all. Counter
// contains the raw salsa20 counter bytes (both nonce and block counter).
func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) {
genericXORKeyStream(out, in, counter, key)
}
================================================
FILE: vendor/golang.org/x/crypto/salsa20/salsa/salsa20_ref.go
================================================
// Copyright 2012 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.
package salsa
import "math/bits"
const rounds = 20
// core applies the Salsa20 core function to 16-byte input in, 32-byte key k,
// and 16-byte constant c, and puts the result into 64-byte array out.
func core(out *[64]byte, in *[16]byte, k *[32]byte, c *[16]byte) {
j0 := uint32(c[0]) | uint32(c[1])<<8 | uint32(c[2])<<16 | uint32(c[3])<<24
j1 := uint32(k[0]) | uint32(k[1])<<8 | uint32(k[2])<<16 | uint32(k[3])<<24
j2 := uint32(k[4]) | uint32(k[5])<<8 | uint32(k[6])<<16 | uint32(k[7])<<24
j3 := uint32(k[8]) | uint32(k[9])<<8 | uint32(k[10])<<16 | uint32(k[11])<<24
j4 := uint32(k[12]) | uint32(k[13])<<8 | uint32(k[14])<<16 | uint32(k[15])<<24
j5 := uint32(c[4]) | uint32(c[5])<<8 | uint32(c[6])<<16 | uint32(c[7])<<24
j6 := uint32(in[0]) | uint32(in[1])<<8 | uint32(in[2])<<16 | uint32(in[3])<<24
j7 := uint32(in[4]) | uint32(in[5])<<8 | uint32(in[6])<<16 | uint32(in[7])<<24
j8 := uint32(in[8]) | uint32(in[9])<<8 | uint32(in[10])<<16 | uint32(in[11])<<24
j9 := uint32(in[12]) | uint32(in[13])<<8 | uint32(in[14])<<16 | uint32(in[15])<<24
j10 := uint32(c[8]) | uint32(c[9])<<8 | uint32(c[10])<<16 | uint32(c[11])<<24
j11 := uint32(k[16]) | uint32(k[17])<<8 | uint32(k[18])<<16 | uint32(k[19])<<24
j12 := uint32(k[20]) | uint32(k[21])<<8 | uint32(k[22])<<16 | uint32(k[23])<<24
j13 := uint32(k[24]) | uint32(k[25])<<8 | uint32(k[26])<<16 | uint32(k[27])<<24
j14 := uint32(k[28]) | uint32(k[29])<<8 | uint32(k[30])<<16 | uint32(k[31])<<24
j15 := uint32(c[12]) | uint32(c[13])<<8 | uint32(c[14])<<16 | uint32(c[15])<<24
x0, x1, x2, x3, x4, x5, x6, x7, x8 := j0, j1, j2, j3, j4, j5, j6, j7, j8
x9, x10, x11, x12, x13, x14, x15 := j9, j10, j11, j12, j13, j14, j15
for i := 0; i < rounds; i += 2 {
u := x0 + x12
x4 ^= bits.RotateLeft32(u, 7)
u = x4 + x0
x8 ^= bits.RotateLeft32(u, 9)
u = x8 + x4
x12 ^= bits.RotateLeft32(u, 13)
u = x12 + x8
x0 ^= bits.RotateLeft32(u, 18)
u = x5 + x1
x9 ^= bits.RotateLeft32(u, 7)
u = x9 + x5
x13 ^= bits.RotateLeft32(u, 9)
u = x13 + x9
x1 ^= bits.RotateLeft32(u, 13)
u = x1 + x13
x5 ^= bits.RotateLeft32(u, 18)
u = x10 + x6
x14 ^= bits.RotateLeft32(u, 7)
u = x14 + x10
x2 ^= bits.RotateLeft32(u, 9)
u = x2 + x14
x6 ^= bits.RotateLeft32(u, 13)
u = x6 + x2
x10 ^= bits.RotateLeft32(u, 18)
u = x15 + x11
x3 ^= bits.RotateLeft32(u, 7)
u = x3 + x15
x7 ^= bits.RotateLeft32(u, 9)
u = x7 + x3
x11 ^= bits.RotateLeft32(u, 13)
u = x11 + x7
x15 ^= bits.RotateLeft32(u, 18)
u = x0 + x3
x1 ^= bits.RotateLeft32(u, 7)
u = x1 + x0
x2 ^= bits.RotateLeft32(u, 9)
u = x2 + x1
x3 ^= bits.RotateLeft32(u, 13)
u = x3 + x2
x0 ^= bits.RotateLeft32(u, 18)
u = x5 + x4
x6 ^= bits.RotateLeft32(u, 7)
u = x6 + x5
x7 ^= bits.RotateLeft32(u, 9)
u = x7 + x6
x4 ^= bits.RotateLeft32(u, 13)
u = x4 + x7
x5 ^= bits.RotateLeft32(u, 18)
u = x10 + x9
x11 ^= bits.RotateLeft32(u, 7)
u = x11 + x10
x8 ^= bits.RotateLeft32(u, 9)
u = x8 + x11
x9 ^= bits.RotateLeft32(u, 13)
u = x9 + x8
x10 ^= bits.RotateLeft32(u, 18)
u = x15 + x14
x12 ^= bits.RotateLeft32(u, 7)
u = x12 + x15
x13 ^= bits.RotateLeft32(u, 9)
u = x13 + x12
x14 ^= bits.RotateLeft32(u, 13)
u = x14 + x13
x15 ^= bits.RotateLeft32(u, 18)
}
x0 += j0
x1 += j1
x2 += j2
x3 += j3
x4 += j4
x5 += j5
x6 += j6
x7 += j7
x8 += j8
x9 += j9
x10 += j10
x11 += j11
x12 += j12
x13 += j13
x14 += j14
x15 += j15
out[0] = byte(x0)
out[1] = byte(x0 >> 8)
out[2] = byte(x0 >> 16)
out[3] = byte(x0 >> 24)
out[4] = byte(x1)
out[5] = byte(x1 >> 8)
out[6] = byte(x1 >> 16)
out[7] = byte(x1 >> 24)
out[8] = byte(x2)
out[9] = byte(x2 >> 8)
out[10] = byte(x2 >> 16)
out[11] = byte(x2 >> 24)
out[12] = byte(x3)
out[13] = byte(x3 >> 8)
out[14] = byte(x3 >> 16)
out[15] = byte(x3 >> 24)
out[16] = byte(x4)
out[17] = byte(x4 >> 8)
out[18] = byte(x4 >> 16)
out[19] = byte(x4 >> 24)
out[20] = byte(x5)
out[21] = byte(x5 >> 8)
out[22] = byte(x5 >> 16)
out[23] = byte(x5 >> 24)
out[24] = byte(x6)
out[25] = byte(x6 >> 8)
out[26] = byte(x6 >> 16)
out[27] = byte(x6 >> 24)
out[28] = byte(x7)
out[29] = byte(x7 >> 8)
out[30] = byte(x7 >> 16)
out[31] = byte(x7 >> 24)
out[32] = byte(x8)
out[33] = byte(x8 >> 8)
out[34] = byte(x8 >> 16)
out[35] = byte(x8 >> 24)
out[36] = byte(x9)
out[37] = byte(x9 >> 8)
out[38] = byte(x9 >> 16)
out[39] = byte(x9 >> 24)
out[40] = byte(x10)
out[41] = byte(x10 >> 8)
out[42] = byte(x10 >> 16)
out[43] = byte(x10 >> 24)
out[44] = byte(x11)
out[45] = byte(x11 >> 8)
out[46] = byte(x11 >> 16)
out[47] = byte(x11 >> 24)
out[48] = byte(x12)
out[49] = byte(x12 >> 8)
out[50] = byte(x12 >> 16)
out[51] = byte(x12 >> 24)
out[52] = byte(x13)
out[53] = byte(x13 >> 8)
out[54] = byte(x13 >> 16)
out[55] = byte(x13 >> 24)
out[56] = byte(x14)
out[57] = byte(x14 >> 8)
out[58] = byte(x14 >> 16)
out[59] = byte(x14 >> 24)
out[60] = byte(x15)
out[61] = byte(x15 >> 8)
out[62] = byte(x15 >> 16)
out[63] = byte(x15 >> 24)
}
// genericXORKeyStream is the generic implementation of XORKeyStream to be used
// when no assembly implementation is available.
func genericXORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) {
var block [64]byte
var counterCopy [16]byte
copy(counterCopy[:], counter[:])
for len(in) >= 64 {
core(&block, &counterCopy, key, &Sigma)
for i, x := range block {
out[i] = in[i] ^ x
}
u := uint32(1)
for i := 8; i < 16; i++ {
u += uint32(counterCopy[i])
counterCopy[i] = byte(u)
u >>= 8
}
in = in[64:]
out = out[64:]
}
if len(in) > 0 {
core(&block, &counterCopy, key, &Sigma)
for i, v := range in {
out[i] = v ^ block[i]
}
}
}
================================================
FILE: vendor/golang.org/x/sys/LICENSE
================================================
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: vendor/golang.org/x/sys/PATENTS
================================================
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the Go project.
Google hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as stated in this section)
patent license to make, have made, use, offer to sell, sell, import,
transfer and otherwise run, modify and propagate the contents of this
implementation of Go, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of Go. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of Go or any code incorporated within this
implementation of Go constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of Go
shall terminate as of the date such litigation is filed.
================================================
FILE: vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s
================================================
// Copyright 2018 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.
//go:build gc
#include "textflag.h"
//
// System calls for ppc64, AIX are implemented in runtime/syscall_aix.go
//
TEXT ·syscall6(SB),NOSPLIT,$0-88
JMP syscall·syscall6(SB)
TEXT ·rawSyscall6(SB),NOSPLIT,$0-88
JMP syscall·rawSyscall6(SB)
================================================
FILE: vendor/golang.org/x/sys/cpu/asm_darwin_x86_gc.s
================================================
// Copyright 2024 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.
//go:build darwin && amd64 && gc
#include "textflag.h"
TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_sysctl(SB)
GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $8
DATA ·libc_sysctl_trampoline_addr(SB)/8, $libc_sysctl_trampoline<>(SB)
TEXT libc_sysctlbyname_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_sysctlbyname(SB)
GLOBL ·libc_sysctlbyname_trampoline_addr(SB), RODATA, $8
DATA ·libc_sysctlbyname_trampoline_addr(SB)/8, $libc_sysctlbyname_trampoline<>(SB)
================================================
FILE: vendor/golang.org/x/sys/cpu/byteorder.go
================================================
// Copyright 2019 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.
package cpu
import (
"runtime"
)
// byteOrder is a subset of encoding/binary.ByteOrder.
type byteOrder interface {
Uint32([]byte) uint32
Uint64([]byte) uint64
}
type littleEndian struct{}
type bigEndian struct{}
func (littleEndian) Uint32(b []byte) uint32 {
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
}
func (littleEndian) Uint64(b []byte) uint64 {
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
}
func (bigEndian) Uint32(b []byte) uint32 {
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
}
func (bigEndian) Uint64(b []byte) uint64 {
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
}
// hostByteOrder returns littleEndian on little-endian machines and
// bigEndian on big-endian machines.
func hostByteOrder() byteOrder {
switch runtime.GOARCH {
case "386", "amd64", "amd64p32",
"alpha",
"arm", "arm64",
"loong64",
"mipsle", "mips64le", "mips64p32le",
"nios2",
"ppc64le",
"riscv", "riscv64",
"sh":
return littleEndian{}
case "armbe", "arm64be",
"m68k",
"mips", "mips64", "mips64p32",
"ppc", "ppc64",
"s390", "s390x",
"shbe",
"sparc", "sparc64":
return bigEndian{}
}
panic("unknown architecture")
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu.go
================================================
// Copyright 2018 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.
// Package cpu implements processor feature detection for
// various CPU architectures.
package cpu
import (
"os"
"strings"
)
// Initialized reports whether the CPU features were initialized.
//
// For some GOOS/GOARCH combinations initialization of the CPU features depends
// on reading an operating specific file, e.g. /proc/self/auxv on linux/arm
// Initialized will report false if reading the file fails.
var Initialized bool
// CacheLinePad is used to pad structs to avoid false sharing.
type CacheLinePad struct{ _ [cacheLineSize]byte }
// X86 contains the supported CPU features of the
// current X86/AMD64 platform. If the current platform
// is not X86/AMD64 then all feature flags are false.
//
// X86 is padded to avoid false sharing. Further the HasAVX
// and HasAVX2 are only set if the OS supports XMM and YMM
// registers in addition to the CPUID feature bit being set.
var X86 struct {
_ CacheLinePad
HasAES bool // AES hardware implementation (AES NI)
HasADX bool // Multi-precision add-carry instruction extensions
HasAVX bool // Advanced vector extension
HasAVX2 bool // Advanced vector extension 2
HasAVX512 bool // Advanced vector extension 512
HasAVX512F bool // Advanced vector extension 512 Foundation Instructions
HasAVX512CD bool // Advanced vector extension 512 Conflict Detection Instructions
HasAVX512ER bool // Advanced vector extension 512 Exponential and Reciprocal Instructions
HasAVX512PF bool // Advanced vector extension 512 Prefetch Instructions
HasAVX512VL bool // Advanced vector extension 512 Vector Length Extensions
HasAVX512BW bool // Advanced vector extension 512 Byte and Word Instructions
HasAVX512DQ bool // Advanced vector extension 512 Doubleword and Quadword Instructions
HasAVX512IFMA bool // Advanced vector extension 512 Integer Fused Multiply Add
HasAVX512VBMI bool // Advanced vector extension 512 Vector Byte Manipulation Instructions
HasAVX5124VNNIW bool // Advanced vector extension 512 Vector Neural Network Instructions Word variable precision
HasAVX5124FMAPS bool // Advanced vector extension 512 Fused Multiply Accumulation Packed Single precision
HasAVX512VPOPCNTDQ bool // Advanced vector extension 512 Double and quad word population count instructions
HasAVX512VPCLMULQDQ bool // Advanced vector extension 512 Vector carry-less multiply operations
HasAVX512VNNI bool // Advanced vector extension 512 Vector Neural Network Instructions
HasAVX512GFNI bool // Advanced vector extension 512 Galois field New Instructions
HasAVX512VAES bool // Advanced vector extension 512 Vector AES instructions
HasAVX512VBMI2 bool // Advanced vector extension 512 Vector Byte Manipulation Instructions 2
HasAVX512BITALG bool // Advanced vector extension 512 Bit Algorithms
HasAVX512BF16 bool // Advanced vector extension 512 BFloat16 Instructions
HasAMXTile bool // Advanced Matrix Extension Tile instructions
HasAMXInt8 bool // Advanced Matrix Extension Int8 instructions
HasAMXBF16 bool // Advanced Matrix Extension BFloat16 instructions
HasBMI1 bool // Bit manipulation instruction set 1
HasBMI2 bool // Bit manipulation instruction set 2
HasCX16 bool // Compare and exchange 16 Bytes
HasERMS bool // Enhanced REP for MOVSB and STOSB
HasFMA bool // Fused-multiply-add instructions
HasOSXSAVE bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers.
HasPCLMULQDQ bool // PCLMULQDQ instruction - most often used for AES-GCM
HasPOPCNT bool // Hamming weight instruction POPCNT.
HasRDRAND bool // RDRAND instruction (on-chip random number generator)
HasRDSEED bool // RDSEED instruction (on-chip random number generator)
HasSSE2 bool // Streaming SIMD extension 2 (always available on amd64)
HasSSE3 bool // Streaming SIMD extension 3
HasSSSE3 bool // Supplemental streaming SIMD extension 3
HasSSE41 bool // Streaming SIMD extension 4 and 4.1
HasSSE42 bool // Streaming SIMD extension 4 and 4.2
HasAVXIFMA bool // Advanced vector extension Integer Fused Multiply Add
HasAVXVNNI bool // Advanced vector extension Vector Neural Network Instructions
HasAVXVNNIInt8 bool // Advanced vector extension Vector Neural Network Int8 instructions
_ CacheLinePad
}
// ARM64 contains the supported CPU features of the
// current ARMv8(aarch64) platform. If the current platform
// is not arm64 then all feature flags are false.
var ARM64 struct {
_ CacheLinePad
HasFP bool // Floating-point instruction set (always available)
HasASIMD bool // Advanced SIMD (always available)
HasEVTSTRM bool // Event stream support
HasAES bool // AES hardware implementation
HasPMULL bool // Polynomial multiplication instruction set
HasSHA1 bool // SHA1 hardware implementation
HasSHA2 bool // SHA2 hardware implementation
HasCRC32 bool // CRC32 hardware implementation
HasATOMICS bool // Atomic memory operation instruction set
HasFPHP bool // Half precision floating-point instruction set
HasASIMDHP bool // Advanced SIMD half precision instruction set
HasCPUID bool // CPUID identification scheme registers
HasASIMDRDM bool // Rounding double multiply add/subtract instruction set
HasJSCVT bool // Javascript conversion from floating-point to integer
HasFCMA bool // Floating-point multiplication and addition of complex numbers
HasLRCPC bool // Release Consistent processor consistent support
HasDCPOP bool // Persistent memory support
HasSHA3 bool // SHA3 hardware implementation
HasSM3 bool // SM3 hardware implementation
HasSM4 bool // SM4 hardware implementation
HasASIMDDP bool // Advanced SIMD double precision instruction set
HasSHA512 bool // SHA512 hardware implementation
HasSVE bool // Scalable Vector Extensions
HasSVE2 bool // Scalable Vector Extensions 2
HasASIMDFHM bool // Advanced SIMD multiplication FP16 to FP32
HasDIT bool // Data Independent Timing support
HasI8MM bool // Advanced SIMD Int8 matrix multiplication instructions
_ CacheLinePad
}
// ARM contains the supported CPU features of the current ARM (32-bit) platform.
// All feature flags are false if:
// 1. the current platform is not arm, or
// 2. the current operating system is not Linux.
var ARM struct {
_ CacheLinePad
HasSWP bool // SWP instruction support
HasHALF bool // Half-word load and store support
HasTHUMB bool // ARM Thumb instruction set
Has26BIT bool // Address space limited to 26-bits
HasFASTMUL bool // 32-bit operand, 64-bit result multiplication support
HasFPA bool // Floating point arithmetic support
HasVFP bool // Vector floating point support
HasEDSP bool // DSP Extensions support
HasJAVA bool // Java instruction set
HasIWMMXT bool // Intel Wireless MMX technology support
HasCRUNCH bool // MaverickCrunch context switching and handling
HasTHUMBEE bool // Thumb EE instruction set
HasNEON bool // NEON instruction set
HasVFPv3 bool // Vector floating point version 3 support
HasVFPv3D16 bool // Vector floating point version 3 D8-D15
HasTLS bool // Thread local storage support
HasVFPv4 bool // Vector floating point version 4 support
HasIDIVA bool // Integer divide instruction support in ARM mode
HasIDIVT bool // Integer divide instruction support in Thumb mode
HasVFPD32 bool // Vector floating point version 3 D15-D31
HasLPAE bool // Large Physical Address Extensions
HasEVTSTRM bool // Event stream support
HasAES bool // AES hardware implementation
HasPMULL bool // Polynomial multiplication instruction set
HasSHA1 bool // SHA1 hardware implementation
HasSHA2 bool // SHA2 hardware implementation
HasCRC32 bool // CRC32 hardware implementation
_ CacheLinePad
}
// The booleans in Loong64 contain the correspondingly named cpu feature bit.
// The struct is padded to avoid false sharing.
var Loong64 struct {
_ CacheLinePad
HasLSX bool // support 128-bit vector extension
HasLASX bool // support 256-bit vector extension
HasCRC32 bool // support CRC instruction
HasLAM_BH bool // support AM{SWAP/ADD}[_DB].{B/H} instruction
HasLAMCAS bool // support AMCAS[_DB].{B/H/W/D} instruction
_ CacheLinePad
}
// MIPS64X contains the supported CPU features of the current mips64/mips64le
// platforms. If the current platform is not mips64/mips64le or the current
// operating system is not Linux then all feature flags are false.
var MIPS64X struct {
_ CacheLinePad
HasMSA bool // MIPS SIMD architecture
_ CacheLinePad
}
// PPC64 contains the supported CPU features of the current ppc64/ppc64le platforms.
// If the current platform is not ppc64/ppc64le then all feature flags are false.
//
// For ppc64/ppc64le, it is safe to check only for ISA level starting on ISA v3.00,
// since there are no optional categories. There are some exceptions that also
// require kernel support to work (DARN, SCV), so there are feature bits for
// those as well. The struct is padded to avoid false sharing.
var PPC64 struct {
_ CacheLinePad
HasDARN bool // Hardware random number generator (requires kernel enablement)
HasSCV bool // Syscall vectored (requires kernel enablement)
IsPOWER8 bool // ISA v2.07 (POWER8)
IsPOWER9 bool // ISA v3.00 (POWER9), implies IsPOWER8
_ CacheLinePad
}
// S390X contains the supported CPU features of the current IBM Z
// (s390x) platform. If the current platform is not IBM Z then all
// feature flags are false.
//
// S390X is padded to avoid false sharing. Further HasVX is only set
// if the OS supports vector registers in addition to the STFLE
// feature bit being set.
var S390X struct {
_ CacheLinePad
HasZARCH bool // z/Architecture mode is active [mandatory]
HasSTFLE bool // store facility list extended
HasLDISP bool // long (20-bit) displacements
HasEIMM bool // 32-bit immediates
HasDFP bool // decimal floating point
HasETF3EH bool // ETF-3 enhanced
HasMSA bool // message security assist (CPACF)
HasAES bool // KM-AES{128,192,256} functions
HasAESCBC bool // KMC-AES{128,192,256} functions
HasAESCTR bool // KMCTR-AES{128,192,256} functions
HasAESGCM bool // KMA-GCM-AES{128,192,256} functions
HasGHASH bool // KIMD-GHASH function
HasSHA1 bool // K{I,L}MD-SHA-1 functions
HasSHA256 bool // K{I,L}MD-SHA-256 functions
HasSHA512 bool // K{I,L}MD-SHA-512 functions
HasSHA3 bool // K{I,L}MD-SHA3-{224,256,384,512} and K{I,L}MD-SHAKE-{128,256} functions
HasVX bool // vector facility
HasVXE bool // vector-enhancements facility 1
_ CacheLinePad
}
// RISCV64 contains the supported CPU features and performance characteristics for riscv64
// platforms. The booleans in RISCV64, with the exception of HasFastMisaligned, indicate
// the presence of RISC-V extensions.
//
// It is safe to assume that all the RV64G extensions are supported and so they are omitted from
// this structure. As riscv64 Go programs require at least RV64G, the code that populates
// this structure cannot run successfully if some of the RV64G extensions are missing.
// The struct is padded to avoid false sharing.
var RISCV64 struct {
_ CacheLinePad
HasFastMisaligned bool // Fast misaligned accesses
HasC bool // Compressed instruction-set extension
HasV bool // Vector extension compatible with RVV 1.0
HasZba bool // Address generation instructions extension
HasZbb bool // Basic bit-manipulation extension
HasZbs bool // Single-bit instructions extension
HasZvbb bool // Vector Basic Bit-manipulation
HasZvbc bool // Vector Carryless Multiplication
HasZvkb bool // Vector Cryptography Bit-manipulation
HasZvkt bool // Vector Data-Independent Execution Latency
HasZvkg bool // Vector GCM/GMAC
HasZvkn bool // NIST Algorithm Suite (AES/SHA256/SHA512)
HasZvknc bool // NIST Algorithm Suite with carryless multiply
HasZvkng bool // NIST Algorithm Suite with GCM
HasZvks bool // ShangMi Algorithm Suite
HasZvksc bool // ShangMi Algorithm Suite with carryless multiplication
HasZvksg bool // ShangMi Algorithm Suite with GCM
_ CacheLinePad
}
func init() {
archInit()
initOptions()
processOptions()
}
// options contains the cpu debug options that can be used in GODEBUG.
// Options are arch dependent and are added by the arch specific initOptions functions.
// Features that are mandatory for the specific GOARCH should have the Required field set
// (e.g. SSE2 on amd64).
var options []option
// Option names should be lower case. e.g. avx instead of AVX.
type option struct {
Name string
Feature *bool
Specified bool // whether feature value was specified in GODEBUG
Enable bool // whether feature should be enabled
Required bool // whether feature is mandatory and can not be disabled
}
func processOptions() {
env := os.Getenv("GODEBUG")
field:
for env != "" {
field := ""
i := strings.IndexByte(env, ',')
if i < 0 {
field, env = env, ""
} else {
field, env = env[:i], env[i+1:]
}
if len(field) < 4 || field[:4] != "cpu." {
continue
}
i = strings.IndexByte(field, '=')
if i < 0 {
print("GODEBUG sys/cpu: no value specified for \"", field, "\"\n")
continue
}
key, value := field[4:i], field[i+1:] // e.g. "SSE2", "on"
var enable bool
switch value {
case "on":
enable = true
case "off":
enable = false
default:
print("GODEBUG sys/cpu: value \"", value, "\" not supported for cpu option \"", key, "\"\n")
continue field
}
if key == "all" {
for i := range options {
options[i].Specified = true
options[i].Enable = enable || options[i].Required
}
continue field
}
for i := range options {
if options[i].Name == key {
options[i].Specified = true
options[i].Enable = enable
continue field
}
}
print("GODEBUG sys/cpu: unknown cpu feature \"", key, "\"\n")
}
for _, o := range options {
if !o.Specified {
continue
}
if o.Enable && !*o.Feature {
print("GODEBUG sys/cpu: can not enable \"", o.Name, "\", missing CPU support\n")
continue
}
if !o.Enable && o.Required {
print("GODEBUG sys/cpu: can not disable \"", o.Name, "\", required CPU feature\n")
continue
}
*o.Feature = o.Enable
}
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_aix.go
================================================
// Copyright 2019 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.
//go:build aix
package cpu
const (
// getsystemcfg constants
_SC_IMPL = 2
_IMPL_POWER8 = 0x10000
_IMPL_POWER9 = 0x20000
)
func archInit() {
impl := getsystemcfg(_SC_IMPL)
if impl&_IMPL_POWER8 != 0 {
PPC64.IsPOWER8 = true
}
if impl&_IMPL_POWER9 != 0 {
PPC64.IsPOWER8 = true
PPC64.IsPOWER9 = true
}
Initialized = true
}
func getsystemcfg(label int) (n uint64) {
r0, _ := callgetsystemcfg(label)
n = uint64(r0)
return
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_arm.go
================================================
// Copyright 2018 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.
package cpu
const cacheLineSize = 32
// HWCAP/HWCAP2 bits.
// These are specific to Linux.
const (
hwcap_SWP = 1 << 0
hwcap_HALF = 1 << 1
hwcap_THUMB = 1 << 2
hwcap_26BIT = 1 << 3
hwcap_FAST_MULT = 1 << 4
hwcap_FPA = 1 << 5
hwcap_VFP = 1 << 6
hwcap_EDSP = 1 << 7
hwcap_JAVA = 1 << 8
hwcap_IWMMXT = 1 << 9
hwcap_CRUNCH = 1 << 10
hwcap_THUMBEE = 1 << 11
hwcap_NEON = 1 << 12
hwcap_VFPv3 = 1 << 13
hwcap_VFPv3D16 = 1 << 14
hwcap_TLS = 1 << 15
hwcap_VFPv4 = 1 << 16
hwcap_IDIVA = 1 << 17
hwcap_IDIVT = 1 << 18
hwcap_VFPD32 = 1 << 19
hwcap_LPAE = 1 << 20
hwcap_EVTSTRM = 1 << 21
hwcap2_AES = 1 << 0
hwcap2_PMULL = 1 << 1
hwcap2_SHA1 = 1 << 2
hwcap2_SHA2 = 1 << 3
hwcap2_CRC32 = 1 << 4
)
func initOptions() {
options = []option{
{Name: "pmull", Feature: &ARM.HasPMULL},
{Name: "sha1", Feature: &ARM.HasSHA1},
{Name: "sha2", Feature: &ARM.HasSHA2},
{Name: "swp", Feature: &ARM.HasSWP},
{Name: "thumb", Feature: &ARM.HasTHUMB},
{Name: "thumbee", Feature: &ARM.HasTHUMBEE},
{Name: "tls", Feature: &ARM.HasTLS},
{Name: "vfp", Feature: &ARM.HasVFP},
{Name: "vfpd32", Feature: &ARM.HasVFPD32},
{Name: "vfpv3", Feature: &ARM.HasVFPv3},
{Name: "vfpv3d16", Feature: &ARM.HasVFPv3D16},
{Name: "vfpv4", Feature: &ARM.HasVFPv4},
{Name: "half", Feature: &ARM.HasHALF},
{Name: "26bit", Feature: &ARM.Has26BIT},
{Name: "fastmul", Feature: &ARM.HasFASTMUL},
{Name: "fpa", Feature: &ARM.HasFPA},
{Name: "edsp", Feature: &ARM.HasEDSP},
{Name: "java", Feature: &ARM.HasJAVA},
{Name: "iwmmxt", Feature: &ARM.HasIWMMXT},
{Name: "crunch", Feature: &ARM.HasCRUNCH},
{Name: "neon", Feature: &ARM.HasNEON},
{Name: "idivt", Feature: &ARM.HasIDIVT},
{Name: "idiva", Feature: &ARM.HasIDIVA},
{Name: "lpae", Feature: &ARM.HasLPAE},
{Name: "evtstrm", Feature: &ARM.HasEVTSTRM},
{Name: "aes", Feature: &ARM.HasAES},
{Name: "crc32", Feature: &ARM.HasCRC32},
}
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_arm64.go
================================================
// Copyright 2019 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.
package cpu
import "runtime"
// cacheLineSize is used to prevent false sharing of cache lines.
// We choose 128 because Apple Silicon, a.k.a. M1, has 128-byte cache line size.
// It doesn't cost much and is much more future-proof.
const cacheLineSize = 128
func initOptions() {
options = []option{
{Name: "fp", Feature: &ARM64.HasFP},
{Name: "asimd", Feature: &ARM64.HasASIMD},
{Name: "evstrm", Feature: &ARM64.HasEVTSTRM},
{Name: "aes", Feature: &ARM64.HasAES},
{Name: "fphp", Feature: &ARM64.HasFPHP},
{Name: "jscvt", Feature: &ARM64.HasJSCVT},
{Name: "lrcpc", Feature: &ARM64.HasLRCPC},
{Name: "pmull", Feature: &ARM64.HasPMULL},
{Name: "sha1", Feature: &ARM64.HasSHA1},
{Name: "sha2", Feature: &ARM64.HasSHA2},
{Name: "sha3", Feature: &ARM64.HasSHA3},
{Name: "sha512", Feature: &ARM64.HasSHA512},
{Name: "sm3", Feature: &ARM64.HasSM3},
{Name: "sm4", Feature: &ARM64.HasSM4},
{Name: "sve", Feature: &ARM64.HasSVE},
{Name: "sve2", Feature: &ARM64.HasSVE2},
{Name: "crc32", Feature: &ARM64.HasCRC32},
{Name: "atomics", Feature: &ARM64.HasATOMICS},
{Name: "asimdhp", Feature: &ARM64.HasASIMDHP},
{Name: "cpuid", Feature: &ARM64.HasCPUID},
{Name: "asimrdm", Feature: &ARM64.HasASIMDRDM},
{Name: "fcma", Feature: &ARM64.HasFCMA},
{Name: "dcpop", Feature: &ARM64.HasDCPOP},
{Name: "asimddp", Feature: &ARM64.HasASIMDDP},
{Name: "asimdfhm", Feature: &ARM64.HasASIMDFHM},
{Name: "dit", Feature: &ARM64.HasDIT},
{Name: "i8mm", Feature: &ARM64.HasI8MM},
}
}
func archInit() {
switch runtime.GOOS {
case "freebsd":
readARM64Registers()
case "linux", "netbsd", "openbsd", "windows":
doinit()
default:
// Many platforms don't seem to allow reading these registers.
setMinimalFeatures()
}
}
// setMinimalFeatures fakes the minimal ARM64 features expected by
// TestARM64minimalFeatures.
func setMinimalFeatures() {
ARM64.HasASIMD = true
ARM64.HasFP = true
}
func readARM64Registers() {
Initialized = true
parseARM64SystemRegisters(getisar0(), getisar1(), getpfr0())
}
func parseARM64SystemRegisters(isar0, isar1, pfr0 uint64) {
// ID_AA64ISAR0_EL1
switch extractBits(isar0, 4, 7) {
case 1:
ARM64.HasAES = true
case 2:
ARM64.HasAES = true
ARM64.HasPMULL = true
}
switch extractBits(isar0, 8, 11) {
case 1:
ARM64.HasSHA1 = true
}
switch extractBits(isar0, 12, 15) {
case 1:
ARM64.HasSHA2 = true
case 2:
ARM64.HasSHA2 = true
ARM64.HasSHA512 = true
}
switch extractBits(isar0, 16, 19) {
case 1:
ARM64.HasCRC32 = true
}
switch extractBits(isar0, 20, 23) {
case 2:
ARM64.HasATOMICS = true
}
switch extractBits(isar0, 28, 31) {
case 1:
ARM64.HasASIMDRDM = true
}
switch extractBits(isar0, 32, 35) {
case 1:
ARM64.HasSHA3 = true
}
switch extractBits(isar0, 36, 39) {
case 1:
ARM64.HasSM3 = true
}
switch extractBits(isar0, 40, 43) {
case 1:
ARM64.HasSM4 = true
}
switch extractBits(isar0, 44, 47) {
case 1:
ARM64.HasASIMDDP = true
}
// ID_AA64ISAR1_EL1
switch extractBits(isar1, 0, 3) {
case 1:
ARM64.HasDCPOP = true
}
switch extractBits(isar1, 12, 15) {
case 1:
ARM64.HasJSCVT = true
}
switch extractBits(isar1, 16, 19) {
case 1:
ARM64.HasFCMA = true
}
switch extractBits(isar1, 20, 23) {
case 1:
ARM64.HasLRCPC = true
}
switch extractBits(isar1, 52, 55) {
case 1:
ARM64.HasI8MM = true
}
// ID_AA64PFR0_EL1
switch extractBits(pfr0, 16, 19) {
case 0:
ARM64.HasFP = true
case 1:
ARM64.HasFP = true
ARM64.HasFPHP = true
}
switch extractBits(pfr0, 20, 23) {
case 0:
ARM64.HasASIMD = true
case 1:
ARM64.HasASIMD = true
ARM64.HasASIMDHP = true
}
switch extractBits(pfr0, 32, 35) {
case 1:
ARM64.HasSVE = true
parseARM64SVERegister(getzfr0())
}
switch extractBits(pfr0, 48, 51) {
case 1:
ARM64.HasDIT = true
}
}
func parseARM64SVERegister(zfr0 uint64) {
switch extractBits(zfr0, 0, 3) {
case 1:
ARM64.HasSVE2 = true
}
}
func extractBits(data uint64, start, end uint) uint {
return (uint)(data>>start) & ((1 << (end - start + 1)) - 1)
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_arm64.s
================================================
// Copyright 2019 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.
//go:build gc
#include "textflag.h"
// func getisar0() uint64
TEXT ·getisar0(SB),NOSPLIT,$0-8
// get Instruction Set Attributes 0 into x0
MRS ID_AA64ISAR0_EL1, R0
MOVD R0, ret+0(FP)
RET
// func getisar1() uint64
TEXT ·getisar1(SB),NOSPLIT,$0-8
// get Instruction Set Attributes 1 into x0
MRS ID_AA64ISAR1_EL1, R0
MOVD R0, ret+0(FP)
RET
// func getpfr0() uint64
TEXT ·getpfr0(SB),NOSPLIT,$0-8
// get Processor Feature Register 0 into x0
MRS ID_AA64PFR0_EL1, R0
MOVD R0, ret+0(FP)
RET
// func getzfr0() uint64
TEXT ·getzfr0(SB),NOSPLIT,$0-8
// get SVE Feature Register 0 into x0
MRS ID_AA64ZFR0_EL1, R0
MOVD R0, ret+0(FP)
RET
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_darwin_x86.go
================================================
// Copyright 2024 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.
//go:build darwin && amd64 && gc
package cpu
// darwinSupportsAVX512 checks Darwin kernel for AVX512 support via sysctl
// call (see issue 43089). It also restricts AVX512 support for Darwin to
// kernel version 21.3.0 (MacOS 12.2.0) or later (see issue 49233).
//
// Background:
// Darwin implements a special mechanism to economize on thread state when
// AVX512 specific registers are not in use. This scheme minimizes state when
// preempting threads that haven't yet used any AVX512 instructions, but adds
// special requirements to check for AVX512 hardware support at runtime (e.g.
// via sysctl call or commpage inspection). See issue 43089 and link below for
// full background:
// https://github.com/apple-oss-distributions/xnu/blob/xnu-11215.1.10/osfmk/i386/fpu.c#L214-L240
//
// Additionally, all versions of the Darwin kernel from 19.6.0 through 21.2.0
// (corresponding to MacOS 10.15.6 - 12.1) have a bug that can cause corruption
// of the AVX512 mask registers (K0-K7) upon signal return. For this reason
// AVX512 is considered unsafe to use on Darwin for kernel versions prior to
// 21.3.0, where a fix has been confirmed. See issue 49233 for full background.
func darwinSupportsAVX512() bool {
return darwinSysctlEnabled([]byte("hw.optional.avx512f\x00")) && darwinKernelVersionCheck(21, 3, 0)
}
// Ensure Darwin kernel version is at least major.minor.patch, avoiding dependencies
func darwinKernelVersionCheck(major, minor, patch int) bool {
var release [256]byte
err := darwinOSRelease(&release)
if err != nil {
return false
}
var mmp [3]int
c := 0
Loop:
for _, b := range release[:] {
switch {
case b >= '0' && b <= '9':
mmp[c] = 10*mmp[c] + int(b-'0')
case b == '.':
c++
if c > 2 {
return false
}
case b == 0:
break Loop
default:
return false
}
}
if c != 2 {
return false
}
return mmp[0] > major || mmp[0] == major && (mmp[1] > minor || mmp[1] == minor && mmp[2] >= patch)
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go
================================================
// Copyright 2019 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.
//go:build gc
package cpu
func getisar0() uint64
func getisar1() uint64
func getpfr0() uint64
func getzfr0() uint64
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go
================================================
// Copyright 2019 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.
//go:build gc
package cpu
// haveAsmFunctions reports whether the other functions in this file can
// be safely called.
func haveAsmFunctions() bool { return true }
// The following feature detection functions are defined in cpu_s390x.s.
// They are likely to be expensive to call so the results should be cached.
func stfle() facilityList
func kmQuery() queryResult
func kmcQuery() queryResult
func kmctrQuery() queryResult
func kmaQuery() queryResult
func kimdQuery() queryResult
func klmdQuery() queryResult
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_gc_x86.go
================================================
// Copyright 2018 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.
//go:build (386 || amd64 || amd64p32) && gc
package cpu
// cpuid is implemented in cpu_gc_x86.s for gc compiler
// and in cpu_gccgo.c for gccgo.
func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
// xgetbv with ecx = 0 is implemented in cpu_gc_x86.s for gc compiler
// and in cpu_gccgo.c for gccgo.
func xgetbv() (eax, edx uint32)
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_gc_x86.s
================================================
// Copyright 2018 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.
//go:build (386 || amd64 || amd64p32) && gc
#include "textflag.h"
// func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
TEXT ·cpuid(SB), NOSPLIT, $0-24
MOVL eaxArg+0(FP), AX
MOVL ecxArg+4(FP), CX
CPUID
MOVL AX, eax+8(FP)
MOVL BX, ebx+12(FP)
MOVL CX, ecx+16(FP)
MOVL DX, edx+20(FP)
RET
// func xgetbv() (eax, edx uint32)
TEXT ·xgetbv(SB), NOSPLIT, $0-8
MOVL $0, CX
XGETBV
MOVL AX, eax+0(FP)
MOVL DX, edx+4(FP)
RET
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go
================================================
// Copyright 2019 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.
//go:build gccgo
package cpu
func getisar0() uint64 { return 0 }
func getisar1() uint64 { return 0 }
func getpfr0() uint64 { return 0 }
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go
================================================
// Copyright 2019 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.
//go:build gccgo
package cpu
// haveAsmFunctions reports whether the other functions in this file can
// be safely called.
func haveAsmFunctions() bool { return false }
// TODO(mundaym): the following feature detection functions are currently
// stubs. See https://golang.org/cl/162887 for how to fix this.
// They are likely to be expensive to call so the results should be cached.
func stfle() facilityList { panic("not implemented for gccgo") }
func kmQuery() queryResult { panic("not implemented for gccgo") }
func kmcQuery() queryResult { panic("not implemented for gccgo") }
func kmctrQuery() queryResult { panic("not implemented for gccgo") }
func kmaQuery() queryResult { panic("not implemented for gccgo") }
func kimdQuery() queryResult { panic("not implemented for gccgo") }
func klmdQuery() queryResult { panic("not implemented for gccgo") }
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c
================================================
// Copyright 2018 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.
//go:build (386 || amd64 || amd64p32) && gccgo
#include
#include
#include
// Need to wrap __get_cpuid_count because it's declared as static.
int
gccgoGetCpuidCount(uint32_t leaf, uint32_t subleaf,
uint32_t *eax, uint32_t *ebx,
uint32_t *ecx, uint32_t *edx)
{
return __get_cpuid_count(leaf, subleaf, eax, ebx, ecx, edx);
}
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
#pragma GCC push_options
#pragma GCC target("xsave")
#pragma clang attribute push (__attribute__((target("xsave"))), apply_to=function)
// xgetbv reads the contents of an XCR (Extended Control Register)
// specified in the ECX register into registers EDX:EAX.
// Currently, the only supported value for XCR is 0.
void
gccgoXgetbv(uint32_t *eax, uint32_t *edx)
{
uint64_t v = _xgetbv(0);
*eax = v & 0xffffffff;
*edx = v >> 32;
}
#pragma clang attribute pop
#pragma GCC pop_options
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go
================================================
// Copyright 2018 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.
//go:build (386 || amd64 || amd64p32) && gccgo
package cpu
//extern gccgoGetCpuidCount
func gccgoGetCpuidCount(eaxArg, ecxArg uint32, eax, ebx, ecx, edx *uint32)
func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) {
var a, b, c, d uint32
gccgoGetCpuidCount(eaxArg, ecxArg, &a, &b, &c, &d)
return a, b, c, d
}
//extern gccgoXgetbv
func gccgoXgetbv(eax, edx *uint32)
func xgetbv() (eax, edx uint32) {
var a, d uint32
gccgoXgetbv(&a, &d)
return a, d
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_linux.go
================================================
// Copyright 2018 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.
//go:build !386 && !amd64 && !amd64p32 && !arm64
package cpu
func archInit() {
if err := readHWCAP(); err != nil {
return
}
doinit()
Initialized = true
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_linux_arm.go
================================================
// Copyright 2019 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.
package cpu
func doinit() {
ARM.HasSWP = isSet(hwCap, hwcap_SWP)
ARM.HasHALF = isSet(hwCap, hwcap_HALF)
ARM.HasTHUMB = isSet(hwCap, hwcap_THUMB)
ARM.Has26BIT = isSet(hwCap, hwcap_26BIT)
ARM.HasFASTMUL = isSet(hwCap, hwcap_FAST_MULT)
ARM.HasFPA = isSet(hwCap, hwcap_FPA)
ARM.HasVFP = isSet(hwCap, hwcap_VFP)
ARM.HasEDSP = isSet(hwCap, hwcap_EDSP)
ARM.HasJAVA = isSet(hwCap, hwcap_JAVA)
ARM.HasIWMMXT = isSet(hwCap, hwcap_IWMMXT)
ARM.HasCRUNCH = isSet(hwCap, hwcap_CRUNCH)
ARM.HasTHUMBEE = isSet(hwCap, hwcap_THUMBEE)
ARM.HasNEON = isSet(hwCap, hwcap_NEON)
ARM.HasVFPv3 = isSet(hwCap, hwcap_VFPv3)
ARM.HasVFPv3D16 = isSet(hwCap, hwcap_VFPv3D16)
ARM.HasTLS = isSet(hwCap, hwcap_TLS)
ARM.HasVFPv4 = isSet(hwCap, hwcap_VFPv4)
ARM.HasIDIVA = isSet(hwCap, hwcap_IDIVA)
ARM.HasIDIVT = isSet(hwCap, hwcap_IDIVT)
ARM.HasVFPD32 = isSet(hwCap, hwcap_VFPD32)
ARM.HasLPAE = isSet(hwCap, hwcap_LPAE)
ARM.HasEVTSTRM = isSet(hwCap, hwcap_EVTSTRM)
ARM.HasAES = isSet(hwCap2, hwcap2_AES)
ARM.HasPMULL = isSet(hwCap2, hwcap2_PMULL)
ARM.HasSHA1 = isSet(hwCap2, hwcap2_SHA1)
ARM.HasSHA2 = isSet(hwCap2, hwcap2_SHA2)
ARM.HasCRC32 = isSet(hwCap2, hwcap2_CRC32)
}
func isSet(hwc uint, value uint) bool {
return hwc&value != 0
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go
================================================
// Copyright 2018 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.
package cpu
import (
"strings"
"syscall"
)
// HWCAP/HWCAP2 bits. These are exposed by Linux.
const (
hwcap_FP = 1 << 0
hwcap_ASIMD = 1 << 1
hwcap_EVTSTRM = 1 << 2
hwcap_AES = 1 << 3
hwcap_PMULL = 1 << 4
hwcap_SHA1 = 1 << 5
hwcap_SHA2 = 1 << 6
hwcap_CRC32 = 1 << 7
hwcap_ATOMICS = 1 << 8
hwcap_FPHP = 1 << 9
hwcap_ASIMDHP = 1 << 10
hwcap_CPUID = 1 << 11
hwcap_ASIMDRDM = 1 << 12
hwcap_JSCVT = 1 << 13
hwcap_FCMA = 1 << 14
hwcap_LRCPC = 1 << 15
hwcap_DCPOP = 1 << 16
hwcap_SHA3 = 1 << 17
hwcap_SM3 = 1 << 18
hwcap_SM4 = 1 << 19
hwcap_ASIMDDP = 1 << 20
hwcap_SHA512 = 1 << 21
hwcap_SVE = 1 << 22
hwcap_ASIMDFHM = 1 << 23
hwcap_DIT = 1 << 24
hwcap2_SVE2 = 1 << 1
hwcap2_I8MM = 1 << 13
)
// linuxKernelCanEmulateCPUID reports whether we're running
// on Linux 4.11+. Ideally we'd like to ask the question about
// whether the current kernel contains
// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=77c97b4ee21290f5f083173d957843b615abbff2
// but the version number will have to do.
func linuxKernelCanEmulateCPUID() bool {
var un syscall.Utsname
syscall.Uname(&un)
var sb strings.Builder
for _, b := range un.Release[:] {
if b == 0 {
break
}
sb.WriteByte(byte(b))
}
major, minor, _, ok := parseRelease(sb.String())
return ok && (major > 4 || major == 4 && minor >= 11)
}
func doinit() {
if err := readHWCAP(); err != nil {
// We failed to read /proc/self/auxv. This can happen if the binary has
// been given extra capabilities(7) with /bin/setcap.
//
// When this happens, we have two options. If the Linux kernel is new
// enough (4.11+), we can read the arm64 registers directly which'll
// trap into the kernel and then return back to userspace.
//
// But on older kernels, such as Linux 4.4.180 as used on many Synology
// devices, calling readARM64Registers (specifically getisar0) will
// cause a SIGILL and we'll die. So for older kernels, parse /proc/cpuinfo
// instead.
//
// See golang/go#57336.
if linuxKernelCanEmulateCPUID() {
readARM64Registers()
} else {
readLinuxProcCPUInfo()
}
return
}
// HWCAP feature bits
ARM64.HasFP = isSet(hwCap, hwcap_FP)
ARM64.HasASIMD = isSet(hwCap, hwcap_ASIMD)
ARM64.HasEVTSTRM = isSet(hwCap, hwcap_EVTSTRM)
ARM64.HasAES = isSet(hwCap, hwcap_AES)
ARM64.HasPMULL = isSet(hwCap, hwcap_PMULL)
ARM64.HasSHA1 = isSet(hwCap, hwcap_SHA1)
ARM64.HasSHA2 = isSet(hwCap, hwcap_SHA2)
ARM64.HasCRC32 = isSet(hwCap, hwcap_CRC32)
ARM64.HasATOMICS = isSet(hwCap, hwcap_ATOMICS)
ARM64.HasFPHP = isSet(hwCap, hwcap_FPHP)
ARM64.HasASIMDHP = isSet(hwCap, hwcap_ASIMDHP)
ARM64.HasCPUID = isSet(hwCap, hwcap_CPUID)
ARM64.HasASIMDRDM = isSet(hwCap, hwcap_ASIMDRDM)
ARM64.HasJSCVT = isSet(hwCap, hwcap_JSCVT)
ARM64.HasFCMA = isSet(hwCap, hwcap_FCMA)
ARM64.HasLRCPC = isSet(hwCap, hwcap_LRCPC)
ARM64.HasDCPOP = isSet(hwCap, hwcap_DCPOP)
ARM64.HasSHA3 = isSet(hwCap, hwcap_SHA3)
ARM64.HasSM3 = isSet(hwCap, hwcap_SM3)
ARM64.HasSM4 = isSet(hwCap, hwcap_SM4)
ARM64.HasASIMDDP = isSet(hwCap, hwcap_ASIMDDP)
ARM64.HasSHA512 = isSet(hwCap, hwcap_SHA512)
ARM64.HasSVE = isSet(hwCap, hwcap_SVE)
ARM64.HasASIMDFHM = isSet(hwCap, hwcap_ASIMDFHM)
ARM64.HasDIT = isSet(hwCap, hwcap_DIT)
// HWCAP2 feature bits
ARM64.HasSVE2 = isSet(hwCap2, hwcap2_SVE2)
ARM64.HasI8MM = isSet(hwCap2, hwcap2_I8MM)
}
func isSet(hwc uint, value uint) bool {
return hwc&value != 0
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_linux_loong64.go
================================================
// Copyright 2025 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.
package cpu
// HWCAP bits. These are exposed by the Linux kernel.
const (
hwcap_LOONGARCH_LSX = 1 << 4
hwcap_LOONGARCH_LASX = 1 << 5
)
func doinit() {
// TODO: Features that require kernel support like LSX and LASX can
// be detected here once needed in std library or by the compiler.
Loong64.HasLSX = hwcIsSet(hwCap, hwcap_LOONGARCH_LSX)
Loong64.HasLASX = hwcIsSet(hwCap, hwcap_LOONGARCH_LASX)
}
func hwcIsSet(hwc uint, val uint) bool {
return hwc&val != 0
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go
================================================
// Copyright 2020 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.
//go:build linux && (mips64 || mips64le)
package cpu
// HWCAP bits. These are exposed by the Linux kernel 5.4.
const (
// CPU features
hwcap_MIPS_MSA = 1 << 1
)
func doinit() {
// HWCAP feature bits
MIPS64X.HasMSA = isSet(hwCap, hwcap_MIPS_MSA)
}
func isSet(hwc uint, value uint) bool {
return hwc&value != 0
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go
================================================
// Copyright 2019 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.
//go:build linux && !arm && !arm64 && !loong64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !s390x && !riscv64
package cpu
func doinit() {}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go
================================================
// Copyright 2018 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.
//go:build linux && (ppc64 || ppc64le)
package cpu
// HWCAP/HWCAP2 bits. These are exposed by the kernel.
const (
// ISA Level
_PPC_FEATURE2_ARCH_2_07 = 0x80000000
_PPC_FEATURE2_ARCH_3_00 = 0x00800000
// CPU features
_PPC_FEATURE2_DARN = 0x00200000
_PPC_FEATURE2_SCV = 0x00100000
)
func doinit() {
// HWCAP2 feature bits
PPC64.IsPOWER8 = isSet(hwCap2, _PPC_FEATURE2_ARCH_2_07)
PPC64.IsPOWER9 = isSet(hwCap2, _PPC_FEATURE2_ARCH_3_00)
PPC64.HasDARN = isSet(hwCap2, _PPC_FEATURE2_DARN)
PPC64.HasSCV = isSet(hwCap2, _PPC_FEATURE2_SCV)
}
func isSet(hwc uint, value uint) bool {
return hwc&value != 0
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go
================================================
// Copyright 2024 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.
package cpu
import (
"syscall"
"unsafe"
)
// RISC-V extension discovery code for Linux. The approach here is to first try the riscv_hwprobe
// syscall falling back to HWCAP to check for the C extension if riscv_hwprobe is not available.
//
// A note on detection of the Vector extension using HWCAP.
//
// Support for the Vector extension version 1.0 was added to the Linux kernel in release 6.5.
// Support for the riscv_hwprobe syscall was added in 6.4. It follows that if the riscv_hwprobe
// syscall is not available then neither is the Vector extension (which needs kernel support).
// The riscv_hwprobe syscall should then be all we need to detect the Vector extension.
// However, some RISC-V board manufacturers ship boards with an older kernel on top of which
// they have back-ported various versions of the Vector extension patches but not the riscv_hwprobe
// patches. These kernels advertise support for the Vector extension using HWCAP. Falling
// back to HWCAP to detect the Vector extension, if riscv_hwprobe is not available, or simply not
// bothering with riscv_hwprobe at all and just using HWCAP may then seem like an attractive option.
//
// Unfortunately, simply checking the 'V' bit in AT_HWCAP will not work as this bit is used by
// RISC-V board and cloud instance providers to mean different things. The Lichee Pi 4A board
// and the Scaleway RV1 cloud instances use the 'V' bit to advertise their support for the unratified
// 0.7.1 version of the Vector Specification. The Banana Pi BPI-F3 and the CanMV-K230 board use
// it to advertise support for 1.0 of the Vector extension. Versions 0.7.1 and 1.0 of the Vector
// extension are binary incompatible. HWCAP can then not be used in isolation to populate the
// HasV field as this field indicates that the underlying CPU is compatible with RVV 1.0.
//
// There is a way at runtime to distinguish between versions 0.7.1 and 1.0 of the Vector
// specification by issuing a RVV 1.0 vsetvli instruction and checking the vill bit of the vtype
// register. This check would allow us to safely detect version 1.0 of the Vector extension
// with HWCAP, if riscv_hwprobe were not available. However, the check cannot
// be added until the assembler supports the Vector instructions.
//
// Note the riscv_hwprobe syscall does not suffer from these ambiguities by design as all of the
// extensions it advertises support for are explicitly versioned. It's also worth noting that
// the riscv_hwprobe syscall is the only way to detect multi-letter RISC-V extensions, e.g., Zba.
// These cannot be detected using HWCAP and so riscv_hwprobe must be used to detect the majority
// of RISC-V extensions.
//
// Please see https://docs.kernel.org/arch/riscv/hwprobe.html for more information.
// golang.org/x/sys/cpu is not allowed to depend on golang.org/x/sys/unix so we must
// reproduce the constants, types and functions needed to make the riscv_hwprobe syscall
// here.
const (
// Copied from golang.org/x/sys/unix/ztypes_linux_riscv64.go.
riscv_HWPROBE_KEY_IMA_EXT_0 = 0x4
riscv_HWPROBE_IMA_C = 0x2
riscv_HWPROBE_IMA_V = 0x4
riscv_HWPROBE_EXT_ZBA = 0x8
riscv_HWPROBE_EXT_ZBB = 0x10
riscv_HWPROBE_EXT_ZBS = 0x20
riscv_HWPROBE_EXT_ZVBB = 0x20000
riscv_HWPROBE_EXT_ZVBC = 0x40000
riscv_HWPROBE_EXT_ZVKB = 0x80000
riscv_HWPROBE_EXT_ZVKG = 0x100000
riscv_HWPROBE_EXT_ZVKNED = 0x200000
riscv_HWPROBE_EXT_ZVKNHB = 0x800000
riscv_HWPROBE_EXT_ZVKSED = 0x1000000
riscv_HWPROBE_EXT_ZVKSH = 0x2000000
riscv_HWPROBE_EXT_ZVKT = 0x4000000
riscv_HWPROBE_KEY_CPUPERF_0 = 0x5
riscv_HWPROBE_MISALIGNED_FAST = 0x3
riscv_HWPROBE_MISALIGNED_MASK = 0x7
)
const (
// sys_RISCV_HWPROBE is copied from golang.org/x/sys/unix/zsysnum_linux_riscv64.go.
sys_RISCV_HWPROBE = 258
)
// riscvHWProbePairs is copied from golang.org/x/sys/unix/ztypes_linux_riscv64.go.
type riscvHWProbePairs struct {
key int64
value uint64
}
const (
// CPU features
hwcap_RISCV_ISA_C = 1 << ('C' - 'A')
)
func doinit() {
// A slice of key/value pair structures is passed to the RISCVHWProbe syscall. The key
// field should be initialised with one of the key constants defined above, e.g.,
// RISCV_HWPROBE_KEY_IMA_EXT_0. The syscall will set the value field to the appropriate value.
// If the kernel does not recognise a key it will set the key field to -1 and the value field to 0.
pairs := []riscvHWProbePairs{
{riscv_HWPROBE_KEY_IMA_EXT_0, 0},
{riscv_HWPROBE_KEY_CPUPERF_0, 0},
}
// This call only indicates that extensions are supported if they are implemented on all cores.
if riscvHWProbe(pairs, 0) {
if pairs[0].key != -1 {
v := uint(pairs[0].value)
RISCV64.HasC = isSet(v, riscv_HWPROBE_IMA_C)
RISCV64.HasV = isSet(v, riscv_HWPROBE_IMA_V)
RISCV64.HasZba = isSet(v, riscv_HWPROBE_EXT_ZBA)
RISCV64.HasZbb = isSet(v, riscv_HWPROBE_EXT_ZBB)
RISCV64.HasZbs = isSet(v, riscv_HWPROBE_EXT_ZBS)
RISCV64.HasZvbb = isSet(v, riscv_HWPROBE_EXT_ZVBB)
RISCV64.HasZvbc = isSet(v, riscv_HWPROBE_EXT_ZVBC)
RISCV64.HasZvkb = isSet(v, riscv_HWPROBE_EXT_ZVKB)
RISCV64.HasZvkg = isSet(v, riscv_HWPROBE_EXT_ZVKG)
RISCV64.HasZvkt = isSet(v, riscv_HWPROBE_EXT_ZVKT)
// Cryptography shorthand extensions
RISCV64.HasZvkn = isSet(v, riscv_HWPROBE_EXT_ZVKNED) &&
isSet(v, riscv_HWPROBE_EXT_ZVKNHB) && RISCV64.HasZvkb && RISCV64.HasZvkt
RISCV64.HasZvknc = RISCV64.HasZvkn && RISCV64.HasZvbc
RISCV64.HasZvkng = RISCV64.HasZvkn && RISCV64.HasZvkg
RISCV64.HasZvks = isSet(v, riscv_HWPROBE_EXT_ZVKSED) &&
isSet(v, riscv_HWPROBE_EXT_ZVKSH) && RISCV64.HasZvkb && RISCV64.HasZvkt
RISCV64.HasZvksc = RISCV64.HasZvks && RISCV64.HasZvbc
RISCV64.HasZvksg = RISCV64.HasZvks && RISCV64.HasZvkg
}
if pairs[1].key != -1 {
v := pairs[1].value & riscv_HWPROBE_MISALIGNED_MASK
RISCV64.HasFastMisaligned = v == riscv_HWPROBE_MISALIGNED_FAST
}
}
// Let's double check with HWCAP if the C extension does not appear to be supported.
// This may happen if we're running on a kernel older than 6.4.
if !RISCV64.HasC {
RISCV64.HasC = isSet(hwCap, hwcap_RISCV_ISA_C)
}
}
func isSet(hwc uint, value uint) bool {
return hwc&value != 0
}
// riscvHWProbe is a simplified version of the generated wrapper function found in
// golang.org/x/sys/unix/zsyscall_linux_riscv64.go. We simplify it by removing the
// cpuCount and cpus parameters which we do not need. We always want to pass 0 for
// these parameters here so the kernel only reports the extensions that are present
// on all cores.
func riscvHWProbe(pairs []riscvHWProbePairs, flags uint) bool {
var _zero uintptr
var p0 unsafe.Pointer
if len(pairs) > 0 {
p0 = unsafe.Pointer(&pairs[0])
} else {
p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := syscall.Syscall6(sys_RISCV_HWPROBE, uintptr(p0), uintptr(len(pairs)), uintptr(0), uintptr(0), uintptr(flags), 0)
return e1 == 0
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go
================================================
// Copyright 2019 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.
package cpu
const (
// bit mask values from /usr/include/bits/hwcap.h
hwcap_ZARCH = 2
hwcap_STFLE = 4
hwcap_MSA = 8
hwcap_LDISP = 16
hwcap_EIMM = 32
hwcap_DFP = 64
hwcap_ETF3EH = 256
hwcap_VX = 2048
hwcap_VXE = 8192
)
func initS390Xbase() {
// test HWCAP bit vector
has := func(featureMask uint) bool {
return hwCap&featureMask == featureMask
}
// mandatory
S390X.HasZARCH = has(hwcap_ZARCH)
// optional
S390X.HasSTFLE = has(hwcap_STFLE)
S390X.HasLDISP = has(hwcap_LDISP)
S390X.HasEIMM = has(hwcap_EIMM)
S390X.HasETF3EH = has(hwcap_ETF3EH)
S390X.HasDFP = has(hwcap_DFP)
S390X.HasMSA = has(hwcap_MSA)
S390X.HasVX = has(hwcap_VX)
if S390X.HasVX {
S390X.HasVXE = has(hwcap_VXE)
}
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_loong64.go
================================================
// Copyright 2022 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.
//go:build loong64
package cpu
const cacheLineSize = 64
// Bit fields for CPUCFG registers, Related reference documents:
// https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#_cpucfg
const (
// CPUCFG1 bits
cpucfg1_CRC32 = 1 << 25
// CPUCFG2 bits
cpucfg2_LAM_BH = 1 << 27
cpucfg2_LAMCAS = 1 << 28
)
func initOptions() {
options = []option{
{Name: "lsx", Feature: &Loong64.HasLSX},
{Name: "lasx", Feature: &Loong64.HasLASX},
{Name: "crc32", Feature: &Loong64.HasCRC32},
{Name: "lam_bh", Feature: &Loong64.HasLAM_BH},
{Name: "lamcas", Feature: &Loong64.HasLAMCAS},
}
// The CPUCFG data on Loong64 only reflects the hardware capabilities,
// not the kernel support status, so features such as LSX and LASX that
// require kernel support cannot be obtained from the CPUCFG data.
//
// These features only require hardware capability support and do not
// require kernel specific support, so they can be obtained directly
// through CPUCFG
cfg1 := get_cpucfg(1)
cfg2 := get_cpucfg(2)
Loong64.HasCRC32 = cfgIsSet(cfg1, cpucfg1_CRC32)
Loong64.HasLAMCAS = cfgIsSet(cfg2, cpucfg2_LAMCAS)
Loong64.HasLAM_BH = cfgIsSet(cfg2, cpucfg2_LAM_BH)
}
func get_cpucfg(reg uint32) uint32
func cfgIsSet(cfg uint32, val uint32) bool {
return cfg&val != 0
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_loong64.s
================================================
// Copyright 2025 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.
#include "textflag.h"
// func get_cpucfg(reg uint32) uint32
TEXT ·get_cpucfg(SB), NOSPLIT|NOFRAME, $0
MOVW reg+0(FP), R5
// CPUCFG R5, R4 = 0x00006ca4
WORD $0x00006ca4
MOVW R4, ret+8(FP)
RET
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_mips64x.go
================================================
// Copyright 2018 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.
//go:build mips64 || mips64le
package cpu
const cacheLineSize = 32
func initOptions() {
options = []option{
{Name: "msa", Feature: &MIPS64X.HasMSA},
}
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_mipsx.go
================================================
// Copyright 2018 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.
//go:build mips || mipsle
package cpu
const cacheLineSize = 32
func initOptions() {}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go
================================================
// Copyright 2020 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.
package cpu
import (
"syscall"
"unsafe"
)
// Minimal copy of functionality from x/sys/unix so the cpu package can call
// sysctl without depending on x/sys/unix.
const (
_CTL_QUERY = -2
_SYSCTL_VERS_1 = 0x1000000
)
var _zero uintptr
func sysctl(mib []int32, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
var _p0 unsafe.Pointer
if len(mib) > 0 {
_p0 = unsafe.Pointer(&mib[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
_, _, errno := syscall.Syscall6(
syscall.SYS___SYSCTL,
uintptr(_p0),
uintptr(len(mib)),
uintptr(unsafe.Pointer(old)),
uintptr(unsafe.Pointer(oldlen)),
uintptr(unsafe.Pointer(new)),
uintptr(newlen))
if errno != 0 {
return errno
}
return nil
}
type sysctlNode struct {
Flags uint32
Num int32
Name [32]int8
Ver uint32
__rsvd uint32
Un [16]byte
_sysctl_size [8]byte
_sysctl_func [8]byte
_sysctl_parent [8]byte
_sysctl_desc [8]byte
}
func sysctlNodes(mib []int32) ([]sysctlNode, error) {
var olen uintptr
// Get a list of all sysctl nodes below the given MIB by performing
// a sysctl for the given MIB with CTL_QUERY appended.
mib = append(mib, _CTL_QUERY)
qnode := sysctlNode{Flags: _SYSCTL_VERS_1}
qp := (*byte)(unsafe.Pointer(&qnode))
sz := unsafe.Sizeof(qnode)
if err := sysctl(mib, nil, &olen, qp, sz); err != nil {
return nil, err
}
// Now that we know the size, get the actual nodes.
nodes := make([]sysctlNode, olen/sz)
np := (*byte)(unsafe.Pointer(&nodes[0]))
if err := sysctl(mib, np, &olen, qp, sz); err != nil {
return nil, err
}
return nodes, nil
}
func nametomib(name string) ([]int32, error) {
// Split name into components.
var parts []string
last := 0
for i := 0; i < len(name); i++ {
if name[i] == '.' {
parts = append(parts, name[last:i])
last = i + 1
}
}
parts = append(parts, name[last:])
mib := []int32{}
// Discover the nodes and construct the MIB OID.
for partno, part := range parts {
nodes, err := sysctlNodes(mib)
if err != nil {
return nil, err
}
for _, node := range nodes {
n := make([]byte, 0)
for i := range node.Name {
if node.Name[i] != 0 {
n = append(n, byte(node.Name[i]))
}
}
if string(n) == part {
mib = append(mib, int32(node.Num))
break
}
}
if len(mib) != partno+1 {
return nil, err
}
}
return mib, nil
}
// aarch64SysctlCPUID is struct aarch64_sysctl_cpu_id from NetBSD's
type aarch64SysctlCPUID struct {
midr uint64 /* Main ID Register */
revidr uint64 /* Revision ID Register */
mpidr uint64 /* Multiprocessor Affinity Register */
aa64dfr0 uint64 /* A64 Debug Feature Register 0 */
aa64dfr1 uint64 /* A64 Debug Feature Register 1 */
aa64isar0 uint64 /* A64 Instruction Set Attribute Register 0 */
aa64isar1 uint64 /* A64 Instruction Set Attribute Register 1 */
aa64mmfr0 uint64 /* A64 Memory Model Feature Register 0 */
aa64mmfr1 uint64 /* A64 Memory Model Feature Register 1 */
aa64mmfr2 uint64 /* A64 Memory Model Feature Register 2 */
aa64pfr0 uint64 /* A64 Processor Feature Register 0 */
aa64pfr1 uint64 /* A64 Processor Feature Register 1 */
aa64zfr0 uint64 /* A64 SVE Feature ID Register 0 */
mvfr0 uint32 /* Media and VFP Feature Register 0 */
mvfr1 uint32 /* Media and VFP Feature Register 1 */
mvfr2 uint32 /* Media and VFP Feature Register 2 */
pad uint32
clidr uint64 /* Cache Level ID Register */
ctr uint64 /* Cache Type Register */
}
func sysctlCPUID(name string) (*aarch64SysctlCPUID, error) {
mib, err := nametomib(name)
if err != nil {
return nil, err
}
out := aarch64SysctlCPUID{}
n := unsafe.Sizeof(out)
_, _, errno := syscall.Syscall6(
syscall.SYS___SYSCTL,
uintptr(unsafe.Pointer(&mib[0])),
uintptr(len(mib)),
uintptr(unsafe.Pointer(&out)),
uintptr(unsafe.Pointer(&n)),
uintptr(0),
uintptr(0))
if errno != 0 {
return nil, errno
}
return &out, nil
}
func doinit() {
cpuid, err := sysctlCPUID("machdep.cpu0.cpu_id")
if err != nil {
setMinimalFeatures()
return
}
parseARM64SystemRegisters(cpuid.aa64isar0, cpuid.aa64isar1, cpuid.aa64pfr0)
Initialized = true
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.go
================================================
// Copyright 2022 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.
package cpu
import (
"syscall"
"unsafe"
)
// Minimal copy of functionality from x/sys/unix so the cpu package can call
// sysctl without depending on x/sys/unix.
const (
// From OpenBSD's sys/sysctl.h.
_CTL_MACHDEP = 7
// From OpenBSD's machine/cpu.h.
_CPU_ID_AA64ISAR0 = 2
_CPU_ID_AA64ISAR1 = 3
)
// Implemented in the runtime package (runtime/sys_openbsd3.go)
func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno)
//go:linkname syscall_syscall6 syscall.syscall6
func sysctl(mib []uint32, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
_, _, errno := syscall_syscall6(libc_sysctl_trampoline_addr, uintptr(unsafe.Pointer(&mib[0])), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
if errno != 0 {
return errno
}
return nil
}
var libc_sysctl_trampoline_addr uintptr
//go:cgo_import_dynamic libc_sysctl sysctl "libc.so"
func sysctlUint64(mib []uint32) (uint64, bool) {
var out uint64
nout := unsafe.Sizeof(out)
if err := sysctl(mib, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0); err != nil {
return 0, false
}
return out, true
}
func doinit() {
setMinimalFeatures()
// Get ID_AA64ISAR0 and ID_AA64ISAR1 from sysctl.
isar0, ok := sysctlUint64([]uint32{_CTL_MACHDEP, _CPU_ID_AA64ISAR0})
if !ok {
return
}
isar1, ok := sysctlUint64([]uint32{_CTL_MACHDEP, _CPU_ID_AA64ISAR1})
if !ok {
return
}
parseARM64SystemRegisters(isar0, isar1, 0)
Initialized = true
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.s
================================================
// Copyright 2022 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.
#include "textflag.h"
TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_sysctl(SB)
GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $8
DATA ·libc_sysctl_trampoline_addr(SB)/8, $libc_sysctl_trampoline<>(SB)
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_other_arm.go
================================================
// Copyright 2020 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.
//go:build !linux && arm
package cpu
func archInit() {}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_other_arm64.go
================================================
// Copyright 2019 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.
//go:build !linux && !netbsd && !openbsd && !windows && arm64
package cpu
func doinit() {}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go
================================================
// Copyright 2020 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.
//go:build !linux && (mips64 || mips64le)
package cpu
func archInit() {
Initialized = true
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_other_ppc64x.go
================================================
// Copyright 2022 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.
//go:build !aix && !linux && (ppc64 || ppc64le)
package cpu
func archInit() {
PPC64.IsPOWER8 = true
Initialized = true
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go
================================================
// Copyright 2022 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.
//go:build !linux && riscv64
package cpu
func archInit() {
Initialized = true
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_other_x86.go
================================================
// Copyright 2024 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.
//go:build 386 || amd64p32 || (amd64 && (!darwin || !gc))
package cpu
func darwinSupportsAVX512() bool {
panic("only implemented for gc && amd64 && darwin")
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_ppc64x.go
================================================
// Copyright 2020 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.
//go:build ppc64 || ppc64le
package cpu
const cacheLineSize = 128
func initOptions() {
options = []option{
{Name: "darn", Feature: &PPC64.HasDARN},
{Name: "scv", Feature: &PPC64.HasSCV},
}
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_riscv64.go
================================================
// Copyright 2019 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.
//go:build riscv64
package cpu
const cacheLineSize = 64
func initOptions() {
options = []option{
{Name: "fastmisaligned", Feature: &RISCV64.HasFastMisaligned},
{Name: "c", Feature: &RISCV64.HasC},
{Name: "v", Feature: &RISCV64.HasV},
{Name: "zba", Feature: &RISCV64.HasZba},
{Name: "zbb", Feature: &RISCV64.HasZbb},
{Name: "zbs", Feature: &RISCV64.HasZbs},
// RISC-V Cryptography Extensions
{Name: "zvbb", Feature: &RISCV64.HasZvbb},
{Name: "zvbc", Feature: &RISCV64.HasZvbc},
{Name: "zvkb", Feature: &RISCV64.HasZvkb},
{Name: "zvkg", Feature: &RISCV64.HasZvkg},
{Name: "zvkt", Feature: &RISCV64.HasZvkt},
{Name: "zvkn", Feature: &RISCV64.HasZvkn},
{Name: "zvknc", Feature: &RISCV64.HasZvknc},
{Name: "zvkng", Feature: &RISCV64.HasZvkng},
{Name: "zvks", Feature: &RISCV64.HasZvks},
{Name: "zvksc", Feature: &RISCV64.HasZvksc},
{Name: "zvksg", Feature: &RISCV64.HasZvksg},
}
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_s390x.go
================================================
// Copyright 2020 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.
package cpu
const cacheLineSize = 256
func initOptions() {
options = []option{
{Name: "zarch", Feature: &S390X.HasZARCH, Required: true},
{Name: "stfle", Feature: &S390X.HasSTFLE, Required: true},
{Name: "ldisp", Feature: &S390X.HasLDISP, Required: true},
{Name: "eimm", Feature: &S390X.HasEIMM, Required: true},
{Name: "dfp", Feature: &S390X.HasDFP},
{Name: "etf3eh", Feature: &S390X.HasETF3EH},
{Name: "msa", Feature: &S390X.HasMSA},
{Name: "aes", Feature: &S390X.HasAES},
{Name: "aescbc", Feature: &S390X.HasAESCBC},
{Name: "aesctr", Feature: &S390X.HasAESCTR},
{Name: "aesgcm", Feature: &S390X.HasAESGCM},
{Name: "ghash", Feature: &S390X.HasGHASH},
{Name: "sha1", Feature: &S390X.HasSHA1},
{Name: "sha256", Feature: &S390X.HasSHA256},
{Name: "sha3", Feature: &S390X.HasSHA3},
{Name: "sha512", Feature: &S390X.HasSHA512},
{Name: "vx", Feature: &S390X.HasVX},
{Name: "vxe", Feature: &S390X.HasVXE},
}
}
// bitIsSet reports whether the bit at index is set. The bit index
// is in big endian order, so bit index 0 is the leftmost bit.
func bitIsSet(bits []uint64, index uint) bool {
return bits[index/64]&((1<<63)>>(index%64)) != 0
}
// facility is a bit index for the named facility.
type facility uint8
const (
// mandatory facilities
zarch facility = 1 // z architecture mode is active
stflef facility = 7 // store-facility-list-extended
ldisp facility = 18 // long-displacement
eimm facility = 21 // extended-immediate
// miscellaneous facilities
dfp facility = 42 // decimal-floating-point
etf3eh facility = 30 // extended-translation 3 enhancement
// cryptography facilities
msa facility = 17 // message-security-assist
msa3 facility = 76 // message-security-assist extension 3
msa4 facility = 77 // message-security-assist extension 4
msa5 facility = 57 // message-security-assist extension 5
msa8 facility = 146 // message-security-assist extension 8
msa9 facility = 155 // message-security-assist extension 9
// vector facilities
vx facility = 129 // vector facility
vxe facility = 135 // vector-enhancements 1
vxe2 facility = 148 // vector-enhancements 2
)
// facilityList contains the result of an STFLE call.
// Bits are numbered in big endian order so the
// leftmost bit (the MSB) is at index 0.
type facilityList struct {
bits [4]uint64
}
// Has reports whether the given facilities are present.
func (s *facilityList) Has(fs ...facility) bool {
if len(fs) == 0 {
panic("no facility bits provided")
}
for _, f := range fs {
if !bitIsSet(s.bits[:], uint(f)) {
return false
}
}
return true
}
// function is the code for the named cryptographic function.
type function uint8
const (
// KM{,A,C,CTR} function codes
aes128 function = 18 // AES-128
aes192 function = 19 // AES-192
aes256 function = 20 // AES-256
// K{I,L}MD function codes
sha1 function = 1 // SHA-1
sha256 function = 2 // SHA-256
sha512 function = 3 // SHA-512
sha3_224 function = 32 // SHA3-224
sha3_256 function = 33 // SHA3-256
sha3_384 function = 34 // SHA3-384
sha3_512 function = 35 // SHA3-512
shake128 function = 36 // SHAKE-128
shake256 function = 37 // SHAKE-256
// KLMD function codes
ghash function = 65 // GHASH
)
// queryResult contains the result of a Query function
// call. Bits are numbered in big endian order so the
// leftmost bit (the MSB) is at index 0.
type queryResult struct {
bits [2]uint64
}
// Has reports whether the given functions are present.
func (q *queryResult) Has(fns ...function) bool {
if len(fns) == 0 {
panic("no function codes provided")
}
for _, f := range fns {
if !bitIsSet(q.bits[:], uint(f)) {
return false
}
}
return true
}
func doinit() {
initS390Xbase()
// We need implementations of stfle, km and so on
// to detect cryptographic features.
if !haveAsmFunctions() {
return
}
// optional cryptographic functions
if S390X.HasMSA {
aes := []function{aes128, aes192, aes256}
// cipher message
km, kmc := kmQuery(), kmcQuery()
S390X.HasAES = km.Has(aes...)
S390X.HasAESCBC = kmc.Has(aes...)
if S390X.HasSTFLE {
facilities := stfle()
if facilities.Has(msa4) {
kmctr := kmctrQuery()
S390X.HasAESCTR = kmctr.Has(aes...)
}
if facilities.Has(msa8) {
kma := kmaQuery()
S390X.HasAESGCM = kma.Has(aes...)
}
}
// compute message digest
kimd := kimdQuery() // intermediate (no padding)
klmd := klmdQuery() // last (padding)
S390X.HasSHA1 = kimd.Has(sha1) && klmd.Has(sha1)
S390X.HasSHA256 = kimd.Has(sha256) && klmd.Has(sha256)
S390X.HasSHA512 = kimd.Has(sha512) && klmd.Has(sha512)
S390X.HasGHASH = kimd.Has(ghash) // KLMD-GHASH does not exist
sha3 := []function{
sha3_224, sha3_256, sha3_384, sha3_512,
shake128, shake256,
}
S390X.HasSHA3 = kimd.Has(sha3...) && klmd.Has(sha3...)
}
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_s390x.s
================================================
// Copyright 2019 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.
//go:build gc
#include "textflag.h"
// func stfle() facilityList
TEXT ·stfle(SB), NOSPLIT|NOFRAME, $0-32
MOVD $ret+0(FP), R1
MOVD $3, R0 // last doubleword index to store
XC $32, (R1), (R1) // clear 4 doublewords (32 bytes)
WORD $0xb2b01000 // store facility list extended (STFLE)
RET
// func kmQuery() queryResult
TEXT ·kmQuery(SB), NOSPLIT|NOFRAME, $0-16
MOVD $0, R0 // set function code to 0 (KM-Query)
MOVD $ret+0(FP), R1 // address of 16-byte return value
WORD $0xB92E0024 // cipher message (KM)
RET
// func kmcQuery() queryResult
TEXT ·kmcQuery(SB), NOSPLIT|NOFRAME, $0-16
MOVD $0, R0 // set function code to 0 (KMC-Query)
MOVD $ret+0(FP), R1 // address of 16-byte return value
WORD $0xB92F0024 // cipher message with chaining (KMC)
RET
// func kmctrQuery() queryResult
TEXT ·kmctrQuery(SB), NOSPLIT|NOFRAME, $0-16
MOVD $0, R0 // set function code to 0 (KMCTR-Query)
MOVD $ret+0(FP), R1 // address of 16-byte return value
WORD $0xB92D4024 // cipher message with counter (KMCTR)
RET
// func kmaQuery() queryResult
TEXT ·kmaQuery(SB), NOSPLIT|NOFRAME, $0-16
MOVD $0, R0 // set function code to 0 (KMA-Query)
MOVD $ret+0(FP), R1 // address of 16-byte return value
WORD $0xb9296024 // cipher message with authentication (KMA)
RET
// func kimdQuery() queryResult
TEXT ·kimdQuery(SB), NOSPLIT|NOFRAME, $0-16
MOVD $0, R0 // set function code to 0 (KIMD-Query)
MOVD $ret+0(FP), R1 // address of 16-byte return value
WORD $0xB93E0024 // compute intermediate message digest (KIMD)
RET
// func klmdQuery() queryResult
TEXT ·klmdQuery(SB), NOSPLIT|NOFRAME, $0-16
MOVD $0, R0 // set function code to 0 (KLMD-Query)
MOVD $ret+0(FP), R1 // address of 16-byte return value
WORD $0xB93F0024 // compute last message digest (KLMD)
RET
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_wasm.go
================================================
// Copyright 2019 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.
//go:build wasm
package cpu
// We're compiling the cpu package for an unknown (software-abstracted) CPU.
// Make CacheLinePad an empty struct and hope that the usual struct alignment
// rules are good enough.
const cacheLineSize = 0
func initOptions() {}
func archInit() {}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_windows_arm64.go
================================================
// Copyright 2026 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.
package cpu
import (
"golang.org/x/sys/windows"
)
func doinit() {
// set HasASIMD and HasFP to true as per
// https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170#base-requirements
//
// The ARM64 version of Windows always presupposes that it's running on an ARMv8 or later architecture.
// Both floating-point and NEON support are presumed to be present in hardware.
//
ARM64.HasASIMD = true
ARM64.HasFP = true
if windows.IsProcessorFeaturePresent(windows.PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) {
ARM64.HasAES = true
ARM64.HasPMULL = true
ARM64.HasSHA1 = true
ARM64.HasSHA2 = true
}
ARM64.HasSHA3 = windows.IsProcessorFeaturePresent(windows.PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE)
ARM64.HasCRC32 = windows.IsProcessorFeaturePresent(windows.PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE)
ARM64.HasSHA512 = windows.IsProcessorFeaturePresent(windows.PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE)
ARM64.HasATOMICS = windows.IsProcessorFeaturePresent(windows.PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE)
if windows.IsProcessorFeaturePresent(windows.PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE) {
ARM64.HasASIMDDP = true
ARM64.HasASIMDRDM = true
}
if windows.IsProcessorFeaturePresent(windows.PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE) {
ARM64.HasLRCPC = true
ARM64.HasSM3 = true
}
ARM64.HasSVE = windows.IsProcessorFeaturePresent(windows.PF_ARM_SVE_INSTRUCTIONS_AVAILABLE)
ARM64.HasSVE2 = windows.IsProcessorFeaturePresent(windows.PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE)
ARM64.HasJSCVT = windows.IsProcessorFeaturePresent(windows.PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE)
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_x86.go
================================================
// Copyright 2018 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.
//go:build 386 || amd64 || amd64p32
package cpu
import "runtime"
const cacheLineSize = 64
func initOptions() {
options = []option{
{Name: "adx", Feature: &X86.HasADX},
{Name: "aes", Feature: &X86.HasAES},
{Name: "avx", Feature: &X86.HasAVX},
{Name: "avx2", Feature: &X86.HasAVX2},
{Name: "avx512", Feature: &X86.HasAVX512},
{Name: "avx512f", Feature: &X86.HasAVX512F},
{Name: "avx512cd", Feature: &X86.HasAVX512CD},
{Name: "avx512er", Feature: &X86.HasAVX512ER},
{Name: "avx512pf", Feature: &X86.HasAVX512PF},
{Name: "avx512vl", Feature: &X86.HasAVX512VL},
{Name: "avx512bw", Feature: &X86.HasAVX512BW},
{Name: "avx512dq", Feature: &X86.HasAVX512DQ},
{Name: "avx512ifma", Feature: &X86.HasAVX512IFMA},
{Name: "avx512vbmi", Feature: &X86.HasAVX512VBMI},
{Name: "avx512vnniw", Feature: &X86.HasAVX5124VNNIW},
{Name: "avx5124fmaps", Feature: &X86.HasAVX5124FMAPS},
{Name: "avx512vpopcntdq", Feature: &X86.HasAVX512VPOPCNTDQ},
{Name: "avx512vpclmulqdq", Feature: &X86.HasAVX512VPCLMULQDQ},
{Name: "avx512vnni", Feature: &X86.HasAVX512VNNI},
{Name: "avx512gfni", Feature: &X86.HasAVX512GFNI},
{Name: "avx512vaes", Feature: &X86.HasAVX512VAES},
{Name: "avx512vbmi2", Feature: &X86.HasAVX512VBMI2},
{Name: "avx512bitalg", Feature: &X86.HasAVX512BITALG},
{Name: "avx512bf16", Feature: &X86.HasAVX512BF16},
{Name: "amxtile", Feature: &X86.HasAMXTile},
{Name: "amxint8", Feature: &X86.HasAMXInt8},
{Name: "amxbf16", Feature: &X86.HasAMXBF16},
{Name: "bmi1", Feature: &X86.HasBMI1},
{Name: "bmi2", Feature: &X86.HasBMI2},
{Name: "cx16", Feature: &X86.HasCX16},
{Name: "erms", Feature: &X86.HasERMS},
{Name: "fma", Feature: &X86.HasFMA},
{Name: "osxsave", Feature: &X86.HasOSXSAVE},
{Name: "pclmulqdq", Feature: &X86.HasPCLMULQDQ},
{Name: "popcnt", Feature: &X86.HasPOPCNT},
{Name: "rdrand", Feature: &X86.HasRDRAND},
{Name: "rdseed", Feature: &X86.HasRDSEED},
{Name: "sse3", Feature: &X86.HasSSE3},
{Name: "sse41", Feature: &X86.HasSSE41},
{Name: "sse42", Feature: &X86.HasSSE42},
{Name: "ssse3", Feature: &X86.HasSSSE3},
{Name: "avxifma", Feature: &X86.HasAVXIFMA},
{Name: "avxvnni", Feature: &X86.HasAVXVNNI},
{Name: "avxvnniint8", Feature: &X86.HasAVXVNNIInt8},
// These capabilities should always be enabled on amd64:
{Name: "sse2", Feature: &X86.HasSSE2, Required: runtime.GOARCH == "amd64"},
}
}
func archInit() {
// From internal/cpu
const (
// eax bits
cpuid_AVXVNNI = 1 << 4
// ecx bits
cpuid_SSE3 = 1 << 0
cpuid_PCLMULQDQ = 1 << 1
cpuid_AVX512VBMI = 1 << 1
cpuid_AVX512VBMI2 = 1 << 6
cpuid_SSSE3 = 1 << 9
cpuid_AVX512GFNI = 1 << 8
cpuid_AVX512VAES = 1 << 9
cpuid_AVX512VNNI = 1 << 11
cpuid_AVX512BITALG = 1 << 12
cpuid_FMA = 1 << 12
cpuid_AVX512VPOPCNTDQ = 1 << 14
cpuid_SSE41 = 1 << 19
cpuid_SSE42 = 1 << 20
cpuid_POPCNT = 1 << 23
cpuid_AES = 1 << 25
cpuid_OSXSAVE = 1 << 27
cpuid_AVX = 1 << 28
// "Extended Feature Flag" bits returned in EBX for CPUID EAX=0x7 ECX=0x0
cpuid_BMI1 = 1 << 3
cpuid_AVX2 = 1 << 5
cpuid_BMI2 = 1 << 8
cpuid_ERMS = 1 << 9
cpuid_AVX512F = 1 << 16
cpuid_AVX512DQ = 1 << 17
cpuid_ADX = 1 << 19
cpuid_AVX512CD = 1 << 28
cpuid_SHA = 1 << 29
cpuid_AVX512BW = 1 << 30
cpuid_AVX512VL = 1 << 31
// "Extended Feature Flag" bits returned in ECX for CPUID EAX=0x7 ECX=0x0
cpuid_AVX512_VBMI = 1 << 1
cpuid_AVX512_VBMI2 = 1 << 6
cpuid_GFNI = 1 << 8
cpuid_AVX512VPCLMULQDQ = 1 << 10
cpuid_AVX512_BITALG = 1 << 12
// edx bits
cpuid_FSRM = 1 << 4
// edx bits for CPUID 0x80000001
cpuid_RDTSCP = 1 << 27
)
// Additional constants not in internal/cpu
const (
// eax=1: edx
cpuid_SSE2 = 1 << 26
// eax=1: ecx
cpuid_CX16 = 1 << 13
cpuid_RDRAND = 1 << 30
// eax=7,ecx=0: ebx
cpuid_RDSEED = 1 << 18
cpuid_AVX512IFMA = 1 << 21
cpuid_AVX512PF = 1 << 26
cpuid_AVX512ER = 1 << 27
// eax=7,ecx=0: edx
cpuid_AVX5124VNNIW = 1 << 2
cpuid_AVX5124FMAPS = 1 << 3
cpuid_AMXBF16 = 1 << 22
cpuid_AMXTile = 1 << 24
cpuid_AMXInt8 = 1 << 25
// eax=7,ecx=1: eax
cpuid_AVX512BF16 = 1 << 5
cpuid_AVXIFMA = 1 << 23
// eax=7,ecx=1: edx
cpuid_AVXVNNIInt8 = 1 << 4
)
Initialized = true
maxID, _, _, _ := cpuid(0, 0)
if maxID < 1 {
return
}
_, _, ecx1, edx1 := cpuid(1, 0)
X86.HasSSE2 = isSet(edx1, cpuid_SSE2)
X86.HasSSE3 = isSet(ecx1, cpuid_SSE3)
X86.HasPCLMULQDQ = isSet(ecx1, cpuid_PCLMULQDQ)
X86.HasSSSE3 = isSet(ecx1, cpuid_SSSE3)
X86.HasFMA = isSet(ecx1, cpuid_FMA)
X86.HasCX16 = isSet(ecx1, cpuid_CX16)
X86.HasSSE41 = isSet(ecx1, cpuid_SSE41)
X86.HasSSE42 = isSet(ecx1, cpuid_SSE42)
X86.HasPOPCNT = isSet(ecx1, cpuid_POPCNT)
X86.HasAES = isSet(ecx1, cpuid_AES)
X86.HasOSXSAVE = isSet(ecx1, cpuid_OSXSAVE)
X86.HasRDRAND = isSet(ecx1, cpuid_RDRAND)
var osSupportsAVX, osSupportsAVX512 bool
// For XGETBV, OSXSAVE bit is required and sufficient.
if X86.HasOSXSAVE {
eax, _ := xgetbv()
// Check if XMM and YMM registers have OS support.
osSupportsAVX = isSet(eax, 1<<1) && isSet(eax, 1<<2)
if runtime.GOOS == "darwin" {
// Darwin requires special AVX512 checks, see cpu_darwin_x86.go
osSupportsAVX512 = osSupportsAVX && darwinSupportsAVX512()
} else {
// Check if OPMASK and ZMM registers have OS support.
osSupportsAVX512 = osSupportsAVX && isSet(eax, 1<<5) && isSet(eax, 1<<6) && isSet(eax, 1<<7)
}
}
X86.HasAVX = isSet(ecx1, cpuid_AVX) && osSupportsAVX
if maxID < 7 {
return
}
eax7, ebx7, ecx7, edx7 := cpuid(7, 0)
X86.HasBMI1 = isSet(ebx7, cpuid_BMI1)
X86.HasAVX2 = isSet(ebx7, cpuid_AVX2) && osSupportsAVX
X86.HasBMI2 = isSet(ebx7, cpuid_BMI2)
X86.HasERMS = isSet(ebx7, cpuid_ERMS)
X86.HasRDSEED = isSet(ebx7, cpuid_RDSEED)
X86.HasADX = isSet(ebx7, cpuid_ADX)
X86.HasAVX512 = isSet(ebx7, cpuid_AVX512F) && osSupportsAVX512 // Because avx-512 foundation is the core required extension
if X86.HasAVX512 {
X86.HasAVX512F = true
X86.HasAVX512CD = isSet(ebx7, cpuid_AVX512CD)
X86.HasAVX512ER = isSet(ebx7, cpuid_AVX512ER)
X86.HasAVX512PF = isSet(ebx7, cpuid_AVX512PF)
X86.HasAVX512VL = isSet(ebx7, cpuid_AVX512VL)
X86.HasAVX512BW = isSet(ebx7, cpuid_AVX512BW)
X86.HasAVX512DQ = isSet(ebx7, cpuid_AVX512DQ)
X86.HasAVX512IFMA = isSet(ebx7, cpuid_AVX512IFMA)
X86.HasAVX512VBMI = isSet(ecx7, cpuid_AVX512_VBMI)
X86.HasAVX5124VNNIW = isSet(edx7, cpuid_AVX5124VNNIW)
X86.HasAVX5124FMAPS = isSet(edx7, cpuid_AVX5124FMAPS)
X86.HasAVX512VPOPCNTDQ = isSet(ecx7, cpuid_AVX512VPOPCNTDQ)
X86.HasAVX512VPCLMULQDQ = isSet(ecx7, cpuid_AVX512VPCLMULQDQ)
X86.HasAVX512VNNI = isSet(ecx7, cpuid_AVX512VNNI)
X86.HasAVX512GFNI = isSet(ecx7, cpuid_AVX512GFNI)
X86.HasAVX512VAES = isSet(ecx7, cpuid_AVX512VAES)
X86.HasAVX512VBMI2 = isSet(ecx7, cpuid_AVX512VBMI2)
X86.HasAVX512BITALG = isSet(ecx7, cpuid_AVX512BITALG)
}
X86.HasAMXTile = isSet(edx7, cpuid_AMXTile)
X86.HasAMXInt8 = isSet(edx7, cpuid_AMXInt8)
X86.HasAMXBF16 = isSet(edx7, cpuid_AMXBF16)
// These features depend on the second level of extended features.
if eax7 >= 1 {
eax71, _, _, edx71 := cpuid(7, 1)
if X86.HasAVX512 {
X86.HasAVX512BF16 = isSet(eax71, cpuid_AVX512BF16)
}
if X86.HasAVX {
X86.HasAVXIFMA = isSet(eax71, cpuid_AVXIFMA)
X86.HasAVXVNNI = isSet(eax71, cpuid_AVXVNNI)
X86.HasAVXVNNIInt8 = isSet(edx71, cpuid_AVXVNNIInt8)
}
}
}
func isSet(hwc uint32, value uint32) bool {
return hwc&value != 0
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_zos.go
================================================
// Copyright 2020 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.
package cpu
func archInit() {
doinit()
Initialized = true
}
================================================
FILE: vendor/golang.org/x/sys/cpu/cpu_zos_s390x.go
================================================
// Copyright 2020 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.
package cpu
func initS390Xbase() {
// get the facilities list
facilities := stfle()
// mandatory
S390X.HasZARCH = facilities.Has(zarch)
S390X.HasSTFLE = facilities.Has(stflef)
S390X.HasLDISP = facilities.Has(ldisp)
S390X.HasEIMM = facilities.Has(eimm)
// optional
S390X.HasETF3EH = facilities.Has(etf3eh)
S390X.HasDFP = facilities.Has(dfp)
S390X.HasMSA = facilities.Has(msa)
S390X.HasVX = facilities.Has(vx)
if S390X.HasVX {
S390X.HasVXE = facilities.Has(vxe)
}
}
================================================
FILE: vendor/golang.org/x/sys/cpu/endian_big.go
================================================
// Copyright 2023 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.
//go:build armbe || arm64be || m68k || mips || mips64 || mips64p32 || ppc || ppc64 || s390 || s390x || shbe || sparc || sparc64
package cpu
// IsBigEndian records whether the GOARCH's byte order is big endian.
const IsBigEndian = true
================================================
FILE: vendor/golang.org/x/sys/cpu/endian_little.go
================================================
// Copyright 2023 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.
//go:build 386 || amd64 || amd64p32 || alpha || arm || arm64 || loong64 || mipsle || mips64le || mips64p32le || nios2 || ppc64le || riscv || riscv64 || sh || wasm
package cpu
// IsBigEndian records whether the GOARCH's byte order is big endian.
const IsBigEndian = false
================================================
FILE: vendor/golang.org/x/sys/cpu/hwcap_linux.go
================================================
// Copyright 2019 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.
package cpu
import (
"os"
)
const (
_AT_HWCAP = 16
_AT_HWCAP2 = 26
procAuxv = "/proc/self/auxv"
uintSize = int(32 << (^uint(0) >> 63))
)
// For those platforms don't have a 'cpuid' equivalent we use HWCAP/HWCAP2
// These are initialized in cpu_$GOARCH.go
// and should not be changed after they are initialized.
var hwCap uint
var hwCap2 uint
func readHWCAP() error {
// For Go 1.21+, get auxv from the Go runtime.
if a := getAuxv(); len(a) > 0 {
for len(a) >= 2 {
tag, val := a[0], uint(a[1])
a = a[2:]
switch tag {
case _AT_HWCAP:
hwCap = val
case _AT_HWCAP2:
hwCap2 = val
}
}
return nil
}
buf, err := os.ReadFile(procAuxv)
if err != nil {
// e.g. on android /proc/self/auxv is not accessible, so silently
// ignore the error and leave Initialized = false. On some
// architectures (e.g. arm64) doinit() implements a fallback
// readout and will set Initialized = true again.
return err
}
bo := hostByteOrder()
for len(buf) >= 2*(uintSize/8) {
var tag, val uint
switch uintSize {
case 32:
tag = uint(bo.Uint32(buf[0:]))
val = uint(bo.Uint32(buf[4:]))
buf = buf[8:]
case 64:
tag = uint(bo.Uint64(buf[0:]))
val = uint(bo.Uint64(buf[8:]))
buf = buf[16:]
}
switch tag {
case _AT_HWCAP:
hwCap = val
case _AT_HWCAP2:
hwCap2 = val
}
}
return nil
}
================================================
FILE: vendor/golang.org/x/sys/cpu/parse.go
================================================
// Copyright 2022 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.
package cpu
import "strconv"
// parseRelease parses a dot-separated version number. It follows the semver
// syntax, but allows the minor and patch versions to be elided.
//
// This is a copy of the Go runtime's parseRelease from
// https://golang.org/cl/209597.
func parseRelease(rel string) (major, minor, patch int, ok bool) {
// Strip anything after a dash or plus.
for i := range len(rel) {
if rel[i] == '-' || rel[i] == '+' {
rel = rel[:i]
break
}
}
next := func() (int, bool) {
for i := range len(rel) {
if rel[i] == '.' {
ver, err := strconv.Atoi(rel[:i])
rel = rel[i+1:]
return ver, err == nil
}
}
ver, err := strconv.Atoi(rel)
rel = ""
return ver, err == nil
}
if major, ok = next(); !ok || rel == "" {
return
}
if minor, ok = next(); !ok || rel == "" {
return
}
patch, ok = next()
return
}
================================================
FILE: vendor/golang.org/x/sys/cpu/proc_cpuinfo_linux.go
================================================
// Copyright 2022 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.
//go:build linux && arm64
package cpu
import (
"errors"
"io"
"os"
"strings"
)
func readLinuxProcCPUInfo() error {
f, err := os.Open("/proc/cpuinfo")
if err != nil {
return err
}
defer f.Close()
var buf [1 << 10]byte // enough for first CPU
n, err := io.ReadFull(f, buf[:])
if err != nil && err != io.ErrUnexpectedEOF {
return err
}
in := string(buf[:n])
const features = "\nFeatures : "
i := strings.Index(in, features)
if i == -1 {
return errors.New("no CPU features found")
}
in = in[i+len(features):]
if i := strings.Index(in, "\n"); i != -1 {
in = in[:i]
}
m := map[string]*bool{}
initOptions() // need it early here; it's harmless to call twice
for _, o := range options {
m[o.Name] = o.Feature
}
// The EVTSTRM field has alias "evstrm" in Go, but Linux calls it "evtstrm".
m["evtstrm"] = &ARM64.HasEVTSTRM
for _, f := range strings.Fields(in) {
if p, ok := m[f]; ok {
*p = true
}
}
return nil
}
================================================
FILE: vendor/golang.org/x/sys/cpu/runtime_auxv.go
================================================
// Copyright 2023 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.
package cpu
// getAuxvFn is non-nil on Go 1.21+ (via runtime_auxv_go121.go init)
// on platforms that use auxv.
var getAuxvFn func() []uintptr
func getAuxv() []uintptr {
if getAuxvFn == nil {
return nil
}
return getAuxvFn()
}
================================================
FILE: vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go
================================================
// Copyright 2023 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.
//go:build go1.21
package cpu
import (
_ "unsafe" // for linkname
)
//go:linkname runtime_getAuxv runtime.getAuxv
func runtime_getAuxv() []uintptr
func init() {
getAuxvFn = runtime_getAuxv
}
================================================
FILE: vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go
================================================
// Copyright 2020 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.
// Recreate a getsystemcfg syscall handler instead of
// using the one provided by x/sys/unix to avoid having
// the dependency between them. (See golang.org/issue/32102)
// Moreover, this file will be used during the building of
// gccgo's libgo and thus must not used a CGo method.
//go:build aix && gccgo
package cpu
import (
"syscall"
)
//extern getsystemcfg
func gccgoGetsystemcfg(label uint32) (r uint64)
func callgetsystemcfg(label int) (r1 uintptr, e1 syscall.Errno) {
r1 = uintptr(gccgoGetsystemcfg(uint32(label)))
e1 = syscall.GetErrno()
return
}
================================================
FILE: vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go
================================================
// Copyright 2019 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.
// Minimal copy of x/sys/unix so the cpu package can make a
// system call on AIX without depending on x/sys/unix.
// (See golang.org/issue/32102)
//go:build aix && ppc64 && gc
package cpu
import (
"syscall"
"unsafe"
)
//go:cgo_import_dynamic libc_getsystemcfg getsystemcfg "libc.a/shr_64.o"
//go:linkname libc_getsystemcfg libc_getsystemcfg
type syscallFunc uintptr
var libc_getsystemcfg syscallFunc
type errno = syscall.Errno
// Implemented in runtime/syscall_aix.go.
func rawSyscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err errno)
func syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err errno)
func callgetsystemcfg(label int) (r1 uintptr, e1 errno) {
r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_getsystemcfg)), 1, uintptr(label), 0, 0, 0, 0, 0)
return
}
================================================
FILE: vendor/golang.org/x/sys/cpu/syscall_darwin_x86_gc.go
================================================
// Copyright 2024 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.
// Minimal copy of x/sys/unix so the cpu package can make a
// system call on Darwin without depending on x/sys/unix.
//go:build darwin && amd64 && gc
package cpu
import (
"syscall"
"unsafe"
)
type _C_int int32
// adapted from unix.Uname() at x/sys/unix/syscall_darwin.go L419
func darwinOSRelease(release *[256]byte) error {
// from x/sys/unix/zerrors_openbsd_amd64.go
const (
CTL_KERN = 0x1
KERN_OSRELEASE = 0x2
)
mib := []_C_int{CTL_KERN, KERN_OSRELEASE}
n := unsafe.Sizeof(*release)
return sysctl(mib, &release[0], &n, nil, 0)
}
type Errno = syscall.Errno
var _zero uintptr // Single-word zero for use when we need a valid pointer to 0 bytes.
// from x/sys/unix/zsyscall_darwin_amd64.go L791-807
func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) error {
var _p0 unsafe.Pointer
if len(mib) > 0 {
_p0 = unsafe.Pointer(&mib[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
if _, _, err := syscall_syscall6(
libc_sysctl_trampoline_addr,
uintptr(_p0),
uintptr(len(mib)),
uintptr(unsafe.Pointer(old)),
uintptr(unsafe.Pointer(oldlen)),
uintptr(unsafe.Pointer(new)),
uintptr(newlen),
); err != 0 {
return err
}
return nil
}
var libc_sysctl_trampoline_addr uintptr
// adapted from internal/cpu/cpu_arm64_darwin.go
func darwinSysctlEnabled(name []byte) bool {
out := int32(0)
nout := unsafe.Sizeof(out)
if ret := sysctlbyname(&name[0], (*byte)(unsafe.Pointer(&out)), &nout, nil, 0); ret != nil {
return false
}
return out > 0
}
//go:cgo_import_dynamic libc_sysctl sysctl "/usr/lib/libSystem.B.dylib"
var libc_sysctlbyname_trampoline_addr uintptr
// adapted from runtime/sys_darwin.go in the pattern of sysctl() above, as defined in x/sys/unix
func sysctlbyname(name *byte, old *byte, oldlen *uintptr, new *byte, newlen uintptr) error {
if _, _, err := syscall_syscall6(
libc_sysctlbyname_trampoline_addr,
uintptr(unsafe.Pointer(name)),
uintptr(unsafe.Pointer(old)),
uintptr(unsafe.Pointer(oldlen)),
uintptr(unsafe.Pointer(new)),
uintptr(newlen),
0,
); err != 0 {
return err
}
return nil
}
//go:cgo_import_dynamic libc_sysctlbyname sysctlbyname "/usr/lib/libSystem.B.dylib"
// Implemented in the runtime package (runtime/sys_darwin.go)
func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
//go:linkname syscall_syscall6 syscall.syscall6
================================================
FILE: vendor/golang.org/x/sys/plan9/asm.s
================================================
// Copyright 2014 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.
#include "textflag.h"
TEXT ·use(SB),NOSPLIT,$0
RET
================================================
FILE: vendor/golang.org/x/sys/plan9/asm_plan9_386.s
================================================
// Copyright 2009 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.
#include "textflag.h"
//
// System call support for 386, Plan 9
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-32
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-44
JMP syscall·Syscall6(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)
TEXT ·seek(SB),NOSPLIT,$0-36
JMP syscall·seek(SB)
TEXT ·exit(SB),NOSPLIT,$4-4
JMP syscall·exit(SB)
================================================
FILE: vendor/golang.org/x/sys/plan9/asm_plan9_amd64.s
================================================
// Copyright 2009 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.
#include "textflag.h"
//
// System call support for amd64, Plan 9
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-64
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-88
JMP syscall·Syscall6(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
TEXT ·seek(SB),NOSPLIT,$0-56
JMP syscall·seek(SB)
TEXT ·exit(SB),NOSPLIT,$8-8
JMP syscall·exit(SB)
================================================
FILE: vendor/golang.org/x/sys/plan9/asm_plan9_arm.s
================================================
// Copyright 2009 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.
#include "textflag.h"
// System call support for plan9 on arm
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-32
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-44
JMP syscall·Syscall6(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)
TEXT ·seek(SB),NOSPLIT,$0-36
JMP syscall·exit(SB)
================================================
FILE: vendor/golang.org/x/sys/plan9/const_plan9.go
================================================
package plan9
// Plan 9 Constants
// Open modes
const (
O_RDONLY = 0
O_WRONLY = 1
O_RDWR = 2
O_TRUNC = 16
O_CLOEXEC = 32
O_EXCL = 0x1000
)
// Rfork flags
const (
RFNAMEG = 1 << 0
RFENVG = 1 << 1
RFFDG = 1 << 2
RFNOTEG = 1 << 3
RFPROC = 1 << 4
RFMEM = 1 << 5
RFNOWAIT = 1 << 6
RFCNAMEG = 1 << 10
RFCENVG = 1 << 11
RFCFDG = 1 << 12
RFREND = 1 << 13
RFNOMNT = 1 << 14
)
// Qid.Type bits
const (
QTDIR = 0x80
QTAPPEND = 0x40
QTEXCL = 0x20
QTMOUNT = 0x10
QTAUTH = 0x08
QTTMP = 0x04
QTFILE = 0x00
)
// Dir.Mode bits
const (
DMDIR = 0x80000000
DMAPPEND = 0x40000000
DMEXCL = 0x20000000
DMMOUNT = 0x10000000
DMAUTH = 0x08000000
DMTMP = 0x04000000
DMREAD = 0x4
DMWRITE = 0x2
DMEXEC = 0x1
)
const (
STATMAX = 65535
ERRMAX = 128
STATFIXLEN = 49
)
// Mount and bind flags
const (
MREPL = 0x0000
MBEFORE = 0x0001
MAFTER = 0x0002
MORDER = 0x0003
MCREATE = 0x0004
MCACHE = 0x0010
MMASK = 0x0017
)
================================================
FILE: vendor/golang.org/x/sys/plan9/dir_plan9.go
================================================
// Copyright 2012 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.
// Plan 9 directory marshalling. See intro(5).
package plan9
import "errors"
var (
ErrShortStat = errors.New("stat buffer too short")
ErrBadStat = errors.New("malformed stat buffer")
ErrBadName = errors.New("bad character in file name")
)
// A Qid represents a 9P server's unique identification for a file.
type Qid struct {
Path uint64 // the file server's unique identification for the file
Vers uint32 // version number for given Path
Type uint8 // the type of the file (plan9.QTDIR for example)
}
// A Dir contains the metadata for a file.
type Dir struct {
// system-modified data
Type uint16 // server type
Dev uint32 // server subtype
// file data
Qid Qid // unique id from server
Mode uint32 // permissions
Atime uint32 // last read time
Mtime uint32 // last write time
Length int64 // file length
Name string // last element of path
Uid string // owner name
Gid string // group name
Muid string // last modifier name
}
var nullDir = Dir{
Type: ^uint16(0),
Dev: ^uint32(0),
Qid: Qid{
Path: ^uint64(0),
Vers: ^uint32(0),
Type: ^uint8(0),
},
Mode: ^uint32(0),
Atime: ^uint32(0),
Mtime: ^uint32(0),
Length: ^int64(0),
}
// Null assigns special "don't touch" values to members of d to
// avoid modifying them during plan9.Wstat.
func (d *Dir) Null() { *d = nullDir }
// Marshal encodes a 9P stat message corresponding to d into b
//
// If there isn't enough space in b for a stat message, ErrShortStat is returned.
func (d *Dir) Marshal(b []byte) (n int, err error) {
n = STATFIXLEN + len(d.Name) + len(d.Uid) + len(d.Gid) + len(d.Muid)
if n > len(b) {
return n, ErrShortStat
}
for _, c := range d.Name {
if c == '/' {
return n, ErrBadName
}
}
b = pbit16(b, uint16(n)-2)
b = pbit16(b, d.Type)
b = pbit32(b, d.Dev)
b = pbit8(b, d.Qid.Type)
b = pbit32(b, d.Qid.Vers)
b = pbit64(b, d.Qid.Path)
b = pbit32(b, d.Mode)
b = pbit32(b, d.Atime)
b = pbit32(b, d.Mtime)
b = pbit64(b, uint64(d.Length))
b = pstring(b, d.Name)
b = pstring(b, d.Uid)
b = pstring(b, d.Gid)
b = pstring(b, d.Muid)
return n, nil
}
// UnmarshalDir decodes a single 9P stat message from b and returns the resulting Dir.
//
// If b is too small to hold a valid stat message, ErrShortStat is returned.
//
// If the stat message itself is invalid, ErrBadStat is returned.
func UnmarshalDir(b []byte) (*Dir, error) {
if len(b) < STATFIXLEN {
return nil, ErrShortStat
}
size, buf := gbit16(b)
if len(b) != int(size)+2 {
return nil, ErrBadStat
}
b = buf
var d Dir
d.Type, b = gbit16(b)
d.Dev, b = gbit32(b)
d.Qid.Type, b = gbit8(b)
d.Qid.Vers, b = gbit32(b)
d.Qid.Path, b = gbit64(b)
d.Mode, b = gbit32(b)
d.Atime, b = gbit32(b)
d.Mtime, b = gbit32(b)
n, b := gbit64(b)
d.Length = int64(n)
var ok bool
if d.Name, b, ok = gstring(b); !ok {
return nil, ErrBadStat
}
if d.Uid, b, ok = gstring(b); !ok {
return nil, ErrBadStat
}
if d.Gid, b, ok = gstring(b); !ok {
return nil, ErrBadStat
}
if d.Muid, b, ok = gstring(b); !ok {
return nil, ErrBadStat
}
return &d, nil
}
// pbit8 copies the 8-bit number v to b and returns the remaining slice of b.
func pbit8(b []byte, v uint8) []byte {
b[0] = byte(v)
return b[1:]
}
// pbit16 copies the 16-bit number v to b in little-endian order and returns the remaining slice of b.
func pbit16(b []byte, v uint16) []byte {
b[0] = byte(v)
b[1] = byte(v >> 8)
return b[2:]
}
// pbit32 copies the 32-bit number v to b in little-endian order and returns the remaining slice of b.
func pbit32(b []byte, v uint32) []byte {
b[0] = byte(v)
b[1] = byte(v >> 8)
b[2] = byte(v >> 16)
b[3] = byte(v >> 24)
return b[4:]
}
// pbit64 copies the 64-bit number v to b in little-endian order and returns the remaining slice of b.
func pbit64(b []byte, v uint64) []byte {
b[0] = byte(v)
b[1] = byte(v >> 8)
b[2] = byte(v >> 16)
b[3] = byte(v >> 24)
b[4] = byte(v >> 32)
b[5] = byte(v >> 40)
b[6] = byte(v >> 48)
b[7] = byte(v >> 56)
return b[8:]
}
// pstring copies the string s to b, prepending it with a 16-bit length in little-endian order, and
// returning the remaining slice of b..
func pstring(b []byte, s string) []byte {
b = pbit16(b, uint16(len(s)))
n := copy(b, s)
return b[n:]
}
// gbit8 reads an 8-bit number from b and returns it with the remaining slice of b.
func gbit8(b []byte) (uint8, []byte) {
return uint8(b[0]), b[1:]
}
// gbit16 reads a 16-bit number in little-endian order from b and returns it with the remaining slice of b.
func gbit16(b []byte) (uint16, []byte) {
return uint16(b[0]) | uint16(b[1])<<8, b[2:]
}
// gbit32 reads a 32-bit number in little-endian order from b and returns it with the remaining slice of b.
func gbit32(b []byte) (uint32, []byte) {
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, b[4:]
}
// gbit64 reads a 64-bit number in little-endian order from b and returns it with the remaining slice of b.
func gbit64(b []byte) (uint64, []byte) {
lo := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
hi := uint32(b[4]) | uint32(b[5])<<8 | uint32(b[6])<<16 | uint32(b[7])<<24
return uint64(lo) | uint64(hi)<<32, b[8:]
}
// gstring reads a string from b, prefixed with a 16-bit length in little-endian order.
// It returns the string with the remaining slice of b and a boolean. If the length is
// greater than the number of bytes in b, the boolean will be false.
func gstring(b []byte) (string, []byte, bool) {
n, b := gbit16(b)
if int(n) > len(b) {
return "", b, false
}
return string(b[:n]), b[n:], true
}
================================================
FILE: vendor/golang.org/x/sys/plan9/env_plan9.go
================================================
// 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.
// Plan 9 environment variables.
package plan9
import (
"syscall"
)
func Getenv(key string) (value string, found bool) {
return syscall.Getenv(key)
}
func Setenv(key, value string) error {
return syscall.Setenv(key, value)
}
func Clearenv() {
syscall.Clearenv()
}
func Environ() []string {
return syscall.Environ()
}
func Unsetenv(key string) error {
return syscall.Unsetenv(key)
}
================================================
FILE: vendor/golang.org/x/sys/plan9/errors_plan9.go
================================================
// 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.
package plan9
import "syscall"
// Constants
const (
// Invented values to support what package os expects.
O_CREAT = 0x02000
O_APPEND = 0x00400
O_NOCTTY = 0x00000
O_NONBLOCK = 0x00000
O_SYNC = 0x00000
O_ASYNC = 0x00000
S_IFMT = 0x1f000
S_IFIFO = 0x1000
S_IFCHR = 0x2000
S_IFDIR = 0x4000
S_IFBLK = 0x6000
S_IFREG = 0x8000
S_IFLNK = 0xa000
S_IFSOCK = 0xc000
)
// Errors
var (
EINVAL = syscall.NewError("bad arg in system call")
ENOTDIR = syscall.NewError("not a directory")
EISDIR = syscall.NewError("file is a directory")
ENOENT = syscall.NewError("file does not exist")
EEXIST = syscall.NewError("file already exists")
EMFILE = syscall.NewError("no free file descriptors")
EIO = syscall.NewError("i/o error")
ENAMETOOLONG = syscall.NewError("file name too long")
EINTR = syscall.NewError("interrupted")
EPERM = syscall.NewError("permission denied")
EBUSY = syscall.NewError("no free devices")
ETIMEDOUT = syscall.NewError("connection timed out")
EPLAN9 = syscall.NewError("not supported by plan 9")
// The following errors do not correspond to any
// Plan 9 system messages. Invented to support
// what package os and others expect.
EACCES = syscall.NewError("access permission denied")
EAFNOSUPPORT = syscall.NewError("address family not supported by protocol")
)
================================================
FILE: vendor/golang.org/x/sys/plan9/mkall.sh
================================================
#!/usr/bin/env bash
# Copyright 2009 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.
# The plan9 package provides access to the raw system call
# interface of the underlying operating system. Porting Go to
# a new architecture/operating system combination requires
# some manual effort, though there are tools that automate
# much of the process. The auto-generated files have names
# beginning with z.
#
# This script runs or (given -n) prints suggested commands to generate z files
# for the current system. Running those commands is not automatic.
# This script is documentation more than anything else.
#
# * asm_${GOOS}_${GOARCH}.s
#
# This hand-written assembly file implements system call dispatch.
# There are three entry points:
#
# func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr);
# func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
# func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr);
#
# The first and second are the standard ones; they differ only in
# how many arguments can be passed to the kernel.
# The third is for low-level use by the ForkExec wrapper;
# unlike the first two, it does not call into the scheduler to
# let it know that a system call is running.
#
# * syscall_${GOOS}.go
#
# This hand-written Go file implements system calls that need
# special handling and lists "//sys" comments giving prototypes
# for ones that can be auto-generated. Mksyscall reads those
# comments to generate the stubs.
#
# * syscall_${GOOS}_${GOARCH}.go
#
# Same as syscall_${GOOS}.go except that it contains code specific
# to ${GOOS} on one particular architecture.
#
# * types_${GOOS}.c
#
# This hand-written C file includes standard C headers and then
# creates typedef or enum names beginning with a dollar sign
# (use of $ in variable names is a gcc extension). The hardest
# part about preparing this file is figuring out which headers to
# include and which symbols need to be #defined to get the
# actual data structures that pass through to the kernel system calls.
# Some C libraries present alternate versions for binary compatibility
# and translate them on the way in and out of system calls, but
# there is almost always a #define that can get the real ones.
# See types_darwin.c and types_linux.c for examples.
#
# * zerror_${GOOS}_${GOARCH}.go
#
# This machine-generated file defines the system's error numbers,
# error strings, and signal numbers. The generator is "mkerrors.sh".
# Usually no arguments are needed, but mkerrors.sh will pass its
# arguments on to godefs.
#
# * zsyscall_${GOOS}_${GOARCH}.go
#
# Generated by mksyscall.pl; see syscall_${GOOS}.go above.
#
# * zsysnum_${GOOS}_${GOARCH}.go
#
# Generated by mksysnum_${GOOS}.
#
# * ztypes_${GOOS}_${GOARCH}.go
#
# Generated by godefs; see types_${GOOS}.c above.
GOOSARCH="${GOOS}_${GOARCH}"
# defaults
mksyscall="go run mksyscall.go"
mkerrors="./mkerrors.sh"
zerrors="zerrors_$GOOSARCH.go"
mksysctl=""
zsysctl="zsysctl_$GOOSARCH.go"
mksysnum=
mktypes=
run="sh"
case "$1" in
-syscalls)
for i in zsyscall*go
do
sed 1q $i | sed 's;^// ;;' | sh > _$i && gofmt < _$i > $i
rm _$i
done
exit 0
;;
-n)
run="cat"
shift
esac
case "$#" in
0)
;;
*)
echo 'usage: mkall.sh [-n]' 1>&2
exit 2
esac
case "$GOOSARCH" in
_* | *_ | _)
echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2
exit 1
;;
plan9_386)
mkerrors=
mksyscall="go run mksyscall.go -l32 -plan9 -tags plan9,386"
mksysnum="./mksysnum_plan9.sh /n/sources/plan9/sys/src/libc/9syscall/sys.h"
mktypes="XXX"
;;
plan9_amd64)
mkerrors=
mksyscall="go run mksyscall.go -l32 -plan9 -tags plan9,amd64"
mksysnum="./mksysnum_plan9.sh /n/sources/plan9/sys/src/libc/9syscall/sys.h"
mktypes="XXX"
;;
plan9_arm)
mkerrors=
mksyscall="go run mksyscall.go -l32 -plan9 -tags plan9,arm"
mksysnum="./mksysnum_plan9.sh /n/sources/plan9/sys/src/libc/9syscall/sys.h"
mktypes="XXX"
;;
*)
echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
exit 1
;;
esac
(
if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi
case "$GOOS" in
plan9)
syscall_goos="syscall_$GOOS.go"
if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos |gofmt >zsyscall_$GOOSARCH.go"; fi
;;
esac
if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go |gofmt >ztypes_$GOOSARCH.go"; fi
) | $run
================================================
FILE: vendor/golang.org/x/sys/plan9/mkerrors.sh
================================================
#!/usr/bin/env bash
# Copyright 2009 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.
# Generate Go code listing errors and other #defined constant
# values (ENAMETOOLONG etc.), by asking the preprocessor
# about the definitions.
unset LANG
export LC_ALL=C
export LC_CTYPE=C
CC=${CC:-gcc}
uname=$(uname)
includes='
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
'
ccflags="$@"
# Write go tool cgo -godefs input.
(
echo package plan9
echo
echo '/*'
indirect="includes_$(uname)"
echo "${!indirect} $includes"
echo '*/'
echo 'import "C"'
echo
echo 'const ('
# The gcc command line prints all the #defines
# it encounters while processing the input
echo "${!indirect} $includes" | $CC -x c - -E -dM $ccflags |
awk '
$1 != "#define" || $2 ~ /\(/ || $3 == "" {next}
$2 ~ /^E([ABCD]X|[BIS]P|[SD]I|S|FL)$/ {next} # 386 registers
$2 ~ /^(SIGEV_|SIGSTKSZ|SIGRT(MIN|MAX))/ {next}
$2 ~ /^(SCM_SRCRT)$/ {next}
$2 ~ /^(MAP_FAILED)$/ {next}
$2 !~ /^ETH_/ &&
$2 !~ /^EPROC_/ &&
$2 !~ /^EQUIV_/ &&
$2 !~ /^EXPR_/ &&
$2 ~ /^E[A-Z0-9_]+$/ ||
$2 ~ /^B[0-9_]+$/ ||
$2 ~ /^V[A-Z0-9]+$/ ||
$2 ~ /^CS[A-Z0-9]/ ||
$2 ~ /^I(SIG|CANON|CRNL|EXTEN|MAXBEL|STRIP|UTF8)$/ ||
$2 ~ /^IGN/ ||
$2 ~ /^IX(ON|ANY|OFF)$/ ||
$2 ~ /^IN(LCR|PCK)$/ ||
$2 ~ /(^FLU?SH)|(FLU?SH$)/ ||
$2 ~ /^C(LOCAL|READ)$/ ||
$2 == "BRKINT" ||
$2 == "HUPCL" ||
$2 == "PENDIN" ||
$2 == "TOSTOP" ||
$2 ~ /^PAR/ ||
$2 ~ /^SIG[^_]/ ||
$2 ~ /^O[CNPFP][A-Z]+[^_][A-Z]+$/ ||
$2 ~ /^IN_/ ||
$2 ~ /^LOCK_(SH|EX|NB|UN)$/ ||
$2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|ICMP6|TCP|EVFILT|NOTE|EV|SHUT|PROT|MAP|PACKET|MSG|SCM|MCL|DT|MADV|PR)_/ ||
$2 == "ICMPV6_FILTER" ||
$2 == "SOMAXCONN" ||
$2 == "NAME_MAX" ||
$2 == "IFNAMSIZ" ||
$2 ~ /^CTL_(MAXNAME|NET|QUERY)$/ ||
$2 ~ /^SYSCTL_VERS/ ||
$2 ~ /^(MS|MNT)_/ ||
$2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ ||
$2 ~ /^(O|F|FD|NAME|S|PTRACE|PT)_/ ||
$2 ~ /^LINUX_REBOOT_CMD_/ ||
$2 ~ /^LINUX_REBOOT_MAGIC[12]$/ ||
$2 !~ "NLA_TYPE_MASK" &&
$2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P)_/ ||
$2 ~ /^SIOC/ ||
$2 ~ /^TIOC/ ||
$2 !~ "RTF_BITS" &&
$2 ~ /^(IFF|IFT|NET_RT|RTM|RTF|RTV|RTA|RTAX)_/ ||
$2 ~ /^BIOC/ ||
$2 ~ /^RUSAGE_(SELF|CHILDREN|THREAD)/ ||
$2 ~ /^RLIMIT_(AS|CORE|CPU|DATA|FSIZE|NOFILE|STACK)|RLIM_INFINITY/ ||
$2 ~ /^PRIO_(PROCESS|PGRP|USER)/ ||
$2 ~ /^CLONE_[A-Z_]+/ ||
$2 !~ /^(BPF_TIMEVAL)$/ &&
$2 ~ /^(BPF|DLT)_/ ||
$2 !~ "WMESGLEN" &&
$2 ~ /^W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", $2, $2)}
$2 ~ /^__WCOREFLAG$/ {next}
$2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)}
{next}
' | sort
echo ')'
) >_const.go
# Pull out the error names for later.
errors=$(
echo '#include ' | $CC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print $2 }' |
sort
)
# Pull out the signal names for later.
signals=$(
echo '#include ' | $CC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' |
grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT' |
sort
)
# Again, writing regexps to a file.
echo '#include ' | $CC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print "^\t" $2 "[ \t]*=" }' |
sort >_error.grep
echo '#include ' | $CC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' |
grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT' |
sort >_signal.grep
echo '// mkerrors.sh' "$@"
echo '// Code generated by the command above; DO NOT EDIT.'
echo
go tool cgo -godefs -- "$@" _const.go >_error.out
cat _error.out | grep -vf _error.grep | grep -vf _signal.grep
echo
echo '// Errors'
echo 'const ('
cat _error.out | grep -f _error.grep | sed 's/=\(.*\)/= Errno(\1)/'
echo ')'
echo
echo '// Signals'
echo 'const ('
cat _error.out | grep -f _signal.grep | sed 's/=\(.*\)/= Signal(\1)/'
echo ')'
# Run C program to print error and syscall strings.
(
echo -E "
#include
#include
#include
#include
#include
#include
#define nelem(x) (sizeof(x)/sizeof((x)[0]))
enum { A = 'A', Z = 'Z', a = 'a', z = 'z' }; // avoid need for single quotes below
int errors[] = {
"
for i in $errors
do
echo -E ' '$i,
done
echo -E "
};
int signals[] = {
"
for i in $signals
do
echo -E ' '$i,
done
# Use -E because on some systems bash builtin interprets \n itself.
echo -E '
};
static int
intcmp(const void *a, const void *b)
{
return *(int*)a - *(int*)b;
}
int
main(void)
{
int i, j, e;
char buf[1024], *p;
printf("\n\n// Error table\n");
printf("var errors = [...]string {\n");
qsort(errors, nelem(errors), sizeof errors[0], intcmp);
for(i=0; i 0 && errors[i-1] == e)
continue;
strcpy(buf, strerror(e));
// lowercase first letter: Bad -> bad, but STREAM -> STREAM.
if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
buf[0] += a - A;
printf("\t%d: \"%s\",\n", e, buf);
}
printf("}\n\n");
printf("\n\n// Signal table\n");
printf("var signals = [...]string {\n");
qsort(signals, nelem(signals), sizeof signals[0], intcmp);
for(i=0; i 0 && signals[i-1] == e)
continue;
strcpy(buf, strsignal(e));
// lowercase first letter: Bad -> bad, but STREAM -> STREAM.
if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
buf[0] += a - A;
// cut trailing : number.
p = strrchr(buf, ":"[0]);
if(p)
*p = '\0';
printf("\t%d: \"%s\",\n", e, buf);
}
printf("}\n\n");
return 0;
}
'
) >_errors.c
$CC $ccflags -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors _const.go _error.grep _signal.grep _error.out
================================================
FILE: vendor/golang.org/x/sys/plan9/mksysnum_plan9.sh
================================================
#!/bin/sh
# Copyright 2009 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.
COMMAND="mksysnum_plan9.sh $@"
cat <= 10 {
buf[i] = byte(val%10 + '0')
i--
val /= 10
}
buf[i] = byte(val + '0')
return string(buf[i:])
}
================================================
FILE: vendor/golang.org/x/sys/plan9/syscall.go
================================================
// Copyright 2009 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.
//go:build plan9
// Package plan9 contains an interface to the low-level operating system
// primitives. OS details vary depending on the underlying system, and
// by default, godoc will display the OS-specific documentation for the current
// system. If you want godoc to display documentation for another
// system, set $GOOS and $GOARCH to the desired system. For example, if
// you want to view documentation for freebsd/arm on linux/amd64, set $GOOS
// to freebsd and $GOARCH to arm.
//
// The primary use of this package is inside other packages that provide a more
// portable interface to the system, such as "os", "time" and "net". Use
// those packages rather than this one if you can.
//
// For details of the functions and data types in this package consult
// the manuals for the appropriate operating system.
//
// These calls return err == nil to indicate success; otherwise
// err represents an operating system error describing the failure and
// holds a value of type syscall.ErrorString.
package plan9 // import "golang.org/x/sys/plan9"
import (
"bytes"
"strings"
"unsafe"
)
// ByteSliceFromString returns a NUL-terminated slice of bytes
// containing the text of s. If s contains a NUL byte at any
// location, it returns (nil, EINVAL).
func ByteSliceFromString(s string) ([]byte, error) {
if strings.IndexByte(s, 0) != -1 {
return nil, EINVAL
}
a := make([]byte, len(s)+1)
copy(a, s)
return a, nil
}
// BytePtrFromString returns a pointer to a NUL-terminated array of
// bytes containing the text of s. If s contains a NUL byte at any
// location, it returns (nil, EINVAL).
func BytePtrFromString(s string) (*byte, error) {
a, err := ByteSliceFromString(s)
if err != nil {
return nil, err
}
return &a[0], nil
}
// ByteSliceToString returns a string form of the text represented by the slice s, with a terminating NUL and any
// bytes after the NUL removed.
func ByteSliceToString(s []byte) string {
if i := bytes.IndexByte(s, 0); i != -1 {
s = s[:i]
}
return string(s)
}
// BytePtrToString takes a pointer to a sequence of text and returns the corresponding string.
// If the pointer is nil, it returns the empty string. It assumes that the text sequence is terminated
// at a zero byte; if the zero byte is not present, the program may crash.
func BytePtrToString(p *byte) string {
if p == nil {
return ""
}
if *p == 0 {
return ""
}
// Find NUL terminator.
n := 0
for ptr := unsafe.Pointer(p); *(*byte)(ptr) != 0; n++ {
ptr = unsafe.Pointer(uintptr(ptr) + 1)
}
return string(unsafe.Slice(p, n))
}
// Single-word zero for use when we need a valid pointer to 0 bytes.
// See mksyscall.pl.
var _zero uintptr
func (ts *Timespec) Unix() (sec int64, nsec int64) {
return int64(ts.Sec), int64(ts.Nsec)
}
func (tv *Timeval) Unix() (sec int64, nsec int64) {
return int64(tv.Sec), int64(tv.Usec) * 1000
}
func (ts *Timespec) Nano() int64 {
return int64(ts.Sec)*1e9 + int64(ts.Nsec)
}
func (tv *Timeval) Nano() int64 {
return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000
}
// use is a no-op, but the compiler cannot see that it is.
// Calling use(p) ensures that p is kept live until that point.
//
//go:noescape
func use(p unsafe.Pointer)
================================================
FILE: vendor/golang.org/x/sys/plan9/syscall_plan9.go
================================================
// 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.
// Plan 9 system calls.
// This file is compiled as ordinary Go code,
// but it is also input to mksyscall,
// which parses the //sys lines and generates system call stubs.
// Note that sometimes we use a lowercase //sys name and
// wrap it in our own nicer implementation.
package plan9
import (
"bytes"
"syscall"
"unsafe"
)
// A Note is a string describing a process note.
// It implements the os.Signal interface.
type Note string
func (n Note) Signal() {}
func (n Note) String() string {
return string(n)
}
var (
Stdin = 0
Stdout = 1
Stderr = 2
)
// For testing: clients can set this flag to force
// creation of IPv6 sockets to return EAFNOSUPPORT.
var SocketDisableIPv6 bool
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.ErrorString)
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.ErrorString)
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
func atoi(b []byte) (n uint) {
n = 0
for i := 0; i < len(b); i++ {
n = n*10 + uint(b[i]-'0')
}
return
}
func cstring(s []byte) string {
i := bytes.IndexByte(s, 0)
if i == -1 {
i = len(s)
}
return string(s[:i])
}
func errstr() string {
var buf [ERRMAX]byte
RawSyscall(SYS_ERRSTR, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)), 0)
buf[len(buf)-1] = 0
return cstring(buf[:])
}
// Implemented in assembly to import from runtime.
func exit(code int)
func Exit(code int) { exit(code) }
func readnum(path string) (uint, error) {
var b [12]byte
fd, e := Open(path, O_RDONLY)
if e != nil {
return 0, e
}
defer Close(fd)
n, e := Pread(fd, b[:], 0)
if e != nil {
return 0, e
}
m := 0
for ; m < n && b[m] == ' '; m++ {
}
return atoi(b[m : n-1]), nil
}
func Getpid() (pid int) {
n, _ := readnum("#c/pid")
return int(n)
}
func Getppid() (ppid int) {
n, _ := readnum("#c/ppid")
return int(n)
}
func Read(fd int, p []byte) (n int, err error) {
return Pread(fd, p, -1)
}
func Write(fd int, p []byte) (n int, err error) {
return Pwrite(fd, p, -1)
}
var ioSync int64
//sys fd2path(fd int, buf []byte) (err error)
func Fd2path(fd int) (path string, err error) {
var buf [512]byte
e := fd2path(fd, buf[:])
if e != nil {
return "", e
}
return cstring(buf[:]), nil
}
//sys pipe(p *[2]int32) (err error)
func Pipe(p []int) (err error) {
if len(p) != 2 {
return syscall.ErrorString("bad arg in system call")
}
var pp [2]int32
err = pipe(&pp)
if err == nil {
p[0] = int(pp[0])
p[1] = int(pp[1])
}
return
}
// Underlying system call writes to newoffset via pointer.
// Implemented in assembly to avoid allocation.
func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
newoffset, e := seek(0, fd, offset, whence)
if newoffset == -1 {
err = syscall.ErrorString(e)
}
return
}
func Mkdir(path string, mode uint32) (err error) {
fd, err := Create(path, O_RDONLY, DMDIR|mode)
if fd != -1 {
Close(fd)
}
return
}
type Waitmsg struct {
Pid int
Time [3]uint32
Msg string
}
func (w Waitmsg) Exited() bool { return true }
func (w Waitmsg) Signaled() bool { return false }
func (w Waitmsg) ExitStatus() int {
if len(w.Msg) == 0 {
// a normal exit returns no message
return 0
}
return 1
}
//sys await(s []byte) (n int, err error)
func Await(w *Waitmsg) (err error) {
var buf [512]byte
var f [5][]byte
n, err := await(buf[:])
if err != nil || w == nil {
return
}
nf := 0
p := 0
for i := 0; i < n && nf < len(f)-1; i++ {
if buf[i] == ' ' {
f[nf] = buf[p:i]
p = i + 1
nf++
}
}
f[nf] = buf[p:]
nf++
if nf != len(f) {
return syscall.ErrorString("invalid wait message")
}
w.Pid = int(atoi(f[0]))
w.Time[0] = uint32(atoi(f[1]))
w.Time[1] = uint32(atoi(f[2]))
w.Time[2] = uint32(atoi(f[3]))
w.Msg = cstring(f[4])
if w.Msg == "''" {
// await() returns '' for no error
w.Msg = ""
}
return
}
func Unmount(name, old string) (err error) {
fixwd()
oldp, err := BytePtrFromString(old)
if err != nil {
return err
}
oldptr := uintptr(unsafe.Pointer(oldp))
var r0 uintptr
var e syscall.ErrorString
// bind(2) man page: If name is zero, everything bound or mounted upon old is unbound or unmounted.
if name == "" {
r0, _, e = Syscall(SYS_UNMOUNT, _zero, oldptr, 0)
} else {
namep, err := BytePtrFromString(name)
if err != nil {
return err
}
r0, _, e = Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(namep)), oldptr, 0)
}
if int32(r0) == -1 {
err = e
}
return
}
func Fchdir(fd int) (err error) {
path, err := Fd2path(fd)
if err != nil {
return
}
return Chdir(path)
}
type Timespec struct {
Sec int32
Nsec int32
}
type Timeval struct {
Sec int32
Usec int32
}
func NsecToTimeval(nsec int64) (tv Timeval) {
nsec += 999 // round up to microsecond
tv.Usec = int32(nsec % 1e9 / 1e3)
tv.Sec = int32(nsec / 1e9)
return
}
func nsec() int64 {
var scratch int64
r0, _, _ := Syscall(SYS_NSEC, uintptr(unsafe.Pointer(&scratch)), 0, 0)
// TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
if r0 == 0 {
return scratch
}
return int64(r0)
}
func Gettimeofday(tv *Timeval) error {
nsec := nsec()
*tv = NsecToTimeval(nsec)
return nil
}
func Getpagesize() int { return 0x1000 }
func Getegid() (egid int) { return -1 }
func Geteuid() (euid int) { return -1 }
func Getgid() (gid int) { return -1 }
func Getuid() (uid int) { return -1 }
func Getgroups() (gids []int, err error) {
return make([]int, 0), nil
}
//sys open(path string, mode int) (fd int, err error)
func Open(path string, mode int) (fd int, err error) {
fixwd()
return open(path, mode)
}
//sys create(path string, mode int, perm uint32) (fd int, err error)
func Create(path string, mode int, perm uint32) (fd int, err error) {
fixwd()
return create(path, mode, perm)
}
//sys remove(path string) (err error)
func Remove(path string) error {
fixwd()
return remove(path)
}
//sys stat(path string, edir []byte) (n int, err error)
func Stat(path string, edir []byte) (n int, err error) {
fixwd()
return stat(path, edir)
}
//sys bind(name string, old string, flag int) (err error)
func Bind(name string, old string, flag int) (err error) {
fixwd()
return bind(name, old, flag)
}
//sys mount(fd int, afd int, old string, flag int, aname string) (err error)
func Mount(fd int, afd int, old string, flag int, aname string) (err error) {
fixwd()
return mount(fd, afd, old, flag, aname)
}
//sys wstat(path string, edir []byte) (err error)
func Wstat(path string, edir []byte) (err error) {
fixwd()
return wstat(path, edir)
}
//sys chdir(path string) (err error)
//sys Dup(oldfd int, newfd int) (fd int, err error)
//sys Pread(fd int, p []byte, offset int64) (n int, err error)
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
//sys Close(fd int) (err error)
//sys Fstat(fd int, edir []byte) (n int, err error)
//sys Fwstat(fd int, edir []byte) (err error)
================================================
FILE: vendor/golang.org/x/sys/plan9/zsyscall_plan9_386.go
================================================
// go run mksyscall.go -l32 -plan9 -tags plan9,386 syscall_plan9.go
// Code generated by the command above; see README.md. DO NOT EDIT.
//go:build plan9 && 386
package plan9
import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func fd2path(fd int, buf []byte) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_FD2PATH, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func pipe(p *[2]int32) (err error) {
r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func await(s []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(s) > 0 {
_p0 = unsafe.Pointer(&s[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_AWAIT, uintptr(_p0), uintptr(len(s)), 0)
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func open(path string, mode int) (fd int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
fd = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func create(path string, mode int, perm uint32) (fd int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
fd = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func remove(path string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(_p0)), 0, 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func stat(path string, edir []byte) (n int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
var _p1 unsafe.Pointer
if len(edir) > 0 {
_p1 = unsafe.Pointer(&edir[0])
} else {
_p1 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func bind(name string, old string, flag int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(name)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(old)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag))
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func mount(fd int, afd int, old string, flag int, aname string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(old)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(aname)
if err != nil {
return
}
r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(_p0)), uintptr(flag), uintptr(unsafe.Pointer(_p1)), 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func wstat(path string, edir []byte) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
var _p1 unsafe.Pointer
if len(edir) > 0 {
_p1 = unsafe.Pointer(&edir[0])
} else {
_p1 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func chdir(path string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Dup(oldfd int, newfd int) (fd int, err error) {
r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0)
fd = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Pread(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Close(fd int) (err error) {
r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Fstat(fd int, edir []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(edir) > 0 {
_p0 = unsafe.Pointer(&edir[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Fwstat(fd int, edir []byte) (err error) {
var _p0 unsafe.Pointer
if len(edir) > 0 {
_p0 = unsafe.Pointer(&edir[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_FWSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
if int32(r0) == -1 {
err = e1
}
return
}
================================================
FILE: vendor/golang.org/x/sys/plan9/zsyscall_plan9_amd64.go
================================================
// go run mksyscall.go -l32 -plan9 -tags plan9,amd64 syscall_plan9.go
// Code generated by the command above; see README.md. DO NOT EDIT.
//go:build plan9 && amd64
package plan9
import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func fd2path(fd int, buf []byte) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_FD2PATH, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func pipe(p *[2]int32) (err error) {
r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func await(s []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(s) > 0 {
_p0 = unsafe.Pointer(&s[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_AWAIT, uintptr(_p0), uintptr(len(s)), 0)
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func open(path string, mode int) (fd int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
fd = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func create(path string, mode int, perm uint32) (fd int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
fd = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func remove(path string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(_p0)), 0, 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func stat(path string, edir []byte) (n int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
var _p1 unsafe.Pointer
if len(edir) > 0 {
_p1 = unsafe.Pointer(&edir[0])
} else {
_p1 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func bind(name string, old string, flag int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(name)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(old)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag))
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func mount(fd int, afd int, old string, flag int, aname string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(old)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(aname)
if err != nil {
return
}
r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(_p0)), uintptr(flag), uintptr(unsafe.Pointer(_p1)), 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func wstat(path string, edir []byte) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
var _p1 unsafe.Pointer
if len(edir) > 0 {
_p1 = unsafe.Pointer(&edir[0])
} else {
_p1 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func chdir(path string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Dup(oldfd int, newfd int) (fd int, err error) {
r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0)
fd = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Pread(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Close(fd int) (err error) {
r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Fstat(fd int, edir []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(edir) > 0 {
_p0 = unsafe.Pointer(&edir[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Fwstat(fd int, edir []byte) (err error) {
var _p0 unsafe.Pointer
if len(edir) > 0 {
_p0 = unsafe.Pointer(&edir[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_FWSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
if int32(r0) == -1 {
err = e1
}
return
}
================================================
FILE: vendor/golang.org/x/sys/plan9/zsyscall_plan9_arm.go
================================================
// go run mksyscall.go -l32 -plan9 -tags plan9,arm syscall_plan9.go
// Code generated by the command above; see README.md. DO NOT EDIT.
//go:build plan9 && arm
package plan9
import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func fd2path(fd int, buf []byte) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_FD2PATH, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func pipe(p *[2]int32) (err error) {
r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func await(s []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(s) > 0 {
_p0 = unsafe.Pointer(&s[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_AWAIT, uintptr(_p0), uintptr(len(s)), 0)
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func open(path string, mode int) (fd int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
fd = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func create(path string, mode int, perm uint32) (fd int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
fd = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func remove(path string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(_p0)), 0, 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func stat(path string, edir []byte) (n int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
var _p1 unsafe.Pointer
if len(edir) > 0 {
_p1 = unsafe.Pointer(&edir[0])
} else {
_p1 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func bind(name string, old string, flag int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(name)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(old)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag))
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func mount(fd int, afd int, old string, flag int, aname string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(old)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(aname)
if err != nil {
return
}
r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(_p0)), uintptr(flag), uintptr(unsafe.Pointer(_p1)), 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func wstat(path string, edir []byte) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
var _p1 unsafe.Pointer
if len(edir) > 0 {
_p1 = unsafe.Pointer(&edir[0])
} else {
_p1 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func chdir(path string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Dup(oldfd int, newfd int) (fd int, err error) {
r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0)
fd = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Pread(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Close(fd int) (err error) {
r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Fstat(fd int, edir []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(edir) > 0 {
_p0 = unsafe.Pointer(&edir[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
n = int(r0)
if int32(r0) == -1 {
err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Fwstat(fd int, edir []byte) (err error) {
var _p0 unsafe.Pointer
if len(edir) > 0 {
_p0 = unsafe.Pointer(&edir[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_FWSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
if int32(r0) == -1 {
err = e1
}
return
}
================================================
FILE: vendor/golang.org/x/sys/plan9/zsysnum_plan9.go
================================================
// mksysnum_plan9.sh /opt/plan9/sys/src/libc/9syscall/sys.h
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
package plan9
const (
SYS_SYSR1 = 0
SYS_BIND = 2
SYS_CHDIR = 3
SYS_CLOSE = 4
SYS_DUP = 5
SYS_ALARM = 6
SYS_EXEC = 7
SYS_EXITS = 8
SYS_FAUTH = 10
SYS_SEGBRK = 12
SYS_OPEN = 14
SYS_OSEEK = 16
SYS_SLEEP = 17
SYS_RFORK = 19
SYS_PIPE = 21
SYS_CREATE = 22
SYS_FD2PATH = 23
SYS_BRK_ = 24
SYS_REMOVE = 25
SYS_NOTIFY = 28
SYS_NOTED = 29
SYS_SEGATTACH = 30
SYS_SEGDETACH = 31
SYS_SEGFREE = 32
SYS_SEGFLUSH = 33
SYS_RENDEZVOUS = 34
SYS_UNMOUNT = 35
SYS_SEMACQUIRE = 37
SYS_SEMRELEASE = 38
SYS_SEEK = 39
SYS_FVERSION = 40
SYS_ERRSTR = 41
SYS_STAT = 42
SYS_FSTAT = 43
SYS_WSTAT = 44
SYS_FWSTAT = 45
SYS_MOUNT = 46
SYS_AWAIT = 47
SYS_PREAD = 50
SYS_PWRITE = 51
SYS_TSEMACQUIRE = 52
SYS_NSEC = 53
)
================================================
FILE: vendor/golang.org/x/sys/unix/.gitignore
================================================
_obj/
unix.test
================================================
FILE: vendor/golang.org/x/sys/unix/README.md
================================================
# Building `sys/unix`
The sys/unix package provides access to the raw system call interface of the
underlying operating system. See: https://godoc.org/golang.org/x/sys/unix
Porting Go to a new architecture/OS combination or adding syscalls, types, or
constants to an existing architecture/OS pair requires some manual effort;
however, there are tools that automate much of the process.
## Build Systems
There are currently two ways we generate the necessary files. We are currently
migrating the build system to use containers so the builds are reproducible.
This is being done on an OS-by-OS basis. Please update this documentation as
components of the build system change.
### Old Build System (currently for `GOOS != "linux"`)
The old build system generates the Go files based on the C header files
present on your system. This means that files
for a given GOOS/GOARCH pair must be generated on a system with that OS and
architecture. This also means that the generated code can differ from system
to system, based on differences in the header files.
To avoid this, if you are using the old build system, only generate the Go
files on an installation with unmodified header files. It is also important to
keep track of which version of the OS the files were generated from (ex.
Darwin 14 vs Darwin 15). This makes it easier to track the progress of changes
and have each OS upgrade correspond to a single change.
To build the files for your current OS and architecture, make sure GOOS and
GOARCH are set correctly and run `mkall.sh`. This will generate the files for
your specific system. Running `mkall.sh -n` shows the commands that will be run.
Requirements: bash, go
### New Build System (currently for `GOOS == "linux"`)
The new build system uses a Docker container to generate the go files directly
from source checkouts of the kernel and various system libraries. This means
that on any platform that supports Docker, all the files using the new build
system can be generated at once, and generated files will not change based on
what the person running the scripts has installed on their computer.
The OS specific files for the new build system are located in the `${GOOS}`
directory, and the build is coordinated by the `${GOOS}/mkall.go` program. When
the kernel or system library updates, modify the Dockerfile at
`${GOOS}/Dockerfile` to checkout the new release of the source.
To build all the files under the new build system, you must be on an amd64/Linux
system and have your GOOS and GOARCH set accordingly. Running `mkall.sh` will
then generate all of the files for all of the GOOS/GOARCH pairs in the new build
system. Running `mkall.sh -n` shows the commands that will be run.
Requirements: bash, go, docker
## Component files
This section describes the various files used in the code generation process.
It also contains instructions on how to modify these files to add a new
architecture/OS or to add additional syscalls, types, or constants. Note that
if you are using the new build system, the scripts/programs cannot be called normally.
They must be called from within the docker container.
### asm files
The hand-written assembly file at `asm_${GOOS}_${GOARCH}.s` implements system
call dispatch. There are three entry points:
```
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
```
The first and second are the standard ones; they differ only in how many
arguments can be passed to the kernel. The third is for low-level use by the
ForkExec wrapper. Unlike the first two, it does not call into the scheduler to
let it know that a system call is running.
When porting Go to a new architecture/OS, this file must be implemented for
each GOOS/GOARCH pair.
### mksysnum
Mksysnum is a Go program located at `${GOOS}/mksysnum.go` (or `mksysnum_${GOOS}.go`
for the old system). This program takes in a list of header files containing the
syscall number declarations and parses them to produce the corresponding list of
Go numeric constants. See `zsysnum_${GOOS}_${GOARCH}.go` for the generated
constants.
Adding new syscall numbers is mostly done by running the build on a sufficiently
new installation of the target OS (or updating the source checkouts for the
new build system). However, depending on the OS, you may need to update the
parsing in mksysnum.
### mksyscall.go
The `syscall.go`, `syscall_${GOOS}.go`, `syscall_${GOOS}_${GOARCH}.go` are
hand-written Go files which implement system calls (for unix, the specific OS,
or the specific OS/Architecture pair respectively) that need special handling
and list `//sys` comments giving prototypes for ones that can be generated.
The mksyscall.go program takes the `//sys` and `//sysnb` comments and converts
them into syscalls. This requires the name of the prototype in the comment to
match a syscall number in the `zsysnum_${GOOS}_${GOARCH}.go` file. The function
prototype can be exported (capitalized) or not.
Adding a new syscall often just requires adding a new `//sys` function prototype
with the desired arguments and a capitalized name so it is exported. However, if
you want the interface to the syscall to be different, often one will make an
unexported `//sys` prototype, and then write a custom wrapper in
`syscall_${GOOS}.go`.
### types files
For each OS, there is a hand-written Go file at `${GOOS}/types.go` (or
`types_${GOOS}.go` on the old system). This file includes standard C headers and
creates Go type aliases to the corresponding C types. The file is then fed
through godef to get the Go compatible definitions. Finally, the generated code
is fed though mkpost.go to format the code correctly and remove any hidden or
private identifiers. This cleaned-up code is written to
`ztypes_${GOOS}_${GOARCH}.go`.
The hardest part about preparing this file is figuring out which headers to
include and which symbols need to be `#define`d to get the actual data
structures that pass through to the kernel system calls. Some C libraries
preset alternate versions for binary compatibility and translate them on the
way in and out of system calls, but there is almost always a `#define` that can
get the real ones.
See `types_darwin.go` and `linux/types.go` for examples.
To add a new type, add in the necessary include statement at the top of the
file (if it is not already there) and add in a type alias line. Note that if
your type is significantly different on different architectures, you may need
some `#if/#elif` macros in your include statements.
### mkerrors.sh
This script is used to generate the system's various constants. This doesn't
just include the error numbers and error strings, but also the signal numbers
and a wide variety of miscellaneous constants. The constants come from the list
of include files in the `includes_${uname}` variable. A regex then picks out
the desired `#define` statements, and generates the corresponding Go constants.
The error numbers and strings are generated from `#include `, and the
signal numbers and strings are generated from `#include `. All of
these constants are written to `zerrors_${GOOS}_${GOARCH}.go` via a C program,
`_errors.c`, which prints out all the constants.
To add a constant, add the header that includes it to the appropriate variable.
Then, edit the regex (if necessary) to match the desired constant. Avoid making
the regex too broad to avoid matching unintended constants.
### internal/mkmerge
This program is used to extract duplicate const, func, and type declarations
from the generated architecture-specific files listed below, and merge these
into a common file for each OS.
The merge is performed in the following steps:
1. Construct the set of common code that is identical in all architecture-specific files.
2. Write this common code to the merged file.
3. Remove the common code from all architecture-specific files.
## Generated files
### `zerrors_${GOOS}_${GOARCH}.go`
A file containing all of the system's generated error numbers, error strings,
signal numbers, and constants. Generated by `mkerrors.sh` (see above).
### `zsyscall_${GOOS}_${GOARCH}.go`
A file containing all the generated syscalls for a specific GOOS and GOARCH.
Generated by `mksyscall.go` (see above).
### `zsysnum_${GOOS}_${GOARCH}.go`
A list of numeric constants for all the syscall number of the specific GOOS
and GOARCH. Generated by mksysnum (see above).
### `ztypes_${GOOS}_${GOARCH}.go`
A file containing Go types for passing into (or returning from) syscalls.
Generated by godefs and the types file (see above).
================================================
FILE: vendor/golang.org/x/sys/unix/affinity_linux.go
================================================
// Copyright 2018 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.
// CPU affinity functions
package unix
import (
"math/bits"
"unsafe"
)
const cpuSetSize = _CPU_SETSIZE / _NCPUBITS
// CPUSet represents a CPU affinity mask.
type CPUSet [cpuSetSize]cpuMask
func schedAffinity(trap uintptr, pid int, set *CPUSet) error {
_, _, e := RawSyscall(trap, uintptr(pid), uintptr(unsafe.Sizeof(*set)), uintptr(unsafe.Pointer(set)))
if e != 0 {
return errnoErr(e)
}
return nil
}
// SchedGetaffinity gets the CPU affinity mask of the thread specified by pid.
// If pid is 0 the calling thread is used.
func SchedGetaffinity(pid int, set *CPUSet) error {
return schedAffinity(SYS_SCHED_GETAFFINITY, pid, set)
}
// SchedSetaffinity sets the CPU affinity mask of the thread specified by pid.
// If pid is 0 the calling thread is used.
func SchedSetaffinity(pid int, set *CPUSet) error {
return schedAffinity(SYS_SCHED_SETAFFINITY, pid, set)
}
// Zero clears the set s, so that it contains no CPUs.
func (s *CPUSet) Zero() {
clear(s[:])
}
// Fill adds all possible CPU bits to the set s. On Linux, [SchedSetaffinity]
// will silently ignore any invalid CPU bits in [CPUSet] so this is an
// efficient way of resetting the CPU affinity of a process.
func (s *CPUSet) Fill() {
for i := range s {
s[i] = ^cpuMask(0)
}
}
func cpuBitsIndex(cpu int) int {
return cpu / _NCPUBITS
}
func cpuBitsMask(cpu int) cpuMask {
return cpuMask(1 << (uint(cpu) % _NCPUBITS))
}
// Set adds cpu to the set s.
func (s *CPUSet) Set(cpu int) {
i := cpuBitsIndex(cpu)
if i < len(s) {
s[i] |= cpuBitsMask(cpu)
}
}
// Clear removes cpu from the set s.
func (s *CPUSet) Clear(cpu int) {
i := cpuBitsIndex(cpu)
if i < len(s) {
s[i] &^= cpuBitsMask(cpu)
}
}
// IsSet reports whether cpu is in the set s.
func (s *CPUSet) IsSet(cpu int) bool {
i := cpuBitsIndex(cpu)
if i < len(s) {
return s[i]&cpuBitsMask(cpu) != 0
}
return false
}
// Count returns the number of CPUs in the set s.
func (s *CPUSet) Count() int {
c := 0
for _, b := range s {
c += bits.OnesCount64(uint64(b))
}
return c
}
================================================
FILE: vendor/golang.org/x/sys/unix/aliases.go
================================================
// Copyright 2018 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.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package unix
import "syscall"
type Signal = syscall.Signal
type Errno = syscall.Errno
type SysProcAttr = syscall.SysProcAttr
================================================
FILE: vendor/golang.org/x/sys/unix/asm_aix_ppc64.s
================================================
// Copyright 2018 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.
//go:build gc
#include "textflag.h"
//
// System calls for ppc64, AIX are implemented in runtime/syscall_aix.go
//
TEXT ·syscall6(SB),NOSPLIT,$0-88
JMP syscall·syscall6(SB)
TEXT ·rawSyscall6(SB),NOSPLIT,$0-88
JMP syscall·rawSyscall6(SB)
================================================
FILE: vendor/golang.org/x/sys/unix/asm_bsd_386.s
================================================
// Copyright 2021 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.
//go:build (freebsd || netbsd || openbsd) && gc
#include "textflag.h"
// System call support for 386 BSD
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-52
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)
================================================
FILE: vendor/golang.org/x/sys/unix/asm_bsd_amd64.s
================================================
// Copyright 2021 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.
//go:build (darwin || dragonfly || freebsd || netbsd || openbsd) && gc
#include "textflag.h"
// System call support for AMD64 BSD
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
================================================
FILE: vendor/golang.org/x/sys/unix/asm_bsd_arm.s
================================================
// Copyright 2021 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.
//go:build (freebsd || netbsd || openbsd) && gc
#include "textflag.h"
// System call support for ARM BSD
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
B syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
B syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-52
B syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
B syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
B syscall·RawSyscall6(SB)
================================================
FILE: vendor/golang.org/x/sys/unix/asm_bsd_arm64.s
================================================
// Copyright 2021 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.
//go:build (darwin || freebsd || netbsd || openbsd) && gc
#include "textflag.h"
// System call support for ARM64 BSD
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
================================================
FILE: vendor/golang.org/x/sys/unix/asm_bsd_ppc64.s
================================================
// Copyright 2022 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.
//go:build (darwin || freebsd || netbsd || openbsd) && gc
#include "textflag.h"
//
// System call support for ppc64, BSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
================================================
FILE: vendor/golang.org/x/sys/unix/asm_bsd_riscv64.s
================================================
// Copyright 2021 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.
//go:build (darwin || freebsd || netbsd || openbsd) && gc
#include "textflag.h"
// System call support for RISCV64 BSD
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
================================================
FILE: vendor/golang.org/x/sys/unix/asm_linux_386.s
================================================
// Copyright 2009 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.
//go:build gc
#include "textflag.h"
//
// System calls for 386, Linux
//
// See ../runtime/sys_linux_386.s for the reason why we always use int 0x80
// instead of the glibc-specific "CALL 0x10(GS)".
#define INVOKE_SYSCALL INT $0x80
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
JMP syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
CALL runtime·entersyscall(SB)
MOVL trap+0(FP), AX // syscall entry
MOVL a1+4(FP), BX
MOVL a2+8(FP), CX
MOVL a3+12(FP), DX
MOVL $0, SI
MOVL $0, DI
INVOKE_SYSCALL
MOVL AX, r1+16(FP)
MOVL DX, r2+20(FP)
CALL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
MOVL trap+0(FP), AX // syscall entry
MOVL a1+4(FP), BX
MOVL a2+8(FP), CX
MOVL a3+12(FP), DX
MOVL $0, SI
MOVL $0, DI
INVOKE_SYSCALL
MOVL AX, r1+16(FP)
MOVL DX, r2+20(FP)
RET
TEXT ·socketcall(SB),NOSPLIT,$0-36
JMP syscall·socketcall(SB)
TEXT ·rawsocketcall(SB),NOSPLIT,$0-36
JMP syscall·rawsocketcall(SB)
TEXT ·seek(SB),NOSPLIT,$0-28
JMP syscall·seek(SB)
================================================
FILE: vendor/golang.org/x/sys/unix/asm_linux_amd64.s
================================================
// Copyright 2009 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.
//go:build gc
#include "textflag.h"
//
// System calls for AMD64, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
CALL runtime·entersyscall(SB)
MOVQ a1+8(FP), DI
MOVQ a2+16(FP), SI
MOVQ a3+24(FP), DX
MOVQ $0, R10
MOVQ $0, R8
MOVQ $0, R9
MOVQ trap+0(FP), AX // syscall entry
SYSCALL
MOVQ AX, r1+32(FP)
MOVQ DX, r2+40(FP)
CALL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOVQ a1+8(FP), DI
MOVQ a2+16(FP), SI
MOVQ a3+24(FP), DX
MOVQ $0, R10
MOVQ $0, R8
MOVQ $0, R9
MOVQ trap+0(FP), AX // syscall entry
SYSCALL
MOVQ AX, r1+32(FP)
MOVQ DX, r2+40(FP)
RET
TEXT ·gettimeofday(SB),NOSPLIT,$0-16
JMP syscall·gettimeofday(SB)
================================================
FILE: vendor/golang.org/x/sys/unix/asm_linux_arm.s
================================================
// Copyright 2009 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.
//go:build gc
#include "textflag.h"
//
// System calls for arm, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
B syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
B syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
BL runtime·entersyscall(SB)
MOVW trap+0(FP), R7
MOVW a1+4(FP), R0
MOVW a2+8(FP), R1
MOVW a3+12(FP), R2
MOVW $0, R3
MOVW $0, R4
MOVW $0, R5
SWI $0
MOVW R0, r1+16(FP)
MOVW $0, R0
MOVW R0, r2+20(FP)
BL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
B syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
B syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
MOVW trap+0(FP), R7 // syscall entry
MOVW a1+4(FP), R0
MOVW a2+8(FP), R1
MOVW a3+12(FP), R2
SWI $0
MOVW R0, r1+16(FP)
MOVW $0, R0
MOVW R0, r2+20(FP)
RET
TEXT ·seek(SB),NOSPLIT,$0-28
B syscall·seek(SB)
================================================
FILE: vendor/golang.org/x/sys/unix/asm_linux_arm64.s
================================================
// Copyright 2015 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.
//go:build linux && arm64 && gc
#include "textflag.h"
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
B syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
B syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
BL runtime·entersyscall(SB)
MOVD a1+8(FP), R0
MOVD a2+16(FP), R1
MOVD a3+24(FP), R2
MOVD $0, R3
MOVD $0, R4
MOVD $0, R5
MOVD trap+0(FP), R8 // syscall entry
SVC
MOVD R0, r1+32(FP) // r1
MOVD R1, r2+40(FP) // r2
BL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
B syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
B syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOVD a1+8(FP), R0
MOVD a2+16(FP), R1
MOVD a3+24(FP), R2
MOVD $0, R3
MOVD $0, R4
MOVD $0, R5
MOVD trap+0(FP), R8 // syscall entry
SVC
MOVD R0, r1+32(FP)
MOVD R1, r2+40(FP)
RET
================================================
FILE: vendor/golang.org/x/sys/unix/asm_linux_loong64.s
================================================
// Copyright 2022 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.
//go:build linux && loong64 && gc
#include "textflag.h"
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
JAL runtime·entersyscall(SB)
MOVV a1+8(FP), R4
MOVV a2+16(FP), R5
MOVV a3+24(FP), R6
MOVV R0, R7
MOVV R0, R8
MOVV R0, R9
MOVV trap+0(FP), R11 // syscall entry
SYSCALL
MOVV R4, r1+32(FP)
MOVV R0, r2+40(FP) // r2 is not used. Always set to 0
JAL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOVV a1+8(FP), R4
MOVV a2+16(FP), R5
MOVV a3+24(FP), R6
MOVV R0, R7
MOVV R0, R8
MOVV R0, R9
MOVV trap+0(FP), R11 // syscall entry
SYSCALL
MOVV R4, r1+32(FP)
MOVV R0, r2+40(FP) // r2 is not used. Always set to 0
RET
================================================
FILE: vendor/golang.org/x/sys/unix/asm_linux_mips64x.s
================================================
// Copyright 2015 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.
//go:build linux && (mips64 || mips64le) && gc
#include "textflag.h"
//
// System calls for mips64, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
JAL runtime·entersyscall(SB)
MOVV a1+8(FP), R4
MOVV a2+16(FP), R5
MOVV a3+24(FP), R6
MOVV R0, R7
MOVV R0, R8
MOVV R0, R9
MOVV trap+0(FP), R2 // syscall entry
SYSCALL
MOVV R2, r1+32(FP)
MOVV R3, r2+40(FP)
JAL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOVV a1+8(FP), R4
MOVV a2+16(FP), R5
MOVV a3+24(FP), R6
MOVV R0, R7
MOVV R0, R8
MOVV R0, R9
MOVV trap+0(FP), R2 // syscall entry
SYSCALL
MOVV R2, r1+32(FP)
MOVV R3, r2+40(FP)
RET
================================================
FILE: vendor/golang.org/x/sys/unix/asm_linux_mipsx.s
================================================
// Copyright 2016 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.
//go:build linux && (mips || mipsle) && gc
#include "textflag.h"
//
// System calls for mips, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-52
JMP syscall·Syscall9(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
JAL runtime·entersyscall(SB)
MOVW a1+4(FP), R4
MOVW a2+8(FP), R5
MOVW a3+12(FP), R6
MOVW R0, R7
MOVW trap+0(FP), R2 // syscall entry
SYSCALL
MOVW R2, r1+16(FP) // r1
MOVW R3, r2+20(FP) // r2
JAL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
MOVW a1+4(FP), R4
MOVW a2+8(FP), R5
MOVW a3+12(FP), R6
MOVW trap+0(FP), R2 // syscall entry
SYSCALL
MOVW R2, r1+16(FP)
MOVW R3, r2+20(FP)
RET
================================================
FILE: vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s
================================================
// Copyright 2014 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.
//go:build linux && (ppc64 || ppc64le) && gc
#include "textflag.h"
//
// System calls for ppc64, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
BL runtime·entersyscall(SB)
MOVD a1+8(FP), R3
MOVD a2+16(FP), R4
MOVD a3+24(FP), R5
MOVD R0, R6
MOVD R0, R7
MOVD R0, R8
MOVD trap+0(FP), R9 // syscall entry
SYSCALL R9
MOVD R3, r1+32(FP)
MOVD R4, r2+40(FP)
BL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOVD a1+8(FP), R3
MOVD a2+16(FP), R4
MOVD a3+24(FP), R5
MOVD R0, R6
MOVD R0, R7
MOVD R0, R8
MOVD trap+0(FP), R9 // syscall entry
SYSCALL R9
MOVD R3, r1+32(FP)
MOVD R4, r2+40(FP)
RET
================================================
FILE: vendor/golang.org/x/sys/unix/asm_linux_riscv64.s
================================================
// Copyright 2019 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.
//go:build riscv64 && gc
#include "textflag.h"
//
// System calls for linux/riscv64.
//
// Where available, just jump to package syscall's implementation of
// these functions.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
CALL runtime·entersyscall(SB)
MOV a1+8(FP), A0
MOV a2+16(FP), A1
MOV a3+24(FP), A2
MOV trap+0(FP), A7 // syscall entry
ECALL
MOV A0, r1+32(FP) // r1
MOV A1, r2+40(FP) // r2
CALL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOV a1+8(FP), A0
MOV a2+16(FP), A1
MOV a3+24(FP), A2
MOV trap+0(FP), A7 // syscall entry
ECALL
MOV A0, r1+32(FP)
MOV A1, r2+40(FP)
RET
================================================
FILE: vendor/golang.org/x/sys/unix/asm_linux_s390x.s
================================================
// Copyright 2016 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.
//go:build linux && s390x && gc
#include "textflag.h"
//
// System calls for s390x, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
BR syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
BR syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
BL runtime·entersyscall(SB)
MOVD a1+8(FP), R2
MOVD a2+16(FP), R3
MOVD a3+24(FP), R4
MOVD $0, R5
MOVD $0, R6
MOVD $0, R7
MOVD trap+0(FP), R1 // syscall entry
SYSCALL
MOVD R2, r1+32(FP)
MOVD R3, r2+40(FP)
BL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
BR syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
BR syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOVD a1+8(FP), R2
MOVD a2+16(FP), R3
MOVD a3+24(FP), R4
MOVD $0, R5
MOVD $0, R6
MOVD $0, R7
MOVD trap+0(FP), R1 // syscall entry
SYSCALL
MOVD R2, r1+32(FP)
MOVD R3, r2+40(FP)
RET
================================================
FILE: vendor/golang.org/x/sys/unix/asm_openbsd_mips64.s
================================================
// Copyright 2019 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.
//go:build gc
#include "textflag.h"
//
// System call support for mips64, OpenBSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
================================================
FILE: vendor/golang.org/x/sys/unix/asm_solaris_amd64.s
================================================
// Copyright 2014 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.
//go:build gc
#include "textflag.h"
//
// System calls for amd64, Solaris are implemented in runtime/syscall_solaris.go
//
TEXT ·sysvicall6(SB),NOSPLIT,$0-88
JMP syscall·sysvicall6(SB)
TEXT ·rawSysvicall6(SB),NOSPLIT,$0-88
JMP syscall·rawSysvicall6(SB)
================================================
FILE: vendor/golang.org/x/sys/unix/asm_zos_s390x.s
================================================
// Copyright 2020 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.
//go:build zos && s390x && gc
#include "textflag.h"
#define PSALAA 1208(R0)
#define GTAB64(x) 80(x)
#define LCA64(x) 88(x)
#define SAVSTACK_ASYNC(x) 336(x) // in the LCA
#define CAA(x) 8(x)
#define CEECAATHDID(x) 976(x) // in the CAA
#define EDCHPXV(x) 1016(x) // in the CAA
#define GOCB(x) 1104(x) // in the CAA
// SS_*, where x=SAVSTACK_ASYNC
#define SS_LE(x) 0(x)
#define SS_GO(x) 8(x)
#define SS_ERRNO(x) 16(x)
#define SS_ERRNOJR(x) 20(x)
// Function Descriptor Offsets
#define __errno 0x156*16
#define __err2ad 0x16C*16
// Call Instructions
#define LE_CALL BYTE $0x0D; BYTE $0x76 // BL R7, R6
#define SVC_LOAD BYTE $0x0A; BYTE $0x08 // SVC 08 LOAD
#define SVC_DELETE BYTE $0x0A; BYTE $0x09 // SVC 09 DELETE
DATA zosLibVec<>(SB)/8, $0
GLOBL zosLibVec<>(SB), NOPTR, $8
TEXT ·initZosLibVec(SB), NOSPLIT|NOFRAME, $0-0
MOVW PSALAA, R8
MOVD LCA64(R8), R8
MOVD CAA(R8), R8
MOVD EDCHPXV(R8), R8
MOVD R8, zosLibVec<>(SB)
RET
TEXT ·GetZosLibVec(SB), NOSPLIT|NOFRAME, $0-0
MOVD zosLibVec<>(SB), R8
MOVD R8, ret+0(FP)
RET
TEXT ·clearErrno(SB), NOSPLIT, $0-0
BL addrerrno<>(SB)
MOVD $0, 0(R3)
RET
// Returns the address of errno in R3.
TEXT addrerrno<>(SB), NOSPLIT|NOFRAME, $0-0
// Get library control area (LCA).
MOVW PSALAA, R8
MOVD LCA64(R8), R8
// Get __errno FuncDesc.
MOVD CAA(R8), R9
MOVD EDCHPXV(R9), R9
ADD $(__errno), R9
LMG 0(R9), R5, R6
// Switch to saved LE stack.
MOVD SAVSTACK_ASYNC(R8), R9
MOVD 0(R9), R4
MOVD $0, 0(R9)
// Call __errno function.
LE_CALL
NOPH
// Switch back to Go stack.
XOR R0, R0 // Restore R0 to $0.
MOVD R4, 0(R9) // Save stack pointer.
RET
// func svcCall(fnptr unsafe.Pointer, argv *unsafe.Pointer, dsa *uint64)
TEXT ·svcCall(SB), NOSPLIT, $0
BL runtime·save_g(SB) // Save g and stack pointer
MOVW PSALAA, R8
MOVD LCA64(R8), R8
MOVD SAVSTACK_ASYNC(R8), R9
MOVD R15, 0(R9)
MOVD argv+8(FP), R1 // Move function arguments into registers
MOVD dsa+16(FP), g
MOVD fnptr+0(FP), R15
BYTE $0x0D // Branch to function
BYTE $0xEF
BL runtime·load_g(SB) // Restore g and stack pointer
MOVW PSALAA, R8
MOVD LCA64(R8), R8
MOVD SAVSTACK_ASYNC(R8), R9
MOVD 0(R9), R15
RET
// func svcLoad(name *byte) unsafe.Pointer
TEXT ·svcLoad(SB), NOSPLIT, $0
MOVD R15, R2 // Save go stack pointer
MOVD name+0(FP), R0 // Move SVC args into registers
MOVD $0x80000000, R1
MOVD $0, R15
SVC_LOAD
MOVW R15, R3 // Save return code from SVC
MOVD R2, R15 // Restore go stack pointer
CMP R3, $0 // Check SVC return code
BNE error
MOVD $-2, R3 // Reset last bit of entry point to zero
AND R0, R3
MOVD R3, ret+8(FP) // Return entry point returned by SVC
CMP R0, R3 // Check if last bit of entry point was set
BNE done
MOVD R15, R2 // Save go stack pointer
MOVD $0, R15 // Move SVC args into registers (entry point still in r0 from SVC 08)
SVC_DELETE
MOVD R2, R15 // Restore go stack pointer
error:
MOVD $0, ret+8(FP) // Return 0 on failure
done:
XOR R0, R0 // Reset r0 to 0
RET
// func svcUnload(name *byte, fnptr unsafe.Pointer) int64
TEXT ·svcUnload(SB), NOSPLIT, $0
MOVD R15, R2 // Save go stack pointer
MOVD name+0(FP), R0 // Move SVC args into registers
MOVD fnptr+8(FP), R15
SVC_DELETE
XOR R0, R0 // Reset r0 to 0
MOVD R15, R1 // Save SVC return code
MOVD R2, R15 // Restore go stack pointer
MOVD R1, ret+16(FP) // Return SVC return code
RET
// func gettid() uint64
TEXT ·gettid(SB), NOSPLIT, $0
// Get library control area (LCA).
MOVW PSALAA, R8
MOVD LCA64(R8), R8
// Get CEECAATHDID
MOVD CAA(R8), R9
MOVD CEECAATHDID(R9), R9
MOVD R9, ret+0(FP)
RET
//
// Call LE function, if the return is -1
// errno and errno2 is retrieved
//
TEXT ·CallLeFuncWithErr(SB), NOSPLIT, $0
MOVW PSALAA, R8
MOVD LCA64(R8), R8
MOVD CAA(R8), R9
MOVD g, GOCB(R9)
// Restore LE stack.
MOVD SAVSTACK_ASYNC(R8), R9 // R9-> LE stack frame saving address
MOVD 0(R9), R4 // R4-> restore previously saved stack frame pointer
MOVD parms_base+8(FP), R7 // R7 -> argument array
MOVD parms_len+16(FP), R8 // R8 number of arguments
// arg 1 ---> R1
CMP R8, $0
BEQ docall
SUB $1, R8
MOVD 0(R7), R1
// arg 2 ---> R2
CMP R8, $0
BEQ docall
SUB $1, R8
ADD $8, R7
MOVD 0(R7), R2
// arg 3 --> R3
CMP R8, $0
BEQ docall
SUB $1, R8
ADD $8, R7
MOVD 0(R7), R3
CMP R8, $0
BEQ docall
MOVD $2176+16, R6 // starting LE stack address-8 to store 4th argument
repeat:
ADD $8, R7
MOVD 0(R7), R0 // advance arg pointer by 8 byte
ADD $8, R6 // advance LE argument address by 8 byte
MOVD R0, (R4)(R6*1) // copy argument from go-slice to le-frame
SUB $1, R8
CMP R8, $0
BNE repeat
docall:
MOVD funcdesc+0(FP), R8 // R8-> function descriptor
LMG 0(R8), R5, R6
MOVD $0, 0(R9) // R9 address of SAVSTACK_ASYNC
LE_CALL // balr R7, R6 (return #1)
NOPH
MOVD R3, ret+32(FP)
CMP R3, $-1 // compare result to -1
BNE done
// retrieve errno and errno2
MOVD zosLibVec<>(SB), R8
ADD $(__errno), R8
LMG 0(R8), R5, R6
LE_CALL // balr R7, R6 __errno (return #3)
NOPH
MOVWZ 0(R3), R3
MOVD R3, err+48(FP)
MOVD zosLibVec<>(SB), R8
ADD $(__err2ad), R8
LMG 0(R8), R5, R6
LE_CALL // balr R7, R6 __err2ad (return #2)
NOPH
MOVW (R3), R2 // retrieve errno2
MOVD R2, errno2+40(FP) // store in return area
done:
MOVD R4, 0(R9) // Save stack pointer.
RET
//
// Call LE function, if the return is 0
// errno and errno2 is retrieved
//
TEXT ·CallLeFuncWithPtrReturn(SB), NOSPLIT, $0
MOVW PSALAA, R8
MOVD LCA64(R8), R8
MOVD CAA(R8), R9
MOVD g, GOCB(R9)
// Restore LE stack.
MOVD SAVSTACK_ASYNC(R8), R9 // R9-> LE stack frame saving address
MOVD 0(R9), R4 // R4-> restore previously saved stack frame pointer
MOVD parms_base+8(FP), R7 // R7 -> argument array
MOVD parms_len+16(FP), R8 // R8 number of arguments
// arg 1 ---> R1
CMP R8, $0
BEQ docall
SUB $1, R8
MOVD 0(R7), R1
// arg 2 ---> R2
CMP R8, $0
BEQ docall
SUB $1, R8
ADD $8, R7
MOVD 0(R7), R2
// arg 3 --> R3
CMP R8, $0
BEQ docall
SUB $1, R8
ADD $8, R7
MOVD 0(R7), R3
CMP R8, $0
BEQ docall
MOVD $2176+16, R6 // starting LE stack address-8 to store 4th argument
repeat:
ADD $8, R7
MOVD 0(R7), R0 // advance arg pointer by 8 byte
ADD $8, R6 // advance LE argument address by 8 byte
MOVD R0, (R4)(R6*1) // copy argument from go-slice to le-frame
SUB $1, R8
CMP R8, $0
BNE repeat
docall:
MOVD funcdesc+0(FP), R8 // R8-> function descriptor
LMG 0(R8), R5, R6
MOVD $0, 0(R9) // R9 address of SAVSTACK_ASYNC
LE_CALL // balr R7, R6 (return #1)
NOPH
MOVD R3, ret+32(FP)
CMP R3, $0 // compare result to 0
BNE done
// retrieve errno and errno2
MOVD zosLibVec<>(SB), R8
ADD $(__errno), R8
LMG 0(R8), R5, R6
LE_CALL // balr R7, R6 __errno (return #3)
NOPH
MOVWZ 0(R3), R3
MOVD R3, err+48(FP)
MOVD zosLibVec<>(SB), R8
ADD $(__err2ad), R8
LMG 0(R8), R5, R6
LE_CALL // balr R7, R6 __err2ad (return #2)
NOPH
MOVW (R3), R2 // retrieve errno2
MOVD R2, errno2+40(FP) // store in return area
XOR R2, R2
MOVWZ R2, (R3) // clear errno2
done:
MOVD R4, 0(R9) // Save stack pointer.
RET
//
// function to test if a pointer can be safely dereferenced (content read)
// return 0 for succces
//
TEXT ·ptrtest(SB), NOSPLIT, $0-16
MOVD arg+0(FP), R10 // test pointer in R10
// set up R2 to point to CEECAADMC
BYTE $0xE3; BYTE $0x20; BYTE $0x04; BYTE $0xB8; BYTE $0x00; BYTE $0x17 // llgt 2,1208
BYTE $0xB9; BYTE $0x17; BYTE $0x00; BYTE $0x22 // llgtr 2,2
BYTE $0xA5; BYTE $0x26; BYTE $0x7F; BYTE $0xFF // nilh 2,32767
BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x58; BYTE $0x00; BYTE $0x04 // lg 2,88(2)
BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x08; BYTE $0x00; BYTE $0x04 // lg 2,8(2)
BYTE $0x41; BYTE $0x22; BYTE $0x03; BYTE $0x68 // la 2,872(2)
// set up R5 to point to the "shunt" path which set 1 to R3 (failure)
BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x33 // xgr 3,3
BYTE $0xA7; BYTE $0x55; BYTE $0x00; BYTE $0x04 // bras 5,lbl1
BYTE $0xA7; BYTE $0x39; BYTE $0x00; BYTE $0x01 // lghi 3,1
// if r3 is not zero (failed) then branch to finish
BYTE $0xB9; BYTE $0x02; BYTE $0x00; BYTE $0x33 // lbl1 ltgr 3,3
BYTE $0xA7; BYTE $0x74; BYTE $0x00; BYTE $0x08 // brc b'0111',lbl2
// stomic store shunt address in R5 into CEECAADMC
BYTE $0xE3; BYTE $0x52; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 5,0(2)
// now try reading from the test pointer in R10, if it fails it branches to the "lghi" instruction above
BYTE $0xE3; BYTE $0x9A; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x04 // lg 9,0(10)
// finish here, restore 0 into CEECAADMC
BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x99 // lbl2 xgr 9,9
BYTE $0xE3; BYTE $0x92; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 9,0(2)
MOVD R3, ret+8(FP) // result in R3
RET
//
// function to test if a untptr can be loaded from a pointer
// return 1: the 8-byte content
// 2: 0 for success, 1 for failure
//
// func safeload(ptr uintptr) ( value uintptr, error uintptr)
TEXT ·safeload(SB), NOSPLIT, $0-24
MOVD ptr+0(FP), R10 // test pointer in R10
MOVD $0x0, R6
BYTE $0xE3; BYTE $0x20; BYTE $0x04; BYTE $0xB8; BYTE $0x00; BYTE $0x17 // llgt 2,1208
BYTE $0xB9; BYTE $0x17; BYTE $0x00; BYTE $0x22 // llgtr 2,2
BYTE $0xA5; BYTE $0x26; BYTE $0x7F; BYTE $0xFF // nilh 2,32767
BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x58; BYTE $0x00; BYTE $0x04 // lg 2,88(2)
BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x08; BYTE $0x00; BYTE $0x04 // lg 2,8(2)
BYTE $0x41; BYTE $0x22; BYTE $0x03; BYTE $0x68 // la 2,872(2)
BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x33 // xgr 3,3
BYTE $0xA7; BYTE $0x55; BYTE $0x00; BYTE $0x04 // bras 5,lbl1
BYTE $0xA7; BYTE $0x39; BYTE $0x00; BYTE $0x01 // lghi 3,1
BYTE $0xB9; BYTE $0x02; BYTE $0x00; BYTE $0x33 // lbl1 ltgr 3,3
BYTE $0xA7; BYTE $0x74; BYTE $0x00; BYTE $0x08 // brc b'0111',lbl2
BYTE $0xE3; BYTE $0x52; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 5,0(2)
BYTE $0xE3; BYTE $0x6A; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x04 // lg 6,0(10)
BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x99 // lbl2 xgr 9,9
BYTE $0xE3; BYTE $0x92; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 9,0(2)
MOVD R6, value+8(FP) // result in R6
MOVD R3, error+16(FP) // error in R3
RET
================================================
FILE: vendor/golang.org/x/sys/unix/auxv.go
================================================
// Copyright 2025 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.
//go:build go1.21 && (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos)
package unix
import (
"syscall"
"unsafe"
)
//go:linkname runtime_getAuxv runtime.getAuxv
func runtime_getAuxv() []uintptr
// Auxv returns the ELF auxiliary vector as a sequence of key/value pairs.
// The returned slice is always a fresh copy, owned by the caller.
// It returns an error on non-ELF platforms, or if the auxiliary vector cannot be accessed,
// which happens in some locked-down environments and build modes.
func Auxv() ([][2]uintptr, error) {
vec := runtime_getAuxv()
vecLen := len(vec)
if vecLen == 0 {
return nil, syscall.ENOENT
}
if vecLen%2 != 0 {
return nil, syscall.EINVAL
}
result := make([]uintptr, vecLen)
copy(result, vec)
return unsafe.Slice((*[2]uintptr)(unsafe.Pointer(&result[0])), vecLen/2), nil
}
================================================
FILE: vendor/golang.org/x/sys/unix/auxv_unsupported.go
================================================
// Copyright 2025 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.
//go:build !go1.21 && (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos)
package unix
import "syscall"
func Auxv() ([][2]uintptr, error) {
return nil, syscall.ENOTSUP
}
================================================
FILE: vendor/golang.org/x/sys/unix/bluetooth_linux.go
================================================
// Copyright 2016 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.
// Bluetooth sockets and messages
package unix
// Bluetooth Protocols
const (
BTPROTO_L2CAP = 0
BTPROTO_HCI = 1
BTPROTO_SCO = 2
BTPROTO_RFCOMM = 3
BTPROTO_BNEP = 4
BTPROTO_CMTP = 5
BTPROTO_HIDP = 6
BTPROTO_AVDTP = 7
)
const (
HCI_CHANNEL_RAW = 0
HCI_CHANNEL_USER = 1
HCI_CHANNEL_MONITOR = 2
HCI_CHANNEL_CONTROL = 3
HCI_CHANNEL_LOGGING = 4
)
// Socketoption Level
const (
SOL_BLUETOOTH = 0x112
SOL_HCI = 0x0
SOL_L2CAP = 0x6
SOL_RFCOMM = 0x12
SOL_SCO = 0x11
)
================================================
FILE: vendor/golang.org/x/sys/unix/bpxsvc_zos.go
================================================
// Copyright 2024 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.
//go:build zos
package unix
import (
"bytes"
"fmt"
"unsafe"
)
//go:noescape
func bpxcall(plist []unsafe.Pointer, bpx_offset int64)
//go:noescape
func A2e([]byte)
//go:noescape
func E2a([]byte)
const (
BPX4STA = 192 // stat
BPX4FST = 104 // fstat
BPX4LST = 132 // lstat
BPX4OPN = 156 // open
BPX4CLO = 72 // close
BPX4CHR = 500 // chattr
BPX4FCR = 504 // fchattr
BPX4LCR = 1180 // lchattr
BPX4CTW = 492 // cond_timed_wait
BPX4GTH = 1056 // __getthent
BPX4PTQ = 412 // pthread_quiesc
BPX4PTR = 320 // ptrace
)
const (
//options
//byte1
BPX_OPNFHIGH = 0x80
//byte2
BPX_OPNFEXEC = 0x80
//byte3
BPX_O_NOLARGEFILE = 0x08
BPX_O_LARGEFILE = 0x04
BPX_O_ASYNCSIG = 0x02
BPX_O_SYNC = 0x01
//byte4
BPX_O_CREXCL = 0xc0
BPX_O_CREAT = 0x80
BPX_O_EXCL = 0x40
BPX_O_NOCTTY = 0x20
BPX_O_TRUNC = 0x10
BPX_O_APPEND = 0x08
BPX_O_NONBLOCK = 0x04
BPX_FNDELAY = 0x04
BPX_O_RDWR = 0x03
BPX_O_RDONLY = 0x02
BPX_O_WRONLY = 0x01
BPX_O_ACCMODE = 0x03
BPX_O_GETFL = 0x0f
//mode
// byte1 (file type)
BPX_FT_DIR = 1
BPX_FT_CHARSPEC = 2
BPX_FT_REGFILE = 3
BPX_FT_FIFO = 4
BPX_FT_SYMLINK = 5
BPX_FT_SOCKET = 6
//byte3
BPX_S_ISUID = 0x08
BPX_S_ISGID = 0x04
BPX_S_ISVTX = 0x02
BPX_S_IRWXU1 = 0x01
BPX_S_IRUSR = 0x01
//byte4
BPX_S_IRWXU2 = 0xc0
BPX_S_IWUSR = 0x80
BPX_S_IXUSR = 0x40
BPX_S_IRWXG = 0x38
BPX_S_IRGRP = 0x20
BPX_S_IWGRP = 0x10
BPX_S_IXGRP = 0x08
BPX_S_IRWXOX = 0x07
BPX_S_IROTH = 0x04
BPX_S_IWOTH = 0x02
BPX_S_IXOTH = 0x01
CW_INTRPT = 1
CW_CONDVAR = 32
CW_TIMEOUT = 64
PGTHA_NEXT = 2
PGTHA_CURRENT = 1
PGTHA_FIRST = 0
PGTHA_LAST = 3
PGTHA_PROCESS = 0x80
PGTHA_CONTTY = 0x40
PGTHA_PATH = 0x20
PGTHA_COMMAND = 0x10
PGTHA_FILEDATA = 0x08
PGTHA_THREAD = 0x04
PGTHA_PTAG = 0x02
PGTHA_COMMANDLONG = 0x01
PGTHA_THREADFAST = 0x80
PGTHA_FILEPATH = 0x40
PGTHA_THDSIGMASK = 0x20
// thread quiece mode
QUIESCE_TERM int32 = 1
QUIESCE_FORCE int32 = 2
QUIESCE_QUERY int32 = 3
QUIESCE_FREEZE int32 = 4
QUIESCE_UNFREEZE int32 = 5
FREEZE_THIS_THREAD int32 = 6
FREEZE_EXIT int32 = 8
QUIESCE_SRB int32 = 9
)
type Pgtha struct {
Pid uint32 // 0
Tid0 uint32 // 4
Tid1 uint32
Accesspid byte // C
Accesstid byte // D
Accessasid uint16 // E
Loginname [8]byte // 10
Flag1 byte // 18
Flag1b2 byte // 19
}
type Bpxystat_t struct { // DSECT BPXYSTAT
St_id [4]uint8 // 0
St_length uint16 // 0x4
St_version uint16 // 0x6
St_mode uint32 // 0x8
St_ino uint32 // 0xc
St_dev uint32 // 0x10
St_nlink uint32 // 0x14
St_uid uint32 // 0x18
St_gid uint32 // 0x1c
St_size uint64 // 0x20
St_atime uint32 // 0x28
St_mtime uint32 // 0x2c
St_ctime uint32 // 0x30
St_rdev uint32 // 0x34
St_auditoraudit uint32 // 0x38
St_useraudit uint32 // 0x3c
St_blksize uint32 // 0x40
St_createtime uint32 // 0x44
St_auditid [4]uint32 // 0x48
St_res01 uint32 // 0x58
Ft_ccsid uint16 // 0x5c
Ft_flags uint16 // 0x5e
St_res01a [2]uint32 // 0x60
St_res02 uint32 // 0x68
St_blocks uint32 // 0x6c
St_opaque [3]uint8 // 0x70
St_visible uint8 // 0x73
St_reftime uint32 // 0x74
St_fid uint64 // 0x78
St_filefmt uint8 // 0x80
St_fspflag2 uint8 // 0x81
St_res03 [2]uint8 // 0x82
St_ctimemsec uint32 // 0x84
St_seclabel [8]uint8 // 0x88
St_res04 [4]uint8 // 0x90
// end of version 1
_ uint32 // 0x94
St_atime64 uint64 // 0x98
St_mtime64 uint64 // 0xa0
St_ctime64 uint64 // 0xa8
St_createtime64 uint64 // 0xb0
St_reftime64 uint64 // 0xb8
_ uint64 // 0xc0
St_res05 [16]uint8 // 0xc8
// end of version 2
}
type BpxFilestatus struct {
Oflag1 byte
Oflag2 byte
Oflag3 byte
Oflag4 byte
}
type BpxMode struct {
Ftype byte
Mode1 byte
Mode2 byte
Mode3 byte
}
// Thr attribute structure for extended attributes
type Bpxyatt_t struct { // DSECT BPXYATT
Att_id [4]uint8
Att_version uint16
Att_res01 [2]uint8
Att_setflags1 uint8
Att_setflags2 uint8
Att_setflags3 uint8
Att_setflags4 uint8
Att_mode uint32
Att_uid uint32
Att_gid uint32
Att_opaquemask [3]uint8
Att_visblmaskres uint8
Att_opaque [3]uint8
Att_visibleres uint8
Att_size_h uint32
Att_size_l uint32
Att_atime uint32
Att_mtime uint32
Att_auditoraudit uint32
Att_useraudit uint32
Att_ctime uint32
Att_reftime uint32
// end of version 1
Att_filefmt uint8
Att_res02 [3]uint8
Att_filetag uint32
Att_res03 [8]uint8
// end of version 2
Att_atime64 uint64
Att_mtime64 uint64
Att_ctime64 uint64
Att_reftime64 uint64
Att_seclabel [8]uint8
Att_ver3res02 [8]uint8
// end of version 3
}
func BpxOpen(name string, options *BpxFilestatus, mode *BpxMode) (rv int32, rc int32, rn int32) {
if len(name) < 1024 {
var namebuf [1024]byte
sz := int32(copy(namebuf[:], name))
A2e(namebuf[:sz])
var parms [7]unsafe.Pointer
parms[0] = unsafe.Pointer(&sz)
parms[1] = unsafe.Pointer(&namebuf[0])
parms[2] = unsafe.Pointer(options)
parms[3] = unsafe.Pointer(mode)
parms[4] = unsafe.Pointer(&rv)
parms[5] = unsafe.Pointer(&rc)
parms[6] = unsafe.Pointer(&rn)
bpxcall(parms[:], BPX4OPN)
return rv, rc, rn
}
return -1, -1, -1
}
func BpxClose(fd int32) (rv int32, rc int32, rn int32) {
var parms [4]unsafe.Pointer
parms[0] = unsafe.Pointer(&fd)
parms[1] = unsafe.Pointer(&rv)
parms[2] = unsafe.Pointer(&rc)
parms[3] = unsafe.Pointer(&rn)
bpxcall(parms[:], BPX4CLO)
return rv, rc, rn
}
func BpxFileFStat(fd int32, st *Bpxystat_t) (rv int32, rc int32, rn int32) {
st.St_id = [4]uint8{0xe2, 0xe3, 0xc1, 0xe3}
st.St_version = 2
stat_sz := uint32(unsafe.Sizeof(*st))
var parms [6]unsafe.Pointer
parms[0] = unsafe.Pointer(&fd)
parms[1] = unsafe.Pointer(&stat_sz)
parms[2] = unsafe.Pointer(st)
parms[3] = unsafe.Pointer(&rv)
parms[4] = unsafe.Pointer(&rc)
parms[5] = unsafe.Pointer(&rn)
bpxcall(parms[:], BPX4FST)
return rv, rc, rn
}
func BpxFileStat(name string, st *Bpxystat_t) (rv int32, rc int32, rn int32) {
if len(name) < 1024 {
var namebuf [1024]byte
sz := int32(copy(namebuf[:], name))
A2e(namebuf[:sz])
st.St_id = [4]uint8{0xe2, 0xe3, 0xc1, 0xe3}
st.St_version = 2
stat_sz := uint32(unsafe.Sizeof(*st))
var parms [7]unsafe.Pointer
parms[0] = unsafe.Pointer(&sz)
parms[1] = unsafe.Pointer(&namebuf[0])
parms[2] = unsafe.Pointer(&stat_sz)
parms[3] = unsafe.Pointer(st)
parms[4] = unsafe.Pointer(&rv)
parms[5] = unsafe.Pointer(&rc)
parms[6] = unsafe.Pointer(&rn)
bpxcall(parms[:], BPX4STA)
return rv, rc, rn
}
return -1, -1, -1
}
func BpxFileLStat(name string, st *Bpxystat_t) (rv int32, rc int32, rn int32) {
if len(name) < 1024 {
var namebuf [1024]byte
sz := int32(copy(namebuf[:], name))
A2e(namebuf[:sz])
st.St_id = [4]uint8{0xe2, 0xe3, 0xc1, 0xe3}
st.St_version = 2
stat_sz := uint32(unsafe.Sizeof(*st))
var parms [7]unsafe.Pointer
parms[0] = unsafe.Pointer(&sz)
parms[1] = unsafe.Pointer(&namebuf[0])
parms[2] = unsafe.Pointer(&stat_sz)
parms[3] = unsafe.Pointer(st)
parms[4] = unsafe.Pointer(&rv)
parms[5] = unsafe.Pointer(&rc)
parms[6] = unsafe.Pointer(&rn)
bpxcall(parms[:], BPX4LST)
return rv, rc, rn
}
return -1, -1, -1
}
func BpxChattr(path string, attr *Bpxyatt_t) (rv int32, rc int32, rn int32) {
if len(path) >= 1024 {
return -1, -1, -1
}
var namebuf [1024]byte
sz := int32(copy(namebuf[:], path))
A2e(namebuf[:sz])
attr_sz := uint32(unsafe.Sizeof(*attr))
var parms [7]unsafe.Pointer
parms[0] = unsafe.Pointer(&sz)
parms[1] = unsafe.Pointer(&namebuf[0])
parms[2] = unsafe.Pointer(&attr_sz)
parms[3] = unsafe.Pointer(attr)
parms[4] = unsafe.Pointer(&rv)
parms[5] = unsafe.Pointer(&rc)
parms[6] = unsafe.Pointer(&rn)
bpxcall(parms[:], BPX4CHR)
return rv, rc, rn
}
func BpxLchattr(path string, attr *Bpxyatt_t) (rv int32, rc int32, rn int32) {
if len(path) >= 1024 {
return -1, -1, -1
}
var namebuf [1024]byte
sz := int32(copy(namebuf[:], path))
A2e(namebuf[:sz])
attr_sz := uint32(unsafe.Sizeof(*attr))
var parms [7]unsafe.Pointer
parms[0] = unsafe.Pointer(&sz)
parms[1] = unsafe.Pointer(&namebuf[0])
parms[2] = unsafe.Pointer(&attr_sz)
parms[3] = unsafe.Pointer(attr)
parms[4] = unsafe.Pointer(&rv)
parms[5] = unsafe.Pointer(&rc)
parms[6] = unsafe.Pointer(&rn)
bpxcall(parms[:], BPX4LCR)
return rv, rc, rn
}
func BpxFchattr(fd int32, attr *Bpxyatt_t) (rv int32, rc int32, rn int32) {
attr_sz := uint32(unsafe.Sizeof(*attr))
var parms [6]unsafe.Pointer
parms[0] = unsafe.Pointer(&fd)
parms[1] = unsafe.Pointer(&attr_sz)
parms[2] = unsafe.Pointer(attr)
parms[3] = unsafe.Pointer(&rv)
parms[4] = unsafe.Pointer(&rc)
parms[5] = unsafe.Pointer(&rn)
bpxcall(parms[:], BPX4FCR)
return rv, rc, rn
}
func BpxCondTimedWait(sec uint32, nsec uint32, events uint32, secrem *uint32, nsecrem *uint32) (rv int32, rc int32, rn int32) {
var parms [8]unsafe.Pointer
parms[0] = unsafe.Pointer(&sec)
parms[1] = unsafe.Pointer(&nsec)
parms[2] = unsafe.Pointer(&events)
parms[3] = unsafe.Pointer(secrem)
parms[4] = unsafe.Pointer(nsecrem)
parms[5] = unsafe.Pointer(&rv)
parms[6] = unsafe.Pointer(&rc)
parms[7] = unsafe.Pointer(&rn)
bpxcall(parms[:], BPX4CTW)
return rv, rc, rn
}
func BpxGetthent(in *Pgtha, outlen *uint32, out unsafe.Pointer) (rv int32, rc int32, rn int32) {
var parms [7]unsafe.Pointer
inlen := uint32(26) // nothing else will work. Go says Pgtha is 28-byte because of alignment, but Pgtha is "packed" and must be 26-byte
parms[0] = unsafe.Pointer(&inlen)
parms[1] = unsafe.Pointer(&in)
parms[2] = unsafe.Pointer(outlen)
parms[3] = unsafe.Pointer(&out)
parms[4] = unsafe.Pointer(&rv)
parms[5] = unsafe.Pointer(&rc)
parms[6] = unsafe.Pointer(&rn)
bpxcall(parms[:], BPX4GTH)
return rv, rc, rn
}
func ZosJobname() (jobname string, err error) {
var pgtha Pgtha
pgtha.Pid = uint32(Getpid())
pgtha.Accesspid = PGTHA_CURRENT
pgtha.Flag1 = PGTHA_PROCESS
var out [256]byte
var outlen uint32
outlen = 256
rv, rc, rn := BpxGetthent(&pgtha, &outlen, unsafe.Pointer(&out[0]))
if rv == 0 {
gthc := []byte{0x87, 0xa3, 0x88, 0x83} // 'gthc' in ebcdic
ix := bytes.Index(out[:], gthc)
if ix == -1 {
err = fmt.Errorf("BPX4GTH: gthc return data not found")
return
}
jn := out[ix+80 : ix+88] // we didn't declare Pgthc, but jobname is 8-byte at offset 80
E2a(jn)
jobname = string(bytes.TrimRight(jn, " "))
} else {
err = fmt.Errorf("BPX4GTH: rc=%d errno=%d reason=code=0x%x", rv, rc, rn)
}
return
}
func Bpx4ptq(code int32, data string) (rv int32, rc int32, rn int32) {
var userdata [8]byte
var parms [5]unsafe.Pointer
copy(userdata[:], data+" ")
A2e(userdata[:])
parms[0] = unsafe.Pointer(&code)
parms[1] = unsafe.Pointer(&userdata[0])
parms[2] = unsafe.Pointer(&rv)
parms[3] = unsafe.Pointer(&rc)
parms[4] = unsafe.Pointer(&rn)
bpxcall(parms[:], BPX4PTQ)
return rv, rc, rn
}
const (
PT_TRACE_ME = 0 // Debug this process
PT_READ_I = 1 // Read a full word
PT_READ_D = 2 // Read a full word
PT_READ_U = 3 // Read control info
PT_WRITE_I = 4 //Write a full word
PT_WRITE_D = 5 //Write a full word
PT_CONTINUE = 7 //Continue the process
PT_KILL = 8 //Terminate the process
PT_READ_GPR = 11 // Read GPR, CR, PSW
PT_READ_FPR = 12 // Read FPR
PT_READ_VR = 13 // Read VR
PT_WRITE_GPR = 14 // Write GPR, CR, PSW
PT_WRITE_FPR = 15 // Write FPR
PT_WRITE_VR = 16 // Write VR
PT_READ_BLOCK = 17 // Read storage
PT_WRITE_BLOCK = 19 // Write storage
PT_READ_GPRH = 20 // Read GPRH
PT_WRITE_GPRH = 21 // Write GPRH
PT_REGHSET = 22 // Read all GPRHs
PT_ATTACH = 30 // Attach to a process
PT_DETACH = 31 // Detach from a process
PT_REGSET = 32 // Read all GPRs
PT_REATTACH = 33 // Reattach to a process
PT_LDINFO = 34 // Read loader info
PT_MULTI = 35 // Multi process mode
PT_LD64INFO = 36 // RMODE64 Info Area
PT_BLOCKREQ = 40 // Block request
PT_THREAD_INFO = 60 // Read thread info
PT_THREAD_MODIFY = 61
PT_THREAD_READ_FOCUS = 62
PT_THREAD_WRITE_FOCUS = 63
PT_THREAD_HOLD = 64
PT_THREAD_SIGNAL = 65
PT_EXPLAIN = 66
PT_EVENTS = 67
PT_THREAD_INFO_EXTENDED = 68
PT_REATTACH2 = 71
PT_CAPTURE = 72
PT_UNCAPTURE = 73
PT_GET_THREAD_TCB = 74
PT_GET_ALET = 75
PT_SWAPIN = 76
PT_EXTENDED_EVENT = 98
PT_RECOVER = 99 // Debug a program check
PT_GPR0 = 0 // General purpose register 0
PT_GPR1 = 1 // General purpose register 1
PT_GPR2 = 2 // General purpose register 2
PT_GPR3 = 3 // General purpose register 3
PT_GPR4 = 4 // General purpose register 4
PT_GPR5 = 5 // General purpose register 5
PT_GPR6 = 6 // General purpose register 6
PT_GPR7 = 7 // General purpose register 7
PT_GPR8 = 8 // General purpose register 8
PT_GPR9 = 9 // General purpose register 9
PT_GPR10 = 10 // General purpose register 10
PT_GPR11 = 11 // General purpose register 11
PT_GPR12 = 12 // General purpose register 12
PT_GPR13 = 13 // General purpose register 13
PT_GPR14 = 14 // General purpose register 14
PT_GPR15 = 15 // General purpose register 15
PT_FPR0 = 16 // Floating point register 0
PT_FPR1 = 17 // Floating point register 1
PT_FPR2 = 18 // Floating point register 2
PT_FPR3 = 19 // Floating point register 3
PT_FPR4 = 20 // Floating point register 4
PT_FPR5 = 21 // Floating point register 5
PT_FPR6 = 22 // Floating point register 6
PT_FPR7 = 23 // Floating point register 7
PT_FPR8 = 24 // Floating point register 8
PT_FPR9 = 25 // Floating point register 9
PT_FPR10 = 26 // Floating point register 10
PT_FPR11 = 27 // Floating point register 11
PT_FPR12 = 28 // Floating point register 12
PT_FPR13 = 29 // Floating point register 13
PT_FPR14 = 30 // Floating point register 14
PT_FPR15 = 31 // Floating point register 15
PT_FPC = 32 // Floating point control register
PT_PSW = 40 // PSW
PT_PSW0 = 40 // Left half of the PSW
PT_PSW1 = 41 // Right half of the PSW
PT_CR0 = 42 // Control register 0
PT_CR1 = 43 // Control register 1
PT_CR2 = 44 // Control register 2
PT_CR3 = 45 // Control register 3
PT_CR4 = 46 // Control register 4
PT_CR5 = 47 // Control register 5
PT_CR6 = 48 // Control register 6
PT_CR7 = 49 // Control register 7
PT_CR8 = 50 // Control register 8
PT_CR9 = 51 // Control register 9
PT_CR10 = 52 // Control register 10
PT_CR11 = 53 // Control register 11
PT_CR12 = 54 // Control register 12
PT_CR13 = 55 // Control register 13
PT_CR14 = 56 // Control register 14
PT_CR15 = 57 // Control register 15
PT_GPRH0 = 58 // GP High register 0
PT_GPRH1 = 59 // GP High register 1
PT_GPRH2 = 60 // GP High register 2
PT_GPRH3 = 61 // GP High register 3
PT_GPRH4 = 62 // GP High register 4
PT_GPRH5 = 63 // GP High register 5
PT_GPRH6 = 64 // GP High register 6
PT_GPRH7 = 65 // GP High register 7
PT_GPRH8 = 66 // GP High register 8
PT_GPRH9 = 67 // GP High register 9
PT_GPRH10 = 68 // GP High register 10
PT_GPRH11 = 69 // GP High register 11
PT_GPRH12 = 70 // GP High register 12
PT_GPRH13 = 71 // GP High register 13
PT_GPRH14 = 72 // GP High register 14
PT_GPRH15 = 73 // GP High register 15
PT_VR0 = 74 // Vector register 0
PT_VR1 = 75 // Vector register 1
PT_VR2 = 76 // Vector register 2
PT_VR3 = 77 // Vector register 3
PT_VR4 = 78 // Vector register 4
PT_VR5 = 79 // Vector register 5
PT_VR6 = 80 // Vector register 6
PT_VR7 = 81 // Vector register 7
PT_VR8 = 82 // Vector register 8
PT_VR9 = 83 // Vector register 9
PT_VR10 = 84 // Vector register 10
PT_VR11 = 85 // Vector register 11
PT_VR12 = 86 // Vector register 12
PT_VR13 = 87 // Vector register 13
PT_VR14 = 88 // Vector register 14
PT_VR15 = 89 // Vector register 15
PT_VR16 = 90 // Vector register 16
PT_VR17 = 91 // Vector register 17
PT_VR18 = 92 // Vector register 18
PT_VR19 = 93 // Vector register 19
PT_VR20 = 94 // Vector register 20
PT_VR21 = 95 // Vector register 21
PT_VR22 = 96 // Vector register 22
PT_VR23 = 97 // Vector register 23
PT_VR24 = 98 // Vector register 24
PT_VR25 = 99 // Vector register 25
PT_VR26 = 100 // Vector register 26
PT_VR27 = 101 // Vector register 27
PT_VR28 = 102 // Vector register 28
PT_VR29 = 103 // Vector register 29
PT_VR30 = 104 // Vector register 30
PT_VR31 = 105 // Vector register 31
PT_PSWG = 106 // PSWG
PT_PSWG0 = 106 // Bytes 0-3
PT_PSWG1 = 107 // Bytes 4-7
PT_PSWG2 = 108 // Bytes 8-11 (IA high word)
PT_PSWG3 = 109 // Bytes 12-15 (IA low word)
)
func Bpx4ptr(request int32, pid int32, addr unsafe.Pointer, data unsafe.Pointer, buffer unsafe.Pointer) (rv int32, rc int32, rn int32) {
var parms [8]unsafe.Pointer
parms[0] = unsafe.Pointer(&request)
parms[1] = unsafe.Pointer(&pid)
parms[2] = unsafe.Pointer(&addr)
parms[3] = unsafe.Pointer(&data)
parms[4] = unsafe.Pointer(&buffer)
parms[5] = unsafe.Pointer(&rv)
parms[6] = unsafe.Pointer(&rc)
parms[7] = unsafe.Pointer(&rn)
bpxcall(parms[:], BPX4PTR)
return rv, rc, rn
}
func copyU8(val uint8, dest []uint8) int {
if len(dest) < 1 {
return 0
}
dest[0] = val
return 1
}
func copyU8Arr(src, dest []uint8) int {
if len(dest) < len(src) {
return 0
}
for i, v := range src {
dest[i] = v
}
return len(src)
}
func copyU16(val uint16, dest []uint16) int {
if len(dest) < 1 {
return 0
}
dest[0] = val
return 1
}
func copyU32(val uint32, dest []uint32) int {
if len(dest) < 1 {
return 0
}
dest[0] = val
return 1
}
func copyU32Arr(src, dest []uint32) int {
if len(dest) < len(src) {
return 0
}
for i, v := range src {
dest[i] = v
}
return len(src)
}
func copyU64(val uint64, dest []uint64) int {
if len(dest) < 1 {
return 0
}
dest[0] = val
return 1
}
================================================
FILE: vendor/golang.org/x/sys/unix/bpxsvc_zos.s
================================================
// Copyright 2024 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.
#include "go_asm.h"
#include "textflag.h"
// function to call USS assembly language services
//
// doc: https://www.ibm.com/support/knowledgecenter/en/SSLTBW_3.1.0/com.ibm.zos.v3r1.bpxb100/bit64env.htm
//
// arg1 unsafe.Pointer array that ressembles an OS PLIST
//
// arg2 function offset as in
// doc: https://www.ibm.com/support/knowledgecenter/en/SSLTBW_3.1.0/com.ibm.zos.v3r1.bpxb100/bpx2cr_List_of_offsets.htm
//
// func bpxcall(plist []unsafe.Pointer, bpx_offset int64)
TEXT ·bpxcall(SB), NOSPLIT|NOFRAME, $0
MOVD plist_base+0(FP), R1 // r1 points to plist
MOVD bpx_offset+24(FP), R2 // r2 offset to BPX vector table
MOVD R14, R7 // save r14
MOVD R15, R8 // save r15
MOVWZ 16(R0), R9
MOVWZ 544(R9), R9
MOVWZ 24(R9), R9 // call vector in r9
ADD R2, R9 // add offset to vector table
MOVWZ (R9), R9 // r9 points to entry point
BYTE $0x0D // BL R14,R9 --> basr r14,r9
BYTE $0xE9 // clobbers 0,1,14,15
MOVD R8, R15 // restore 15
JMP R7 // return via saved return address
// func A2e(arr [] byte)
// code page conversion from 819 to 1047
TEXT ·A2e(SB), NOSPLIT|NOFRAME, $0
MOVD arg_base+0(FP), R2 // pointer to arry of characters
MOVD arg_len+8(FP), R3 // count
XOR R0, R0
XOR R1, R1
BYTE $0xA7; BYTE $0x15; BYTE $0x00; BYTE $0x82 // BRAS 1,(2+(256/2))
// ASCII -> EBCDIC conversion table:
BYTE $0x00; BYTE $0x01; BYTE $0x02; BYTE $0x03
BYTE $0x37; BYTE $0x2d; BYTE $0x2e; BYTE $0x2f
BYTE $0x16; BYTE $0x05; BYTE $0x15; BYTE $0x0b
BYTE $0x0c; BYTE $0x0d; BYTE $0x0e; BYTE $0x0f
BYTE $0x10; BYTE $0x11; BYTE $0x12; BYTE $0x13
BYTE $0x3c; BYTE $0x3d; BYTE $0x32; BYTE $0x26
BYTE $0x18; BYTE $0x19; BYTE $0x3f; BYTE $0x27
BYTE $0x1c; BYTE $0x1d; BYTE $0x1e; BYTE $0x1f
BYTE $0x40; BYTE $0x5a; BYTE $0x7f; BYTE $0x7b
BYTE $0x5b; BYTE $0x6c; BYTE $0x50; BYTE $0x7d
BYTE $0x4d; BYTE $0x5d; BYTE $0x5c; BYTE $0x4e
BYTE $0x6b; BYTE $0x60; BYTE $0x4b; BYTE $0x61
BYTE $0xf0; BYTE $0xf1; BYTE $0xf2; BYTE $0xf3
BYTE $0xf4; BYTE $0xf5; BYTE $0xf6; BYTE $0xf7
BYTE $0xf8; BYTE $0xf9; BYTE $0x7a; BYTE $0x5e
BYTE $0x4c; BYTE $0x7e; BYTE $0x6e; BYTE $0x6f
BYTE $0x7c; BYTE $0xc1; BYTE $0xc2; BYTE $0xc3
BYTE $0xc4; BYTE $0xc5; BYTE $0xc6; BYTE $0xc7
BYTE $0xc8; BYTE $0xc9; BYTE $0xd1; BYTE $0xd2
BYTE $0xd3; BYTE $0xd4; BYTE $0xd5; BYTE $0xd6
BYTE $0xd7; BYTE $0xd8; BYTE $0xd9; BYTE $0xe2
BYTE $0xe3; BYTE $0xe4; BYTE $0xe5; BYTE $0xe6
BYTE $0xe7; BYTE $0xe8; BYTE $0xe9; BYTE $0xad
BYTE $0xe0; BYTE $0xbd; BYTE $0x5f; BYTE $0x6d
BYTE $0x79; BYTE $0x81; BYTE $0x82; BYTE $0x83
BYTE $0x84; BYTE $0x85; BYTE $0x86; BYTE $0x87
BYTE $0x88; BYTE $0x89; BYTE $0x91; BYTE $0x92
BYTE $0x93; BYTE $0x94; BYTE $0x95; BYTE $0x96
BYTE $0x97; BYTE $0x98; BYTE $0x99; BYTE $0xa2
BYTE $0xa3; BYTE $0xa4; BYTE $0xa5; BYTE $0xa6
BYTE $0xa7; BYTE $0xa8; BYTE $0xa9; BYTE $0xc0
BYTE $0x4f; BYTE $0xd0; BYTE $0xa1; BYTE $0x07
BYTE $0x20; BYTE $0x21; BYTE $0x22; BYTE $0x23
BYTE $0x24; BYTE $0x25; BYTE $0x06; BYTE $0x17
BYTE $0x28; BYTE $0x29; BYTE $0x2a; BYTE $0x2b
BYTE $0x2c; BYTE $0x09; BYTE $0x0a; BYTE $0x1b
BYTE $0x30; BYTE $0x31; BYTE $0x1a; BYTE $0x33
BYTE $0x34; BYTE $0x35; BYTE $0x36; BYTE $0x08
BYTE $0x38; BYTE $0x39; BYTE $0x3a; BYTE $0x3b
BYTE $0x04; BYTE $0x14; BYTE $0x3e; BYTE $0xff
BYTE $0x41; BYTE $0xaa; BYTE $0x4a; BYTE $0xb1
BYTE $0x9f; BYTE $0xb2; BYTE $0x6a; BYTE $0xb5
BYTE $0xbb; BYTE $0xb4; BYTE $0x9a; BYTE $0x8a
BYTE $0xb0; BYTE $0xca; BYTE $0xaf; BYTE $0xbc
BYTE $0x90; BYTE $0x8f; BYTE $0xea; BYTE $0xfa
BYTE $0xbe; BYTE $0xa0; BYTE $0xb6; BYTE $0xb3
BYTE $0x9d; BYTE $0xda; BYTE $0x9b; BYTE $0x8b
BYTE $0xb7; BYTE $0xb8; BYTE $0xb9; BYTE $0xab
BYTE $0x64; BYTE $0x65; BYTE $0x62; BYTE $0x66
BYTE $0x63; BYTE $0x67; BYTE $0x9e; BYTE $0x68
BYTE $0x74; BYTE $0x71; BYTE $0x72; BYTE $0x73
BYTE $0x78; BYTE $0x75; BYTE $0x76; BYTE $0x77
BYTE $0xac; BYTE $0x69; BYTE $0xed; BYTE $0xee
BYTE $0xeb; BYTE $0xef; BYTE $0xec; BYTE $0xbf
BYTE $0x80; BYTE $0xfd; BYTE $0xfe; BYTE $0xfb
BYTE $0xfc; BYTE $0xba; BYTE $0xae; BYTE $0x59
BYTE $0x44; BYTE $0x45; BYTE $0x42; BYTE $0x46
BYTE $0x43; BYTE $0x47; BYTE $0x9c; BYTE $0x48
BYTE $0x54; BYTE $0x51; BYTE $0x52; BYTE $0x53
BYTE $0x58; BYTE $0x55; BYTE $0x56; BYTE $0x57
BYTE $0x8c; BYTE $0x49; BYTE $0xcd; BYTE $0xce
BYTE $0xcb; BYTE $0xcf; BYTE $0xcc; BYTE $0xe1
BYTE $0x70; BYTE $0xdd; BYTE $0xde; BYTE $0xdb
BYTE $0xdc; BYTE $0x8d; BYTE $0x8e; BYTE $0xdf
retry:
WORD $0xB9931022 // TROO 2,2,b'0001'
BVS retry
RET
// func e2a(arr [] byte)
// code page conversion from 1047 to 819
TEXT ·E2a(SB), NOSPLIT|NOFRAME, $0
MOVD arg_base+0(FP), R2 // pointer to arry of characters
MOVD arg_len+8(FP), R3 // count
XOR R0, R0
XOR R1, R1
BYTE $0xA7; BYTE $0x15; BYTE $0x00; BYTE $0x82 // BRAS 1,(2+(256/2))
// EBCDIC -> ASCII conversion table:
BYTE $0x00; BYTE $0x01; BYTE $0x02; BYTE $0x03
BYTE $0x9c; BYTE $0x09; BYTE $0x86; BYTE $0x7f
BYTE $0x97; BYTE $0x8d; BYTE $0x8e; BYTE $0x0b
BYTE $0x0c; BYTE $0x0d; BYTE $0x0e; BYTE $0x0f
BYTE $0x10; BYTE $0x11; BYTE $0x12; BYTE $0x13
BYTE $0x9d; BYTE $0x0a; BYTE $0x08; BYTE $0x87
BYTE $0x18; BYTE $0x19; BYTE $0x92; BYTE $0x8f
BYTE $0x1c; BYTE $0x1d; BYTE $0x1e; BYTE $0x1f
BYTE $0x80; BYTE $0x81; BYTE $0x82; BYTE $0x83
BYTE $0x84; BYTE $0x85; BYTE $0x17; BYTE $0x1b
BYTE $0x88; BYTE $0x89; BYTE $0x8a; BYTE $0x8b
BYTE $0x8c; BYTE $0x05; BYTE $0x06; BYTE $0x07
BYTE $0x90; BYTE $0x91; BYTE $0x16; BYTE $0x93
BYTE $0x94; BYTE $0x95; BYTE $0x96; BYTE $0x04
BYTE $0x98; BYTE $0x99; BYTE $0x9a; BYTE $0x9b
BYTE $0x14; BYTE $0x15; BYTE $0x9e; BYTE $0x1a
BYTE $0x20; BYTE $0xa0; BYTE $0xe2; BYTE $0xe4
BYTE $0xe0; BYTE $0xe1; BYTE $0xe3; BYTE $0xe5
BYTE $0xe7; BYTE $0xf1; BYTE $0xa2; BYTE $0x2e
BYTE $0x3c; BYTE $0x28; BYTE $0x2b; BYTE $0x7c
BYTE $0x26; BYTE $0xe9; BYTE $0xea; BYTE $0xeb
BYTE $0xe8; BYTE $0xed; BYTE $0xee; BYTE $0xef
BYTE $0xec; BYTE $0xdf; BYTE $0x21; BYTE $0x24
BYTE $0x2a; BYTE $0x29; BYTE $0x3b; BYTE $0x5e
BYTE $0x2d; BYTE $0x2f; BYTE $0xc2; BYTE $0xc4
BYTE $0xc0; BYTE $0xc1; BYTE $0xc3; BYTE $0xc5
BYTE $0xc7; BYTE $0xd1; BYTE $0xa6; BYTE $0x2c
BYTE $0x25; BYTE $0x5f; BYTE $0x3e; BYTE $0x3f
BYTE $0xf8; BYTE $0xc9; BYTE $0xca; BYTE $0xcb
BYTE $0xc8; BYTE $0xcd; BYTE $0xce; BYTE $0xcf
BYTE $0xcc; BYTE $0x60; BYTE $0x3a; BYTE $0x23
BYTE $0x40; BYTE $0x27; BYTE $0x3d; BYTE $0x22
BYTE $0xd8; BYTE $0x61; BYTE $0x62; BYTE $0x63
BYTE $0x64; BYTE $0x65; BYTE $0x66; BYTE $0x67
BYTE $0x68; BYTE $0x69; BYTE $0xab; BYTE $0xbb
BYTE $0xf0; BYTE $0xfd; BYTE $0xfe; BYTE $0xb1
BYTE $0xb0; BYTE $0x6a; BYTE $0x6b; BYTE $0x6c
BYTE $0x6d; BYTE $0x6e; BYTE $0x6f; BYTE $0x70
BYTE $0x71; BYTE $0x72; BYTE $0xaa; BYTE $0xba
BYTE $0xe6; BYTE $0xb8; BYTE $0xc6; BYTE $0xa4
BYTE $0xb5; BYTE $0x7e; BYTE $0x73; BYTE $0x74
BYTE $0x75; BYTE $0x76; BYTE $0x77; BYTE $0x78
BYTE $0x79; BYTE $0x7a; BYTE $0xa1; BYTE $0xbf
BYTE $0xd0; BYTE $0x5b; BYTE $0xde; BYTE $0xae
BYTE $0xac; BYTE $0xa3; BYTE $0xa5; BYTE $0xb7
BYTE $0xa9; BYTE $0xa7; BYTE $0xb6; BYTE $0xbc
BYTE $0xbd; BYTE $0xbe; BYTE $0xdd; BYTE $0xa8
BYTE $0xaf; BYTE $0x5d; BYTE $0xb4; BYTE $0xd7
BYTE $0x7b; BYTE $0x41; BYTE $0x42; BYTE $0x43
BYTE $0x44; BYTE $0x45; BYTE $0x46; BYTE $0x47
BYTE $0x48; BYTE $0x49; BYTE $0xad; BYTE $0xf4
BYTE $0xf6; BYTE $0xf2; BYTE $0xf3; BYTE $0xf5
BYTE $0x7d; BYTE $0x4a; BYTE $0x4b; BYTE $0x4c
BYTE $0x4d; BYTE $0x4e; BYTE $0x4f; BYTE $0x50
BYTE $0x51; BYTE $0x52; BYTE $0xb9; BYTE $0xfb
BYTE $0xfc; BYTE $0xf9; BYTE $0xfa; BYTE $0xff
BYTE $0x5c; BYTE $0xf7; BYTE $0x53; BYTE $0x54
BYTE $0x55; BYTE $0x56; BYTE $0x57; BYTE $0x58
BYTE $0x59; BYTE $0x5a; BYTE $0xb2; BYTE $0xd4
BYTE $0xd6; BYTE $0xd2; BYTE $0xd3; BYTE $0xd5
BYTE $0x30; BYTE $0x31; BYTE $0x32; BYTE $0x33
BYTE $0x34; BYTE $0x35; BYTE $0x36; BYTE $0x37
BYTE $0x38; BYTE $0x39; BYTE $0xb3; BYTE $0xdb
BYTE $0xdc; BYTE $0xd9; BYTE $0xda; BYTE $0x9f
retry:
WORD $0xB9931022 // TROO 2,2,b'0001'
BVS retry
RET
================================================
FILE: vendor/golang.org/x/sys/unix/cap_freebsd.go
================================================
// Copyright 2017 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.
//go:build freebsd
package unix
import (
"errors"
"fmt"
)
// Go implementation of C mostly found in /usr/src/sys/kern/subr_capability.c
const (
// This is the version of CapRights this package understands. See C implementation for parallels.
capRightsGoVersion = CAP_RIGHTS_VERSION_00
capArSizeMin = CAP_RIGHTS_VERSION_00 + 2
capArSizeMax = capRightsGoVersion + 2
)
var (
bit2idx = []int{
-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1,
4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
}
)
func capidxbit(right uint64) int {
return int((right >> 57) & 0x1f)
}
func rightToIndex(right uint64) (int, error) {
idx := capidxbit(right)
if idx < 0 || idx >= len(bit2idx) {
return -2, fmt.Errorf("index for right 0x%x out of range", right)
}
return bit2idx[idx], nil
}
func caprver(right uint64) int {
return int(right >> 62)
}
func capver(rights *CapRights) int {
return caprver(rights.Rights[0])
}
func caparsize(rights *CapRights) int {
return capver(rights) + 2
}
// CapRightsSet sets the permissions in setrights in rights.
func CapRightsSet(rights *CapRights, setrights []uint64) error {
// This is essentially a copy of cap_rights_vset()
if capver(rights) != CAP_RIGHTS_VERSION_00 {
return fmt.Errorf("bad rights version %d", capver(rights))
}
n := caparsize(rights)
if n < capArSizeMin || n > capArSizeMax {
return errors.New("bad rights size")
}
for _, right := range setrights {
if caprver(right) != CAP_RIGHTS_VERSION_00 {
return errors.New("bad right version")
}
i, err := rightToIndex(right)
if err != nil {
return err
}
if i >= n {
return errors.New("index overflow")
}
if capidxbit(rights.Rights[i]) != capidxbit(right) {
return errors.New("index mismatch")
}
rights.Rights[i] |= right
if capidxbit(rights.Rights[i]) != capidxbit(right) {
return errors.New("index mismatch (after assign)")
}
}
return nil
}
// CapRightsClear clears the permissions in clearrights from rights.
func CapRightsClear(rights *CapRights, clearrights []uint64) error {
// This is essentially a copy of cap_rights_vclear()
if capver(rights) != CAP_RIGHTS_VERSION_00 {
return fmt.Errorf("bad rights version %d", capver(rights))
}
n := caparsize(rights)
if n < capArSizeMin || n > capArSizeMax {
return errors.New("bad rights size")
}
for _, right := range clearrights {
if caprver(right) != CAP_RIGHTS_VERSION_00 {
return errors.New("bad right version")
}
i, err := rightToIndex(right)
if err != nil {
return err
}
if i >= n {
return errors.New("index overflow")
}
if capidxbit(rights.Rights[i]) != capidxbit(right) {
return errors.New("index mismatch")
}
rights.Rights[i] &= ^(right & 0x01FFFFFFFFFFFFFF)
if capidxbit(rights.Rights[i]) != capidxbit(right) {
return errors.New("index mismatch (after assign)")
}
}
return nil
}
// CapRightsIsSet checks whether all the permissions in setrights are present in rights.
func CapRightsIsSet(rights *CapRights, setrights []uint64) (bool, error) {
// This is essentially a copy of cap_rights_is_vset()
if capver(rights) != CAP_RIGHTS_VERSION_00 {
return false, fmt.Errorf("bad rights version %d", capver(rights))
}
n := caparsize(rights)
if n < capArSizeMin || n > capArSizeMax {
return false, errors.New("bad rights size")
}
for _, right := range setrights {
if caprver(right) != CAP_RIGHTS_VERSION_00 {
return false, errors.New("bad right version")
}
i, err := rightToIndex(right)
if err != nil {
return false, err
}
if i >= n {
return false, errors.New("index overflow")
}
if capidxbit(rights.Rights[i]) != capidxbit(right) {
return false, errors.New("index mismatch")
}
if (rights.Rights[i] & right) != right {
return false, nil
}
}
return true, nil
}
func capright(idx uint64, bit uint64) uint64 {
return ((1 << (57 + idx)) | bit)
}
// CapRightsInit returns a pointer to an initialised CapRights structure filled with rights.
// See man cap_rights_init(3) and rights(4).
func CapRightsInit(rights []uint64) (*CapRights, error) {
var r CapRights
r.Rights[0] = (capRightsGoVersion << 62) | capright(0, 0)
r.Rights[1] = capright(1, 0)
err := CapRightsSet(&r, rights)
if err != nil {
return nil, err
}
return &r, nil
}
// CapRightsLimit reduces the operations permitted on fd to at most those contained in rights.
// The capability rights on fd can never be increased by CapRightsLimit.
// See man cap_rights_limit(2) and rights(4).
func CapRightsLimit(fd uintptr, rights *CapRights) error {
return capRightsLimit(int(fd), rights)
}
// CapRightsGet returns a CapRights structure containing the operations permitted on fd.
// See man cap_rights_get(3) and rights(4).
func CapRightsGet(fd uintptr) (*CapRights, error) {
r, err := CapRightsInit(nil)
if err != nil {
return nil, err
}
err = capRightsGet(capRightsGoVersion, int(fd), r)
if err != nil {
return nil, err
}
return r, nil
}
================================================
FILE: vendor/golang.org/x/sys/unix/constants.go
================================================
// Copyright 2015 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.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package unix
const (
R_OK = 0x4
W_OK = 0x2
X_OK = 0x1
)
================================================
FILE: vendor/golang.org/x/sys/unix/dev_aix_ppc.go
================================================
// Copyright 2018 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.
//go:build aix && ppc
// Functions to access/create device major and minor numbers matching the
// encoding used by AIX.
package unix
// Major returns the major component of a Linux device number.
func Major(dev uint64) uint32 {
return uint32((dev >> 16) & 0xffff)
}
// Minor returns the minor component of a Linux device number.
func Minor(dev uint64) uint32 {
return uint32(dev & 0xffff)
}
// Mkdev returns a Linux device number generated from the given major and minor
// components.
func Mkdev(major, minor uint32) uint64 {
return uint64(((major) << 16) | (minor))
}
================================================
FILE: vendor/golang.org/x/sys/unix/dev_aix_ppc64.go
================================================
// Copyright 2018 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.
//go:build aix && ppc64
// Functions to access/create device major and minor numbers matching the
// encoding used AIX.
package unix
// Major returns the major component of a Linux device number.
func Major(dev uint64) uint32 {
return uint32((dev & 0x3fffffff00000000) >> 32)
}
// Minor returns the minor component of a Linux device number.
func Minor(dev uint64) uint32 {
return uint32((dev & 0x00000000ffffffff) >> 0)
}
// Mkdev returns a Linux device number generated from the given major and minor
// components.
func Mkdev(major, minor uint32) uint64 {
var DEVNO64 uint64
DEVNO64 = 0x8000000000000000
return ((uint64(major) << 32) | (uint64(minor) & 0x00000000FFFFFFFF) | DEVNO64)
}
================================================
FILE: vendor/golang.org/x/sys/unix/dev_darwin.go
================================================
// Copyright 2017 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.
// Functions to access/create device major and minor numbers matching the
// encoding used in Darwin's sys/types.h header.
package unix
// Major returns the major component of a Darwin device number.
func Major(dev uint64) uint32 {
return uint32((dev >> 24) & 0xff)
}
// Minor returns the minor component of a Darwin device number.
func Minor(dev uint64) uint32 {
return uint32(dev & 0xffffff)
}
// Mkdev returns a Darwin device number generated from the given major and minor
// components.
func Mkdev(major, minor uint32) uint64 {
return (uint64(major) << 24) | uint64(minor)
}
================================================
FILE: vendor/golang.org/x/sys/unix/dev_dragonfly.go
================================================
// Copyright 2017 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.
// Functions to access/create device major and minor numbers matching the
// encoding used in Dragonfly's sys/types.h header.
//
// The information below is extracted and adapted from sys/types.h:
//
// Minor gives a cookie instead of an index since in order to avoid changing the
// meanings of bits 0-15 or wasting time and space shifting bits 16-31 for
// devices that don't use them.
package unix
// Major returns the major component of a DragonFlyBSD device number.
func Major(dev uint64) uint32 {
return uint32((dev >> 8) & 0xff)
}
// Minor returns the minor component of a DragonFlyBSD device number.
func Minor(dev uint64) uint32 {
return uint32(dev & 0xffff00ff)
}
// Mkdev returns a DragonFlyBSD device number generated from the given major and
// minor components.
func Mkdev(major, minor uint32) uint64 {
return (uint64(major) << 8) | uint64(minor)
}
================================================
FILE: vendor/golang.org/x/sys/unix/dev_freebsd.go
================================================
// Copyright 2017 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.
// Functions to access/create device major and minor numbers matching the
// encoding used in FreeBSD's sys/types.h header.
//
// The information below is extracted and adapted from sys/types.h:
//
// Minor gives a cookie instead of an index since in order to avoid changing the
// meanings of bits 0-15 or wasting time and space shifting bits 16-31 for
// devices that don't use them.
package unix
// Major returns the major component of a FreeBSD device number.
func Major(dev uint64) uint32 {
return uint32((dev >> 8) & 0xff)
}
// Minor returns the minor component of a FreeBSD device number.
func Minor(dev uint64) uint32 {
return uint32(dev & 0xffff00ff)
}
// Mkdev returns a FreeBSD device number generated from the given major and
// minor components.
func Mkdev(major, minor uint32) uint64 {
return (uint64(major) << 8) | uint64(minor)
}
================================================
FILE: vendor/golang.org/x/sys/unix/dev_linux.go
================================================
// Copyright 2017 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.
// Functions to access/create device major and minor numbers matching the
// encoding used by the Linux kernel and glibc.
//
// The information below is extracted and adapted from bits/sysmacros.h in the
// glibc sources:
//
// dev_t in glibc is 64-bit, with 32-bit major and minor numbers. glibc's
// default encoding is MMMM Mmmm mmmM MMmm, where M is a hex digit of the major
// number and m is a hex digit of the minor number. This is backward compatible
// with legacy systems where dev_t is 16 bits wide, encoded as MMmm. It is also
// backward compatible with the Linux kernel, which for some architectures uses
// 32-bit dev_t, encoded as mmmM MMmm.
package unix
// Major returns the major component of a Linux device number.
func Major(dev uint64) uint32 {
major := uint32((dev & 0x00000000000fff00) >> 8)
major |= uint32((dev & 0xfffff00000000000) >> 32)
return major
}
// Minor returns the minor component of a Linux device number.
func Minor(dev uint64) uint32 {
minor := uint32((dev & 0x00000000000000ff) >> 0)
minor |= uint32((dev & 0x00000ffffff00000) >> 12)
return minor
}
// Mkdev returns a Linux device number generated from the given major and minor
// components.
func Mkdev(major, minor uint32) uint64 {
dev := (uint64(major) & 0x00000fff) << 8
dev |= (uint64(major) & 0xfffff000) << 32
dev |= (uint64(minor) & 0x000000ff) << 0
dev |= (uint64(minor) & 0xffffff00) << 12
return dev
}
================================================
FILE: vendor/golang.org/x/sys/unix/dev_netbsd.go
================================================
// Copyright 2017 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.
// Functions to access/create device major and minor numbers matching the
// encoding used in NetBSD's sys/types.h header.
package unix
// Major returns the major component of a NetBSD device number.
func Major(dev uint64) uint32 {
return uint32((dev & 0x000fff00) >> 8)
}
// Minor returns the minor component of a NetBSD device number.
func Minor(dev uint64) uint32 {
minor := uint32((dev & 0x000000ff) >> 0)
minor |= uint32((dev & 0xfff00000) >> 12)
return minor
}
// Mkdev returns a NetBSD device number generated from the given major and minor
// components.
func Mkdev(major, minor uint32) uint64 {
dev := (uint64(major) << 8) & 0x000fff00
dev |= (uint64(minor) << 12) & 0xfff00000
dev |= (uint64(minor) << 0) & 0x000000ff
return dev
}
================================================
FILE: vendor/golang.org/x/sys/unix/dev_openbsd.go
================================================
// Copyright 2017 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.
// Functions to access/create device major and minor numbers matching the
// encoding used in OpenBSD's sys/types.h header.
package unix
// Major returns the major component of an OpenBSD device number.
func Major(dev uint64) uint32 {
return uint32((dev & 0x0000ff00) >> 8)
}
// Minor returns the minor component of an OpenBSD device number.
func Minor(dev uint64) uint32 {
minor := uint32((dev & 0x000000ff) >> 0)
minor |= uint32((dev & 0xffff0000) >> 8)
return minor
}
// Mkdev returns an OpenBSD device number generated from the given major and minor
// components.
func Mkdev(major, minor uint32) uint64 {
dev := (uint64(major) << 8) & 0x0000ff00
dev |= (uint64(minor) << 8) & 0xffff0000
dev |= (uint64(minor) << 0) & 0x000000ff
return dev
}
================================================
FILE: vendor/golang.org/x/sys/unix/dev_zos.go
================================================
// Copyright 2020 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.
//go:build zos && s390x
// Functions to access/create device major and minor numbers matching the
// encoding used by z/OS.
//
// The information below is extracted and adapted from macros.
package unix
// Major returns the major component of a z/OS device number.
func Major(dev uint64) uint32 {
return uint32((dev >> 16) & 0x0000FFFF)
}
// Minor returns the minor component of a z/OS device number.
func Minor(dev uint64) uint32 {
return uint32(dev & 0x0000FFFF)
}
// Mkdev returns a z/OS device number generated from the given major and minor
// components.
func Mkdev(major, minor uint32) uint64 {
return (uint64(major) << 16) | uint64(minor)
}
================================================
FILE: vendor/golang.org/x/sys/unix/dirent.go
================================================
// Copyright 2009 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.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package unix
import "unsafe"
// readInt returns the size-bytes unsigned integer in native byte order at offset off.
func readInt(b []byte, off, size uintptr) (u uint64, ok bool) {
if len(b) < int(off+size) {
return 0, false
}
if isBigEndian {
return readIntBE(b[off:], size), true
}
return readIntLE(b[off:], size), true
}
func readIntBE(b []byte, size uintptr) uint64 {
switch size {
case 1:
return uint64(b[0])
case 2:
_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[1]) | uint64(b[0])<<8
case 4:
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24
case 8:
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
default:
panic("syscall: readInt with unsupported size")
}
}
func readIntLE(b []byte, size uintptr) uint64 {
switch size {
case 1:
return uint64(b[0])
case 2:
_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[0]) | uint64(b[1])<<8
case 4:
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24
case 8:
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
default:
panic("syscall: readInt with unsupported size")
}
}
// ParseDirent parses up to max directory entries in buf,
// appending the names to names. It returns the number of
// bytes consumed from buf, the number of entries added
// to names, and the new names slice.
func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
origlen := len(buf)
count = 0
for max != 0 && len(buf) > 0 {
reclen, ok := direntReclen(buf)
if !ok || reclen > uint64(len(buf)) {
return origlen, count, names
}
rec := buf[:reclen]
buf = buf[reclen:]
ino, ok := direntIno(rec)
if !ok {
break
}
if ino == 0 { // File absent in directory.
continue
}
const namoff = uint64(unsafe.Offsetof(Dirent{}.Name))
namlen, ok := direntNamlen(rec)
if !ok || namoff+namlen > uint64(len(rec)) {
break
}
name := rec[namoff : namoff+namlen]
for i, c := range name {
if c == 0 {
name = name[:i]
break
}
}
// Check for useless names before allocating a string.
if string(name) == "." || string(name) == ".." {
continue
}
max--
count++
names = append(names, string(name))
}
return origlen - len(buf), count, names
}
================================================
FILE: vendor/golang.org/x/sys/unix/endian_big.go
================================================
// Copyright 2016 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.
//
//go:build armbe || arm64be || m68k || mips || mips64 || mips64p32 || ppc || ppc64 || s390 || s390x || shbe || sparc || sparc64
package unix
const isBigEndian = true
================================================
FILE: vendor/golang.org/x/sys/unix/endian_little.go
================================================
// Copyright 2016 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.
//
//go:build 386 || amd64 || amd64p32 || alpha || arm || arm64 || loong64 || mipsle || mips64le || mips64p32le || nios2 || ppc64le || riscv || riscv64 || sh
package unix
const isBigEndian = false
================================================
FILE: vendor/golang.org/x/sys/unix/env_unix.go
================================================
// Copyright 2010 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.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
// Unix environment variables.
package unix
import "syscall"
func Getenv(key string) (value string, found bool) {
return syscall.Getenv(key)
}
func Setenv(key, value string) error {
return syscall.Setenv(key, value)
}
func Clearenv() {
syscall.Clearenv()
}
func Environ() []string {
return syscall.Environ()
}
func Unsetenv(key string) error {
return syscall.Unsetenv(key)
}
================================================
FILE: vendor/golang.org/x/sys/unix/fcntl.go
================================================
// Copyright 2014 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.
//go:build dragonfly || freebsd || linux || netbsd
package unix
import "unsafe"
// fcntl64Syscall is usually SYS_FCNTL, but is overridden on 32-bit Linux
// systems by fcntl_linux_32bit.go to be SYS_FCNTL64.
var fcntl64Syscall uintptr = SYS_FCNTL
func fcntl(fd int, cmd, arg int) (int, error) {
valptr, _, errno := Syscall(fcntl64Syscall, uintptr(fd), uintptr(cmd), uintptr(arg))
var err error
if errno != 0 {
err = errno
}
return int(valptr), err
}
// FcntlInt performs a fcntl syscall on fd with the provided command and argument.
func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
return fcntl(int(fd), cmd, arg)
}
// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
_, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(unsafe.Pointer(lk)))
if errno == 0 {
return nil
}
return errno
}
================================================
FILE: vendor/golang.org/x/sys/unix/fcntl_darwin.go
================================================
// Copyright 2019 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.
package unix
import "unsafe"
// FcntlInt performs a fcntl syscall on fd with the provided command and argument.
func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
return fcntl(int(fd), cmd, arg)
}
// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
_, err := fcntl(int(fd), cmd, int(uintptr(unsafe.Pointer(lk))))
return err
}
// FcntlFstore performs a fcntl syscall for the F_PREALLOCATE command.
func FcntlFstore(fd uintptr, cmd int, fstore *Fstore_t) error {
_, err := fcntl(int(fd), cmd, int(uintptr(unsafe.Pointer(fstore))))
return err
}
================================================
FILE: vendor/golang.org/x/sys/unix/fcntl_linux_32bit.go
================================================
// Copyright 2014 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.
//go:build (linux && 386) || (linux && arm) || (linux && mips) || (linux && mipsle) || (linux && ppc)
package unix
func init() {
// On 32-bit Linux systems, the fcntl syscall that matches Go's
// Flock_t type is SYS_FCNTL64, not SYS_FCNTL.
fcntl64Syscall = SYS_FCNTL64
}
================================================
FILE: vendor/golang.org/x/sys/unix/fdset.go
================================================
// Copyright 2019 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.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package unix
// Set adds fd to the set fds.
func (fds *FdSet) Set(fd int) {
fds.Bits[fd/NFDBITS] |= (1 << (uintptr(fd) % NFDBITS))
}
// Clear removes fd from the set fds.
func (fds *FdSet) Clear(fd int) {
fds.Bits[fd/NFDBITS] &^= (1 << (uintptr(fd) % NFDBITS))
}
// IsSet returns whether fd is in the set fds.
func (fds *FdSet) IsSet(fd int) bool {
return fds.Bits[fd/NFDBITS]&(1<<(uintptr(fd)%NFDBITS)) != 0
}
// Zero clears the set fds.
func (fds *FdSet) Zero() {
clear(fds.Bits[:])
}
================================================
FILE: vendor/golang.org/x/sys/unix/gccgo.go
================================================
// Copyright 2015 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.
//go:build gccgo && !aix && !hurd
package unix
import "syscall"
// We can't use the gc-syntax .s files for gccgo. On the plus side
// much of the functionality can be written directly in Go.
func realSyscallNoError(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r uintptr)
func realSyscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r, errno uintptr)
func SyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr) {
syscall.Entersyscall()
r := realSyscallNoError(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0)
syscall.Exitsyscall()
return r, 0
}
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
syscall.Entersyscall()
r, errno := realSyscall(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0)
syscall.Exitsyscall()
return r, 0, syscall.Errno(errno)
}
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) {
syscall.Entersyscall()
r, errno := realSyscall(trap, a1, a2, a3, a4, a5, a6, 0, 0, 0)
syscall.Exitsyscall()
return r, 0, syscall.Errno(errno)
}
func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) {
syscall.Entersyscall()
r, errno := realSyscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9)
syscall.Exitsyscall()
return r, 0, syscall.Errno(errno)
}
func RawSyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr) {
r := realSyscallNoError(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0)
return r, 0
}
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
r, errno := realSyscall(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0)
return r, 0, syscall.Errno(errno)
}
func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) {
r, errno := realSyscall(trap, a1, a2, a3, a4, a5, a6, 0, 0, 0)
return r, 0, syscall.Errno(errno)
}
================================================
FILE: vendor/golang.org/x/sys/unix/gccgo_c.c
================================================
// Copyright 2015 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.
//go:build gccgo && !aix && !hurd
#include
#include
#include
#define _STRINGIFY2_(x) #x
#define _STRINGIFY_(x) _STRINGIFY2_(x)
#define GOSYM_PREFIX _STRINGIFY_(__USER_LABEL_PREFIX__)
// Call syscall from C code because the gccgo support for calling from
// Go to C does not support varargs functions.
struct ret {
uintptr_t r;
uintptr_t err;
};
struct ret gccgoRealSyscall(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9)
__asm__(GOSYM_PREFIX GOPKGPATH ".realSyscall");
struct ret
gccgoRealSyscall(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9)
{
struct ret r;
errno = 0;
r.r = syscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9);
r.err = errno;
return r;
}
uintptr_t gccgoRealSyscallNoError(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9)
__asm__(GOSYM_PREFIX GOPKGPATH ".realSyscallNoError");
uintptr_t
gccgoRealSyscallNoError(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9)
{
return syscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}
================================================
FILE: vendor/golang.org/x/sys/unix/gccgo_linux_amd64.go
================================================
// Copyright 2015 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.
//go:build gccgo && linux && amd64
package unix
import "syscall"
//extern gettimeofday
func realGettimeofday(*Timeval, *byte) int32
func gettimeofday(tv *Timeval) (err syscall.Errno) {
r := realGettimeofday(tv, nil)
if r < 0 {
return syscall.GetErrno()
}
return 0
}
================================================
FILE: vendor/golang.org/x/sys/unix/ifreq_linux.go
================================================
// Copyright 2021 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.
//go:build linux
package unix
import (
"unsafe"
)
// Helpers for dealing with ifreq since it contains a union and thus requires a
// lot of unsafe.Pointer casts to use properly.
// An Ifreq is a type-safe wrapper around the raw ifreq struct. An Ifreq
// contains an interface name and a union of arbitrary data which can be
// accessed using the Ifreq's methods. To create an Ifreq, use the NewIfreq
// function.
//
// Use the Name method to access the stored interface name. The union data
// fields can be get and set using the following methods:
// - Uint16/SetUint16: flags
// - Uint32/SetUint32: ifindex, metric, mtu
type Ifreq struct{ raw ifreq }
// NewIfreq creates an Ifreq with the input network interface name after
// validating the name does not exceed IFNAMSIZ-1 (trailing NULL required)
// bytes.
func NewIfreq(name string) (*Ifreq, error) {
// Leave room for terminating NULL byte.
if len(name) >= IFNAMSIZ {
return nil, EINVAL
}
var ifr ifreq
copy(ifr.Ifrn[:], name)
return &Ifreq{raw: ifr}, nil
}
// TODO(mdlayher): get/set methods for hardware address sockaddr, char array, etc.
// Name returns the interface name associated with the Ifreq.
func (ifr *Ifreq) Name() string {
return ByteSliceToString(ifr.raw.Ifrn[:])
}
// According to netdevice(7), only AF_INET addresses are returned for numerous
// sockaddr ioctls. For convenience, we expose these as Inet4Addr since the Port
// field and other data is always empty.
// Inet4Addr returns the Ifreq union data from an embedded sockaddr as a C
// in_addr/Go []byte (4-byte IPv4 address) value. If the sockaddr family is not
// AF_INET, an error is returned.
func (ifr *Ifreq) Inet4Addr() ([]byte, error) {
raw := *(*RawSockaddrInet4)(unsafe.Pointer(&ifr.raw.Ifru[:SizeofSockaddrInet4][0]))
if raw.Family != AF_INET {
// Cannot safely interpret raw.Addr bytes as an IPv4 address.
return nil, EINVAL
}
return raw.Addr[:], nil
}
// SetInet4Addr sets a C in_addr/Go []byte (4-byte IPv4 address) value in an
// embedded sockaddr within the Ifreq's union data. v must be 4 bytes in length
// or an error will be returned.
func (ifr *Ifreq) SetInet4Addr(v []byte) error {
if len(v) != 4 {
return EINVAL
}
var addr [4]byte
copy(addr[:], v)
ifr.clear()
*(*RawSockaddrInet4)(
unsafe.Pointer(&ifr.raw.Ifru[:SizeofSockaddrInet4][0]),
) = RawSockaddrInet4{
// Always set IP family as ioctls would require it anyway.
Family: AF_INET,
Addr: addr,
}
return nil
}
// Uint16 returns the Ifreq union data as a C short/Go uint16 value.
func (ifr *Ifreq) Uint16() uint16 {
return *(*uint16)(unsafe.Pointer(&ifr.raw.Ifru[:2][0]))
}
// SetUint16 sets a C short/Go uint16 value as the Ifreq's union data.
func (ifr *Ifreq) SetUint16(v uint16) {
ifr.clear()
*(*uint16)(unsafe.Pointer(&ifr.raw.Ifru[:2][0])) = v
}
// Uint32 returns the Ifreq union data as a C int/Go uint32 value.
func (ifr *Ifreq) Uint32() uint32 {
return *(*uint32)(unsafe.Pointer(&ifr.raw.Ifru[:4][0]))
}
// SetUint32 sets a C int/Go uint32 value as the Ifreq's union data.
func (ifr *Ifreq) SetUint32(v uint32) {
ifr.clear()
*(*uint32)(unsafe.Pointer(&ifr.raw.Ifru[:4][0])) = v
}
// clear zeroes the ifreq's union field to prevent trailing garbage data from
// being sent to the kernel if an ifreq is reused.
func (ifr *Ifreq) clear() {
clear(ifr.raw.Ifru[:])
}
// TODO(mdlayher): export as IfreqData? For now we can provide helpers such as
// IoctlGetEthtoolDrvinfo which use these APIs under the hood.
// An ifreqData is an Ifreq which carries pointer data. To produce an ifreqData,
// use the Ifreq.withData method.
type ifreqData struct {
name [IFNAMSIZ]byte
// A type separate from ifreq is required in order to comply with the
// unsafe.Pointer rules since the "pointer-ness" of data would not be
// preserved if it were cast into the byte array of a raw ifreq.
data unsafe.Pointer
// Pad to the same size as ifreq.
_ [len(ifreq{}.Ifru) - SizeofPtr]byte
}
// withData produces an ifreqData with the pointer p set for ioctls which require
// arbitrary pointer data.
func (ifr Ifreq) withData(p unsafe.Pointer) ifreqData {
return ifreqData{
name: ifr.raw.Ifrn,
data: p,
}
}
================================================
FILE: vendor/golang.org/x/sys/unix/ioctl_linux.go
================================================
// Copyright 2021 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.
package unix
import "unsafe"
// IoctlRetInt performs an ioctl operation specified by req on a device
// associated with opened file descriptor fd, and returns a non-negative
// integer that is returned by the ioctl syscall.
func IoctlRetInt(fd int, req uint) (int, error) {
ret, _, err := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), 0)
if err != 0 {
return 0, err
}
return int(ret), nil
}
func IoctlGetUint32(fd int, req uint) (uint32, error) {
var value uint32
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
return value, err
}
func IoctlGetRTCTime(fd int) (*RTCTime, error) {
var value RTCTime
err := ioctlPtr(fd, RTC_RD_TIME, unsafe.Pointer(&value))
return &value, err
}
func IoctlSetRTCTime(fd int, value *RTCTime) error {
return ioctlPtr(fd, RTC_SET_TIME, unsafe.Pointer(value))
}
func IoctlGetRTCWkAlrm(fd int) (*RTCWkAlrm, error) {
var value RTCWkAlrm
err := ioctlPtr(fd, RTC_WKALM_RD, unsafe.Pointer(&value))
return &value, err
}
func IoctlSetRTCWkAlrm(fd int, value *RTCWkAlrm) error {
return ioctlPtr(fd, RTC_WKALM_SET, unsafe.Pointer(value))
}
// IoctlGetEthtoolDrvinfo fetches ethtool driver information for the network
// device specified by ifname.
func IoctlGetEthtoolDrvinfo(fd int, ifname string) (*EthtoolDrvinfo, error) {
ifr, err := NewIfreq(ifname)
if err != nil {
return nil, err
}
value := EthtoolDrvinfo{Cmd: ETHTOOL_GDRVINFO}
ifrd := ifr.withData(unsafe.Pointer(&value))
err = ioctlIfreqData(fd, SIOCETHTOOL, &ifrd)
return &value, err
}
// IoctlGetEthtoolTsInfo fetches ethtool timestamping and PHC
// association for the network device specified by ifname.
func IoctlGetEthtoolTsInfo(fd int, ifname string) (*EthtoolTsInfo, error) {
ifr, err := NewIfreq(ifname)
if err != nil {
return nil, err
}
value := EthtoolTsInfo{Cmd: ETHTOOL_GET_TS_INFO}
ifrd := ifr.withData(unsafe.Pointer(&value))
err = ioctlIfreqData(fd, SIOCETHTOOL, &ifrd)
return &value, err
}
// IoctlGetHwTstamp retrieves the hardware timestamping configuration
// for the network device specified by ifname.
func IoctlGetHwTstamp(fd int, ifname string) (*HwTstampConfig, error) {
ifr, err := NewIfreq(ifname)
if err != nil {
return nil, err
}
value := HwTstampConfig{}
ifrd := ifr.withData(unsafe.Pointer(&value))
err = ioctlIfreqData(fd, SIOCGHWTSTAMP, &ifrd)
return &value, err
}
// IoctlSetHwTstamp updates the hardware timestamping configuration for
// the network device specified by ifname.
func IoctlSetHwTstamp(fd int, ifname string, cfg *HwTstampConfig) error {
ifr, err := NewIfreq(ifname)
if err != nil {
return err
}
ifrd := ifr.withData(unsafe.Pointer(cfg))
return ioctlIfreqData(fd, SIOCSHWTSTAMP, &ifrd)
}
// FdToClockID derives the clock ID from the file descriptor number
// - see clock_gettime(3), FD_TO_CLOCKID macros. The resulting ID is
// suitable for system calls like ClockGettime.
func FdToClockID(fd int) int32 { return int32((int(^fd) << 3) | 3) }
// IoctlPtpClockGetcaps returns the description of a given PTP device.
func IoctlPtpClockGetcaps(fd int) (*PtpClockCaps, error) {
var value PtpClockCaps
err := ioctlPtr(fd, PTP_CLOCK_GETCAPS2, unsafe.Pointer(&value))
return &value, err
}
// IoctlPtpSysOffsetPrecise returns a description of the clock
// offset compared to the system clock.
func IoctlPtpSysOffsetPrecise(fd int) (*PtpSysOffsetPrecise, error) {
var value PtpSysOffsetPrecise
err := ioctlPtr(fd, PTP_SYS_OFFSET_PRECISE2, unsafe.Pointer(&value))
return &value, err
}
// IoctlPtpSysOffsetExtended returns an extended description of the
// clock offset compared to the system clock. The samples parameter
// specifies the desired number of measurements.
func IoctlPtpSysOffsetExtended(fd int, samples uint) (*PtpSysOffsetExtended, error) {
value := PtpSysOffsetExtended{Samples: uint32(samples)}
err := ioctlPtr(fd, PTP_SYS_OFFSET_EXTENDED2, unsafe.Pointer(&value))
return &value, err
}
// IoctlPtpPinGetfunc returns the configuration of the specified
// I/O pin on given PTP device.
func IoctlPtpPinGetfunc(fd int, index uint) (*PtpPinDesc, error) {
value := PtpPinDesc{Index: uint32(index)}
err := ioctlPtr(fd, PTP_PIN_GETFUNC2, unsafe.Pointer(&value))
return &value, err
}
// IoctlPtpPinSetfunc updates configuration of the specified PTP
// I/O pin.
func IoctlPtpPinSetfunc(fd int, pd *PtpPinDesc) error {
return ioctlPtr(fd, PTP_PIN_SETFUNC2, unsafe.Pointer(pd))
}
// IoctlPtpPeroutRequest configures the periodic output mode of the
// PTP I/O pins.
func IoctlPtpPeroutRequest(fd int, r *PtpPeroutRequest) error {
return ioctlPtr(fd, PTP_PEROUT_REQUEST2, unsafe.Pointer(r))
}
// IoctlPtpExttsRequest configures the external timestamping mode
// of the PTP I/O pins.
func IoctlPtpExttsRequest(fd int, r *PtpExttsRequest) error {
return ioctlPtr(fd, PTP_EXTTS_REQUEST2, unsafe.Pointer(r))
}
// IoctlGetWatchdogInfo fetches information about a watchdog device from the
// Linux watchdog API. For more information, see:
// https://www.kernel.org/doc/html/latest/watchdog/watchdog-api.html.
func IoctlGetWatchdogInfo(fd int) (*WatchdogInfo, error) {
var value WatchdogInfo
err := ioctlPtr(fd, WDIOC_GETSUPPORT, unsafe.Pointer(&value))
return &value, err
}
// IoctlWatchdogKeepalive issues a keepalive ioctl to a watchdog device. For
// more information, see:
// https://www.kernel.org/doc/html/latest/watchdog/watchdog-api.html.
func IoctlWatchdogKeepalive(fd int) error {
// arg is ignored and not a pointer, so ioctl is fine instead of ioctlPtr.
return ioctl(fd, WDIOC_KEEPALIVE, 0)
}
// IoctlFileCloneRange performs an FICLONERANGE ioctl operation to clone the
// range of data conveyed in value to the file associated with the file
// descriptor destFd. See the ioctl_ficlonerange(2) man page for details.
func IoctlFileCloneRange(destFd int, value *FileCloneRange) error {
return ioctlPtr(destFd, FICLONERANGE, unsafe.Pointer(value))
}
// IoctlFileClone performs an FICLONE ioctl operation to clone the entire file
// associated with the file description srcFd to the file associated with the
// file descriptor destFd. See the ioctl_ficlone(2) man page for details.
func IoctlFileClone(destFd, srcFd int) error {
return ioctl(destFd, FICLONE, uintptr(srcFd))
}
type FileDedupeRange struct {
Src_offset uint64
Src_length uint64
Reserved1 uint16
Reserved2 uint32
Info []FileDedupeRangeInfo
}
type FileDedupeRangeInfo struct {
Dest_fd int64
Dest_offset uint64
Bytes_deduped uint64
Status int32
Reserved uint32
}
// IoctlFileDedupeRange performs an FIDEDUPERANGE ioctl operation to share the
// range of data conveyed in value from the file associated with the file
// descriptor srcFd to the value.Info destinations. See the
// ioctl_fideduperange(2) man page for details.
func IoctlFileDedupeRange(srcFd int, value *FileDedupeRange) error {
buf := make([]byte, SizeofRawFileDedupeRange+
len(value.Info)*SizeofRawFileDedupeRangeInfo)
rawrange := (*RawFileDedupeRange)(unsafe.Pointer(&buf[0]))
rawrange.Src_offset = value.Src_offset
rawrange.Src_length = value.Src_length
rawrange.Dest_count = uint16(len(value.Info))
rawrange.Reserved1 = value.Reserved1
rawrange.Reserved2 = value.Reserved2
for i := range value.Info {
rawinfo := (*RawFileDedupeRangeInfo)(unsafe.Pointer(
uintptr(unsafe.Pointer(&buf[0])) + uintptr(SizeofRawFileDedupeRange) +
uintptr(i*SizeofRawFileDedupeRangeInfo)))
rawinfo.Dest_fd = value.Info[i].Dest_fd
rawinfo.Dest_offset = value.Info[i].Dest_offset
rawinfo.Bytes_deduped = value.Info[i].Bytes_deduped
rawinfo.Status = value.Info[i].Status
rawinfo.Reserved = value.Info[i].Reserved
}
err := ioctlPtr(srcFd, FIDEDUPERANGE, unsafe.Pointer(&buf[0]))
// Output
for i := range value.Info {
rawinfo := (*RawFileDedupeRangeInfo)(unsafe.Pointer(
uintptr(unsafe.Pointer(&buf[0])) + uintptr(SizeofRawFileDedupeRange) +
uintptr(i*SizeofRawFileDedupeRangeInfo)))
value.Info[i].Dest_fd = rawinfo.Dest_fd
value.Info[i].Dest_offset = rawinfo.Dest_offset
value.Info[i].Bytes_deduped = rawinfo.Bytes_deduped
value.Info[i].Status = rawinfo.Status
value.Info[i].Reserved = rawinfo.Reserved
}
return err
}
func IoctlHIDGetDesc(fd int, value *HIDRawReportDescriptor) error {
return ioctlPtr(fd, HIDIOCGRDESC, unsafe.Pointer(value))
}
func IoctlHIDGetRawInfo(fd int) (*HIDRawDevInfo, error) {
var value HIDRawDevInfo
err := ioctlPtr(fd, HIDIOCGRAWINFO, unsafe.Pointer(&value))
return &value, err
}
func IoctlHIDGetRawName(fd int) (string, error) {
var value [_HIDIOCGRAWNAME_LEN]byte
err := ioctlPtr(fd, _HIDIOCGRAWNAME, unsafe.Pointer(&value[0]))
return ByteSliceToString(value[:]), err
}
func IoctlHIDGetRawPhys(fd int) (string, error) {
var value [_HIDIOCGRAWPHYS_LEN]byte
err := ioctlPtr(fd, _HIDIOCGRAWPHYS, unsafe.Pointer(&value[0]))
return ByteSliceToString(value[:]), err
}
func IoctlHIDGetRawUniq(fd int) (string, error) {
var value [_HIDIOCGRAWUNIQ_LEN]byte
err := ioctlPtr(fd, _HIDIOCGRAWUNIQ, unsafe.Pointer(&value[0]))
return ByteSliceToString(value[:]), err
}
// IoctlIfreq performs an ioctl using an Ifreq structure for input and/or
// output. See the netdevice(7) man page for details.
func IoctlIfreq(fd int, req uint, value *Ifreq) error {
// It is possible we will add more fields to *Ifreq itself later to prevent
// misuse, so pass the raw *ifreq directly.
return ioctlPtr(fd, req, unsafe.Pointer(&value.raw))
}
// TODO(mdlayher): export if and when IfreqData is exported.
// ioctlIfreqData performs an ioctl using an ifreqData structure for input
// and/or output. See the netdevice(7) man page for details.
func ioctlIfreqData(fd int, req uint, value *ifreqData) error {
// The memory layout of IfreqData (type-safe) and ifreq (not type-safe) are
// identical so pass *IfreqData directly.
return ioctlPtr(fd, req, unsafe.Pointer(value))
}
// IoctlKCMClone attaches a new file descriptor to a multiplexor by cloning an
// existing KCM socket, returning a structure containing the file descriptor of
// the new socket.
func IoctlKCMClone(fd int) (*KCMClone, error) {
var info KCMClone
if err := ioctlPtr(fd, SIOCKCMCLONE, unsafe.Pointer(&info)); err != nil {
return nil, err
}
return &info, nil
}
// IoctlKCMAttach attaches a TCP socket and associated BPF program file
// descriptor to a multiplexor.
func IoctlKCMAttach(fd int, info KCMAttach) error {
return ioctlPtr(fd, SIOCKCMATTACH, unsafe.Pointer(&info))
}
// IoctlKCMUnattach unattaches a TCP socket file descriptor from a multiplexor.
func IoctlKCMUnattach(fd int, info KCMUnattach) error {
return ioctlPtr(fd, SIOCKCMUNATTACH, unsafe.Pointer(&info))
}
// IoctlLoopGetStatus64 gets the status of the loop device associated with the
// file descriptor fd using the LOOP_GET_STATUS64 operation.
func IoctlLoopGetStatus64(fd int) (*LoopInfo64, error) {
var value LoopInfo64
if err := ioctlPtr(fd, LOOP_GET_STATUS64, unsafe.Pointer(&value)); err != nil {
return nil, err
}
return &value, nil
}
// IoctlLoopSetStatus64 sets the status of the loop device associated with the
// file descriptor fd using the LOOP_SET_STATUS64 operation.
func IoctlLoopSetStatus64(fd int, value *LoopInfo64) error {
return ioctlPtr(fd, LOOP_SET_STATUS64, unsafe.Pointer(value))
}
// IoctlLoopConfigure configures all loop device parameters in a single step
func IoctlLoopConfigure(fd int, value *LoopConfig) error {
return ioctlPtr(fd, LOOP_CONFIGURE, unsafe.Pointer(value))
}
================================================
FILE: vendor/golang.org/x/sys/unix/ioctl_signed.go
================================================
// Copyright 2018 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.
//go:build aix || solaris
package unix
import "unsafe"
// ioctl itself should not be exposed directly, but additional get/set
// functions for specific types are permissible.
// IoctlSetInt performs an ioctl operation which sets an integer value
// on fd, using the specified request number.
func IoctlSetInt(fd int, req int, value int) error {
return ioctl(fd, req, uintptr(value))
}
// IoctlSetPointerInt performs an ioctl operation which sets an
// integer value on fd, using the specified request number. The ioctl
// argument is called with a pointer to the integer value, rather than
// passing the integer value directly.
func IoctlSetPointerInt(fd int, req int, value int) error {
v := int32(value)
return ioctlPtr(fd, req, unsafe.Pointer(&v))
}
// IoctlSetString performs an ioctl operation which sets a string value
// on fd, using the specified request number.
func IoctlSetString(fd int, req int, value string) error {
bs := append([]byte(value), 0)
return ioctlPtr(fd, req, unsafe.Pointer(&bs[0]))
}
// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
//
// To change fd's window size, the req argument should be TIOCSWINSZ.
func IoctlSetWinsize(fd int, req int, value *Winsize) error {
// TODO: if we get the chance, remove the req parameter and
// hardcode TIOCSWINSZ.
return ioctlPtr(fd, req, unsafe.Pointer(value))
}
// IoctlSetTermios performs an ioctl on fd with a *Termios.
//
// The req value will usually be TCSETA or TIOCSETA.
func IoctlSetTermios(fd int, req int, value *Termios) error {
// TODO: if we get the chance, remove the req parameter.
return ioctlPtr(fd, req, unsafe.Pointer(value))
}
// IoctlGetInt performs an ioctl operation which gets an integer value
// from fd, using the specified request number.
//
// A few ioctl requests use the return value as an output parameter;
// for those, IoctlRetInt should be used instead of this function.
func IoctlGetInt(fd int, req int) (int, error) {
var value int
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
return value, err
}
func IoctlGetWinsize(fd int, req int) (*Winsize, error) {
var value Winsize
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
return &value, err
}
func IoctlGetTermios(fd int, req int) (*Termios, error) {
var value Termios
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
return &value, err
}
================================================
FILE: vendor/golang.org/x/sys/unix/ioctl_unsigned.go
================================================
// Copyright 2018 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.
//go:build darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd
package unix
import "unsafe"
// ioctl itself should not be exposed directly, but additional get/set
// functions for specific types are permissible.
// IoctlSetInt performs an ioctl operation which sets an integer value
// on fd, using the specified request number.
func IoctlSetInt(fd int, req uint, value int) error {
return ioctl(fd, req, uintptr(value))
}
// IoctlSetPointerInt performs an ioctl operation which sets an
// integer value on fd, using the specified request number. The ioctl
// argument is called with a pointer to the integer value, rather than
// passing the integer value directly.
func IoctlSetPointerInt(fd int, req uint, value int) error {
v := int32(value)
return ioctlPtr(fd, req, unsafe.Pointer(&v))
}
// IoctlSetString performs an ioctl operation which sets a string value
// on fd, using the specified request number.
func IoctlSetString(fd int, req uint, value string) error {
bs := append([]byte(value), 0)
return ioctlPtr(fd, req, unsafe.Pointer(&bs[0]))
}
// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
//
// To change fd's window size, the req argument should be TIOCSWINSZ.
func IoctlSetWinsize(fd int, req uint, value *Winsize) error {
// TODO: if we get the chance, remove the req parameter and
// hardcode TIOCSWINSZ.
return ioctlPtr(fd, req, unsafe.Pointer(value))
}
// IoctlSetTermios performs an ioctl on fd with a *Termios.
//
// The req value will usually be TCSETA or TIOCSETA.
func IoctlSetTermios(fd int, req uint, value *Termios) error {
// TODO: if we get the chance, remove the req parameter.
return ioctlPtr(fd, req, unsafe.Pointer(value))
}
// IoctlGetInt performs an ioctl operation which gets an integer value
// from fd, using the specified request number.
//
// A few ioctl requests use the return value as an output parameter;
// for those, IoctlRetInt should be used instead of this function.
func IoctlGetInt(fd int, req uint) (int, error) {
var value int
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
return value, err
}
func IoctlGetWinsize(fd int, req uint) (*Winsize, error) {
var value Winsize
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
return &value, err
}
func IoctlGetTermios(fd int, req uint) (*Termios, error) {
var value Termios
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
return &value, err
}
================================================
FILE: vendor/golang.org/x/sys/unix/ioctl_zos.go
================================================
// Copyright 2020 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.
//go:build zos && s390x
package unix
import (
"runtime"
"unsafe"
)
// ioctl itself should not be exposed directly, but additional get/set
// functions for specific types are permissible.
// IoctlSetInt performs an ioctl operation which sets an integer value
// on fd, using the specified request number.
func IoctlSetInt(fd int, req int, value int) error {
return ioctl(fd, req, uintptr(value))
}
// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
//
// To change fd's window size, the req argument should be TIOCSWINSZ.
func IoctlSetWinsize(fd int, req int, value *Winsize) error {
// TODO: if we get the chance, remove the req parameter and
// hardcode TIOCSWINSZ.
return ioctlPtr(fd, req, unsafe.Pointer(value))
}
// IoctlSetTermios performs an ioctl on fd with a *Termios.
//
// The req value is expected to be TCSETS, TCSETSW, or TCSETSF
func IoctlSetTermios(fd int, req int, value *Termios) error {
if (req != TCSETS) && (req != TCSETSW) && (req != TCSETSF) {
return ENOSYS
}
err := Tcsetattr(fd, int(req), value)
runtime.KeepAlive(value)
return err
}
// IoctlGetInt performs an ioctl operation which gets an integer value
// from fd, using the specified request number.
//
// A few ioctl requests use the return value as an output parameter;
// for those, IoctlRetInt should be used instead of this function.
func IoctlGetInt(fd int, req int) (int, error) {
var value int
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
return value, err
}
func IoctlGetWinsize(fd int, req int) (*Winsize, error) {
var value Winsize
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
return &value, err
}
// IoctlGetTermios performs an ioctl on fd with a *Termios.
//
// The req value is expected to be TCGETS
func IoctlGetTermios(fd int, req int) (*Termios, error) {
var value Termios
if req != TCGETS {
return &value, ENOSYS
}
err := Tcgetattr(fd, &value)
return &value, err
}
================================================
FILE: vendor/golang.org/x/sys/unix/mkall.sh
================================================
#!/usr/bin/env bash
# Copyright 2009 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 script runs or (given -n) prints suggested commands to generate files for
# the Architecture/OS specified by the GOARCH and GOOS environment variables.
# See README.md for more information about how the build system works.
GOOSARCH="${GOOS}_${GOARCH}"
# defaults
mksyscall="go run mksyscall.go"
mkerrors="./mkerrors.sh"
zerrors="zerrors_$GOOSARCH.go"
mksysctl=""
zsysctl="zsysctl_$GOOSARCH.go"
mksysnum=
mktypes=
mkasm=
run="sh"
cmd=""
case "$1" in
-syscalls)
for i in zsyscall*go
do
# Run the command line that appears in the first line
# of the generated file to regenerate it.
sed 1q $i | sed 's;^// ;;' | sh > _$i && gofmt < _$i > $i
rm _$i
done
exit 0
;;
-n)
run="cat"
cmd="echo"
shift
esac
case "$#" in
0)
;;
*)
echo 'usage: mkall.sh [-n]' 1>&2
exit 2
esac
if [[ "$GOOS" = "linux" ]]; then
# Use the Docker-based build system
# Files generated through docker (use $cmd so you can Ctl-C the build or run)
set -e
$cmd docker build --tag generate:$GOOS $GOOS
$cmd docker run --interactive --tty --volume $(cd -- "$(dirname -- "$0")/.." && pwd):/build generate:$GOOS
exit
fi
GOOSARCH_in=syscall_$GOOSARCH.go
case "$GOOSARCH" in
_* | *_ | _)
echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2
exit 1
;;
aix_ppc)
mkerrors="$mkerrors -maix32"
mksyscall="go run mksyscall_aix_ppc.go -aix"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
aix_ppc64)
mkerrors="$mkerrors -maix64"
mksyscall="go run mksyscall_aix_ppc64.go -aix"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
darwin_amd64)
mkerrors="$mkerrors -m64"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
mkasm="go run mkasm.go"
;;
darwin_arm64)
mkerrors="$mkerrors -m64"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
mkasm="go run mkasm.go"
;;
dragonfly_amd64)
mkerrors="$mkerrors -m64"
mksyscall="go run mksyscall.go -dragonfly"
mksysnum="go run mksysnum.go 'https://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/sys/kern/syscalls.master'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
freebsd_386)
mkerrors="$mkerrors -m32"
mksyscall="go run mksyscall.go -l32"
mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
freebsd_amd64)
mkerrors="$mkerrors -m64"
mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
freebsd_arm)
mkerrors="$mkerrors"
mksyscall="go run mksyscall.go -l32 -arm"
mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
# Let the type of C char be signed for making the bare syscall
# API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
freebsd_arm64)
mkerrors="$mkerrors -m64"
mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
freebsd_riscv64)
mkerrors="$mkerrors -m64"
mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
netbsd_386)
mkerrors="$mkerrors -m32"
mksyscall="go run mksyscall.go -l32 -netbsd"
mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
netbsd_amd64)
mkerrors="$mkerrors -m64"
mksyscall="go run mksyscall.go -netbsd"
mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
netbsd_arm)
mkerrors="$mkerrors"
mksyscall="go run mksyscall.go -l32 -netbsd -arm"
mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'"
# Let the type of C char be signed for making the bare syscall
# API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
netbsd_arm64)
mkerrors="$mkerrors -m64"
mksyscall="go run mksyscall.go -netbsd"
mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
openbsd_386)
mkasm="go run mkasm.go"
mkerrors="$mkerrors -m32"
mksyscall="go run mksyscall.go -l32 -openbsd -libc"
mksysctl="go run mksysctl_openbsd.go"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
openbsd_amd64)
mkasm="go run mkasm.go"
mkerrors="$mkerrors -m64"
mksyscall="go run mksyscall.go -openbsd -libc"
mksysctl="go run mksysctl_openbsd.go"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
openbsd_arm)
mkasm="go run mkasm.go"
mkerrors="$mkerrors"
mksyscall="go run mksyscall.go -l32 -openbsd -arm -libc"
mksysctl="go run mksysctl_openbsd.go"
# Let the type of C char be signed for making the bare syscall
# API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
openbsd_arm64)
mkasm="go run mkasm.go"
mkerrors="$mkerrors -m64"
mksyscall="go run mksyscall.go -openbsd -libc"
mksysctl="go run mksysctl_openbsd.go"
# Let the type of C char be signed for making the bare syscall
# API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
openbsd_mips64)
mkasm="go run mkasm.go"
mkerrors="$mkerrors -m64"
mksyscall="go run mksyscall.go -openbsd -libc"
mksysctl="go run mksysctl_openbsd.go"
# Let the type of C char be signed for making the bare syscall
# API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
openbsd_ppc64)
mkasm="go run mkasm.go"
mkerrors="$mkerrors -m64"
mksyscall="go run mksyscall.go -openbsd -libc"
mksysctl="go run mksysctl_openbsd.go"
# Let the type of C char be signed for making the bare syscall
# API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
openbsd_riscv64)
mkasm="go run mkasm.go"
mkerrors="$mkerrors -m64"
mksyscall="go run mksyscall.go -openbsd -libc"
mksysctl="go run mksysctl_openbsd.go"
# Let the type of C char be signed for making the bare syscall
# API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
solaris_amd64)
mksyscall="go run mksyscall_solaris.go"
mkerrors="$mkerrors -m64"
mksysnum=
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
illumos_amd64)
mksyscall="go run mksyscall_solaris.go"
mkerrors=
mksysnum=
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
*)
echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
exit 1
;;
esac
(
if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi
case "$GOOS" in
*)
syscall_goos="syscall_$GOOS.go"
case "$GOOS" in
darwin | dragonfly | freebsd | netbsd | openbsd)
syscall_goos="syscall_bsd.go $syscall_goos"
;;
esac
if [ -n "$mksyscall" ]; then
if [ "$GOOSARCH" == "aix_ppc64" ]; then
# aix/ppc64 script generates files instead of writing to stdin.
echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in && gofmt -w zsyscall_$GOOSARCH.go && gofmt -w zsyscall_"$GOOSARCH"_gccgo.go && gofmt -w zsyscall_"$GOOSARCH"_gc.go " ;
elif [ "$GOOS" == "illumos" ]; then
# illumos code generation requires a --illumos switch
echo "$mksyscall -illumos -tags illumos,$GOARCH syscall_illumos.go |gofmt > zsyscall_illumos_$GOARCH.go";
# illumos implies solaris, so solaris code generation is also required
echo "$mksyscall -tags solaris,$GOARCH syscall_solaris.go syscall_solaris_$GOARCH.go |gofmt >zsyscall_solaris_$GOARCH.go";
else
echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go";
fi
fi
esac
if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go | go run mkpost.go > ztypes_$GOOSARCH.go"; fi
if [ -n "$mkasm" ]; then echo "$mkasm $GOOS $GOARCH"; fi
) | $run
================================================
FILE: vendor/golang.org/x/sys/unix/mkerrors.sh
================================================
#!/usr/bin/env bash
# Copyright 2009 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.
# Generate Go code listing errors and other #defined constant
# values (ENAMETOOLONG etc.), by asking the preprocessor
# about the definitions.
unset LANG
export LC_ALL=C
export LC_CTYPE=C
if test -z "$GOARCH" -o -z "$GOOS"; then
echo 1>&2 "GOARCH or GOOS not defined in environment"
exit 1
fi
# Check that we are using the new build system if we should
if [[ "$GOOS" = "linux" ]] && [[ "$GOLANG_SYS_BUILD" != "docker" ]]; then
echo 1>&2 "In the Docker based build system, mkerrors should not be called directly."
echo 1>&2 "See README.md"
exit 1
fi
if [[ "$GOOS" = "aix" ]]; then
CC=${CC:-gcc}
else
CC=${CC:-cc}
fi
if [[ "$GOOS" = "solaris" ]]; then
# Assumes GNU versions of utilities in PATH.
export PATH=/usr/gnu/bin:$PATH
fi
uname=$(uname)
includes_AIX='
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define AF_LOCAL AF_UNIX
'
includes_Darwin='
#define _DARWIN_C_SOURCE
#define KERNEL 1
#define _DARWIN_USE_64_BIT_INODE
#define __APPLE_USE_RFC_3542
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// for backwards compatibility because moved TIOCREMOTE to Kernel.framework after MacOSX12.0.sdk.
#define TIOCREMOTE 0x80047469
'
includes_DragonFly='
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
'
includes_FreeBSD='
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#if __FreeBSD__ >= 10
#define IFT_CARP 0xf8 // IFT_CARP is deprecated in FreeBSD 10
#undef SIOCAIFADDR
#define SIOCAIFADDR _IOW(105, 26, struct oifaliasreq) // ifaliasreq contains if_data
#undef SIOCSIFPHYADDR
#define SIOCSIFPHYADDR _IOW(105, 70, struct oifaliasreq) // ifaliasreq contains if_data
#endif
'
includes_Linux='
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#ifndef __LP64__
#define _FILE_OFFSET_BITS 64
#endif
#define _GNU_SOURCE
// See the description in unix/linux/types.go
#if defined(__ARM_EABI__) || \
(defined(__mips__) && (_MIPS_SIM == _ABIO32)) || \
(defined(__powerpc__) && (!defined(__powerpc64__)))
# ifdef _TIME_BITS
# undef _TIME_BITS
# endif
# define _TIME_BITS 32
#endif
// is broken on powerpc64, as it fails to include definitions of
// these structures. We just include them copied from .
#if defined(__powerpc__)
struct sgttyb {
char sg_ispeed;
char sg_ospeed;
char sg_erase;
char sg_kill;
short sg_flags;
};
struct tchars {
char t_intrc;
char t_quitc;
char t_startc;
char t_stopc;
char t_eofc;
char t_brkc;
};
struct ltchars {
char t_suspc;
char t_dsuspc;
char t_rprntc;
char t_flushc;
char t_werasc;
char t_lnextc;
};
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#if defined(__sparc__)
// On sparc{,64}, the kernel defines struct termios2 itself which clashes with the
// definition in glibc. As only the error constants are needed here, include the
// generic termibits.h (which is included by termbits.h on sparc).
#include
#else
#include
#endif
#ifndef PTRACE_GETREGS
#define PTRACE_GETREGS 0xc
#endif
#ifndef PTRACE_SETREGS
#define PTRACE_SETREGS 0xd
#endif
#ifdef SOL_BLUETOOTH
// SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h
// but it is already in bluetooth_linux.go
#undef SOL_BLUETOOTH
#endif
// Certain constants are missing from the fs/crypto UAPI
#define FS_KEY_DESC_PREFIX "fscrypt:"
#define FS_KEY_DESC_PREFIX_SIZE 8
#define FS_MAX_KEY_SIZE 64
// The code generator produces -0x1 for (~0), but an unsigned value is necessary
// for the tipc_subscr timeout __u32 field.
#undef TIPC_WAIT_FOREVER
#define TIPC_WAIT_FOREVER 0xffffffff
// Copied from linux/netfilter/nf_nat.h
// Including linux/netfilter/nf_nat.h here causes conflicts between linux/in.h
// and netinet/in.h.
#define NF_NAT_RANGE_MAP_IPS (1 << 0)
#define NF_NAT_RANGE_PROTO_SPECIFIED (1 << 1)
#define NF_NAT_RANGE_PROTO_RANDOM (1 << 2)
#define NF_NAT_RANGE_PERSISTENT (1 << 3)
#define NF_NAT_RANGE_PROTO_RANDOM_FULLY (1 << 4)
#define NF_NAT_RANGE_PROTO_OFFSET (1 << 5)
#define NF_NAT_RANGE_NETMAP (1 << 6)
#define NF_NAT_RANGE_PROTO_RANDOM_ALL \
(NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PROTO_RANDOM_FULLY)
#define NF_NAT_RANGE_MASK \
(NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED | \
NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PERSISTENT | \
NF_NAT_RANGE_PROTO_RANDOM_FULLY | NF_NAT_RANGE_PROTO_OFFSET | \
NF_NAT_RANGE_NETMAP)
// Copied from linux/hid.h.
// Keep in sync with the size of the referenced fields.
#define _HIDIOCGRAWNAME_LEN 128 // sizeof_field(struct hid_device, name)
#define _HIDIOCGRAWPHYS_LEN 64 // sizeof_field(struct hid_device, phys)
#define _HIDIOCGRAWUNIQ_LEN 64 // sizeof_field(struct hid_device, uniq)
#define _HIDIOCGRAWNAME HIDIOCGRAWNAME(_HIDIOCGRAWNAME_LEN)
#define _HIDIOCGRAWPHYS HIDIOCGRAWPHYS(_HIDIOCGRAWPHYS_LEN)
#define _HIDIOCGRAWUNIQ HIDIOCGRAWUNIQ(_HIDIOCGRAWUNIQ_LEN)
// Renamed in v6.16, commit c6d732c38f93 ("net: ethtool: remove duplicate defines for family info")
#define ETHTOOL_FAMILY_NAME ETHTOOL_GENL_NAME
#define ETHTOOL_FAMILY_VERSION ETHTOOL_GENL_VERSION
'
includes_NetBSD='
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// Needed since