Skip to content

Latest commit

 

History

History
1044 lines (797 loc) · 44.8 KB

CONTRIBUTING.md

File metadata and controls

1044 lines (797 loc) · 44.8 KB

Contributing to the PiDP-8/I Project

If you wish to make any changes to the project’s files, here are some rules and hints to keep in mind while you work.

Getting Started with Fossil

The PiDP-8/I software project is hosted using the Fossil distributed version control system, which provides most of the features of GitHub without the complexities of Git.

I recommend one of three paths to learning Fossil:

  • Those coming from command line Git will benefit from the brief command-based approach taken by the Git to Fossil Translation Guide, since it builds on your existing knowledge.

  • The Fossil Quick Start takes you briefly through the primary topics. This is best for people with existing version control knowledge, particularly those who’ve used version control primarily via a GUI or web app of some sort. This path is also good for those coming from some other command-line version control system.

    Note in particular the Fossil Glossary linked from the quick start doc: it outlines the key concepts you must internalize to understand how Fossil works at the user level.

  • If you prefer a linear tutorial approach or have little to no experience with modern version control systems, the 3rd edition of “Fossil Version Control: A User Guide” is worth reading. It’s novella length, so you should be able to get through it in a single read between mealtimes, if you don’t stop to experiment.

I do not recommend starting with the Fossil doc index and seeking topics out from there; not to begin with, anyway. That path is best once you have some Fossil experience and know what you’re looking for.

If you have questions about Fossil, ask on the Fossil forum where I, your humble project maintainer, am active. I also work on the Fossil docs quite a bit, so if your question really isn’t answered somewhere in the above material, I might just solve it by extending the Fossil docs.

Fossil 2.x is pre-installed on our binary OS images since April 2017, and it is included in Raspberry Pi OS (né Raspbian) since June 2019:

$ sudo apt install fossil

Fossil is available in many binary package repositories, and there are official precompiled binaries for several popular platforms. The project repository requires at least Fossil version 2.1, so if you’re stuck with a Fossil 1.x binary, you will have to build Fossil from source.

Fossil Anonymous Access

There are three ways to clone the repository anonymously using Fossil. Each of these methods gets you a file called pidp8i.fossil containing the full history of the PiDP-8/I software project from the upstream 2015.12.15 release onward.

You only need to take one of these options, once per machine. Thereafter, you will just be working with the cloned repository.

One-Step Clone-and-Open

The easiest way requires Fossil 2.14 or higher:

$ fossil clone https://tangentsoft.com/pidp8i
$ cd pidp8i

That gets you a clone of the pidp8i.fossil repository plus a check-out of the current trunk in a pidp8i/ directory alongside it. We recommend that you do this in a directory like ~/src so you don’t commingle these files with other things in your current working directory.

Open from URI

If you have Fossil 2.12 or 2.13, the next-easiest method is:

$ mkdir -p ~/src/pidp8i
$ cd ~/src/pidp8i
$ fossil open https://tangentsoft.com/pidp8i

This clones the repository referenced by that URI into the current directory as pidp8i.fossil, then opens that repo into that same subdirectory.

You have to create the destination directory first with this method because Fossil will refuse to spam a non-empty directory with the check-out contents when opening the repo into a directory containing other files unless you give it the --force flag.

Notice that the repo file ends up inside the check-out tree with this method. This is because of a purposeful semantic difference in Fossil between “open” and “clone.” It may seem strange to someone coming from Git, but while we don’t want to get into the whys and wherefores here, realize there is logic behind this choice.

Separate Clone and Open

The complicated method works with all versions of Fossil back to 2.1, and it is the one we recommend to people who want to get involved with the project, because it has numerous advantages over the easy methods. We’ll explain those benefits in the context of the PiDP-8/I project later, but for now, the method is:

$ mkdir -p ~/museum ~/src/pidp8i/trunk
$ fossil clone https://tangentsoft.com/pidp8i ~/museum/pidp8i.fossil
$ cd ~/src/pidp8i/trunk
$ fossil open ~/museum/pidp8i.fossil

Fossil Developer Access

