1
0
mirror of https://github.com/go-task/task.git synced 2024-12-12 10:45:49 +02:00

Update dependencies

This commit is contained in:
Andrey Nering 2018-07-15 14:38:39 -03:00
parent c541356289
commit ab8549adea
33 changed files with 657 additions and 264 deletions

82
Gopkg.lock generated
View File

@ -3,129 +3,185 @@
[[projects]]
branch = "master"
digest = "1:147fe67eb5dcb4f1a182992bf2a9b00ca4de3f4b8193bda0c89a9fdbb9db6ad6"
name = "github.com/Masterminds/semver"
packages = ["."]
pruneopts = "NUT"
revision = "3c560837130448941620d7694991d3ec440aefc0"
[[projects]]
branch = "master"
digest = "1:43f9a530dfe36fb355b05fbc7a5712f8149a7f6bdfd131bc0ccc634e25c4dd1e"
name = "github.com/Masterminds/sprig"
packages = ["."]
pruneopts = "NUT"
revision = "6b2a58267f6a8b1dc8e2eb5519b984008fa85e8c"
version = "v2.15.0"
[[projects]]
digest = "1:975108e8d4f5dab096fc991326e96a5716ee8d02e5e7386bb4796171afc4ab9a"
name = "github.com/aokoli/goutils"
packages = ["."]
pruneopts = "NUT"
revision = "3391d3790d23d03408670993e957e8f408993c34"
version = "v1.0.1"
[[projects]]
digest = "1:a2c1d0e43bd3baaa071d1b9ed72c27d78169b2b269f71c105ac4ba34b1be4a39"
name = "github.com/davecgh/go-spew"
packages = ["spew"]
pruneopts = "NUT"
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0"
[[projects]]
digest = "1:1bb197a3b5db4e06e00b7560f8e89836c486627f2a0338332ed37daa003d259e"
name = "github.com/google/uuid"
packages = ["."]
pruneopts = "NUT"
revision = "064e2069ce9c359c118179501254f67d7d37ba24"
version = "0.2"
[[projects]]
digest = "1:f5db19d350bd0b542d17f7e7cf4e7068bac416c08adb6a129b3c6d1db8211051"
name = "github.com/huandu/xstrings"
packages = ["."]
pruneopts = "NUT"
revision = "2bf18b218c51864a87384c06996e40ff9dcff8e1"
version = "v1.0.0"
[[projects]]
branch = "master"
digest = "1:65300ccc4bcb38b107b868155c303312978981e56bca707c81efec57575b5e06"
name = "github.com/imdario/mergo"
packages = ["."]
pruneopts = "NUT"
revision = "9316a62528ac99aaecb4e47eadd6dc8aa6533d58"
version = "v0.3.5"
[[projects]]
branch = "master"
digest = "1:fdf499904ff0a8b5e05a32d98a1e65ddaff6b358640dbd8696ce8bb4e8d2d246"
name = "github.com/mattn/go-zglob"
packages = [
".",
"fastwalk"
"fastwalk",
]
revision = "49693fbb3fe3c3a75fc4e4d6fb1d7cedcbdeb385"
pruneopts = "NUT"
revision = "c436403c742d0b6d8fc37e69eadf33e024fe74fa"
[[projects]]
branch = "master"
digest = "1:9db29b604bd78452d167abed82386ddd2f93973df3841896fb6ab8aff936f1d6"
name = "github.com/mitchellh/go-homedir"
packages = ["."]
pruneopts = "NUT"
revision = "3864e76763d94a6df2f9960b16a20a33da9f9a66"
[[projects]]
digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe"
name = "github.com/pmezard/go-difflib"
packages = ["difflib"]
pruneopts = "NUT"
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
version = "v1.0.0"
[[projects]]
branch = "master"
digest = "1:5089085e1b27a57be4fb7acf32bfa71fb6236dc0e8371165651c9e15285a9ce0"
name = "github.com/radovskyb/watcher"
packages = ["."]
pruneopts = "NUT"
revision = "0d9d32686dbf6395752c9b209398a59e302a7f1e"
[[projects]]
branch = "master"
digest = "1:8c05fbdaac9713aed2a89d171a8b4e98a563f6c84e48352d0bcb10b1a5122488"
name = "github.com/spf13/pflag"
packages = ["."]
pruneopts = "NUT"
revision = "3ebe029320b2676d667ae88da602a5f854788a8a"
[[projects]]
digest = "1:bacb8b590716ab7c33f2277240972c9582d389593ee8d66fc10074e0508b8126"
name = "github.com/stretchr/testify"
packages = ["assert"]
pruneopts = "NUT"
revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686"
version = "v1.2.2"
[[projects]]
branch = "master"
digest = "1:17ff32de9f3bf39f76d339ddffcd380140721b112bea96837a86d4dc26c2c633"
name = "golang.org/x/crypto"
packages = [
"pbkdf2",
"scrypt",
"ssh/terminal"
"ssh/terminal",
]
pruneopts = "NUT"
revision = "a49355c7e3f8fe157a85be2f77e6e269a0f89602"
[[projects]]
branch = "master"
digest = "1:76ee51c3f468493aff39dbacc401e8831fbb765104cbf613b89bef01cf4bad70"
name = "golang.org/x/net"
packages = ["context"]
revision = "afe8f62b1d6bbd81f31868121a50b06d8188e1f9"
pruneopts = "NUT"
revision = "d0887baf81f4598189d4e12a37c6da86f0bba4d0"
[[projects]]
branch = "master"
digest = "1:39ebcc2b11457b703ae9ee2e8cca0f68df21969c6102cb3b705f76cca0ea0239"
name = "golang.org/x/sync"
packages = ["errgroup"]
pruneopts = "NUT"
revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca"
[[projects]]
branch = "master"
digest = "1:64107e3c8f52f341891a565d117bf263ed396fe0c16bad19634b25be25debfaa"
name = "golang.org/x/sys"
packages = [
"unix",
"windows"
"windows",
]
revision = "63fc586f45fe72d95d5240a5d5eb95e6503907d3"
pruneopts = "NUT"
revision = "ac767d655b305d4e9612f5f6e33120b9176c4ad4"
[[projects]]
branch = "v2"
digest = "1:7c95b35057a0ff2e19f707173cc1a947fa43a6eb5c4d300d196ece0334046082"
name = "gopkg.in/yaml.v2"
packages = ["."]
pruneopts = "NUT"
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
version = "v2.2.1"
[[projects]]
branch = "master"
digest = "1:36dbf10f4bf8c7568b5d4a5fe1afb57cd8e0451a6566b28f5bc87fc01f65339d"
name = "mvdan.cc/sh"
packages = [
"interp",
"shell",
"syntax"
"syntax",
]
revision = "ca7561fd34910fd8575a3830d3cded291c0ce8b2"
pruneopts = "NUT"
revision = "76fa0d67a25bb78ecf63fa717191661589dcdadd"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "600bd482208fdedec60141bfaffe55eb403df077944bfdf5c007a33132c8ab5a"
input-imports = [
"github.com/Masterminds/semver",
"github.com/Masterminds/sprig",
"github.com/imdario/mergo",
"github.com/mattn/go-zglob",
"github.com/mitchellh/go-homedir",
"github.com/radovskyb/watcher",
"github.com/spf13/pflag",
"github.com/stretchr/testify/assert",
"golang.org/x/sync/errgroup",
"gopkg.in/yaml.v2",
"mvdan.cc/sh/interp",
"mvdan.cc/sh/syntax",
]
solver-name = "gps-cdcl"
solver-version = 1

