Skip to main content
2 of 5
added 112 characters in body
Raffzahn
  • 236.3k
  • 23
  • 682
  • 976

CR-Only is an Equivalent But Independent Solution

It's easy to assume everything has a linage 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 build 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 designer may come to the same use than 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 line. If more lines were to be print cards would be inserted or special conditions were wired for direct control of line and formfeed.

Gen 1: Mainframes

Mainframe 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, 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 to tailor 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 derivative 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 take the luxury IBM took in inventing a complete new 8-bit charset but (had to) stay within the 7 bits ASCII provided. Using any of the weak 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 thru to allow double printing, underlining, strike thru, etc.

Minimal impact while still switching from physical to logical line control. By als adding input translation of CR to LF (and suppression of single LF), one gets 'cooked' input using as well 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 computer before or durign design.

CP/M, DOS and Windows followed that for upward compatibility ... and ultimately the Web.

Gen 3.5: Home Computer

Home computer were in a position much like the *nixes as the technology was established, but they had to make their own thing. In part of again of 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 did build them themself. It's a, if not the main feature about home computers that keyboard input and video (display) output is integrated.

They did as well 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 locked in as an advantage, as if an IBM sales manager had written the requirements (*7).

The Apple II and its Monitor

The Apple II makes a prime example for that situation and solution chosen. Not just because an early home computer and developed in-house without any external goals/restrictions (*8), but also due being mostly developed by a single engineer.

With build 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 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. 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, as well only see a CR if read on a single char base. Since DOS hooked those output vectors any line termination (from BASIC or otherwise) was straight forward 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 reasoning (single line terminator) and constrictions (screen doesn't need two chars and keyboard delivers CR by default) can be assumed 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 teh default ... and many files still containing CR terminated lines :))

Bottom Line

History doesn't repeat, but similar stages do require similar solutions wich may end up different:

  • LF was a conscious decision to use a single char with the least impact on existing hardware, while
  • CR did the same needing the least effort with al new hardware being developed anyway.

*1 - In some way also a bit like every generation thinks they are the first inventing something different that will forever be the most radical version, no mater if 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 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 he Device Control or Seperator 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 to buy third party 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 build in components.

*10 - A lovely piece of code, even more on the Autostart. Nice and tidy. Though, might need some time to read thru :))

*11 - DOS is a way 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 outputted had the high bit set, but that's also a different issue, not changing the principal operation.

Raffzahn
  • 236.3k
  • 23
  • 682
  • 976