github.com/andrewsun2898/u-root@v6.0.1-0.20200616011413-4b2895c1b815+incompatible/cmds/core/comm/comm.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 // comm compares two files. 6 // 7 // Synopsis: 8 // comm [-123h] FILE1 FILE2 9 // 10 // Descrption: 11 // Comm reads file1 and file2, which are in lexicographical order, and 12 // produces a three column output: lines only in file1; lines only in 13 // file2; and lines in both files. The file name – means the standard 14 // input. 15 // 16 // Options: 17 // -1: suppress printing of column 1 18 // -2: suppress printing of column 2 19 // -3: suppress printing of column 3 20 // -h: print this help message and exit 21 package main 22 23 import ( 24 "bufio" 25 "flag" 26 "fmt" 27 "log" 28 "os" 29 "strings" 30 ) 31 32 const cmd = "comm [-123h] file1 file2" 33 34 var ( 35 s1 = flag.Bool("1", false, "suppress printing of column 1") 36 s2 = flag.Bool("2", false, "suppress printing of column 2") 37 s3 = flag.Bool("3", false, "suppress printing of column 3") 38 help = flag.Bool("h", false, "print this help message and exit") 39 ) 40 41 func init() { 42 defUsage := flag.Usage 43 flag.Usage = func() { 44 os.Args[0] = cmd 45 defUsage() 46 } 47 } 48 49 func reader(f *os.File, c chan string) { 50 b := bufio.NewReader(f) 51 52 for { 53 s, err := b.ReadString('\n') 54 c <- strings.TrimRight(s, "\r\n") 55 if err != nil { 56 break 57 } 58 } 59 close(c) 60 } 61 62 type out struct { 63 s1, s2, s3 string 64 } 65 66 func outer(c1, c2 chan string, c chan out) { 67 s1, ok1 := <-c1 68 s2, ok2 := <-c2 69 for { 70 if ok1 && ok2 { 71 switch { 72 case s1 < s2: 73 c <- out{s1, "", ""} 74 s1, ok1 = <-c1 75 case s1 > s2: 76 c <- out{"", s2, ""} 77 s2, ok2 = <-c2 78 default: 79 c <- out{"", "", s2} 80 s1, ok1 = <-c1 81 s2, ok2 = <-c2 82 } 83 } else if ok1 { 84 c <- out{s1, "", ""} 85 s1, ok1 = <-c1 86 } else if ok2 { 87 c <- out{"", s2, ""} 88 s2, ok2 = <-c2 89 } else { 90 break 91 } 92 } 93 close(c) 94 } 95 96 func main() { 97 flag.Parse() 98 if flag.NArg() != 2 || *help { 99 flag.Usage() 100 os.Exit(1) 101 } 102 103 c1 := make(chan string, 100) 104 c2 := make(chan string, 100) 105 c := make(chan out, 100) 106 107 f1, err := os.Open(flag.Args()[0]) 108 if err != nil { 109 log.Fatalf("Can't open %s: %v", flag.Args()[0], err) 110 } 111 112 f2, err := os.Open(flag.Args()[1]) 113 if err != nil { 114 log.Fatalf("Can't open %s: %v", flag.Args()[1], err) 115 } 116 go reader(f1, c1) 117 go reader(f2, c2) 118 go outer(c1, c2, c) 119 120 for { 121 out, ok := <-c 122 if !ok { 123 break 124 } 125 126 line := "" 127 if !*s1 { 128 line += out.s1 129 } 130 line += "\t" 131 if !*s2 { 132 line += out.s2 133 } 134 line += "\t" 135 if !*s3 { 136 line += out.s3 137 } 138 if line != "\t\t" { 139 fmt.Println(strings.TrimRight(line, "\t")) // the unix comm utility does this 140 } 141 } 142 }