If you have a developer account on the tangentsoft.com/pidp8i Fossil instance, just add your username to the URL like so:

$ fossil clone https://[email protected]/pidp8i pidp8i.fossil

If you’ve already cloned anonymously, simply tell Fossil about the new sync URL instead:

$ cd ~/src/pidp8i/trunk
$ fossil sync https://[email protected]/pidp8i

Either way, Fossil will ask you for the password for USERNAME on the remote Fossil instance, and it will offer to remember it for you. If you let it remember the password, operation from then on is scarcely different from working with an anonymous clone, except that on checkin, your changes will be sync’d back to the repository on tangentsoft.com if you’re online at the time, and you’ll get credit under your developer account name for the checkin.

If you’re working offline, Fossil will still do the checkin locally, and it will sync up with the central repository after you get back online. It is best to work on a branch when unable to use Fossil’s autosync feature, as you are less likely to have a sync conflict when attempting to send a new branch to the central server than in attempting to merge your changes to the tip of trunk into the current upstream trunk, which may well have changed since you went offline.

You can purposely work offline by disabling autosync mode:

$ fossil set autosync 0

Until you re-enable it (autosync 1) Fossil will stop trying to sync your local changes back to the central repo. In this mode, Fossil works more like Git’s default mode, buying you many of the same problems that go along with that working style. I recommend disabling autosync mode only when you are truly going to be offline and don’t want Fossil attempting to sync when you know it will fail.

Getting Developer Access

We’re pretty open about giving developer access to someone who’s provided at least one good, substantial patch to the software. If we’ve accepted one of your patches, just ask for a developer account on the forum.

Working with Existing Tags and Branches

The directory structure shown in the separate clone and open sequence above is more complicated than strictly necessary, but it has a number of nice properties.

First, it collects software projects under a common top-level directory. I’ve used ~/src for this example, but you are free to use any scheme you like.

Second, the level underneath the project directory (~/src/pidp8i) stores multiple separate checkouts, one for each version the developer is actively working with at the moment, so to add a few other checkouts, you could say:

$ cd ~/src/pidp8i
$ mkdir -p release          # another branch
$ mkdir -p v20151215        # a tag this time, not a branch
$ mkdir -p 2019-04-01       # the software as of a particular date
  ...etc...
$ cd release
$ fossil open ~/museum/pidp8i.fossil release
$ cd ../v20151215
$ fossil open ~/museum/pidp8i.fossil v20151215
$ cd ../2019-04-01
$ fossil open ~/museum/pidp8i.fossil 2019-04-01
  ...etc...

This gives you multiple independent checkouts, which allows you to quickly switch between versions with “cd” commands. The alternative (favored by Git and some other version control systems) is to use a single working directory and switch among versions by updating that single working directory in place. The problem is that this invalidates all of the build artifacts tied to changed files, so you have a longer rebuild time than simply switching among check-out directories. Since disk space is cheap these days — even on a small Raspberry Pi SD card – it’s better to have multiple working states and just “cd” among them.

When you say fossil update in a check-out directory, you get the “tip” state of that version’s branch. This means that if you created your “release” check-out while version 2017.01.23 was current and you say “fossil update” today, you’ll get the release version 2019.04.25 or later. But, since the v20151215 tag was made on trunk, saying “fossil update” in that check-out directory will fast-forward you to the tip of trunk; you won’t remain pinned to that old version. This is one of the essential differences between tags and branches in Fossil, which are at bottom otherwise nearly identical.

The PiDP-8/I project uses tags for each released version, and it has many working branches. You can use any of those names in “fossil open” and “fossil update” commands, and you can also use any of Fossil’s special check-in names.

Creating Branches

Creating a branch in Fossil is scary-simple, to the point that those coming from other version control systems may ask, “Is that really all there is to it?” Yes, really, this is it:

$ fossil ci --branch new-branch-name

That is to say, you make your changes as you normally would; then when you go to check them in, you give the --branch option to the ci/checkin command to put the changes on a new branch, rather than add them to the same branch the changes were made against.

