Reading the File - richardjwild/arctracker GitHub Wiki

Having deleted get_arguments there now was only one function left in initialise.c so naturally my attention was drawn to it. It was called load_file and its job was to read the file contents into memory, which it did by repeatedly realloc-ing a memory buffer and fread-ing the file in. Some distant voice at the back of my memory called out to me, "mmap." This function can map a file directly into the memory space, which is ideal for my needs here and significantly less complicated (double win), so I rewrote the function to use it. I then moved the load_file function into read_mod.c and created a struct to hold the file size and its mapped address, which enabled me to delete initialise.c and its header file entirely.

Now I was focussed on the code that loaded the file, I decided I didn't like that there was a data structure for the module and another data structure for the samples, and that the two were separate. The samples data structure should be integral to the module data structure, so I integrated it in. There was now no need to separately pass the samples data structure around, so I removed the associated parameters, and then some more. The global complexity was coming down nicely.

I've mentioned before how I hated the way so many of the functions returned status codes, and practically the first thing I did was create an error module that avoided the need to pass them around. The read_file function was returning a status code too but I really wanted it to return a module_t struct instead. This was a bit too big a job to accomplish in one go though, so I began by refactoring the read_tracker_file function to return a struct, and removing all the error status code checks as I went. I followed this with a big cleanup that deleted a lot of lines. I then gave the same treatment to the read_desktop_tracker_file function which also deleted a lot of lines, which enabled me finally to rewrite the read_mod function so that it returned a struct as I desired. I then removed some unused things from main(), gave it a good polish and replaced tabs with spaces. Just for good measure, I made some pointer arguments const where possible to enforce immutability, bearing in mind the aphorism "when it is not necessary to change, it is necessary not to change."

Finally with all this done, my main function looked like this. Isn't it beautiful?

#include "arctracker.h"
#include "configuration.h"
#include "read_mod.h"
#include "play_mod.h"
#include "oss.h"
#include "alsa.h"

audio_api_t initialise_audio_api();

int main(int argc, char *argv[])
{
    read_configuration(argc, argv);
    module_t module = read_file();
    audio_api_t audio_api = initialise_audio_api();
    play_module(&module, audio_api);
    audio_api.finish();
    exit(EXIT_SUCCESS);
}

audio_api_t initialise_audio_api()
{
    switch (configuration().api)
    {
        case OSS:
            return initialise_oss();
        case ALSA:
            return initialise_alsa();
    }
}

I was not quite done yet though. It made more sense to pass the whole mapped_file_t struct to the read_tracker_file and read_desktop_tracker_file functions so I did that. There were some unused things in read_mod.c so I removed them and for good measure I removed all the #ifdef DEVELOPING blocks that were cluttering up the code terribly.

One last thing, I noticed that the command options in the readme file were wrong so I corrected them.

Previous: Arguments | Next: Use the Standard Libraries!