Plain text rendering

The next modification is to make the resource manager return an ASCII string instead of a GIF-encoded image. You could almost argue that this should have been "Phase 0," but that's not the way that the development path ended up going.

It would be simple to create a rendering module that copied the ASCII string sent to the "raw bitmap" array, and skip the GIF encoding. The code changes would be minimal, but there would be a lot of wasted space. The raw bitmap array is at least hundreds of bytes, and varies in size according to the X and Y sizes given on the command line. The ASCII string is at most 11 bytes (we impose an arbitrary limit of 10 digits maximum, and you need one more byte for the NUL terminator for the string). Additionally, having the resource manager register a name in the pathname space that ends in .gif, and then having text come out of the GIF-encoded "file" is a little odd.

Therefore, the approach taken was to create a second pathname that strips the extension and adds a different extension of ".txt" for the text version. We now have two attributes structures: one for the original GIF-encoded version and another for the text version.

Note: This is a fairly common extension to resource managers in the field. Someone decides they need data to come out of the resource manager in a different format, so instead of overloading the meaning of the registered pathname, they add a second one.

The first change is to create the two attributes structures in execute_resmgr(). So, instead of:

static void
execute_resmgr (void)
{
    resmgr_attr_t           resmgr_attr;
    resmgr_connect_funcs_t  connect_func;
    resmgr_io_funcs_t       io_func;
    my_attr_t               attr;
    dispatch_t              *dpp;
    resmgr_context_t        *ctp;
    ...

we now have:

// one for GIF, one for text
static  my_attr_t   attr_gif;
static  my_attr_t   attr_txt;

static void
execute_resmgr (void)
{
    resmgr_attr_t           resmgr_attr;
    resmgr_connect_funcs_t  connect_func;
    resmgr_io_funcs_t       io_func;
    dispatch_t              *dpp;
    resmgr_context_t        *ctp;
    ...

Notice how we moved the two attributes structures out of the execute_resmgr() function and into the global space. You'll see why we did this shortly. Ordinarily, I'd be wary of moving something into global space. In this case, it's purely a scope issue—the attributes structure is a per-device structure, so it doesn't really matter where we store it.

Next, we need to register the two pathnames instead of just the one. There are some code modifications that we aren't going to discuss in this book, such as initializing both attributes structures instead of just the one, and so on. Instead of:

// establish a name in the pathname space
if (resmgr_attach (dpp, &resmgr_attr, optn, _FTYPE_ANY, 0, 
                 &connect_func, &io_func, &attr) == -1) {
    perror ("Unable to resmgr_attach()\n");
    exit (EXIT_FAILURE);
}

we now have:

// establish a name in the pathname space for the .GIF file:
if (resmgr_attach (dpp, &resmgr_attr, optn, _FTYPE_ANY, 0, 
                   &connect_func, &io_func, &attr_gif) == -1) {
    perror ("Unable to resmgr_attach() for GIF device\n");
    exit (EXIT_FAILURE);
}

// establish a name in the pathname space for the text file:
convert_gif_to_txt_filename (optn, txtname);
if (resmgr_attach (dpp, &resmgr_attr, txtname, _FTYPE_ANY, 0, 
                   &connect_func, &io_func, &attr_txt) == -1) {
    perror ("Unable to resmgr_attach() for text device\n");
    exit (EXIT_FAILURE);
}

The convert_gif_to_txt_filename() function does the magic of stripping out the extension and replacing it with ".txt." It also handles other extensions by adding ".txt" to the filename.

At this point, we have registered two pathnames in the pathname space. If you didn't specify a name via -n, then the default registered names would be:

/dev/webcounter.gif
/dev/webcounter.txt

Notice how we don't change the count based on reading the text resource. This was a conscious decision on my part—I wanted to be able to read the "current" value from the command line without affecting the count:

cat /dev/webcounter.txt

The rationale is that we didn't actually read the web page; it was an administrative read of the counter, so the count should not be incremented. There's a slight hack here, in that I reach into the GIF's attributes structure to grab the count. This is acceptable, because the binding between the two resources (the GIF-encoded resource and the text resource) is done at a high level.