1// Copyright 2015 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// +build ignore 6 7// This is a program that works like the GNU c++filt program. 8// It's here for testing purposes and as an example. 9 10package main 11 12import ( 13 "bufio" 14 "flag" 15 "fmt" 16 "io" 17 "os" 18 "strings" 19 "unicode" 20 21 "github.com/ianlancetaylor/demangle" 22) 23 24func flagUsage() { 25 usage(os.Stderr, 2) 26} 27 28func usage(w io.Writer, status int) { 29 fmt.Fprintf(w, "Usage: %s [options] [mangled names]\n", os.Args[0]) 30 flag.CommandLine.SetOutput(w) 31 flag.PrintDefaults() 32 fmt.Fprintln(w, `Demangled names are displayed to stdout 33If a name cannot be demangled it is just echoed to stdout. 34If no names are provided on the command line, stdin is read.`) 35 os.Exit(status) 36} 37 38var stripUnderscore = flag.Bool("_", false, "Ignore first leading underscore") 39var noParams = flag.Bool("p", false, "Do not display function argument types") 40var noVerbose = flag.Bool("i", false, "Do not show implementation details (if any)") 41var help = flag.Bool("h", false, "Display help information") 42var debug = flag.Bool("d", false, "Display debugging information for strings on command line") 43 44// Unimplemented c++filt flags: 45// -n (opposite of -_) 46// -t (demangle types) 47// -s (set demangling style) 48// -V (print version information) 49 50// Characters considered to be part of a symbol. 51const symbolChars = "_$." 52 53func main() { 54 flag.Usage = func() { usage(os.Stderr, 1) } 55 flag.Parse() 56 57 if *help { 58 usage(os.Stdout, 0) 59 } 60 61 out := bufio.NewWriter(os.Stdout) 62 63 if flag.NArg() > 0 { 64 for _, f := range flag.Args() { 65 if *debug { 66 a, err := demangle.ToAST(f, options()...) 67 if err != nil { 68 fmt.Fprintf(os.Stderr, "%s: %v\n", f, err) 69 } else { 70 fmt.Fprintf(out, "%#v\n", a) 71 } 72 } else { 73 doDemangle(out, f) 74 } 75 out.WriteByte('\n') 76 } 77 if err := out.Flush(); err != nil { 78 fmt.Fprintln(os.Stderr, err) 79 os.Exit(2) 80 } 81 return 82 } 83 84 scanner := bufio.NewScanner(bufio.NewReader(os.Stdin)) 85 for scanner.Scan() { 86 line := scanner.Text() 87 start := -1 88 for i, c := range line { 89 if unicode.IsLetter(c) || unicode.IsNumber(c) || strings.ContainsRune(symbolChars, c) { 90 if start < 0 { 91 start = i 92 } 93 } else { 94 if start >= 0 { 95 doDemangle(out, line[start:i]) 96 } 97 out.WriteRune(c) 98 start = -1 99 } 100 } 101 if start >= 0 { 102 doDemangle(out, line[start:]) 103 start = -1 104 } 105 out.WriteByte('\n') 106 if err := out.Flush(); err != nil { 107 fmt.Fprintln(os.Stderr, err) 108 os.Exit(2) 109 } 110 } 111} 112 113// Demangle a string just as the GNU c++filt program does. 114func doDemangle(out *bufio.Writer, name string) { 115 skip := 0 116 if name[0] == '.' || name[0] == '$' { 117 skip++ 118 } 119 if *stripUnderscore && name[skip] == '_' { 120 skip++ 121 } 122 result := demangle.Filter(name[skip:], options()...) 123 if result == name[skip:] { 124 out.WriteString(name) 125 } else { 126 if name[0] == '.' { 127 out.WriteByte('.') 128 } 129 out.WriteString(result) 130 } 131} 132 133// options returns the demangling options to use based on the command 134// line flags. 135func options() []demangle.Option { 136 var options []demangle.Option 137 if *noParams { 138 options = append(options, demangle.NoParams) 139 } 140 if !*noVerbose { 141 options = append(options, demangle.Verbose) 142 } 143 return options 144} 145