package shellquote

import (
	
	
	
)

// Join quotes each argument and joins them with a space.
// If passed to /bin/sh, the resulting string will be split back into the
// original arguments.
func ( ...string) string {
	var  bytes.Buffer
	for ,  := range  {
		if  != 0 {
			.WriteByte(' ')
		}
		quote(, &)
	}
	return .String()
}

const (
	specialChars      = "\\'\"`${[|&;<>()*?!"
	extraSpecialChars = " \t\n"
	prefixChars       = "~"
)

func quote( string,  *bytes.Buffer) {
	// We want to try to produce a "nice" output. As such, we will
	// backslash-escape most characters, but if we encounter a space, or if we
	// encounter an extra-special char (which doesn't work with
	// backslash-escaping) we switch over to quoting the whole word. We do this
	// with a space because it's typically easier for people to read multi-word
	// arguments when quoted with a space rather than with ugly backslashes
	// everywhere.
	 := .Len()

	if len() == 0 {
		// oops, no content
		.WriteString("''")
		return
	}

	,  := , 
	 := true
	for len() > 0 {
		,  := utf8.DecodeRuneInString()
		 = [:]
		if strings.ContainsRune(specialChars, ) || ( && strings.ContainsRune(prefixChars, )) {
			// copy the non-special chars up to this point
			if len() < len() {
				.WriteString([0 : len()-len()-])
			}
			.WriteByte('\\')
			.WriteRune()
			 = 
		} else if strings.ContainsRune(extraSpecialChars, ) {
			// start over in quote mode
			.Truncate()
			goto 
		}
		 = false
	}
	if len() > 0 {
		.WriteString()
	}
	return

:
	// quote mode
	// Use single-quotes, but if we find a single-quote in the word, we need
	// to terminate the string, emit an escaped quote, and start the string up
	// again
	 := false
	for len() > 0 {
		 := strings.IndexRune(, '\'')
		if  == -1 {
			break
		}
		if  > 0 {
			if ! {
				.WriteByte('\'')
				 = true
			}
			.WriteString([0:])
		}
		 = [+1:]
		if  {
			.WriteByte('\'')
			 = false
		}
		.WriteString("\\'")
	}
	if len() > 0 {
		if ! {
			.WriteByte('\'')
		}
		.WriteString()
		.WriteByte('\'')
	}
}