Author Archives: Allen Huffman

About Allen Huffman

Co-founder of Sub-Etha Software.

Color BASIC and octal

Updates:

  • 2025-02-19 – Thanks to a comment from William Astle, the term “decimal” number has replaced my incorrect use of “integer.” And per a comment from James Jones, a clarification that all values you input are still stored internally as the same type of numeric floating point – the parsing converts them all to this floating point representation.

Color BASIC had one type of number you could use: decimal. These are the normal numbers we use every day like 1, 50392 or 42.

A=42
PRINT "A IS";A

When Extended Color BASIC was added, the CoCo accepted the following notations for numeric constants: integer, hexadecimal and octal. (Internally, BASIC converts them all to the same numeric representation of a floating point value.)

Getting Started with Extended Color BASIC describes hex and octal as follows:

Extended Color BASIC lets you use both hexadecimal and octal constants.

Hexadecimal numbers are quantities represented in Base 16 notation, composed of the numerals 0 to 9 and the “numerals” A to F. Hexadecimal constants must be in the range 0 to FFFF, corresponding to the decimal range 0 to 65535.

To indicate that a number is an octal constant, precede it with the symbol &H, as shown here:

&HA010 &HFE &HDl &HC &H4000

Octal numbers are quantities represented in Base 8 notation, composed of the numerals 0 to 7. Octal constants must be in the range 0 to 177777. The computer stores them as two-byte integers that correspond to the decimal range 0 to 65535.

To indicate that a number is an octal constant, precede it with the symbol &0 or &, as shown here:

&070 &044 U1777 &7170 &17 &01234

The use of “hex” and octal constants is convenient in programs that reference memory locations and contents. For further information, read a book on machine-language programming.

– Getting Started With Extended Color BASIC (p. 195, 1984 revision)

I most likely learned hexadecimal when I was learning assembly language. Today, I use hex values often in C programming. But octal? I do not think I have ever used it for anything. Have you?

I do believe I have seen it used “in the real world.” In the late 1980s (possibly early 1990s) I had a Kawai K1 synthesizer keyboard. It organized its instrument settings (called “patches” in reference to early synthesizers using “patch cables” to route signals do different processors) into two groups of Internal (onboard storage, uppercase “I” and lowercase “I”) and two groups of External (memory card, uppercase “E” and lowercase “e”). Each section had eight patches.

My first commercial CoCo program was a MIDI Librarian that could read the patches from the synthesizer and save them to disk, or load patches from disk into the keyboard. The patch screen in question looked like this:

You will see that each area had four banks (A-D) and each of those had eight patches (1-8). Uppercase “I” was A(1-8), B(1-8), C(1-8) and D(1-8), and lowercase “i” was the same. This was also the same for the External banks.

Thus, octal. I could have used octal in my program — but I do not know if I even realized this was octal at the time. I’d have to think about how I would have even done that. Maybe something like this:

0 'OCTALIN.BAS (2-15-2025)
10 LINE INPUT "BANK (0-7):";B$
20 LINE INPUT "PATCH(0-7):";P$
30 NM=VAL("&O"+B$+P$)
40 PRINT "THAT IS PATCH #";NM

…though I do not recall how the MIDI messages. It could have just been a user interface thing and internally the patches were still 1-whatever.

But I digress.

Juan Castro posted to the Color Computer e-mail list about a bug in the octal routines:

Octal constant (Ex.: &O14 = 12 decimal)

It accepts 8 as a digit. D’oh. Try “PRINT &O18” in a CoCo 1 or CoCo 2.

Without having a CoCo3 at hand to check I’ll wager it patches that bug. All
it has to do is replace a LBHI with a LBHS.

Juan Castro
Enviado do meu Olivetti Programma 101
http://retropolis.com.br

Since an octal value should only be 0-7, a value of 8 is not valid octal.

10 CLS:PRINT"DEC","OCT"
20 FOR A=0 TO 10
30 PRINT A,VAL("&O"+STR$(A))
40 NEXT

This should print 0-7 then error out. Yet…

And is there really no better error than SYNTAX for this type of problem?

And naturally, I had to see what HEX values do. A valid hex digit is 0-9 and A-F, representing 0 to 15. Will it do a syntax error as well if I go past the letter F?

It appears it does not. It seems to bail on the parsing and print them as two variables. Which is a neat trick, since you have to put a space or semicolon between two variables if you want to print them otherwise.

To confirm that is what it is doing, I tried this:

Ah, so it is not treating this as variables “H” and “G”. And I just learned something new (and probably useless).

Something new (and probably useless)…

Integer values are things like 1, 2, or 152032. They are floating point values, so you can also have things like 1.2 or 33.5. Though, not always. Floating point values cannot represent every decimal value accurately, but that’s a story for another article…

Somewhere, someone learned that a decimal (period) by itself would be treated as zero. The fastest way to assign 0 to a variable in Color BASIC is like this:

A=.

Weird, but it works. It seems the parser starts looking for a fractional amount, like “.25” or whatever, so it processes the period and then there is nothing else so the code returns with 0 (the initialization value when the function is called). It is still weird, though.

I found out tonight that the same thing applies to hex. You can do this:

A=&H

…and you get a zero. Try “PRINT &H” to see for yourself.

Of course, I had to try a quick benchmark, sitting in a loop doing something like “Z=.” and another run doing “Z=&H”. 1000 times through with “Z=.” used 140 timer ticks. The “Z=&H” used 154. I guess that is the overhead of parsing two characters instead of one.

