1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
// 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
}
|