From f062d7b10b276c1b698819f492e4b4754e160ee3 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 20 Feb 2025 22:20:38 -0800 Subject: [PATCH] cmd/go: look at runes, not bytes, when printing env vars For #58508 Fixes #71863 Change-Id: Ib1ebaf751bcc6900da6ffd01a9462dd237e2c89a Reviewed-on: https://go-review.googlesource.com/c/go/+/651295 LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor Reviewed-by: Michael Matloob Reviewed-by: Michael Knyszek --- src/cmd/go/internal/envcmd/env.go | 53 +++++++++++++++++-------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/src/cmd/go/internal/envcmd/env.go b/src/cmd/go/internal/envcmd/env.go index 7c370d427f..f0a6989a57 100644 --- a/src/cmd/go/internal/envcmd/env.go +++ b/src/cmd/go/internal/envcmd/env.go @@ -522,51 +522,56 @@ func PrintEnv(w io.Writer, env []cfg.EnvVar, onlyChanged bool) { } } +// isWindowsUnquotableRune reports whether r can't be quoted in a +// Windows "set" command. +// These runes will be replaced by the Unicode replacement character. +func isWindowsUnquotableRune(r rune) bool { + if r == '\r' || r == '\n' { + return true + } + return !unicode.IsGraphic(r) && !unicode.IsSpace(r) +} + func hasNonGraphic(s string) bool { - for _, c := range []byte(s) { - if c == '\r' || c == '\n' || (!unicode.IsGraphic(rune(c)) && !unicode.IsSpace(rune(c))) { - return true - } - } - return false + return strings.ContainsFunc(s, isWindowsUnquotableRune) } func shellQuote(s string) string { - var b bytes.Buffer - b.WriteByte('\'') - for _, x := range []byte(s) { - if x == '\'' { + var sb strings.Builder + sb.WriteByte('\'') + for _, r := range s { + if r == '\'' { // Close the single quoted string, add an escaped single quote, // and start another single quoted string. - b.WriteString(`'\''`) + sb.WriteString(`'\''`) } else { - b.WriteByte(x) + sb.WriteRune(r) } } - b.WriteByte('\'') - return b.String() + sb.WriteByte('\'') + return sb.String() } func batchEscape(s string) string { - var b bytes.Buffer - for _, x := range []byte(s) { - if x == '\r' || x == '\n' || (!unicode.IsGraphic(rune(x)) && !unicode.IsSpace(rune(x))) { - b.WriteRune(unicode.ReplacementChar) + var sb strings.Builder + for _, r := range s { + if isWindowsUnquotableRune(r) { + sb.WriteRune(unicode.ReplacementChar) continue } - switch x { + switch r { case '%': - b.WriteString("%%") + sb.WriteString("%%") case '<', '>', '|', '&', '^': // These are special characters that need to be escaped with ^. See // https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/set_1. - b.WriteByte('^') - b.WriteByte(x) + sb.WriteByte('^') + sb.WriteRune(r) default: - b.WriteByte(x) + sb.WriteRune(r) } } - return b.String() + return sb.String() } func printEnvAsJSON(env []cfg.EnvVar, onlyChanged bool) { -- 2.50.0