| // Copyright 2015 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // +build ignore |
| |
| // This is a program that works like the GNU c++filt program. |
| // It's here for testing purposes and as an example. |
| |
| package main |
| |
| import ( |
| "bufio" |
| "flag" |
| "fmt" |
| "io" |
| "os" |
| "strings" |
| "unicode" |
| |
| "github.com/ianlancetaylor/demangle" |
| ) |
| |
| func flagUsage() { |
| usage(os.Stderr, 2) |
| } |
| |
| func usage(w io.Writer, status int) { |
| fmt.Fprintf(w, "Usage: %s [options] [mangled names]\n", os.Args[0]) |
| flag.CommandLine.SetOutput(w) |
| flag.PrintDefaults() |
| fmt.Fprintln(w, `Demangled names are displayed to stdout |
| If a name cannot be demangled it is just echoed to stdout. |
| If no names are provided on the command line, stdin is read.`) |
| os.Exit(status) |
| } |
| |
| var stripUnderscore = flag.Bool("_", false, "Ignore first leading underscore") |
| var noParams = flag.Bool("p", false, "Do not display function argument types") |
| var noVerbose = flag.Bool("i", false, "Do not show implementation details (if any)") |
| var help = flag.Bool("h", false, "Display help information") |
| var debug = flag.Bool("d", false, "Display debugging information for strings on command line") |
| |
| // Unimplemented c++filt flags: |
| // -n (opposite of -_) |
| // -t (demangle types) |
| // -s (set demangling style) |
| // -V (print version information) |
| |
| // Characters considered to be part of a symbol. |
| const symbolChars = "_$." |
| |
| func main() { |
| flag.Usage = func() { usage(os.Stderr, 1) } |
| flag.Parse() |
| |
| if *help { |
| usage(os.Stdout, 0) |
| } |
| |
| out := bufio.NewWriter(os.Stdout) |
| |
| if flag.NArg() > 0 { |
| for _, f := range flag.Args() { |
| if *debug { |
| a, err := demangle.ToAST(f, options()...) |
| if err != nil { |
| fmt.Fprintf(os.Stderr, "%s: %v\n", f, err) |
| } else { |
| fmt.Fprintf(out, "%#v\n", a) |
| } |
| } else { |
| doDemangle(out, f) |
| } |
| out.WriteByte('\n') |
| } |
| if err := out.Flush(); err != nil { |
| fmt.Fprintln(os.Stderr, err) |
| os.Exit(2) |
| } |
| return |
| } |
| |
| scanner := bufio.NewScanner(bufio.NewReader(os.Stdin)) |
| for scanner.Scan() { |
| line := scanner.Text() |
| start := -1 |
| for i, c := range line { |
| if unicode.IsLetter(c) || unicode.IsNumber(c) || strings.ContainsRune(symbolChars, c) { |
| if start < 0 { |
| start = i |
| } |
| } else { |
| if start >= 0 { |
| doDemangle(out, line[start:i]) |
| } |
| out.WriteRune(c) |
| start = -1 |
| } |
| } |
| if start >= 0 { |
| doDemangle(out, line[start:]) |
| start = -1 |
| } |
| out.WriteByte('\n') |
| if err := out.Flush(); err != nil { |
| fmt.Fprintln(os.Stderr, err) |
| os.Exit(2) |
| } |
| } |
| } |
| |
| // Demangle a string just as the GNU c++filt program does. |
| func doDemangle(out *bufio.Writer, name string) { |
| skip := 0 |
| if name[0] == '.' || name[0] == '$' { |
| skip++ |
| } |
| if *stripUnderscore && name[skip] == '_' { |
| skip++ |
| } |
| result := demangle.Filter(name[skip:], options()...) |
| if result == name[skip:] { |
| out.WriteString(name) |
| } else { |
| if name[0] == '.' { |
| out.WriteByte('.') |
| } |
| out.WriteString(result) |
| } |
| } |
| |
| // options returns the demangling options to use based on the command |
| // line flags. |
| func options() []demangle.Option { |
| var options []demangle.Option |
| if *noParams { |
| options = append(options, demangle.NoParams) |
| } |
| if !*noVerbose { |
| options = append(options, demangle.Verbose) |
| } |
| return options |
| } |