Operating System Programming with Multiple Libraries — A Walkthrough

This article is a structured synthesis of Chapter 4 ("Operating System Programming") of Amiga C for Advanced Programmers by Bleek, Jennrich, Schulz (Abacus / Data Becker, ~1991). The chapter is structured as a build-along tutorial: the authors construct a complete text editor in C that combines several Amiga libraries (intuition, graphics, dos) and the Exec memory allocator. This page distils the OS-programming lessons from that tutorial; for the full source listing see the raw OCR source (pages 391 onwards).

Editorial note: this synthesis is derived from an OCR scan of a scanned book. Body text is generally clean, but code blocks may have minor OCR artefacts (> may render as ->, indentation may be inconsistent, hyphens sometimes split across lines). Page references use the PDF page index in the raw source, not the book's printed page numbers.


4.1 Planning the editor (pages 391–398)

The chapter opens with a planning phase. Before any code, the authors argue for a linked-list representation of editor lines over a fixed-size array:

  • Linked-list approach: each line is a separate memory block; line length is unbounded; total capacity is limited by available memory; insertion/deletion is O(1) by pointer manipulation.
  • Trade-off: memory management becomes more complex than a fixed array, but the result is the standard Editor-as-Exec-list pattern the rest of the chapter builds on.

The data structures introduced (pages 396–398):

struct Memoryblock {
    struct Memoryblock *succ;   /* successor in list */
    /* …length, free bytes, etc. */
};

struct BList {
    struct Memoryblock *head;
    struct Memoryblock *tailpred;
    struct Memoryblock *tail;   /* always NULL — sentinel */
};

The head / tailpred / tail=NULL layout is the same idiom used by Exec's own List structure (see exec/exec-library-reference.md). The authors chose to roll their own rather than depend on Exec lists directly, so they can control memory layout and line metadata in the same block.

Editorial note [claim — unverified]: the exact field names and ordering shown above are reconstructed from OCR; verify against the printed book if quoting.


4.2 Development stages (pages 399–407)

The first executable version of the editor does nothing but open and close the three libraries the program will need. This is the minimal multi-library harness, and it is the canonical template for any non-trivial Amiga C program:

4.2.1 Library base pointers

#include <exec/types.h>
#include <intuition/intuition.h>

struct IntuitionBase *IntuitionBase;
struct GfxBase       *GfxBase;
struct DosLibrary    *DosBase;

int main(void) {
    if (!(IntuitionBase = (struct IntuitionBase *)
            OpenLibrary("intuition.library", REV)))
        goto Ende;
    if (!(GfxBase = (struct GfxBase *)
            OpenLibrary("graphics.library", REV)))
        goto Ende;
    if (!(DosBase = (struct DosLibrary *)
            OpenLibrary("dos.library", REV)))
        goto Ende;

    printf("Everything is open\n");

Ende:
    if (DosBase)        CloseLibrary((struct Library *)DosBase);
    if (GfxBase)        CloseLibrary((struct Library *)GfxBase);
    if (IntuitionBase)  CloseLibrary((struct Library *)IntuitionBase);
    return 0;
}

The goto Ende cleanup pattern is the standard pre-Cleanup C idiom for Amiga multi-library programs. With exec.library providing automatic library-base semantics, you can use exec.library Cleanup macros (introduced in later NDKs) instead — but the manual goto pattern shown here was the canonical template in 1991, and is still used in code targeting Aztec C.

4.2.2 Build pipeline

The chapter introduces the Aztec C compiler invocation pattern and a make-driven build:

  • Header pre-compilation (+I): the C compiler pre-processes all #include directives into a single precompiled-header file:

cc +Ipre/Editor.pre src/Editor.c

This was a significant speed-up on 1991 hardware — the authors note "the compiler should now work faster". For a tutorial written before ccache or NDK 3.x's include-file caching, this was the standard optimisation.

  • make-based builds: the chapter introduces makefiles early so the build can scale as the editor grows in modules.

Editorial note [claim — unverified]: the specific Aztec C flag spellings (+I, +B, -O) and the makefile syntax shown are reconstructed from OCR. If quoting, cross-check against an Aztec C manual.


4.3 Step by step — building the editor (pages 408–end)

The third section is the longest. It walks through the construction of the editor module by module. The principal sub-sections are:

