12

I'm writing a program on a Linux platform that is generating text files that will be viewed on, inevitably, a Windows platform.

Right now, passing std::endl into a ostream generates the CR character only for newlines. Naturally, these text files look wrong in MS Notepad.

  1. Is there a way to change std::endl such that it uses CR+LF for newline instead of LF?
  2. I know I could write my own custom manipulator, like win_endl, for generating my own newlines, but I use the std::endl symbol in a lot of places, and like many programmers, have a tendency to do the thing that requires the least work possible. Could I simply overload std::endl to produce CR+LF, or is this a dumb idea for maintainability?

NB: I checked out this question, but it's asking about going the other way, and the accepted answer seems rather incomplete.

Community
  • 1
  • 1
J. Polfer
  • 12,251
  • 10
  • 54
  • 83
  • 3
    Another option is to use a tool on Windows that knows how to deal with Unix style newlines (ie., almost any editor other than Notepad), or use a tool that converts line endings (commonly called unix2dos.exe or something). – Michael Burr Oct 30 '09 at 20:02
  • @Michael Burr - good idea, but tough to support with our customer base is my gut reaction. – J. Polfer Oct 30 '09 at 20:04
  • 1
    It doesn't have to run on the customer machine - there are filters that'll do the same on a Unix box. You can have the output files produced by your current program run through the filter before you package them for distribution to the customer. It seems hacky, but I think it might actually be less hacky than mucking around with the C++ streamio (and it's probably far less work). – Michael Burr Oct 30 '09 at 20:07
  • @Michael Burr - your second point is also a good idea, and one that I thought about a bit. Maybe I need to think about it a little bit more. The main reason I balked at this idea was I really wanted to keep the "filtering" within my C++ app instead of calling an external program on the resultant file. Turn your comments into an answer, and I'll give you a +1. – J. Polfer Oct 30 '09 at 20:28
  • The problem is that you used `std::endl`, which you [shouldn't](https://stackoverflow.com/q/213907/995714) because [*In many implementations, standard output is line-buffered, and writing '\n' causes a flush anyway, unless std::ios::sync_with_stdio(false) was executed. In those situations, unnecessary endl only degrades the performance of file output, not standard output*](http://en.cppreference.com/w/cpp/io/manip/endl) – phuclv Jan 16 '18 at 11:02

5 Answers5

14

std::endl is basicly:

std::cout << "\n" << std::flush;

So just use "\r\n" instead and omit the flush. It's faster that way, too!

From the ostream header file on endl:

This manipulator is often mistakenly used when a simple newline is desired, leading to poor buffering performance.

ebo
  • 8,985
  • 3
  • 31
  • 37
  • 6
    If you do that, don't forget to open the stream in binary mode - otherwise, if you ever port this code to Windows, you'll get `\r\r\n` in the output (since `\n` itself will be expanded into `\r\n` for a text stream). – Pavel Minaev Oct 30 '09 at 19:57
  • This won't be ported to Windows, I don't think. We probably couldn't handle the licensing. lol – J. Polfer Oct 30 '09 at 20:05
  • +1 - Good info on the endl manipulator. Methinks I will be using it less often now. – J. Polfer Oct 30 '09 at 20:52
  • 2
    If your file is in text mode. The character '\n' is translated into a platform specific end of line sequence when you write to the file. And the end of line sequence is translated into '\n' when you read from the file. – Martin York Oct 30 '09 at 21:15
10

Opening a file in text mode should cause std::endl to be converted to the appropriate line ending for your platform. Your problem is that newline is appropriate for your platform, but the files you create aren't intended for your platform.

I'm not sure how you plan on overloading or changing endl, and changing its behavior would certainly be surprising for any developers new to your project. I'd recommend switching to win_endl (should be a simple search-and-replace) or maybe switching from a standard ostream to a Boost.Iostreams filtering stream to do the conversion for you.

Josh Kelley
  • 56,064
  • 19
  • 146
  • 246
  • 1
    +1 for the Boost.IOStreams solution. More specifically, use a newline_filter: http://www.boost.org/doc/libs/1_40_0/libs/iostreams/doc/index.html?path=4.2.10.1 – Éric Malenfant Oct 30 '09 at 21:00
  • Would have gone this route (still may if the macro becomes cumbersome to maintain) but we have a goofy system for getting boost pkgs at work, and I would've had to bug someone to go through some rigmarole to get it to my console. – J. Polfer Oct 30 '09 at 21:30
8

Windows Notepad is pretty much the only Windows program you'll find that doesn't handle LF-only files properly. Almost everything else (including WordPad) handles LF-only files just fine.

This problem is a bug in Notepad.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • Our customers will likely just double-click on the file, so we'll be at the mercy of whatever app has registered itself at the time on their machine. Likely the default Notepad on Windows. – J. Polfer Oct 30 '09 at 20:02
  • generate html instead? – ebo Oct 30 '09 at 20:05
  • 4
    If you must create files with CRLF line endings, run the output file(s) through a filter that is independent of your program itself. You can find this sort of filter easily, look for `unix2dos` or something like that. This will keep this platform-specific logic out of your program. – Greg Hewgill Oct 30 '09 at 20:07
  • 2
    However, don't forget that Unix programs are generally as unforgiving of reading text files that contain "\r\n" line endings - from my limited experience with Unix, that seems to be a more wide-spread issue (in terms of the number of programs that don't deal well with non-native line endings). – Michael Burr Oct 30 '09 at 20:11
  • Finally, no longer. The Windows 10 version of Notepad can handle line endings. What a progress! Windows 10 is the best Windows we ever had. – Thomas Weller Jun 22 '20 at 14:51
3

You shouldn't use \r\n. Just use \n, but then open the stream in "text" mode, which than will do the conversion for you. You may not care about cross-platform, but this is the official way of doing it.

That way, the same code will spit-out \n on unix, \r\n on windows, and \r on mac.

zumalifeguard
  • 8,648
  • 5
  • 43
  • 56
  • The program that generates the text file will *always* be run on a Linux platform, and it won't be run on Win/Mac at all. The machines that read the text file will be running consumer OSes (Windows, Mac, Linux). – J. Polfer Oct 30 '09 at 20:00
  • The problem is NotePad, as simple as the application is, doesn't respect other newlines. Other platforms default text editors do, so he's being forced to make it `\r\n`, so Windows plays nice as well. – GManNickG Oct 30 '09 at 20:04
  • +1 for reminding me that our customers could be running on Macs. I shouldn't forget about Macs. – J. Polfer Oct 30 '09 at 20:06
  • 1
    \r as EOL was used on Mac OS 9, OS X uses \n. – Cat Plus Plus Oct 30 '09 at 20:13
  • Also, if you have a text file with \n for the line-endings, you can easily view and edit that file if use wordpad, which comes with every windows. You wouldn't do this on your own computer because hopefully you'd have something like notepad++ installed. But if you're running on some arbitrary computer, it's nice to know the wordpad trick. – zumalifeguard Nov 07 '09 at 23:10
0

Here was my solution to the problem. It's a bit of a mash-up of all the info provided in the answers:

  1. I created a macro in a win_endl.h file for the newline I wanted:

    #define win_endl "\r\n"
    
  2. Then I did a search-and-replace:

    sheepsimulator@sheep\_machine > sed -i 's/std::endl/win_endl' *
    

And ensured all my files included win_endl.h.

phuclv
  • 37,963
  • 15
  • 156
  • 475
J. Polfer
  • 12,251
  • 10
  • 54
  • 83
  • This really isn't a solution if you are using text mode, since "\n" is translated into a platform specific end-of-line sequence. On Linux, "\n" does map directly to the LF character. But if you ran this code on Windows, you'd see CR-CR-LF because "\n" maps to CR-LF on Windows. – Brian Neal Oct 30 '09 at 23:57