1package input 2 3import ( 4 "bufio" 5 "io" 6 "os" 7 "strconv" 8 "strings" 9 10 "miller/src/cliutil" 11 "miller/src/lib" 12 "miller/src/types" 13) 14 15type RecordReaderNIDX struct { 16 // TODO: use the parameterization 17 ifs string 18 ips string 19} 20 21func NewRecordReaderNIDX(readerOptions *cliutil.TReaderOptions) *RecordReaderNIDX { 22 return &RecordReaderNIDX{ 23 ifs: readerOptions.IFS, 24 ips: readerOptions.IPS, 25 } 26} 27 28func (this *RecordReaderNIDX) Read( 29 filenames []string, 30 context types.Context, 31 inputChannel chan<- *types.RecordAndContext, 32 errorChannel chan error, 33) { 34 if filenames != nil { // nil for mlr -n 35 if len(filenames) == 0 { // read from stdin 36 handle := os.Stdin 37 this.processHandle(handle, "(stdin)", &context, inputChannel, errorChannel) 38 } else { 39 for _, filename := range filenames { 40 handle, err := os.Open(filename) 41 if err != nil { 42 errorChannel <- err 43 } else { 44 this.processHandle(handle, filename, &context, inputChannel, errorChannel) 45 handle.Close() 46 } 47 } 48 } 49 } 50 inputChannel <- types.NewEndOfStreamMarker(&context) 51} 52 53func (this *RecordReaderNIDX) processHandle( 54 handle *os.File, 55 filename string, 56 context *types.Context, 57 inputChannel chan<- *types.RecordAndContext, 58 errorChannel chan error, 59) { 60 context.UpdateForStartOfFile(filename) 61 62 lineReader := bufio.NewReader(handle) 63 eof := false 64 65 for !eof { 66 line, err := lineReader.ReadString('\n') // TODO: auto-detect 67 if err == io.EOF { 68 err = nil 69 eof = true 70 } else if err != nil { 71 errorChannel <- err 72 } else { 73 // This is how to do a chomp: 74 line = strings.TrimRight(line, "\n") 75 record := recordFromNIDXLine(&line, &this.ifs) 76 77 context.UpdateForInputRecord() 78 inputChannel <- types.NewRecordAndContext( 79 record, 80 context, 81 ) 82 } 83 } 84} 85 86// ---------------------------------------------------------------- 87func recordFromNIDXLine( 88 line *string, 89 ifs *string, 90) *types.Mlrmap { 91 record := types.NewMlrmap() 92 values := lib.SplitString(*line, *ifs) // TODO: repifs ... 93 var i int = 0 94 for _, value := range values { 95 i++ 96 key := strconv.Itoa(i) 97 mval := types.MlrvalPointerFromInferredType(value) 98 record.PutReference(key, mval) 99 } 100 return record 101} 102