"Fossies" - the Fresh Open Source Software Archive

Member "sift-0.9.0/output.go" (22 Oct 2016, 11078 Bytes) of package /linux/privat/sift-0.9.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Go source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "output.go": 0.8.0_vs_0.9.0.

    1 // sift
    2 // Copyright (C) 2014-2016 Sven Taute
    3 //
    4 // This program is free software: you can redistribute it and/or modify
    5 // it under the terms of the GNU General Public License as published by
    6 // the Free Software Foundation, version 3 of the License.
    7 //
    8 // This program is distributed in the hope that it will be useful,
    9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
   10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   11 // GNU General Public License for more details.
   12 //
   13 // You should have received a copy of the GNU General Public License
   14 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
   15 
   16 package main
   17 
   18 import (
   19     "fmt"
   20     "path/filepath"
   21     "strings"
   22 )
   23 
   24 func resultHandler() {
   25     for result := range global.resultsChan {
   26         if options.TargetsOnly {
   27             fmt.Println(result.target)
   28             continue
   29         }
   30         global.totalTargetCount++
   31         result.applyConditions()
   32         printResult(result)
   33     }
   34     global.resultsDoneChan <- struct{}{}
   35 }
   36 
   37 func writeOutput(format string, a ...interface{}) {
   38     output := fmt.Sprintf(format, a...)
   39     _, err := global.outputFile.Write([]byte(output))
   40     if err != nil {
   41         errorLogger.Fatalln("cannot write to output file:", err)
   42     }
   43 }
   44 
   45 func printFilename(filename string, delim string) {
   46     if options.ShowFilename == "on" && !options.GroupByFile {
   47         if options.OutputUnixPath {
   48             filename = filepath.ToSlash(filename)
   49         }
   50         writeOutput(global.termHighlightFilename+"%s"+global.termHighlightReset+delim, filename)
   51     }
   52 }
   53 
   54 func printLineno(lineno int64, delim string) {
   55     if options.ShowLineNumbers {
   56         writeOutput(global.termHighlightLineno+"%d"+global.termHighlightReset+delim, lineno)
   57     }
   58 }
   59 
   60 func printColumnNo(m *Match) {
   61     if options.ShowColumnNumbers {
   62         writeOutput("%d"+options.FieldSeparator, m.start-m.lineStart+1)
   63     }
   64 }
   65 
   66 func printByteOffset(m *Match) {
   67     if options.ShowByteOffset {
   68         if options.OnlyMatching {
   69             writeOutput("%d"+options.FieldSeparator, m.start)
   70         } else {
   71             writeOutput("%d"+options.FieldSeparator, m.lineStart)
   72         }
   73     }
   74 }
   75 
   76 // printMatch prints the context after the previous match, the context before the match and the match itself
   77 func printMatch(match Match, lastMatch Match, target string, lastPrintedLine *int64) {
   78     var matchOutput = match.line
   79 
   80     if !options.InvertMatch {
   81         if options.Replace != "" {
   82             matchOutput = match.match
   83             var matchTest string
   84             if options.IgnoreCase {
   85                 tmp := []byte(match.match)
   86                 for i := 0; i < len(tmp); i++ {
   87                     bytesToLower(tmp, tmp, len(tmp))
   88                 }
   89                 matchTest = string(tmp)
   90             } else {
   91                 matchTest = match.match
   92             }
   93 
   94             var res []byte
   95             for _, re := range global.matchRegexes {
   96                 submatchIndexes := re.FindAllStringSubmatchIndex(matchTest, -1)
   97                 if len(submatchIndexes) > 0 {
   98                     for _, subIndex := range submatchIndexes {
   99                         res = re.ExpandString(res, options.Replace, matchOutput, subIndex)
  100                     }
  101                     break
  102                 }
  103             }
  104 
  105             matchOutput = string(res)
  106             if options.OutputLimit > 0 {
  107                 var end int
  108                 if options.OutputLimit > len(matchOutput) {
  109                     end = len(matchOutput)
  110                 } else {
  111                     end = options.OutputLimit
  112                 }
  113                 matchOutput = matchOutput[0:end]
  114             }
  115         } else {
  116             // replace option not used
  117             if options.OutputLimit > 0 {
  118                 var end int
  119                 if options.OutputLimit > len(matchOutput) {
  120                     end = len(matchOutput)
  121                 } else {
  122                     end = options.OutputLimit
  123                 }
  124                 matchOutput = matchOutput[0:end]
  125             }
  126             if options.Color == "on" {
  127                 start := match.start - match.lineStart
  128                 end := match.end - match.lineStart
  129                 if int(end) <= len(matchOutput) {
  130                     matchOutput = matchOutput[0:end] + global.termHighlightReset + matchOutput[end:]
  131                     matchOutput = matchOutput[0:start] + global.termHighlightMatch + matchOutput[start:]
  132                 }
  133             }
  134         }
  135     }
  136 
  137     // print contextAfter of the previous match
  138     contextBlockIncomplete := false
  139     if lastMatch.contextAfter != nil {
  140         contextLines := strings.Split(*lastMatch.contextAfter, "\n")
  141         for index, line := range contextLines {
  142             var lineno int64
  143             if options.Multiline {
  144                 multilineLineCount := len(strings.Split(lastMatch.line, "\n")) - 1
  145                 lineno = lastMatch.lineno + int64(index) + 1 + int64(multilineLineCount)
  146             } else {
  147                 lineno = lastMatch.lineno + int64(index) + 1
  148             }
  149             // line is not part of the current match
  150             if lineno < match.lineno {
  151                 printFilename(target, "-")
  152                 printLineno(lineno, "-")
  153                 writeOutput("%s\n", line)
  154                 *lastPrintedLine = lineno
  155             } else {
  156                 contextBlockIncomplete = true
  157             }
  158         }
  159     }
  160     if (lastMatch.contextAfter != nil || match.contextBefore != nil) && !contextBlockIncomplete {
  161         if match.lineno-int64(options.ContextBefore) > *lastPrintedLine+1 {
  162             // at least one line between the contextAfter of the previous match and the contextBefore of the current match
  163             fmt.Fprintln(global.outputFile, "--")
  164         }
  165     }
  166 
  167     // print contextBefore of the current match
  168     if match.contextBefore != nil {
  169         contextLines := strings.Split(*match.contextBefore, "\n")
  170         for index, line := range contextLines {
  171             lineno := match.lineno - int64(len(contextLines)) + int64(index)
  172             if lineno > *lastPrintedLine {
  173                 printFilename(target, "-")
  174                 printLineno(lineno, "-")
  175                 writeOutput("%s\n", line)
  176                 *lastPrintedLine = lineno
  177             }
  178         }
  179     }
  180 
  181     // print current match
  182     if options.Multiline {
  183         lines := strings.Split(match.line, "\n")
  184         if len(lines) > 1 && options.Replace == "" {
  185             firstLine := lines[0]
  186             lastLine := lines[len(lines)-1]
  187             firstLineOffset := match.start - match.lineStart
  188             lastLineOffset := int64(len(lastLine)) - (match.lineEnd - match.end)
  189 
  190             // first line of multiline match with partial highlighting
  191             printFilename(target, options.FieldSeparator)
  192             printLineno(match.lineno, options.FieldSeparator)
  193             printColumnNo(&match)
  194             printByteOffset(&match)
  195             writeOutput("%s%s%s%s\n", firstLine[0:firstLineOffset], global.termHighlightMatch,
  196                 firstLine[firstLineOffset:len(firstLine)], global.termHighlightReset)
  197 
  198             // lines 2 upto n-1 of multiline match with full highlighting
  199             for i := 1; i < len(lines)-1; i++ {
  200                 line := lines[i]
  201                 printFilename(target, options.FieldSeparator)
  202                 printLineno(match.lineno+int64(i), options.FieldSeparator)
  203                 writeOutput("%s%s%s\n", global.termHighlightMatch, line, global.termHighlightReset)
  204             }
  205 
  206             // last line of multiline match with partial highlighting
  207             printFilename(target, options.FieldSeparator)
  208             printLineno(match.lineno+int64(len(lines))-1, options.FieldSeparator)
  209             writeOutput("%s%s%s%s%s", global.termHighlightMatch, lastLine[0:lastLineOffset],
  210                 global.termHighlightReset, lastLine[lastLineOffset:len(lastLine)], options.OutputSeparator)
  211             *lastPrintedLine = match.lineno + int64(len(lines)-1)
  212         } else {
  213             // single line output in multiline mode or replace option used
  214             printFilename(target, options.FieldSeparator)
  215             printLineno(match.lineno, options.FieldSeparator)
  216             printColumnNo(&match)
  217             printByteOffset(&match)
  218             writeOutput("%s%s", matchOutput, options.OutputSeparator)
  219             *lastPrintedLine = match.lineno + int64(len(lines)-1)
  220         }
  221     } else {
  222         // single line output
  223         printFilename(target, options.FieldSeparator)
  224         printLineno(match.lineno, options.FieldSeparator)
  225         printColumnNo(&match)
  226         printByteOffset(&match)
  227         writeOutput("%s%s", matchOutput, options.OutputSeparator)
  228         *lastPrintedLine = match.lineno
  229     }
  230 }
  231 
  232 // printResult prints results using printMatch and handles various output options.
  233 func printResult(result *Result) {
  234     var matchCount int64
  235     target := result.target
  236     matches := result.matches
  237     if options.FilesWithoutMatch {
  238         if len(matches) == 0 {
  239             writeOutput("%s\n", target)
  240             global.totalResultCount++
  241         }
  242         return
  243     }
  244     if options.FilesWithMatches && !options.Count {
  245         if len(matches) > 0 {
  246             writeOutput("%s\n", target)
  247             global.totalMatchCount++
  248             global.totalResultCount++
  249         }
  250         return
  251     }
  252     if options.Count {
  253         matchCount = int64(len(matches))
  254         if options.Limit != 0 && matchCount > options.Limit {
  255             matchCount = options.Limit
  256         }
  257         if result.streaming {
  258         countingMatchesLoop:
  259             for matches := range result.matchChan {
  260                 matchCount += int64(len(matches))
  261                 if options.Limit != 0 && matchCount >= options.Limit {
  262                     matchCount = options.Limit
  263                     break countingMatchesLoop
  264                 }
  265             }
  266         }
  267         if options.FilesWithMatches {
  268             if matchCount > 0 {
  269                 writeOutput("%s"+options.FieldSeparator+"%d\n", target, matchCount)
  270             }
  271         } else {
  272             if options.ShowFilename == "on" {
  273                 writeOutput("%s"+options.FieldSeparator, target)
  274             }
  275             writeOutput("%d\n", matchCount)
  276         }
  277         global.totalMatchCount += matchCount
  278         if matchCount > 0 {
  279             global.totalResultCount++
  280         }
  281         return
  282     }
  283 
  284     if len(matches) == 0 {
  285         return
  286     }
  287 
  288     // print separator between file results if this is not the first result
  289     if global.totalMatchCount > 0 {
  290         if options.GroupByFile {
  291             fmt.Fprintln(global.outputFile, "")
  292         } else {
  293             if options.ContextBefore > 0 || options.ContextAfter > 0 {
  294                 fmt.Fprintln(global.outputFile, "--")
  295             }
  296         }
  297     }
  298 
  299     if result.isBinary && !options.BinarySkip && !options.BinaryAsText {
  300         filename := result.target
  301         if options.OutputUnixPath {
  302             filename = filepath.ToSlash(filename)
  303         }
  304         writeOutput("Binary file matches: %s\n", filename)
  305         global.totalMatchCount++
  306         global.totalResultCount++
  307         return
  308     }
  309 
  310     if options.GroupByFile {
  311         filename := result.target
  312         if options.OutputUnixPath {
  313             filename = filepath.ToSlash(filename)
  314         }
  315         writeOutput(global.termHighlightFilename+"%s\n"+global.termHighlightReset, filename)
  316     }
  317 
  318     var lastPrintedLine int64 = -1
  319     var lastMatch Match
  320 
  321     // print contextBefore of first match
  322     if m := matches[0]; m.contextBefore != nil {
  323         contextLines := strings.Split(*m.contextBefore, "\n")
  324         for index, line := range contextLines {
  325             lineno := m.lineno - int64(len(contextLines)) + int64(index)
  326             printFilename(result.target, "-")
  327             printLineno(lineno, "-")
  328             writeOutput("%s\n", line)
  329             lastPrintedLine = lineno
  330         }
  331     }
  332 
  333     // print matches with their context
  334     lastMatch = matches[0]
  335     for _, match := range matches {
  336         printMatch(match, lastMatch, result.target, &lastPrintedLine)
  337         lastMatch = match
  338         matchCount++
  339         if options.Limit != 0 && matchCount >= options.Limit {
  340             break
  341         }
  342     }
  343     if result.streaming {
  344     matchStreamLoop:
  345         for matches := range result.matchChan {
  346             for _, match := range matches {
  347                 printMatch(match, lastMatch, result.target, &lastPrintedLine)
  348                 lastMatch = match
  349                 matchCount++
  350                 if options.Limit != 0 && matchCount >= options.Limit {
  351                     break matchStreamLoop
  352                 }
  353             }
  354         }
  355     }
  356 
  357     // print contextAfter of last match
  358     if lastMatch.contextAfter != nil {
  359         contextLines := strings.Split(*lastMatch.contextAfter, "\n")
  360         for index, line := range contextLines {
  361             var lineno int64
  362             if options.Multiline {
  363                 multilineLineCount := len(strings.Split(lastMatch.line, "\n")) - 1
  364                 lineno = lastMatch.lineno + int64(index) + 1 + int64(multilineLineCount)
  365             } else {
  366                 lineno = lastMatch.lineno + int64(index) + 1
  367             }
  368             printFilename(result.target, "-")
  369             printLineno(lineno, "-")
  370             writeOutput("%s\n", line)
  371             lastPrintedLine = lineno
  372         }
  373     }
  374 
  375     global.totalMatchCount += matchCount
  376     global.totalResultCount++
  377 }