Why Man Pages are a Bad Idea

(And don't get me started on the GNU texinfo shite!)

Let me delve into a little bit of history first. I started out using QNX 2 — it had this concept that if someone put "-?" (or something — this is going back to decades ago) on the command line, the executable would be invoked with argc set to zero, and you could tell that this was a user request for help.

The program would spit out a "gentle reminder" usage message.

Then I moved to QNX 4 and QNX 6, and they expanded this "use message" concept a bit further. It was now a section in the executable of the image, and you could embed that into the exe from a C program (via clever #ifdef, IIRC), or it could be a separate file, and a "usemsg" tool would embed it into the exe for you.

Then I moved to FreeBSD, and found man pages.

I adapted my usage messages to funky nroff format, and it was okay for a while. I had to learn two things — the funky nroff format, and the Makefile magic to build and install man pages. Not the end of the world.

Then I moved to Ubuntu. The move to Ubuntu was planned, but still quick. Instead of trying to figure out the man pages on Ubuntu, I went back to simply embedding the usage messages in the program.

And you know what? I liked it!

Here's why:

So, from now on, I'm back to the "standard C" implementation of usage messages. They can still be long and descriptive, but I've just given up on man pages as such.

(I also found that I just wasn't updating them anyway, too hard).

Here's an example:

static char usage_message [] =
{
    "it [options] arguments\n"
    "\n"
    "where [options] are optional parameters chosen from:\n"
    "    -c c,v         set control \"c\" to value \"v\"\n"
    "    -t traces      enable traces, which are given as one or more digits 0..9\n"
    "    -v             verbose operation\n"
    "\n"
    "This utility is responsible for testing the instrumentation control system\n"
    "by allowing you to give it a control value (via -c) and enable the internal\n"
    "instrumentation traces (via -t)\n"
};

int
main (int argc, char **argv)
{
    if (options_init (argc, argv, "c:t:v") != OPTIONS_OK) {
        write (2, usage_message, sizeof (usage_message));
        exit (EXIT_FAILURE);
    }
    options_count ("v", &optv);
    options_callout ("ct", optc_callout, optt_callout);
...