mkae driver creation more resilient against memory allocation errors; Doxygen-ize

This commit is contained in:
marschap
2008-12-14 17:40:22 +00:00
parent 30f16bcdaa
commit fba2e96e31
+188 -43
View File
@@ -38,10 +38,11 @@
/* lcd.h is used for the driver API definition */ /* lcd.h is used for the driver API definition */
/** property / method symbols in a Driver structure */
typedef struct driver_symbols { typedef struct driver_symbols {
const char *name; const char *name; /**< symbol name */
short offset; /* offset in Driver structure */ short offset; /**< offset in Driver structure */
short required; short required; /**< is the symbol mandatory */
} DriverSymbols; } DriverSymbols;
DriverSymbols driver_symbols[] = { DriverSymbols driver_symbols[] = {
@@ -86,22 +87,48 @@ static int request_display_height(void);
static int driver_store_private_ptr(Driver *driver, void *private_data); 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 *
driver_load(const char *name, const char *filename) driver_load(const char *name, const char *filename)
{ {
Driver *driver = NULL; Driver *driver = NULL;
int res; 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 */ /* Allocate memory for new driver struct */
driver = malloc(sizeof(Driver)); driver = calloc(1, sizeof(Driver));
memset(driver, 0, sizeof(Driver)); if (driver == NULL) {
report(RPT_ERR, "%s: error allocating driver", __FUNCTION__);
return NULL;
}
/* And store its name and filename */ /* And store its name and filename */
driver->name = malloc(strlen(name) + 1); 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); strcpy(driver->name, name);
driver->filename = malloc(strlen(filename) + 1); 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); strcpy(driver->filename, filename);
/* Load and bind the driver module and locate the symbols */ /* 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 */ /* 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); res = driver->init(driver);
if (res < 0) { 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 /* Driver load failed, driver should not be added to list
* Free driver structure again * 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 int
driver_unload(Driver *driver) driver_unload(Driver *driver)
{ {
debug(RPT_NOTICE, "Closing driver [%.40s]", driver->name); 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); driver->close(driver);
/* Unlaod the module */ /* unload the module */
driver_unbind_module(driver); driver_unbind_module(driver);
/* Free its data */ /* free its data */
free(driver->filename); free(driver->filename);
driver->filename = NULL;
free(driver->name); free(driver->name);
driver->name = NULL;
free(driver); free(driver);
driver = NULL;
debug(RPT_DEBUG, "%s: Driver unloaded", __FUNCTION__); debug(RPT_DEBUG, "%s: Driver unloaded", __FUNCTION__);
return 0; 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 int
driver_bind_module(Driver *driver) driver_bind_module(Driver *driver)
{ {
@@ -180,22 +226,25 @@ driver_bind_module(Driver *driver)
#endif #endif
if (driver->module_handle == NULL) { if (driver->module_handle == NULL) {
#ifndef WIN32 #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 #else
/* REVISIT: replace dlerror() */ /* 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 #endif
return -1; return -1;
} }
/* And locate the symbols */ /* And locate the symbols */
for (i = 0; driver_symbols[i].name; i++) { for (i = 0; driver_symbols[i].name != NULL; i++) {
void (**p)(); void (**p)();
p = (void(**)()) ((size_t)driver + (driver_symbols[i].offset)); p = (void(**)()) ((size_t)driver + (driver_symbols[i].offset));
*p = NULL; *p = NULL;
/* Add the symbol_prefix */ /* 1) try to retrieve the symbol with the driver's symbol_prefix added */
if (driver->symbol_prefix) { if (driver->symbol_prefix != NULL) {
char *s = malloc(strlen(*(driver->symbol_prefix)) + strlen(driver_symbols[i].name) + 1); char *s = malloc(strlen(*(driver->symbol_prefix)) + strlen(driver_symbols[i].name) + 1);
strcpy(s, *(driver->symbol_prefix)); strcpy(s, *(driver->symbol_prefix));
strcat(s, driver_symbols[i].name); strcat(s, driver_symbols[i].name);
@@ -207,8 +256,8 @@ driver_bind_module(Driver *driver)
#endif #endif
free(s); free(s);
} }
/* Retrieve the symbol */ /* 2) try to retrieve the symbol without the symbol prefix */
if (!*p) { if (*p == NULL) {
debug(RPT_DEBUG, "%s: finding symbol: %s", __FUNCTION__, driver_symbols[i].name); debug(RPT_DEBUG, "%s: finding symbol: %s", __FUNCTION__, driver_symbols[i].name);
#ifndef WIN32 #ifndef WIN32
*p = dlsym(driver->module_handle, driver_symbols[i].name); *p = dlsym(driver->module_handle, driver_symbols[i].name);
@@ -217,20 +266,23 @@ driver_bind_module(Driver *driver)
#endif #endif
} }
if (*p) { if (*p != NULL) {
debug(RPT_DEBUG, "%s: found symbol at: %p", __FUNCTION__, *p); debug(RPT_DEBUG, "%s: found symbol at: %p", __FUNCTION__, *p);
} }
else {
/* Was the symbol required but not found ? */ /* Was the symbol required but not found ? */
if (!*p && driver_symbols[i].required) { if (driver_symbols[i].required) {
report(RPT_ERR, "Driver [%.40s] does not have required symbol: %s", driver->name, driver_symbols[i].name); report(RPT_ERR, "Driver [%.40s] does not have required symbol: %s",
missing_symbols = 1; driver->name, driver_symbols[i].name);
missing_symbols++;
}
} }
} }
/* If errors, leave now while we can :) */ /* If errors, leave now while we can :) */
if (missing_symbols) { if (missing_symbols > 0) {
report(RPT_ERR, "Driver [%.40s] does not have all obligatory symbols", driver->name); report(RPT_ERR, "Driver [%.40s] misses %d required symbols",
driver->name, missing_symbols);
#ifndef WIN32 #ifndef WIN32
dlclose(driver->module_handle); dlclose(driver->module_handle);
#else #else
@@ -239,7 +291,6 @@ driver_bind_module(Driver *driver)
return -1; return -1;
} }
/* Add our exported functions */ /* Add our exported functions */
/* Config file 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 int
driver_unbind_module(Driver *driver) 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 bool
driver_does_output(Driver *driver) 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 bool
driver_does_input(Driver *driver) 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 bool
driver_stay_in_foreground(Driver *driver) 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 bool
driver_supports_multiple(Driver *driver) driver_supports_multiple(Driver *driver)
{ {
@@ -314,7 +393,8 @@ driver_supports_multiple(Driver *driver)
static int static int
driver_store_private_ptr(Driver *driver, void *private_data) 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; driver->private_data = private_data;
return 0; return 0;
@@ -329,6 +409,7 @@ request_display_width(void)
return display_props->width; return display_props->width;
} }
static int static int
request_display_height(void) request_display_height(void)
{ {
@@ -337,15 +418,28 @@ request_display_height(void)
return display_props->height; 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 void
driver_alt_vbar(Driver *drv, int x, int y, int len, int promille, int pattern) driver_alt_vbar(Driver *drv, int x, int y, int len, int promille, int pattern)
{ {
int pos; 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; return;
for (pos = 0; pos < len; pos++) { for (pos = 0; pos < len; pos++) {
if (2 * pos < ((long) promille * len / 500 + 1)) { if (2 * pos < ((long) promille * len / 500 + 1)) {
drv->chr(drv, x, y-pos, '|'); 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 void
driver_alt_hbar(Driver *drv, int x, int y, int len, int promille, int pattern) driver_alt_hbar(Driver *drv, int x, int y, int len, int promille, int pattern)
{ {
int pos; 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; return;
for (pos = 0; pos < len; pos++) { 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 void
driver_alt_num(Driver *drv, int x, int num) 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; 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)) if ((num < 0) || (num > 10))
return; return;
if (!drv->chr) /* if the driver does not support output, do nothing */
if (drv->chr == NULL)
return; return;
for (y = 0; y < 4; y++) 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]); 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 void
driver_alt_heartbeat(Driver *drv, int state) driver_alt_heartbeat(Driver *drv, int state)
{ {
int icon; 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) if (state == HEARTBEAT_OFF)
return; return;
/* Don't display anything */ /* Don't display anything */
if (!drv->width) /* if the driver does not support output, do nothing */
if (drv->width == NULL)
return; return;
/* Hmm, is this a good method ? /* 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); 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 void
driver_alt_icon(Driver *drv, int x, int y, int icon) driver_alt_icon(Driver *drv, int x, int y, int icon)
{ {
char ch1 = '?'; char ch1 = '?';
char ch2 = '\0'; 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; return;
switch (icon) { 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_PREV: ch1 = '|'; ch2 = '<'; break;
case ICON_REC: ch1 = '('; ch2 = ')'; break; case ICON_REC: ch1 = '('; ch2 = ')'; break;
} }
drv->chr(drv, x, y, ch1); drv->chr(drv, x, y, ch1);
if (ch2) if (ch2 != '\0')
drv->chr(drv, x+1, y, ch2); 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) void driver_alt_cursor(Driver *drv, int x, int y, int state)
{ {
/* Same question about timer in this function... */ /* 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) { switch (state) {
case CURSOR_BLOCK: case CURSOR_BLOCK:
case CURSOR_DEFAULT_ON: case CURSOR_DEFAULT_ON:
if (timer & 2 && drv->chr) { if ((timer & 2) && (drv->chr != NULL)) {
if (drv->icon) { if (drv->icon != NULL) {
drv->icon(drv, x, y, ICON_BLOCK_FILLED); drv->icon(drv, x, y, ICON_BLOCK_FILLED);
} else { } else {
driver_alt_icon(drv, x, y, ICON_BLOCK_FILLED); 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; break;
case CURSOR_UNDER: case CURSOR_UNDER:
if (timer & 2 && drv->chr) { if ((timer & 2) && (drv->chr != NULL)) {
drv->chr(drv, x, y, '_'); drv->chr(drv, x, y, '_');
} }
break; break;