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 10 package main 11 12 import ( 13 "bufio" 14 "flag" 15 "fmt" 16 "io" 17 "os" 18 "strings" 19 "unicode" 20 21 "github.com/ianlancetaylor/demangle" 22 ) 23 24 func flagUsage() { 25 usage(os.Stderr, 2) 26 } 27 28 func 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 33 If a name cannot be demangled it is just echoed to stdout. 34 If no names are provided on the command line, stdin is read.`) 35 os.Exit(status) 36 } 37 38 var stripUnderscore = flag.Bool("_", false, "Ignore first leading underscore") 39 var noParams = flag.Bool("p", false, "Do not display function argument types") 40 var noVerbose = flag.Bool("i", false, "Do not show implementation details (if any)") 41 var help = flag.Bool("h", false, "Display help information") 42 var 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. 51 const symbolChars = "_$." 52 53 func 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. 114 func 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. 135 func 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