Section PDF page Topic
4.3.1 408 Project layout: Editor.h, Editor.c, pre/, src/, build modules
4.3.2 416 RAWKEY → ASCII conversion (user-defined conversion table, IDCMP raw-key event handling)
4.3.3 ~420 Memory allocation module: getZline(len), free-list bookkeeping, block splitting
4.3.4 429 Testing the new memory functions (Test module)

After section 4.3, the source listings continue to the end of the chapter. The full appendices (editor listings, version 1 and version 6) follow in the raw source from page 463 onward.

4.3.1 — Editor.h declarations (page 408)

The chapter sets up the public header with the data structures shared across modules. Notable points:

  • Standard includes: <exec/types.h>, <intuition/intuition.h> (the 1991 minimum — pre-2.0 NDK), plus the local Editor.h.
  • Forward declarations for struct RastPort, struct Window, struct Screen — required because the full struct definitions were too heavy to include everywhere.

4.3.2 — RAWKEY to ASCII (page 416)

A key OS-programming topic: how to convert the IDCMP RAWKEY events the Intuition event loop delivers, into the characters your application actually needs. The book's approach:

  • A user-defined conversion table, indexed by (rawkey_code << 1) | qualifier_flag.
  • Modifier-key handling (IEQUALIFIER_LSHIFT, IEQUALIFIER_RSHIFT, IEQUALIFIER_CAPSLOCK) as a separate mask combining step.

This is the standard pre-2.0 pattern. From AmigaOS 2.0 onward, Intuition provides Intuition → Keymap mapping as a first-class API; from AmigaOS 3.5 / NDK 3.9 the keymap.library API exposes the underlying tables directly. See intuition/intuition-library-reference.md for the modern API.

Editorial note: this article does not cover the modern Keymap API; for that, see the Intuition Library Reference and the relevant autodocs in your NDK.

4.3.3 — getZline(len) (page 420)

The memory allocation primitive. Walks the BList of Memoryblocks looking for a block with enough free space, splits the block if needed, and returns a pointer to the line buffer. The implementation includes:

  • Length rounding to even byte boundary (because Exec memory blocks have alignment requirements).
  • Free-list insertion / removal via Remove(struct Node *) (Exec list primitive).
  • BlockSplit semantics: a freed tail of the block is returned to the free list.

The pattern shown is functionally a slab allocator over Exec memory — a design that reappears in many Amiga C programs of the era.

4.3.4 — Testing (page 429)

A separate Test module exercises the memory functions before they are wired into the editor. The book makes a point that the test functions are stripped from the final build — they're scaffolding only.


OS-programming patterns extracted from this chapter

The tutorial, although framed around a single application, demonstrates several OS-programming patterns that recur across the wider Amiga codebase:

1. Library-base pointer globals

Pre-NDK 3.x code uses global library-base pointers (IntuitionBase, GfxBase, DosBase). The function call patterns (OpenWindow(...), Open(...)) work because the compiler emits code that loads the global, indexes into the function table, and jumps. With exec.library exec.library Cleanup macros and modern NDKs, you can use struct Library *IntuitionBase (or IExec for inline Exec) and have the OS auto-resolve. The book uses the pre-Cleanup style.

2. Goto-cleanup for resource management

The goto Ende pattern (4.2.1) is the canonical pre-RAII idiom for ensuring resources are released in reverse order on early failure. Modern NDKs add exec.library Cleanup macros which formalise this.

3. Custom data structures layered over Exec

The BList / Memoryblock design (4.1) is a recurring pattern: define your own higher-level structure, but use Exec's list primitives (Remove, AddHead, AddTail, Insert) underneath. See exec/exec-library-reference.md.

4. Pre-compiled headers (+I flag)

Aztec C's precompiled-header flag was the era's answer to slow C compilation. Modern SAS/C, VBCC, and GCC all have analogous features; on SAS/C it's #pragma, on GCC it's -include.

5. RAWKEY conversion table

The 1991-era pattern from 4.3.2 (custom conversion table) is now obsolete in production code: OS 2.0+ provides Keymap and OS 3.5+ provides keymap.library. The book mentions these as forward-looking only.


What this chapter does not cover

The chapter is deliberately focused on synthesising the lessons of Chapters 1–3 (compiler, Intuition) into a single application. It does not cover:

For modern multi-library programs, conventions/coding-standards.md is the canonical reference for the equivalent patterns in current NDKs.


Sources

Editorial markers [claim — unverified] indicate content reconstructed from OCR that should be cross-checked against the printed book before quoting verbatim.