But I digress. Again.

I have not looked up what BASIC is doing (see the excellent “BASIC Unravelled” books for the disassembly of the BASIC ROMs), but I suspect the parser starts looking and finds the “&” followed by the “H” and is ready to parse… it then hits an invalid character, so the parsing is over and 0 is there. Then it sees the G, which is not a command so it is treated like a variable.

Using “PRINT” was deceiving. Had I just tried this:

A=&HG

…I would have got what I was expecting:

?SN ERROR

Thanks, Juan, for sharing this. I learned about a bug, and in writing this, discovered another odd thing, which is less odd now that I understand what happened.

Until next time…

Sub-Etha graphical adventures?

Around 93-94, I created a text adventure that featured black and white digitized pictures from the 1992 Atlanta CoCoFest. It was more of a “simulation” than a game — and even called itself a simulation on the splash screen. But, while browsing through the source code, I found there were quite a number of things you could “do” in the game, while the score let you know how much of it you completed.

I also found one from a Chicago CoCoFest, which seems to be complete other than missing the images. Rooms were numbers with the vendor name and description. It was kind of like “playing” one of my old CoCoFest reports. Trippy.

And a weird 3-D first-person Pac-Man game I was working on…

Now that I have Xroar running the current Ease of Use NitrOS-9 build, and have my CoCoSDC “real CoCo” hard drive image mounted as the second drive, I may finally be able to dig through all this stuff and see what else I have.

Like finding I made a Towel V1.05” — after I moved to Iowa! I have no recollection of that. Lots of stuff to get archived and posted online.

Should be fun.

Build a (marginally) better malloc and free

This is a dumb one, but maybe someone else will find it useful.

I have been working on some C code that uses dynamically allocated linked lists. There are index structures and record structures and individual elements of different kinds in the records, all malloc()’d and then (hopefully) free()’d at the end.

Since my background is low-resource embedded systems (one system has a mere 8K of RAM), I have never really done much with malloc(). In fact, on some of the environments I have worked in they did not even provide a malloc()/free(). And this is probably a good thing. Without an OS watching over you, any memory allocated that did not get properly freed (a “memory leak“) can be big trouble for an embedded system meant to “run forever without a reboot.”

What I am writing right now is for a PC, and my understanding is if you allocate a bunch of memory then exit, Windows will clean it up for you:

int main()
{
    char *ptr = malloc (65535); // Allocate 64K

    // And now just exit without freeing it.
    return 0;
}

But no one should be writing code like that intentionally. This is the same mentality that has people who throw their trash on the ground because “someone else will clean it up for me.” Just because you have a garbage collector doesn’t mean you should rely on it to clean up after your mistakes.

But I digress.

In my program, I was wondering if I was getting it right. Debug “printf” messages can only go so far in to seeing what is going on. Did I free every last record? Did all the elements inside the records get freed as well?

I have no idea.

MAUI to the rescue!

Then a memory popped into my head. When I worked for Microware Systems Corp., we had a New Media division that worked on digital TV set-top boxes. (Yes, Virginia, I saw a demo of streaming video-on-demand with pause, fast forward and rewind back in the summer of 1995. But that’s a story for another day…)

The D.A.V.I.D. product (Digital Audio Video Interactive Decoder) used various APIs to handle things like networking, MPEG video decoding, sound, and graphics. The graphics API was called M.A.U.I. (Multimedia Application User Interface).

MAUI had various APIs such as GFX (graphics device), DRW (drawing API), ANM (animation), CDB (configuration database?), BLT (a blitter) and more. There was even a MEM (memory) API that was a special way to allocate and free memory.

I did not understand much of this at the time, beyond the entry level stuff I sometimes taught in a training course.

But the memory API had some interesting features. The manual introduced it as follows:

“Efficient memory management is a requirement for any graphical environment. Graphical environments tend to be very dynamic when it comes to allocating and freeing memory segments. Therefore, unless an application takes specific steps to avoid it, memory fragmentation can become a serious problem.

The Shaded Memory API provides the facilities applications (and other APIs) required to manage multiple pools of memory.

– Microware MAUI manual, 2000

One interesting feature of this API was the ability to detect memory overflows and underflows. For example, if you allocate 50 bytes and get a pointer to that memory, then copy out 60 bytes, you have overflowed that memory by 10 bytes (“buffer overrun“). Likewise, if the pointer started at 0x1000 in memory, and you wrote to memory before that pointer, that would be a buffer underflow.

The manual describes it as follows:

To print the list of overflows/underflows call mem_list_overflows(). When a shade is created with the check overflows option true, safe areas are created at the beginning and the end of the segment. If these safe areas are overwritten, the overflow/underflow situation is reported by mem_list_overflows().

– Microware MAUI manual, 2000

This gave me an idea on how to verify I was allocating and freeing everything properly. I could make my own malloc() and free() wrapper that tracked how much memory was allocated and freed, and have a function that returned the current amount. Check it at startup and it should be zero. Check it after all the allocations and it should have some number. Free all the memory and it should be back at zero. (Malloc already tracks all of the internally, but C does not give us a legal way to get to that information.)

Simple!

Sounds simple!

At first, you might think it could be as simple as something like this:

static int S_memAllocated = 0;

void *MyMalloc (size_t size)
{
    S_memAllocated += size;

    return malloc (size);
}

