PrintStar's Blog
Ramblings of a Fortran Nut
October 22, 2016 by Jeff

Finishing Touches

The static blog generator, believe it or not, is actually working!  I have a few sample test files that I’ve been working with, and the code seems to be in working order now.  I ran into some difficulties with how the Textile parser was handling exclamation points (every single one triggered the code to generate an image tag), but I’ve more-or-less corrected it now.  The parser, again, is a subset of the Textile markup language, making some pretty reasonable assumptions to keep the code clean.

I did add a few notable items to the code since I last updated this blog:

  • Static files, stored in the project’s STATIC folder, are now copied to the deployment folder
  • A page listing all posts is now generated
  • An INDEX.HTM file is created by copying the latest post to be the default landing page

The very last addition I’d like to add is possibly some parsing of the dates.  In this static site generator, blog post filenames are formatted as YYYYMMDD.TXT as a rule.  I still need to parse the filenames and generate a more friendly date for each post.

I also need to upload a sample project for the site generator.  Once I have the sample site, I’ll be moving on to actually setting up the Rainbow as the web server and beginning my blogging on floppy disks!

  •   •   •   •   •
October 18, 2016 by Jeff

Forgetting How BASIC Works

I finally had enough code earlier today to actually launch the site generator today!  There were plenty of bugs, of course, but I didn’t forsee the bugs related to my handling of arrays.

The first, simple bug I ran into was the “Duplicate Definition” error.  Without really thinking, I never accounted for multiple calls to subroutines that contained BASIC’s DIM instruction for sizing an array.  One cannot simply call DIM for the same variable multiple times.  I do recall a REDIM instruction that existed in PowerBASIC, but it doesn’t exist in ol’ GW.  To fix the issue, I basically “check” if I’ve called the subroutine before by seeing if a variable is set to 1.  If so, I use the ERASE statement to clear the arrays that I’m about to dimension.  It’s dirty but functional.

Once that simple bug was fixed, I noticed most of my arrays were empty later on in the program.  After some digging, I realized that my naive use of assignment of arrays to another variable simply doesn’t work.  I had to squeeze in some additional dimensioning and assignment loops to copy arrays, as one can see in this diff of the blog generator master routine. I feel silly for making such a mistake.

There are still a number of bugs, and it doesn’t “just work” yet, but it did actually generate two HTML files the last time I ran it.  The files themselves, though, are a mess, meaning I’ll need to look at how the Textile processor is wokring again.  Additionally, I did run a test that I thought had shown I could just issue a new line character, but that test was clearly incorrect.

  •   •   •   •   •
October 17, 2016 by Jeff

Moving Slowly Ahead

I’ve recently added another file to the repository, GWBLOG.BAS, that represents the beginnings of the actual static site generator.  As I mentioned before, I thought I’d use the GW-BASIC MERGE statement to keep all the modules separate.  It turns out that MERGE doesn’t exactly work as I had expected.  When called programatically, it actually halts execution after the first MERGE statement.  My attempt at some coding cleanliness failed.

I could just continue by copy/pasting everything into a single BASIC source file, but that could have some downsides just from trying to locate things.  On the other hand, every other GW-BASIC program I’ve ever attempted was a single file, including one game that I once printed out on paper, measuring 11 pages of tractor-fed spagetti code.  I’m already feeling some of the stress of having separate files since I have to call subroutines by line number, and I keep forgetting what the damn subroutine line numbers are!

I’ve decided instead to use a batch file to combine all the files into a single BASIC file and launch the subsequent BASIC file.  I actually tried it for the first time today, and I ran into a bug that I had feared: The list of files returned by the directory listing don’t contain a path, whereas TSORT.BAS expects a full, valid path.  It’s a minor speed bump that I should have some time to correct tomorrow.

  •   •   •   •   •
October 12, 2016 by Jeff

Finally, Some Code!

I’ve been working on my GW-BASIC blog generator quite a bit, and I’ve finally gotten around to posting the code:

The code is currently a set of GW-BASIC source files that each contain a single general purpose.  The goal is to combine all these into a single, functioning static site generator using GW-BASIC’s MERGE command in a programmatic manner.  MERGE will function a bit like the C preprocessor’s #include functionality, but, due to line numbers, you need to plan ahead so that any given file will not overwrite another file.

Below I’ll provide some basic (haha) explanations of each module of the static site generator as it stands today:


