flak rss random

improving bcd

Owing to its BSD heritage, OpenBSD ships with a few games installed in /usr/games. Quite a few, in fact. There are more programs in games (46) than in /bin (43). Some of them aren’t really games, but more like toys, but nevertheless there they are. They aren’t exactly the focus of OpenBSD, but they’re still part of the system and do get the occasional maintenance update.

One such game is bcd, which prints out punch card looking diagrams of input strings. I made a few improvements to it recently.

signed char

First, perhaps due to the original author’s familiarity with mainframe architectures, several parts of the code assumed that the char type was unsigned. On many common architectures, the opposite is true; char is signed. This meant that using char as index into an array would incorrectly negatively index before the array started. Piping random input into bcd should not cause it to crash, even if there’s no way to represent those bytes on a punch card.

long lines

The original implementation would truncate long strings to fit the 48 column width of a card. I noticed this when trying to create a card containing the signify key for 5.6. Only about half the key fits. After fixing, bcd now iterates over the string, printing additional cards as necessary. I’m not sure that historic card typewriters would have done this, but what good are modern computers if we don’t use them to improve our lives?


Unlike its games compatriots, ppt and morse, bcd was unable to decode its own output back to an ASCII string. Curiously, while all three programs are separate on disk, they share a single man page, so it’s not unreasonable to expect similar functionality in all of them.

Round tripping data is also a good way to verify that the encode and decode methods are correct. As a comment near the top of bcd.c states, the Q and R punch outs were identical for at least four years before anybody noticed. This could have been detected easily by feeding even a simple alphabet string through bcd and making sure the decocded output was the same. Much easier than examining punch cards by hand, for sure.

The bcd -d option was added to decode cards read from stdin. Each column of a card represents a 12-bit number, which would have required a fairly large reverse lookup table, so instead the original forward lookup table is simply traversed until a matching value is found.

As expected, this found a few bugs.

bcd "[]{}" | bcd -d

The bcd output for } is the same as for ]. I’m not sure what the correct output is, so I haven’t corrected this yet.

wide cards

At the time bcd was written, most people had at most an 80 column terminal. Printing 48 column cards made sense with a nice border, but this meant longer 80 column cards weren’t supported. I added an -l option for that. Now I can finally fit the signify key on a single card:

bcd -l RWR0EANmo9nqhpPbPUZDIBcRtrVcRwQxZ8UKGWY8Ui4RHi229KFL84wV
|    ]]      ]  ]   ]]]]    ]        ]    ]  ]]    ]                             |
|] ]   ]]] ]] ]] ]      ] ]  ] ]    ]       ]     ] ]                            |
| ] ]             ]]     ] ]  ] ]] ]  ]] ]             ]]                        |

Of course, bcd only supports upper case letters, so this isn’t as useful as one might imagine.


I found a few images of cards online (one, two, three). They don’t seem to help in finding the correct encoding for } which isn’t displayed. The current output for _ is also very suspect, punching out rows 6, 7, 8, and 9.

Real cards typically display a row of 00000, but the bcd program leaves this blank. Probably because the 0 may look like a hole, but for the sake of accuracy we should probably change that too. Maybe print X for holes instead of ]?

Lots of card images.

Posted 06 Nov 2014 21:04 by tedu Updated: 07 Nov 2014 01:23
Tagged: c openbsd programming