func csvFileReader(o Options, callback func(line []string)) error {
	if len(o.KeyColumns) == 0 {
		return errors.New("key column is not set")
	}
	
	var max_key_index = 0
	var columns_checked = false
	var header_skipped = false
	
	file, err := os.Open(o.Input)
	if err != nil {
		return err
	}
	defer file.Close()
	
	var reader = csv.NewReader(file)
	reader.Comma = o.Delimiter
	reader.LazyQuotes = o.LazyQuotes
	reader.TrimLeadingSpace = true
	for {
		
		line, e := reader.Read()
		if e != nil {
			if e == io.EOF {
				break
			} else {
				if strings.Contains(e.Error(), "wrong number of fields") {
					// Process line if it has wrong number of field, but it's length is >= max_key_index
					if len(line) - 1 < max_key_index {
						continue
					}
				} else if strings.Contains(e.Error(), "index out of range") {
					// Skip this one
					continue
				} else {
					return e
				}
			}
		}
		
		// Skip header if needed
		if !header_skipped && o.SkipHeader {
			header_skipped = true
			continue
		}
		
		// Let's check really quick, if there are all the columns for hash key we need
		if !columns_checked {
			max_key_index = getColumnsMaxIndex(o.KeyColumns)
			if max_key_index > len(line) - 1 {
				return errors.New(fmt.Sprintf("Key column index '%v' is beyond the slice length! Keep in mind, index count starts at 0.", max_key_index))
			}
			columns_checked = true
		}
		
		callback(line)
		
	}
	
	return nil
}
// csvFileReader reads csv file and pass it's lines into callback function
csvFileReader reads csv file and pass it's lines into callback function
// csvFileReader reads csv file and pass it ' s lines into callback function
func csvFileReader(o Options, callback func(line []string)) error {
	if len(o.KeyColumns) == 0 {
		return errors.New("key column is not set")
	}
	var max_key_index = 0
	var columns_checked = false
	var header_skipped = false
	file, err := os.Open(o.Input)
	if err != nil {
		return err
	}
	defer file.Close()
	var reader = csv.NewReader(file)
	reader.Comma = o.Delimiter
	reader.LazyQuotes = o.LazyQuotes
	reader.TrimLeadingSpace = true
	for {
		line, e := reader.Read()
		if e != nil {
			if e == io.EOF {
				break
			} else {
				if strings.Contains(e.Error(), "wrong number of fields") {
					if len(line) - 1 < max_key_index {
						continue
					}
				} else if strings.Contains(e.Error(), "index out of range") {
					continue
				} else {
					return e
				}
			}
		}
		if !header_skipped && o.SkipHeader {
			header_skipped = true
			continue
		}
		if !columns_checked {
			max_key_index = getColumnsMaxIndex(o.KeyColumns)
			if max_key_index > len(line) - 1 {
				return errors.New(fmt.Sprintf("Key column index '%v' is beyond the slice length! Keep in mind, index count starts at 0.", max_key_index))
			}
			columns_checked = true
		}
		callback(line)
	}
	return nil
}
func csvFileReader ( o Options , callback func ( line [ ] string ) ) error { if len ( o . KeyColumns ) == 0 { return errors . New ( " " ) } var max_key_index = 0 var columns_checked = false var header_skipped = false file , err := os . Open ( o . Input ) if err != nil { return err } defer file . Close ( ) var reader = csv . NewReader ( file ) reader . Comma = o . Delimiter reader . LazyQuotes = o . LazyQuotes reader . TrimLeadingSpace = true for { line , e := reader . Read ( ) if e != nil { if e == io . EOF { break } else { if strings . Contains ( e . Error ( ) , " " ) { if len ( line ) - 1 < max_key_index { continue } } else if strings . Contains ( e . Error ( ) , " " ) { continue } else { return e } } } if ! header_skipped && o . SkipHeader { header_skipped = true continue } if ! columns_checked { max_key_index = getColumnsMaxIndex ( o . KeyColumns ) if max_key_index > len ( line ) - 1 { return errors . New ( fmt . Sprintf ( " " , max_key_index ) ) } columns_checked = true } callback ( line ) } return nil }
csvFileReader reads csv file and pass it's lines into callback function
csvFileReader reads csv file and pass it ' s lines into callback function
// Process line if it has wrong number of field, but it's length is >= max_key_index // Skip this one // Skip header if needed // Let's check really quick, if there are all the columns for hash key we need