This file contains a subroutine for listing files in a given subdirectory.  The task of getting a directory listing as an array is actually pretty infuriating.  In summary, the subroutine actually executes “DIR” using BASIC’s SHELL statement, piping the output to a temporary file.  This file is, in turn, read in and parsed line-by-line in the most naive manner.  Later versions of MS-DOS provided ways to retrieve directory listings without all the other nonsense like file sizes and dates, but MS-DOS 3.10 on a Rainbow 100 does not.


This rather short pair of subroutines create links and lists of links given labels and URLs.


This file contains two subroutines for actually generating complete HTML pages from Textile  markup that are meant to be either a dated post or a static page.  Most of the heavy lifting (e.g. the actual Textile parsing) is handled elsewhere.


This source file contains an extremely simple templating engine (if you could even call it that).  Basically, it’s just a straightforward text replacement engine.  A template filename is provided along with arrays of keys and values, and replaced text is returned.  It can’t do fancy things like loop through lists or perform conditional replacements.  It’s enough, though, to throw a title or link on a page.


This BASIC source code is designed to sort a list of files by either title or date depending on the file’s name.  The idea for blog posts is that each will be named based on the date written: YYYYMMDD.txt In contrast, a page would just be something generic.  If the filename is a date, we need to sort the files based on this date.  If not, the files should probably be sorted based on the page’s title, assumed to be the first occurrence of an h1. tag in the Textile.  This subroutine both sorts the pages appropriately and loads their titles.


This poorly-thought-out file was meant to process a whole directory of Textile into HTML, but it doesn’t have the necessary templates and header/footer code needed that POST.BAS provides.


The madness contained in this file is actually a crude, fragile Textile markup processor.  It unbelievably does work.  Currently, it understands:

  • Headers
  • Paragraphs
  • Ordered and Unordered Lists
  • Links
  • Images
  • Block quotes (because they’re easy)
  • Preformatted text
  • Text styling (bold and italics)

The fact that any of it works is quite baffling to me.  It’s handling of lists, for example, is atrocious.  However, it does actually work, so I can’t complain that much.

The next step is to build an example site to start integrating and testing.  Once that seems to be working, I’ll get an actual blog post or two written in it and attempt to configure the actual Rainbow as a host!


  •   •   •   •   •
October 3, 2016 by Jeff

About My Software

I haven’t had much of a chance to update the ol’ blog this weekend because I’ve had some delightful plumbing problems and I couldn’t miss watching the NWSL playoffs!  I’ll add a quick post tonight, though.

Generally, most work during this Retrochalleng will focus on writing the static blog generator.  To do so, I thought I’d mention some of the software I’d be using since I’m doing everything on the Rainbow itself:

MS-DOS 3.10b

Version 3.10b was the last version of MS-DOS released for the Rainbow.  In fact, Digital Equipment Corp. didn’t even release it.  A separate company, Suitable Solutions, purchased the nearly finished port after DEC killed the Rainbow line and released it to the public.  MS-DOS 3 always felt like a sweet spot to me, although it didn’t come with its own screen editor, which brings me to…


SEDT, or Screen EDiTor, is a fantastic text editor written by Anker Berg-Sonne for an enormous variety of computers.  The MS-DOS version, though, actually recognizes Rainbow 100 hardware, making it somewhat unique amongst DOS text editors.  On DEC machines with an LK-series keyboard, the hotkeys are wonderful to use, relying on the “Gold” key (Num Lock on IBM compatibles) for tons of functionality.  It’s the only text editor on which I really learned all the hotkeys.


GW-BASIC on the Rainbow stopped at version 2, while the IBM PC saw plenty of future releases.  The Rainbow version probably froze because it was almost certainly being ported by DEC itself rather than Microsoft.  That said, GW-BASIC 2 is plenty complete for my purposes.  It’s where I learned to program!

Turbo C 2

Borland’s Turbo C version 2 does “work” on the Rainbow, but only after patching.  For whatever reason, Borland decided with version 2 to employ an interrupt internally that the IBM personal computer didn’t use, but the Rainbow used to access serial ports (I think? It’s been a while since I patched my copy…).  This development was particularly infuriating because version 1 worked just fine.  A little MS-DOS DEBUG action can fix the Turbo C executables, though.

I’m using Turbo C to compile the uIP/FOSSIL TCP/IP stack.  I believe originally I compiled uIP/FOSSIL with Open Watcom on a modern machine, but Turbo C on a Rainbow is way more fun.  The most annoying part, however, is that Turbo C 2 doesn’t understand UNIX line endings, so I have to make sure that MS-DOS line endings are maintain in the source repo.

