github.com/mem/u-root@v2.0.1-0.20181004165302-9b18b4636a33+incompatible/cmds/sort/sort.go (about)

     1  // Copyright 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  // Sort lines.
     6  //
     7  // Synopsis:
     8  //     sort [OPTIONS]... [INPUT]...
     9  //
    10  // Description:
    11  //     Sort copies lines from the input to the output, sorting them in the
    12  //     process. This does nothing fancy (no multi-threading, compression,
    13  //     optiminzations, ...); it simply uses Go's sort.Sort function.
    14  //
    15  // Options:
    16  //     -r:      reverse
    17  //     -o FILE: output file
    18  package main
    19  
    20  import (
    21  	"flag"
    22  	"io/ioutil"
    23  	"log"
    24  	"os"
    25  	"sort"
    26  	"strings"
    27  )
    28  
    29  var (
    30  	reverse    = flag.Bool("r", false, "Reverse")
    31  	outputFile = flag.String("o", "", "Output file")
    32  )
    33  
    34  func readInput() string {
    35  	// Input files
    36  	from := []*os.File{}
    37  	if flag.NArg() > 0 {
    38  		for _, v := range flag.Args() {
    39  			if f, err := os.Open(v); err == nil {
    40  				from = append(from, f)
    41  				defer f.Close()
    42  			} else {
    43  				log.Fatal(err)
    44  			}
    45  		}
    46  	} else {
    47  		from = []*os.File{os.Stdin}
    48  	}
    49  
    50  	// Read unicode string from input
    51  	fileContents := []string{}
    52  	for _, f := range from {
    53  		bytes, err := ioutil.ReadAll(f)
    54  		if err != nil {
    55  			log.Fatal(err)
    56  		}
    57  		s := string(bytes)
    58  		fileContents = append(fileContents, s)
    59  		// Add a separator between files if the file is not newline
    60  		// terminated. Prevents concatenating lines between files.
    61  		if len(s) > 0 && s[len(s)-1] != '\n' {
    62  			fileContents = append(fileContents, "\n")
    63  		}
    64  	}
    65  	return strings.Join(fileContents, "")
    66  }
    67  
    68  func sortAlgorithm(s string) string {
    69  	if len(s) == 0 {
    70  		return "" // edge case mimics coreutils
    71  	}
    72  	if s[len(s)-1] == '\n' {
    73  		s = s[:len(s)-1] // remove newline terminator
    74  	}
    75  	lines := strings.Split(string(s), "\n")
    76  	if *reverse {
    77  		sort.Sort(sort.Reverse(sort.StringSlice(lines)))
    78  	} else {
    79  		sort.Strings(lines)
    80  	}
    81  	return strings.Join(lines, "\n") + "\n" // append newline terminator
    82  }
    83  
    84  func writeOutput(s string) {
    85  	to := os.Stdout
    86  	if *outputFile != "" {
    87  		if f, err := os.Create(*outputFile); err == nil {
    88  			to = f
    89  			defer f.Close()
    90  		} else {
    91  			log.Fatal(err)
    92  		}
    93  	}
    94  	to.Write([]byte(s))
    95  }
    96  
    97  func main() {
    98  	flag.Parse()
    99  
   100  	// Input files must be closed before writing to output files to solve
   101  	// the situtation in which the output file is the same as an input.
   102  	writeOutput(sortAlgorithm(readInput()))
   103  }