Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
blog:x68_launcher_2 [2020/08/22 19:42] – [data.c / data.h] john | blog:x68_launcher_2 [2020/08/23 19:20] (current) – [Control Flow (a simple main.c)] john | ||
---|---|---|---|
Line 45: | Line 45: | ||
---- | ---- | ||
- | === int dirFromPath(char *path, char *buffer) === | + | === dirFromPath() === |
**Input** | **Input** | ||
Line 53: | Line 53: | ||
**Output** | **Output** | ||
+ | |||
+ | * int | ||
Returns __0__ on success, __-1__ on error. | Returns __0__ on success, __-1__ on error. | ||
Line 76: | Line 78: | ||
---- | ---- | ||
- | === int dirHasData(char *path) === | + | === dirHasData() === |
**Input** | **Input** | ||
Line 83: | Line 85: | ||
**Output** | **Output** | ||
+ | |||
+ | * int | ||
Returns __1__ if a file containing metadata for the launcher application is found within a given directory. Otherwise returns __0__. | Returns __1__ if a file containing metadata for the launcher application is found within a given directory. Otherwise returns __0__. | ||
Line 103: | Line 107: | ||
---- | ---- | ||
- | === int drvLetterToNum(char drive_letter) === | + | === drvLetterToNum() === |
**Inputs** | **Inputs** | ||
Line 110: | Line 114: | ||
**Output** | **Output** | ||
+ | |||
+ | * int | ||
Returns an integer representing the drive letter. 0 == A, 1 == B, etc. | Returns an integer representing the drive letter. 0 == A, 1 == B, etc. | ||
Line 131: | Line 137: | ||
---- | ---- | ||
- | === char drvNumToLetter(int drive_number) === | + | === drvNumToLetter() === |
**Input** | **Input** | ||
Line 138: | Line 144: | ||
**Output** | **Output** | ||
+ | |||
+ | * char | ||
Returns a single upper-case character for the drive; A == 0, B == 1, etc. | Returns a single upper-case character for the drive; A == 0, B == 1, etc. | ||
Line 159: | Line 167: | ||
---- | ---- | ||
- | === int isDir(char *path) === | + | === isDir() === |
**Input** | **Input** | ||
Line 166: | Line 174: | ||
**Output** | **Output** | ||
+ | |||
+ | * int | ||
Returns __1__ if the path is a directory, returns __0__ if the path is actually a file or other non-directory object. | Returns __1__ if the path is a directory, returns __0__ if the path is actually a file or other non-directory object. | ||
Line 192: | Line 202: | ||
---- | ---- | ||
- | === int findDirs(char *path, gamedata_t *gamedata, int startnum) === | + | === findDirs() === |
**Input** | **Input** | ||
Line 201: | Line 211: | ||
**Returns** | **Returns** | ||
+ | |||
+ | * int | ||
An integer representing the number of immediate sub-directories found in the searchpath // | An integer representing the number of immediate sub-directories found in the searchpath // | ||
Line 250: | Line 262: | ||
</ | </ | ||
- | More importantly, | + | More importantly, |
- | == gamedata_t == | + | === gamedata_t |
<code " | <code " | ||
Line 265: | Line 277: | ||
</ | </ | ||
- | == launchdat_t == | + | The __gamedata_t__ type is used to describe the basic information about every //game// that has been found in the // |
+ | |||
+ | Each new game that is found is added on to the end of the existing gamedata list, with the pointer being set in the //*next// variable. | ||
+ | |||
+ | === launchdat_t | ||
<code " | <code " | ||
Line 279: | Line 295: | ||
</ | </ | ||
- | == imagefile_t == | + | The __launchdat_t__ type holds information that is parsed from a single games metadata file. The file is parsed in combination by functions within //data.c// and //ini.c//, with the final version of the information being set within the launchdat structure. |
+ | |||
+ | The metadata file format follows the standard Windows .ini file layout, and can thus be parsed by the same functions as the main application config file. It also means that it eschews any complexity from XML, JSON or non-plain-text data. | ||
+ | |||
+ | It would be relatively simple to alter or expand the metadata available for a game by adjusting the above structure and adding the additional fields into the parser. If any existing metadata file didn't have the new fields, they would just be left empty. | ||
+ | |||
+ | === imagefile_t | ||
<code " | <code " | ||
Line 288: | Line 310: | ||
</ | </ | ||
- | == gamedir_t == | + | The __imagefile_t__ type is a basic linked-list data structure that stores a list of all the artwork/ |
+ | |||
+ | === gamedir_t | ||
<code " | <code " | ||
Line 297: | Line 321: | ||
</ | </ | ||
- | == config_t == | + | The __gamedir_t__ type is a basic linked-list data structure that stores a list of all the game search directories as listed within the config file of the main application. A new //gamedir// object is added to the list for each individual filename, and it is this //gamedir// objects //path// variable that is handed to // |
+ | |||
+ | === config_t | ||
<code " | <code " | ||
Line 307: | Line 333: | ||
} __attribute__((__packed__)) __attribute__((aligned (2))) config_t; | } __attribute__((__packed__)) __attribute__((aligned (2))) config_t; | ||
</ | </ | ||
+ | |||
+ | The __config_t__ type is the parsed representation of the main applications config file. As of now, this is a relatively compact data structure (verbose output on/off, game list saving on/off, list of search directories). As new functions are added to the application, | ||
+ | |||
+ | ---- | ||
+ | |||
+ | === getGameid() === | ||
+ | |||
+ | **Input** | ||
+ | |||
+ | * int gameid | ||
+ | * gamedata_t *gamedata | ||
+ | |||
+ | **Output** | ||
+ | |||
+ | * gamedata_t *gamedata | ||
+ | |||
+ | **Description** | ||
+ | |||
+ | The function takes the head item of the // | ||
+ | |||
+ | We use this function to find a gamedata object when we only know a game ID. Once we have a games gamedata object, we can then use it to look up the additional metadata, since the gamedata object tells us whether it has that additional data file, and where it is located on the filesystem. | ||
+ | |||
+ | **Example** | ||
+ | |||
+ | <code " | ||
+ | int gameid; | ||
+ | gamedata_t *gamedata_head = NULL; | ||
+ | |||
+ | gameid = 23; | ||
+ | |||
+ | // Assuming the gamedata list is already populated... | ||
+ | // Keep a record of the head of the list | ||
+ | gamedata_head = gamedata; | ||
+ | |||
+ | // Return the node which matches the given gameid | ||
+ | gamedata = getGameid(gameid); | ||
+ | |||
+ | if (gamedata != NULL){ | ||
+ | | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ---- | ||
+ | |||
+ | === getLastGamedata() === | ||
+ | |||
+ | **Input** | ||
+ | |||
+ | * gamedata_t * | ||
+ | |||
+ | **Output** | ||
+ | |||
+ | * gamedata_t *gamedata | ||
+ | |||
+ | **Description** | ||
+ | |||
+ | This function loops over all items of the gamedata list, from the current position, until it reaches the end (defined as being the node where the //next// pointer is NULL). We use this to determine where to add a new item to the list. | ||
+ | |||
+ | **Example** | ||
+ | |||
+ | This is __only__ currently called within the // | ||
+ | |||
+ | <code " | ||
+ | gamedata = getLastGamedata(gamedata); | ||
+ | gamedata-> | ||
+ | gamedata-> | ||
+ | gamedata-> | ||
+ | strcpy(gamedata-> | ||
+ | strcpy(gamedata-> | ||
+ | gamedata-> | ||
+ | gamedata-> | ||
+ | </ | ||
+ | |||
+ | ---- | ||
+ | |||
+ | === getLastImage() === | ||
+ | |||
+ | **Input** | ||
+ | |||
+ | * imagefile_t *imagefile | ||
+ | |||
+ | **Output** | ||
+ | |||
+ | * imagefile_t *imagefile | ||
+ | |||
+ | **Description** | ||
+ | |||
+ | Works much the same as the getLastGamedata() function in that it traverses the image list from the current position until it finds the end (determined by the //next// value being NULL). | ||
+ | |||
+ | **Example** | ||
+ | |||
+ | This function is only called within getImageList() within data.c, and is used to build the list of image/ | ||
+ | |||
+ | <code " | ||
+ | imagefile = getLastImage(imagefile); | ||
+ | imagefile-> | ||
+ | strcpy(imagefile-> | ||
+ | imagefile-> | ||
+ | </ | ||
+ | |||
+ | ---- | ||
+ | |||
+ | === getLastGameDir() === | ||
+ | |||
+ | **Input** | ||
+ | |||
+ | * gamedir_t *gamedir | ||
+ | |||
+ | **Output** | ||
+ | |||
+ | * gamedir_t *gamedir | ||
+ | |||
+ | **Description** | ||
+ | |||
+ | Behaves the same as // | ||
+ | |||
+ | **Example** | ||
+ | |||
+ | __Not currently used.__ | ||
+ | |||
+ | ---- | ||
+ | |||
+ | === removeGamedata() === | ||
+ | |||
+ | **Input** | ||
+ | |||
+ | * gamedata_t *gamedata | ||
+ | * int verbose | ||
+ | |||
+ | **Output** | ||
+ | |||
+ | * int | ||
+ | |||
+ | **Description** | ||
+ | |||
+ | **Example** | ||
+ | |||
+ | ---- | ||
+ | |||
+ | === removeImagefile() === | ||
+ | |||
+ | **Input** | ||
+ | |||
+ | * imagefile_t *imagefile | ||
+ | |||
+ | **Output** | ||
+ | |||
+ | * int | ||
+ | |||
+ | **Description** | ||
+ | |||
+ | **Example** | ||
+ | |||
+ | ---- | ||
+ | |||
+ | === sortGamedata() === | ||
+ | |||
+ | **Input** | ||
+ | |||
+ | * gamedata_t *gamedata | ||
+ | * int verbose | ||
+ | |||
+ | **Output** | ||
+ | |||
+ | * int | ||
+ | |||
+ | **Description** | ||
+ | |||
+ | **Example** | ||
+ | |||
+ | ---- | ||
+ | |||
+ | === swapGamedata() === | ||
+ | |||
+ | **Input** | ||
+ | |||
+ | * gamedata_t *gamedata1 | ||
+ | * gamedata_t *gamedata2 | ||
+ | |||
+ | **Output** | ||
+ | |||
+ | * int | ||
+ | |||
+ | **Description** | ||
+ | |||
+ | **Example** | ||
+ | |||
+ | ---- | ||
+ | |||
+ | === launchdatHandler() === | ||
+ | |||
+ | **Input** | ||
+ | |||
+ | * void* user | ||
+ | * const char* section | ||
+ | * const char* name | ||
+ | * const char* value | ||
+ | |||
+ | **Output** | ||
+ | |||
+ | * int | ||
+ | |||
+ | **Description** | ||
+ | |||
+ | **Example** | ||
+ | |||
+ | ---- | ||
+ | |||
+ | === launchdataDefaults() === | ||
+ | |||
+ | **Input** | ||
+ | |||
+ | * launchdat_t *launchdat | ||
+ | |||
+ | **Description** | ||
+ | |||
+ | **Example** | ||
+ | |||
+ | ---- | ||
+ | |||
+ | === configDefaults() === | ||
+ | |||
+ | **Input** | ||
+ | |||
+ | * config_t *config | ||
+ | |||
+ | **Description** | ||
+ | |||
+ | **Example** | ||
+ | |||
+ | ---- | ||
+ | |||
+ | === getLaunchdata() === | ||
+ | |||
+ | **Input** | ||
+ | |||
+ | * gamedata_t *gamedata | ||
+ | * launchdat_t *launchdat | ||
+ | |||
+ | **Output** | ||
+ | |||
+ | * int | ||
+ | |||
+ | **Description** | ||
+ | |||
+ | **Example** | ||
+ | |||
+ | ---- | ||
+ | |||
+ | === configHandler() === | ||
+ | |||
+ | **Input** | ||
+ | |||
+ | * void* user | ||
+ | * const char* section | ||
+ | * const char* name | ||
+ | * const char* value | ||
+ | |||
+ | **Output** | ||
+ | |||
+ | * static int | ||
+ | |||
+ | **Description** | ||
+ | |||
+ | **Example** | ||
+ | |||
+ | ---- | ||
+ | |||
+ | === getIni() === | ||
+ | |||
+ | **Input** | ||
+ | |||
+ | * config_t *config | ||
+ | * int verbose | ||
+ | |||
+ | **Output** | ||
+ | |||
+ | * int | ||
+ | |||
+ | **Description** | ||
+ | |||
+ | **Example** | ||
+ | |||
+ | ---- | ||
+ | |||
+ | === getImageList() === | ||
+ | |||
+ | **Input** | ||
+ | |||
+ | * launchdat_t *launchdat | ||
+ | * imagefile_t *imagefile | ||
+ | |||
+ | **Output** | ||
+ | |||
+ | * int | ||
+ | |||
+ | **Description** | ||
+ | |||
+ | **Example** | ||
+ | |||
+ | ---- | ||
+ | |||
+ | === getDirList() === | ||
+ | |||
+ | **Input** | ||
+ | |||
+ | * config_t *config | ||
+ | * gamedir_t *gamedir | ||
+ | * int verbose | ||
+ | |||
+ | **Output** | ||
+ | |||
+ | * int | ||
+ | |||
+ | **Description** | ||
+ | |||
+ | **Example** | ||
+ | |||
+ | ---- | ||
+ | |||
==== ini.c / ini.h ==== | ==== ini.c / ini.h ==== | ||
* https:// | * https:// | ||
* https:// | * https:// | ||
+ | |||
+ | The ini parsing library is a drop-in component from https:// | ||
+ | |||
+ | The entire contents of __ini.c__ and __ini.h__ are from that project, only modified to disable or enable certain functionality. | ||
+ | |||
+ | The ini parsing functions are used only by a small number of calls within __data.c__, they are not directly called by any other code within the application. | ||
==== Example Configuration ==== | ==== Example Configuration ==== | ||
+ | |||
+ | The configuration file for the application is (by default, via a constant in //data.h//) named __launcher.txt__ and is searched for in the same directory as the launcher application itself. A hardcoded path is not defined. | ||
+ | |||
+ | The contents of an example config file could look as follows | ||
< | < | ||
[default] | [default] | ||
verbose=1 | verbose=1 | ||
+ | savedirs=0 | ||
gamedirs=A: | gamedirs=A: | ||
</ | </ | ||
+ | |||
+ | At a minimum the '// | ||
==== Control Flow (a simple main.c) ==== | ==== Control Flow (a simple main.c) ==== | ||
Line 330: | Line 689: | ||
gamedata_t *gamedata_head = NULL; // Constant pointer to the start of the gamedata list | gamedata_t *gamedata_head = NULL; // Constant pointer to the start of the gamedata list | ||
- | // Create a new empty gamedata entry | + | // Create a new empty gamedata entry which will hold all of |
+ | // the games that we find | ||
gamedata = (gamedata_t *) malloc(sizeof(gamedata_t)); | gamedata = (gamedata_t *) malloc(sizeof(gamedata_t)); | ||
gamedata-> | gamedata-> | ||
- | // Parse the gamedirs that are set | + | // Create a new gamedir list to hold the game search directories |
+ | // which are extracted from the application config file | ||
gamedir = (gamedir_t *) malloc(sizeof(gamedir_t)); | gamedir = (gamedir_t *) malloc(sizeof(gamedir_t)); | ||
gamedir-> | gamedir-> | ||
- | // Create an instance of a config data | + | // Create an instance of a config data, which will be filled |
+ | // by parsing the application config ini file | ||
config = (config_t *) malloc(sizeof(config_t)); | config = (config_t *) malloc(sizeof(config_t)); | ||
config-> | config-> |