@@ -3,6 +3,7 @@ package main
33import (
44 "encoding/json"
55 "fmt"
6+ "io"
67 "io/ioutil"
78 "os"
89
@@ -83,19 +84,27 @@ func runMain(c *cli.Context) int {
8384 return 0
8485 }
8586 var input interface {}
86- var jsonParser * json. Decoder
87+ var inputStream io. Reader
8788 if c .String ("filename" ) != "" {
8889 f , err := os .Open (c .String ("filename" ))
8990 if err != nil {
9091 return errMsg ("Error opening input file: %s" , err )
9192 }
92- jsonParser = json . NewDecoder ( f )
93+ inputStream = f
9394
9495 } else {
95- jsonParser = json . NewDecoder ( os .Stdin )
96+ inputStream = os .Stdin
9697 }
98+ newlineNumberReader := NewLineNumberReader (inputStream )
99+ jsonParser := json .NewDecoder (newlineNumberReader )
97100 if err := jsonParser .Decode (& input ); err != nil {
98- errMsg ("Error parsing input json: %s\n " , err )
101+ if syntaxError , ok := err .(* json.SyntaxError ); ok {
102+ line , char := newlineNumberReader .ConvertOffset (syntaxError .Offset )
103+ errMsg ("Error parsing input json: %s (line: %d, char: %d)\n " ,
104+ syntaxError , line , char )
105+ } else {
106+ errMsg ("Error parsing input json: %s" , err )
107+ }
99108 return 2
100109 }
101110 result , err := jmespath .Search (expression , input )
@@ -121,3 +130,51 @@ func runMain(c *cli.Context) int {
121130 os .Stdout .WriteString ("\n " )
122131 return 0
123132}
133+
134+ type LineNumberReader struct {
135+ actualReader io.Reader
136+ newlinePositions []int64
137+ bytesRead int64
138+ }
139+
140+ func NewLineNumberReader (actualReader io.Reader ) * LineNumberReader {
141+ return & LineNumberReader {
142+ actualReader : actualReader ,
143+ }
144+ }
145+
146+ func (lnr * LineNumberReader ) Read (p []byte ) (n int , err error ) {
147+ n , err = lnr .actualReader .Read (p )
148+
149+ if err != nil || n == 0 {
150+ return
151+ }
152+
153+ for i , v := range p {
154+ if i >= n {
155+ return
156+ }
157+
158+ if v == '\n' {
159+ lnr .newlinePositions = append (lnr .newlinePositions , lnr .bytesRead + int64 (i )+ 1 )
160+ }
161+ }
162+
163+ lnr .bytesRead = lnr .bytesRead + int64 (n )
164+ return
165+ }
166+
167+ func (lnr * LineNumberReader ) ConvertOffset (offset int64 ) (linePos int , charPos int64 ) {
168+ lastNewlinePos := int64 (0 )
169+ lastLineNumber := 0
170+ for lineNumber , newlinePos := range lnr .newlinePositions {
171+ if newlinePos >= offset {
172+ break
173+ }
174+
175+ lastNewlinePos = newlinePos
176+ lastLineNumber = lineNumber + 1
177+ }
178+
179+ return lastLineNumber + 1 , offset - lastNewlinePos
180+ }
0 commit comments