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 */
/** 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;