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.
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.