CR-Only is an Equivalent But Independent Solution
It's easy to assume everything has a lineage of being directly related/developed in knowledge/copied, but real-world progress includes independent rediscovery/reinvention, like Columbus' re-discovery of America half a millennium after the Vikings, or Gerald Rosenberger's 1957 patent for the 'first' usable carry-look-ahead circuit a good 20 years after Zuse had already built a working mechanical computer using one. None of these are lesser discoveries because they have not been the absolute first.
In engineering (CS) it's often about different groups, often at different times (*1), having to find a solution to the same, usually well known (*2) problem. within their own/new environment. Here it's the discrepancy between wanted logical line/record handling and needed physical device handling, or the lack thereof if one had absolute control over (hardware) environment involved. In either situation, the designer may arrive at the same solution as previous systems without being influenced at all.
Gen 0: Unit Record Equipment
Data processing begins without any line terminator. Lines were cards and cards were lines. If more lines were to be printed, cards would be inserted or special conditions were wired for direct control of line and formfeed.
Gen 1: Mainframes
Mainframes stayed line-orientated, but for the (rather rare) case of in-band line handling (*3) it was done by introducing some dedicated logical line terminator, independent of physical control characters. Nicely compiled with the new, all-encompassing 8-bit EBCDIC character set. It featured the physical
- CR (at x'0D') and
- LF (at x'25') plus a
- logical new line, NL, at x'15'.
Software with a need to handle multiple lines in a single block (*4) and outside of raw device handling would use NL to separate those lines. Still, the most common use case was line-length blocks with a format specifier at position 1.
Gen 2: The Minis
Upcoming mini computer system started from scratch. Like the very first computers their purpose was at first to provide some processing at all. Except where mainframes inherited the record-based handling as primary I/O, they restarted at character-based. As close to hardware as possible, but without the luxury of tailoring devices connected to their need, as IBM could do. They had to fit with the lowest common denominator. For I/O this meant CR/LF for TTY and TTY-derived printers. With that it was just natural to also use CR/LF.
Gen 2.5: Multics and Unix
The *ixes developed from there with a clear intention to make things better. Except, they didn't have the luxury IBM had in inventing a complete new 8-bit charset but (had to) stay within the 7 bits ASCII provided. Using any of the weakly defined ones (*5) would have prohibited certain assumed applications(*6). So either CR or LF was it and LF won.
Using LF as logical line separator makes a lot of sense. A driver could deliver (almost) the same versatility as direct output:
- Logical New Line: LF will be translated to CR/LF
- 'physical' CR/LF: Turned into CR/LF/CR, virtually identical to CR/LF
- 'trickster' CR: Is passed through to allow double printing, underlining, strike-through, etc.
Minimal impact while still switching from physical to logical line control. By also adding input translation of CR to LF (and suppression of single LF), one gets 'cooked' input using just logical line markers. Beautiful new world.
Gen 3: Early Micros
Early micros restarted from scratch. While lessons learned with 2.5 were available, they started out with the very same issue as Gen 2 minis: limited resources and glad to work at all. So naturally the same solutions applied here - even more as the engineers creating those first micros and their operating systems were already using (DEC-like) mini computers before or during design.
CP/M, DOS and Windows followed that for upward compatibility ... and ultimately the Web.
Gen 3.5: Home Computer
Home computers were in a position much like the *nixes as the technology was established, but they had to make their own thing. Partly due to limited resources, but more so because they again had a close control over hardware, much more related to the situation IBM had then DEC or *nix. Their developers did not have to bother how terminals worked as they built them themselves. It's a, if not the main feature about home computers that keyboard input and video (display) output is integrated.
They did not have need to think much about third party peripherals. Quite the other way, as those companies were keen on selling everything on their own, using lock-in as an advantage, as if an IBM sales manager had written the requirements (*7).
Example: the Apple II and its Monitor
The Apple II makes a prime example for that situation and solution chosen. Not just because it's an early home computer and was developed in-house without any external goals/restrictions (*8), but also due to being mostly developed by a single engineer.
With built-in display hardware there is no need to differentiate CR/LF at all. In fact, while the Monitor ROM's (*9) screen handling (*10) includes two entry points for CR (returning to column 0) and LF (advancing one line), CR ($FC62) always overflows into LF ($FC66), so CR alone wasn't ever possible and LF never needed. In fact, CR/LF would have resulted in advancing for two lines. CR (and LF) was directly called by COUT1 when a CR was detected. This nicely mirrors the input situation, where any line input using GETLN ($FD6A) was terminated by a single CR (not included in input length).
Either of those worked via default entry points COUT/KEYIN used by most applications including BASIC. Either used a vector which would be rerouted if other devices (printer, serial, etc.) are to be used for I/O including DOS (*11).
As a result Apple II programs would only use a CR for line, never CR/LF, and see only a CR if read on a single char basis. Since DOS hooked those output vectors, any line termination (from BASIC or otherwise) was straightforwardly stored as CR (*12) to record separator. Likewise reading from disk returned the record without trailing CR. As a result the Apple II provided the same comfort of a logical line end as *nixes did, except using CR instead of LF.
For other home computers, the reasoning (single line terminator) and constrictions (screen doesn't need two chars and keyboard delivers CR by default) can be assumed to be similar, leading to the same result.
Oh, and yes, the Mac inherited CR from the Apple II. It wasn't until OSX transplanted it onto a *nix base that LF became the default ... and many files still containing CR terminated lines :))
Conclusion
History doesn't repeat, but similar stages do require similar solutions which may end up different, in good part due the control creators had over their environment.
All strived for single character logical line termination, but
- only IBM controlled peripheral design and code set,
- most others controlled neither and had to go without
- home computer in turn did not control charset (*13) but peripherals (*14)
As result
- LF was a conscious decision to use a single char with the least impact on existing hardware, while
- CR did the same yielding the least implementation effort while all-new hardware being developed anyway.
*1 - In some way also a bit like every generation thinks they are the first to invent something different that will forever be the most radical version, no matter whether art, literature or music ... anyone remember feeling shocked how rad Mozart is? :))
*2 - Already Babbage knew that improved carry handling would be of great benefit, he just couldn't come up with a working solution. The issue was widely discussed and tinkered at in the heydays of mechanical calculators (1910s to 1940s) but without much practical result.
*3 - Well, that is after those became sufficient to handle abstraction in software and the need did arise due to devices like screen based terminals.
*4 - Mainframes and their software inherited their line orientation from Unit Record Machinery. They handle a line at a time. The vast majority of I/O data was block orientated, either fixed length (punch card, fixed length file) or variable length, where each line/block was prefixed by a (usually) 16-bit length. Handling was usually single line/block.
If a device allowed line control, it was done by special fields (aka the first character of a line to be printed). This includes terminal output.
The only exception were certain non (or simple) format output modes sending multiple lines in one operation. Only here NL was used for both directions and inserted/replaced by whatever the device used/delivered.
*5 - Like the Device Control or Separator characters.
*6 - As communication and maybe more important data exchange with mainframes using them. Not to mention that the DCs were already used by some hardware, like XON/XOFF being defined by TTYs.
*7 - To be fair, they also had a situation similar to IBM, as there wasn't much third party equipment available to buy at the time they introduced their new systems - at least not much in a price range the intended customer would be able to afford ... and custom interfaces were helping to keep it that way.
*8 - Except for ASCII keyboard and NTSC output
*9 - Kind of Apple II's BIOS, a least for all built-in components.
*10 - A lovely piece of code, even more on the Autostart. Nice and tidy. Though, might need some time to read through :))
*11 - DOS is a more complex issue, as it also used those to hook itself to work at all, but for the issue of CR those quirks don't matter.
*12 - Well, it was $8D as all characters output had the high bit set, but that's also a different issue, not changing the principle of operation.
*13 - They did make up their own 8-bit extensions, but stayed with basic 7-bit ASCII for line control.
*14 - Later, when standard printers emerged during he 1980s, they featured ways to be configured to fit various machines definitions - usually including at least a basic CR->CRLF handling.