Println strip out ^M

Hello
I'm learning Rust and trying to re-write "head" for this learning experience.
I have noticed that GNU coreutils "head" is passing around the special character ^M.
And in my case I'm using println!() macro to output the lines from input files, also println!() seems to be stripping out ^M from the output or the way I'm reading the file...
I'm curious how I could pass out this character through println().
This is the piece of code where I read the file and output through println!() the lines.

fn open(filename: &str) -> MyResult<Box<dyn BufRead>> {
    match filename {
        "-" => Ok(Box::new(BufReader::new(io::stdin()))),
        _ => Ok(Box::new(BufReader::new(File::open(filename)?))),
    }
}
match open(&filename) {
                     Err(err) => eprintln!("{}:{}", filename, err),
                     Ok(file) => {
                         let max_output_line = &config.lines;
                         let index = &config.files.iter().position(|r| r == filename).unwrap();
                         let number_of_files = &config.files.len();
                         let first_file: usize = 0;
                         if *number_of_files > 1 {
                            if index == &first_file {
                               println!("==> {} <==", &filename);
                            } else {
                               println!("\n==> {} <==", &filename);
                            }
                         }
                         for (line_num, line) in file.lines().enumerate(){
                             let line = line?;
                             if &line_num == max_output_line {
                                 break;
                             }
                             println!("{}",line);
                         }
                     }
                     }

For reference here is my input:

In the output I don't have the ^M anymore

PS: ^M is the Windows carriage return character (0xD) as interpreted by VIM when showing all characters.

Thanks in advance for any advice or help.

It's not println!, it's Lines that strips the carriage return (\r, ^M).

If you want to preserve the \r of a \r\n, you'll need something besides Lines. Perhaps read_line or read_until.

5 Likes

Thank you ! I missed that one effectively.
Will look at read_line, and fix that.

Thanks for the tips, also I'm probably missing a concept here because it seems that unlike lines(), read_line() does not return an iterator.
I have the feeling that I should re-create lines() without consuming the return character.
Still investigating, by looking at the standard library doc. And source code of lines().

You could, but that would be unnecessary work. It's fairly easy to call read_line in a loop:

// let mut reader = ...
let mut buf = String::with_capacity(100);
loop {
    buf.clear();
    let len = reader.read_line(&mut buf)?;
    if len == 0 {
        break;
    }
    let line = buf.trim_end_matches('\n');
    // note that \r is still present in the line.
    println!("{}", line);
}
2 Likes

Here's another example of using read_line based on your OP.

            let mut line_num = 0;
            let mut line = String::new();
            loop {
                line.clear();
                if 0 == file.read_line(&mut line)? || &line_num == max_output_line {
                    break;
                }
                print!("{}", line);
                line_num += 1;
            }
2 Likes

Thank you guys !
This is awesome, I didn't know the keyword loop very happy to discover it !
And very nice to see this modern syntax ( I know this is not that modern anymore ) on the if statement.

I still can picture/figure out, how my program here is correctly iterating through each line of my file instead of looping always to the first line ?
Could it be because I'm using File ?

All the read methods in the BufRead and Read traits advance the position in the underlying file or buffer.

1 Like

Thank you will look at those two more in depth.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.