Simple! But, when it comes time to free(), there is no way to tell how big that memory block is. All free() gets is a pointer.

Sounds almost simple!

To solve this problem, we can simply store the size of the memory allocated in the block of allocated memory. When it comes time to free, the size of that block will be contained in it.

To do this, if the user wanted to malloc(100) to get 100 bytes, you would allocate 100 + the size of an integer. You would then copy an integer containing the size of this allocated segment into the first bytes of the block (and increment the memory counter by that amount). After that, the pointer returned to the user should be after that copied integer. Like this:

malloc (100 + sizeof(int));
+---+----------------------+
|int| the user's 100 bytes |
+---+----------------------+
^
|_ return this location

When this memory is free()’d, the passed-in pointer would be adjusted back past the integer. Those bytes could be copied into an int (so you know how much to subtract from the counter) and then the block free()’d.

Sounds sorta simple?

Here is what I quickly came up with…

// MyMalloc.h
#ifndef MYMALLOC_H_INCLUDED
#define MYMALLOC_H_INCLUDED
size_t GetSizeAllocated (void);
void *MyMalloc (size_t size);
void MyFree (void *ptr);
#endif // MYMALLOC_H_INCLUDED

// MyMalloc.c
#include <stdlib.h> // for malloc()/free();
#include <string.h> // for memcpy()

#include "MyMalloc.h"

static size_t S_bytesAllocated = 0;

size_t GetSizeAllocated (void)
{
    return S_bytesAllocated;
}

void *MyMalloc (size_t size)
{
    // Allocate room for a "size_t" plus user's requested bytes.
    void *ptr = malloc (sizeof(size) + size);
    
    if (NULL != ptr)
    {
        // Add this amount.
        S_bytesAllocated = S_bytesAllocated + size;
        
        // Copy size into start of memory.
        memcpy (ptr, &size, sizeof (size));

        // Move pointer past the size.
        ptr = ((char*)ptr + sizeof (size));
    }

    return ptr;
}

void MyFree (void *ptr)
{
    if (NULL != ptr)
    {
        size_t size = 0;

        // Move pointer back to the size.
        ptr = ((char*)ptr - sizeof (size));
        
        // Copy out size.
        memcpy (&size, ptr, sizeof(size));

        // Subtract this amount.
        S_bytesAllocated = S_bytesAllocated - size;
        
        // Release the memory.
        free (ptr);
    }
}

Then, as a test, I wrote this program that randomly allocates ‘x’ blocks of memory of random sizes… then frees all those blocks.

#include <stdio.h>
#include <stdlib.h>

#include "MyMalloc.h"

#define NUM_ALLOCATIONS     100
#define LARGEST_ALLOCATION  1024

int main()
{
    char *ptr[NUM_ALLOCATIONS];
    
    printf ("Memory Allocated: %zu\n", GetSizeAllocated());

    // Allocate    
    for (int idx=0; idx<NUM_ALLOCATIONS; idx++)
    {
        ptr[idx] = MyMalloc ( rand() % LARGEST_ALLOCATION + 1);
        
    }

    printf ("Memory Allocated: %zu\n", GetSizeAllocated());

    // Free    
    for (int idx=0; idx<NUM_ALLOCATIONS; idx++)
    {
        MyFree (ptr[idx]);
    }

    printf ("Memory Allocated: %zu\n", GetSizeAllocated());

    return EXIT_SUCCESS;
}

When I run this, I see the memory count before the allocation, after the allocation, then after the free.

Memory Allocated: 0
Memory Allocated: 45464
Memory Allocated: 0

Since it is randomly choosing sizes, the number in the middle may* be different when you run it.

I then plugged this code into my program (I did a search/replace of malloc->MyMalloc and free->MyFree) and added the same memory prints at the start, after allocation, and after freeing.

And it worked. Whew! I guess I did not need to spend time writing MyMalloc() or this post after all.

But I had fun doing it.

Additional thoughts…

Thinking back to the MAUI memory API, extra code could be added to put a pattern at the start and end of the block. A function could be written to verify that the block still had those patterns intact, else it could report a buffer overflow or underflow.

Also, I chose “size_t” for this example just to match the parameter that malloc() takes. But, if you knew you would never be allocating more than 255 bytes at a time, you could change the value you store in the buffer to a uint8_t. Or if you knew 65535 bytes was your upper limit, use a uint16_t. This would prevent wasting 8 bytes (on a 64-bit compiler) at the start of each malloc’d buffer.

But why would you want to do that? If you were on a PC, you wouldn’t need to worry about a few extra bytes each allocation. And if you were on a memory constrained embedded system, you probably shouldn’t be doing dynamic memory allocations anyway! (But if you did, maybe uint8_t would be more than enough.)

I suppose there are plenty of enhanced memory allocation routines in existence that do really useful and fancy things. Feel free to share any suggestions in the comments.

Until next time…

Bonus Tip

If you want to integrate this code in your program without having to change all the “malloc” and “free” instances, try this:

// Other headers
#include "MyMalloc.h"
#define malloc MyMalloc
#define free MyFree

That will cause the C preprocessor to replace instances of “malloc” and “free” in your code to “MyMalloc” and “MyFree” and then it will compile referencing those functions instead.


* Or you may see the same number over and over again each time you run it. But that’s a story for another time…

Blog stats for January 2025

