diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..c73450b --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/fumiama/go-hide-param + +go 1.16 diff --git a/unix.go b/unix.go new file mode 100644 index 0000000..58f8fa6 --- /dev/null +++ b/unix.go @@ -0,0 +1,15 @@ +// +build !windows + +package gohideparam + +import ( + "os" + "unsafe" +) + +func Hide(position uint) { + pwdstr := (*[2]uintptr)(unsafe.Pointer(&os.Args[position])) + for i := 0; i < len(os.Args[3]); i++ { + *(*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(pwdstr)) + uintptr(i))) = '*' + } +} diff --git a/win.go b/win.go new file mode 100644 index 0000000..c1c7319 --- /dev/null +++ b/win.go @@ -0,0 +1,98 @@ +// +build windows + +package gohideparam + +import ( + "os" + "syscall" + "unsafe" +) + +// Slice is the runtime representation of a slice. +// It cannot be used safely or portably and its representation may +// change in a later release. +// +// Unlike reflect.SliceHeader, its Data field is sufficient to guarantee the +// data it references will not be garbage collected. +type Slice struct { + Data unsafe.Pointer + Len int + Cap int +} + +// readNextArg splits command line string cmd into next +// argument and command line remainder. +func readNextArg(cmd *[]uint16, is2erase bool) { + var inquote bool + var nslash int + for ; len(*cmd) > 0; (*cmd) = (*cmd)[1:] { + switch (*cmd)[0] { + case uint16(' '), uint16('\t'): + if !inquote { + return + } + case uint16('"'): + if nslash%2 == 0 { + // use "Prior to 2008" rule from + // http://daviddeley.com/autohotkey/parameters/parameters.htm + // section 5.2 to deal with double double quotes + if inquote && len(*cmd) > 1 && (*cmd)[1] == uint16('"') { + *cmd = (*cmd)[1:] + } + inquote = !inquote + } + nslash = 0 + continue + case uint16('\\'): + nslash++ + if is2erase { + (*cmd)[0] = uint16('*') + } + continue + default: + if is2erase { + (*cmd)[0] = uint16('*') + } + } + nslash = 0 + } +} + +func eraseCommandLine(cmd *[]uint16, pos uint) { + var p uint + for len(*cmd) > 0 && p <= pos { + if (*cmd)[0] == uint16(' ') || (*cmd)[0] == uint16('\t') { + (*cmd) = (*cmd)[1:] + continue + } + readNextArg(cmd, p == pos) + p++ + } +} + +func utf16PtrToSlice(p *uint16) []uint16 { + if p == nil { + return nil + } + // Find NUL terminator. + end := unsafe.Pointer(p) + n := 0 + for *(*uint16)(end) != 0 { + end = unsafe.Pointer(uintptr(end) + unsafe.Sizeof(*p)) + n++ + } + // Turn *uint16 into []uint16. + var s []uint16 + hdr := (*Slice)(unsafe.Pointer(&s)) + hdr.Data = unsafe.Pointer(p) + hdr.Cap = n + hdr.Len = n + return s +} + +func Hide(position uint) { + if position < uint(len(os.Args)) { + cmd := utf16PtrToSlice(syscall.GetCommandLine()) + eraseCommandLine(&cmd, position) + } +}