---
title: DOS
url: 'https://wiki.teletypegames.org/platforms/dos'
markdown: 'https://wiki.teletypegames.org/platforms/dos.md'
lang: en
date: '2026-10-26'
description: 'Our DOS programs are C++98 built with Open Watcom v2: a 16-bit DOS executable (8086, large model) and, where there is one, a 32-bit Win32 console build for Windows 95 and later. They are tested in a headless DOSBox Staging and under Wine, and the shared code is DOSLIB. Open Watcom v2: https://githu…'
taxonomy:
  tag:
    - howto
---

# DOS

Our DOS programs are C++98 built with **Open Watcom v2**: a 16-bit DOS executable (8086, large model) and, where there is one, a 32-bit Win32 console build for Windows 95 and later. They are tested in a headless **DOSBox Staging** and under **Wine**, and the shared code is [DOSLIB](https://wiki.teletypegames.org/dos/doslib).

**Open Watcom v2:** https://github.com/open-watcom/open-watcom-v2 **DOSBox Staging:** https://www.dosbox-staging.org **Tools repository:** https://git.teletypegames.org/build/dos-tools **Programs built with this toolchain:** [GMENU](https://wiki.teletypegames.org/dos/gmenu), [DOSINST](https://wiki.teletypegames.org/dos/dosinst), [BMAGIC](https://wiki.teletypegames.org/dos/bmagic), [TTGWIKI](https://wiki.teletypegames.org/dos/ttgwiki)

---

# A program's repo

Like every other platform, a DOS program's repo holds a one-line marker and its metadata; the pipeline is served by the [WarpEngine](https://wiki.teletypegames.org/engines/warp-engine) of teletypegames.org, and everything it runs is in the builder image.

```yaml
# .woodpecker.yaml
platform: dos
```

```json
// metadata.json
{
  "name": "dosinst",
  "version": "0.6.1",
  "title": "DOSINST",
  "author": "Teletype Games",
  "desc": "Installs, updates and removes DOS programs from an FTP store.",
  "license": "GPL-3.0",
  "category": "tool",
  "dos": {
    "folder": "DOSINST",
    "files": ["DOSINST.EXE", "DOSINST.CFG", "README.md", "LICENSE"],
    "settings": ["DOSINST.CFG"],
    "store_name": "DOSInst Store",
    "store_description": "Installs, updates and removes DOS programs from this store.",
    "win32_folder": "DOSINSTW",
    "win32_files": ["DOSINSTW.EXE", "DOSINST.CFG", "README.md", "LICENSE"],
    "win32_store_name": "DOSInst Store for Windows",
    "win32_store_description": "DOSINST for Windows 95 and later."
  }
}
```

The `dos` block says what a release holds: the folder the program is installed as, the files that go into it, the `settings` that are in the release zip but never in a store update (so an update keeps an installed program's configuration), and the name and text the DOSINST list shows. The `win32_` keys are the same for a Win32 build, and optional.

The rest is convention: `SOURCE/build.sh` builds the executables into the repo root with the Open Watcom in `$WATCOM`, and the tests are where the commands look for them. The version is `version` in `metadata.json`, as on every platform; when `SOURCE/app/version.h` has a `Version`, it has to match (raise the two together).

# The pipeline

After a push the pipeline runs version → test → tag; on the tag: version → test → package → upload → publish → release. The `version` step is the engine's shared one, and DOS releases only from a tag (`release_rule "tag"`), so everything after the test runs on a tag only. The tag is the pipeline's own (WarpEngine 1.9): a new `version` in `metadata.json`, pushed to master, gets its `vX.Y.Z` tag from the `tag` step, and that tag makes the release. A push that leaves the version as it is only tests; off master the build is a `dev-<version>-<branch>` and its `dev-<branch>` tag is moved, which publishes the dev build to the catalog but never to the store (the shelf takes the newest non-`dev-` release). Until 2026-10-27 the DOS repos had no version in `metadata.json` and were released by tagging by hand; a tag made by hand still works, and has to match the version.

| Step | Command | When | What it does |
|---|---|---|---|
| test | `dos-check` | every event | the code style (DOSLIB's clang-format wrapper), the unit tests (`SOURCE/test/unit/run.sh`), the Python tests of a server side (`server/test`) |
| test | `dos-build` | every event | `SOURCE/build.sh`, then every `.EXE` of the file lists must be there |
| test | `dos-test` | every event | `SOURCE/test/run.sh` (DOS in headless DOSBox Staging), `SOURCE/test/runw32.sh` (Win32 under Wine), `SOURCE/test/run.py` (DOSBox screen tests) |
| tag |  | after a push | the engine's shared step (1.9): a new version gets its `vX.Y.Z` tag, whose pipeline runs the rows below; a version tagged already releases nothing; a dev build moves its branch's `dev-<branch>` tag |
| package | `dos-pack` | a tag | the folder zips and each `.EXE` alone, listed in `.release-assets` |
| upload, publish |  | a tag | the folder zip becomes the `cartridge` asset, the Win32 zip `win_x86`; the uploaded metadata keeps the `dos` block |
| release |  | a version tag | the engine's shared release step: the Gitea release with `RELEASE_NOTES.md`, the files of `.release-assets` attached |

There is no store step and no deploy key: the only secrets are the global `application_token` and `gitea_token`. The FTP store, `ftp://ftp.teletypegames.org/APPS`, where [DOSINST](https://wiki.teletypegames.org/dos/dosinst) installs and updates from, is the [WarpEngine](https://wiki.teletypegames.org/engines/warp-engine)'s DOS shelf (`layout: "folders"`). On every publish the engine rebuilds it from the catalog: from the zip and the `dos` block it writes each folder without its `settings` files, with an `INFO.INI` and a `FILES.LST`. A program hidden or deleted in the catalog leaves the store.

# The builder image

`git.teletypegames.org/build/dos-builder` (`builder.Dockerfile` in the tools repository): Open Watcom v2, DOSBox Staging (in `/opt/dosbox-staging`, off the `PATH`) and Debian's DOSBox (on the `PATH`, for the screen tests), Wine 32-bit, g++, Python with pyftpdlib, clang-format, zip, jq and curl, with the `dos-*` commands. The pinned versions are in `/opt/dos-ci/versions`. The same image runs a program's checks locally:

```sh
docker run --rm -v "$PWD:/workspace" git.teletypegames.org/build/dos-builder:latest \
  sh -c 'dos-check && dos-build && dos-test && TAG=v1.2.3 dos-pack'
```

'; var prevLevel = 2; for (var i = 0; i < headings.length; i++) { var h = headings\[i\]; var text = h.textContent.trim(); var slug = text.toLowerCase() .replace(/\[áàâä\]/g,'a').replace(/\[éèêë\]/g,'e').replace(/\[íìîï\]/g,'i') .replace(/\[óòôöő\]/g,'o').replace(/\[úùûüű\]/g,'u') .replace(/\[^a-z0-9\]+/g, '-').replace(/^-|-$/g, ''); if (!slug) slug = 'heading-' + i; if (used\[slug\]) { slug += '-' + i; } used\[slug\] = true; h.id = slug; var level = parseInt(h.tagName.charAt(1)); var cls = level > 2 ? ' class="toc-child"' : ''; html += '- [' + text + '](#'%20+%20slug%20+%20')
'; } html += '
'; toc.innerHTML = html; // Scroll-spy: highlight current heading var links = toc.querySelectorAll('a'); var ids = \[\]; for (var j = 0; j < links.length; j++) ids.push(links\[j\].getAttribute('href').slice(1)); function updateActive() { var current = ''; for (var k = 0; k < ids.length; k++) { var el = document.getElementById(ids\[k\]); if (el && el.getBoundingClientRect().top <= 80) current = ids\[k\]; } for (var m = 0; m < links.length; m++) { links\[m\].parentNode.classList.toggle('active', links\[m\].getAttribute('href') === '#' + current); } } window.addEventListener('scroll', updateActive, { passive: true }); updateActive(); })();

---

## Navigation

- Parent: [Platforms](https://wiki.teletypegames.org/platforms.md)
- Previous: [Commodore 64](https://wiki.teletypegames.org/platforms/c64.md)
- Next: [Ebitengine](https://wiki.teletypegames.org/platforms/ebitengine.md)
