From fba2e96e31258c98d7237e2332a07b4467db6224 Mon Sep 17 00:00:00 2001 From: marschap Date: Sun, 14 Dec 2008 17:40:22 +0000 Subject: [PATCH] mkae driver creation more resilient against memory allocation errors; Doxygen-ize --- server/driver.c | 231 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 188 insertions(+), 43 deletions(-) diff --git a/server/driver.c b/server/driver.c index d9c4e8d..57d7c72 100644 --- a/server/driver.c +++ b/server/driver.c @@ -38,10 +38,11 @@ /* lcd.h is used for the driver API definition */ +/** property / method symbols in a Driver structure */ typedef struct driver_symbols { - const char *name; - short offset; /* offset in Driver structure */ - short required; + const char *name; /**< symbol name */ + short offset; /**< offset in Driver structure */ + short required; /**< is the symbol mandatory */ } DriverSymbols; DriverSymbols driver_symbols[] = { @@ -86,22 +87,48 @@ static int request_display_height(void); static int driver_store_private_ptr(Driver *driver, void *private_data); +/** Create a driver object. + * Allocate memory for the driver object, load it from file and bind its symbols. + * \param name Name under which the driver shall be kbown forther on. + * \param filename Name of the file containing the drivers object code. + * \return Pointer to the freshly created driver; \c NULL on error. + */ Driver * driver_load(const char *name, const char *filename) { Driver *driver = NULL; int res; - report(RPT_DEBUG, "%s(name=\"%.40s\", filename=\"%.80s\")", __FUNCTION__, name, filename); + report(RPT_DEBUG, "%s(name=\"%.40s\", filename=\"%.80s\")", + __FUNCTION__, name, filename); + + /* fail on wrong / missing parameters */ + if ((name == NULL) || (filename == NULL)) + return NULL; /* Allocate memory for new driver struct */ - driver = malloc(sizeof(Driver)); - memset(driver, 0, sizeof(Driver)); + driver = calloc(1, sizeof(Driver)); + if (driver == NULL) { + report(RPT_ERR, "%s: error allocating driver", __FUNCTION__); + return NULL; + } /* And store its name and filename */ driver->name = malloc(strlen(name) + 1); + if (driver->name == NULL) { + report(RPT_ERR, "%s: error allocating driver name", __FUNCTION__); + free(driver); + return NULL; + } strcpy(driver->name, name); + driver->filename = malloc(strlen(filename) + 1); + if (driver->filename == NULL) { + report(RPT_ERR, "%s: error allocating driver filename", __FUNCTION__); + free(driver->name); + free(driver); + return NULL; + } strcpy(driver->filename, filename); /* Load and bind the driver module and locate the symbols */ @@ -124,10 +151,13 @@ driver_load(const char *name, const char *filename) } /* Call the init function */ - debug(RPT_DEBUG, "%s: Calling driver [%.40s] init function", __FUNCTION__, driver->name); + debug(RPT_DEBUG, "%s: Calling driver [%.40s] init function", + __FUNCTION__, driver->name); + res = driver->init(driver); if (res < 0) { - report(RPT_ERR, "Driver [%.40s] init failed, return code < 0", driver->name); + report(RPT_ERR, "Driver [%.40s] init failed, return code %d", + driver->name, res); /* Driver load failed, driver should not be added to list * Free driver structure again */ @@ -144,26 +174,42 @@ driver_load(const char *name, const char *filename) } +/** Unload driver from memory. + * \param driver Driver to unload. + * \retval <0 Error. + * \retval 0 Success. + */ int driver_unload(Driver *driver) { debug(RPT_NOTICE, "Closing driver [%.40s]", driver->name); - if (driver->close) + + /* close the driver, if its \c close method is [already] defined */ + if (driver->close != NULL) driver->close(driver); - /* Unlaod the module */ + /* unload the module */ driver_unbind_module(driver); - /* Free its data */ + /* free its data */ free(driver->filename); + driver->filename = NULL; free(driver->name); + driver->name = NULL; free(driver); + driver = NULL; + debug(RPT_DEBUG, "%s: Driver unloaded", __FUNCTION__); return 0; } +/** Dynamically load a module and bind it to the Driver's symbols. + * \param driver Pointer to the Driver object. + * \retval <0 Error. + * \retval 0 Success. + */ int driver_bind_module(Driver *driver) { @@ -180,22 +226,25 @@ driver_bind_module(Driver *driver) #endif if (driver->module_handle == NULL) { #ifndef WIN32 - report(RPT_ERR, "Could not open driver module %.40s: %s", driver->filename, dlerror()); + report(RPT_ERR, "Could not open driver module %.40s: %s", + driver->filename, dlerror()); #else /* REVISIT: replace dlerror() */ - report(RPT_ERR, "Could not open driver module %.40s.", driver->filename); + report(RPT_ERR, "Could not open driver module %.40s.", + driver->filename); #endif return -1; } /* And locate the symbols */ - for (i = 0; driver_symbols[i].name; i++) { + for (i = 0; driver_symbols[i].name != NULL; i++) { void (**p)(); + p = (void(**)()) ((size_t)driver + (driver_symbols[i].offset)); *p = NULL; - /* Add the symbol_prefix */ - if (driver->symbol_prefix) { + /* 1) try to retrieve the symbol with the driver's symbol_prefix added */ + if (driver->symbol_prefix != NULL) { char *s = malloc(strlen(*(driver->symbol_prefix)) + strlen(driver_symbols[i].name) + 1); strcpy(s, *(driver->symbol_prefix)); strcat(s, driver_symbols[i].name); @@ -207,8 +256,8 @@ driver_bind_module(Driver *driver) #endif free(s); } - /* Retrieve the symbol */ - if (!*p) { + /* 2) try to retrieve the symbol without the symbol prefix */ + if (*p == NULL) { debug(RPT_DEBUG, "%s: finding symbol: %s", __FUNCTION__, driver_symbols[i].name); #ifndef WIN32 *p = dlsym(driver->module_handle, driver_symbols[i].name); @@ -217,20 +266,23 @@ driver_bind_module(Driver *driver) #endif } - if (*p) { + if (*p != NULL) { debug(RPT_DEBUG, "%s: found symbol at: %p", __FUNCTION__, *p); } - - /* Was the symbol required but not found ? */ - if (!*p && driver_symbols[i].required) { - report(RPT_ERR, "Driver [%.40s] does not have required symbol: %s", driver->name, driver_symbols[i].name); - missing_symbols = 1; + else { + /* Was the symbol required but not found ? */ + if (driver_symbols[i].required) { + report(RPT_ERR, "Driver [%.40s] does not have required symbol: %s", + driver->name, driver_symbols[i].name); + missing_symbols++; + } } } /* If errors, leave now while we can :) */ - if (missing_symbols) { - report(RPT_ERR, "Driver [%.40s] does not have all obligatory symbols", driver->name); + if (missing_symbols > 0) { + report(RPT_ERR, "Driver [%.40s] misses %d required symbols", + driver->name, missing_symbols); #ifndef WIN32 dlclose(driver->module_handle); #else @@ -239,7 +291,6 @@ driver_bind_module(Driver *driver) return -1; } - /* Add our exported functions */ /* Config file functions */ @@ -264,6 +315,11 @@ driver_bind_module(Driver *driver) } +/** Unload a Driver's module. + * \param driver Pointer to he driver object. + * \retval <0 Error. + * \retval 0 Success. + */ int driver_unbind_module(Driver *driver) { @@ -279,6 +335,13 @@ driver_unbind_module(Driver *driver) } +/** Determine if the driver is an output driver. + * This is done by checking whether the driver knows dimensions + * and supports the methods that write to the screen. + * \param driver Pointer to he driver object. + * \retval 0 No, it is not an output driver. + * \retval 1 Yes, it is an output driver. + */ bool driver_does_output(Driver *driver) { @@ -290,6 +353,12 @@ driver_does_output(Driver *driver) } +/** Determine if the driver is an input driver. + * This is done by checking whether the driver supports the \c get_key method. + * \param driver Pointer to he driver object. + * \retval 0 No, it is not an input driver. + * \retval 1 Yes, it is an input driver. + */ bool driver_does_input(Driver *driver) { @@ -297,6 +366,11 @@ driver_does_input(Driver *driver) } +/** Tell if the driver needs to stay in the foreground. + * \param driver Pointer to he driver object. + * \retval 0 No, the driver does not need to stay in the foreground. + * \retval 1 Yes, the driver needs to stay in the foreground. + */ bool driver_stay_in_foreground(Driver *driver) { @@ -304,6 +378,11 @@ driver_stay_in_foreground(Driver *driver) } +/** Tell if the driver supports multiple instances. + * \param driver Pointer to he driver object. + * \retval 0 No, it doesn't. + * \retval 1 Yes, it does. + */ bool driver_supports_multiple(Driver *driver) { @@ -314,7 +393,8 @@ driver_supports_multiple(Driver *driver) static int driver_store_private_ptr(Driver *driver, void *private_data) { - debug(RPT_DEBUG, "%s(driver=[%.40s], ptr=%p)", __FUNCTION__, driver->name, private_data); + debug(RPT_DEBUG, "%s(driver=[%.40s], ptr=%p)", + __FUNCTION__, driver->name, private_data); driver->private_data = private_data; return 0; @@ -329,6 +409,7 @@ request_display_width(void) return display_props->width; } + static int request_display_height(void) { @@ -337,15 +418,28 @@ request_display_height(void) return display_props->height; } + +/** Draw a vertical bar bottom-up. + * Fallback for the driver's \c vbar method if the driver does not provide one. + * \param drv Pointer to driver structure. + * \param x Horizontal character position (column) of the starting point. + * \param y Vertical character position (row) of the starting point. + * \param len Number of characters that the bar is high at 100% + * \param promille Current height level of the bar in promille. + * \param options Options (currently unused). + */ void driver_alt_vbar(Driver *drv, int x, int y, int len, int promille, int pattern) { int pos; - debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, y=%d, len=%d, promille=%d, pattern=%d)", __FUNCTION__, drv->name, x, y, len, promille, pattern); + debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, y=%d, len=%d, promille=%d, pattern=%d)", + __FUNCTION__, drv->name, x, y, len, promille, pattern); - if (!drv->chr) + /* if the driver does not support output, do nothing */ + if (drv->chr == NULL) return; + for (pos = 0; pos < len; pos++) { if (2 * pos < ((long) promille * len / 500 + 1)) { drv->chr(drv, x, y-pos, '|'); @@ -355,14 +449,26 @@ driver_alt_vbar(Driver *drv, int x, int y, int len, int promille, int pattern) } } + +/** Draw a horizontal bar to the right. + * Fallback for the driver's \c hbar method if the driver does not provide one. + * \param drv Pointer to driver structure. + * \param x Horizontal character position (column) of the starting point. + * \param y Vertical character position (row) of the starting point. + * \param len Number of characters that the bar is long at 100% + * \param promille Current length level of the bar in promille. + * \param options Options (currently unused). + */ void driver_alt_hbar(Driver *drv, int x, int y, int len, int promille, int pattern) { int pos; - debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, y=%d, len=%d, promille=%d, pattern=%d)", __FUNCTION__, drv->name, x, y, len, promille, pattern); + debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, y=%d, len=%d, promille=%d, pattern=%d)", + __FUNCTION__, drv->name, x, y, len, promille, pattern); - if (!drv->chr) + /* if the driver does not support output, do nothing */ + if (drv->chr == NULL) return; for (pos = 0; pos < len; pos++) { @@ -374,6 +480,13 @@ driver_alt_hbar(Driver *drv, int x, int y, int len, int promille, int pattern) } } + +/** Write a big number to the screen. + * Fallback for the driver's \c num method if the driver does not provide one. + * \param drv Pointer to driver structure. + * \param x Horizontal character position (column). + * \param num Character to write (0 - 10 with 10 representing ':') + */ void driver_alt_num(Driver *drv, int x, int num) { @@ -441,11 +554,13 @@ driver_alt_num(Driver *drv, int x, int num) int y, dx; - debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, num=%d)", __FUNCTION__, drv->name, x, num); + debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, num=%d)", + __FUNCTION__, drv->name, x, num); if ((num < 0) || (num > 10)) return; - if (!drv->chr) + /* if the driver does not support output, do nothing */ + if (drv->chr == NULL) return; for (y = 0; y < 4; y++) @@ -453,18 +568,26 @@ driver_alt_num(Driver *drv, int x, int num) drv->chr(drv, x + dx, y+1, num_map[num][y][dx]); } + +/** Show the heartbeat. + * Fallback for the driver's \c heartbeat method if the driver does not provide one. + * \param drv Pointer to driver structure. + * \param state Current heartbeat state. + */ void driver_alt_heartbeat(Driver *drv, int state) { int icon; - debug(RPT_DEBUG, "%s(drv=[%.40s], state=%d)", __FUNCTION__, drv->name, state); + debug(RPT_DEBUG, "%s(drv=[%.40s], state=%d)", + __FUNCTION__, drv->name, state); if (state == HEARTBEAT_OFF) return; /* Don't display anything */ - if (!drv->width) + /* if the driver does not support output, do nothing */ + if (drv->width == NULL) return; /* Hmm, is this a good method ? @@ -478,15 +601,27 @@ driver_alt_heartbeat(Driver *drv, int state) driver_alt_icon(drv, drv->width(drv), 1, icon); } + +/** Place an icon on the screen. + * Fallback for the driver's \c icon method, in case either the driver does not + * provide one or the driver's method indicates the icon needs to be handled + * by the server core. + * \param drvthis Pointer to driver structure. + * \param x Horizontal character position (column). + * \param y Vertical character position (row). + * \param icon synbolic value representing the icon. + */ void driver_alt_icon(Driver *drv, int x, int y, int icon) { char ch1 = '?'; char ch2 = '\0'; - debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, y=%d, icon=ICON_%s)", __FUNCTION__, drv->name, x, y, widget_icon_to_iconname(icon)); + debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, y=%d, icon=ICON_%s)", + __FUNCTION__, drv->name, x, y, widget_icon_to_iconname(icon)); - if (!drv->chr) + /* if the driver does not support output, do nothing */ + if (drv->chr == NULL) return; switch (icon) { @@ -513,22 +648,32 @@ driver_alt_icon(Driver *drv, int x, int y, int icon) case ICON_PREV: ch1 = '|'; ch2 = '<'; break; case ICON_REC: ch1 = '('; ch2 = ')'; break; } + drv->chr(drv, x, y, ch1); - if (ch2) + if (ch2 != '\0') drv->chr(drv, x+1, y, ch2); } + +/** Set cursor position and state. + * Fallback for the driver's \c cursor method if the driver does not provide one. + * \param drvthis Pointer to driver structure. + * \param x Horizontal cursor position (column). + * \param y Vertical cursor position (row). + * \param state New cursor state. + */ void driver_alt_cursor(Driver *drv, int x, int y, int state) { /* Same question about timer in this function... */ - debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, y=%d, state=%d)", __FUNCTION__, drv->name, x, y, state); + debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, y=%d, state=%d)", + __FUNCTION__, drv->name, x, y, state); switch (state) { case CURSOR_BLOCK: case CURSOR_DEFAULT_ON: - if (timer & 2 && drv->chr) { - if (drv->icon) { + if ((timer & 2) && (drv->chr != NULL)) { + if (drv->icon != NULL) { drv->icon(drv, x, y, ICON_BLOCK_FILLED); } else { driver_alt_icon(drv, x, y, ICON_BLOCK_FILLED); @@ -536,7 +681,7 @@ void driver_alt_cursor(Driver *drv, int x, int y, int state) } break; case CURSOR_UNDER: - if (timer & 2 && drv->chr) { + if ((timer & 2) && (drv->chr != NULL)) { drv->chr(drv, x, y, '_'); } break;