I am trying something new, when I remember to do it. Unfortunately, copying and pasting from the stats dashboard seems to make links that have no URL attached to them. Annoying. So for now, just the titles.

Top Posts & Pages:

  1. Using the DJI MIC 2 or Mic Mini with the iPhone native camera app
  2. DJI Neo error downloading videos to phone
  3. Splitting a 16-bit value to two 8-bit values in C
  4. Insta360 X3 and X4 file transfer comparisons
  5. Nested ternary operators in C
  6. Wire up your own RS-232 WiFi modem for under $10 using ESP8266 and Zimodem firmware.
  7. Wokwi online Arduino/ESP32 simulator
  8. C warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
  9. Insta360 ONE X2 photo and video modes and filenames

I guess I need to post more CoCo articles and see if I can get those back in the Top 9.

Top Referrers:

  1. Reddit – mostly from posts in the Insta360 camera group, I believe.
  2. Facebook
  3. WordPress Android App
  4. ecosia.org – “The Greenest Search Engine on the Planet”
  5. vogons.org – a Hitchhiker’s Guide reference! Mostly about my WiFi modem experiments with the ZiModem firmware.
  6. youtube.com
  7. Hacker News
  8. ccsinfo.com – they sell the PIC24 compiler I use at work. I have this blog in my signature.
  9. cse2.chickenkiller.com

I was curious about #9:

chickenkiller.com is being shared via Free DNS, a dynamic DNS domain sharing project where members can setup, and administrate their dns entries on their own remote internet connected systems in real time.

– chickenkiller.com

Top Countries:

  1. United States
  2. Canada
  3. United Kingdom
  4. India
  5. Australia
  6. Germany
  7. New Zealand
  8. France
  9. China
  10. Russia

Old C dog, new C tricks part 1: NULL != ptr

See Also: part 1, part 2, part 3, part 4 and part 5.

Updates:

  • 2025-02-19 – “new information has come to light!”

As someone who learned C back in the late 1980s, I am constantly surprised by all the “new” things I learn about this language. Back then, it was a K&R-era compiler, so there were no prototypes, and functions looked like this:

main(argc,argv)
int argc;          /* argc = # of arguments on command line */
char *argv[];      /* argv[1-?] = argurments */
{
    ...stuf...
} 

…and this…

MallocError(wpath)
int wpath;
{
   ShutDown(wpath);
   fputs("\nFATAL ERROR:  Towel was unable to allocate necessary memory to process\n",stderr);
   fputs(  "              this directory.\n",stderr);
   sleep(0);
   exit(0);
}

Today’s article is not about how old I am, but about something I just started doing, and wish I had done long ago.

Yoda would be happy…

When I learned to program BASIC, I learned how to compare a variable:

IF A=42 THEN PRINT "DON'T PANIC!"

When I learned C, the thing I had to get used to was double equals “==” for compare and single equal “=” for assignment:

int a = 42;

if (a == 42)
{
    printf ("Don't Panic!\n");
}

This, of course, leads to a common mistake that I have stumbled on many, many times over the past decades: Sometimes a programmer misses one of those equals:

if (a = 42)
{
    printf ("Don't Panic!\n");
}

This will cause the code to always enter that section and run it, regardless of what you think “a” is set to. Why? Because it is basically saying “if a can be set to 42, then…”


Or does it?

Normally, I wait for a follow up to discuss corrections and additional details I learn from the comments, but this one deserves an immediate revision. Aidan Hall left this tidbit:

It’s even worse than what you suggest! Assignment expressions evaluate to the value that was assigned (on the RHS), so this if block wouldn’t run:

if (a = 0) {
puts(“zeroed”);
}

– Aidan Hall

I had mistakenly thought it was testing the result of “can a be assigned” and assuming this would always be true. I did not realize it was the value of the assignment that was used. Wowza. Thanks, Aidan! And now back to the original content…


By leaving out that second equal, it now becomes an assignment. It might as well be saying:

if (1)
{
    a = 42;
    printf ("Don't Panic!\n");
}

I have caught this type of thing in code I have worked on at several jobs. And, I’ve caught it in code I wrote as well. Even recently…

But Yoda would be proud. Smarter programmers already figured out that you can write those comparisons backwards, like this:

if (42 == a)
{
    printf ("Don't Panic!\n");
}

The first time I ever saw that was at a former job, and it was code from a team over in India. I thought this was very odd, and wondered if it was some odd convention in that country, similar to how in America we would write “$5” for five dollars, but in Europe it might be “5 €” for five Euros.

Honestly, as backwards as that looks to me, phonetically it makes more sense when you read it ;-)

And don’t get me started on America’s Month/Day/Year and how confusing OS-9’s “backwards” time of Year/Month/Day was… but I quickly adopted that, since you can sort dates that way, but not in the “normal” way.

But I digress…

By reversing these comparisons, you now eliminate the possibility of forgetting an equal. This won’t give an error (but a good compiler might give a warning):

if (a = 42)

…but this cannot be compiled:

if (42 = a)

When I started working on some new code this past weekend, I just decided to start doing things that way. It quickly becomes second nature:

if (NULL != ptr)
{
}

if (false == status)
{
}

But it still looks weird.

Now to fire up that old 1980s compiler and see if that was even possible back then…

Until next time…

MAZE.BAS for the CoCo

While looking for something completely unrelated, I ended up going through some of my old BBS disks. In addition to my *ALLRAM* tape-based BBS, I worked on several other BBSes that were never completed.

