github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/cmds/exp/freq/freq.go (about)

     1  // Copyright 2013-2017 the u-root 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  // Freq reads the given files (default standard input) and prints histograms of the
     6  // character frequencies. By default, freq counts each byte as a character; under
     7  // the –r option it instead counts UTF sequences, that is, runes.
     8  //
     9  // Synopsis:
    10  //
    11  //	freq [-rdxoc] [FILES]...
    12  //
    13  // Description:
    14  //
    15  //	Each non–zero entry of the table is printed preceded by the byte value,
    16  //	in decimal, octal, hex, and Unicode character (if printable). If any
    17  //	options are given, the –d, –x, –o, –c flags specify a subset of value
    18  //	formats: decimal, hex, octal, and character, respectively.
    19  //
    20  // Options:
    21  //
    22  //	–r: treat input as UTF-8
    23  //	–d: print decimal value
    24  //	–x: print hex value
    25  //	–o: print octal value
    26  //	–c: print character/UTF value
    27  package main
    28  
    29  import (
    30  	"bufio"
    31  	"flag"
    32  	"fmt"
    33  	"io"
    34  	"os"
    35  	"unicode/utf8"
    36  )
    37  
    38  var (
    39  	utf = flag.Bool("r", false, "treat input as UTF-8")
    40  	dec = flag.Bool("d", false, "print decimal value")
    41  	hex = flag.Bool("x", false, "print hexadecimal value")
    42  	oct = flag.Bool("o", false, "print octal value")
    43  	chr = flag.Bool("c", false, "print character/rune")
    44  )
    45  
    46  var freq [utf8.MaxRune + 1]uint64
    47  
    48  func doFreq(f *os.File) {
    49  	b := bufio.NewReaderSize(f, 8192)
    50  
    51  	var r rune
    52  	var c byte
    53  	var err error
    54  	if *utf {
    55  		for {
    56  			r, _, err = b.ReadRune()
    57  			if err != nil {
    58  				if err != io.EOF {
    59  					fmt.Fprintf(os.Stderr, "error reading: %v", err)
    60  				}
    61  				return
    62  			}
    63  			freq[r]++
    64  		}
    65  	} else {
    66  		for {
    67  			c, err = b.ReadByte()
    68  			if err != nil {
    69  				if err != io.EOF {
    70  					fmt.Fprintf(os.Stderr, "error reading: %v", err)
    71  				}
    72  				return
    73  			}
    74  			freq[c]++
    75  		}
    76  	}
    77  }
    78  
    79  func main() {
    80  	flag.Parse()
    81  
    82  	if flag.NArg() > 0 {
    83  		for _, v := range flag.Args() {
    84  			f, err := os.Open(v)
    85  			if err != nil {
    86  				fmt.Fprintf(os.Stderr, "open %s: %v", v, err)
    87  				os.Exit(1)
    88  			}
    89  			doFreq(f)
    90  			f.Close()
    91  		}
    92  	} else {
    93  		doFreq(os.Stdin)
    94  	}
    95  
    96  	if !(*dec || *hex || *oct || *chr) {
    97  		*dec, *hex, *oct, *chr = true, true, true, true
    98  	}
    99  
   100  	b := bufio.NewWriterSize(os.Stdout, 8192*4)
   101  	for i, v := range freq {
   102  		if v == 0 {
   103  			continue
   104  		}
   105  
   106  		if *dec {
   107  			fmt.Fprintf(b, "%3d ", i)
   108  		}
   109  		if *oct {
   110  			fmt.Fprintf(b, "%.3o ", i)
   111  		}
   112  		if *hex {
   113  			fmt.Fprintf(b, "%.2x ", i)
   114  		}
   115  		if *chr {
   116  			if i <= 0x20 || (i >= 0x7f && i < 0xa0) || (i > 0xff && !(*utf)) {
   117  				b.WriteString("- ")
   118  			} else {
   119  				b.WriteRune(rune(i))
   120  				b.WriteString(" ")
   121  			}
   122  		}
   123  		fmt.Fprintf(b, "%8d\n", v)
   124  	}
   125  	b.Flush()
   126  }