While developers with login rights to the PiDP-8/I Fossil instance are allowed to check in on the trunk at any time, we recommend using branches whenever you’re working on something experimental, or where you can’t make the necessary changes in a single coherent checkin.

One of this project’s core principles is that trunk should always build without error, and it should always function correctly. That’s an ideal we have not always achieved, but we do always try to achieve it.

Contrast branches, which PiDP-8/I developers may use to isolate work until it is ready to merge into the trunk. It is okay to check work in on a branch that doesn’t work, or doesn’t even build, so long as the goal is to get it to a point that it does build and work properly before merging it into trunk.

Here again we have a difference with Git: because Fossil normally syncs your work back to the central repository, this means we get to see the branches you are still working on. This is a good thing. Do not fear committing broken or otherwise bad code to a branch. You are not your code. We are software developers, too: we understand that software development is an iterative process, that not all ideas spring forth perfect and production-ready from the fingers of its developers. These public branches let your collaborators see what you’re up to; they may be able to lend advice, to help with the work, or to at least be unsurprised when your change finally lands in trunk.

Fossil fosters close cooperation, whereas Git fosters wild tangents that never come back home.

Jim McCarthy (author of Dynamics of Software Development) has a presentation on YouTube that touches on this topic at a couple of points:

Fossil’s sync-by-default behavior fights these negative tendencies.

PiDP-8/I project developers are welcome to create branches at will. The main rule is to follow the branch naming scheme: all lowercase with hyphens separating words. See the available branch list for examples to emulate.

If you have checkin rights on the repository, it is generally fine to check things in on someone else’s feature branch, as long as you do so in a way that cooperates with the purpose of that branch. The same is true of trunk: you should not check something in directly on the trunk that changes the nature of the software in a major way without discussing the idea first. This is yet another use for branches: to make a possibly-controversial change so that it can be discussed before being merged into the trunk.

Special Branches

Most of the branches in the PiDP-8/I project are feature branches of the sort described in the previous section: an isolated line of development by one or more of the project’s developers to work towards some new feature, with the goal of merging that feature into the trunk branch.

There are a few branches in the project that are special, which are subject to different rules than other branches:

  • release — One of the steps in the release process is to merge the stabilized trunk into the release branch, from which the release tarballs and binary OS images are created. Only the project’s release manager — currently Warren Young — should make changes to this branch.

  • bogus or BOGUS — Because a branch is basically just a label for a specific checkin, Fossil allows the tip of one branch to be “moved” to another branch by applying a branch label to that checkin. We use this label when someone makes a checkin on the tip of a branch that should be “forgotten.” Fossil makes destroying project history very difficult, on purpose, so things moved to the “bogus” branch are not actually destroyed; instead, they are merely moved out of the way so that they do not interfere with that branch’s normal purpose.

    If you find yourself needing to prune the tip of a branch this way, the simplest way is to do it via the web UI, using the checkin description page’s “edit” link. You can instead do it from the command line with the fossil amend command.

Developer Discussion Forum

The “Forum” link at the top of the Fossil web interface is for discussing the development of the PiDP-8/I software only. All other traffic should go to the end-user focused mailing list instead. We’re not trying to split the community by providing a second discussion forum; we just think many development-related discussions are too low-level to be of any interest to most of the people on the mailing list.

You can sign up for the forums without having a developer login, and you can even post anonymously. If you have a login, you can sign up for email alerts if you like.

Keep in mind that posts to the Fossil forum are treated much the same way as ticket submissions and wiki articles. They are permanently archived with the project. The “edit” feature of Fossil forums just creates a replacement record for a post, but the old post is still available in the repository. Don’t post anything you wouldn’t want made part of the permanent record of the project!

Debug Builds

By default, the build system creates a release build, but you can force it to produce a binary without as much optimization and with debug symbols included:

$ ./configure --debug-mode
$ make clean
$ tools/mmake

Manipulating the Build System Source Files

The autosetup build system is composed of these files and directories:

