Mimsy Were the Borogoves

Hacks: Articles about programming in Python, Perl, PHP, and whatever else I happen to feel like hacking at.

42 Astoundingly Useful Scripts and Automations for the Macintosh

Work faster and more reliably. Add actions to the services menu and the menu bar, and create drag-and-drop apps to make your Macintosh play music, roll dice, and talk to you. Create ASCII art from your photos. There’s a script for all of that in my new book, 42 Astounding Scripts for the Macintosh.

TRS-80 Color Computer RCHECK+ in Perl

Jerry Stratton, November 20, 2019

CoCo Terminal profile example

The only text editor I could find that would wrap exactly at 32 characters was vi in the Terminal.

I may be the only person who still enjoys typing in code from old books and magazines, but I do enjoy it, and enough to have written a modern version of those old books, 42 Astoundingly Useful Scripts and Automations for the Macintosh. I recently acquired a TRS-80 Color Computer 2, so I’ve been typing in old code from The Rainbow.

One of the big advantages of The Rainbow over other magazines of its era is the program RCHECK+. It’s a machine-language program that you load into memory before typing the code, and when you press the down arrow, it calculates a very simple checksum from the code you’ve typed.1 The listing in the magazine contains a series of checkpoints, such as this for TRENCH in the July 1986 issue of The Rainbow:

checkpointchecksum
7208
15178
20102
2828
3783
51188
END180

After typing line 7, the checksum should be 208; after typing line 15, it should be 178; and after typing in the entire program, it should be 180.

It turns out that this is a very simple checksum. All it’s doing is adding up the ASCII values of the code in RAM, cycling back to zero after a sum of 255. So the checksum is always from 0 to 255.2

The program is so useful that, even though I would much prefer to type BASIC code on a modern computer in a modern text editor with a modern keyboard, I didn’t.3 The values that RCHECK+ uses are the tokenized values, which means that GOTO is not G plus O plus T plus O, but rather the sum of hex 81 and A5, the tokenization of GOTO. But then I discovered that the decb program from the ToolShed suite can take a text BASIC listing and tokenize it to a standalone file.

Which makes it possible to write rcheck in Perl and run it on a text file created by decb.

There was a lot of trial and error getting this to work. I don’t have the listing for RCHECK+, so I can’t know for sure what the algorithm is. But poking at it on the CoCo by adding, removing, and altering strings, BASIC statements, and line numbers, and watching how the checksum changes, I’m pretty sure I have it. It certainly works on the BASIC code I’ve tested it on so far. But there are no guarantees.

Here’s what it looks like using it:

  • $ ~/bin/rcheck TRENCH.BAS 7 15 20 28 37 51
  • 7: 208
  • 15: 178
  • 20: 102
  • 28: 28
  • 37: 84
  • 51: 224
  • END: 223

Clearly, I went south sometime after line 28.4

You don’t need to give rcheck the checkpoint lines; if you leave them out it will only report the final checksum.

[toggle code]

  • #!/usr/bin/perl
  • # run the Rainbow checksum against a BASIC text file
  • # requires decb to tokenize the BASIC
  • # Jerry Stratton http://www.hoboes.com/Mimsy/hacks/coco/
  • use File::Temp qw/tempfile/;
  • while ($option = shift) {
    • if ($option eq '--debug') {
      • $debug = 1;
    • } elsif ($option eq '--help') {
      • help();
    • } elsif ($option =~ /^[1-9][0-9]*$/) {
      • $checksumLines{$option} = 1;
    • } elsif (!$basicFile && -f $option) {
      • $basicFile = $option;
    • } else {
      • help("Unknown option $option");
    • }
  • }
  • help("No input file provided.") if !$basicFile;
  • # first, tokenize the BASIC file
  • ($tokenHandle, $tokenFile) = tempfile(UNLINK=>1);
  • `/usr/local/bin/decb copy -b -t $basicFile $tokenFile`;
  • print `hexdump -C $tokenFile` if $debug;
  • # then read the tokenized file
  • # character zero marks the end of a line, and thus also the beginning of a line
  • open $codeHandle, $tokenFile or die("Can't open $tokenFile: $!");
  • $code = do { local $/; <$codeHandle> };
  • close $codeHandle;
  • # finally, loop through the tokenized code and add up each character
  • $counter = -1;
  • while ($counter < length($code)) {
    • #will be zero when $counter is -1
    • $character = substr($code, $counter, 1);
    • $addend = ord($character);
    • #line numbers need to be handled specially
    • #character 0 marks the end of a line
    • if ($addend == 0) {
      • #advance to line number
      • $counter += 3;
      • #calculate line number
      • my $linePartOne = ord(substr($code, $counter, 1));
      • my $linePartTwo = ord(substr($code, $counter+1, 1));
      • $line = $linePartOne*16*16 + $linePartTwo;
      • #use the tokenized line number for the checksum
      • $addend = $linePartOne + $linePartTwo;
      • #advance past the line number
      • $counter +=1;
    • }
    • print "$previousLine:\t", checksum($sum), "\n" if ($debug || $checksumLines{$previousLine}) && $previousLine ne "" && $line != $previousLine;
    • $sum += $addend;
    • $previousLine = $line;
    • $counter++;
  • }
  • print "END:\t" if $debug || %checksumLines;
  • print checksum($sum), "\n";
  • sub help {
    • $message = shift;
    • print "$0 [--debug] [--help] <BASIC file to checksum> [<line numbers to report>]\n";
    • print "$message\n" if $message;
    • exit;
  • }
  • sub checksum {
    • my $sum = shift;
    • return $sum%256;
  • }