One one of those disks was something called MAZE.BAS. But why would a maze game be on a BBS disk?

Running it showed me this…

The player “P” can move around the maze while the enemy “*” tries to get to you. It uses “A-S” for left and right, and “W-Z” for up and down.

Ah, now I remember. I had learned about VIDTEXT/VIDEOTEXT/whatever having control codes to move the cursor around the screen, so I was going to write a maze game to run online in the BBS. If you had a compatible terminal program, you could play an actual “action” game rather than just some text adventure or simulation.

The numbers at the bottom were diagnostics messages. X/Y and movement direction for Up/Down and Left/Right.

Interesting.

Here is the listing…

0 'PALETTE12,63:PALETTE13,0
9 CLS
10 PRINT" #####
11 PRINT" ########## ##########
12 PRINT" # # #
13 PRINT" ### ###### ####### ###### ###
14 PRINT" # # # #
15 PRINT" # ### ################# ### #
16 PRINT" # # # #
17 PRINT" ####### #### #### #######
18 PRINT" # #
19 PRINT" # ###### # # ###### #
20 PRINT" # # ### # #
21 PRINT" # #### #### #
22 PRINT" ### ####### ###
23 PRINT" #### ####
24 PRINT" ###########
25 MX=15:MY=1:PX=15:PY=13
30 POKE1024+(PY*32+PX),80:POKE1024+(MY*32+MX),96
31 PRINT@512-32,PX;PY;XP;YP,MX;MY;X;Y;
35 X=SGN(PX-MX):Y=SGN(PY-MY):Z=(1024+(MY*32+MX))
36 IFPEEK(Z+(Y*32))=96 THENMY=MY+Y ELSEIFPEEK(Z+Y*32+X)=96 THENMX=MX+X:GOTO39
37 IFPEEK(Z+X)=96 THENMX=MX+X:GOTO39
39 POKE1024+(MY*32+MX),42
40 A$=INKEY$:IFA$=""THEN55
45 IFA$="W"THENYP=-1:XP=0 ELSEIFA$="Z"THENYP=+1:XP=0
50 IFA$="A"THENXP=-1:YP=0 ELSEIFA$="S"THENXP=+1:YP=0
55 IFPEEK(1024+(PY*32+PX)+(32*YP)+XP)=96 THENPOKE(1024+PY*32+PX),96:PX=PX+XP:PY=PY+YP
60 GOTO30
999 GOTO999

Using what I know about BASIC today, I would tackle this in quite a different manner.

Maybe I will, as a benchmark exercise.

Until then…

Our magazine ads, before they were typeset…

While going through some random disk images, I found some text files that seem to be the Sub-Etha Software ads, before we took them to the printshop to have them typeset by a professional.

First, this looks like the first ad we planned to run in Rainbow magazine, before we got a deal to do a quarter page inside. Note the company name was going to be Forty-Two Technology and the phone # listed was before I had a dedicated line.

Multi-Basic-- Ever wonder why, with 128K or 512K, you cannot use even 32K under RS-Dos?  Well now there's MultiBasic, making possible, without adding ANY commands, the use of ALL of your CoCo3's memory by basic.  Have several programs loaded in memory at once, able to call subroutines from each other, move between each other, even load other programs from disk, all without variable loss or interruption of program flow.

Shadow BBS-- Finally, a CoCo3 RS-Dos BBS with power, speed, and flair. Uses RS232 Pak or serial port. Features include full ANSI, X/Y Modem, 28 line 40/80 column support, 240 byte onscreen status window, software clock, up to 255 independently numbered message areas, borderlines, one-liner discussions, surveys, auto-messages, doors to external programs, user profiles, full sysop utilities, much, much more! See for yourself, call ShadowBBS HQ at (409)63-REALM. Order thru BBS or thru: Forty-Two Technology, PO Box 4242, Lufkin, TX 75901. (409)637-7604.

Next up is the prototype for the ad we did run, featuring MultiBASIC and SHADOW BBS by Terry Todd. We didn’t have a dedicated phone number yet, so the 632-4200 was just a made up one for the mockup.

 _____________________________________________________________
| |
| |
| |
| |
| |
| |
| MULTIBASIC - Use all 128K/512K of your CoCo 3 without |
| learning ANY new commands! Have several programs loaded |
| at once sharing subroutines and variables! Load programs |
| without losing variables, and more! INTRO. PRICE: $24.95 |
| |
| SHADOW BBS - An RS-Dos BBS with Power, Speed, and Flair! |
| ANSI, X/Y Modem, Clock, Surveys, AutoMessage, Up to 255 |
| Msg Areas, User Profiles, Doors, Borderlines, Full SysOp |
| Utilities, and Much, Much More! Runs on 128K CoCo 3 with |
| Disk Drive(s), Serial Port OR RS232 pak! Call and see |
| for yourself! (409) 63-REALM INTRO. PRICE: $34.95 |
| |
| Sub-Etha Software Call or write for information! |
| P.O. Box 152442 Add $2.00 S&H and $3.00 C.O.D. |
| Lufkin, TX 75901 Texas residents add 8.25% tax. |
| (409) 632-4200 "Don't Panic!" |
|___________________________________________________________|

