mirror of
https://github.com/johnkerl/miller.git
synced 2026-01-23 02:14:13 +00:00
* Static-check fixes from @lespea #1657, batch 2/n * Static-check fixes from @lespea #1657, batch 3/n * Static-check fixes from @lespea #1657, batch 4/n
154 lines
4 KiB
Go
154 lines
4 KiB
Go
// ================================================================
|
|
// Handling single quotes and double quotes is different on Windows unless
|
|
// particular care is taken, which is what this file does.
|
|
// ================================================================
|
|
|
|
//go:build windows
|
|
// +build windows
|
|
|
|
package platform
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
shellquote "github.com/kballard/go-shellquote"
|
|
"golang.org/x/sys/windows"
|
|
)
|
|
|
|
// GetArgs returns a copy of os.Args, as-is except for any arg wrapped in single quotes.
|
|
// This is for compatibility Linux/Unix/MacOS.
|
|
//
|
|
// For example:
|
|
//
|
|
// mlr --icsv --ojson put '$filename = $basename . ".ext"' ..\data\foo.csv
|
|
//
|
|
// The Windows way to say that is
|
|
//
|
|
// mlr --icsv --ojson put "$filename = $basename . """.ext"""" ..\data\foo.csv
|
|
//
|
|
// This function makes it possible to say the former, or the latter.
|
|
|
|
func GetArgs() []string {
|
|
// If this code is running in MSYS2: MSYS2 does the right thing already and
|
|
// we won't try to improve on that. This is true regardless of whether we
|
|
// were compiled inside MSYS2 or outside; what matters is whether we're
|
|
// _running_ inside MSYS2 or outside. (I.e. this is necessarily a run-time
|
|
// check, not a compile-time check.)
|
|
msystem := os.Getenv("MSYSTEM")
|
|
if msystem != "" {
|
|
return os.Args
|
|
}
|
|
|
|
//printArgs(os.Args, "ORIGINAL")
|
|
|
|
regrouped, ok := regroupForSingleQuote(os.Args)
|
|
if !ok {
|
|
return os.Args
|
|
}
|
|
//printArgs(regrouped, "REGROUPED")
|
|
|
|
// Things on the command line include: args[0], which is fine as-is;
|
|
// various flags like -x or --xyz which are fine as-is; DSL expressions
|
|
// such as '$a = $b . "ccc"'. We don't want to give back the result of
|
|
// shellquote.Split since that will remove the backslashes from things like
|
|
// ..\data\foo\dat or C:\foo\bar.baz.
|
|
rawCommandLine := windows.UTF16PtrToString(windows.GetCommandLine())
|
|
splitArgs, err := shellquote.Split(rawCommandLine)
|
|
if err != nil {
|
|
fmt.Fprintf(
|
|
os.Stderr,
|
|
"mlr: internal error: could not parse Windows raw command line: %v\n",
|
|
err,
|
|
)
|
|
}
|
|
|
|
retargs := make([]string, 0)
|
|
|
|
// TODO err/stetret if lens uneq
|
|
|
|
for i, oldArg := range regrouped {
|
|
if strings.HasPrefix(oldArg, "'") && strings.HasSuffix(oldArg, "'") {
|
|
retargs = append(retargs, splitArgs[i])
|
|
} else {
|
|
retargs = append(retargs, regrouped[i])
|
|
}
|
|
}
|
|
//printArgs(retargs, "NEW")
|
|
|
|
globbed := make([]string, 0)
|
|
for i := range retargs {
|
|
// Expand things like *.csv
|
|
matches, err := filepath.Glob(retargs[i])
|
|
if matches != nil && err == nil {
|
|
globbed = append(globbed, matches...)
|
|
} else {
|
|
globbed = append(globbed, retargs[i])
|
|
}
|
|
}
|
|
//printArgs(globbed, "NEW")
|
|
|
|
return globbed
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
func printArgs(args []string, description string) {
|
|
fmt.Printf("%s:\n", description)
|
|
for i, arg := range args {
|
|
fmt.Printf("%d %s\n", i, arg)
|
|
}
|
|
fmt.Println()
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
func regroupForSingleQuote(inargs []string) ([]string, bool) {
|
|
outargs := make([]string, 0, len(inargs))
|
|
inside := false
|
|
var concat string
|
|
|
|
// TODO: comment
|
|
// TODO: UT this all
|
|
for _, inarg := range inargs {
|
|
if !inside {
|
|
if !strings.HasPrefix(inarg, "'") {
|
|
// Current arg is not single-quoted, and not inside a single-quoted region
|
|
outargs = append(outargs, inarg)
|
|
|
|
} else {
|
|
|
|
// Start of single-quoted region
|
|
if strings.HasSuffix(inarg, "'") {
|
|
// Start and end of single-quoted region, like '$y=$x'
|
|
outargs = append(outargs, inarg)
|
|
} else {
|
|
// Start but not end of single-quoted region, like '$y=
|
|
inside = true
|
|
concat = inarg
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
if !strings.HasSuffix(inarg, "'") {
|
|
// Continuation of single-quoted region
|
|
concat = concat + " " + inarg
|
|
|
|
} else {
|
|
// End of single-quoted region
|
|
inside = false
|
|
concat = concat + " " + inarg
|
|
outargs = append(outargs, concat)
|
|
concat = ""
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: error not bool?
|
|
if inside {
|
|
return nil, false
|
|
}
|
|
|
|
return outargs, true
|
|
}
|