View File

@ -19,6 +19,7 @@ import (
"os"
"path/filepath"
"runtime"
"sync"
)
// TraverseLink is a sentinel error for fastWalk, similar to filepath.SkipDir.
@ -67,11 +68,18 @@ func FastWalk(root string, walkFn func(path string, typ os.FileMode) error) erro
// buffered for correctness & not leaking goroutines:
resc: make(chan error, numWorkers),
}
defer close(w.donec)
// TODO(bradfitz): start the workers as needed? maybe not worth it.
var wg sync.WaitGroup
for i := 0; i < numWorkers; i++ {
go w.doWork()
wg.Add(1)
go w.doWork(&wg)
}
// Ensure we wait for goroutines we started to finish before we return.
defer wg.Wait()
defer close(w.donec)
todo := []walkItem{{dir: root}}
out := 0
for {
@ -113,10 +121,11 @@ func FastWalk(root string, walkFn func(path string, typ os.FileMode) error) erro
// doWork reads directories as instructed (via workc) and runs the
// user's callback function.
func (w *walker) doWork() {
func (w *walker) doWork(wg *sync.WaitGroup) {
for {
select {
case <-w.donec:
wg.Done()
return
case it := <-w.workc:
w.resc <- w.walk(it.dir, !it.callbackDone)

21
vendor/github.com/mitchellh/go-homedir/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2013 Mitchell Hashimoto
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.

155
vendor/github.com/mitchellh/go-homedir/homedir.go generated vendored Normal file
View File

@ -0,0 +1,155 @@
package homedir
import (
"bytes"
"errors"
"os"
"os/exec"
"path/filepath"
"runtime"
"strconv"
"strings"
"sync"
)
// DisableCache will disable caching of the home directory. Caching is enabled
// by default.
var DisableCache bool
var homedirCache string
var cacheLock sync.RWMutex
// Dir returns the home directory for the executing user.
//
// This uses an OS-specific method for discovering the home directory.
// An error is returned if a home directory cannot be detected.
func Dir() (string, error) {
if !DisableCache {
cacheLock.RLock()
cached := homedirCache
cacheLock.RUnlock()
if cached != "" {
return cached, nil
}
}
cacheLock.Lock()
defer cacheLock.Unlock()
var result string
var err error
if runtime.GOOS == "windows" {
result, err = dirWindows()
} else {
// Unix-like system, so just assume Unix
result, err = dirUnix()
}
if err != nil {
return "", err
}
homedirCache = result
return result, nil
}
// Expand expands the path to include the home directory if the path
// is prefixed with `~`. If it isn't prefixed with `~`, the path is
// returned as-is.
func Expand(path string) (string, error) {
if len(path) == 0 {
return path, nil
}
if path[0] != '~' {
return path, nil
}
if len(path) > 1 && path[1] != '/' && path[1] != '\\' {
return "", errors.New("cannot expand user-specific home dir")
}
dir, err := Dir()
if err != nil {
return "", err
}
return filepath.Join(dir, path[1:]), nil
}
func dirUnix() (string, error) {
homeEnv := "HOME"
if runtime.GOOS == "plan9" {
// On plan9, env vars are lowercase.
homeEnv = "home"
}
// First prefer the HOME environmental variable
if home := os.Getenv(homeEnv); home != "" {
return home, nil
}
var stdout bytes.Buffer
// If that fails, try OS specific commands
if runtime.GOOS == "darwin" {
cmd := exec.Command("sh", "-c", `dscl -q . -read /Users/"$(whoami)" NFSHomeDirectory | sed 's/^[^ ]*: //'`)
cmd.Stdout = &stdout
if err := cmd.Run(); err == nil {
result := strings.TrimSpace(stdout.String())
if result != "" {
return result, nil
}
}
} else {
cmd := exec.Command("getent", "passwd", strconv.Itoa(os.Getuid()))
cmd.Stdout = &stdout
if err := cmd.Run(); err != nil {
// If the error is ErrNotFound, we ignore it. Otherwise, return it.
if err != exec.ErrNotFound {
return "", err
}
} else {
if passwd := strings.TrimSpace(stdout.String()); passwd != "" {
// username:password:uid:gid:gecos:home:shell
passwdParts := strings.SplitN(passwd, ":", 7)
if len(passwdParts) > 5 {
return passwdParts[5], nil
}
}
}
}
// If all else fails, try the shell
stdout.Reset()
cmd := exec.Command("sh", "-c", "cd && pwd")
cmd.Stdout = &stdout
if err := cmd.Run(); err != nil {
return "", err
}
result := strings.TrimSpace(stdout.String())
if result == "" {
return "", errors.New("blank output when reading home directory")
}
return result, nil
}
func dirWindows() (string, error) {
// First prefer the HOME environmental variable
if home := os.Getenv("HOME"); home != "" {
return home, nil
}
drive := os.Getenv("HOMEDRIVE")
path := os.Getenv("HOMEPATH")
home := drive + path
if drive == "" || path == "" {
home = os.Getenv("USERPROFILE")
}
if home == "" {
return "", errors.New("HOMEDRIVE, HOMEPATH, and USERPROFILE are blank")
}
return home, nil
}

View File

@ -14,7 +14,11 @@ var fcntl64Syscall uintptr = SYS_FCNTL
// FcntlInt performs a fcntl syscall on fd with the provided command and argument.
func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
valptr, _, err := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(arg))
valptr, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(arg))
var err error
if errno != 0 {
err = errno
}
return int(valptr), err
}

View File

@ -206,7 +206,7 @@ func (sa *SockaddrDatalink) sockaddr() (unsafe.Pointer, _Socklen, error) {
return unsafe.Pointer(&sa.raw), SizeofSockaddrDatalink, nil
}
func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
switch rsa.Addr.Family {
case AF_LINK:
pp := (*RawSockaddrDatalink)(unsafe.Pointer(rsa))
@ -286,7 +286,7 @@ func Accept(fd int) (nfd int, sa Sockaddr, err error) {
Close(nfd)
return 0, nil, ECONNABORTED
}
sa, err = anyToSockaddr(&rsa)
sa, err = anyToSockaddr(fd, &rsa)
if err != nil {
Close(nfd)
nfd = 0
@ -306,7 +306,7 @@ func Getsockname(fd int) (sa Sockaddr, err error) {
rsa.Addr.Family = AF_UNIX
rsa.Addr.Len = SizeofSockaddrUnix
}
return anyToSockaddr(&rsa)
return anyToSockaddr(fd, &rsa)
}
//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error)
@ -356,7 +356,7 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
recvflags = int(msg.Flags)
// source address is only specified if the socket is unconnected
if rsa.Addr.Family != AF_UNSPEC {
from, err = anyToSockaddr(&rsa)
from, err = anyToSockaddr(fd, &rsa)
}
return
}

View File

@ -87,7 +87,7 @@ func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) {
if len > SizeofSockaddrAny {
panic("RawSockaddrAny too small")
}
sa, err = anyToSockaddr(&rsa)
sa, err = anyToSockaddr(fd, &rsa)
if err != nil {
Close(nfd)
nfd = 0

View File

@ -89,7 +89,7 @@ func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) {
if len > SizeofSockaddrAny {
panic("RawSockaddrAny too small")
}
sa, err = anyToSockaddr(&rsa)
sa, err = anyToSockaddr(fd, &rsa)
if err != nil {
Close(nfd)
nfd = 0

View File

@ -489,6 +489,47 @@ func (sa *SockaddrL2) sockaddr() (unsafe.Pointer, _Socklen, error) {
return unsafe.Pointer(&sa.raw), SizeofSockaddrL2, nil
}
// SockaddrRFCOMM implements the Sockaddr interface for AF_BLUETOOTH type sockets
// using the RFCOMM protocol.
//
// Server example:
//
// fd, _ := Socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)
// _ = unix.Bind(fd, &unix.SockaddrRFCOMM{
// Channel: 1,
// Addr: [6]uint8{0, 0, 0, 0, 0, 0}, // BDADDR_ANY or 00:00:00:00:00:00
// })
// _ = Listen(fd, 1)
// nfd, sa, _ := Accept(fd)
// fmt.Printf("conn addr=%v fd=%d", sa.(*unix.SockaddrRFCOMM).Addr, nfd)
// Read(nfd, buf)
//
// Client example:
//
// fd, _ := Socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)
// _ = Connect(fd, &SockaddrRFCOMM{
// Channel: 1,
// Addr: [6]byte{0x11, 0x22, 0x33, 0xaa, 0xbb, 0xcc}, // CC:BB:AA:33:22:11
// })
// Write(fd, []byte(`hello`))
type SockaddrRFCOMM struct {
// Addr represents a bluetooth address, byte ordering is little-endian.
Addr [6]uint8
// Channel is a designated bluetooth channel, only 1-30 are available for use.
// Since Linux 2.6.7 and further zero value is the first available channel.
Channel uint8
raw RawSockaddrRFCOMM
}
func (sa *SockaddrRFCOMM) sockaddr() (unsafe.Pointer, _Socklen, error) {
sa.raw.Family = AF_BLUETOOTH
sa.raw.Channel = sa.Channel
sa.raw.Bdaddr = sa.Addr
return unsafe.Pointer(&sa.raw), SizeofSockaddrRFCOMM, nil
}
// SockaddrCAN implements the Sockaddr interface for AF_CAN type sockets.
// The RxID and TxID fields are used for transport protocol addressing in
// (CAN_TP16, CAN_TP20, CAN_MCNET, and CAN_ISOTP), they can be left with
@ -651,7 +692,7 @@ func (sa *SockaddrVM) sockaddr() (unsafe.Pointer, _Socklen, error) {
return unsafe.Pointer(&sa.raw), SizeofSockaddrVM, nil
}
func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
switch rsa.Addr.Family {
case AF_NETLINK:
pp := (*RawSockaddrNetlink)(unsafe.Pointer(rsa))
@ -728,6 +769,30 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
Port: pp.Port,
}
return sa, nil
case AF_BLUETOOTH:
proto, err := GetsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL)
if err != nil {
return nil, err
}
// only BTPROTO_L2CAP and BTPROTO_RFCOMM can accept connections
switch proto {
case BTPROTO_L2CAP:
pp := (*RawSockaddrL2)(unsafe.Pointer(rsa))
sa := &SockaddrL2{
PSM: pp.Psm,
CID: pp.Cid,
Addr: pp.Bdaddr,
AddrType: pp.Bdaddr_type,
}
return sa, nil
case BTPROTO_RFCOMM:
pp := (*RawSockaddrRFCOMM)(unsafe.Pointer(rsa))
sa := &SockaddrRFCOMM{
Channel: pp.Channel,
Addr: pp.Bdaddr,
}
return sa, nil
}
}
return nil, EAFNOSUPPORT
}
@ -739,7 +804,7 @@ func Accept(fd int) (nfd int, sa Sockaddr, err error) {
if err != nil {
return
}
sa, err = anyToSockaddr(&rsa)
sa, err = anyToSockaddr(fd, &rsa)
if err != nil {
Close(nfd)
nfd = 0
@ -757,7 +822,7 @@ func Accept4(fd int, flags int) (nfd int, sa Sockaddr, err error) {
if len > SizeofSockaddrAny {
panic("RawSockaddrAny too small")
}
sa, err = anyToSockaddr(&rsa)
sa, err = anyToSockaddr(fd, &rsa)
if err != nil {
Close(nfd)
nfd = 0
@ -771,7 +836,7 @@ func Getsockname(fd int) (sa Sockaddr, err error) {
if err = getsockname(fd, &rsa, &len); err != nil {
return
}
return anyToSockaddr(&rsa)
return anyToSockaddr(fd, &rsa)
}
func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) {
@ -960,7 +1025,7 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
recvflags = int(msg.Flags)
// source address is only specified if the socket is unconnected
if rsa.Addr.Family != AF_UNSPEC {
from, err = anyToSockaddr(&rsa)
from, err = anyToSockaddr(fd, &rsa)
}
return
}

View File

@ -112,7 +112,7 @@ func Getsockname(fd int) (sa Sockaddr, err error) {
if err = getsockname(fd, &rsa, &len); err != nil {
return
}
return anyToSockaddr(&rsa)
return anyToSockaddr(fd, &rsa)
}
// GetsockoptString returns the string value of the socket option opt for the
@ -314,7 +314,11 @@ func UtimesNanoAt(dirfd int, path string, ts []Timespec, flags int) error {
// FcntlInt performs a fcntl syscall on fd with the provided command and argument.
func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
valptr, _, err := sysvicall6(uintptr(unsafe.Pointer(&procfcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(arg), 0, 0, 0)
valptr, _, errno := sysvicall6(uintptr(unsafe.Pointer(&procfcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(arg), 0, 0, 0)
var err error
if errno != 0 {
err = errno
}
return int(valptr), err
}
@ -356,7 +360,7 @@ func Futimes(fd int, tv []Timeval) error {
return futimesat(fd, nil, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
}
func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
switch rsa.Addr.Family {
case AF_UNIX:
pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
@ -407,7 +411,7 @@ func Accept(fd int) (nfd int, sa Sockaddr, err error) {
if nfd == -1 {
return
}
sa, err = anyToSockaddr(&rsa)
sa, err = anyToSockaddr(fd, &rsa)
if err != nil {
Close(nfd)
nfd = 0
@ -444,7 +448,7 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
oobn = int(msg.Accrightslen)
// source address is only specified if the socket is unconnected
if rsa.Addr.Family != AF_UNSPEC {
from, err = anyToSockaddr(&rsa)
from, err = anyToSockaddr(fd, &rsa)
}
return
}

View File

@ -219,7 +219,7 @@ func Getpeername(fd int) (sa Sockaddr, err error) {
if err = getpeername(fd, &rsa, &len); err != nil {
return
}
return anyToSockaddr(&rsa)
return anyToSockaddr(fd, &rsa)
}
func GetsockoptByte(fd, level, opt int) (value byte, err error) {
@ -291,7 +291,7 @@ func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {
return
}
if rsa.Addr.Family != AF_UNSPEC {
from, err = anyToSockaddr(&rsa)
from, err = anyToSockaddr(fd, &rsa)
}
return
}

View File

@ -1474,6 +1474,21 @@ func Munlockall() (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func faccessat(dirfd int, path string, mode uint32) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
_, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
if e1 != 0 {
err = errnoErr(e1)
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Dup2(oldfd int, newfd int) (err error) {
_, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
if e1 != 0 {
@ -1495,21 +1510,6 @@ func EpollCreate(size int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func faccessat(dirfd int, path string, mode uint32) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
_, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
if e1 != 0 {
err = errnoErr(e1)
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
var _p0 unsafe.Pointer
if len(events) > 0 {

View File

@ -1474,6 +1474,21 @@ func Munlockall() (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func faccessat(dirfd int, path string, mode uint32) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
_, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
if e1 != 0 {
err = errnoErr(e1)
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Dup2(oldfd int, newfd int) (err error) {
_, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
if e1 != 0 {
@ -1495,21 +1510,6 @@ func EpollCreate(size int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func faccessat(dirfd int, path string, mode uint32) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
_, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
if e1 != 0 {
err = errnoErr(e1)
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
var _p0 unsafe.Pointer
if len(events) > 0 {

View File

@ -248,6 +248,13 @@ type RawSockaddrL2 struct {
_ [1]byte
}
type RawSockaddrRFCOMM struct {
Family uint16
Bdaddr [6]uint8
Channel uint8
_ [1]byte
}
type RawSockaddrCAN struct {
Family uint16
_ [2]byte
@ -401,6 +408,7 @@ const (
SizeofSockaddrNetlink = 0xc
SizeofSockaddrHCI = 0x6
SizeofSockaddrL2 = 0xe
SizeofSockaddrRFCOMM = 0xa
SizeofSockaddrCAN = 0x10
SizeofSockaddrALG = 0x58
SizeofSockaddrVM = 0x10

View File

@ -250,6 +250,13 @@ type RawSockaddrL2 struct {
_ [1]byte
}
type RawSockaddrRFCOMM struct {
Family uint16
Bdaddr [6]uint8
Channel uint8
_ [1]byte
}
type RawSockaddrCAN struct {
Family uint16
_ [2]byte
@ -405,6 +412,7 @@ const (
SizeofSockaddrNetlink = 0xc
SizeofSockaddrHCI = 0x6
SizeofSockaddrL2 = 0xe
SizeofSockaddrRFCOMM = 0xa
SizeofSockaddrCAN = 0x10
SizeofSockaddrALG = 0x58
SizeofSockaddrVM = 0x10

View File

@ -251,6 +251,13 @@ type RawSockaddrL2 struct {
_ [1]byte
}
type RawSockaddrRFCOMM struct {
Family uint16
Bdaddr [6]uint8
Channel uint8
_ [1]byte
}
type RawSockaddrCAN struct {
Family uint16
_ [2]byte
@ -404,6 +411,7 @@ const (
SizeofSockaddrNetlink = 0xc
SizeofSockaddrHCI = 0x6
SizeofSockaddrL2 = 0xe
SizeofSockaddrRFCOMM = 0xa
SizeofSockaddrCAN = 0x10
SizeofSockaddrALG = 0x58
SizeofSockaddrVM = 0x10

View File

@ -251,6 +251,13 @@ type RawSockaddrL2 struct {
_ [1]byte
}
type RawSockaddrRFCOMM struct {
Family uint16
Bdaddr [6]uint8
Channel uint8
_ [1]byte
}
type RawSockaddrCAN struct {
Family uint16
_ [2]byte
@ -406,6 +413,7 @@ const (
SizeofSockaddrNetlink = 0xc
SizeofSockaddrHCI = 0x6
SizeofSockaddrL2 = 0xe
SizeofSockaddrRFCOMM = 0xa
SizeofSockaddrCAN = 0x10
SizeofSockaddrALG = 0x58
SizeofSockaddrVM = 0x10

View File

@ -249,6 +249,13 @@ type RawSockaddrL2 struct {
_ [1]byte
}
type RawSockaddrRFCOMM struct {
Family uint16
Bdaddr [6]uint8
Channel uint8
_ [1]byte
}
type RawSockaddrCAN struct {
Family uint16
_ [2]byte
@ -402,6 +409,7 @@ const (
SizeofSockaddrNetlink = 0xc
SizeofSockaddrHCI = 0x6
SizeofSockaddrL2 = 0xe
SizeofSockaddrRFCOMM = 0xa
SizeofSockaddrCAN = 0x10
SizeofSockaddrALG = 0x58
SizeofSockaddrVM = 0x10

View File

@ -251,6 +251,13 @@ type RawSockaddrL2 struct {
_ [1]byte
}
type RawSockaddrRFCOMM struct {
Family uint16
Bdaddr [6]uint8
Channel uint8
_ [1]byte
}
type RawSockaddrCAN struct {
Family uint16
_ [2]byte
@ -406,6 +413,7 @@ const (
SizeofSockaddrNetlink = 0xc
SizeofSockaddrHCI = 0x6
SizeofSockaddrL2 = 0xe
SizeofSockaddrRFCOMM = 0xa
SizeofSockaddrCAN = 0x10
SizeofSockaddrALG = 0x58
SizeofSockaddrVM = 0x10

View File

@ -251,6 +251,13 @@ type RawSockaddrL2 struct {
_ [1]byte
}
type RawSockaddrRFCOMM struct {
Family uint16
Bdaddr [6]uint8
Channel uint8
_ [1]byte
}
type RawSockaddrCAN struct {
Family uint16
_ [2]byte
@ -406,6 +413,7 @@ const (
SizeofSockaddrNetlink = 0xc
SizeofSockaddrHCI = 0x6
SizeofSockaddrL2 = 0xe
SizeofSockaddrRFCOMM = 0xa
SizeofSockaddrCAN = 0x10
SizeofSockaddrALG = 0x58
SizeofSockaddrVM = 0x10

View File

@ -249,6 +249,13 @@ type RawSockaddrL2 struct {
_ [1]byte
}
type RawSockaddrRFCOMM struct {
Family uint16
Bdaddr [6]uint8
Channel uint8
_ [1]byte
}
type RawSockaddrCAN struct {
Family uint16
_ [2]byte
@ -402,6 +409,7 @@ const (
SizeofSockaddrNetlink = 0xc
SizeofSockaddrHCI = 0x6
SizeofSockaddrL2 = 0xe
SizeofSockaddrRFCOMM = 0xa
SizeofSockaddrCAN = 0x10
SizeofSockaddrALG = 0x58
SizeofSockaddrVM = 0x10

View File

@ -252,6 +252,13 @@ type RawSockaddrL2 struct {
_ [1]byte
}
type RawSockaddrRFCOMM struct {
Family uint16
Bdaddr [6]uint8
Channel uint8
_ [1]byte
}
type RawSockaddrCAN struct {
Family uint16
_ [2]byte
@ -407,6 +414,7 @@ const (
SizeofSockaddrNetlink = 0xc
SizeofSockaddrHCI = 0x6
SizeofSockaddrL2 = 0xe
SizeofSockaddrRFCOMM = 0xa
SizeofSockaddrCAN = 0x10
SizeofSockaddrALG = 0x58
SizeofSockaddrVM = 0x10

View File

@ -252,6 +252,13 @@ type RawSockaddrL2 struct {
_ [1]byte
}
type RawSockaddrRFCOMM struct {
Family uint16
Bdaddr [6]uint8
Channel uint8
_ [1]byte
}
type RawSockaddrCAN struct {
Family uint16
_ [2]byte
@ -407,6 +414,7 @@ const (
SizeofSockaddrNetlink = 0xc
SizeofSockaddrHCI = 0x6
SizeofSockaddrL2 = 0xe
SizeofSockaddrRFCOMM = 0xa
SizeofSockaddrCAN = 0x10
SizeofSockaddrALG = 0x58
SizeofSockaddrVM = 0x10

View File

@ -250,6 +250,13 @@ type RawSockaddrL2 struct {
_ [1]byte
}
type RawSockaddrRFCOMM struct {
Family uint16
Bdaddr [6]uint8
Channel uint8
_ [1]byte
}
type RawSockaddrCAN struct {
Family uint16
_ [2]byte
@ -405,6 +412,7 @@ const (
SizeofSockaddrNetlink = 0xc
SizeofSockaddrHCI = 0x6
SizeofSockaddrL2 = 0xe
SizeofSockaddrRFCOMM = 0xa
SizeofSockaddrCAN = 0x10
SizeofSockaddrALG = 0x58
SizeofSockaddrVM = 0x10

View File

@ -43,6 +43,11 @@ const (
SC_STATUS_PROCESS_INFO = 0
SC_ACTION_NONE = 0
SC_ACTION_RESTART = 1
SC_ACTION_REBOOT = 2
SC_ACTION_RUN_COMMAND = 3
SERVICE_STOPPED = 1
SERVICE_START_PENDING = 2
SERVICE_STOP_PENDING = 3
@ -148,6 +153,19 @@ type ENUM_SERVICE_STATUS_PROCESS struct {
ServiceStatusProcess SERVICE_STATUS_PROCESS
}
type SERVICE_FAILURE_ACTIONS struct {
ResetPeriod uint32
RebootMsg *uint16
Command *uint16
ActionsCount uint32
Actions *SC_ACTION
}
type SC_ACTION struct {
Type uint32
Delay uint32
}
//sys CloseServiceHandle(handle Handle) (err error) = advapi32.CloseServiceHandle
//sys CreateService(mgr Handle, serviceName *uint16, displayName *uint16, access uint32, srvType uint32, startType uint32, errCtl uint32, pathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16) (handle Handle, err error) [failretval==0] = advapi32.CreateServiceW
//sys OpenService(mgr Handle, serviceName *uint16, access uint32) (handle Handle, err error) [failretval==0] = advapi32.OpenServiceW

View File

@ -94,16 +94,29 @@ const (
FILE_APPEND_DATA = 0x00000004
FILE_WRITE_ATTRIBUTES = 0x00000100
FILE_SHARE_READ = 0x00000001
FILE_SHARE_WRITE = 0x00000002
FILE_SHARE_DELETE = 0x00000004
FILE_ATTRIBUTE_READONLY = 0x00000001
FILE_ATTRIBUTE_HIDDEN = 0x00000002
FILE_ATTRIBUTE_SYSTEM = 0x00000004
FILE_ATTRIBUTE_DIRECTORY = 0x00000010
FILE_ATTRIBUTE_ARCHIVE = 0x00000020
FILE_ATTRIBUTE_NORMAL = 0x00000080
FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400
FILE_SHARE_READ = 0x00000001
FILE_SHARE_WRITE = 0x00000002
FILE_SHARE_DELETE = 0x00000004
FILE_ATTRIBUTE_READONLY = 0x00000001
FILE_ATTRIBUTE_HIDDEN = 0x00000002
FILE_ATTRIBUTE_SYSTEM = 0x00000004
FILE_ATTRIBUTE_DIRECTORY = 0x00000010
FILE_ATTRIBUTE_ARCHIVE = 0x00000020
FILE_ATTRIBUTE_DEVICE = 0x00000040
FILE_ATTRIBUTE_NORMAL = 0x00000080
FILE_ATTRIBUTE_TEMPORARY = 0x00000100
FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200
FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400
FILE_ATTRIBUTE_COMPRESSED = 0x00000800
FILE_ATTRIBUTE_OFFLINE = 0x00001000
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000
FILE_ATTRIBUTE_ENCRYPTED = 0x00004000
FILE_ATTRIBUTE_INTEGRITY_STREAM = 0x00008000
FILE_ATTRIBUTE_VIRTUAL = 0x00010000
FILE_ATTRIBUTE_NO_SCRUB_DATA = 0x00020000
FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x00040000
FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0x00400000
INVALID_FILE_ATTRIBUTES = 0xffffffff

View File

@ -1,9 +0,0 @@
// Copyright (c) 2017, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information
// Package shell contains high-level features that use the syntax and
// interp packages under the hood.
//
// This package is a work in progress and EXPERIMENTAL; its API is not
// subject to the 1.x backwards compatibility guarantee.
package shell // import "mvdan.cc/sh/shell"

View File

@ -1,41 +0,0 @@
// Copyright (c) 2018, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information
package shell
import (
"strings"
"mvdan.cc/sh/interp"
"mvdan.cc/sh/syntax"
)
// Expand performs shell expansion on s, using env to resolve variables.
// The expansion will apply to parameter expansions like $var and
// ${#var}, but also to arithmetic expansions like $((var + 3)), and
// command substitutions like $(echo foo).
//
// If env is nil, the current environment variables are used.
//
// Any side effects or modifications to the system are forbidden when
// interpreting the program. This is enforced via whitelists when
// executing programs and opening paths.
func Expand(s string, env func(string) string) (string, error) {
p := syntax.NewParser()
src := "<<EOF\n" + s + "\nEOF"
f, err := p.Parse(strings.NewReader(src), "")
if err != nil {
return "", err
}
word := f.Stmts[0].Redirs[0].Hdoc
r := pureRunner()
if env != nil {
r.Env = interp.FuncEnviron(env)
}
r.Reset()
fields := r.Fields(word)
// TODO: runner error
join := strings.Join(fields, "")
// since the heredoc implies a trailing newline
return strings.TrimSuffix(join, "\n"), nil
}

View File

@ -1,85 +0,0 @@
// Copyright (c) 2018, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information
package shell
import (
"fmt"
"io"
"os"
"mvdan.cc/sh/interp"
"mvdan.cc/sh/syntax"
)
// SourceFile sources a shell file from disk and returns the variables
// declared in it.
//
// A default parser is used; to set custom options, use SourceNode
// instead.
func SourceFile(path string) (map[string]interp.Variable, error) {
f, err := os.Open(path)
if err != nil {
return nil, fmt.Errorf("could not open: %v", err)
}
defer f.Close()
p := syntax.NewParser()
file, err := p.Parse(f, path)
if err != nil {
return nil, fmt.Errorf("could not parse: %v", err)
}
return SourceNode(file)
}
// purePrograms holds a list of common programs that do not have side
// effects, or otherwise cannot modify or harm the system that runs
// them.
var purePrograms = []string{
// string handling
"sed", "grep", "tr", "cut", "cat", "head", "tail", "seq", "yes",
"wc",
// paths
"ls", "pwd", "basename", "realpath",
// others
"env", "sleep", "uniq", "sort",
}
func pureRunner() *interp.Runner {
r := &interp.Runner{}
// forbid executing programs that might cause trouble
r.Exec = func(ctx interp.Ctxt, path string, args []string) error {
for _, name := range purePrograms {
if args[0] == name {
return interp.DefaultExec(ctx, path, args)
}
}
return fmt.Errorf("program not in whitelist: %s", args[0])
}
// forbid opening any real files
r.Open = interp.OpenDevImpls(func(ctx interp.Ctxt, path string, flags int, mode os.FileMode) (io.ReadWriteCloser, error) {
return nil, fmt.Errorf("cannot open path: %s", ctx.UnixPath(path))
})
return r
}
// SourceNode sources a shell program from a node and returns the
// variables declared in it.
//
// Any side effects or modifications to the system are forbidden when
// interpreting the program. This is enforced via whitelists when
// executing programs and opening paths.
func SourceNode(node syntax.Node) (map[string]interp.Variable, error) {
r := pureRunner()
r.Reset()
if err := r.Run(node); err != nil {
return nil, fmt.Errorf("could not run: %v", err)
}
// delete the internal shell vars that the user is not
// interested in
delete(r.Vars, "PWD")
delete(r.Vars, "HOME")
delete(r.Vars, "PATH")
delete(r.Vars, "IFS")
delete(r.Vars, "OPTIND")
return r.Vars, nil
}

View File

@ -107,6 +107,7 @@ retry:
} else if p.fill(); p.bs == nil {
p.bsp++
p.r = utf8.RuneSelf
p.w = 1
} else {
goto retry
}
@ -232,6 +233,7 @@ skipSpace:
w := utf8.RuneLen(r)
if bytes.HasPrefix(p.bs[p.bsp-w:], p.stopAt) {
p.r = utf8.RuneSelf
p.w = 1
p.tok = _EOF
return
}
@ -748,10 +750,13 @@ func (p *Parser) endLit() (s string) {
return
}
func (p *Parser) numLit() bool {
for _, b := range p.litBs {
func (p *Parser) isLitRedir() bool {
lit := p.litBs[:len(p.litBs)-1]
if lit[0] == '{' && lit[len(lit)-1] == '}' {
return ValidName(string(lit[1 : len(lit)-1]))
}
for _, b := range lit {
switch b {
case '>', '<':
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
default:
return false
@ -800,7 +805,7 @@ loop:
break loop
}
case '/':
if p.quote&allParamExp != 0 && p.quote != paramExpExp {
if p.quote != paramExpExp {
break loop
}
case ':', '=', '%', '^', ',', '?', '!', '*':
@ -838,7 +843,7 @@ loop:
p.discardLit(2)
}
case '>', '<':
if p.peekByte('(') || !p.numLit() {
if p.peekByte('(') || !p.isLitRedir() {
tok = _Lit
} else {
tok = _LitRedir

View File

@ -232,7 +232,7 @@ func (a *Assign) End() Pos {
type Redirect struct {
OpPos Pos
Op RedirOperator
N *Lit // N>, must be a number
N *Lit // fd>, or {varname}> in Bash
Word *Word // >word
Hdoc *Word // here-document body
}

View File

@ -30,6 +30,18 @@ func Variant(l LangVariant) func(*Parser) {
return func(p *Parser) { p.lang = l }
}
func (l LangVariant) String() string {
switch l {
case LangBash:
return "bash"
case LangPOSIX:
return "posix"
case LangMirBSDKorn:
return "mksh"
}
return "unknown shell language variant"
}
// StopAt configures the lexer to stop at an arbitrary word, treating it
// as if it were the end of the input. It can contain any characters
// except whitespace, and cannot be over four bytes in size.
@ -480,26 +492,60 @@ func (p *Parser) errPass(err error) {
p.err = err
p.bsp = len(p.bs) + 1
p.r = utf8.RuneSelf
p.w = 1
p.tok = _EOF
}
}
// ParseError represents an error found when parsing a source file.
// ParseError represents an error found when parsing a source file, from which
// the parser cannot recover.
type ParseError struct {
Filename string
Pos
Text string
}
func (e *ParseError) Error() string {
func (e ParseError) Error() string {
if e.Filename == "" {
return fmt.Sprintf("%s: %s", e.Pos.String(), e.Text)
}
return fmt.Sprintf("%s:%s: %s", e.Filename, e.Pos.String(), e.Text)
}
// LangError is returned when the parser encounters code that is only valid in
// other shell language variants. The error includes what feature is not present
// in the current language variant, and what languages support it.
type LangError struct {
Filename string
Pos
Feature string
Langs []LangVariant
}
func (e LangError) Error() string {
var buf bytes.Buffer
if e.Filename != "" {
buf.WriteString(e.Filename + ":")
}
buf.WriteString(e.Pos.String() + ": ")
buf.WriteString(e.Feature)
if strings.HasSuffix(e.Feature, "s") {
buf.WriteString(" are a ")
} else {
buf.WriteString(" is a ")
}
for i, lang := range e.Langs {
if i > 0 {
buf.WriteString("/")
}
buf.WriteString(lang.String())
}
buf.WriteString(" feature")
return buf.String()
}
func (p *Parser) posErr(pos Pos, format string, a ...interface{}) {
p.errPass(&ParseError{
p.errPass(ParseError{
Filename: p.f.Name,
Pos: pos,
Text: fmt.Sprintf(format, a...),
@ -510,6 +556,15 @@ func (p *Parser) curErr(format string, a ...interface{}) {
p.posErr(p.pos, format, a...)
}
func (p *Parser) langErr(pos Pos, feature string, langs ...LangVariant) {
p.errPass(LangError{
Filename: p.f.Name,
Pos: pos,
Feature: feature,
Langs: langs,
})
}
func (p *Parser) stmts(fn func(*Stmt) bool, stops ...string) {
gotEnd := true
loop:
@ -668,7 +723,7 @@ func (p *Parser) wordPart() WordPart {
p.next()
if p.got(hash) {
if p.lang != LangMirBSDKorn {
p.posErr(ar.Pos(), "unsigned expressions are a mksh feature")
p.langErr(ar.Pos(), "unsigned expressions", LangMirBSDKorn)
}
ar.Unsigned = true
}
@ -712,9 +767,16 @@ func (p *Parser) wordPart() WordPart {
p.pos = posAddCol(p.pos, 1)
pe.Param = p.getLit()
if pe.Param != nil && pe.Param.Value == "" {
// e.g. "$\\\n", which we can't detect above
l := p.lit(pe.Dollar, "$")
p.next()
if p.val == "" {
// e.g. "$\\\n" followed by a closing double
// quote, so we need the next token.
p.next()
} else {
// e.g. "$\\\"" within double quotes, so we must
// keep the rest of the literal characters.
l.ValueEnd = posAddCol(l.ValuePos, 1)
}
return l
}
return pe
@ -777,7 +839,7 @@ func (p *Parser) wordPart() WordPart {
return cs
case globQuest, globStar, globPlus, globAt, globExcl:
if p.lang == LangPOSIX {
p.curErr("extended globs are a bash feature")
p.langErr(p.pos, "extended globs", LangBash, LangMirBSDKorn)
}
eg := &ExtGlob{Op: GlobOperator(p.tok), OpPos: p.pos}
lparens := 1
@ -1058,7 +1120,7 @@ func (p *Parser) paramExp() *ParamExp {
case exclMark:
if paramNameOp(p.r) {
if p.lang == LangPOSIX {
p.curErr("${!foo} is a bash feature")
p.langErr(p.pos, "${!foo}", LangBash, LangMirBSDKorn)
}
pe.Excl = true
p.next()
@ -1067,6 +1129,9 @@ func (p *Parser) paramExp() *ParamExp {
op := p.tok
switch p.tok {
case _Lit, _LitWord:
if !numberLiteral(p.val) && !ValidName(p.val) {
p.curErr("invalid parameter name")
}
pe.Param = p.lit(p.pos, p.val)
p.next()
case quest, minus:
@ -1093,7 +1158,7 @@ func (p *Parser) paramExp() *ParamExp {
return pe
case leftBrack:
if p.lang == LangPOSIX {
p.curErr("arrays are a bash feature")
p.langErr(p.pos, "arrays", LangBash, LangMirBSDKorn)
}
if !ValidName(pe.Param.Value) {
p.curErr("cannot index a special parameter name")
@ -1113,7 +1178,7 @@ func (p *Parser) paramExp() *ParamExp {
case slash, dblSlash:
// pattern search and replace
if p.lang == LangPOSIX {
p.curErr("search and replace is a bash feature")
p.langErr(p.pos, "search and replace", LangBash, LangMirBSDKorn)
}
pe.Repl = &Replace{All: p.tok == dblSlash}
p.quote = paramExpRepl
@ -1126,7 +1191,7 @@ func (p *Parser) paramExp() *ParamExp {
case colon:
// slicing
if p.lang == LangPOSIX {
p.curErr("slicing is a bash feature")
p.langErr(p.pos, "slicing", LangBash, LangMirBSDKorn)
}
pe.Slice = &Slice{}
colonPos := p.pos
@ -1141,13 +1206,13 @@ func (p *Parser) paramExp() *ParamExp {
case caret, dblCaret, comma, dblComma:
// upper/lower case
if p.lang != LangBash {
p.curErr("this expansion operator is a bash feature")
p.langErr(p.pos, "this expansion operator", LangBash)
}
pe.Exp = p.paramExpExp()
case at, star:
switch {
case p.tok == at && p.lang == LangPOSIX:
p.curErr("this expansion operator is a bash feature")
p.langErr(p.pos, "this expansion operator", LangBash, LangMirBSDKorn)
case p.tok == star && !pe.Excl:
p.curErr("not a valid parameter expansion operator: %v", p.tok)
case pe.Excl:
@ -1252,6 +1317,15 @@ func ValidName(val string) bool {
return true
}
func numberLiteral(val string) bool {
for _, r := range val {
if '0' > r || r > '9' {
return false
}
}
return true
}
func (p *Parser) hasValidIdent() bool {
if p.tok != _Lit && p.tok != _LitWord {
return false
@ -1319,7 +1393,7 @@ func (p *Parser) getAssign(needEqual bool) *Assign {
}
if as.Value == nil && p.tok == leftParen {
if p.lang == LangPOSIX {
p.curErr("arrays are a bash feature")
p.langErr(p.pos, "arrays", LangBash, LangMirBSDKorn)
}
if as.Index != nil {
p.curErr("arrays cannot be nested")
@ -1394,6 +1468,9 @@ func (p *Parser) doRedirect(s *Stmt) {
s.Redirs = append(s.Redirs, r)
}
r.N = p.getLit()
if p.lang != LangBash && r.N != nil && r.N.Value[0] == '{' {
p.langErr(r.N.Pos(), "{varname} redirects", LangBash)
}
r.Op, r.OpPos = RedirOperator(p.tok), p.pos
p.next()
switch r.Op {
@ -1643,7 +1720,7 @@ func (p *Parser) arithmExpCmd(s *Stmt) {
p.next()
if p.got(hash) {
if p.lang != LangMirBSDKorn {
p.posErr(ar.Pos(), "unsigned expressions are a mksh feature")
p.langErr(ar.Pos(), "unsigned expressions", LangMirBSDKorn)
}
ar.Unsigned = true
}
@ -1725,7 +1802,7 @@ func (p *Parser) loop(fpos Pos) Loop {
if p.lang != LangBash {
switch p.tok {
case leftParen, dblLeftParen:
p.curErr("c-style fors are a bash feature")
p.langErr(p.pos, "c-style fors", LangBash)
}
}
if p.tok == dblLeftParen {
@ -1909,7 +1986,7 @@ func (p *Parser) testExpr(ftok token, fpos Pos, pastAndOr bool) TestExpr {
}
case TsReMatch:
if p.lang != LangBash {
p.curErr("regex tests are a bash feature")
p.langErr(p.pos, "regex tests", LangBash)
}
oldReOpenParens := p.reOpenParens
old := p.preNested(testRegexp)

View File

@ -68,17 +68,12 @@ func NewPrinter(options ...func(*Printer)) *Printer {
func (p *Printer) Print(w io.Writer, node Node) error {
p.reset()
p.bufWriter.Reset(w)
p.line = node.Pos().Line()
switch x := node.(type) {
case *File:
p.stmts(x.StmtList)
p.stmtList(x.StmtList)
p.newline(x.End())
case *Stmt:
sl := StmtList{Stmts: []*Stmt{x}}
// StmtList.pos is better than Stmt.Pos, since it also takes
// comments into account.
p.line = sl.pos().Line()
p.stmts(sl)
p.stmtList(StmtList{Stmts: []*Stmt{x}})
case *Word:
p.word(x)
case Command:
@ -152,6 +147,8 @@ type Printer struct {
// comment in the same line, breaking programs.
pendingComments []Comment
// firstLine means we are still writing the first line
firstLine bool
// line is the current line number
line uint
@ -180,7 +177,11 @@ func (p *Printer) reset() {
p.wantSpace, p.wantNewline = false, false
p.commentPadding = 0
p.pendingComments = p.pendingComments[:0]
// minification uses its own newline logic
p.firstLine = !p.minify
p.line = 0
p.lastLevel, p.level = 0, 0
p.levelIncs = p.levelIncs[:0]
p.nestedBinary = false
@ -354,7 +355,8 @@ func (p *Printer) flushHeredocs() {
}
func (p *Printer) newlines(pos Pos) {
if !p.wantNewline && p.line == 0 && len(p.pendingComments) == 0 {
if p.firstLine && len(p.pendingComments) == 0 {
p.firstLine = false
return // no empty lines at the top
}
if !p.wantNewline && pos.Line() <= p.line {
@ -379,11 +381,11 @@ func (p *Printer) rightParen(pos Pos) {
p.wantSpace = true
}
func (p *Printer) semiRsrv(s string, pos Pos, fallback bool) {
func (p *Printer) semiRsrv(s string, pos Pos) {
if p.wantNewline || pos.Line() > p.line {
p.newlines(pos)
} else {
if fallback && !p.wroteSemi {
if !p.wroteSemi {
p.WriteByte(';')
}
if !p.minify {
@ -403,6 +405,9 @@ func (p *Printer) comment(c Comment) {
func (p *Printer) flushComments() {
for i, c := range p.pendingComments {
p.firstLine = false
// We can't call any of the newline methods, as they call this
// function and we'd recurse forever.
cline := c.Hash.Line()
switch {
case i > 0, cline > p.line && p.line > 0:
@ -430,6 +435,9 @@ func (p *Printer) flushComments() {
}
func (p *Printer) comments(cs []Comment) {
if p.minify {
return
}
p.pendingComments = append(p.pendingComments, cs...)
}
@ -465,12 +473,12 @@ func (p *Printer) wordPart(wp, next WordPart) {
p.wantSpace = true
p.nestedStmts(x.StmtList, x.Right)
p.wantSpace = false
p.semiRsrv("}", x.Right, true)
p.semiRsrv("}", x.Right)
case x.ReplyVar:
p.WriteString("${|")
p.nestedStmts(x.StmtList, x.Right)
p.wantSpace = false
p.semiRsrv("}", x.Right, true)
p.semiRsrv("}", x.Right)
default:
p.WriteString("$(")
p.wantSpace = len(x.Stmts) > 0 && startsWithLparen(x.Stmts[0])
@ -478,14 +486,19 @@ func (p *Printer) wordPart(wp, next WordPart) {
p.rightParen(x.Right)
}
case *ParamExp:
nextLit, ok := next.(*Lit)
litCont := ";"
if ok {
if nextLit, ok := next.(*Lit); ok {
litCont = nextLit.Value[:1]
}
if p.minify && !x.Excl && !x.Length && !x.Width &&
x.Index == nil && x.Slice == nil && x.Repl == nil &&
x.Exp == nil && !ValidName(x.Param.Value+litCont) {
name := x.Param.Value
switch {
case !p.minify:
case x.Excl, x.Length, x.Width:
case x.Index != nil, x.Slice != nil:
case x.Repl != nil, x.Exp != nil:
case len(name) > 1 && !ValidName(name): // ${10}
case ValidName(name + litCont): // ${var}cont
default:
x2 := *x
x2.Short = true
p.paramExp(&x2)
@ -510,7 +523,7 @@ func (p *Printer) wordPart(wp, next WordPart) {
}
p.WriteString(x.Op.String())
p.nestedStmts(x.StmtList, x.Rparen)
p.WriteByte(')')
p.rightParen(x.Rparen)
}
}
@ -787,8 +800,7 @@ func (p *Printer) stmt(s *Stmt) {
if r.OpPos.Line() > p.line {
p.bslashNewl()
}
if p.minify && r.N == nil {
} else if p.wantSpace {
if p.wantSpace {
p.spacePad(r.Pos())
}
if r.N != nil {
@ -839,8 +851,7 @@ func (p *Printer) command(cmd Command, redirs []*Redirect) (startRedirs int) {
if r.Pos().After(x.Args[1].Pos()) || r.Op == Hdoc || r.Op == DashHdoc {
break
}
if p.minify && r.N == nil {
} else if p.wantSpace {
if p.wantSpace {
p.spacePad(r.Pos())
}
if r.N != nil {
@ -860,7 +871,7 @@ func (p *Printer) command(cmd Command, redirs []*Redirect) (startRedirs int) {
p.WriteByte('{')
p.wantSpace = true
p.nestedStmts(x.StmtList, x.Rbrace)
p.semiRsrv("}", x.Rbrace, true)
p.semiRsrv("}", x.Rbrace)
case *IfClause:
p.ifClause(x, false)
case *Subshell:
@ -880,7 +891,7 @@ func (p *Printer) command(cmd Command, redirs []*Redirect) (startRedirs int) {
p.nestedStmts(x.Cond, Pos{})
p.semiOrNewl("do", x.DoPos)
p.nestedStmts(x.Do, x.DonePos)
p.semiRsrv("done", x.DonePos, true)
p.semiRsrv("done", x.DonePos)
case *ForClause:
if x.Select {
p.WriteString("select ")
@ -890,7 +901,7 @@ func (p *Printer) command(cmd Command, redirs []*Redirect) (startRedirs int) {
p.loop(x.Loop)
p.semiOrNewl("do", x.DoPos)
p.nestedStmts(x.Do, x.DonePos)
p.semiRsrv("done", x.DonePos, true)
p.semiRsrv("done", x.DonePos)
case *BinaryCmd:
p.stmt(x.X)
if p.minify || x.Y.Pos().Line() <= p.line {
@ -973,6 +984,8 @@ func (p *Printer) command(cmd Command, redirs []*Redirect) (startRedirs int) {
p.wantNewline = true
}
p.spacedToken(ci.Op.String(), ci.OpPos)
// avoid ; directly after tokens like ;;
p.wroteSemi = true
if inlineCom != nil {
p.comment(*inlineCom)
}
@ -984,7 +997,7 @@ func (p *Printer) command(cmd Command, redirs []*Redirect) (startRedirs int) {
p.flushComments()
p.decLevel()
}
p.semiRsrv("esac", x.Esac, len(x.Items) == 0)
p.semiRsrv("esac", x.Esac)
case *ArithmCmd:
p.WriteString("((")
if x.Unsigned {
@ -1037,17 +1050,17 @@ func (p *Printer) ifClause(ic *IfClause, elif bool) {
p.semiOrNewl("then", ic.ThenPos)
p.nestedStmts(ic.Then, ic.bodyEndPos())
if ic.FollowedByElif() {
p.semiRsrv("elif", ic.ElsePos, true)
p.semiRsrv("elif", ic.ElsePos)
p.ifClause(ic.Else.Stmts[0].Cmd.(*IfClause), true)
return
}
if !ic.Else.empty() {
p.semiRsrv("else", ic.ElsePos, true)
p.semiRsrv("else", ic.ElsePos)
p.nestedStmts(ic.Else, ic.FiPos)
} else if ic.ElsePos.IsValid() {
p.line = ic.ElsePos.Line()
}
p.semiRsrv("fi", ic.FiPos, true)
p.semiRsrv("fi", ic.FiPos)
}
func startsWithLparen(s *Stmt) bool {
@ -1069,7 +1082,7 @@ func (p *Printer) hasInline(s *Stmt) bool {
return false
}
func (p *Printer) stmts(sl StmtList) {
func (p *Printer) stmtList(sl StmtList) {
sep := p.wantNewline ||
(len(sl.Stmts) > 0 && sl.Stmts[0].Pos().Line() > p.line)
inlineIndent := 0
@ -1216,7 +1229,7 @@ func (p *Printer) nestedStmts(sl StmtList, closing Pos) {
// do foo; done
p.wantNewline = true
}
p.stmts(sl)
p.stmtList(sl)
if closing.IsValid() {
p.flushComments()
}