Next, another prototype… Much closer to what ended up being typeset and published – and even has the real phone number. These blank spots at the top where were the logo was going to go. I did these ASCII ones to show them exactly what we wanted.

 _____________________________________________________________
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| Ever wonder why, with a 128K or 512K CoCo 3 you cannot |
| even use 32K under RS-Dos? Well, now there's MultiBasic, |
| making possible without adding ANY commands the use of |
| your CoCo 3's "hidden" memory by Basic. Have several |
| programs loaded in memory at once able to call |
| subroutines from each other. Move between programs and |
| load other programs from disk without variable loss or |
| interruption of program flow. A "must-have" utility for |
| Basic programmers! |
| |
| INTRODUCTORY PRICE ............................... $24.95 |
| |
| |
| /) Shadow BBS (\ |
| Complete RS-Dos BBS with Low Hardware Requirements! |
| |
| Finally, an RS-Dos CoCo 3 BBS with power, speed, and |
| flair! Uses RS232 Pak OR serial port! Features include |
| ANSI, X/Y Modem file transfers, 28 line 40/80 column |
| support, 240 byte on-screen status window, software |
| clock, up to 255 independently numbered message areas, |
| borderlines, one-liner discussions, surveys, automessage, |
| doors to external programs, user profiles, full SysOp |
| utilities, and much, much more! And unlike most BBSs |
| you've seen, no hard drive, RS232 Pak, or memory upgrade |
| is required! Shadow BBS will run on a 128K CoCo 3 with |
| one disk drive and a modem, yet it is capable of taking |
| advantage of all the hardware your system includes. A |
| full appreciation of Shadow BBS comes not, however, from |
| it's many features or it's low hardware requirements, but |
| from the flair and smoothness of the program itself. We |
| want you to see what this incredible BBS can do. Call |
| The Shadow's Realm, the official Shadow BBS HQ system, at |
| (409) 63-REALM (300/1200 Baud, 24 Hrs.) and see for |
| yourself! |
| |
| INTRODUCTORY PRICE ............................... $34.95 |
| |
| |
| Sub-Etha Software Call or Write for Information! |
| P.O. Box 142442 Add $2.00 S&H and $2.50 C.O.D. |
| Lufkin, Texas 75915 Texas residents add 8.25% tax. |
| (409) 639-ETHA [3842] "Don't Panic!" |
|___________________________________________________________|

And this one, AD4.txt, is another variation:

_____________________________________________________________
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|___________________________________________________________|
|| ||
|| *: MultiBasic :* ||
|| More Memory for Basic without Learning New Commands! ||
|| ||
|| Ever wonder why, with a 128K or 512K CoCo 3 you cannot ||
|| even use 32K under RS-Dos? Well, now there's ||
|| MultiBasic, making possible without adding ANY commands ||
|| the use of your CoCo 3's "hidden" memory by Basic. ||
|| Have several programs loaded in memory at once able to ||
|| call subroutines from each other. Move between ||
|| programs and load other programs from disk without ||
|| variable loss or interruption of program flow. A ||
|| "must-have" utility for Basic programmers! ||
|| ||
|| INTRODUCTORY PRICE ............................. $24.95 ||
|| ||
|| ||
|| *: Shadow BBS :* ||
|| Complete RS-Dos BBS with Low Hardware Requirements! ||
|| ||
|| Finally, an RS-Dos CoCo 3 BBS with power, speed, and ||
|| flair! Uses RS232 Pak OR serial port! Features include ||
|| ANSI, X/Y Modem file transfers, 28 line 40/80 column ||
|| support, 240 byte on-screen status window, software ||
|| clock, up to 255 independently numbered message areas, ||
|| borderlines (quotes), one-liner discussions, surveys, ||
|| automessage, doors to external programs, user profiles, ||
|| full SysOp utilities, and much, much more! And unlike ||
|| most BBSs you've seen, no hard drive, RS232 Pak, or ||
|| memory upgrade is required! Shadow BBS will run on a ||
|| 128K CoCo 3 with one disk drive and a modem, yet it is ||
|| capable of taking advantage of all the hardware your ||
|| system includes. A full appreciation of Shadow BBS ||
|| comes not, however, from it's many features or it's low ||
|| hardware requirements, but from the flair and ||
|| smoothness of the program itself. We want you to see ||
|| what this incredible BBS can do. Call The Shadow's ||
|| Realm, the official Shadow BBS HQ system, at (409) ||
|| 63-REALM (300/1200 Baud, 24 Hrs.) and see for yourself! ||
|| ||
|| INTRODUCTORY PRICE ............................. $34.95 ||
||_________________________________________________________||
| |
| Sub-Etha Software Call or Write for Information! |
| P.O. Box 152442 Add $2.50 S&H and $3.50 C.O.D. |
| Lufkin, Texas 75915 Texas residents add 8.25% tax. |
| (409) 639-ETHA [3842] "Don't Panic -- We Ship Fast!" |
|___________________________________________________________|

I guess by this next one we trusted the typesetting person, since it was just the raw text:

Happy Holidays From...

SUB-ETHA SOFTWARE

"In Support of the CoCo"

Thanks to those who stopped by our booth at the CoCo Fest!

*: MiniBanners :*
Multiple Line Banners on ANY Printer!

NEW! Create single or multiple line banners with adjustable heights and
widths. Up to 16 lines of text with independently sized characters. Even
works with daisy wheel and non-graphic printers! Includes over 30 fonts!

INTRODUCTORY PRICE ................................................ $14.95

*: MultiBasic :*
More Memory for Basic without Learning New Commands!

PRETTY NEW! Tired of being limited to 22K for Basic? We were too, so we
created MultiBasic, a utility which allows you to use the "hidden" memory of
your CoCo 3 without learning ANY new commands. Load multiple programs, disk
chain, share subroutines and variables, all without interrupting program flow.

HOLIDAY PRICE ..................................................... $24.95

*: Shadow BBS :*
Complete RS-Dos BBS with Low Hardware Requirements!

ALSO PRETTY NEW! Finally, an RS-Dos BBS with power, speed, and flair. Uses
RS232 Pak OR serial port. Does not require a hard drive or memory upgrade!
Features: SysOp Utilities, Up to 255 Msg Areas, X/Y Modem, ANSI, Status
Window, Clock, AutoMessage, User Surveys and Profiles, and too much more to
mention here! A full appreciation of Shadow BBS comes not, however, from it's
many features or low hardware requirements, but from the flair and smoothness
of the program itself. We want you to see what this BBS can do. Call the
Shadow's Realm, the official Shadow BBS HQ, at (409) 63-REALM (300-2400 Baud,
24 Hrs.) and see for yourself!