The above is a little rundown on what’s being used.  I’ll get a bit more specific as I discuss the specific tasks on which I’m working.

  •   •   •   •   •
October 1, 2016 by Jeff

A Peek at My Hardware

I’ll be doing almost all my Retrochallenge programming on one of my Digital Rainbow 100 personal computers.  The one I currently have set up is particularly exciting because:

  • It’s mounted in an E.T. stand
  • It’s using an MFM Emulator for its hard disk

The E.T. stand mounting is pictured below:

An E.T. Stand

The E.T. stand had been featured on this blog before, I believe.  It’s a ridiculous piece of hardware that feautres a pedal-driving monitor arm.  Good times!

The disk emulator is currently set up to simulate a 40MB MFM hard disk; using a higher capacity disk on the Rainbow can be troublesome due to DEC’s terrible cable connecting the disk to the controller.  However, the machine is delightfully silent now that some ancient Seagate monstrosity doesn’t have to spin up.  Furthermore, the emulator is a bit faster than an actual hard disk (though not appreciably so).  I had previously taken some pictures of the emulator, so I’ll skip that for now.

Just two days ago, I decided to “modify” the LK201 keyboard attached to my ‘bow.  Some years ago I acquired a clear plastic cover to replace the tan plastic on the keyboard.  The alternate casing was apparently created by DEC as a way to show off the keyboard’s internals at promotional events.  It’s clearly built by them since a mold that fits perfectly would have been expensive to produce.

