#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include static struct object_table_entry def_object_table[] = { { .type = OBJECT_TYPE_UNDEFINED, .name = "<>", .ops = { .new = NULL, .free = NULL, .str = NULL, .draw = NULL, }, }, { .type = OBJECT_TYPE_LINE, .name = "line", .ops = { .new = (object_t *(*)(void))line_new, .free = (void (*)(object_t*))line_free, .str = (char* (*)(object_t*))line_str, .draw = (void (*)(object_t*, surface_t*))line_draw, }, }, { .type = OBJECT_TYPE_CIRCLE, .name = "circle", .ops = { .new = (object_t *(*)(void))circle_new, .free = (void (*)(object_t*))circle_free, .str = (char* (*)(object_t*))circle_str, .draw = (void (*)(object_t*, surface_t*))circle_draw, }, }, { .type = OBJECT_TYPE_ELLIPSE, .name = "ellipse", .ops = { .new = (object_t *(*)(void))ellipse_new, .free = (void (*)(object_t*))ellipse_free, .str = (char* (*)(object_t*))ellipse_str, .draw = (void (*)(object_t*, surface_t*))ellipse_draw, }, }, { .type = OBJECT_TYPE_POLYGON, .name = "polygon", .ops = { .new = (object_t *(*)(void))polygon_new, .free = (void (*)(object_t*))polygon_free, .str = (char* (*)(object_t*))polygon_str, .draw = (void (*)(object_t*, surface_t*))polygon_draw, }, }, }; static uint16_t object_table_size = \ sizeof(def_object_table) / sizeof(*def_object_table); static struct object_table_entry *object_table = def_object_table; /** * Add new object to object's table. * * @param name an unique name to object. * @param ops operations for this object. * * @return pointer to the entry in the table, please use the returned * type for this object. */ struct object_table_entry * add_object_table_entry( const char *name, const struct object_ops *ops ) { uint16_t i; uint16_t s = object_table_size + 1; struct object_table_entry *t; for ( i=0; i < object_table_size; i++ ) if ( strcmp( name, object_table[ i ].name ) == 0 ) { err( "Tried to add a new object, but name \"%s\" already exists.\n", name ); return NULL; } if ( object_table == def_object_table ) /* virgin object table */ t = malloc( sizeof(*t) * s ); else t = realloc( object_table, s ); if ( t == NULL ) { err( "Could not allocate memory to object_table\n" ); return NULL; } object_table = t; object_table_size = s; t = &object_table[ s - 1 ]; t->type = s - 1; t->name = strdup( name ); t->ops = *ops; return t; } /** * Get the object entry from the object's table. * * The object entry holds information about the object, like functions * to act on it, its name and possible other information. * * @param type the object type. * * @return pointer to object table entry, with object name, type and * operations. */ struct object_table_entry * get_object_table_entry( uint16_t type ) { struct object_table_entry *t = NULL; if ( type < object_table_size ) { t = &object_table[ type ]; assert( t->type == type ); /* else it was hacked, so fail */ } return t; } /** * Restores the original object table, free data. * * You may register this function on program exit if you add something to * object table, otherwise you may get some "memory leaks" notices when * you exit. See atexit(3). */ void clear_object_table( void ) { if ( object_table != def_object_table ) { uint16_t i = sizeof(def_object_table) / sizeof(*def_object_table); for ( ; i < object_table_size; i++ ) free( object_table[ i ].name ); free( object_table ); object_table = def_object_table; object_table_size = sizeof(def_object_table) / sizeof(*def_object_table); } }