HOLIDAY PRICE ..................................................... $34.95

I wonder what else I will find as I go through these things…

The Hitchhiker Phenomenon (my late 1980s book report)

In the late 1980s, I had a writing assignment and decided to write about The Hitchhiker’s Guide to the Galaxy by Douglas Adams. I recently found this document and decided to share it. It was written in Deskmate for the Radio Shack Color Computer.

Today we know far, far more about Douglas Adams and his life and writings, so I am curious to see what we “thought we knew” back then.

R.I.P., Douglas Adams. You are still missed.


The Hitchhiker Phenomenon

This is the story of Douglas Adams’ now famous “Hitchhiker Trilogy.” It is a story of amazing success, and it all began very simply. It began with a field.

In the early seventies, Douglas Adams was less than the successful writer he is today. A native of England, he was hitchhiking his way around Europe. One evening he found himself lying drunk in a field near Innsbruck. He had been carrying with him “The Hitchhiker’s Guide to Europe” by Ken Walsh, and as the world spun lightly around him, he thought someone should write a hitchhiker’s guide to the galaxy as well.

This idea stayed in the back of his mind for the next six years while he straightened himself up and got an education at Cambridge. After getting “educated,” he would soon find employment in such various fields as chicken shed cleaning, body guarding, and eventually a script writer for such BBC television programs as Monty Python and Dr. Who. His work on these shows displayed his ability for comedy and science fiction writing, which he would soon combine.

Adams was directing a Cambridge Footlights show when he met Geoffrey Perkins, who worked at BBC radio. The link between BBC and Adams now had been made. He had an idea, and he had an opportunity.

He originally wanted to do a series about “The Ends of the Earth” just to see how many ways of destruction he could devise. This would require a character to be there to explain what was going on. To explain why the character was there, Adams decided to make him a researcher for a book: The Hitchhiker’s Guide to the Galaxy. His idea had now evolved into something useful. Now all that had to be done was to get it approved by the BBC Radio Light Entertainment Department.

His idea was submitted, and approved. “…The script was commissioned in the first place not out of a burning desire to do a sci-fi comedy but because the Chief Producer at the time was rather taken with a sketch Douglas had written…about a Kamikaze pilot being briefed for his ninteenth mission.” (Scripts/P.32) Now all Adams had to do was make it.

Radio series at that time were still primitive. Adams knew exactly what he wanted from the start. He wanted Hitchhiker’s to sound like a rock ablum. “I wanted the voices and the effects and the music to be so seamlessly orchestrated as to create a coherent picture of a whole other world…” (Scripts/P.14) he recalls. Even the theme was planned. He wanted an electronic tune with a banjo in it, so the choice of the Eagles “Journey of the Sorcerer” seemed perfect

Sound effects produced for the series are still some of the greatest ever created. (The radio crew spent more time making sounds than other shows spent on their whole program!) Finally, after all of the sounds, music, and actors had been assembled, the story was ready to be told. On March 8, 1978 the first episode was aired.

The story followed the adventures of Arthur Dent. He is rescued by his friend Ford Prefect when the Earth is destroyed to make way for an interstellar bypass, and Arthur begins his cosmic journey. They meet up with Zaphod Beeblebrox, ex-president of the Galaxy, and his companian Trillian, a sexy space-cadet originally from Earth, as well as Marvin, a depressed robot.

This newly assembled crew sets out on a fantastic adventure which reveals the ultimate answer to life, the universe, and everything, which is fourty-two, and the ancient quest to discover what the actual question is. The question was to be calculated by a giant computer called the Earth, which was built and ran for mice.

Zaphod was also on a mission that he didn’t know about. He was going to find the man who rulled the Universe. Detours along the way take them to the legendary planet of Magrathea, The Restaurant at the End of the Universe, and the evil planet Frogstar.

This exciting adventure is hampered and assisted by amazing plot twists. Adams would decide to have his characters flushed out unprotected into space just to see what would happen. Many of his throw-away jokes, such as a robot with personality disorders, were so popular that he kept them. In fact, the whole story soon gained tremendous following in England, and the BBC had to fight to win back the rights for merchandising.