There’s a brief look at where I’ll be working!  I’ll have another post on the software I’m working with on the Rainbow itself next.

      •   •   •   •   •
    September 30, 2016 by Jeff

    Retrochallenge 2016/10

    I’ve decided to try another Retrochallenge!  This October, I plan to attempt migrating my blogging activities, however sparse, to a DEC Rainbow 100 permanently.  The blog will be generated by a static site generator written in GW-BASIC and served using uIP/FOSSIL, originally ported during the 2009 Retrochallenge Winter Warm Up.

    Using WordPress has become somewhat unpleasant.  Yes, I’m currently typing into a WordPress blog, but it isn’t a fun experience.  Lately, for work, I’ve transitioned a number of websites to static sites generated via Cactus.  I think moving to a static generator for my blog could be delightful.

    Over the past few weeks, I’ve been writing some GW-BASIC subroutines to support this endeavor.  A nice deadline, though, should really get things moving.

    I plan on providing some delightful details of the hardware involved of getting a DEC Rainbow 100 permanently serving pages. I also plan on completing the static blog generator in GW-BASIC, and hopefully someone else might actually find it useful or, at the very least, amusing.  With a DEC Rainbow serving a blog, I think I might perhaps become a bit more prolific.

      •   •   •   •   •
    July 23, 2014 by Jeff

    The Unfamiliar Land of 8088 Interrupts

    It’s been just less than two weeks since my last Retrochallenge update.  I started off strong with posting, but I fizzled fast once I hit the real work.  So have I dropped out?  Not exactly…

    After perusing the piles of Rainbow documentation I have available in a desperate search for how to interact with the Z80 CPU through hardware, I started writing some test code.  At first it was simply a naive attempt to trigger the Z80 to execute anything at all.  Without any context, I was signaling the Z80 to start running by pushing code 0×21 out through I/O port 0 on the 8088 CPU.  This exercise was entirely uninteresting because, after doing so, the 8088 continues on about its own business.  It doesn’t automatically stop and wait for its sister CPU to finish up.

    What should happen under these circumstances is that the Z80 should trigger an interrupt (0×47 to be exact) on the 8088 to notify its friend that it has completed the requested work.  In order to perform this work, I wrote a slightly more elaborate program.  Now it would load some Z80 machine code into the lower 64KB of Rainbow RAM (but above the 2KB mark), attempt to configure the Z80′s start address, and request that the Z80 execute the code.  The unclear part of the above is how exactly to specify the start address to the Z80.  To move things along, I decided to hand-type the MS-DOS BIOS’s execz80 routine.

    The above, once again, really didn’t do much at all since the code didn’t handle any Z80 interrupts yet.  I did send the code off to the Z80, request some work, and halt the 8088, which did work.  What this program showed was that some miscellaneous interrupt was triggering the 8088 to come back to life.  I hoped it would be interrupt 0×47 from the Z80, but I wasn’t sure.  It was time to start writing an appropriate interrupt handler.

    The problem with all these attempts, of course, is that I really don’t know how to work with interrupts.  Sure, in the past, I’ve triggered interrupts to access screen or disk I/O, but I’ve never responded to an interrupt.  The other problem with writing something “new” of this vintage is the documentation.  I have a complete Microsoft C and Macro Assembler documentation set, but nowhere in these binders do they explain exactly how one might author an interrupt handler.  Sure, they provide functions to hook your handlers into the OS, but there’s no implementation examples.  Online searches are generally useless as well because they either focus on modern 32-bit (or higher) machines or they don’t turn up in results.

    I did find a promising introductory paper that gave an example of an interrupt handler responding to system clock ticks.  I decided to work with that code, and I wrote a simple handler that would allow my main program to proceed if it were ever triggered.  I attached the handler to the Z80 interrupt, and, lo and behold, I received the dreaded Message 16 – Interrupts Off message on the Rainbow, returning me to the boot menu. Anyone familiar with the Rainbow know that this message generally means, “something went wrong, so here’s an error that doesn’t actually help you figure out where the problem is.”

    While it was an error, it was something, at least.  For a few more days, I toyed with this same program, trying to get it to do something.  After continual failure, I decided to see if I could write a simple program to trigger and catch a generic, unused interrupt.  This program was met with varying success.  It didn’t always trigger Message 16, though, but it didn’t proceed either.  Basically, the program would trigger an interrupt, then continually check a variable to see if it changed.  The interrupt handler would change that variable when the interrupt was caught, allowing the program to exit.  Almost always, it simply sat there locked up.

    Yesterday it occurred to me that perhaps the handler wasn’t changing the variable properly.  Looking at the code, I made one simple change.  I had declared my status variable that allowed my program to exit as a global:

    static int returned;

    I had been compiling my program as a “small” memory model (don’t you all love x86 chips!).  In this circumstance, though, the variable “returned” existed only in the data segment in which my program ran.  The interrupt handler, on the other hand, does not run in this same segment.  I made one simple change:

    static int far returned;

    Surprise!  My program suddenly worked!  x86 segmented memory strikes again!

    I stopped yesterday after that small victory.  I’ll try again today (hopefully) to catch Z80 interrupts.


      •   •   •   •   •
    July 10, 2014 by Jeff

    Switching to Microsoft

    After a couple of days away from my Retrochallenge, I decided to dive back into trying to get that damn Z80 CPU to listen to me from MS-DOS.  A few days back, I actually stopped in frustration when I realized that I would definitely need to do some x86 assembly language programming to get things moving forwards.

    I had posted a scanned page from the Rainbow 100′s CP/M technical documentation that seemed to outline how to pass a message to the Z80 properly:

    The page outlined the values for the registers of the 8088 when trying to pass arbitrary code to the Z80.  To be honest, I have some serious doubts about the above scheme working when in MS-DOS; I can’t seem to see where anything similar is done in the MS-DOS BIOS code to trigger the Z80 to perform disk access.  There is a good chance that the CP/M BIOS is performing some extra work behind the scenes after the above call is made.  However, the method above is easy enough to try.

    I foolishly assumed, though, that I would be able to first set the values of the 8088 registers and then signal the 8088 output port from C.  This idea is, of course, nonsense because C is too “high-level” to hope that any particular register would persist between being set and my calling a C outport() function.  I needed to use assembly, which annoyed me enough to stop for a bit.

    Yesterday I decided to dive back in.  However, I did run into some speed bumps.  Normally on the Rainbow I work with Turbo C as opposed to Microsoft C.  This preference is based on:

    • Turbo C’s MAKE utility actually works (unlike Microsoft’s lobotomized MAKE)
    • Turbo C’s directory layout is considerably simpler

    For an assembler, things became a bit trickier.  I do also have Turbo Assembler, but, when I ran it yesterday, I found that it did not work on the Rainbow at all.  It wouldn’t even run under Code Blue.  And why is doesn’t it work?

    Borland is mildly famous in DEC Rainbow circles (is that a thing?) for being complete jerks.  Borland produced a number of compilers and applications for the Rainbow as native programs, both under MS-DOS and CP/M.  However, when Turbo C 2.0 was released, things went bad.  Rainbow users who bough the software were horrified to find that this “MS-DOS compatible” compiler didn’t run at all, while previous versions ran just fine.  Borland was completely silent on the issue, too.

    One enterprising Rainbow user was able to determine what was actually happening.  Internally, the Borland compilers were unexpectedly using MS-DOS interrupt 0×18.  This interrupt is relatively harmless on an IBM PC, but it is used for communications ports on a Rainbow.  There was no reason for Borland to choose 0×18 in the first place; it is entirely arbitrary, which makes Borland’s choice so frustrating.  This helpful Rainbow user, though, was able to generate a set of patches for the Turbo C executables, the compiler and preprocessor specifically, that changed their internal interrupt calls to use 0×60 instead.  The same user went on to generate patches for a number of other Borland tools as they continued to use interrupt 0×18 all over their development tools, including Turbo Assembler..

    My copy of Turbo C is obviously already patched.  However, I never did take the time to patch Turbo Assembler, apparently.  Additionally, I have no hard-copy documentation for any Borland tools.  The unpatched assembler and the lack of immediately available documentation convinced me that it was time to move on to Microsoft’s tooling.

    I spent yesterday transferring Microsoft’s Macro Assembler and C Optimizing Compiler onto my Rainbow 190.  All these packages do add up to a considerable amount of disk space relative to its 20MB disk.  However, my 190 is not one of my long-held Rainbows, so it started the Retrochallenge with a relatively empty disk, only containing my essentials:

    • MS-DOS 3.10b
    • Borland Turbo C 2.0
    • BinkleyTerm 2.40
    • Kermit
    • GW-BASIC

    The transfer of MASM to the Rainbow was simple and fast.  Although the archive was about 680KB in size, it goes relatively fast transferring it from a GNU/Linux server via ZModem at 19200 bps.  On the other hand, my stripped-down MSC 5.1 distribution, weighing in at about 900KB, was sitting on another Rainbow with a notoriously (in my house) slow hard disk.  I couldn’t transfer between the two Rainbows using ZModem because the receiving Rainbow would time out prior to the “slow hard disk” Rainbow even accessing the file to transfer.

    Whenever serial transfers become problematic, it’s time to pull out old, slow, and reliable Kermit.  If ZModem were a sports car, Kermit would be a car that won’t start and is being pushed manually up a steep hill. In contrast, though, Kermit provides drastically more reliable error checking than ZModem to the point of overkill.  Back in the BBS days, I rarely had any issues with ZModem, but occasionally the speed of disks can become an issue, requiring a slower transfer rate.  I started the transfer and left the two Rainbows to talk it out.

    In summary, I now have a fully function Microsoft C and MASM environment all set up and functioning.  Hopefully I can get on with my work.

      •   •   •   •   •
    July 3, 2014 by Jeff

    Finding the Z80

    I started today’s Retrochallenge work by trying to hunt down exactly how to trigger the Z80 to execute code.  Unsurprisingly, the Rainbow’s MS-DOS technical documentation doesn’t actually provide an answer to this question directly.  Because the Rainbow’s MS-DOS BIOS only employs the Z80 for disk access, there would be no “practical” reason to do so otherwise.

    The interrupt tables also suggest this inability to access the Z80.  The only interrupts available that appear to do anything similar are actually “Interrupt from the Z80A,” rather than asking the Z80 to do work.  So where to go now?

    Digital’s Technical Documentation  for the Rainbow is an odd collection of massive binders containing a plethora of both useless, high-level information (“Available Peripherals: Keyboard…”) and low-level gems (the video memory’s linked-list layout and scrolling via changing pointers alone).  It also, oddly enough, contains the complete Microsoft Macro Assembler source code for its MS-DOS BIOS.  That’s right, Digital provided every last line of source code for their BIOS.

    If we want access to the Z80, we just need to look up the RX50 disk driver source code in the BIOS.  Sure enough, when we look closely through the code, we come across the routine “execz80” in the assembly:

    I’m not any sort of assembly language expert, but I can usually stumble through the code.  It appears, though, that simply pushing some data OUT to port 0 (the value of intz80) on the 8088, causing the Z80 to begin execution of code.  There is obviously some work to be done setting up what exactly the Z80 should be doing, but it appears that the process is rather straightforward.  The 8088 then sits in a waiting loop checking to see if the Z80 is done.

    I’d rather like to avoid writing assembly language code for this challenge with the exception, possibly, of some Z80 assembly.  Peeking through Turbo C and Microsoft C headers, I ran across “outport” and “outp” respectively (MSVC still supports outp…).  These should allow me to fire off requests to the Z80 from C hopefully, but we’ll have to see.

    As an aside, I’ll try to post any images to my SDF Gallery account for all to see and enjoy.  Some Twitter pictures might take a few days to show up, but I’ll do my best to consolidate everything.

      •   •   •   •   •