maettig.com

MiDat TSR database

← Back to the index of my DOS archive

One of my creations I ended using most often was a fast, light-weight, line-oriented micro database. The DOS program was waiting in the background as a memory-resistant program, ready to be activated from every other text mode based DOS program by hitting the Alt+Scroll lock key.

Screenshot of MiDat for DOS on the top of the screen, FILE_ID.DIZ in the background Screenshot of MiDat for DOS Screenshot of MiDat for DOS

It was TSR program. A concept PowerBASIC called "popup".

As in many of my later PowerBASIC creations I used version numbers like "v1.0", but more as a marketing tool, since that was what version numbers meant to me these days. I had no idea how semantic versioning works. In addition I kept track of the date whe a source file was changed last.

All my source code files had a license header back then. I called it "copyright", not "license", but it was a license. Specifically "Public Domain".

I used a documentation header that was the same in many of my projects, as well as a custom set of PowerBASIC compiler directives, mostly for a minimized executable file.

I used German inline comment next to English variable names for a very long time.

Impressive Features

You can specify a working directory, including a file name extension pattern, e.g. midat c:\tables\*.tsv. There is quite some code to deal with all the possible combinations, including some inline assembler not to get the current working directory (that would have been a simple CURDIR$ function) but to get the directory of the MIDAT.EXE executable. The default was to store the text files right there in the program directory. This was quite common when working with DOS.

File selector dialog with quick search.

Kind of forshadowing how UI patterns would evolve the next 20 years there is no save button anywhere – but unfortunately also no undo. MiDat simply auto-saves.

Automatic alphabetical order. ARRAY SORT strings$ COLLATE UCASE.

quick search and continue searching by pressing Ctrl+Enter.

The Tab key moved the short MiDat window to the bottom of the screen, and back up. This was an essential feature. See, the whole reason why the MiDat UI was so tiny and callable from within other programs was so that I could see the original program – e.g. Norton Commander – in the background and make notes about whatever was on the screen that moment.

There is a lossy character set conversion function, triggered by pressing Shift+F2, that allows to open Windows text files and convert their charset from Windows-1252/ISO 8859-1 to MS-DOS' codepage 437/850. This conversion is limited to the German umlauts ä, ö, ü, Ä Ö, Ü and ß. F2 triggers an "export to Windows" function, converting tabulator-separated text to semicolon-separated CSV while also converting the charset to Windows-1252. These files get the extension WDB, which stands for "Works database", the target program I had in mind.

There is a print function, triggered by pressing F9, doing LPRINT in a loop. With a confirmation popup. With error checking and reporting. All unnamed, in the middle of the main keyboard handler loop, which is in the middle of the TSR loop. Awesome. Clearly a "because I can" feature. I can't remember using it. Why should I? You can not choose what to print. It's even bound to a specific printer when it tries to predict the number of pages it's going to print, assuming a page will contain exactly 66 lines. Epson LQ-550, that was the model my family had back then. A programmable (!) printer that deserves it's own whole story.

Hidden features

I wrote a robust tabulator expansion algorithm that converts tabs to the correct amount of spaces, just as in any other text editor I used back then (mostly the PowerBASIC and Norton Commander editors). Traditionally, the tab width in DOS programs is 8 spaces, and can not be changed.

The line editor supports Ctrl+Cursor right and left, which makes the cursor jump to the end of the next or the beginning of the previous word. It's somewhat impressive that I loved this feature so much that I came up with my own implementation, including a custimized set of "jump over" characters. And today, 18 years later, I still use word-jumping every single day. I need it so much that I get angry when it's missing in an editor, e.g. in the otherwise totally awesome Nano editor I currently use to write my Git commit message.

MiDat uses a custom blinking text cursor, spanning the bottom two pixel rows of the character. Usually it's a single pixel line. The assembler instruction for this is mov ah, 01h; mov ch, 06h; mov cl, 07h; int 10h, or, converted to 16 bit decimal numbers, reg 1, &h0100: reg 3, 1543: call interrupt &h10.

You can leave the line edit mode any time by pressing Enter or the cursor up/down keys.

Pressing Esc in edit mode usually means "cancel", and changes to the current line are reverted. But there is one exception: When the line was empty, there is nothing that can get lost and the new line is saved.

There is a backup feature you can enable by using /bak as a command line parameter. I remember myself not using this feature, because it did not made much sense, considering how the tool was meant to be used: You open it by pressing Alt+Scroll lock, edit a single line, and close it. This means the backup file was usually only a few minutes older than the original, with very few or even a single line being different.

You can send the tool back to sleep by pressing Esc or another key combination I couldn't remember until I looked it's key code 0,45 up. Alt+X, a hotkey widely used as a boss key in DOS games.

Structure

The structure of the code is really horrible, even back then. One instruction per line? Named functions? Nah. Minimal code was much more important, which does make quite some sense considering the screen space was limited to 21 lines with 77 characters each in the PowerBASIC IDE. There are only five procedures and one function. The main part of the code, more than 400 lines, are not structured at all. Even worse. There is a giant, unconditional loop wrapping more than 300 lines. The deepest nesting level is 7 levels. Variable names are a mess. There is stuff like fff, fw, fw1 and tmp, and the main data structure is called u1$.

There are three different keyboard handler loops: One in the file selector, one when browsing the lines of a text file, and one in the line editor. I remember being proud when I understood this core concept.

do
  i$ = ""
  while len(i$) = 0
    i$ = inkey$
  wend

  if ascii(i$) = 27 then
    print "Esc was pressed"
    exit loop
  else
    print "Character " + $i + " was pressed"
  end if
loop
Yes, this is an endless loop that wastes 100% CPU resources as long as no key is pressed. Yes, that's how it's typically done under DOS. There is no multitasking anyway. Back then I had no idea how to set up a custom keyboard interrupt handler.

I was still using GOTO in a few places. Sometimes to exit nested loops, similar to what we are still allowed to do nowadays. Sometimes to jump back to the file selector when pressing F3.

In total, there are 13 interrupt functions called. One of the calls is even done in an inline assembler section. Some pieces of code are simply copied when I needed them again. As said, nothing is reused.

There is a lot of PEEK and POKE going on for multiple purposes, which is PowerBASIC's way to work with pointers to directly access the memory. I'm using it mostly to access the shadow video RAM and draw the UI, which is much more powerful and also much faster than using BASIC's PRINT command.

Bugs

  • Move the selection to a long line and press End. Parts of the screen are not refreshed and show a fragment of the long line. This is because I changed the UI once to have more narrow borders and a longer line editor. I forgot to update a minor redraw code snippet accordingly.
  • Switch to edit mode by pressing Enter and continue typing at the end of the line. This kind of works but can not be seen since there is no horizontal scrolling.
  • When you open a regular text file, it appears to be empty, because all the empty lines in the file get ordered to the top.

Download the »MiDat« source code (PowerBASIC)