CoCo Terminal profile (text)

You can create a profile that will set the background and foreground colors.

Save the script as rcheck. You may find my edit script for 42 Astounding Scripts useful for pasting this or any scripts into TextEdit or your favorite text editor.

As you can see, besides requiring that decb be installed on your computer, the only tricky part of the program is detecting where BASIC lines begin. CoCo BASIC uses the null character, character zero, to mark the end of a line. So I have the script look for character zero, grab (and sum) the line number, and then skip ahead to after the line number. This is probably not completely kosher, but it works so far. I’m ignoring two bytes that are probably important.

And, in order to successfully report on the first line, I set the counter to -1. Since there is no character at -1 in any string, it comes out as null, and the script thinks that the very first line is preceded by an end-of-line marker.

In the original RCHECK+, it was critical to verify the checksums every time you reached a checkpoint; it was difficult to see previous checkpoints. You had to delete lines of code. With this program, if you prefer to type in the whole program and then debug, you can do it. Just provide the checkpoints to the script, and then you can type as much as you want. Later, you can go through each checkpoint one at a time fixing any discrepancies in that section.

CoCo Terminal profile (window)

And, more importantly, set the width to the same width as the Color Computer listings in Rainbow.

One of the nice things about such a simple checksum is that the discrepancy is often a clue to what the problem is. Very often, I find that if I’ve checked and double-checked the code and the number still doesn’t match, it is because I left out a character, probably on the last line. Often, this is obvious. There’s a space at the end of a line which is of course invisible in the printed listing, and the checksum is 32 less than what it’s supposed to be.5

In BASIC, of course, the way to check which character is missing is to use CHR$(VALUE) where value is the discrepancy. While typing in TRENCH, I was going crazy thinking I had something wrong with the rcheck script, checking over and over and not finding anything wrong with the code. It was low by 41; because the script can provide the checksum on multiple checkpoints (a distinct advantage over the original RCHECK+), I decided to go ahead to the next checkpoint. It was still 41 low. It was very clear that the problem was not with the script but with my typing.

What is character 41? In Chipmunk BASIC:

  • $ basic
  • Chipmunk BASIC 368b1.07
  • >print chr$(41)
  • )
  • >

The missing character was almost certainly a close parentheses.6 Since I clearly couldn’t be missing a close paren except on the last line—it would have been obvious from the 32-character width—I checked and found the error in less than a minute.

Yes, 32-character width. The other advantage to Rainbow listings is that they were 32-characters wide, and matched exactly7 what should be on screen. This is helpful enough that I emulate it on the Mac by using vi in the Terminal. I’ve created a special Terminal profile for 32-character width typing.

I tried to use my GUI text editors, but they all want to wrap intelligently, that is, at word boundaries. I couldn’t figure out how to tell TextEdit, Textastic, or TextWrangler to simply wrap at the end of the line regardless of word boundaries.

REMEMBER ALSO TO USE CAPS LOCK when typing but TURN IT OFF when done. It will make it a lot easier to find typos if your screen matches exactly what is in Rainbow magazine. But if you leave CAPS LOCK on while in VI’s command mode, the commands you get will not be the commands you expect.

You may also find the “+” key useful for moving to the beginning of the next line in vi. Just using the down arrow will move to the same location in the next line that you are in this line.

The only thing I haven’t figured out how to do is have a better visual or audio cue when the line wraps at 32 characters. When typing directly on the CoCo, the screen is big enough that even while looking at the listing in the magazine I can see the line wrap out of the corner of my eye—the entire screen shifts up one, after all. If I don’t see the shift out of the corner of my eye, I know that I typed too little (or, if the shift happens too soon, I typed too much). This effect is much less pronounced on a modern screen. Having a bell sound when vi wraps a line would be great, but I don’t see how to do it, or even if it’s possible. The problem is exacerbated by vi’s inability to partially scroll the top visible line. If the top line of code takes up four screen lines, then vi will scroll up by four lines. The next word wrap won’t even need to scroll.

  1. I considered providing a similar program for Astounding Scripts, but the advantage of modern scripting languages over BASIC—their readability—also makes it more difficult to ensure that typists use exactly the same characters, especially spaces and tabs, as in the original.

  2. And, importantly, order of values didn’t matter. This is not as bad as it could be because if you transpose letters in a BASIC keyword, the value of the keyword changes. But I had a vicious problem with Vicious Vic in the July 19867 issue because I mistyped the variable MN as NM. The rcheck algorithm reported the correct checksum, but the program failed until I was able to hand-trace the code to figure out why the it was trying to get a CHR$ of a negative number.

  3. Ed Snider’s CoCo SDC combined with the decb program makes it easy to copy files via SD card between modern computers and CoCos.

  4. And you may find the aligntabs script from 42 Astoundingly Useful Scripts and Automations for the Macintosh useful for aligning the numbers. Just pipe it through: ~/bin/rcheck TRENCH.BAS 7 15 20 28 37 51 | aligntabs.

  5. Or, if the author had the habit of adding spaces to the end of lines, a multiple of 32. It’s important to remember that the difference between upper and lower case—or reverse text in the case of Color Computer programs—is also 32. Reverse case is often used to emphasize some text. And sometimes in obscure locations such as comments.

  6. The same method, using CHR$(), would work in Extended Color BASIC itself, either on a real CoCo or in an emulator such as XRoar.

  7. Barring strange printer artifacts such as replacing reverse text with lowercase. I think the up arrow printed differently as well, though I may be misremembering the Model I.

  1. <- POV photos