mirror of
				https://github.com/coredns/coredns.git
				synced 2025-10-30 17:53:21 -04:00 
			
		
		
		
	
		
			
	
	
		
			121 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			121 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
|  | package middleware
 | ||
|  | 
 | ||
|  | import (
 | ||
|  | 	"errors"
 | ||
|  | 	"runtime"
 | ||
|  | 	"unicode"
 | ||
|  | 
 | ||
|  | 	"github.com/flynn/go-shlex"
 | ||
|  | )
 | ||
|  | 
 | ||
|  | var runtimeGoos = runtime.GOOS
 | ||
|  | 
 | ||
|  | // SplitCommandAndArgs takes a command string and parses it
 | ||
|  | // shell-style into the command and its separate arguments.
 | ||
|  | func SplitCommandAndArgs(command string) (cmd string, args []string, err error) {
 | ||
|  | 	var parts []string
 | ||
|  | 
 | ||
|  | 	if runtimeGoos == "windows" {
 | ||
|  | 		parts = parseWindowsCommand(command) // parse it Windows-style
 | ||
|  | 	} else {
 | ||
|  | 		parts, err = parseUnixCommand(command) // parse it Unix-style
 | ||
|  | 		if err != nil {
 | ||
|  | 			err = errors.New("error parsing command: " + err.Error())
 | ||
|  | 			return
 | ||
|  | 		}
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	if len(parts) == 0 {
 | ||
|  | 		err = errors.New("no command contained in '" + command + "'")
 | ||
|  | 		return
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	cmd = parts[0]
 | ||
|  | 	if len(parts) > 1 {
 | ||
|  | 		args = parts[1:]
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	return
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // parseUnixCommand parses a unix style command line and returns the
 | ||
|  | // command and its arguments or an error
 | ||
|  | func parseUnixCommand(cmd string) ([]string, error) {
 | ||
|  | 	return shlex.Split(cmd)
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // parseWindowsCommand parses windows command lines and
 | ||
|  | // returns the command and the arguments as an array. It
 | ||
|  | // should be able to parse commonly used command lines.
 | ||
|  | // Only basic syntax is supported:
 | ||
|  | //  - spaces in double quotes are not token delimiters
 | ||
|  | //  - double quotes are escaped by either backspace or another double quote
 | ||
|  | //  - except for the above case backspaces are path separators (not special)
 | ||
|  | //
 | ||
|  | // Many sources point out that escaping quotes using backslash can be unsafe.
 | ||
|  | // Use two double quotes when possible. (Source: http://stackoverflow.com/a/31413730/2616179 )
 | ||
|  | //
 | ||
|  | // This function has to be used on Windows instead
 | ||
|  | // of the shlex package because this function treats backslash
 | ||
|  | // characters properly.
 | ||
|  | func parseWindowsCommand(cmd string) []string {
 | ||
|  | 	const backslash = '\\'
 | ||
|  | 	const quote = '"'
 | ||
|  | 
 | ||
|  | 	var parts []string
 | ||
|  | 	var part string
 | ||
|  | 	var inQuotes bool
 | ||
|  | 	var lastRune rune
 | ||
|  | 
 | ||
|  | 	for i, ch := range cmd {
 | ||
|  | 
 | ||
|  | 		if i != 0 {
 | ||
|  | 			lastRune = rune(cmd[i-1])
 | ||
|  | 		}
 | ||
|  | 
 | ||
|  | 		if ch == backslash {
 | ||
|  | 			// put it in the part - for now we don't know if it's an
 | ||
|  | 			// escaping char or path separator
 | ||
|  | 			part += string(ch)
 | ||
|  | 			continue
 | ||
|  | 		}
 | ||
|  | 
 | ||
|  | 		if ch == quote {
 | ||
|  | 			if lastRune == backslash {
 | ||
|  | 				// remove the backslash from the part and add the escaped quote instead
 | ||
|  | 				part = part[:len(part)-1]
 | ||
|  | 				part += string(ch)
 | ||
|  | 				continue
 | ||
|  | 			}
 | ||
|  | 
 | ||
|  | 			if lastRune == quote {
 | ||
|  | 				// revert the last change of the inQuotes state
 | ||
|  | 				// it was an escaping quote
 | ||
|  | 				inQuotes = !inQuotes
 | ||
|  | 				part += string(ch)
 | ||
|  | 				continue
 | ||
|  | 			}
 | ||
|  | 
 | ||
|  | 			// normal escaping quotes
 | ||
|  | 			inQuotes = !inQuotes
 | ||
|  | 			continue
 | ||
|  | 
 | ||
|  | 		}
 | ||
|  | 
 | ||
|  | 		if unicode.IsSpace(ch) && !inQuotes && len(part) > 0 {
 | ||
|  | 			parts = append(parts, part)
 | ||
|  | 			part = ""
 | ||
|  | 			continue
 | ||
|  | 		}
 | ||
|  | 
 | ||
|  | 		part += string(ch)
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	if len(part) > 0 {
 | ||
|  | 		parts = append(parts, part)
 | ||
|  | 		part = ""
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	return parts
 | ||
|  | }
 |