auto.def
autosetup/*
configure
Makefile.in

Unlike with GNU Autoconf, which you may be familiar with, the configure script is not output from some other tool. It is just a driver for the generic Tcl and C code under the autosetup directory, which in turn runs the project-specific auto.def Tcl script to configure the software. Some knowledge of Tcl syntax will therefore be helpful in modifying auto.def.

If you have to modify any of the files in autosetup/ to get some needed effect, you should try to get that change into the upstream Autosetup project, then merge that change down into the local copy when it lands upstream.

If you do not have Tcl installed on your system, configure builds a minimal Tcl interpreter called jimsh0, based on the Jim Tcl project. Developers working on the build system are encouraged to use this stripped-down version of Tcl rather than “real” Tcl because Jim Tcl is a mostly-pure subset of Tcl, and jimsh0 is a subset of the complete Jim Tcl distribution, so any changes you make that work with the jimsh0 interpreter should also work with “real” Tcl, but not vice versa. If you have Tcl installed and don’t really need it, consider uninstalling it to force Autosetup to build and use jimsh0 to ensure that your changes to auto.def work on both interpreters.

The Makefile.in file is largely a standard GNU make file excepting only that it has variables substituted into it by Autosetup using its @VARIABLE@ syntax. At this time, we do not attempt to achieve compatibility with other make programs, though in the future we may need it to work with BSD make as well, so if you are adding features, you might want to stick to the common subset of features implemented by both the GNU and BSD flavors of make. We do not anticipate any need to support any other make flavors.

This, by the way, is why we’re not using some heavy-weight build system such as the GNU Autotools, CMake, etc.

The primary advantage of GNU Autotools is that you can generate standalone source packages that will configure and build on weird and ancient flavors of Unix. We don’t need that.

Cross-platform build systems such as CMake ease building the same software on multiple disparate platforms, but the PiDP-8/I software is built primarily on and for a single operating system, Raspberry Pi OS, né Raspbian. It also happens to build and run on several other OSes, for which we also do not need the full power of something like CMake. Autosetup and GNU make suffice for our purposes here.

Directory Structure

The directory structure of the PiDP-8/I project is as follows:

  • . — Top level, occupied only by the few files the end user of the source code needs immediately at hand on first unpacking the project: the top level build system files, key documentation, and licensing information. If a given file can be buried deeper, it should be buried to reduce clutter at this most precious level of the hierarchy.

  • .fossil-settings — Versioned settings for the Fossil build system which Fossil applies as defaults everywhere you check out a Fossil version. Settings made here are intended to be correct for all users of the system; think of these not as expressing defaults but as expressing policy. It is possible to override these settings, but we do not make settings here if we expect that some users may quibble with our choices here.

    Any setting whose value may vary between users of the Fossil repository should be done locally with a fossil setting command rather than by creating or editing files in this subdirectory.

    See the Fossil settings documentation for more on this.

  • autosetup — The bulk of the Autosetup build system. These are generic files, not modified by the project itself. We occasionally run tools/autosetup-update to merge in upstream changes.

  • bin — Programs installed to $prefix/bin, which may also be run during development, if only to test changes to those programs. Some scripts stored here are written in place by the project’s developers, while other files in this directory are outputs of the build system.

    A subset of this directory’s content is copied to $prefix/bin at installation time, which is added to the user’s PATH by the make install script. We don’t copy the whole thing as-is because the build system places some files here that get installed to other locations or which don’t get installed at all.

  • boot — SIMH initialization scripts. The *.script.in files are written by the project developers but have local configuration values substituted in by the configure script to produce a *.script version. Scripts which need no config-time values substituted in are checked in directly as *.script. The *.script files in this directory which do not fall into either of those categories are outputs of tools/mkbootscript, which produces them from palbart assembly listings.

    All of these *.script files are copied to $prefix/share/boot by make mediainstall which runs automatically from make install when we detect that the binary media and SIMH boot scripts have never been installed at this site before. On subsequent installs, the user chooses whether to run make mediainstall by hand to overwrite all of this.

  • doc — Documentation files that can wait for new users to discover them, which do not need to be available immediately to the user on inspecting the tree for the first time.

    Fossil’s embedded documentation feature allows us to present the contents of doc to web site users all but indistinguishably from a wiki page.

    You may then ask, “Why are there two different ways to achieve the same end — embedded docs and the wiki — and how do we decide which mechanism to use?” Let us explore the differences before we answer the question.

    Fossil’s wiki feature behaves much like Wikipedia: it keeps change history for wiki documents, but it always presents the most recent version unless you go out of your way to manually dig up a historical version. This is true even if you’ve run fossil ui from a check-out directory where you’ve rolled back to a historical version. This doesn’t roll back the wiki to the same point in time; it continues showing the most recent version of each article.

    Embedded documentation — being files like any other committed to the repository — are rolled back to historical versions when you say something like fossil update 2018-04-01 to see the software as of April Fool’s Day 2018. You see the embedded docs as of that date as well, unlike with the wiki.

    That leads us to the razor we use to decide where a given document lives.

    Use the wiki for evergreen content: material likely to remain correct for future versions of the software as well as the version contemporaneous with the initial version of the document. Also use the wiki for documention of conditions that change independently of the software’s version history, a good example being our OS Compatibility wiki article. In either case, there is no tie between the software’s internal version history and changes out in the wider world, so the wiki’s always-current nature matches our needs well.

    The best case for using embedded documentation is when changes to the software are likely to require changes to the corresponding documentation, so that the commit changes both docs and code, keeping them in lock-step.

    When in doubt, use embedded documentation.

    The doc/graphics subdirectory holds JPEGs and SVGs displayed inline within wiki articles.

  • etc — Files which get copied to /etc or one of its subdirectories at installation time.

    There is an exception: pidp8i.service.in does not get installed to /etc at install time, but only because systemd’s unit file load path scheme is screwy: some unit files go in /etc, while others do not. The systemd docs claim we can put user units in /etc/systemd/user but this does not appear to work on a Raspberry Pi running Raspbian Stretch at least. We’ve fallen back to another directory that does work, which feels more right to us anyway, but which happens not to be in /etc. If systemd were designed sanely, we’d install such files to $HOME/etc/systemd but noooo…

    Since none of the above actually argues for creating another top-level repository directory to hold this one file, we’ve chosen to store it in etc.

  • examples — Example programs for the end user’s edification. Many of these are referenced by documentation files and therefore should not be renamed or moved, since there may be public web links referring to these examples.

  • hardware — Schematics and such for the PiDP-8/I board or associated hardware.

  • labels — Graphics intended to be printed out and used as labels for removable media.

  • lib — Library routines used by other programs, installed to $prefix/lib.

  • libexec — A logical extension of lib, these are standalone programs that nevertheless are intended to be run primarily by other programs. Whereas a file in lib might have its interface described by a programmer’s reference manual, the interface of a program in libexec is described by its usage message.

    Currently, there is only one such program, scanswitch, which si run primarily by etc/pidp8i. It is only run by hand when someone is trying to debug something, as in development.

    Programs in libexec are installed to $prefix/libexec, which is not put into the user’s PATH, on purpose. If a program should end up in the user’s PATH, it belongs in bin. Alternately, a wrapper may be put in bin which calls a libexec program as a helper.

  • media — Binary media images used either by SIMH directly or inputs consumed by tools like os8-run to produce media used by SIMH.

    The contents of this tree are installed to $prefix/share/media.

  • obj — Intermediate output directory used by the build system. It is safe to remove this directory at any time, as its contents may be recreated by make. No file checked into Fossil should be placed here.

    (Contrast bin which does have some files checked into Fossil; all of the other files that end up in bin can be recreated by make, but not these few hand-written programs.)

  • scripts — Scripts driving os8-run, most of which are invoked by the build system, though some are meant to be run by hand, such as the content of scripts/test.

  • src — Source code for the project’s programs, especially those that cannot be used until they are built. The great majority of these programs are written in C. The build system’s output directories are bin, boot, libexec, and obj.

    Programs that can be used without being “built,” example programs, and single-file scripts are placed elsewhere: bin, examples, libexec, tools, etc. Basically, we place such files where the build system would place them if they were built from something under src.

    This directory also contains PDP-8 source files of various sorts, mainly those used for building the SIMH media and the os8pkg packages. These are all “built” into other forms that then appear when running the simulator, rather than being used directly in this source code form.

    There are no program sources in the top level of src. The file src/config.h may appear to be an exception to that restriction, but it is generated output of the configure script, not “source code” per se.

    Multi-module programs each have their own subdirectory of src, each named after the program contained within.

    Single module programs live in src/misc or src/asm, depending on whether they are host-side C programs or PAL8 assembly programs.

  • test — Output directory used by tools/test-*.

  • tools — Programs run only during development and not installed.

    If a program is initially created here but we later decide that it should be installed for use by end users of the PiDP-8/I system, we move it to either bin or libexec, depending on whether it is run directly at the command line or run from some other program that is also installed, respectively.

Submitting Patches

If you do not have a developer login on the project repository, you can still send changes to the project.

The simplest way is to say this after developing your change against trunk:

$ fossil diff > my-changes.patch

Then paste that into a forum post using a fenced code block. We will also accept trivial patches not needing discussion as text or attachments on a Fossil ticket.

If you're making a patch against a PiDP-8/I distribution tarball, you can generate a patch this way:

$ diff -ruN pidp8i-olddir pidp8i-newdir > mychange.patch

The diff command is part of every Unix and Linux system, and should be installed by default. If you're on a Windows machine, GNU diff is part of Cygwin and WSL. Fossil is also available for all of these systems. There are no excuses for not being able to make unified diffs. :)

Bundles Instead of Patches

If your change is more than a small patch, fossil diff might not incorporate all of the changes you have made. The old unified diff format can’t encode branch names, file renamings, file deletions, tags, checkin comments, and other Fossil-specific information. For such changes, it is better to send a Fossil bundle:

$ fossil set autosync 0                # disable autosync
$ fossil checkin --branch my-changes
  ...followed by more checkins on that branch...
$ fossil bundle export --branch my-changes my-changes.bundle

After that first fossil checkin --branch ... command, any subsequent fossil ci commands will check your changes in on that branch without needing a --branch option until you explicitly switch that checkout directory to some other branch. This lets you build up a larger change on a private branch until you’re ready to submit the whole thing as a bundle.

Because you are working on a branch on your private copy of the project’s Fossil repository, you are free to make as many checkins as you like on the new branch before giving the bundle export command.

Once you are done with the bundle, upload it somewhere public and point to it from a forum post or ticket.

Contribution Licensing

Submissions should include a declaration of the license you wish to contribute your changes under. We suggest using the SIMH license, but any non-viral OSI-approved license should suffice. We’re willing to tolerate viral licenses for standalone products; for example, CC8 is under the GPL, but it’s fine because it isn’t statically linked into any other part of the PiDP-8/I software system.

Can I Use GitHub Instead?

Although the PiDP-8/I project does have a GitHub mirror, it is intended as a read-only mirror for those heavily tied into Git-based tooling. You’re welcome to send us a PR anyway, but realize that what’s going to happen on the back end is that we’ll generate a patch, apply it to the Fossil repo by hand, test it, and then commit it to the repository under one of our existing Fossil developer accounts. Only then do we update the mirror so that the change appears on GitHub; thus, you don’t get GitHub credit for the PR. You avoid these problems by simply asking for a developer account on the Fossil repo, so you can commit there instead.

This is not simply because setting up bidirectional mirroring is difficult, it is actually impossible to achieve 100% fidelity due to limitations of Git and/or GitHub. If you want a faithful clone of the project repo, or if you wish to contribute to the project’s development with full credit for your contributions, it’s best done via Fossil, not via GitHub.

The PiDP-8/I Software Project Code Style Rules

Every code base should have a common code style. Love it or hate it, here are PiDP-8/I’s current code style rules:

C Source Code

File types: *.c, *.h, *.c.in

We follow the SIMH project’s pre-existing code style when modifying one of its source files:

  • Spaces for indents, size 4; tabs are rendered size 8 in HTML output, since that’s how a PDP-8 terminal would likely interpret it!

  • DOS line endings. (Yes, even though this is a Linux-based project! All decent Linux text editors can cope with this.)

  • Function, structure, type, and variable names are all lowercase, with underscores separating words

  • Macro names are in ALL_UPPERCASE_WITH_UNDERSCORES

  • Whitespace in the SIMH C files is of a style I have never seen anywhere else in my decades of software development. This example shows the important features:

    int some_function (char some_parameter)
    {
    int some_variable = 0;
    
    if (some_parameter != '\0') {
        int nbytes = sizeof (some_parameter);
        char *buffer = malloc (4 * nbytes);
    
        switch (some_parameter) {
            case 'a':
                do_something_with_buffer ((char *)buffer); 
            default:
                do_something_else ();
            }
        }
    else {
        some_other_function (with_a_large, "number of parameters",
            wraps_with_a_single, "indent level");
        printf (stderr, "Failed to allocate buffer.\n");
        }
    }

    It is vaguely like K&R C style except that:

    • The top level of statements in a function are not indented

    • The closing curly brace is indented to the same level as the statement(s) it contains

    • There is a space before all opening parentheses, not just those used in if, while, and similar flow control statements.

      Nested open parentheses do not have extra spaces, however. Only the outer opening parenthesis has a space separating it from what went before.

    • Multiple variables declared together don’t have their types and variable names aligned in columns.

    I find that this style is mostly sensible, but with two serious problems: I find the indented closing curly braces confusing, and I find that the loss of the first indent level for the statements inside a function makes functions all visually run together in a screenful of code. Therefore, when we have the luxury to be working on a file separate from SIMH, we use a variant of its style with these two changes, which you can produce with the tools/restyle command. See its internal comments for details.

    That gives the following, when applied to the above example:

    int some_function (char some_parameter)
    {
        int some_variable = 0;
    
        if (some_parameter != '\0') {
            int nbytes = sizeof (some_parameter);
            char *buffer = malloc (4 * nbytes);
    
            switch (some_parameter) {
                case 'a':
                    do_something_with_buffer ((char *)buffer); 
                default:
                    do_something_else ();
            }
        }
        else {
            some_other_function (with_a_large, "number of parameters",
                wraps_with_a_single, "indent level");
            printf (stderr, "Failed to allocate buffer.\n");
        }
    }

    If that looks greatly different, realize that it is just two indenting level differences: add one indent at function level, except for the closing braces, which we leave at their previous position.

    SIMH occasionally exceeds 100-column lines. I recommend breaking long lines at 72 columns. Call me an 80-column traditionalist.

    When in doubt, mimic what you see in the current code. When still in doubt, ask on the project forum.

Plain Text Files

File types: *.md, *.txt

  • Spaces for indents, size 4.

  • Unix line endings. The only common text editor I’m aware of that has a problem with this is Notepad, and people looking at these files anywhere other than unpacked on a Raspberry Pi box are probably looking at them through the Fossil web interface on tangentsoft.com.

  • Markdown files must follow the syntax flavor understood by Fossil’s Markdown interpreter.

Ticket Workflow

Normal end users of the Fossil ticket system are not expected to understand it properly or to fill out tickets properly. Without certain permissions, it is in fact not possible to completely fill out a ticket properly. Project developers typically must triage, augment, and correct submissions from the start.

Here’s the basic workflow for a “code defect” ticket, colloquially called a bug report:

      fill = bisque
      linerad = 15px

      oval "SUBMIT TICKET" width 150%
      down
      arrow 50%
NEW:  file "New bug ticket" "marked \"Open\"" fit
      arrow same
      box "Triage," "augment &" "correct" fit
      arrow same
DC:   box "Developer comments" fit
      arrow same
FR:   box "Filer responds" fit
      arrow 100%
REJ:  diamond "Reject?"
      right
      arrow 100% "Yes" above
      box "Mark ticket" "\"Rejected\" &" "\"Resolved\"" fit with .w at previous.e
      arrow right 50%
REJF: file "Rejected" "ticket" fit
      arrow right 50%
REOP: diamond "Reopen?"
      down
REJA: arrow 75% from REJ.s "  No; fix it" ljust
CHNG: box "Developer changes code" with .n at last arrow.s fit
      arrow 50%
FIXD: diamond "Fixed?"
      right
FNO:  arrow "No" above
RES:  box "Optional:" "Update ticket resolution:" "\"Partial Fix\", etc." fit
      down
      arrow 75% "  Yes" ljust from FIXD.s
      box "Mark ticket" "\"Fixed\" & \"Closed\"" fit
      arrow 50%
RESF: file "Resolved ticket" fit
      arrow same
      oval "END"

      line from 0.3<FR.ne,FR.se> right even with 0.25 right of DC.e then \
          up even with DC.e then to DC.e ->

      line from NEW.w left 0.5 then down even with REJ.w then to REJ.w ->
      line invis from 2nd vertex of last line to 3rd vertex of last line \
          "fast reject path" above aligned

      line from RES.e right 0.3 then up even with CHNG.e then to CHNG.e ->

      line from REOP.s "No" aligned above down 0.4
      line from previous.s down to (previous.s, RESF.e) then to RESF.e ->

      line from REOP.n "Yes" aligned below up 0.3
      line from previous.n up even with 0.6<FR.ne,FR.se> then to 0.6<FR.ne,FR.se> ->

On noticing a new-filed ticket — such as because you are subscribed to email notifications on ticket changes — someone with sufficient privilege triages it, sets values for the fields not exposed to the ticket’s filer, and fixes up any incorrect values given in the initial submission.

The Status of a ticket initially starts out as Open; the filer cannot change that default value, short-circuiting the process. If the person triaging a ticket takes the time to check that the bug actually occurs as the ticket filer claims, the Status should change to Verified.

If a developer implements a fix in response to a ticket, he has two choices: change the ticket’s Status to “Review” if he wants someone to check out the change before closing it, or go straight to Closed status. Closing a ticket hides it from the Wishes and Bugs ticket reports.

The process for software feature request and documentation improvement request tickets is essentially the same, differing mainly in terminology rather than process flow: instead of verifying the existence of a bug, the one triaging the ticket verifies that the feature does in fact not exist yet, and so on.

A common requrement in larger teams is that all ticket changes to go through Review status before getting to Closed, but the PiDP-8/I project is too small to require such ceremony: if we’ve given you a developer account on the repository, you’re expected to resolve and close tickets in the same step, most of the time. If you cannot confidently close a ticket when resolving it, you should probably not be assigning a resolution yet anyway. Do whatever you have to with tests and such to become certain before you resolve a ticket.

There is a process interlock between the Resolution and Status settings for a ticket: while Status is not Closed, Resolution should be Open. When Resolution changes from Open, Status should change to either Review or, preferentially, Closed. A resolution is an end state, not an expression of changeable intent: no more ceremony than setting a ticket’s Resolution state away from Open and its Status to Closed is required.

If you do not intend to close a ticket but wish to advocate for a particular resolution, just add a comment to the ticket and let someone else choose whether to close the ticket or not. Don’t change the Resolution value until the issue has been resolved for good.

For example, the resolution “Works as Designed” does not merely mean, “Yes, we know it works that way,” it also implies “…and we have no intention to change that behavior, ever.” If there is a chance that the behavior described in the ticket could change, you should not assign any resolution. Just leave it open until someone decides to do something final with the ticket.

This is not to say that a ticket can never be re-opened once it’s had a resolution assigned and been closed, but that this is a rare occurrence. When a developer makes a decision about a ticket, it should be difficult to re-open the issue. A rejected ticket probably shouldn’t be re-opened with anything short of a working patch, for example:

User A: I want feature X.

Dev B: No, we’re not going to do that. Ticket closed and rejected.

User C: Here’s a patch to implement feature X.

Dev B: Well, that’s different, then. Thanks for the patch! Ticket marked Implemented, but still Closed.

License

Copyright © 2016-2020 by Warren Young. This document is licensed under the terms of the SIMH license.