Suprisingly, many of the subjects written about were not as far-fetched as they might seem. “I…find things that…are self-defeating are funny,” (Zest/P.28) Adams recalls. For instance, a wasteland planet which is encountered in the series was a victim of an economic phenomen known as the Shoe Event Horizon. The whole economy mutated into nothing but shoe shops causing a total colapse. Adams claims to have gotten this concept from Oxford Street in London where he once spent three days trying to buy a pair of shoes. “You cannont hurl a brick…without hitting half a dozen shoe shops,” (Scripts/P.227) Adams claims. He says that “shop after shop, all virtually next to each other, carried exactly the same range, and were all out of stock of exactly the same styles and sizes.” (Scripts/P.227)

On this same planet, a delayed spaship in encountered. It is delayed by over nine-hundred years because it couldn’t take off until the supplies of lemon-soaked paper napkins were loaded. Again, this came from a real Adams experience. He was trying to make an important journey from London to Leeds, which he would have made by train if time were not important. Due to the bar not being loaded, the plane sat doing nothing for a half-hour, making the journey take more time than by train, and thus defeating the whole point of taking it. Adams reasons that in order for a plane to fly, it has to have “a pilot,…a couple of wings,…enough fuel,…coffee and biscuits.” (Zest/P.28)

The original radio series projected Adams into a spotlight. He was asked to write a book version. Adams never thought he “would have have the sheer tenacity or bloody-mindedness required to sit down and write a full length novel,” (Zest/P.22) but he did and the books all became instant best-sellers. A seven episode television show followed, and then a two-record album. The Hitchhiker Phenomenon was rolling.

Each form it took was slightly different. Some major events were drastically altered by Adams, but the basic story line manages to end up the same. This made Hitchhiker’s new to old fans each time they experienced a different telling. When the long rumored movie is produced, Adams plans to tell the story once again from a different perspective.

Recent updates to the Hitchhiker series include a fourth book, and the original radio series and TV shows are being broadcast on public radio and television stations all over America. A computer game has also been created, and another is planned. A fifth book has been publically denied by Adams, which means he’s working on one.

The Hitchhiker Phenomenon has been around for almost ten years and shows no sign of slowing. Fans all over the world appear at standing-room-only autograph sessions sporting their Hitchhiker towels and Don’t Panic buttons. The devoted fans are out there, and his following will continue to grow. Douglas Adams didn’t create a simple story – he created an incredible phenomenon.

winget – like apt-get for Linux and brew for Mac?

I was today years old when I learned that winget is a thing for windows.

I powered up my ancient Lenovo ideapad FLEX 4 (so old, it cannot run Windows 11) today, and looked to see what updates where waiting. There were plenty in the Microsoft Store plus some in Windows Update. I only use this machine for running my vinyl cutter and laser engraver, so there is not much on it.

Due to the tiny SSD hard drive, I do have WinDirStat installed. It is a nice tool that will show you what is using up all your hard drive space.

I went to the WinDirStat website to look for updates:

WinDirStat – Downloads

My version was quite behind, so I was abouty to download the installer then I noticed this:

You may also install it with:

  • 📦 winget install -e –id WinDirStat.WinDirStat (or use winget upgrade subsequently)
  • 📦 scoop install extras/windirstat (requires scoop bucket add extras)
WinDirStat – Downloads

I am pretty sure I have used winget before to install some developer thing, but was unaware that it was used by other apps.

Typing “winget upgrade” showed me that it recognized several things on my PC:

C:\Users\alspl>winget upgrade
Name Id Version Available Source
-----------------------------------------------------------------------------------------------------------------------
WinMerge 2.16.18.0 x64 WinMerge.WinMerge 2.16.18.0 2.16.44.0 winget
Windows PC Health Check Microsoft.WindowsPCHealthCheck 3.6.2204.08001 3.7.2204.15001 winget
Microsoft ODBC Driver 17 for SQL Server Microsoft.msodbcsql.17 17.7.2.1 17.10.6.1 winget
Microsoft Visual Studio Code Microsoft.VisualStudioCode 1.91.1 1.96.4 winget
Visual Studio Community 2022 Microsoft.VisualStudio.2022.Community 17.4.1 17.12.3 winget
Dropbox Dropbox.Dropbox 216.4.4420 217.3.4243 winget
Google Chrome Google.Chrome.EXE 131.0.6778.267 132.0.6834.111 winget
Microsoft Visual C++ 2015-2022 Redistributa… Microsoft.VCRedist.2015+.x86 14.31.31103.0 14.42.34433.0 winget
Microsoft Visual C++ 2015-2022 Redistributa… Microsoft.VCRedist.2015+.x64 14.40.33810.0 14.42.34433.0 winget
Slack SlackTechnologies.Slack 4.39.93 4.42.115 winget
Lenovo Service Bridge Lenovo.ServiceBridge 5.0.2.9 5.0.2.17 winget
App Installer Microsoft.AppInstaller 1.23.1911.0 1.24.25200.0 winget
Dev Home Microsoft.DevHome 0.1900.687.0 0.1901.687.0 winget
13 upgrades available.

I tried “winget upgrade WinMerge.WinMerge” and saw it kick off and download the installer, then launch it. Very cool! It even has a spinning cursor while downloading :)

There is a “winget upgrade – all” option that should do all of them. The installers may pop up an authorization box you have to click on, so they are not fully automated, but still neat.

Did I do something on this computer years ago to install winget, or is it on any Windows 10/11 system just waiting to be used? Give “winget upgrade” a try on your PC and let me know if it works…

I have some upgrading to do.

Until next time…