• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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