@@ -58,6 +58,9 @@ type runner struct {
5858 lastBytesUncompressed int64
5959
6060 noProgress bool
61+
62+ hasOptions bool
63+ options Options
6164}
6265
6366// st renders Status as a string.
@@ -150,7 +153,7 @@ func (r *runner) readFile(rd io.Reader, out io.Writer) {
150153 }
151154}
152155
153- func (r * runner ) scanFile (rd io.Reader , out io.Writer ) {
156+ func (r * runner ) scanFile (filename string , rd io.Reader , out io.Writer ) {
154157 s := bufio .NewScanner (rd )
155158 s .Buffer (make ([]byte , 64 * 1024 ), 10 * 1024 * 1024 )
156159
@@ -164,17 +167,29 @@ func (r *runner) scanFile(rd io.Reader, out io.Writer) {
164167 lines = 0
165168 }
166169
167- if ! r .shouldWrite (s .Bytes ()) {
170+ line := s .Bytes ()
171+
172+ if ! r .shouldWrite (line ) {
168173 continue
169174 }
170175
176+ if r .hasOptions {
177+ if r .options .PrepareLine != nil {
178+ line = r .options .PrepareLine (filename , lines , line )
179+ }
180+
181+ if line == nil {
182+ continue
183+ }
184+ }
185+
171186 atomic .AddInt64 (& r .matches , 1 )
172187
173188 if r .parallel > 1 && r .outDir == "" {
174189 r .mu .Lock ()
175190 }
176191
177- if _ , err := out .Write (append (s . Bytes () , '\n' )); err != nil {
192+ if _ , err := out .Write (append (line , '\n' )); err != nil {
178193 r .lastErr = err
179194
180195 if r .parallel > 1 && r .outDir == "" {
@@ -249,7 +264,7 @@ func (r *runner) shouldWrite(line []byte) bool {
249264 return shouldWrite
250265}
251266
252- func (r * runner ) cat (filename string ) (err error ) {
267+ func (r * runner ) cat (filename string ) (err error ) { //nolint:gocyclo
253268 file , err := os .Open (filename ) //nolint:gosec
254269 if err != nil {
255270 return err
@@ -329,8 +344,8 @@ func (r *runner) cat(filename string) (err error) {
329344 })
330345 }
331346
332- if len (r .pass ) > 0 || len (r .skip ) > 0 || r .parallel > 1 {
333- r .scanFile (rd , out )
347+ if len (r .pass ) > 0 || len (r .skip ) > 0 || r .parallel > 1 || r . hasOptions {
348+ r .scanFile (filename , rd , out )
334349 } else {
335350 r .readFile (rd , out )
336351 }
@@ -407,15 +422,29 @@ func (i *stringFlags) Set(value string) error {
407422 return nil
408423}
409424
425+ // Options allows behavior customisations.
426+ type Options struct {
427+ // PrepareLine is invoked for every line, if result is nil, line is skipped.
428+ PrepareLine func (filename string , lineNr int , line []byte ) []byte
429+ }
430+
410431// Main is the entry point for catp CLI tool.
411- func Main () error { //nolint:funlen,cyclop,gocognit,gocyclo,maintidx
432+ func Main (options ... func ( o * Options ) ) error { //nolint:funlen,cyclop,gocognit,gocyclo,maintidx
412433 var (
413434 pass stringFlags
414435 skip stringFlags
415436 )
416437
417438 r := & runner {}
418439
440+ if len (options ) > 0 {
441+ r .hasOptions = true
442+
443+ for _ , opt := range options {
444+ opt (& r .options )
445+ }
446+ }
447+
419448 flag .Var (& pass , "pass" , "filter matching, may contain multiple AND patterns separated by ^,\n " +
420449 "if filter matches, line is passed to the output (unless filtered out by -skip)\n " +
421450 "each -pass value is added with OR logic,\n " +
0 commit comments