Home | History | Annotate | Download | only in demangle
      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